Compare commits

...

210 Commits

Author SHA1 Message Date
6a956472fe Release 3.0.5 2017-10-10 12:27:16 +03:00
0c4407f43a Merge pull request #1126 from mailpoet/eslint3
Eslint rules [MAILPOET-1084]
2017-10-10 11:46:45 +03:00
b6c864e7a1 Change the JSON API error message
[MAILPOET-1103]
2017-10-10 09:45:50 +01:00
3d9dc6465d Merge pull request #1132 from mailpoet/image_alignment
Add image alignment option to newsletter editor [MAILPOET-1124]
2017-10-10 11:37:11 +03:00
9a6fec094a fixing divider and spacer resize 2017-10-10 08:35:26 +00:00
61af224d7d Fixing image resize 2017-10-09 12:12:47 +00:00
9b41641e97 Tests vars-on-top 2017-10-09 11:17:23 +00:00
4e2e9f6f8f rebasing on master 2017-10-09 11:17:23 +00:00
c29dc8b4c7 fixing tests 2017-10-09 11:15:58 +00:00
98a3c6b156 Tests no-unused-vars 2017-10-09 11:15:58 +00:00
69c540288b Tests one-var 2017-10-09 11:15:58 +00:00
651c9f5692 Tests one-var-declaration-per-line 2017-10-09 11:15:58 +00:00
9ad3778cf7 ES6 rules 2017-10-09 11:15:58 +00:00
c90e0e9f64 ES5 no-unused-vars 2017-10-09 11:15:58 +00:00
cb1730c4e2 ES5 no-var 2017-10-09 11:15:58 +00:00
3dd8a973fd ES5 vars-on-top 2017-10-09 11:15:58 +00:00
c3ea088fca ES5 one-var 2017-10-09 11:15:58 +00:00
a11d6d7868 ES5 one-var-declaration-per-line 2017-10-09 11:15:58 +00:00
a596add838 ES5 block-scoped-var 2017-10-09 11:15:58 +00:00
7e7103ddab ES5 block-scoped-var 2017-10-09 11:15:58 +00:00
0064970ed7 Add a test for an alignment setting of an image block in the editor [MAILPOET-1124] 2017-10-09 13:00:39 +03:00
9d93f3ea95 Add a test for image alignment rendering [MAILPOET-1124] 2017-10-09 09:37:31 +03:00
ff2a3cd19e Release 3.0.4 2017-10-05 12:09:28 +00:00
8419d95ea1 Fix spacer and divider resizing [MAILPOET-1131] 2017-10-05 10:48:52 +01:00
4ad317ac7b Release MP3 3.0.3 2017-10-03 21:37:51 +03:00
7cccebbf2c Merge pull request #1135 from mailpoet/wp_sync_collations_fix
Get rid of WP user IDs updating query in favor of an insert-update due to collation problems [MAILPOET-1132]
2017-10-03 21:01:44 +03:00
e4f76ee9eb Get rid of WP user IDs updating query in favor of an insert-update due to collation problems [MAILPOET-1132] 2017-10-03 20:52:35 +03:00
7f52f72c25 Releasing 3.0.2 2017-10-03 14:27:56 +00:00
44afcbbeaf Merge pull request #1134 from mailpoet/new-poll
Add a new poll to update page [MAILPOET-1129]
2017-10-02 19:55:36 +03:00
e816c59539 Add a new poll to update page 2017-10-02 18:47:39 +03:00
c74421a42a Merge pull request #1133 from mailpoet/permission_update_fix
Remove the check for a plugin update permission [MAILPOET-1130]
2017-10-02 14:58:08 +02:00
23eb4633c4 Remove the check for a plugin update permission [MAILPOET-1130] 2017-10-02 15:44:06 +03:00
26241afb86 Add image alignment option to newsletter editor [MAILPOET-1124] 2017-10-02 15:30:43 +03:00
92dbf966a1 Add a UI hint for managing capabilities using the Members plugin [MAILPOET-1123] 2017-10-02 10:33:20 +01:00
db226b54a8 Include admin-global.css only on admin pages [MAILPOET-493] 2017-10-02 10:22:40 +01:00
3af059f5c4 Fix MailPoet icon displaying in Members tab on production [MAILPOET-493] 2017-10-02 10:22:40 +01:00
8706abcdf0 Change access_plugin_admin permission label [MAILPOET-493] 2017-10-02 10:22:40 +01:00
2129d041ac Fix indentation [MAILPOET-493] 2017-10-02 10:22:40 +01:00
2a4a44ebb5 Make a condition more easy to read [MAILPOET-493] 2017-10-02 10:22:40 +01:00
a4f2d5402c Manage MP3 permissions with WP role capabilities, add Members plugin support [MAILPOET-493] 2017-10-02 10:22:40 +01:00
9f5fc151b4 Move throttling out of the Subscriber model to the API 'subscribe' method [MAILPOET-1115] 2017-09-28 15:45:35 +01:00
8a91eb46e6 Fix the possibility of repeatedly submitting a form with an existing e-mail address [MAILPOET-1115] 2017-09-28 12:59:57 +01:00
e4ab928e82 Merge pull request #1127 from mailpoet/presubscribed_wp_sync_fix
Fix synchronization of presubscribed WP users [MAILPOET-1127]
2017-09-28 11:24:32 +02:00
a1b02cb862 Fix synchronization of presubscribed WP users [MAILPOET-1127] 2017-09-28 10:44:29 +03:00
84b942b9d2 Merge pull request #1121 from mailpoet/template_sort
Applies sorting by date created and name [MAILPOET-1119]
2017-09-27 11:14:00 +02:00
1ca99a6209 Updates Premium tab language 2017-09-27 10:07:36 +01:00
6b61abe8c0 Removes text domain from plugin header 2017-09-27 10:05:10 +01:00
27028ca1ef Merge pull request #1124 from mailpoet/alc_and_post_exclude_search_results
Prevents excluded post types from being displayed in newsletter editor [MAILPOET-701]
2017-09-27 11:40:51 +03:00
eed88926a2 Merge pull request #1120 from mailpoet/editor_horizontal_scroll_fix
Fixes horizontal scrolling inside post/ALC options panel [MAILPOET-1118]
2017-09-27 11:31:34 +03:00
b25877c514 Bump up release version to 3.0.1 2017-09-26 18:18:17 +03:00
119e574495 Prevents excluded post types from being displayed in newsletter editor 2017-09-25 19:45:33 -04:00
7308d253b2 Applies sorting by date created and name 2017-09-25 18:47:43 -04:00
1c19b71697 Fixes horizontal scrolling inside post/ALC options panel 2017-09-25 18:09:58 -04:00
7551fff93f Merge pull request #1116 from mailpoet/fix-tests
Fixing Shortcodes issue [MAILPOET-1104]
2017-09-25 17:14:35 -04:00
b2aa919574 Merge pull request #1118 from mailpoet/fix-query
Add index to improve query performance [MAILPOET-1117]
2017-09-25 17:04:25 -04:00
1102bbe483 Merge pull request #1056 from mailpoet/resize-image
Add image resize feature [MAILPOET-1047]
2017-09-25 13:07:10 +03:00
b78dd22ba9 Merge pull request #1109 from mailpoet/templates-images-src
Adding https prefix the image sources [MAILPOET-1109]
2017-09-25 12:08:02 +03:00
73110ada46 fixing ESLint tests 2017-09-25 09:06:55 +00:00
74dedd06bc changing missing tempaltes 2017-09-25 08:57:18 +00:00
20c936d13b limitting width with CSS 2017-09-21 18:58:17 +00:00
f135b89de9 Fixed image resize bugs 2017-09-21 18:58:16 +00:00
6a83930ae0 Resizing the image fixed 2017-09-21 18:57:35 +00:00
a1d0acfac2 Add image resize feature 2017-09-21 18:56:47 +00:00
04be06c0cb remove additional new line 2017-09-21 18:47:43 +00:00
78d52d6298 Merge pull request #1117 from mailpoet/eslint
Eslint rules [MAILPOET-1081]
2017-09-21 19:42:19 +03:00
5ff7c28c43 Merge pull request #1110 from mailpoet/es6_spacing
Fix ESLint spacing rules for ES6 [MAILPOET-1082]
2017-09-21 17:15:57 +03:00
5526f315d2 Merge pull request #1115 from mailpoet/scheduled_newsletter_status_fix
Sets newsletter status to draft when it's unscheduled [MAILPOET-1060]
2017-09-21 16:32:12 +03:00
d5e25fdeb1 Merge pull request #1114 from mailpoet/long_email_sql_error_fix
Fixes SQL error resulting from subscription with long email [MAILPOET-1113]
2017-09-21 16:17:21 +03:00
90a7bf5179 Adds back rendered subject clearing test
Removes duplicate line
2017-09-21 09:13:13 -04:00
bf1f696870 Add index to improve query performance
[MAILPOET-1117]
2017-09-21 13:17:02 +01:00
95551ad049 ES5 keyword-spacing 2017-09-21 09:13:36 +00:00
1ad90680f4 ES5 object-curly-spacing 2017-09-21 09:12:52 +00:00
d69d3cb421 ES5 array-bracket-spacing 2017-09-21 09:12:37 +00:00
9adca07393 ES5 computed-property-spacing 2017-09-21 09:12:23 +00:00
a9d129fddc ES5 block-spacing 2017-09-21 09:12:09 +00:00
b4ac09bea3 ES5 key-spacing 2017-09-21 09:11:55 +00:00
b1a403d9b5 ES5 space-infix-ops 2017-09-21 09:09:29 +00:00
28504fb5e3 ES5 spaced-comment 2017-09-21 09:08:52 +00:00
8ebb8e3c02 ES5 no-trailing-spaces 2017-09-21 09:04:47 +00:00
c95c2cd1ae ES5 space-in-parens 2017-09-21 09:04:32 +00:00
946bee2194 ES5 space-before-blocks 2017-09-21 09:02:50 +00:00
1f9bd04308 ES5 space-unary-ops 2017-09-21 08:52:30 +00:00
33572b2dc7 ES5 no-multi-spaces 2017-09-21 08:47:23 +00:00
680446b77e ES5 space-before-function-parens 2017-09-21 08:35:12 +00:00
bf1d76a3a7 Fix readme.txt 2017-09-20 16:57:17 +01:00
c915fcfdff Release 3.0.0 2017-09-20 15:21:55 +01:00
02966c3b93 Sets cron daemon timeout to 5s across the plugin
Adds hook to override cron request arguments
2017-09-20 14:59:48 +01:00
84dc48daec Allow passing cron timeouts
[MAILPOET-1114]
2017-09-20 14:59:48 +01:00
12225004f4 Apply hook on cron timeout
[MAILPOET-1114]
2017-09-20 14:59:48 +01:00
320dfa2ec5 Extracts duplicate code into reusable methods
Updates unit test
2017-09-20 14:59:48 +01:00
b5f3016085 Removes URL from user agent
(https://mailpoet.slack.com/archives/C02MTKAJL/p1505488541000029?thread_ts=1505488163.000795&cid=C02MTKAJL)
2017-09-20 14:59:48 +01:00
cd53e369d0 Allows accessing full URL from within custom cron hook 2017-09-20 14:59:48 +01:00
6fc11af774 Returns error message instead of empty body 2017-09-20 14:59:48 +01:00
42e3a97616 Fixing Shortcodes issue 2017-09-20 12:34:27 +00:00
6b16aa1692 Sets newsletter status to draft when it's unscheduled 2017-09-19 21:59:03 -04:00
03d0de74e4 Merge pull request #1108 from mailpoet/send_twice_tooltip
Show a tooltip about sending an email twice only when the Send button is disabled [MAILPOET-1098]
2017-09-19 20:38:10 -04:00
c3b643df84 Prevents leaking SQL errors in API response 2017-09-19 20:32:26 -04:00
697f9ba5bc Adds min/max email length in UI and backend 2017-09-19 20:04:49 -04:00
28c75c5b96 Adds a thousand separator 2017-09-19 09:55:38 -04:00
6f255854f2 Merge pull request #1112 from mailpoet/copy_update
Update free MSS plan size to 2000 subscribers [MAILPOET-1112]
2017-09-19 12:46:36 +03:00
91c5f9c43e Clarify Premium plugin benefits 2017-09-19 12:41:25 +03:00
62acd6404a Update free MSS plan size to 2k subscribers, update plugin description 2017-09-19 12:15:46 +03:00
adc1461771 Don't show send tooltip for paused newsletters [MAILPOET-1098] 2017-09-19 08:51:16 +03:00
66cc0964ce Merge pull request #1106 from mailpoet/fix-tests
Fixing MP API test
2017-09-18 18:23:20 -04:00
10d77720ad Merge pull request #1107 from mailpoet/hooks_unit_test_update
Updates hooks unit test [MAILPOET-1110]
2017-09-18 17:39:50 +02:00
475114c6f9 Fix ES6 no-irregular-whitespace eslint rule [MAILPOET-1082] 2017-09-18 18:31:13 +03:00
a0fec7d103 Fix ES6 space-infix-ops eslint rule [MAILPOET-1082] 2017-09-18 18:27:43 +03:00
4d9d92a026 Fix ES6 array-bracket-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:26:43 +03:00
e51aa8c271 Fix ES6 space-in-parens eslint rule [MAILPOET-1082] 2017-09-18 18:25:37 +03:00
d44adedade Fix ES6 key-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:24:26 +03:00
9fb3c50aa7 Fix ES6 no-multi-spaces eslint rule [MAILPOET-1082] 2017-09-18 18:23:36 +03:00
907053a349 Fix ES6 space-unary-ops eslint rule [MAILPOET-1082] 2017-09-18 18:22:48 +03:00
f0f85cfb59 Fix ES6 template-curly-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:21:44 +03:00
44d0341fb2 Fix ES6 keyword-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:20:55 +03:00
0cdae52c66 Fix ES6 react/jsx-curly-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:18:45 +03:00
0cd9c8e416 Adding https prefix the image sources 2017-09-18 15:11:55 +00:00
9e3010ab52 Fix ES6 react/jsx-tag-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:05:57 +03:00
d831b2df55 Explicitly sets up hooks instead of assuming they are already set up 2017-09-18 10:43:17 -04:00
16ff630e88 Show a tooltip about sending an email twice only when the Send button is dsiabled [MAILPOET-1098] 2017-09-18 17:42:24 +03:00
d35763662e Fixing MP API test 2017-09-18 12:00:43 +00:00
10be411b12 Prepare release v3.0.0 2017-09-18 11:35:59 +01:00
6ecce192f7 Merge pull request #1105 from mailpoet/wp_sync_multisite
Fix WP sync throwing 'Table "users" doesn't exist' errors on multisite subsites [MAILPOET-1107]
2017-09-18 11:48:30 +03:00
ee07e60fe9 Adds new survey 2017-09-18 09:13:06 +01:00
a35d7a1154 Fix WP sync throwing 'Table users doesn't exist' errors on multisite subsites [MAILPOET-1107] 2017-09-18 10:55:49 +03:00
ebba8dbfd6 Merge pull request #1103 from mailpoet/twig_version_conflict_detection_improvement
Updates Twig version conflict detection logic [MAILPOET-1068]
2017-09-18 10:42:51 +03:00
44c637c06b Merge pull request #1101 from mailpoet/premium_key_in_beacon
Add Premium key to Help Scout beacon [MAILPOET-1090]
2017-09-17 12:08:52 -04:00
d54ba734bf Adds a min-max range of supported Twig versions 2017-09-17 11:25:35 -04:00
b45fc22306 Updates coding style and cleans up JS script inclusion part 2017-09-16 11:34:21 -04:00
994935d4ae Adds check for minimum Twig version loaded by external plugins 2017-09-16 11:33:40 -04:00
ceb5ce850c Removes deprecated Twig_ExtensionInterface::getName()
(https://github.com/twigphp/Twig/blob/2.x/CHANGELOG#L207)
Removes deprecated Twig_Extension_GlobalsInterface
(https://github.com/twigphp/Twig/blob/2.x/CHANGELOG#L259)
2017-09-16 11:30:40 -04:00
97b5ed945d Merge pull request #1100 from mailpoet/update-send-copy
Update send copy [MAILPOET-1101]
2017-09-14 20:02:28 +02:00
873b322245 Translate
[MAILPOET-1101]
2017-09-14 18:52:33 +01:00
12ad9e41e7 Translate a string
[MAILPOET-1101]
2017-09-14 18:40:04 +01:00
96b418e455 Our free plan will be for 1,000 subscribers and not 250
[MAILPOET-1101]
2017-09-14 17:35:15 +01:00
8ea7861f77 Merge pull request #1102 from mailpoet/welcome-tab-update
Update welcome tab [MAILPOET-1099]
2017-09-14 19:34:01 +03:00
821976c881 Make text random
[MAILPOET-1099]
2017-09-14 17:19:55 +01:00
6f1443e43d Update welcome tab
[MAILPOET-1099]
2017-09-14 15:35:07 +01:00
09fcaecdfc Add Premium key to Help Scout beacon [MAILPOET-1090] 2017-09-14 16:24:15 +03:00
efd72ca9f6 Merge pull request #1099 from mailpoet/update-readme
Update readme.txt for launch v3
2017-09-14 15:38:36 +03:00
550b5e9aed More readme.txt updates
[MAILPOET-1105]
2017-09-14 13:37:10 +01:00
4b7ae5fcff Fix typo
[MAILPOET-1105]
2017-09-14 13:28:44 +01:00
fa85e12127 Update premium section in readme.txt
[MAILPOET-1105]
2017-09-14 13:27:07 +01:00
1cce50902b Update Send with... other copy
[MAILPOET-1101]
2017-09-14 11:39:20 +01:00
2048fa5cf9 Update Send with... mailpoet copy
[MAILPOET-1101]
2017-09-14 11:31:43 +01:00
f438c8fd31 Update readme.txt for launch v3
[MAILPOET-1105]
2017-09-14 10:15:00 +01:00
0bfa832dad Merge pull request #1098 from mailpoet/subscribers-fix
Subscribers fix [MAILPOET-1102]
2017-09-13 18:17:56 +03:00
483dfbe1ec Fix removal of WP segment subscribers without wp_user_id [MAILPOET-1102] 2017-09-13 16:46:50 +03:00
561fee491d Merge pull request #1097 from mailpoet/makepot_views_fix
Fix makepot adding extra slashes to escaped characters in views [MAILPOET-1093]
2017-09-13 14:54:25 +02:00
97d157192a Remove orphaned links
[MAILPOET-1102]
2017-09-13 13:30:23 +01:00
6b14a8a057 Remove data from usermeta
[MAILPOET-1102]
2017-09-13 13:18:39 +01:00
d27b187f5e Fix QA problems
[MAILPOET-1102]
2017-09-13 13:15:50 +01:00
02d49ba2ca DELETE subscribers in WP list which are not WP users
[MAILPOET-1102]
2017-09-13 13:07:01 +01:00
f3571a5855 Add another testing scenario
[MAILPOET-1102]
2017-09-13 08:54:54 +01:00
3d5f0df213 Don't delete subscribers with wp_user_id = 0 [MAILPOET-1102] 2017-09-13 10:15:09 +03:00
595a201fe7 Stop deleting subscribers
[MAILPOET-1102]
2017-09-12 17:53:12 +01:00
c3db7d8148 Release 3.0.0-rc.2.0.3 2017-09-12 15:41:06 +03:00
4a2187ff32 Merge pull request #1096 from mailpoet/translation_strings_update
Removes escape character in translations [MAILPOET-1093]
2017-09-12 14:24:38 +03:00
279c36a30d Merge pull request #1094 from mailpoet/initializer_update
Updates plugin initialization logic [MAILPOET-1097]
2017-09-12 12:34:27 +03:00
fd65117a5d Fix makepot adding extra slashes to escaped characters in views [MAILPOET-1093] 2017-09-12 11:17:04 +03:00
9305beace3 Removes escape character in translations 2017-09-11 19:27:03 -04:00
ba86cbfb18 Updates unit test 2017-09-11 11:40:14 -04:00
2ac7d1d4ab Breaks plugin initialization into 3 stages: preInit, init and postInit 2017-09-11 11:33:03 -04:00
e9c55260c8 Merge pull request #1092 from mailpoet/db_version_settings_logic_update
Uses plugin's settings to store DB version [MAILPOET-1095]
2017-09-11 18:15:17 +03:00
99b6a287f8 Highlight a container block when hovering over its tools [MAILPOET-1088] 2017-09-11 15:32:45 +01:00
d645f0cad4 Merge pull request #1087 from mailpoet/eslint-un
Eslint un [MAILPOET-1073]
2017-09-11 16:16:51 +02:00
b0343254c0 Renames db version setting value 2017-09-11 10:05:09 -04:00
cc368f015b Remove redundant argument
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
4e508855fc Fix eslint no-unused-expressions in tests
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
72c0a6f165 Fix eslint no-undef in tests
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
f266508654 Fix eslint no-undef in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
1893d82b2d Fix eslint no-unused-expressions in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
bb1dd6a2ec Fix eslint import/no-unresolved in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
7097ea5d9b Fix eslint no-unreachable in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
b4092e0641 Fix eslint no-unneeded-ternary in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
2c068c7bb6 Fix eslint no-unreachable in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
a1a4fcb978 Fix eslint no-unused-expressions in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
f77620d649 Fix eslint no-undef in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
9e932c9078 Merge pull request #1085 from mailpoet/improve-user-sync
Improve user sync [MAILPOET-1073]
2017-09-11 14:56:41 +03:00
de47dbe41b Removes arrow functions that are not supported in IE 2017-09-11 10:25:43 +01:00
6d36d67a60 Delete orphaned subscribers instead of updating their id
[MAILPOET-1073]
2017-09-11 10:09:32 +01:00
607bf51b37 Merge two test cases for one class
[MAILPOET-1073]
2017-09-11 09:28:39 +01:00
f38ed0272c Merge pull request #1093 from mailpoet/cron_helper_improvement
Cron helper improvement [MAILPOET-1096]
2017-09-11 11:23:01 +03:00
eef969439b Code comment
[MAILPOET-1073]
2017-09-11 09:22:40 +01:00
272f552f3c Clean data befre and after test run
[MAILPOET-1073]
2017-09-11 09:22:18 +01:00
dff9c1012b Moves widget initialization back to widgets_init hook
Removes priority from plugin initialization
2017-09-10 19:49:05 -04:00
52470360a1 Returns ping response body instead of boolean 2017-09-10 18:49:15 -04:00
6c62459ed4 Adds filter to override default cron request URL 2017-09-10 18:36:22 -04:00
98482cebf9 Uses plugin's settings to store DB version 2017-09-10 16:31:36 -04:00
509880119e Merge pull request #1090 from mailpoet/eslint-indent
Eslint indent [MAILPOET-1029]
2017-09-07 20:13:20 -04:00
195ccb5eed Fix indent rule in tests
[MAILPOET-1029]
2017-09-07 16:05:45 +01:00
122af1c943 Fix react/jsx-indent rule in ES6
[MAILPOET-1029]
2017-09-07 15:59:38 +01:00
169940058b Fix react/jsx-indent-props rule in ES6
[MAILPOET-1029]
2017-09-07 15:52:46 +01:00
478e60d60e Fix indent rule in ES5
[MAILPOET-1029]
2017-09-07 15:51:25 +01:00
9fc0ac8c4f Merge pull request #1089 from mailpoet/color_picker
Change color on click, add history to color picker [MAILPOET-1087]
2017-09-07 17:08:09 +03:00
e86b780479 Fix build`
[MAILPOET-1073]
2017-09-07 14:44:55 +01:00
42f08bdc65 Fix handling of empty color and transparent color selected from palette [MAILPOET-1087] 2017-09-07 15:48:14 +03:00
c2789cdac3 Don't load all ids to memory, PHP could crash
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
8a362f49f8 Add test for users synchronisation
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
784a80d1a5 Use ->prefix instead of wp_
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
922d2b4b5f Fix migration
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
91e8461cac Clean the code
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
8757598a2d Add index
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
524aabea1d Split users sync into multiple queries
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
513181ff47 Change color on click, add history to color picker [MAILPOET-1087] 2017-09-07 13:17:57 +03:00
6bc288ed54 Merge pull request #1088 from mailpoet/depreciated_twig_notice_fix
Fixed Twig's deprecated notice [MAILPOET-1092]
2017-09-07 12:48:11 +03:00
77f3a875dd Does not set global is_rtl variable 2017-09-06 20:56:52 -04:00
6584250d1a Adds is_rtl() function to Twig 2017-09-06 20:55:44 -04:00
e42db162aa Merge pull request #1086 from mailpoet/translation_fixes
Fix translations based on translator feedback on TX [MAILPOET-1091]
2017-09-06 16:30:13 +03:00
2762096167 Switch strtoupper to mb_strtoupper based on feedback 2017-09-06 16:14:52 +03:00
b2ec3e5f7b Fix translations based on translator feedback on TX [MAILPOET-1091] 2017-09-06 13:45:42 +03:00
225 changed files with 5718 additions and 4419 deletions

View File

@ -9,18 +9,13 @@
},
"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,
"no-useless-concat": 0,
"no-multi-spaces": 0,
"no-nested-ternary": 0,
"no-sequences": 0,
"no-useless-return": 0,
@ -28,53 +23,34 @@
"new-cap": 0,
"no-continue": 0,
"no-new": 0,
"space-unary-ops": 0,
"no-redeclare": 0,
"no-console": 0,
"no-empty": 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,
"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,
"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,
"indent": 0,
"prefer-template": 0,
"func-names": 0
}

View File

@ -10,6 +10,9 @@
"jsx": true
}
},
"settings": {
"import/resolver": "webpack"
},
"rules": {
"comma-dangle": ["error", "always-multiline"],
"import/no-amd": 0,
@ -18,19 +21,15 @@
"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,
@ -41,45 +40,31 @@
"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,
"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,
"space-in-parens": 0,
"no-case-declarations": 0,
"array-bracket-spacing": 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
"no-underscore-dangle": 0
}
}

View File

@ -9,9 +9,6 @@
},
"rules": {
"import/no-amd": 0,
"no-undef": 0,
"one-var": 0,
"indent": 0,
"no-whitespace-before-property": 0,
"global-require": 0,
"keyword-spacing": 0,
@ -20,15 +17,11 @@
"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
}

View File

@ -90,6 +90,7 @@ class RoboFile extends \Robo\Tasks {
$css_files = array(
'assets/css/src/admin.styl',
'assets/css/src/admin-global.styl',
'assets/css/src/newsletter_editor/newsletter_editor.styl',
'assets/css/src/public.styl',
'assets/css/src/rtl.styl',

View File

@ -0,0 +1,15 @@
@import 'nib'
@require 'icons'
/*
Style for Members plugin
*/
.members-tab-title
.mailpoet-icon-logo
vertical-align: middle;
height: 20px;
width: 20px;
font-size: 20px;
margin-right: 3px;

24
assets/css/src/icons.styl Normal file
View File

@ -0,0 +1,24 @@
icon-font-path ?= "../fonts"
@font-face
font-family 'mailpoet'
src url(icon-font-path + '/mailpoet.ttf?mx0b6n') format('truetype'), url(icon-font-path + '/mailpoet.woff?mx0b6n') format('woff'), url(icon-font-path + '/mailpoet.svg?mx0b6n#mailpoet') format('svg')
font-weight normal
font-style normal
[class^="mailpoet-icon-"], [class*=" mailpoet-icon-"]
font-family 'mailpoet' !important
speak none
font-style normal
font-weight normal
font-variant normal
text-transform none
line-height 1
/* Better Font Rendering =========== */
-webkit-font-smoothing antialiased
-moz-osx-font-smoothing grayscale
.mailpoet-icon-logo
&:before
content "\e900"

View File

@ -48,3 +48,41 @@ $resize-handle-z-index = 2
.mailpoet_resize_handle
display: inline-block
.mailpoet_image_resize_handle_container
position: absolute
bottom: 0
right: 0
width: 20px
height: 20px
.mailpoet_image_resize_handle
position: relative
background: $resize-handle-background-color
border-radius(3px)
display: inline-block
width: 20px
height: 20px
cursor: nwse-resize
z-index: $resize-handle-z-index
.mailpoet_image_resize_handle_text,
.mailpoet_image_resize_handle_icon
pointer-events: none
.mailpoet_image_resize_handle_icon
position: absolute
top: 0
right: 0
& > svg
width: 100%
height: 100%
fill: $resize-handle-font-color
.mailpoet_block.mailpoet_image_resize_active > .mailpoet_block_highlight
border: 1px dashed $resize-active-color
.mailpoet_image_resize_handle
display: inline-block

View File

@ -23,9 +23,11 @@ $block-text-line-height = $text-line-height
border: 1px solid $transparent-color
&:hover > .mailpoet_block_highlight
&.mailpoet_highlight > .mailpoet_block_highlight
border: 1px dashed $block-hover-highlight-color
&.mailpoet_highlight > .mailpoet_block_highlight
border: 1px dashed $block-hover-highlight-color !important
.mailpoet_content
position: relative
line-height: $block-text-line-height

View File

@ -3,14 +3,19 @@
img
vertical-align: bottom
max-width: 100%
width: auto
height: auto
&.mailpoet_full_image
padding-left: 0
padding-right: 0
margin: auto
margin-bottom: 0
.mailpoet_content a:hover
.mailpoet_content
margin: auto
max-width: 100%
min-width: 36px
a:hover
cursor: all-scroll

View File

@ -2,7 +2,7 @@ animation-slide-open-downwards($max-height = 2000px)
transition: all 250ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
max-height: $max-height
opacity: 1
overflow-y: hidden
overflow-y: inherit
&.mailpoet_closed
max-height: 0px

View File

@ -33,3 +33,6 @@ Custom styles for MailPoet pages.
p.top-space-triple
margin-top: 3em
p.mailpoet-top-text
margin-right: 0

View File

@ -62,6 +62,15 @@
margin-bottom: 2em
margin-top: 2em
.sending-free-plan-button
background: #FF5301
border-color: #e64c03
text-shadow: 0 -1px 1px #e64c03
box-shadow: 0 1px 0 #e64c03
margin: 10px 0
strong
text-transform: uppercase
.mailpoet_success_item::before
content ' '

11
assets/fonts/mailpoet.svg Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="mailpoet" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="0" d="" />
<glyph unicode="&#xe900;" glyph-name="optimised" horiz-adv-x="972" d="M230.188 949.695c-21.982-3.361-41.376-14.741-48.618-28.188l-5.948-11.637 0.517-265.588c0.776-263.779 0.776-265.847 6.206-273.088 11.12-15.258 40.601-22.24 68.79-16.551 16.551 3.621 25.861 9.827 32.584 21.723 3.879 7.499 4.397 23.791 5.689 185.161l1.293 176.628 60.514-161.111c33.102-88.702 63.875-168.612 68.013-177.404 13.707-29.481 35.687-41.376 72.151-39.049 21.206 1.293 39.308 9.827 47.584 22.499 3.361 5.172 35.947 91.806 72.41 192.662s67.237 185.42 68.53 187.49c1.551 2.587 2.587-69.307 2.587-185.937v-190.335l5.948-11.379c8.533-16.809 20.172-21.982 49.652-21.982 27.929 0.259 39.825 4.914 49.911 20.172l6.982 10.603v530.401l-5.689 9.31c-12.671 20.43-50.17 31.033-91.806 25.601-34.394-4.138-53.79-16.292-66.72-41.118-2.587-5.172-35.947-101.89-73.961-214.902s-69.824-206.367-70.6-207.403c-1.034-1.034-32.326 86.115-69.824 193.954-37.757 107.581-71.892 205.075-76.030 216.453-10.086 26.118-25.601 42.929-45.514 48.877-17.326 5.172-46.807 6.982-64.652 4.138zM54.854 243.443c-20.172-3.879-43.963-19.136-51.204-33.619-6.206-11.379-4.914-32.843 2.587-47.841 23.533-46.807 71.634-86.892 126.717-104.736 17.068-5.689 23.274-5.948 120.252-7.499 97.235-1.551 102.926-1.81 116.373-7.241 29.739-11.896 51.204-35.687 61.807-68.013 3.621-11.12 13.964-21.206 25.861-25.344 4.914-1.551 18.361-2.844 29.739-2.844 16.809 0 23.533 1.293 32.584 5.689 11.896 6.206 13.964 9.31 26.895 38.791 11.896 27.671 39.567 49.652 70.858 56.117 8.533 1.81 47.067 2.844 100.856 2.844 99.563 0 113.786 2.068 151.801 20.689 49.652 24.567 96.978 77.84 101.373 113.529 3.104 26.118-17.326 49.394-51.204 58.187-25.601 6.465-41.635-0.517-54.825-24.050-11.12-19.655-29.998-38.015-47.841-46.29l-14.741-6.982-99.563-1.551c-90.77-1.293-101.373-2.068-120.252-6.982-27.154-7.499-58.444-23.016-80.427-40.084l-17.844-13.964-16.809 13.964c-20.689 16.809-51.462 32.584-78.875 39.825-19.136 5.172-28.705 5.948-120.252 7.241l-99.563 1.551-15.775 7.241c-18.102 8.533-32.584 21.982-48.36 45.773-16.034 24.567-26.895 29.998-50.17 25.601z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/fonts/mailpoet.ttf Normal file

Binary file not shown.

BIN
assets/fonts/mailpoet.woff Normal file

Binary file not shown.

View File

@ -2,11 +2,10 @@ function requestFailed(errorMessage, xhr) {
if (xhr.responseJSON) {
return xhr.responseJSON;
}
var message = errorMessage.replace('%d', xhr.status);
return {
errors: [
{
message: message
message: errorMessage.replace('%d', xhr.status)
}
]
};
@ -35,7 +34,7 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(mp, jQuery, _) {
// set default url
if (this.options.url === null) {
this.options.url = ajaxurl;
this.options.url = window.ajaxurl;
}
// set default token
@ -54,11 +53,13 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(mp, jQuery, _) {
};
},
request: function (method, options) {
var params;
var deferred;
// set options
this.init(options);
// set request params
var params = this.getParams();
params = this.getParams();
// remove null values from the data object
if (_.isObject(params.data)) {
@ -68,7 +69,7 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(mp, jQuery, _) {
}
// ajax request
var deferred = jQuery.post(
deferred = jQuery.post(
this.options.url,
params,
null,

View File

@ -43,15 +43,6 @@ function trackCachedEvents() {
});
}
function initializeMixpanelWhenLoaded() {
if (typeof window.mixpanel === 'object') {
exportMixpanel(MailPoet);
trackCachedEvents();
} else {
setTimeout(initializeMixpanelWhenLoaded, 100);
}
}
function cacheEvent(forced, name, data) {
eventsCache.push({
name: name,
@ -65,6 +56,15 @@ define(
function (mp, _) {
var MailPoet = mp;
function initializeMixpanelWhenLoaded() {
if (typeof window.mixpanel === 'object') {
exportMixpanel(MailPoet);
trackCachedEvents();
} else {
setTimeout(initializeMixpanelWhenLoaded, 100);
}
}
MailPoet.trackEvent = _.partial(cacheEvent, false);
MailPoet.forceTrackEvent = _.partial(cacheEvent, true);

View File

@ -43,9 +43,10 @@ define('date',
},
format: function (date, opts) {
var options = opts || {};
var momentDate;
this.init(options);
var momentDate = Moment(date, this.convertFormat(options.parseFormat));
momentDate = Moment(date, this.convertFormat(options.parseFormat));
if (options.offset === 0) momentDate = momentDate.utc();
return momentDate.format(this.convertFormat(this.options.format));
},
@ -71,6 +72,11 @@ define('date',
});
},
convertFormat: function (format) {
var replacements;
var convertedFormat;
var escapeToken;
var index;
var token;
var format_mappings = {
date: {
d: 'DD',
@ -140,12 +146,11 @@ define('date',
if (!format || format.length <= 0) return format;
var replacements = format_mappings['date'];
replacements = format_mappings['date'];
convertedFormat = [];
escapeToken = false;
var convertedFormat = [];
var escapeToken = false;
for(var index = 0, token = ''; format.charAt(index); index += 1){
for (index = 0, token = ''; format.charAt(index); index += 1) {
token = format.charAt(index);
if (escapeToken === true) {
convertedFormat.push('[' + token + ']');

View File

@ -212,7 +212,6 @@ define([
year={this.state.year}
placeholder={this.props.field.year_placeholder}
/>);
break;
case 'MM':
return (<FormFieldDateMonth
@ -224,7 +223,6 @@ define([
monthNames={monthNames}
placeholder={this.props.field.month_placeholder}
/>);
break;
case 'DD':
return (<FormFieldDateDay
@ -235,7 +233,6 @@ define([
day={this.state.day}
placeholder={this.props.field.day_placeholder}
/>);
break;
}
});

View File

@ -7,6 +7,7 @@ define([
'form/fields/checkbox.jsx',
'form/fields/selection.jsx',
'form/fields/date.jsx',
'jquery',
],
(
React,
@ -16,7 +17,8 @@ define([
FormFieldRadio,
FormFieldCheckbox,
FormFieldSelection,
FormFieldDate
FormFieldDate,
jQuery
) => {
const FormField = React.createClass({
renderField: function (data, inline = false) {

View File

@ -116,6 +116,7 @@ define([
}
},
handleChange: function (e) {
let value;
if (this.props.onValueChange !== undefined) {
if (this.props.field.multiple) {
value = jQuery('#' + this.refs.select.id).val();

View File

@ -5,13 +5,15 @@ define(
'classnames',
'react-router',
'form/fields/field.jsx',
'jquery',
],
(
React,
MailPoet,
classNames,
Router,
FormField
FormField,
jQuery
) => {
const Form = React.createClass({

View File

@ -7,6 +7,10 @@
'use strict';
var Observable;
var WysijaHistory;
var WysijaForm;
Event.cacheDelegated = {};
Object.extend(document, (function () {
var cache = Event.cacheDelegated;
@ -30,18 +34,21 @@ Object.extend(document, (function() {
}
function destroyWrapper(selector, eventName, handler) {
var wrapper;
var c = getCacheForSelector(selector);
if (!c[eventName]) return false;
var wrapper = findWrapper(selector, eventName, handler);
wrapper = findWrapper(selector, eventName, handler);
c[eventName] = c[eventName].without(wrapper);
return wrapper;
}
function createWrapper(selector, eventName, handler, context) {
var wrapper, c = getWrappersForSelector(selector, eventName);
var wrapper;
var element;
var c = getWrappersForSelector(selector, eventName);
if (c.pluck('handler').include(handler)) return false;
wrapper = function (event) {
var element = event.findElement(selector);
element = event.findElement(selector);
if (element) handler.call(context || element, event, element);
};
wrapper.handler = handler;
@ -49,13 +56,14 @@ Object.extend(document, (function() {
return wrapper;
}
return {
delegate: function(selector, eventName, handler, context) {
delegate: function (selector, eventName) {
var wrapper = createWrapper.apply(null, arguments);
if (wrapper) document.observe(eventName, wrapper);
return document;
},
stopDelegating: function(selector, eventName, handler) {
stopDelegating: function (selector, eventName) {
var length = arguments.length;
var wrapper;
switch (length) {
case 2:
getWrappersForSelector(selector, eventName).each(function (wrapper) {
@ -73,7 +81,7 @@ Object.extend(document, (function() {
});
break;
default:
var wrapper = destroyWrapper.apply(null, arguments);
wrapper = destroyWrapper.apply(null, arguments);
if (wrapper) document.stopObserving(eventName, wrapper);
}
return document;
@ -81,7 +89,7 @@ Object.extend(document, (function() {
};
})());
var Observable = (function() {
Observable = (function () {
function getEventName(nameA, namespace) {
var name = nameA.substring(2);
if (namespace) name = namespace + ':' + name;
@ -89,9 +97,9 @@ var Observable = (function() {
}
function getHandlers(klass) {
var proto = klass.prototype,
namespace = proto.namespace;
return Object.keys(proto).grep(/^on/).inject($H(), function(handlers, name) {
var proto = klass.prototype;
var namespace = proto.namespace;
return Object.keys(proto).grep(/^on/).inject(window.$H(), function (handlers, name) {
if (name === 'onDomLoaded') return handlers;
handlers.set(getEventName(name, namespace), getWrapper(proto[name], klass));
return handlers;
@ -105,16 +113,22 @@ var Observable = (function() {
}
function onDomLoad(selector, klass) {
$$(selector).each(function(element) {
window.$$(selector).each(function (element) {
new klass(element).onDomLoaded();
});
}
return {
observe: function (selector) {
var klass = this;
if (!this.handlers) this.handlers = {};
if (this.handlers[selector]) return;
var klass = this;
if(this.prototype.onDomLoaded) document.loaded ? onDomLoad(selector, klass) : document.observe('dom:loaded', onDomLoad.curry(selector, klass));
if (this.prototype.onDomLoaded) {
if (document.loaded) {
onDomLoad(selector, klass);
} else {
document.observe('dom:loaded', onDomLoad.curry(selector, klass));
}
}
this.handlers[selector] = getHandlers(klass).each(function (handler) {
document.delegate(selector, handler.key, handler.value);
});
@ -130,36 +144,37 @@ var Observable = (function() {
})();
// override droppables
Object.extend(Droppables, {
deactivate: Droppables.deactivate.wrap(function(proceed, drop, draggable) {
Object.extend(window.Droppables, {
deactivate: window.Droppables.deactivate.wrap(function (proceed, drop, draggable) {
if (drop.onLeave) drop.onLeave(draggable, drop.element);
return proceed(drop);
}),
activate: Droppables.activate.wrap(function(proceed, drop, draggable) {
activate: window.Droppables.activate.wrap(function (proceed, drop, draggable) {
if (drop.onEnter) drop.onEnter(draggable, drop.element);
return proceed(drop);
}),
show: function (point, element) {
var drop;
var affected = [];
if (!this.drops.length) return;
var drop, affected = [];
this.drops.each(function (drop) {
if(Droppables.isAffected(point, element, drop)) affected.push(drop);
if (window.Droppables.isAffected(point, element, drop)) affected.push(drop);
});
if(affected.length > 0) drop = Droppables.findDeepestChild(affected);
if (affected.length > 0) drop = window.Droppables.findDeepestChild(affected);
if (this.last_active && this.last_active !== drop) this.deactivate(this.last_active, element);
if (drop) {
Position.within(drop.element, point[0], point[1]);
if(drop.onHover) drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
if(drop !== this.last_active) Droppables.activate(drop, element);
window.Position.within(drop.element, point[0], point[1]);
if (drop.onHover) drop.onHover(element, drop.element, window.Position.overlap(drop.overlap, drop.element));
if (drop !== this.last_active) window.Droppables.activate(drop, element);
}
},
displayArea: function(draggable) {
displayArea: function () {
if (!this.drops.length) return;
// hide controls when displaying drop areas.
WysijaForm.hideBlockControls();
this.drops.each(function(drop, iterator) {
this.drops.each(function (drop) {
if (drop.element.hasClassName('block_placeholder')) {
drop.element.addClassName('active');
}
@ -167,7 +182,7 @@ Object.extend(Droppables, {
},
hideArea: function () {
if (!this.drops.length) return;
this.drops.each(function(drop, iterator) {
this.drops.each(function (drop) {
if (drop.element.hasClassName('block_placeholder')) {
drop.element.removeClassName('active');
} else if (drop.element.hasClassName('image_placeholder')) {
@ -189,7 +204,7 @@ Object.extend(Droppables, {
- set a maximum number of items to be stored
*/
var WysijaHistory = {
WysijaHistory = {
container: 'mailpoet_form_history',
size: 30,
enqueue: function (element) {
@ -199,41 +214,41 @@ var WysijaHistory = {
// check if the field is unique
if (parseInt(clone.readAttribute('wysija_unique'), 10) === 1) {
// check if the field is already in the queue
$(WysijaHistory.container).select('[wysija_name="' + clone.readAttribute('wysija_name') + '"]').invoke('remove');
window.$(WysijaHistory.container).select('[wysija_name="' + clone.readAttribute('wysija_name') + '"]').invoke('remove');
}
// check history size
if($(WysijaHistory.container).select('> div').length >= WysijaHistory.size) {
if (window.$(WysijaHistory.container).select('> div').length >= WysijaHistory.size) {
// remove oldest element (last in the list)
$(WysijaHistory.container).select('> div').last().remove();
window.$(WysijaHistory.container).select('> div').last().remove();
}
// store block in history
$(WysijaHistory.container).insert({
window.$(WysijaHistory.container).insert({
top: clone
});
},
dequeue: function () {
// pop last block off the history
var block = $(WysijaHistory.container).select('div').first();
var block = window.$(WysijaHistory.container).select('div').first();
if (block !== undefined) {
// insert block back into the editor
$(WysijaForm.options.body).insert({
window.$(WysijaForm.options.body).insert({
top: block
});
}
},
clear: function () {
$(WysijaHistory.container).innerHTML = '';
window.$(WysijaHistory.container).innerHTML = '';
},
remove: function (field) {
$(WysijaHistory.container).select('[wysija_name="' + field + '"]').invoke('remove');
window.$(WysijaHistory.container).select('[wysija_name="' + field + '"]').invoke('remove');
}
};
/* MailPoet Form */
var WysijaForm = {
WysijaForm = {
version: '0.7',
options: {
container: 'mailpoet_form_container',
@ -272,31 +287,32 @@ var WysijaForm = {
},
loading: function (is_loading) {
if (is_loading) {
$(WysijaForm.options.editor).addClassName('loading');
$(WysijaForm.options.toolbar).addClassName('loading');
window.$(WysijaForm.options.editor).addClassName('loading');
window.$(WysijaForm.options.toolbar).addClassName('loading');
} else {
$(WysijaForm.options.editor).removeClassName('loading');
$(WysijaForm.options.toolbar).removeClassName('loading');
window.$(WysijaForm.options.editor).removeClassName('loading');
window.$(WysijaForm.options.toolbar).removeClassName('loading');
}
},
loadStatic: function (blocks) {
$A(blocks).each(function(block) {
window.$A(blocks).each(function (block) {
// create block
WysijaForm.Block.create(block, $('block_placeholder'));
WysijaForm.Block.create(block, window.$('block_placeholder'));
});
},
load: function (data) {
var settings_elements;
if (data === undefined) return;
// load body
if (data.body !== undefined) {
$A(data.body).each(function(block) {
window.$A(data.body).each(function (block) {
// create block
WysijaForm.Block.create(block, $('block_placeholder'));
WysijaForm.Block.create(block, window.$('block_placeholder'));
});
// load settings
var settings_elements = $('mailpoet_form_settings').getElements();
settings_elements = window.$('mailpoet_form_settings').getElements();
settings_elements.each(function (setting) {
// skip lists
if (setting.name === 'segments') {
@ -305,7 +321,7 @@ var WysijaForm = {
// if the input value is equal to the one stored in the settings
if (setting.value === data.settings[setting.name]) {
// check selected value
$(setting).checked = true;
window.$(setting).checked = true;
}
} else if (data.settings[setting.name] !== undefined) {
if (typeof data.settings[setting.name] === 'string') {
@ -318,12 +334,12 @@ var WysijaForm = {
}
},
save: function () {
var position = 1,
data = {
name: $F('mailpoet_form_name'),
settings: $('mailpoet_form_settings').serialize(true),
var position = 1;
var data = {
name: window.$F('mailpoet_form_name'),
settings: window.$('mailpoet_form_settings').serialize(true),
body: [],
styles: (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
styles: (window.MailPoet.CodeEditor !== undefined) ? window.MailPoet.CodeEditor.getValue() : null
};
// body
WysijaForm.getBlocks().each(function (b) {
@ -395,33 +411,35 @@ var WysijaForm = {
return data;
},
toggleWidgets: function () {
$$('a[wysija_unique="1"]').invoke('removeClassName', 'disabled');
var hasSegmentSelection;
window.$$('a[wysija_unique="1"]').invoke('removeClassName', 'disabled');
// loop through each unique field already inserted in the editor and disable its toolbar equivalent
$$('#' + WysijaForm.options.editor + ' [wysija_unique="1"]').map(function(element) {
var field = $$('#' + WysijaForm.options.toolbar + ' [wysija_id="' + element.readAttribute('wysija_id') + '"]');
window.$$('#' + WysijaForm.options.editor + ' [wysija_unique="1"]').map(function (element) {
var field = window.$$('#' + WysijaForm.options.toolbar + ' [wysija_id="' + element.readAttribute('wysija_id') + '"]');
if (field.length > 0) {
field.first().addClassName('disabled');
}
});
var hasSegmentSelection = WysijaForm.hasSegmentSelection();
hasSegmentSelection = WysijaForm.hasSegmentSelection();
if (hasSegmentSelection) {
$('mailpoet_form_segments').writeAttribute('required', false).disable();
$('mailpoet_settings_segment_selection').hide();
window.$('mailpoet_form_segments').writeAttribute('required', false).disable();
window.$('mailpoet_settings_segment_selection').hide();
} else {
$('mailpoet_form_segments').writeAttribute('required', true).enable();
$('mailpoet_settings_segment_selection').show();
window.$('mailpoet_form_segments').writeAttribute('required', true).enable();
window.$('mailpoet_settings_segment_selection').show();
}
},
hasSegmentSelection: function () {
return ($$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0);
return (window.$$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0);
},
isSegmentSelectionValid: function () {
var segment_selection = $$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]')[0];
var segment_selection = window.$$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]')[0];
var block;
if (segment_selection !== undefined) {
var block = WysijaForm.get(segment_selection).block.getData();
block = WysijaForm.get(segment_selection).block.getData();
return (
(block.params.values !== undefined)
&&
@ -431,10 +449,12 @@ var WysijaForm = {
return false;
},
setBlockPositions: function (event, target) {
var index = 1;
var block_placeholder;
var previous_placeholder;
// release dragging lock
WysijaForm.locks.dragging = false;
var index = 1;
WysijaForm.getBlocks().each(function (container) {
container.setPosition(index++);
// remove z-index value to avoid issues when resizing images
@ -447,7 +467,7 @@ var WysijaForm = {
if (target !== undefined) {
// get placeholders (previous placeholder matches the placeholder linked to the next block)
var block_placeholder = $(target.element.readAttribute('wysija_placeholder')),
block_placeholder = window.$(target.element.readAttribute('wysija_placeholder'));
previous_placeholder = target.element.previous('.block_placeholder');
if (block_placeholder !== null) {
@ -469,64 +489,59 @@ var WysijaForm = {
WysijaForm.scroll = document.viewport.getScrollOffsets();
},
hideSettings: function () {
$(WysijaForm.options.container).select('.wysija_settings').invoke('hide');
window.$(WysijaForm.options.container).select('.wysija_settings').invoke('hide');
},
setSettingsPosition: function () {
// get viewport offsets and dimensions
var viewportHeight = document.viewport.getHeight(),
blockPadding = 5;
var viewportHeight = document.viewport.getHeight();
$(WysijaForm.options.container).select('.wysija_settings').each(function(element) {
window.$(WysijaForm.options.container).select('.wysija_settings').each(function (element) {
// get parent dimensions and position
var parentDim = element.up('.mailpoet_form_block').getDimensions(),
parentPos = element.up('.mailpoet_form_block').cumulativeOffset(),
is_visible = (parentPos.top <= (WysijaForm.scroll.top + viewportHeight)) ? true : false,
buttonMargin = 5,
relativeTop = buttonMargin;
var parentDim = element.up('.mailpoet_form_block').getDimensions();
var parentPos = element.up('.mailpoet_form_block').cumulativeOffset();
var is_visible = (parentPos.top <= (WysijaForm.scroll.top + viewportHeight));
var buttonMargin = 5;
var relativeTop = buttonMargin;
if (is_visible) {
// desired position is set to center of viewport
var absoluteTop = parseInt(WysijaForm.scroll.top + ((viewportHeight / 2) - (element.getHeight() / 2)), 10),
parentTop = parseInt(parentPos.top - blockPadding, 10),
parentBottom = parseInt(parentPos.top + parentDim.height - blockPadding, 10);
// always center
relativeTop = parseInt((parentDim.height / 2) - (element.getHeight() / 2), 10);
}
// set position for button
$(element).setStyle({
window.$(element).setStyle({
left: parseInt((parentDim.width / 2) - (element.getWidth() / 2)) + 'px',
top: relativeTop + 'px'
});
});
},
initToolbarPosition: function () {
if(WysijaForm.toolbar.top === null) WysijaForm.toolbar.top = parseInt($(WysijaForm.options.container).positionedOffset().top);
if (WysijaForm.toolbar.top === null) WysijaForm.toolbar.top = parseInt(window.$(WysijaForm.options.container).positionedOffset().top);
if (WysijaForm.toolbar.y === null) WysijaForm.toolbar.y = parseInt(WysijaForm.toolbar.top);
if(isRtl) {
if (window.isRtl) {
if (WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = 0;
} else {
if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = parseInt($(WysijaForm.options.container).positionedOffset().left);
if (WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = parseInt(window.$(WysijaForm.options.container).positionedOffset().left);
}
if(WysijaForm.toolbar.x === null) WysijaForm.toolbar.x = parseInt(WysijaForm.toolbar.left + $(WysijaForm.options.container).getDimensions().width + 15);
if (WysijaForm.toolbar.x === null) WysijaForm.toolbar.x = parseInt(WysijaForm.toolbar.left + window.$(WysijaForm.options.container).getDimensions().width + 15);
},
setToolbarPosition: function () {
var position;
WysijaForm.initToolbarPosition();
var position = {
position = {
top: WysijaForm.toolbar.y + 'px',
visibility: 'visible'
};
if(isRtl) {
if (window.isRtl) {
position.right = WysijaForm.toolbar.x + 'px';
} else {
position.left = WysijaForm.toolbar.x + 'px';
}
$(WysijaForm.options.toolbar).setStyle(position);
window.$(WysijaForm.options.toolbar).setStyle(position);
},
updateToolbarPosition: function () {
// init toolbar position (updates scroll and toolbar y)
@ -538,31 +553,31 @@ var WysijaForm = {
if (WysijaForm.scroll.top >= (WysijaForm.toolbar.top - 20)) {
WysijaForm.toolbar.y = parseInt(20 + WysijaForm.scroll.top);
// start effect
WysijaForm.toolbar.effect = new Effect.Move(WysijaForm.options.toolbar, {
WysijaForm.toolbar.effect = new window.Effect.Move(WysijaForm.options.toolbar, {
x: WysijaForm.toolbar.x,
y: WysijaForm.toolbar.y,
mode: 'absolute',
duration: 0.2
});
} else {
$(WysijaForm.options.toolbar).setStyle({
window.$(WysijaForm.options.toolbar).setStyle({
left: WysijaForm.toolbar.x + 'px',
top: WysijaForm.toolbar.top + 'px'
});
}
},
blockDropOptions: {
accept: $w('mailpoet_form_field'), // acceptable items (classes array)
accept: window.$w('mailpoet_form_field'), // acceptable items (classes array)
onEnter: function (draggable, droppable) {
$(droppable).addClassName('hover');
window.$(droppable).addClassName('hover');
},
onLeave: function (draggable, droppable) {
$(droppable).removeClassName('hover');
window.$(droppable).removeClassName('hover');
},
onDrop: function (draggable, droppable) {
// custom data for images
droppable.fire('wjfe:item:drop', WysijaForm.getFieldData(draggable));
$(droppable).removeClassName('hover');
window.$(droppable).removeClassName('hover');
}
},
hideControls: function () {
@ -573,26 +588,28 @@ var WysijaForm = {
}
},
hideTools: function () {
$$('.wysija_tools').invoke('hide');
window.$$('.wysija_tools').invoke('hide');
WysijaForm.locks.showingTools = false;
},
instances: {},
get: function (element, typ) {
var type = typ;
var id;
var instance;
if (type === undefined) type = 'block';
// identify element
var id = element.identify();
var instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
id = element.identify();
instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
WysijaForm.instances[id] = instance;
return instance;
},
makeDroppable: function () {
Droppables.add('block_placeholder', WysijaForm.blockDropOptions);
window.Droppables.add('block_placeholder', WysijaForm.blockDropOptions);
},
makeSortable: function () {
var body = $(WysijaForm.options.body);
Sortable.create(body, {
var body = window.$(WysijaForm.options.body);
window.Sortable.create(body, {
tag: 'div',
only: 'mailpoet_form_block',
scroll: window,
@ -600,15 +617,15 @@ var WysijaForm = {
constraint: 'vertical'
});
Draggables.removeObserver(body);
Draggables.addObserver({
window.Draggables.removeObserver(body);
window.Draggables.addObserver({
element: body,
onStart: WysijaForm.startBlockPositions,
onEnd: WysijaForm.setBlockPositions
});
},
hideBlockControls: function () {
$$('.wysija_controls').invoke('hide');
window.$$('.wysija_controls').invoke('hide');
this.getBlockElements().invoke('removeClassName', 'hover');
},
getBlocks: function () {
@ -617,7 +634,7 @@ var WysijaForm = {
});
},
getBlockElements: function () {
return $(WysijaForm.options.container).select('.mailpoet_form_block');
return window.$(WysijaForm.options.container).select('.mailpoet_form_block');
},
startBlockPositions: function (event, target) {
if (target.element.hasClassName('mailpoet_form_block')) {
@ -630,8 +647,8 @@ var WysijaForm = {
},
encodeURIComponent: function (str) {
// check if it's a url and if so, prevent encoding of protocol
var regexp = new RegExp(/^http[s]?:\/\//),
protocol = regexp.exec(str);
var regexp = new RegExp(/^http[s]?:\/\//);
var protocol = regexp.exec(str);
if (protocol === null) {
// this is not a url so encode the whole thing
@ -665,19 +682,19 @@ var WysijaForm = {
}
};
WysijaForm.DraggableItem = Class.create({
WysijaForm.DraggableItem = window.Class.create({
initialize: function (element) {
this.elementType = $(element).readAttribute('wysija_type');
this.element = $(element).down() || $(element);
this.elementType = window.$(element).readAttribute('wysija_type');
this.element = window.$(element).down() || window.$(element);
this.clone = this.cloneElement();
this.insert();
},
STYLES: new Template('position: absolute; top: #{top}px; left: #{left}px;'),
STYLES: new window.Template('position: absolute; top: #{top}px; left: #{left}px;'),
cloneElement: function () {
var clone = this.element.clone(),
offset = this.element.cumulativeOffset(),
list = this.getList(),
styles = this.STYLES.evaluate({
var clone = this.element.clone();
var offset = this.element.cumulativeOffset();
var list = this.getList();
var styles = this.STYLES.evaluate({
top: offset.top - list.scrollTop,
left: offset.left - list.scrollLeft
});
@ -695,27 +712,27 @@ WysijaForm.DraggableItem = Class.create({
return this.element.up('ul');
},
insert: function () {
$$('body')[0].insert(this.clone);
window.$$('body')[0].insert(this.clone);
},
onMousedown: function (event) {
var draggable = new Draggable(this.clone, {
var draggable = new window.Draggable(this.clone, {
scroll: window,
onStart: function () {
Droppables.displayArea(draggable);
window.Droppables.displayArea(draggable);
},
onEnd: function (drag) {
drag.destroy();
drag.element.remove();
Droppables.hideArea();
window.Droppables.hideArea();
},
starteffect: function (element) {
new Effect.Opacity(element, {
new window.Effect.Opacity(element, {
duration: 0.2,
from: element.getOpacity(),
to: 0.7
});
},
endeffect: Prototype.emptyFunction
endeffect: window.Prototype.emptyFunction
});
draggable.initDrag(event);
draggable.startDrag(event);
@ -725,12 +742,12 @@ WysijaForm.DraggableItem = Class.create({
Object.extend(WysijaForm.DraggableItem, Observable).observe('a[class="mailpoet_form_field"]');
WysijaForm.Block = Class.create({
WysijaForm.Block = window.Class.create({
/* Invoked on load */
initialize: function (element) {
info('block -> init');
this.element = $(element);
this.element = window.$(element);
this.block = new WysijaForm.Widget(this.element);
// enable block placeholder
@ -761,16 +778,18 @@ WysijaForm.Block = Class.create({
}
},
makeBlockDroppable: function () {
var block_placeholder;
if (this.isBlockDroppableEnabled() === false) {
var block_placeholder = this.getBlockDroppable();
Droppables.add(block_placeholder.identify(), WysijaForm.blockDropOptions);
block_placeholder = this.getBlockDroppable();
window.Droppables.add(block_placeholder.identify(), WysijaForm.blockDropOptions);
block_placeholder.addClassName('enabled');
}
},
removeBlockDroppable: function () {
var block_placeholder;
if (this.isBlockDroppableEnabled()) {
var block_placeholder = this.getBlockDroppable();
Droppables.remove(block_placeholder.identify());
block_placeholder = this.getBlockDroppable();
window.Droppables.remove(block_placeholder.identify());
block_placeholder.removeClassName('enabled');
}
},
@ -786,7 +805,7 @@ WysijaForm.Block = Class.create({
createBlockDroppable: function () {
info('block -> createBlockDroppable');
this.element.insert({
before: '<div class=\"block_placeholder\">' + $('block_placeholder').innerHTML + '</div>'
before: '<div class=\"block_placeholder\">' + window.$('block_placeholder').innerHTML + '</div>'
});
return this.element.previous('.block_placeholder');
},
@ -801,6 +820,7 @@ WysijaForm.Block = Class.create({
return this.element.down('.wysija_controls');
},
setupControls: function () {
var block;
// enable controls
this.controls = this.getControls();
@ -851,9 +871,8 @@ WysijaForm.Block = Class.create({
if (this.settingsButton !== null) {
this.settingsButton.observe('click', function (event) {
// TODO: refactor
var block = $(event.target).up('.mailpoet_form_block') || null;
block = window.$(event.target).up('.mailpoet_form_block') || null;
if (block !== null) {
var field = WysijaForm.getFieldData(block);
this.editSettings();
}
}.bind(this));
@ -867,7 +886,7 @@ WysijaForm.Block = Class.create({
// save block in history
WysijaHistory.enqueue(this.element);
Effect.Fade(this.element.identify(), {
window.Effect.Fade(this.element.identify(), {
duration: 0.2,
afterFinish: function (effect) {
// remove placeholder
@ -899,20 +918,25 @@ WysijaForm.Block = Class.create({
/* Invoked on item dropped */
WysijaForm.Block.create = function (createBlock, target) {
var block = createBlock;
if($('form_template_' + block.type) === null) {
var body;
var block_template;
var template;
var output;
var settings_segments;
if (window.$('form_template_' + block.type) === null) {
return false;
}
var body = $(WysijaForm.options.body),
block_template = Handlebars.compile($('form_template_block').innerHTML),
template = Handlebars.compile($('form_template_' + block.type).innerHTML),
body = window.$(WysijaForm.options.body);
block_template = window.Handlebars.compile(window.$('form_template_block').innerHTML);
template = window.Handlebars.compile(window.$('form_template_' + block.type).innerHTML);
output = '';
if (block.type === 'segment') {
if (block.params.values === undefined) {
var settings_segments = jQuery('#mailpoet_form_segments').val();
settings_segments = window.jQuery('#mailpoet_form_segments').val();
if (settings_segments !== null && settings_segments.length > 0) {
block.params.values = mailpoet_segments.filter(function(segment) {
block.params.values = window.mailpoet_segments.filter(function (segment) {
return (settings_segments.indexOf(segment.id) !== -1);
});
}
@ -930,14 +954,13 @@ WysijaForm.Block.create = function(createBlock, target) {
}
// if the drop target was the bottom placeholder
var element = null;
if (target.identify() === 'block_placeholder') {
// insert block at the bottom
element = body.insert(output);
body.insert(output);
// block = body.childElements().last();
} else {
// insert block before the drop target
element = target.insert({
target.insert({
before: output
});
// block = target.previous('.mailpoet_form_block');
@ -967,10 +990,10 @@ document.observe('wjfe:item:drop', function(event) {
});
/* Form Widget */
WysijaForm.Widget = Class.create(WysijaForm.Block, {
WysijaForm.Widget = window.Class.create(WysijaForm.Block, {
initialize: function (element) {
info('widget -> init');
this.element = $(element);
this.element = window.$(element);
return this;
},
setup: function () {
@ -978,8 +1001,8 @@ WysijaForm.Widget = Class.create(WysijaForm.Block, {
this.setupControls();
},
save: function () {
info('widget -> save');
var data = this.getData();
info('widget -> save');
if (data.element !== undefined) {
delete data.element;
@ -988,8 +1011,8 @@ WysijaForm.Widget = Class.create(WysijaForm.Block, {
return data;
},
setData: function (data) {
var current_data = this.getData(),
params = $H(current_data.params).merge(data.params).toObject();
var current_data = this.getData();
var params = window.$H(current_data.params).merge(data.params).toObject();
// update type if it changed
if (data.type !== undefined && data.type !== current_data.type) {
@ -1014,26 +1037,30 @@ WysijaForm.Widget = Class.create(WysijaForm.Block, {
this.removeBlock();
},
redraw: function (data) {
var options;
var block_template;
var template;
var params;
// set parameters
this.setData(data);
var options = this.getData();
options = this.getData();
// redraw block
var block_template = Handlebars.compile($('form_template_block').innerHTML),
template = Handlebars.compile($('form_template_' + options.type).innerHTML),
data = $H(options).merge({
block_template = window.Handlebars.compile(window.$('form_template_block').innerHTML);
template = window.Handlebars.compile(window.$('form_template_' + options.type).innerHTML);
params = window.$H(options).merge({
template: template(options)
}).toObject();
this.element.replace(block_template(data));
this.element.replace(block_template(params));
WysijaForm.init();
},
editSettings: function () {
MailPoet.Modal.popup({
title: MailPoet.I18n.t('editFieldSettings'),
template: jQuery('#form_template_field_settings').html(),
window.MailPoet.Modal.popup({
title: window.MailPoet.I18n.t('editFieldSettings'),
template: window.jQuery('#form_template_field_settings').html(),
data: this.getData(),
onSuccess: function () {
var data = jQuery('#form_field_settings').serializeObject();
var data = window.jQuery('#form_field_settings').serializeObject();
this.redraw(data);
}.bind(this)
});
@ -1055,8 +1082,8 @@ function info(value) {
var noop = function () {};
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
var length = methods.length;
window.console = {};
var console = {};
window.console = {};
while (length--) {
console[methods[length]] = noop;
}

View File

@ -2,7 +2,7 @@ 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';
import FormList from './list.jsx';
const history = useRouterHistory(createHashHistory)({ queryKey: false });

View File

@ -1,7 +1,8 @@
import React from 'react';
import Listing from 'listing/listing.jsx';
import classNames from 'classnames';
import MailPoet from 'mailpoet';
import jQuery from 'jquery';
import Listing from '../listing/listing.jsx';
const columns = [
{
@ -128,7 +129,7 @@ const FormList = React.createClass({
endpoint: 'forms',
action: 'create',
}).done((response) => {
window.location = mailpoet_form_edit_url + response.data.id;
window.location = window.mailpoet_form_edit_url + response.data.id;
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
@ -145,7 +146,7 @@ const FormList = React.createClass({
'has-row-actions'
);
let segments = mailpoet_segments.filter((segment) => {
let segments = window.mailpoet_segments.filter((segment) => {
return (jQuery.inArray(segment.id, form.segments) !== -1);
}).map((segment) => {
return segment.name;
@ -190,7 +191,7 @@ const FormList = React.createClass({
</h1>
<Listing
limit={ mailpoet_listing_per_page }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
messages={messages}

View File

@ -1,30 +1,32 @@
define('handlebars_helpers', ['handlebars'], function (Handlebars) {
// Handlebars helpers
Handlebars.registerHelper('concat', function () {
var size = (arguments.length - 1),
output = '';
for(var i = 0; i < size; i++) {
var size = (arguments.length - 1);
var output = '';
var i;
for (i = 0; i < size; i++) {
output += arguments[i];
}
return output;
});
Handlebars.registerHelper('number_format', function(value, block) {
Handlebars.registerHelper('number_format', function (value) {
return Number(value).toLocaleString();
});
Handlebars.registerHelper('date_format', function (timestamp, block) {
var f;
if (window.moment) {
if (timestamp === undefined || isNaN(timestamp) || timestamp <= 0) {
return;
}
// set date format
var f = block.hash.format || 'MMM Do, YYYY';
f = block.hash.format || 'MMM Do, YYYY';
// check if we passed a timestamp
if (parseInt(timestamp, 10) == timestamp) {
return moment.unix(timestamp).format(f);
return window.moment.unix(timestamp).format(f);
} else {
return moment.utc(timestamp).format(f);
return window.moment.utc(timestamp).format(f);
}
} else {
return timestamp;
@ -59,25 +61,24 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
case '||':
return (v1 || v2) ? options.fn(this) : options.inverse(this);
case 'in':
var values = v2.split(',');
return (v2.indexOf(v1) !== -1) ? options.fn(this) : options.inverse(this);
default:
return options.inverse(this);
}
});
Handlebars.registerHelper('nl2br', function(value, block) {
Handlebars.registerHelper('nl2br', function (value) {
return value.gsub('\n', '<br />');
});
Handlebars.registerHelper('json_encode', function(value, block) {
Handlebars.registerHelper('json_encode', function (value) {
return JSON.stringify(value);
});
Handlebars.registerHelper('json_decode', function(value, block) {
Handlebars.registerHelper('json_decode', function (value) {
return JSON.parse(value);
});
Handlebars.registerHelper('url', function(value, block) {
Handlebars.registerHelper('url', function (value) {
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
return url + value;
@ -90,16 +91,17 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
return value;
}
});
Handlebars.registerHelper('lookup', function(obj, field, options) {
Handlebars.registerHelper('lookup', function (obj, field) {
return obj && obj[field];
});
Handlebars.registerHelper('rsa_key', function(value, block) {
Handlebars.registerHelper('rsa_key', function (value) {
var lines;
// extract all lines into an array
if (value === undefined) return '';
var lines = value.trim().split('\n');
lines = value.trim().split('\n');
// remove header & footer
lines.shift();
@ -109,7 +111,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
return lines.join('');
});
Handlebars.registerHelper('trim', function(value, block) {
Handlebars.registerHelper('trim', function (value) {
if (value === null || value === undefined) return '';
return value.trim();
});
@ -126,10 +128,10 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
*/
Handlebars.registerHelper('ellipsis', function (str, limit, append) {
var strAppend = append;
var sanitized = str.replace(/(<([^>]+)>)/g, '');
if (strAppend === undefined) {
strAppend = '';
}
var sanitized = str.replace(/(<([^>]+)>)/g, '');
if (sanitized.length > limit) {
return sanitized.substr(0, limit - strAppend.length) + strAppend;
} else {

View File

@ -24,20 +24,20 @@ define(
* http://benalman.com/about/license/
*/
$.fn.serializeObject = function (coerce) {
var obj = {},
coerce_types = { true: !0, false: !1, null: null };
var obj = {};
var coerce_types = { true: !0, false: !1, null: null };
// Iterate over all name=value pairs.
$.each(this.serializeArray(), function (j, v) {
var key = v.name,
val = v.value,
cur = obj,
i = 0,
var key = v.name;
var val = v.value;
var cur = obj;
var i = 0;
// If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
// into its component parts.
keys = key.split( '][' ),
keys_last = keys.length - 1;
var keys = key.split('][');
var keys_last = keys.length - 1;
// If the first keys part contains [ and the last ends with ], then []
// are correctly balanced.

View File

@ -276,7 +276,7 @@ const ListingItems = React.createClass({
selection={this.props.selection}
is_selectable={this.props.is_selectable}
item_actions={this.props.item_actions}
group={ this.props.group }
group={this.props.group}
key={`item-${renderItem.id}-${index}`}
item={renderItem} />
);
@ -658,8 +658,8 @@ const Listing = React.createClass({
});
},
handleSelectItem: function (id, is_checked) {
let selected_ids = this.state.selected_ids,
selection = false;
let selected_ids = this.state.selected_ids;
let selection = false;
if (is_checked) {
selected_ids = jQuery.merge(selected_ids, [id]);

View File

@ -112,11 +112,11 @@ define('modal', ['mailpoet', 'jquery'],
if (this.renderer === 'html') {
return function () { return template; };
} else {
return Handlebars.compile(template);
return window.Handlebars.compile(template);
}
return false;
},
init: function (options) {
var modal;
if (this.initialized === true) {
this.close();
}
@ -135,7 +135,7 @@ define('modal', ['mailpoet', 'jquery'],
if (this.options.type !== null) {
// insert modal depending on its type
if (this.options.type === 'popup') {
var modal = this.compileTemplate(
modal = this.compileTemplate(
this.templates[this.options.type]
);
// create modal
@ -179,7 +179,7 @@ define('modal', ['mailpoet', 'jquery'],
return this;
},
initOverlay: function(toggle) {
initOverlay: function () {
if (jQuery('#mailpoet_modal_overlay').length === 0) {
// insert overlay into the DOM
jQuery('body').append(this.templates.overlay);
@ -344,20 +344,21 @@ define('modal', ['mailpoet', 'jquery'],
return this;
},
setPosition: function () {
var screenWidth;
var screenHeight;
var modalWidth;
var modalHeight;
switch (this.options.type) {
case 'popup':
var screenWidth = jQuery(window).width(),
screenHeight = jQuery(window).height(),
modalWidth = jQuery('.mailpoet_'+ this.options.type +'_wrapper').width(),
screenWidth = jQuery(window).width();
screenHeight = jQuery(window).height();
modalWidth = jQuery('.mailpoet_'+ this.options.type +'_wrapper').width();
modalHeight = jQuery('.mailpoet_'+ this.options.type +'_wrapper').height();
var top = Math.max(48, parseInt((screenHeight / 2) - (modalHeight / 2))),
left = Math.max(0, parseInt((screenWidth / 2) - (modalWidth / 2)));
// set position of popup depending on screen dimensions.
jQuery('#mailpoet_popup').css({
top: top,
left: left
top: Math.max(48, parseInt((screenHeight / 2) - (modalHeight / 2))),
left: Math.max(0, parseInt((screenWidth / 2) - (modalWidth / 2)))
});
break;
case 'panel':
@ -437,7 +438,7 @@ define('modal', ['mailpoet', 'jquery'],
.removeClass('mailpoet_modal_highlight');
return this;
},
hideModal: function(callback) {
hideModal: function () {
// set modal as closed
this.opened = false;
@ -452,7 +453,7 @@ define('modal', ['mailpoet', 'jquery'],
return this;
},
showOverlay: function(force) {
showOverlay: function () {
jQuery('#mailpoet_modal_overlay').show();
return this;
},

View File

@ -26,7 +26,7 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
displayLogs: function () {
jQuery.ajax({
url: mailpoet_mp2_migrator.log_file_url,
url: window.mailpoet_mp2_migrator.log_file_url,
cache: false
}).done(function (result) {
jQuery('#logger').html('');
@ -53,7 +53,7 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
updateProgressbar: function () {
jQuery.ajax({
url: mailpoet_mp2_migrator.progress_url,
url: window.mailpoet_mp2_migrator.progress_url,
cache: false,
dataType: 'json'
}).always(function (result) {

View File

@ -1,12 +1,8 @@
define([
'backbone',
'backbone.marionette',
'backbone.radio',
'jquery',
'underscore',
'handlebars',
'handlebars_helpers'
], function(Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
'backbone.radio'
], function (Backbone, Marionette, BackboneRadio) {
var Radio = BackboneRadio;
var AppView = Marionette.View.extend({

View File

@ -8,19 +8,39 @@ define([
'newsletter_editor/behaviors/BehaviorsLookup',
'mailpoet',
'spectrum'
], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) {
], function (Marionette, BehaviorsLookup, MailPoet) {
var BL = BehaviorsLookup;
BL.ColorPickerBehavior = Marionette.Behavior.extend({
onRender: function () {
this.view.$('.mailpoet_color').spectrum({
var that = this;
var preferredFormat = 'hex6';
this.view.$('.mailpoet_color').each(function () {
var $input = that.view.$(this);
var updateColorInput = function (color) {
if (color && color.getAlpha() > 0) {
$input.val(color.toString(preferredFormat));
} else {
$input.val('');
}
$input.trigger('change');
};
$input.spectrum({
clickoutFiresChange: true,
showInput: true,
showInitial: true,
preferredFormat: 'hex6',
showPalette: true,
showSelectionPalette: true,
palette: [],
localStorageKey: 'newsletter_editor.spectrum.palette',
preferredFormat: preferredFormat,
allowEmpty: true,
chooseText: MailPoet.I18n.t('selectColor'),
cancelText: MailPoet.I18n.t('cancelColorSelection')
cancelText: MailPoet.I18n.t('cancelColorSelection'),
change: updateColorInput,
move: updateColorInput,
hide: updateColorInput
});
});
}
});

View File

@ -1,3 +1,4 @@
/**
* ContainerDropZoneBehavior
*
@ -24,11 +25,11 @@ define([
this.addDropZone();
}
},
addDropZone: function(_event) {
var that = this,
view = this.view,
domElement = that.$el.get(0),
acceptableElementSelector;
addDropZone: function () {
var that = this;
var view = this.view;
var domElement = that.$el.get(0);
var acceptableElementSelector;
// TODO: Extract this limitation code to be controlled from containers
if (this.view.renderOptions.depth === 0) {
@ -46,11 +47,11 @@ define([
interact(domElement).dropzone({
accept: acceptableElementSelector,
overlap: 'pointer', // Mouse pointer denotes location of a droppable
ondragenter: function(event) {
ondragenter: function () {
// 1. Visually mark block as active for dropping
view.$el.addClass('mailpoet_drop_active');
},
ondragleave: function(event) {
ondragleave: function () {
// 1. Remove visual markings of active dropping container
// 2. Remove visual markings of drop position visualization
that.cleanup();
@ -67,15 +68,21 @@ define([
view.$el,
view.model.get('orientation'),
view.model.get('blocks').length
),
element = view.$el,
markerWidth = '',
markerHeight = '',
containerOffset = element.offset(),
viewCollection = that.getCollection(),
marker, targetModel, targetView, targetElement,
topOffset, leftOffset, isLastBlockInsertion,
$targetBlock, margin;
);
var element = view.$el;
var markerWidth = '';
var markerHeight = '';
var containerOffset = element.offset();
var viewCollection = that.getCollection();
var marker;
var targetModel;
var targetView;
var targetElement;
var topOffset;
var leftOffset;
var isLastBlockInsertion;
var $targetBlock;
var margin;
if (dropPosition === undefined) return;
@ -182,10 +189,14 @@ define([
view.$el,
view.model.get('orientation'),
view.model.get('blocks').length
),
droppableModel = event.draggable.getDropModel(),
viewCollection = that.getCollection(),
droppedView, droppedModel, index, tempCollection, tempCollection2;
);
var droppableModel = event.draggable.getDropModel();
var viewCollection = that.getCollection();
var droppedView;
var index;
var tempCollection;
var tempCollection2;
var tempModel;
if (dropPosition === undefined) return;
@ -195,7 +206,8 @@ 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'))({
tempCollection = new (window.EditorApplication.getBlockTypeModel('container'))({
orientation: 'vertical'
});
tempCollection.get('blocks').add(droppableModel);
@ -208,9 +220,9 @@ define([
} else {
// Special insertion by replacing target block with collection
// and inserting dropModel into that
var tempModel = viewCollection.at(dropPosition.index);
tempModel = viewCollection.at(dropPosition.index);
tempCollection = new (EditorApplication.getBlockTypeModel('container'))({
tempCollection = new (window.EditorApplication.getBlockTypeModel('container'))({
orientation: (view.model.get('orientation') === 'vertical') ? 'horizontal' : 'vertical'
});
@ -218,19 +230,19 @@ define([
if (tempCollection.get('orientation') === 'horizontal') {
if (dropPosition.position === 'before') {
tempCollection2 = new (EditorApplication.getBlockTypeModel('container'))({
tempCollection2 = new (window.EditorApplication.getBlockTypeModel('container'))({
orientation: 'vertical'
});
tempCollection2.get('blocks').add(droppableModel);
tempCollection.get('blocks').add(tempCollection2);
}
tempCollection2 = new (EditorApplication.getBlockTypeModel('container'))({
tempCollection2 = new (window.EditorApplication.getBlockTypeModel('container'))({
orientation: 'vertical'
});
tempCollection2.get('blocks').add(tempModel);
tempCollection.get('blocks').add(tempCollection2);
if (dropPosition.position === 'after') {
tempCollection2 = new (EditorApplication.getBlockTypeModel('container'))({
tempCollection2 = new (window.EditorApplication.getBlockTypeModel('container'))({
orientation: 'vertical'
});
tempCollection2.get('blocks').add(droppableModel);
@ -270,28 +282,32 @@ define([
this.view.$('.mailpoet_drop_marker').remove();
},
getDropPosition: function (eventX, eventY, is_unsafe) {
var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3
var SPECIAL_AREA_INSERTION_WIDTH = 0.00; // Disable special insertion. Default: 0.3
element = this.view.$el,
orientation = this.view.model.get('orientation'),
var element = this.view.$el;
var orientation = this.view.model.get('orientation');
elementOffset = element.offset(),
elementPageX = elementOffset.left,
elementPageY = elementOffset.top,
elementWidth = element.outerWidth(true),
elementHeight = element.outerHeight(true),
var elementOffset = element.offset();
var elementPageX = elementOffset.left;
var elementPageY = elementOffset.top;
var elementWidth = element.outerWidth(true);
var elementHeight = element.outerHeight(true);
relativeX = eventX - elementPageX,
relativeY = eventY - elementPageY,
var relativeX = eventX - elementPageX;
var relativeY = eventY - elementPageY;
relativeOffset, elementLength,
var relativeOffset;
var elementLength;
canAcceptNormalInsertion = this._canAcceptNormalInsertion(),
canAcceptSpecialInsertion = this._canAcceptSpecialInsertion(),
var canAcceptNormalInsertion = this._canAcceptNormalInsertion();
var canAcceptSpecialInsertion = this._canAcceptSpecialInsertion();
insertionType, index, position, indexAndPosition;
var insertionType;
var index;
var position;
var indexAndPosition;
unsafe = !!is_unsafe;
var unsafe = !!is_unsafe;
if (this.getCollection().length === 0) {
return {
@ -357,12 +373,14 @@ define([
// target element if event happens on the second half of the element.
// Halves depend on orientation.
var index = this._computeCellIndex(eventX, eventY),
var index = this._computeCellIndex(eventX, eventY);
// TODO: Handle case when there are no children, container is empty
targetView = this.getChildren().findByModel(this.getCollection().at(index)),
orientation = this.view.model.get('orientation'),
element = targetView.$el,
eventOffset, closeOffset, elementDimension;
var targetView = this.getChildren().findByModel(this.getCollection().at(index));
var orientation = this.view.model.get('orientation');
var element = targetView.$el;
var eventOffset;
var closeOffset;
var elementDimension;
if (orientation === 'vertical') {
eventOffset = eventY;
@ -392,11 +410,12 @@ define([
return this._computeCellIndex(eventX, eventY);
},
_computeCellIndex: function (eventX, eventY) {
var orientation = this.view.model.get('orientation'),
eventOffset = (orientation === 'vertical') ? eventY : eventX,
resultView = this.getChildren().find(function(view) {
var element = view.$el,
closeOffset, farOffset;
var orientation = this.view.model.get('orientation');
var eventOffset = (orientation === 'vertical') ? eventY : eventX;
var resultView = this.getChildren().find(function (view) {
var element = view.$el;
var closeOffset;
var farOffset;
if (orientation === 'vertical') {
closeOffset = element.offset().top;
@ -415,16 +434,16 @@ define([
return index;
},
_canAcceptNormalInsertion: function () {
var orientation = this.view.model.get('orientation'),
depth = this.view.renderOptions.depth,
childCount = this.getChildren().length;
var orientation = this.view.model.get('orientation');
var depth = this.view.renderOptions.depth;
var 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.getChildren().length;
var orientation = this.view.model.get('orientation');
var depth = this.view.renderOptions.depth;
var childCount = this.getChildren().length;
return depth === 0 || (depth === 1 && orientation === 'horizontal' && childCount <= this.options.columnLimit);
},
getCollectionView: function () {

View File

@ -28,12 +28,12 @@ define([
throw "Missing 'drop' function for DraggableBehavior";
},
onDrop: function(model, view) {},
testAttachToInstance: function(model, view) { return true; }
onDrop: function () {},
testAttachToInstance: function () { return true; }
},
onRender: function () {
var that = this,
interactable;
var that = this;
var interactable;
// Give instances more control over whether Draggable should be applied
if (!this.options.testAttachToInstance(this.view.model, this.view)) return;
@ -49,16 +49,19 @@ define([
onstart: function (startEvent) {
var event = startEvent;
var centerXOffset;
var centerYOffset;
var tempClone;
var clone;
var $clone;
if (that.options.cloneOriginal === true) {
// Use substitution instead of a clone
var tempClone = (_.isFunction(that.options.onDragSubstituteBy)) ? that.options.onDragSubstituteBy(that) : undefined,
tempClone = (_.isFunction(that.options.onDragSubstituteBy)) ? that.options.onDragSubstituteBy(that) : undefined;
// Or use a clone
clone = tempClone ? tempClone : event.target.cloneNode(true),
$original = jQuery(event.target),
$clone = jQuery(clone),
centerXOffset, centerYOffset, parentOffset;
clone = tempClone || event.target.cloneNode(true);
jQuery(event.target);
$clone = jQuery(clone);
$clone.addClass('mailpoet_droppable_active');
$clone.css('position', 'absolute');
@ -85,10 +88,10 @@ define([
},
// call this function on every dragmove event
onmove: function (event) {
var target = event.target,
var target = event.target;
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';

View File

@ -0,0 +1,26 @@
/**
* Highlight Container Behavior
*
* Highlights a container block when hovering over its tools
*/
define([
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup'
], function (Marionette, BehaviorsLookup) {
var BL = BehaviorsLookup;
BL.HighlightContainerBehavior = Marionette.Behavior.extend({
events: {
'mouseenter @ui.tools': 'enableHighlight',
'mouseleave @ui.tools': 'disableHighlight'
},
enableHighlight: function () {
this.$el.addClass('mailpoet_highlight');
},
disableHighlight: function () {
if (!this.view._isBeingEdited) {
this.$el.removeClass('mailpoet_highlight');
}
}
});
});

View File

@ -15,9 +15,11 @@ define([
stopEditing: 'disableHighlight'
},
enableHighlight: function () {
this.view._isBeingEdited = true;
this.$el.addClass('mailpoet_highlight');
},
disableHighlight: function () {
this.view._isBeingEdited = false;
this.$el.removeClass('mailpoet_highlight');
}
});

View File

@ -14,9 +14,16 @@ define([
defaults: {
elementSelector: null,
resizeHandleSelector: true, // true will use edges of the element itself
transformationFunction: function(y) { return y; },
transformationFunction: function (y) { return y; }, // for blocks that use the default onResize function
minLength: 0,
modelField: 'styles.block.height'
maxLength: Infinity,
modelField: 'styles.block.height',
onResize: function (event) {
var currentLength = parseFloat(this.view.model.get(this.options.modelField));
var newLength = currentLength + this.options.transformationFunction(event.dy);
newLength = Math.min(this.options.maxLength, Math.max(this.options.minLength, newLength));
this.view.model.set(this.options.modelField, newLength + 'px');
}
},
events: {
mouseenter: 'showResizeHandle',
@ -30,8 +37,8 @@ define([
}
},
attachResize: function () {
var domElement = (this.options.elementSelector === null) ? this.view.$el.get(0) : this.view.$(this.options.elementSelector).get(0),
that = this;
var domElement = (this.options.elementSelector === null) ? this.view.$el.get(0) : this.view.$(this.options.elementSelector).get(0);
var that = this;
interact(domElement).resizable({
// axis: 'y',
edges: {
@ -40,18 +47,16 @@ define([
right: false,
bottom: (typeof this.options.resizeHandleSelector === 'string') ? this.view.$(this.options.resizeHandleSelector).get(0) : this.options.resizeHandleSelector
}
}).on('resizestart', function(event) {
})
.on('resizestart', function () {
that.isBeingResized = true;
that.$el.addClass('mailpoet_resize_active');
}).on('resizemove', function(event) {
var currentLength = parseFloat(that.view.model.get(that.options.modelField)),
newLength = currentLength + that.options.transformationFunction(event.dy);
if (newLength < that.options.minLength) newLength = that.options.minLength;
that.view.model.set(that.options.modelField, newLength + 'px');
})
.on('resizeend', function(event) {
.on('resizemove', function (event) {
var onResize = that.options.onResize.bind(that);
return onResize(event);
})
.on('resizeend', function () {
that.isBeingResized = null;
that.$el.removeClass('mailpoet_resize_active');
});

View File

@ -24,9 +24,9 @@ define([
ui.item.removeData('previousIndex');
},
update: function (event, ui) {
var previousIndex = ui.item.data('previousIndex'),
newIndex = ui.item.index(),
model = collection.at(previousIndex);
var previousIndex = ui.item.data('previousIndex');
var newIndex = ui.item.index();
var model = collection.at(previousIndex);
// Replicate DOM changes. Move target model to a new position
// within the collection

View File

@ -42,7 +42,7 @@ define([
relative_urls: false,
remove_script_host: false,
convert_urls: true,
urlconverter_callback: function(url, node, on_save, name) {
urlconverter_callback: function (url) {
if (url.match(/\[.+\]/g)) {
// Do not convert URLs with shortcodes
return url;
@ -57,7 +57,7 @@ define([
plugins: this.options.plugins,
setup: function (editor) {
editor.on('change', function(e) {
editor.on('change', function () {
that.view.triggerMethod('text:editor:change', editor.getContent());
});
@ -65,18 +65,18 @@ define([
editor.focus();
if (that._isActivationClick) {
editor.selection.setRng(
tinymce.dom.RangeUtils.getCaretRangeFromPoint(e.clientX, e.clientY, editor.getDoc())
window.tinymce.dom.RangeUtils.getCaretRangeFromPoint(e.clientX, e.clientY, editor.getDoc())
);
that._isActivationClick = false;
}
});
editor.on('focus', function(e) {
editor.on('focus', function () {
that.view.triggerMethod('text:editor:focus');
that._isActivationClick = true;
});
editor.on('blur', function(e) {
editor.on('blur', function () {
that.view.triggerMethod('text:editor:blur');
});
}

View File

@ -30,8 +30,8 @@ define([
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
Module.ALCSupervisor = SuperModel.extend({
initialize: function () {
@ -43,12 +43,13 @@ define([
);
},
refresh: function () {
var blocks;
var models = App.findModels(function (model) {
return model.get('type') === 'automatedLatestContent';
}) || [];
if (models.length === 0) return;
var blocks = _.map(models, function(model) {
blocks = _.map(models, function (model) {
return model.toJSON();
});
@ -60,8 +61,8 @@ define([
_.each(
_.zip(models, renderedBlocks),
function (args) {
var model = args[0],
contents = args[1];
var model = args[0];
var contents = args[1];
model.trigger('refreshPosts', contents);
}
);
@ -135,7 +136,7 @@ define([
}
App.getChannel().on('replaceAllButtonStyles', replaceButtonStylesHandler.bind(this));
},
getTemplate: function() { return templates.automatedLatestContentBlock; },
getTemplate: function () { return window.templates.automatedLatestContentBlock; },
regions: {
toolsRegion: '.mailpoet_tools',
postsRegion: '.mailpoet_automated_latest_content_block_posts'
@ -150,8 +151,8 @@ define([
}),
onDragSubstituteBy: function () { return Module.AutomatedLatestContentWidgetView; },
onRender: function () {
var ContainerView = App.getBlockTypeView('container'),
renderOptions = {
var ContainerView = App.getBlockTypeView('container');
var renderOptions = {
disableTextEditor: true,
disableDragAndDrop: true,
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay')
@ -168,7 +169,7 @@ define([
// Sidebar view container
Module.AutomatedLatestContentBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.automatedLatestContentBlockSettings; },
getTemplate: function () { return window.templates.automatedLatestContentBlockSettings; },
events: function () {
return {
'click .mailpoet_automated_latest_content_hide_display_options': 'toggleDisplayOptions',
@ -213,12 +214,13 @@ define([
},
transport: function (options, success, failure) {
var taxonomies;
var termsPromise;
var promise = CommunicationComponent.getTaxonomies(
that.model.get('contentType')
).then(function (tax) {
taxonomies = tax;
// Fetch available terms based on the list of taxonomies already fetched
var promise = CommunicationComponent.getTerms({
termsPromise = CommunicationComponent.getTerms({
search: options.data.term,
taxonomies: _.keys(taxonomies)
}).then(function (terms) {
@ -227,7 +229,7 @@ define([
terms: terms
};
});
return promise;
return termsPromise;
});
promise.then(success);
@ -264,9 +266,9 @@ define([
}
}).trigger('change');
},
toggleDisplayOptions: function(event) {
var el = this.$('.mailpoet_automated_latest_content_display_options'),
showControl = this.$('.mailpoet_automated_latest_content_show_display_options');
toggleDisplayOptions: function () {
var el = this.$('.mailpoet_automated_latest_content_display_options');
var showControl = this.$('.mailpoet_automated_latest_content_show_display_options');
if (el.hasClass('mailpoet_closed')) {
el.removeClass('mailpoet_closed');
showControl.addClass('mailpoet_hidden');
@ -275,7 +277,7 @@ define([
showControl.removeClass('mailpoet_hidden');
}
},
showButtonSettings: function(event) {
showButtonSettings: function () {
var buttonModule = ButtonBlock;
(new buttonModule.ButtonBlockSettingsView({
model: this.model.get('readMoreButton'),
@ -286,7 +288,7 @@ define([
}
})).render();
},
showDividerSettings: function(event) {
showDividerSettings: function () {
var dividerModule = DividerBlock;
(new dividerModule.DividerBlockSettingsView({
model: this.model.get('divider'),
@ -349,8 +351,8 @@ define([
this.changeField('titleFormat', event);
},
_updateContentTypes: function (postTypes) {
var select = this.$('.mailpoet_automated_latest_content_content_type'),
selectedValue = this.model.get('contentType');
var select = this.$('.mailpoet_automated_latest_content_content_type');
var selectedValue = this.model.get('contentType');
select.find('option').remove();
_.each(postTypes, function (type) {
@ -364,7 +366,7 @@ define([
});
Module.AutomatedLatestContentWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.automatedLatestContentInsertion; },
getTemplate: function () { return window.templates.automatedLatestContentInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -378,7 +380,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('automatedLatestContent', {
blockModel: Module.AutomatedLatestContentBlockModel,
blockView: Module.AutomatedLatestContentBlockView
@ -391,7 +393,7 @@ define([
});
});
App.on('start', function(App, options) {
App.on('start', function (App) {
var Application = App;
Application._ALCSupervisor = new Module.ALCSupervisor();
Application._ALCSupervisor.refresh();

View File

@ -12,17 +12,16 @@ define([
'jquery',
'mailpoet',
'modal'
], function(App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
], function (App, Marionette, SuperModel, _, jQuery, MailPoet) {
'use strict';
var Module = {},
AugmentedView = Marionette.View.extend({});
var Module = {};
var AugmentedView = Marionette.View.extend({});
Module.BlockModel = SuperModel.extend({
stale: [], // Attributes to be removed upon saving
initialize: function () {
var that = this;
this.on('change', function () {
App.getChannel().trigger('autoSave');
});
@ -68,7 +67,8 @@ define([
options.dragBehavior.view.model.destroy();
},
onDragSubstituteBy: function (behavior) {
var WidgetView, node;
var WidgetView;
var 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
@ -98,13 +98,13 @@ define([
this.on('dom:refresh', this.showBlock, this);
this._isFirstRender = true;
},
showTools: function(_event) {
showTools: function () {
if (!this.showingToolsDisabled) {
this.$('> .mailpoet_tools').addClass('mailpoet_display_tools');
this.toolsView.triggerMethod('showTools');
}
},
hideTools: function(e) {
hideTools: function () {
this.$('> .mailpoet_tools').removeClass('mailpoet_display_tools');
this.toolsView.triggerMethod('hideTools');
},
@ -178,7 +178,7 @@ define([
});
Module.BlockToolsView = AugmentedView.extend({
getTemplate: function() { return templates.genericBlockTools; },
getTemplate: function () { return window.templates.genericBlockTools; },
events: {
'click .mailpoet_edit_block': 'changeSettings',
'click .mailpoet_delete_block_activate': 'showDeletionConfirmation',
@ -240,8 +240,9 @@ define([
ColorPickerBehavior: {}
},
initialize: function (params) {
var panelParams;
this.model.trigger('startEditing');
var panelParams = {
panelParams = {
element: this.$el,
template: '',
position: 'right',
@ -262,7 +263,7 @@ define([
model: this.model.toJSON()
};
},
close: function(event) {
close: function () {
this.destroy();
},
changeField: function (field, event) {
@ -275,7 +276,7 @@ define([
this.model.set(field, jQuery(event.target).val() + suffix);
},
changeBoolField: function (field, event) {
this.model.set(field, (jQuery(event.target).val() === 'true') ? true : false);
this.model.set(field, (jQuery(event.target).val() === 'true'));
},
changeBoolCheckboxField: function (field, event) {
this.model.set(field, (!!jQuery(event.target).prop('checked')));

View File

@ -11,8 +11,8 @@ define([
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
Module.ButtonBlockModel = base.BlockModel.extend({
defaults: function () {
@ -42,7 +42,7 @@ define([
Module.ButtonBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_button_block mailpoet_droppable_block',
getTemplate: function() { return templates.buttonBlock; },
getTemplate: function () { return window.templates.buttonBlock; },
onDragSubstituteBy: function () { return Module.ButtonWidgetView; },
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
ShowSettingsBehavior: {}
@ -65,7 +65,7 @@ define([
});
Module.ButtonBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.buttonBlockSettings; },
getTemplate: function () { return window.templates.buttonBlockSettings; },
events: function () {
return {
'input .mailpoet_field_button_text': _.partial(this.changeField, 'text'),
@ -121,7 +121,7 @@ define([
});
Module.ButtonWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.buttonInsertion; },
getTemplate: function () { return window.templates.buttonInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -132,7 +132,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('button', {
blockModel: Module.ButtonBlockModel,
blockView: Module.ButtonBlockView

View File

@ -14,9 +14,9 @@ define([
'use strict';
var Module = {},
base = BaseBlock,
BlockCollection;
var Module = {};
var base = BaseBlock;
var BlockCollection;
BlockCollection = Backbone.Collection.extend({
model: base.BlockModel,
@ -24,7 +24,6 @@ define([
this.on('add change remove', function () { App.getChannel().trigger('autoSave'); });
},
parse: function (response) {
var self = this;
return _.map(response, function (block) {
var Type = App.getBlockTypeModel(block.type);
// TODO: If type has no registered model, use a backup one
@ -66,7 +65,7 @@ define([
return response;
},
getChildren: function () {
var models = this.get('blocks').map(function(model, index, list) {
var models = this.get('blocks').map(function (model) {
return [model, model.getChildren()];
});
@ -103,7 +102,7 @@ define([
}
}),
className: 'mailpoet_block mailpoet_container_block mailpoet_droppable_block mailpoet_droppable_layout_block',
getTemplate: function() { return templates.containerBlock; },
getTemplate: function () { return window.templates.containerBlock; },
events: _.extend({}, base.BlockView.prototype.events, {
'click .mailpoet_newsletter_layer_selector': 'toggleEditingLayer'
}),
@ -121,7 +120,8 @@ define([
options.dragBehavior.view.model.destroy();
},
onDragSubstituteBy: function (behavior) {
var WidgetView, node;
var WidgetView;
var 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
@ -138,7 +138,8 @@ define([
// for root and column containers.
return view.renderOptions.depth === 1;
}
}
},
HighlightContainerBehavior: {}
}),
onDragSubstituteBy: function () {
// For two and three column layouts display their respective widgets,
@ -189,18 +190,18 @@ define([
}
},
toggleEditingLayer: function (event) {
var that = this,
$toggleButton = this.$('> .mailpoet_tools .mailpoet_newsletter_layer_selector'),
$overlay = jQuery('.mailpoet_layer_overlay'),
$container = this.$('> .mailpoet_container'),
enableContainerLayer = function() {
var that = this;
var $toggleButton = this.$('> .mailpoet_tools .mailpoet_newsletter_layer_selector');
var $overlay = jQuery('.mailpoet_layer_overlay');
var $container = this.$('> .mailpoet_container');
var enableContainerLayer = function () {
that.$el.addClass('mailpoet_container_layer_active');
$toggleButton.addClass('mailpoet_container_layer_active');
$container.addClass('mailpoet_layer_highlight');
$overlay.click(disableContainerLayer);
$overlay.show();
},
disableContainerLayer = function() {
};
var disableContainerLayer = function () {
that.$el.removeClass('mailpoet_container_layer_active');
$toggleButton.removeClass('mailpoet_container_layer_active');
$container.removeClass('mailpoet_layer_highlight');
@ -217,7 +218,7 @@ define([
});
Module.ContainerBlockEmptyView = Marionette.View.extend({
getTemplate: function() { return templates.containerEmpty; },
getTemplate: function () { return window.templates.containerEmpty; },
initialize: function (options) {
this.renderOptions = _.defaults(options.renderOptions || {}, {});
},
@ -234,7 +235,7 @@ define([
});
Module.ContainerBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.containerBlockSettings; },
getTemplate: function () { return window.templates.containerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_container_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
@ -266,7 +267,7 @@ define([
});
Module.ContainerBlockColumnSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.containerBlockColumnSettings; },
getTemplate: function () { return window.templates.containerBlockColumnSettings; },
initialize: function (options) {
this.columnNumber = (options.columnIndex || 0) + 1;
},
@ -280,7 +281,7 @@ define([
Module.OneColumnContainerWidgetView = base.WidgetView.extend({
className: base.WidgetView.prototype.className + ' mailpoet_droppable_layout_block',
getTemplate: function() { return templates.oneColumnLayoutInsertion; },
getTemplate: function () { return window.templates.oneColumnLayoutInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -298,7 +299,7 @@ define([
Module.TwoColumnContainerWidgetView = base.WidgetView.extend({
className: base.WidgetView.prototype.className + ' mailpoet_droppable_layout_block',
getTemplate: function() { return templates.twoColumnLayoutInsertion; },
getTemplate: function () { return window.templates.twoColumnLayoutInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -317,7 +318,7 @@ define([
Module.ThreeColumnContainerWidgetView = base.WidgetView.extend({
className: base.WidgetView.prototype.className + ' mailpoet_droppable_layout_block',
getTemplate: function() { return templates.threeColumnLayoutInsertion; },
getTemplate: function () { return window.templates.threeColumnLayoutInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -335,7 +336,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('container', {
blockModel: Module.ContainerBlockModel,
blockView: Module.ContainerBlockView

View File

@ -5,14 +5,13 @@ define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'jquery',
'mailpoet'
], function(App, BaseBlock, _, jQuery, MailPoet) {
'jquery'
], function (App, BaseBlock, _, jQuery) {
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
Module.DividerBlockModel = base.BlockModel.extend({
defaults: function () {
@ -33,7 +32,7 @@ define([
Module.DividerBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_divider_block mailpoet_droppable_block',
getTemplate: function() { return templates.dividerBlock; },
getTemplate: function () { return window.templates.dividerBlock; },
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
behaviors: _.defaults({
ResizableBehavior: {
@ -49,8 +48,8 @@ define([
}, base.BlockView.prototype.behaviors),
onDragSubstituteBy: function () { return Module.DividerWidgetView; },
initialize: function () {
base.BlockView.prototype.initialize.apply(this, arguments);
var that = this;
base.BlockView.prototype.initialize.apply(this, arguments);
// Listen for attempts to change all dividers in one go
this._replaceDividerHandler = function (data) { that.model.set(data); that.model.trigger('applyToAll'); };
@ -84,7 +83,7 @@ define([
});
Module.DividerBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.dividerBlockSettings; },
getTemplate: function () { return window.templates.dividerBlockSettings; },
events: function () {
return {
'click .mailpoet_field_divider_style': 'changeStyle',
@ -119,7 +118,7 @@ define([
repaintDividerStyleOptions: function () {
this.$('.mailpoet_field_divider_style > div').css('border-top-color', this.model.get('styles.block.borderColor'));
},
applyToAll: function(event) {
applyToAll: function () {
App.getChannel().trigger('replaceAllDividers', this.model.toJSON());
},
updateValueAndCall: function (fieldToUpdate, callable, event) {
@ -129,7 +128,7 @@ define([
});
Module.DividerWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.dividerInsertion; },
getTemplate: function () { return window.templates.dividerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -139,7 +138,7 @@ define([
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('divider', {
blockModel: Module.DividerBlockModel,
blockView: Module.DividerBlockView

View File

@ -4,13 +4,14 @@
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function(App, BaseBlock, _) {
'underscore',
'mailpoet'
], function (App, BaseBlock, _, MailPoet) {
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
Module.FooterBlockModel = base.BlockModel.extend({
defaults: function () {
@ -38,7 +39,7 @@ define([
Module.FooterBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_footer_block mailpoet_droppable_block',
getTemplate: function() { return templates.footerBlock; },
getTemplate: function () { return window.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'
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
@ -75,7 +76,7 @@ define([
});
Module.FooterBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.footerBlockSettings; },
getTemplate: function () { return window.templates.footerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_footer_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
@ -98,7 +99,7 @@ define([
});
Module.FooterWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.footerInsertion; },
getTemplate: function () { return window.templates.footerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -109,7 +110,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('footer', {
blockModel: Module.FooterBlockModel,
blockView: Module.FooterBlockView

View File

@ -4,13 +4,14 @@
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function(App, BaseBlock, _) {
'underscore',
'mailpoet'
], function (App, BaseBlock, _, MailPoet) {
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
Module.HeaderBlockModel = base.BlockModel.extend({
defaults: function () {
@ -38,7 +39,7 @@ define([
Module.HeaderBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_header_block mailpoet_droppable_block',
getTemplate: function() { return templates.headerBlock; },
getTemplate: function () { return window.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'
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
@ -75,7 +76,7 @@ define([
});
Module.HeaderBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.headerBlockSettings; },
getTemplate: function () { return window.templates.headerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_header_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
@ -98,7 +99,7 @@ define([
});
Module.HeaderWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.headerInsertion; },
getTemplate: function () { return window.templates.headerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -109,7 +110,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('header', {
blockModel: Module.HeaderBlockModel,
blockView: Module.HeaderBlockView

View File

@ -5,14 +5,15 @@ define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'mailpoet'
], function(App, BaseBlock, _, MailPoet) {
'mailpoet',
'jquery'
], function (App, BaseBlock, _, MailPoet, jQuery) {
'use strict';
var Module = {},
base = BaseBlock,
ImageWidgetView;
var Module = {};
var base = BaseBlock;
var ImageWidgetView;
Module.ImageBlockModel = base.BlockModel.extend({
defaults: function () {
@ -35,7 +36,7 @@ define([
Module.ImageBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_image_block mailpoet_droppable_block',
getTemplate: function() { return templates.imageBlock; },
getTemplate: function () { return window.templates.imageBlock; },
onDragSubstituteBy: function () { return Module.ImageWidgetView; },
templateContext: function () {
return _.extend({
@ -43,17 +44,28 @@ define([
}, base.BlockView.prototype.templateContext.apply(this));
},
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
ShowSettingsBehavior: {}
ResizableBehavior: {
elementSelector: '.mailpoet_image',
resizeHandleSelector: '.mailpoet_image_resize_handle',
onResize: function (event) {
var corner = this.$('.mailpoet_image').offset();
var width = event.pageX - corner.left;
this.view.model.set('width', width + 'px');
}
},
ShowSettingsBehavior: {
ignoreFrom: '.mailpoet_image_resize_handle'
}
}),
onRender: function () {
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
this.showChildView('toolsRegion', this.toolsView);
if (this.model.get('fullWidth')) {
this.$el.addClass('mailpoet_full_image');
} else {
this.$el.removeClass('mailpoet_full_image');
}
this.$('.mailpoet_content').css('width', this.model.get('width'));
}
});
@ -72,7 +84,7 @@ define([
tooltip: MailPoet.I18n.t('helpTooltipDesignerIdealWidth')
});
},
getTemplate: function() { return templates.imageBlockSettings; },
getTemplate: function () { return window.templates.imageBlockSettings; },
events: function () {
return {
'input .mailpoet_field_image_link': _.partial(this.changeField, 'link'),
@ -81,9 +93,32 @@ define([
'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'
'click .mailpoet_done_editing': 'close',
'input .mailpoet_field_image_width': _.partial(this.updateValueAndCall, '.mailpoet_field_image_width_input', _.partial(this.changePixelField, 'width').bind(this)),
'change .mailpoet_field_image_width': _.partial(this.updateValueAndCall, '.mailpoet_field_image_width_input', _.partial(this.changePixelField, 'width').bind(this)),
'input .mailpoet_field_image_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_image_width', _.partial(this.changePixelField, 'width').bind(this))
};
},
modelEvents: function () {
return {
'change:maxWidth': 'updateMaxWidth',
'change:width': 'updateWidth'
};
},
updateValueAndCall: function (fieldToUpdate, callable, event) {
this.$(fieldToUpdate).val(jQuery(event.target).val());
callable(event);
},
updateMaxWidth: function () {
var maxWidth = parseInt(this.model.get('maxWidth'));
this.$('.mailpoet_field_image_width').attr('max', maxWidth);
this.$('.mailpoet_field_image_width_input').attr('max', maxWidth);
},
updateWidth: function () {
var width = parseInt(this.model.get('width'));
this.$('.mailpoet_field_image_width').val(width);
this.$('.mailpoet_field_image_width_input').val(width);
},
initialize: function (options) {
base.BlockSettingsView.prototype.initialize.apply(this, arguments);
@ -92,16 +127,19 @@ define([
}
},
showMediaManager: function () {
var that = this;
var MediaManager;
var theFrame;
if (this._mediaManager) {
this._mediaManager.resetSelections();
this._mediaManager.open();
return;
}
var MediaManager = wp.media.view.MediaFrame.Select.extend({
MediaManager = window.wp.media.view.MediaFrame.Select.extend({
initialize: function () {
wp.media.view.MediaFrame.prototype.initialize.apply(this, arguments);
window.wp.media.view.MediaFrame.prototype.initialize.apply(this, arguments);
_.defaults(this.options, {
multiple: true,
@ -123,7 +161,7 @@ define([
},
createQuery: function (options) {
var query = wp.media.query(options);
var query = window.wp.media.query(options);
return query;
},
@ -133,7 +171,7 @@ define([
// Add the default states.
this.states.add([
// Main states.
new wp.media.controller.Library({
new window.wp.media.controller.Library({
id: 'insert',
title: 'Add images',
priority: 20,
@ -155,12 +193,13 @@ define([
})
]);
if(wp.media.view.settings.post.featuredImageId) {
this.states.add(new wp.media.controller.FeaturedImage());
if (window.wp.media.view.settings.post.featuredImageId) {
this.states.add(new window.wp.media.controller.FeaturedImage());
}
},
bindHandlers: function () {
var handlers;
// from Select
this.on('router:create:browse', this.createRouter, this);
this.on('router:render:browse', this.browseRouter, this);
@ -175,7 +214,7 @@ define([
this.on('updateExcluded', this.browseContent, this);
var handlers = {
handlers = {
content: {
embed: 'embedContent',
'edit-selection': 'editSelectionContent'
@ -193,13 +232,13 @@ define([
},
uploadContent: function () {
wp.media.view.MediaFrame.Select.prototype.uploadContent.apply(this, arguments);
window.wp.media.view.MediaFrame.Select.prototype.uploadContent.apply(this, arguments);
this.$el.addClass('hide-toolbar');
},
// Content
embedContent: function () {
var view = new wp.media.view.Embed({
var view = new window.wp.media.view.Embed({
controller: this,
model: this.state()
}).render();
@ -209,11 +248,11 @@ define([
},
editSelectionContent: function () {
var state = this.state(),
selection = state.get('selection'),
view;
var state = this.state();
var selection = state.get('selection');
var view;
view = new wp.media.view.AttachmentsBrowser({
view = new window.wp.media.view.AttachmentsBrowser({
controller: this,
collection: selection,
selection: selection,
@ -222,7 +261,7 @@ define([
search: false,
dragInfo: true,
AttachmentView: wp.media.view.Attachment.EditSelection
AttachmentView: window.wp.media.view.Attachment.EditSelection
}).render();
view.toolbar.set('backToLibrary', {
@ -242,7 +281,7 @@ define([
selectionStatusToolbar: function (view) {
var editable = this.state().get('editable');
view.set('selection', new wp.media.view.Selection({
view.set('selection', new window.wp.media.view.Selection({
controller: this,
collection: this.state().get('selection'),
priority: -40,
@ -267,8 +306,8 @@ define([
requires: { selection: true },
click: function () {
var state = controller.state(),
selection = state.get('selection');
var state = controller.state();
var selection = state.get('selection');
controller.close();
state.trigger('insert', selection).reset();
@ -278,7 +317,7 @@ define([
mainEmbedToolbar: function (toolbar) {
var tbar = toolbar;
tbar.view = new wp.media.view.Toolbar.Embed({
tbar.view = new window.wp.media.view.Toolbar.Embed({
controller: this,
text: 'Add images'
});
@ -286,7 +325,7 @@ define([
});
var theFrame = new MediaManager({
theFrame = new MediaManager({
id: 'mailpoet-media-manager',
frame: 'select',
title: 'Select image',
@ -299,33 +338,29 @@ define([
button: {
text: 'Select'
}
}),
that = this;
});
this._mediaManager = theFrame;
this._mediaManager.on('insert', function () {
// Append media manager image selections to Images tab
var selection = theFrame.state().get('selection');
selection.each(function (attachment) {
var sizes = attachment.get('sizes'),
var sizes = attachment.get('sizes');
// Following advice from Becs, the target width should
// be a double of one column width to render well on
// retina screen devices
targetImageWidth = 1320,
// For main image use the size, that's closest to being 660px in width
sizeKeys = _.keys(sizes),
var targetImageWidth = 1320;
// Pick the width that is closest to target width
increasingByWidthDifference = _.sortBy(
var increasingByWidthDifference = _.sortBy(
_.keys(sizes),
function (size) { return Math.abs(targetImageWidth - sizes[size].width); }
),
bestWidth = sizes[_.first(increasingByWidthDifference)].width,
imagesOfBestWidth = _.filter(_.values(sizes), function(size) { return size.width === bestWidth; }),
);
var bestWidth = sizes[_.first(increasingByWidthDifference)].width;
var imagesOfBestWidth = _.filter(_.values(sizes), function (size) { return size.width === bestWidth; });
// Maximize the height if there are multiple images with same width
mainSize = _.max(imagesOfBestWidth, function(size) { return size.height; });
var mainSize = _.max(imagesOfBestWidth, function (size) { return size.height; });
that.model.set({
height: mainSize.height + 'px',
@ -363,7 +398,7 @@ define([
});
ImageWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.imageInsertion; },
getTemplate: function () { return window.templates.imageInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -378,7 +413,7 @@ define([
});
Module.ImageWidgetView = ImageWidgetView;
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('image', {
blockModel: Module.ImageBlockModel,
blockView: Module.ImageBlockView

View File

@ -39,8 +39,13 @@ define([
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
var PostsDisplayOptionsSettingsView;
var SinglePostSelectionSettingsView;
var EmptyPostSelectionSettingsView;
var PostSelectionSettingsView;
var PostsSelectionCollectionView;
Module.PostsBlockModel = base.BlockModel.extend({
stale: ['_selectedPosts', '_availablePosts', '_transformedPosts'],
@ -89,10 +94,9 @@ define([
};
},
initialize: function () {
var that = this,
POST_REFRESH_DELAY_MS = 500,
refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS),
refreshTransformedPosts = _.debounce(this._refreshTransformedPosts.bind(this), POST_REFRESH_DELAY_MS);
var POST_REFRESH_DELAY_MS = 500;
var refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS);
var refreshTransformedPosts = _.debounce(this._refreshTransformedPosts.bind(this), POST_REFRESH_DELAY_MS);
// Attach Radio.Requests API primarily for highlighting
_.extend(this, Radio.Requests);
@ -120,9 +124,9 @@ define([
});
},
_loadMorePosts: function () {
var that = this,
postCount = this.get('_availablePosts').length,
nextOffset = this.get('offset') + Number(this.get('amount'));
var that = this;
var postCount = this.get('_availablePosts').length;
var nextOffset = this.get('offset') + Number(this.get('amount'));
if (postCount === 0 || postCount < nextOffset) {
// No more posts to load
@ -141,8 +145,8 @@ define([
});
},
_refreshTransformedPosts: function () {
var that = this,
data = this.toJSON();
var that = this;
var data = this.toJSON();
data.posts = this.get('_selectedPosts').pluck('ID');
@ -158,10 +162,9 @@ define([
});
},
_insertSelectedPosts: function () {
var that = this,
data = this.toJSON(),
index = this.collection.indexOf(this),
collection = this.collection;
var data = this.toJSON();
var index = this.collection.indexOf(this);
var collection = this.collection;
data.posts = this.get('_selectedPosts').pluck('ID');
@ -177,7 +180,7 @@ define([
Module.PostsBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_posts_block mailpoet_droppable_block',
getTemplate: function() { return templates.postsBlock; },
getTemplate: function () { return window.templates.postsBlock; },
modelEvents: {}, // Forcefully disable all events
regions: _.extend({
postsRegion: '.mailpoet_posts_block_posts'
@ -190,12 +193,14 @@ define([
this.model.reply('blockView', this.notifyAboutSelf, this);
},
onRender: function () {
var ContainerView;
var renderOptions;
if (!this.getRegion('toolsRegion').hasView()) {
this.showChildView('toolsRegion', this.toolsView);
}
this.trigger('showSettings');
var ContainerView = App.getBlockTypeView('container'),
ContainerView = App.getBlockTypeView('container');
renderOptions = {
disableTextEditor: true,
disableDragAndDrop: true,
@ -216,7 +221,7 @@ define([
});
Module.PostsBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.postsBlockSettings; },
getTemplate: function () { return window.templates.postsBlockSettings; },
regions: {
selectionRegion: '.mailpoet_settings_posts_selection',
displayOptionsRegion: '.mailpoet_settings_posts_display_options'
@ -237,8 +242,8 @@ define([
this.displayOptionsView = new PostsDisplayOptionsSettingsView({ model: this.model });
},
onRender: function () {
var that = this,
blockView = this.model.request('blockView');
var that = this;
this.model.request('blockView');
this.showChildView('selectionRegion', this.selectionView);
this.showChildView('displayOptionsRegion', this.displayOptionsView);
@ -283,7 +288,7 @@ define([
}
});
var PostsSelectionCollectionView = Marionette.CollectionView.extend({
PostsSelectionCollectionView = Marionette.CollectionView.extend({
className: 'mailpoet_post_scroll_container',
childView: function () { return SinglePostSelectionSettingsView; },
emptyView: function () { return EmptyPostSelectionSettingsView; },
@ -307,8 +312,8 @@ define([
}
});
var PostSelectionSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.postSelectionPostsBlockSettings; },
PostSelectionSettingsView = Marionette.View.extend({
getTemplate: function () { return window.templates.postSelectionPostsBlockSettings; },
regions: {
posts: '.mailpoet_post_selection_container'
},
@ -334,9 +339,10 @@ define([
}
},
onRender: function () {
var postsView;
// Dynamically update available post types
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
var postsView = new PostsSelectionCollectionView({
postsView = new PostsSelectionCollectionView({
collection: this.model.get('_availablePosts'),
blockModel: this.model
});
@ -358,12 +364,13 @@ define([
},
transport: function (options, success, failure) {
var taxonomies;
var termsPromise;
var promise = CommunicationComponent.getTaxonomies(
that.model.get('contentType')
).then(function (tax) {
taxonomies = tax;
// Fetch available terms based on the list of taxonomies already fetched
var promise = CommunicationComponent.getTerms({
termsPromise = CommunicationComponent.getTerms({
search: options.data.term,
taxonomies: _.keys(taxonomies)
}).then(function (terms) {
@ -372,7 +379,7 @@ define([
terms: terms
};
});
return promise;
return termsPromise;
});
promise.then(success);
@ -413,8 +420,8 @@ define([
this.model.set(field, jQuery(event.target).val());
},
_updateContentTypes: function (postTypes) {
var select = this.$('.mailpoet_settings_posts_content_type'),
selectedValue = this.model.get('contentType');
var select = this.$('.mailpoet_settings_posts_content_type');
var selectedValue = this.model.get('contentType');
select.find('option').remove();
_.each(postTypes, function (type) {
@ -427,12 +434,12 @@ define([
}
});
var EmptyPostSelectionSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.emptyPostPostsBlockSettings; }
EmptyPostSelectionSettingsView = Marionette.View.extend({
getTemplate: function () { return window.templates.emptyPostPostsBlockSettings; }
});
var SinglePostSelectionSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.singlePostPostsBlockSettings; },
SinglePostSelectionSettingsView = Marionette.View.extend({
getTemplate: function () { return window.templates.singlePostPostsBlockSettings; },
events: function () {
return {
'change .mailpoet_select_post_checkbox': 'postSelectionChange'
@ -448,8 +455,8 @@ define([
this.blockModel = options.blockModel;
},
postSelectionChange: function (event) {
var checkBox = jQuery(event.target),
selectedPostsCollection = this.blockModel.get('_selectedPosts');
var checkBox = jQuery(event.target);
var selectedPostsCollection = this.blockModel.get('_selectedPosts');
if (checkBox.prop('checked')) {
selectedPostsCollection.add(this.model);
} else {
@ -458,8 +465,8 @@ define([
}
});
var PostsDisplayOptionsSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.displayOptionsPostsBlockSettings; },
PostsDisplayOptionsSettingsView = base.BlockSettingsView.extend({
getTemplate: function () { return window.templates.displayOptionsPostsBlockSettings; },
events: function () {
return {
'click .mailpoet_posts_select_button': 'showButtonSettings',
@ -488,7 +495,7 @@ define([
model: this.model.toJSON()
};
},
showButtonSettings: function(event) {
showButtonSettings: function () {
var buttonModule = ButtonBlock;
(new buttonModule.ButtonBlockSettingsView({
model: this.model.get('readMoreButton'),
@ -499,7 +506,7 @@ define([
}
})).render();
},
showDividerSettings: function(event) {
showDividerSettings: function () {
var dividerModule = DividerBlock;
(new dividerModule.DividerBlockSettingsView({
model: this.model.get('divider'),
@ -564,7 +571,7 @@ define([
});
Module.PostsWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.postsInsertion; },
getTemplate: function () { return window.templates.postsInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -575,7 +582,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('posts', {
blockModel: Module.PostsBlockModel,
blockView: Module.PostsBlockView

View File

@ -13,12 +13,13 @@ define([
'use strict';
var Module = {},
base = BaseBlock,
SocialBlockSettingsIconSelectorView,
SocialBlockSettingsIconView,
SocialBlockSettingsIconCollectionView,
SocialBlockSettingsStylesView;
var Module = {};
var base = BaseBlock;
var SocialBlockSettingsIconSelectorView;
var SocialBlockSettingsIconView;
var SocialBlockSettingsIconCollectionView;
var SocialBlockSettingsStylesView;
var SocialIconView;
Module.SocialIconModel = SuperModel.extend({
defaults: function () {
@ -33,12 +34,12 @@ define([
text: defaultValues.get('title')
};
},
initialize: function(options) {
initialize: function () {
var that = this;
// Make model swap to default values for that type when iconType changes
this.on('change:iconType', function () {
var defaultValues = App.getConfig().get('socialIcons').get(that.get('iconType')),
iconSet = that.collection.iconBlockModel.getIconSet();
var defaultValues = App.getConfig().get('socialIcons').get(that.get('iconType'));
var iconSet = that.collection.iconBlockModel.getIconSet();
this.set({
link: defaultValues.get('defaultLink'),
image: iconSet.get(that.get('iconType')),
@ -83,9 +84,9 @@ define([
}
});
var SocialIconView = Marionette.View.extend({
SocialIconView = Marionette.View.extend({
tagName: 'span',
getTemplate: function() { return templates.socialIconBlock; },
getTemplate: function () { return window.templates.socialIconBlock; },
modelEvents: {
change: 'render'
},
@ -105,7 +106,7 @@ define([
Module.SocialBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_social_block mailpoet_droppable_block',
getTemplate: function() { return templates.socialBlock; },
getTemplate: function () { return window.templates.socialBlock; },
regions: _.extend({}, base.BlockView.prototype.regions, {
icons: '.mailpoet_social'
}),
@ -131,7 +132,7 @@ define([
// Sidebar view container
Module.SocialBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.socialBlockSettings; },
getTemplate: function () { return window.templates.socialBlockSettings; },
regions: {
iconRegion: '#mailpoet_social_icons_selection',
stylesRegion: '#mailpoet_social_icons_styles'
@ -155,7 +156,7 @@ define([
// Single icon settings view, used by the selector view
SocialBlockSettingsIconView = Marionette.View.extend({
getTemplate: function() { return templates.socialSettingsIcon; },
getTemplate: function () { return window.templates.socialSettingsIcon; },
events: function () {
return {
'click .mailpoet_delete_block': 'deleteIcon',
@ -175,10 +176,10 @@ define([
}
},
templateContext: function () {
var icons = App.getConfig().get('socialIcons'),
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');
var availableIconTypes = _.map(_.keys(icons.attributes), function (key) { return { iconType: key, title: icons.get(key).get('title') }; });
var allIconSets = App.getAvailableStyles().get('socialIconSets');
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
iconTypes: availableIconTypes,
currentType: icons.get(this.model.get('iconType')).toJSON(),
@ -212,7 +213,7 @@ define([
// Select icons section container view
SocialBlockSettingsIconSelectorView = Marionette.View.extend({
getTemplate: function() { return templates.socialSettingsIconSelector; },
getTemplate: function () { return window.templates.socialSettingsIconSelector; },
regions: {
icons: '#mailpoet_social_icon_selector_contents'
},
@ -235,7 +236,7 @@ define([
});
SocialBlockSettingsStylesView = Marionette.View.extend({
getTemplate: function() { return templates.socialSettingsStyles; },
getTemplate: function () { return window.templates.socialSettingsStyles; },
modelEvents: {
change: 'render'
},
@ -263,7 +264,7 @@ define([
});
Module.SocialWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.socialInsertion; },
getTemplate: function () { return window.templates.socialInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -297,7 +298,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('social', {
blockModel: Module.SocialBlockModel,
blockView: Module.SocialBlockView

View File

@ -9,8 +9,8 @@ define([
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
Module.SpacerBlockModel = base.BlockModel.extend({
defaults: function () {
@ -28,7 +28,7 @@ define([
Module.SpacerBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_spacer_block mailpoet_droppable_block',
getTemplate: function() { return templates.spacerBlock; },
getTemplate: function () { return window.templates.spacerBlock; },
behaviors: _.defaults({
ResizableBehavior: {
elementSelector: '.mailpoet_spacer',
@ -66,7 +66,7 @@ define([
});
Module.SpacerBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.spacerBlockSettings; },
getTemplate: function () { return window.templates.spacerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_spacer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
@ -76,7 +76,7 @@ define([
});
Module.SpacerWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.spacerInsertion; },
getTemplate: function () { return window.templates.spacerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -87,7 +87,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('spacer', {
blockModel: Module.SpacerBlockModel,
blockView: Module.SpacerBlockView

View File

@ -4,13 +4,14 @@
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function(App, BaseBlock, _) {
'underscore',
'mailpoet'
], function (App, BaseBlock, _, MailPoet) {
'use strict';
var Module = {},
base = BaseBlock;
var Module = {};
var base = BaseBlock;
Module.TextBlockModel = base.BlockModel.extend({
defaults: function () {
@ -23,7 +24,7 @@ define([
Module.TextBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_text_block mailpoet_droppable_block',
getTemplate: function() { return templates.textBlock; },
getTemplate: function () { return window.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: {
@ -78,11 +79,11 @@ define([
});
Module.TextBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.textBlockSettings; }
getTemplate: function () { return window.templates.textBlockSettings; }
});
Module.TextWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.textInsertion; },
getTemplate: function () { return window.templates.textInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
@ -93,7 +94,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
App.registerBlockType('text', {
blockModel: Module.TextBlockModel,
blockView: Module.TextBlockView

View File

@ -7,15 +7,15 @@
*/
(function (root, factory) {
var Marionette = require('backbone.marionette');
var Radio = require('backbone.radio');
var _ = require('underscore');
if (typeof define === 'function' && define.amd) {
define(['backbone.marionette', 'backbone.radio', 'underscore'], function (Marionette, Radio, _) {
return factory(Marionette, Radio, _);
});
}
else if (typeof exports !== 'undefined') {
var Marionette = require('backbone.marionette');
var Radio = require('backbone.radio');
var _ = require('underscore');
module.exports = factory(Marionette, Radio, _);
}
else {

View File

@ -98,7 +98,7 @@ define([
});
};
App.on('start', function(App, options) {
App.on('start', function () {
// Prefetch post types
Module.getPostTypes();
});

View File

@ -13,7 +13,7 @@ define([
// handled by other components.
Module.NewsletterModel = SuperModel.extend({
whitelisted: ['id', 'subject', 'preheader'],
initialize: function(options) {
initialize: function () {
this.on('change', function () {
App.getChannel().trigger('autoSave');
});

View File

@ -3,15 +3,16 @@ define([
'backbone',
'backbone.marionette',
'underscore',
'jquery'
], function(App, Backbone, Marionette, _, jQuery) {
'jquery',
'mailpoet'
], function (App, Backbone, Marionette, _, jQuery, MailPoet) {
'use strict';
var Module = {};
Module.HeadingView = Marionette.View.extend({
getTemplate: function() { return templates.heading; },
getTemplate: function () { return window.templates.heading; },
templateContext: function () {
return {
model: this.model.toJSON()
@ -28,7 +29,7 @@ define([
}
});
App.on('start', function(App, options) {
App.on('start', function (App) {
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',

View File

@ -8,7 +8,9 @@ define([
'jquery',
'blob',
'file-saver',
'html2canvas'
'html2canvas',
'underscore',
'jquery'
], function (
App,
CommunicationComponent,
@ -19,13 +21,15 @@ define([
jQuery,
Blob,
FileSaver,
html2canvas
html2canvas,
_,
$
) {
'use strict';
var Module = {},
saveTimeout;
var Module = {};
var saveTimeout;
// Save editor contents to server
Module.save = function () {
@ -72,10 +76,9 @@ define([
// Temporary workaround for html2canvas-alpha2.
// Removes 1px left transparent border from resulting canvas.
var oldContext = oldCanvas.getContext('2d'),
newCanvas = document.createElement('canvas'),
newContext = newCanvas.getContext('2d'),
leftBorderWidth = 1;
var newCanvas = document.createElement('canvas');
var newContext = newCanvas.getContext('2d');
var leftBorderWidth = 1;
newCanvas.width = oldCanvas.width;
newCanvas.height = oldCanvas.height;
@ -91,8 +94,7 @@ define([
};
Module.saveTemplate = function (options) {
var that = this,
promise = jQuery.Deferred();
var promise = jQuery.Deferred();
promise.then(function (thumbnail) {
var data = _.extend(options || {}, {
@ -118,7 +120,6 @@ define([
};
Module.exportTemplate = function (options) {
var that = this;
return Module.getThumbnail(
jQuery('#mailpoet_editor_content > .mailpoet_block').get(0)
).then(function (thumbnail) {
@ -139,7 +140,7 @@ define([
};
Module.SaveView = Marionette.View.extend({
getTemplate: function() { return templates.save; },
getTemplate: function () { return window.templates.save; },
events: {
'click .mailpoet_save_button': 'save',
'click .mailpoet_save_show_options': 'toggleSaveOptions',
@ -151,7 +152,7 @@ define([
'click .mailpoet_save_export': 'toggleExportTemplate',
'click .mailpoet_export_template': 'exportTemplate'
},
initialize: function(options) {
initialize: function () {
App.getChannel().on('beforeEditorSave', this.beforeSave, this);
App.getChannel().on('afterEditorSave', this.afterSave, this);
},
@ -166,7 +167,7 @@ define([
// TODO: Add a loading animation instead
this.$('.mailpoet_autosaved_at').text(MailPoet.I18n.t('saving'));
},
afterSave: function(json, response) {
afterSave: function (json) {
this.validateNewsletter(json);
// Update 'Last saved timer'
this.$('.mailpoet_editor_last_saved').removeClass('mailpoet_hidden');
@ -188,9 +189,9 @@ define([
this.$('.mailpoet_save_as_template_container').addClass('mailpoet_hidden');
},
saveAsTemplate: function () {
var templateName = this.$('.mailpoet_save_as_template_name').val(),
templateDescription = this.$('.mailpoet_save_as_template_description').val(),
that = this;
var templateName = this.$('.mailpoet_save_as_template_name').val();
var templateDescription = this.$('.mailpoet_save_as_template_description').val();
var that = this;
if (templateName === '') {
MailPoet.Notice.error(
@ -244,9 +245,9 @@ define([
this.$('.mailpoet_export_template_container').addClass('mailpoet_hidden');
},
exportTemplate: function () {
var templateName = this.$('.mailpoet_export_template_name').val(),
templateDescription = this.$('.mailpoet_export_template_description').val(),
that = this;
var templateName = this.$('.mailpoet_export_template_name').val();
var templateDescription = this.$('.mailpoet_export_template_description').val();
var that = this;
if (templateName === '') {
MailPoet.Notice.error(
@ -281,18 +282,19 @@ define([
this.hideOptionContents();
if (!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
Module._cancelAutosave();
Module.save().done(function(response) {
Module.save().done(function () {
window.location.href = App.getConfig().get('urls.send');
});
}
},
validateNewsletter: function (jsonObject) {
var contents;
if (!App._contentContainer.isValid()) {
this.showValidationError(App._contentContainer.validationError);
return;
}
var contents = JSON.stringify(jsonObject);
contents = JSON.stringify(jsonObject);
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
contents.indexOf('[link:subscription_unsubscribe_url]') < 0 &&
contents.indexOf('[link:subscription_unsubscribe]') < 0) {
@ -336,9 +338,11 @@ define([
};
Module.beforeExitWithUnsavedChanges = function (e) {
var message;
var event;
if (saveTimeout) {
var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
var event = e || window.event;
message = MailPoet.I18n.t('unsavedChangesWillBeLost');
event = e || window.event;
if (event) {
event.returnValue = message;
@ -348,7 +352,7 @@ define([
}
};
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
var Application = App;
Application.save = Module.save;
Application.getChannel().on('autoSave', Module.autoSave);
@ -358,7 +362,7 @@ define([
Application.getChannel().reply('save', Application.save);
});
App.on('start', function(App, options) {
App.on('start', function (App) {
var saveView = new Module.SaveView();
App._appView.showChildView('bottomRegion', saveView);
});

View File

@ -6,8 +6,7 @@ define([
'backbone.marionette',
'backbone.supermodel',
'underscore',
'jquery',
'sticky-kit'
'jquery'
], function (
App,
CommunicationComponent,
@ -16,14 +15,13 @@ define([
Marionette,
SuperModel,
_,
jQuery,
StickyKit
jQuery
) {
'use strict';
var Module = {};
var SidebarView;
// Widget handlers for use to create new content blocks via drag&drop
Module._contentWidgets = new (Backbone.Collection.extend({
model: SuperModel.extend({
@ -52,8 +50,8 @@ define([
Module.registerLayoutWidget = function (widget) { return Module._layoutWidgets.add(widget); };
Module.getLayoutWidgets = function () { return Module._layoutWidgets; };
var SidebarView = Marionette.View.extend({
getTemplate: function() { return templates.sidebar; },
SidebarView = Marionette.View.extend({
getTemplate: function () { return window.templates.sidebar; },
regions: {
contentRegion: '.mailpoet_content_region',
layoutRegion: '.mailpoet_layout_region',
@ -62,8 +60,8 @@ define([
},
events: {
'click .mailpoet_sidebar_region h3, .mailpoet_sidebar_region .handlediv': function (event) {
var $openRegion = this.$el.find('.mailpoet_sidebar_region:not(.closed)'),
$targetRegion = this.$el.find(event.target).closest('.mailpoet_sidebar_region');
var $openRegion = this.$el.find('.mailpoet_sidebar_region:not(.closed)');
var $targetRegion = this.$el.find(event.target).closest('.mailpoet_sidebar_region');
$openRegion.find('.mailpoet_region_content').velocity(
'slideUp',
@ -90,7 +88,7 @@ define([
}
}
},
initialize: function(options) {
initialize: function () {
jQuery(window)
.on('resize', this.updateHorizontalScroll.bind(this))
.on('scroll', this.updateHorizontalScroll.bind(this));
@ -113,9 +111,8 @@ define([
// position of the sidebar would be scrollable and not fixed
// partially out of visible screen
this.$el.parent().each(function () {
var calculated_left, self;
self = jQuery(this);
var calculated_left;
var self = jQuery(this);
if (self.css('position') === 'fixed') {
calculated_left = self.parent().offset().left - jQuery(window).scrollLeft();
@ -147,7 +144,7 @@ define([
* Responsible for rendering draggable content widgets
*/
Module.SidebarWidgetsView = Marionette.View.extend({
getTemplate: function() { return templates.sidebarContent; },
getTemplate: function () { return window.templates.sidebarContent; },
regions: {
widgets: '.mailpoet_region_content'
},
@ -167,14 +164,14 @@ define([
* Responsible for rendering draggable layout widgets
*/
Module.SidebarLayoutWidgetsView = Module.SidebarWidgetsView.extend({
getTemplate: function() { return templates.sidebarLayout; }
getTemplate: function () { return window.templates.sidebarLayout; }
});
/**
* Responsible for managing global styles
*/
Module.SidebarStylesView = Marionette.View.extend({
getTemplate: function() { return templates.sidebarStyles; },
getTemplate: function () { return window.templates.sidebarStyles; },
behaviors: {
ColorPickerBehavior: {}
},
@ -238,7 +235,7 @@ define([
});
Module.SidebarPreviewView = Marionette.View.extend({
getTemplate: function() { return templates.sidebarPreview; },
getTemplate: function () { return window.templates.sidebarPreview; },
events: {
'click .mailpoet_show_preview': 'showPreview',
'click #mailpoet_send_preview': 'sendPreview'
@ -271,7 +268,7 @@ define([
previewUrl: response.meta.preview_url
});
var view = this.previewView.render();
this.previewView.render();
this.previewView.$el.css('height', '100%');
MailPoet.Modal.popup({
@ -324,7 +321,7 @@ define([
App.getChannel().request('save').always(function () {
CommunicationComponent.previewNewsletter(data).always(function () {
MailPoet.Modal.loading(false);
}).done(function(response) {
}).done(function () {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterPreviewSent'),
{ scroll: true }
@ -346,7 +343,7 @@ define([
});
Module.NewsletterPreviewView = Marionette.View.extend({
getTemplate: function() { return templates.newsletterPreview; },
getTemplate: function () { return window.templates.newsletterPreview; },
initialize: function (options) {
this.previewUrl = options.previewUrl;
this.width = '100%';
@ -363,7 +360,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App) {
var Application = App;
Application.registerWidget = Module.registerWidget;
Application.getWidgets = Module.getWidgets;
@ -371,9 +368,8 @@ define([
Application.getLayoutWidgets = Module.getLayoutWidgets;
});
App.on('start', function(App, options) {
var stylesModel = App.getGlobalStyles(),
sidebarView = new SidebarView();
App.on('start', function (App) {
var sidebarView = new SidebarView();
App._appView.showChildView('sidebarRegion', sidebarView);

View File

@ -1,8 +1,9 @@
define([
'newsletter_editor/App',
'backbone.marionette',
'backbone.supermodel'
], function(App, Marionette, SuperModel) {
'backbone.supermodel',
'underscore'
], function (App, Marionette, SuperModel, _) {
'use strict';
@ -47,7 +48,7 @@ define([
});
Module.StylesView = Marionette.View.extend({
getTemplate: function() { return templates.styles; },
getTemplate: function () { return window.templates.styles; },
modelEvents: {
change: 'render'
},
@ -70,17 +71,19 @@ define([
App.on('before:start', function (App, options) {
var Application = App;
var body;
var globalStyles;
// Expose style methods to global application
Application.getGlobalStyles = Module.getGlobalStyles;
Application.setGlobalStyles = Module.setGlobalStyles;
Application.getAvailableStyles = Module.getAvailableStyles;
var body = options.newsletter.body;
var globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};
body = options.newsletter.body;
globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};
this.setGlobalStyles(globalStyles);
});
App.on('start', function(App, options) {
App.on('start', function (App) {
var stylesView = new Module.StylesView({ model: App.getGlobalStyles() });
App._appView.showChildView('stylesRegion', stylesView);
});

View File

@ -10,12 +10,12 @@
/* jshint unused:false */
/* global tinymce:true */
tinymce.PluginManager.add('mailpoet_shortcodes', function(editor, url) {
tinymce.PluginManager.add('mailpoet_shortcodes', function (editor) {
var appendLabelAndClose = function (shortcode) {
editor.insertContent(shortcode);
editor.windowManager.close();
},
generateOnClickFunc = function(shortcode) {
};
var generateOnClickFunc = function (shortcode) {
return function () {
appendLabelAndClose(shortcode);
};
@ -24,17 +24,19 @@ tinymce.PluginManager.add('mailpoet_shortcodes', function(editor, url) {
editor.addButton('mailpoet_shortcodes', {
icon: 'mailpoet_shortcodes',
onclick: function () {
var shortcodes = [],
configShortcodes = editor.settings.mailpoet_shortcodes;
var shortcodes = [];
var configShortcodes = editor.settings.mailpoet_shortcodes;
var segment;
var i;
for (var segment in configShortcodes) {
for (segment in configShortcodes) {
if (configShortcodes.hasOwnProperty(segment)) {
shortcodes.push({
type: 'label',
text: segment
});
for (var i = 0; i < configShortcodes[segment].length; i += 1) {
for (i = 0; i < configShortcodes[segment].length; i += 1) {
shortcodes.push({
type: 'button',
text: configShortcodes[segment][i].text,

View File

@ -1,27 +0,0 @@
/**
* A sample implementation of template widgets.
* A draggable widget, on drop creates a container with (image|text) block.
*/
ImageAndTextTemplateWidgetView = EditorApplication.module('blocks.base').WidgetView.extend({
getTemplate: function() { return templates.imageAndTextInsertion; },
className: 'mailpoet_droppable_block mailpoet_droppable_widget',
behaviors: {
DraggableBehavior: {
drop: function() {
return new (EditorApplication.getBlockTypeModel('container'))({
type: 'container',
orientation: 'horizontal',
blocks: [
{
type: 'image'
},
{
type: 'text',
text: 'Some random text'
}
]
}, {parse: true});
}
}
}
});

View File

@ -179,11 +179,11 @@ const _StatisticsMixin = {
const percentage_opened_display = MailPoet.Num.toLocaleFixed(percentage_opened, 1);
const percentage_unsubscribed_display = MailPoet.Num.toLocaleFixed(percentage_unsubscribed, 1);
let show_stats_timeout,
newsletter_date,
sent_hours_ago,
too_early_for_stats,
show_kb_link;
let show_stats_timeout;
let newsletter_date;
let sent_hours_ago;
let too_early_for_stats;
let show_kb_link;
if (current_time !== undefined) {
// standard emails and post notifications:
// display green box for newsletters that were just sent

View File

@ -185,7 +185,7 @@ const NewsletterListNotification = React.createClass({
return (
<select
data-id={newsletter.id}
defaultValue={ newsletter.status }
defaultValue={newsletter.status}
onChange={this.updateStatus}
>
<option value="active">{ MailPoet.I18n.t('active') }</option>
@ -317,7 +317,7 @@ const NewsletterListNotification = React.createClass({
<ListingTabs tab="notification" />
<Listing
limit={ mailpoet_listing_per_page }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"

View File

@ -110,7 +110,7 @@ const NewsletterListNotificationHistory = React.createClass({
>{MailPoet.I18n.t('backToPostNotifications')}</Link>
<Listing
limit={ mailpoet_listing_per_page }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"

View File

@ -218,7 +218,7 @@ const NewsletterListStandard = React.createClass({
<ListingTabs tab="standard" />
<Listing
limit={ mailpoet_listing_per_page }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"

View File

@ -165,7 +165,7 @@ const NewsletterListWelcome = React.createClass({
<p>
<select
data-id={newsletter.id}
defaultValue={ newsletter.status }
defaultValue={newsletter.status}
onChange={this.updateStatus}
>
<option value="active">{ MailPoet.I18n.t('active') }</option>
@ -295,7 +295,7 @@ const NewsletterListWelcome = React.createClass({
<ListingTabs tab="welcome" />
<Listing
limit={ mailpoet_listing_per_page }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"

View File

@ -10,6 +10,7 @@ define(
'newsletters/send/welcome.jsx',
'newsletters/breadcrumb.jsx',
'help-tooltip.jsx',
'jquery',
],
(
React,
@ -21,7 +22,8 @@ define(
NotificationNewsletterFields,
WelcomeNewsletterFields,
Breadcrumb,
HelpTooltip
HelpTooltip,
jQuery
) => {
const NewsletterSend = React.createClass({
@ -283,6 +285,7 @@ define(
}
return newField;
});
const sendButtonOptions = this.getSendButtonOptions();
return (
<div>
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
@ -311,7 +314,7 @@ define(
type="button"
onClick={this.handleSend}
value={MailPoet.I18n.t('send')}
{...this.getSendButtonOptions()}
{...sendButtonOptions}
/>
}
&nbsp;
@ -328,10 +331,12 @@ define(
{MailPoet.I18n.t('goBackToDesign')}
</a>.
</p>
{ !isPaused && sendButtonOptions['disabled'] && sendButtonOptions['disabled'] === 'disabled' && (
<HelpTooltip
tooltip={MailPoet.I18n.t('helpTooltipSendEmail')}
tooltipId="helpTooltipSendEmail"
/>
) }
</Form>
</div>
);

View File

@ -47,6 +47,8 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
return this;
},
createNotice: function () {
var onClose;
var positionAfter;
// clone element
this.element = jQuery('#mailpoet_notice_' + this.options.type).clone();
@ -62,7 +64,6 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
this.element.removeAttr('id');
// insert notice after its parent
var positionAfter;
if (typeof this.options.positionAfter === 'object') {
positionAfter = this.options.positionAfter;
} else if (typeof this.options.positionAfter === 'string') {
@ -73,7 +74,7 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
positionAfter.after(this.element);
// setup onClose callback
var onClose = null;
onClose = null;
if (this.options.onClose !== null) {
onClose = this.options.onClose;
}
@ -177,12 +178,13 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
}
},
hide: function (all) {
var id;
if (all !== undefined && all === true) {
// all notices
jQuery('.mailpoet_notice:not([id])').trigger('close');
} else if (all !== undefined && jQuery.isArray(all)) {
// array of ids
for (var id in all) {
for (id in all) {
jQuery('[data-id="' + all[id] + '"]').trigger('close');
}
} if (all !== undefined) {

View File

@ -1,12 +1,10 @@
define([
'mailpoet',
'jquery',
'parsleyjs'
'jquery'
],
function (
MailPoet,
jQuery,
Parsley
jQuery
) {
jQuery(function ($) {
function isSameDomain(url) {
@ -20,7 +18,7 @@ function(
$('form.mailpoet_form').each(function () {
var form = $(this);
form.parsley().on('form:validated', function(parsley) {
form.parsley().on('form:validated', function () {
// clear messages
form.find('.mailpoet_message > p').hide();
@ -33,13 +31,13 @@ function(
form.parsley().on('form:submit', function (parsley) {
var form_data = form.serializeObject() || {};
// check if we're on the same domain
if(isSameDomain(MailPoetForm.ajax_url) === false) {
if (isSameDomain(window.MailPoetForm.ajax_url) === false) {
// non ajax post request
return true;
} else {
// ajax request
MailPoet.Ajax.post({
url: MailPoetForm.ajax_url,
url: window.MailPoetForm.ajax_url,
token: form_data.token,
api_version: form_data.api_version,
endpoint: 'subscribers',

View File

@ -210,7 +210,7 @@ const SegmentList = React.createClass({
if (segment.type === 'wp_users') {
// the WP users segment is not editable so just display its name
segment_name = (
<span className="row-title">{ segment.name }</span>
<span className="row-title">{ segment.name }</span>
);
} else {
segment_name = (
@ -258,7 +258,7 @@ const SegmentList = React.createClass({
</h1>
<Listing
limit={ mailpoet_listing_per_page }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
messages={messages}

View File

@ -5,7 +5,7 @@ define(
function (
MailPoet
) {
var element;
function eventHandler() {
if (confirm(MailPoet.I18n.t('reinstallConfirmation'))) {
MailPoet.trackEvent(
@ -36,7 +36,7 @@ define(
return false;
}
var element = document.getElementById('mailpoet_reinstall');
element = document.getElementById('mailpoet_reinstall');
if (element) {
element.addEventListener('click', eventHandler, false);
}

View File

@ -51,7 +51,7 @@ define(
jQuery('#mailpoet_sending_method_setup').fadeIn();
}
},
tabs: function(tabStr, section) {
tabs: function (tabStr) {
// set default tab
var tab = tabStr || 'mta';

View File

@ -107,7 +107,7 @@ define(
},
];
const custom_fields = window.mailpoet_custom_fields || [];
const custom_fields = window.mailpoet_custom_fields || [];
custom_fields.map((custom_field) => {
const field = {
name: 'cf_' + custom_field.id,

View File

@ -3,35 +3,40 @@ define(
'underscore',
'jquery',
'mailpoet',
'handlebars',
'select2'
'handlebars'
],
function (
_,
jQuery,
MailPoet,
Handlebars,
select2
Handlebars
) {
if (!jQuery('#mailpoet_subscribers_export').length) {
return;
}
jQuery(document).ready(function () {
if (!exportData.segments) {
var segmentsContainerElement;
var subscriberFieldsContainerElement;
var exportConfirmedOptionElement;
var groupBySegmentOptionElement;
var nextStepButton;
var renderSegmentsAndFields;
var subscribers_export_template;
if (!window.exportData.segments) {
return;
}
var subscribers_export_template =
subscribers_export_template =
Handlebars.compile(jQuery('#mailpoet_subscribers_export_template').html());
// render template
jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(exportData));
jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(window.exportData));
// define reusable variables
var segmentsContainerElement = jQuery('#export_lists'),
subscriberFieldsContainerElement = jQuery('#export_columns'),
exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]'),
groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]'),
nextStepButton = jQuery('a.mailpoet_export_process'),
segmentsContainerElement = jQuery('#export_lists');
subscriberFieldsContainerElement = jQuery('#export_columns');
exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]');
groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]');
nextStepButton = jQuery('a.mailpoet_export_process');
renderSegmentsAndFields = function (container, data) {
if (container.data('select2')) {
container
@ -54,18 +59,19 @@ define(
}
})
.on('select2:selecting', function (selectEvent) {
var selectElement = this,
selectedOptionId = selectEvent.params.args.data.id,
fieldsToExclude = [
var selectElement = this;
var selectedOptionId = selectEvent.params.args.data.id;
var fieldsToExclude = [
'select',
'deselect'
];
var allOptions;
if (_.contains(fieldsToExclude, selectedOptionId)) {
selectEvent.preventDefault();
if (selectedOptionId === 'deselect') {
jQuery(selectElement).val('').trigger('change');
} else {
var allOptions = [];
allOptions = [];
_.each(container.find('option'), function (field) {
if (!_.contains(fieldsToExclude, field.value)) {
allOptions.push(field.value);
@ -77,9 +83,9 @@ define(
}
})
.on('change', function () {
if ((exportData.segments && segmentsContainerElement.select2('data').length && subscriberFieldsContainerElement.select2('data').length)
if ((window.exportData.segments && segmentsContainerElement.select2('data').length && subscriberFieldsContainerElement.select2('data').length)
||
(!exportData.segments && subscriberFieldsContainerElement.select2('data').length)
(!window.exportData.segments && subscriberFieldsContainerElement.select2('data').length)
) {
toggleNextStepButton('on');
}
@ -87,20 +93,20 @@ define(
toggleNextStepButton('off');
}
if (segmentsContainerElement.select2('data').length > 1 && exportData.groupBySegmentOption) {
if (segmentsContainerElement.select2('data').length > 1 && window.exportData.groupBySegmentOption) {
jQuery('.mailpoet_group_by_list').show();
}
else if (exportData.groupBySegmentOption) {
else if (window.exportData.groupBySegmentOption) {
jQuery('.mailpoet_group_by_list').hide();
}
});
};
// set confirmed subscribers export option to false
exportData.exportConfirmedOption = false;
window.exportData.exportConfirmedOption = false;
renderSegmentsAndFields(subscriberFieldsContainerElement, subscriberFieldsSelect2);
renderSegmentsAndFields(segmentsContainerElement, segments);
renderSegmentsAndFields(subscriberFieldsContainerElement, window.subscriberFieldsSelect2);
renderSegmentsAndFields(segmentsContainerElement, window.segments);
subscriberFieldsContainerElement.val([
'email',
@ -112,12 +118,12 @@ define(
exportConfirmedOptionElement.change(function () {
var selectedSegments = segmentsContainerElement.val();
if (this.value == 1) {
exportData.exportConfirmedOption = true;
renderSegmentsAndFields(segmentsContainerElement, segmentsWithConfirmedSubscribers);
window.exportData.exportConfirmedOption = true;
renderSegmentsAndFields(segmentsContainerElement, window.segmentsWithConfirmedSubscribers);
}
else {
exportData.exportConfirmedOption = false;
renderSegmentsAndFields(segmentsContainerElement, segments);
window.exportData.exportConfirmedOption = false;
renderSegmentsAndFields(segmentsContainerElement, window.segments);
}
segmentsContainerElement.val(selectedSegments).trigger('change');
});
@ -133,26 +139,27 @@ define(
}
nextStepButton.click(function () {
var exportFormat;
if (jQuery(this).hasClass('button-disabled')) {
return;
}
MailPoet.Modal.loading(true);
var exportFormat = jQuery(':radio[name="option_format"]:checked').val();
exportFormat = jQuery(':radio[name="option_format"]:checked').val();
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'ImportExport',
action: 'processExport',
data: JSON.stringify({
export_confirmed_option: exportData.exportConfirmedOption,
export_confirmed_option: window.exportData.exportConfirmedOption,
export_format_option: exportFormat,
group_by_segment_option: (groupBySegmentOptionElement.is(':visible')) ? groupBySegmentOptionElement.prop('checked') : false,
segments: (exportData.segments) ? segmentsContainerElement.val() : false,
segments: (window.exportData.segments) ? segmentsContainerElement.val() : false,
subscriber_fields: subscriberFieldsContainerElement.val()
})
}).always(function(response) {
}).always(function () {
MailPoet.Modal.loading(false);
}).done(function (response) {
resultMessage = MailPoet.I18n.t('exportMessage')
var resultMessage = MailPoet.I18n.t('exportMessage')
.replace('%1$s', '<strong>' + parseInt(response.data.totalExported).toLocaleString() + '</strong>')
.replace('[link]', '<a href="' + response.data.exportFileURL + '" target="_blank" >')
.replace('[/link]', '</a>');
@ -160,7 +167,7 @@ define(
window.location.href = response.data.exportFileURL;
MailPoet.trackEvent('Subscribers export completed', {
'Total exported': response.data.totalExported,
'Only confirmed?': exportData.exportConfirmedOption,
'Only confirmed?': window.exportData.exportConfirmedOption,
'File Format': exportFormat,
'MailPoet Free version': window.mailpoet_version
});

View File

@ -7,8 +7,7 @@ define(
'handlebars',
'papaparse',
'asyncqueue',
'moment',
'select2'
'moment'
],
function (
Backbone,
@ -18,13 +17,13 @@ define(
Handlebars,
Papa,
AsyncQueue,
Moment,
select2
Moment
) {
if (!jQuery('#mailpoet_subscribers_import').length) {
return;
}
jQuery(document).ready(function () {
var router;
jQuery('input[name="select_method"]').attr('checked', false);
// configure router
router = new (Backbone.Router.extend({
@ -50,49 +49,59 @@ define(
* STEP 1 (upload or copy/paste)
*/
router.on('route:step1', function () {
var methodProcessContainerTemplate;
var currentStepE;
var methodSelectionElement;
var pasteInputElement;
var pasteInputPlaceholderElement;
var pasteProcessButtonElement;
var mailChimpKeyInputElement;
var mailChimpKeyVerifyButtonElement;
var mailChimpListsContainerElement;
var mailChimpProcessButtonElement;
var uploadElement;
var uploadProcessButtonElement;
// set or reset temporary validation rule on all columns
mailpoetColumns = jQuery.map(mailpoetColumns, function (column, columnIndex) {
window.mailpoetColumns = jQuery.map(window.mailpoetColumns, function (column) {
var col = column;
col.validation_rule = false;
return col;
});
if (typeof (importData.step1) !== 'undefined') {
if (typeof (window.importData.step1) !== 'undefined') {
showCurrentStep();
return;
}
// render process button for each method
var methodProcessContainerTemplate =
methodProcessContainerTemplate =
Handlebars.compile(jQuery('#method_process_template').html());
jQuery('.mailpoet_method_process').html(methodProcessContainerTemplate());
// define reusable variables
var currentStepE = jQuery(location.hash),
methodSelectionElement = jQuery('#select_method'),
pasteInputElement = jQuery('#paste_input'),
currentStepE = jQuery(location.hash);
methodSelectionElement = jQuery('#select_method');
pasteInputElement = jQuery('#paste_input');
pasteInputPlaceholderElement =
pasteInputElement.data('placeholder').replace(/\\n/g, '\n'),
pasteInputElement.data('placeholder').replace(/\\n/g, '\n');
pasteProcessButtonElement =
jQuery('#method_paste > div.mailpoet_method_process')
.find('a.mailpoet_process'),
mailChimpKeyInputElement = jQuery('#mailchimp_key'),
mailChimpKeyVerifyButtonElement = jQuery('#mailchimp_key_verify'),
mailChimpListsContainerElement = jQuery('#mailchimp_lists'),
mailChimpProcessButtonElement =
jQuery('#method_mailchimp > div.mailpoet_method_process')
.find('a.mailpoet_process'),
uploadElement = jQuery('#file_local'),
.find('a.mailpoet_process');
mailChimpKeyInputElement = jQuery('#mailchimp_key');
mailChimpKeyVerifyButtonElement = jQuery('#mailchimp_key_verify');
mailChimpListsContainerElement = jQuery('#mailchimp_lists');
mailChimpProcessButtonElement = jQuery('#method_mailchimp > div.mailpoet_method_process')
.find('a.mailpoet_process');
uploadElement = jQuery('#file_local');
uploadProcessButtonElement =
jQuery('#method_file > div.mailpoet_method_process')
.find('a.mailpoet_process');
// define method change behavior
methodSelectionElement.change(function () {
var available_methods = jQuery(':radio[name="select_method"]');
var selected_method = available_methods.index(available_methods.filter(':checked'));
MailPoet.Notice.hide();
var available_methods = jQuery(':radio[name="select_method"]'),
selected_method =
available_methods.index(available_methods.filter(':checked'));
// hide all methods
currentStepE.find('.inside')
.children('div[id^="method_"]')
@ -131,10 +140,10 @@ define(
});
pasteProcessButtonElement.click(function () {
var pasteSize = encodeURI(pasteInputElement.val()).split(/%..|./).length - 1;
MailPoet.Notice.hide();
// get an approximate size of textarea paste in bytes
var pasteSize = encodeURI(pasteInputElement.val()).split(/%..|./).length - 1;
if (pasteSize > maxPostSizeBytes) {
if (pasteSize > window.maxPostSizeBytes) {
MailPoet.Notice.error(MailPoet.I18n.t('maxPostSizeNotice'));
return;
}
@ -149,8 +158,8 @@ define(
* CSV file
*/
uploadElement.change(function () {
MailPoet.Notice.hide();
var ext = this.value.match(/\.(.+)$/);
MailPoet.Notice.hide();
if (ext === null || ext[1].toLowerCase() !== 'csv') {
this.value = '';
MailPoet.Notice.error(MailPoet.I18n.t('wrongFileFormat'));
@ -234,10 +243,10 @@ define(
api_key: mailChimpKeyInputElement.val(),
lists: mailChimpListsContainerElement.find('select').val()
}
}).always(function(response) {
}).always(function () {
MailPoet.Modal.loading(false);
}).done(function (response) {
importData.step1 = response.data;
window.importData.step1 = response.data;
MailPoet.trackEvent('Subscribers import started', {
source: 'MailChimp',
'MailPoet Free version': window.mailpoet_version
@ -294,20 +303,20 @@ define(
}
function parseCSV(isFile) {
var processedSubscribers = [],
parsedEmails = [],
duplicateEmails = [],
invalidEmails = [],
emailColumnPosition = null,
columnCount = null,
isHeaderFound = false,
advancedOptionHeader = true,
advancedOptionDelimiter = '',
advancedOptionNewline = '',
advancedOptionComments = false,
var processedSubscribers = [];
var parsedEmails = [];
var duplicateEmails = [];
var invalidEmails = [];
var emailColumnPosition = null;
var columnCount = null;
var isHeaderFound = false;
var advancedOptionHeader = true;
var advancedOptionDelimiter = '';
var advancedOptionNewline = '';
var advancedOptionComments = false;
// trim spaces, commas, periods,
// single/double quotes and convert to lowercase
detectAndCleanupEmail = function (emailString) {
var detectAndCleanupEmail = function (emailString) {
var test;
// decode HTML entities
var email = jQuery('<div />').html(emailString).text();
@ -347,11 +356,18 @@ define(
MailPoet.Notice.error(MailPoet.I18n.t('dataProcessingError'));
},
complete: function (CSV) {
for (var rowCount in CSV.data) {
var rowData = CSV.data[rowCount].map(function (el) {
var email;
var emailAddress;
var column;
var rowCount;
var rowData;
var rowColumnCount;
var errorNotice;
for (rowCount in CSV.data) {
rowData = CSV.data[rowCount].map(function (el) {
return el.trim();
});
var rowColumnCount = rowData.length;
rowColumnCount = rowData.length;
// set the number of row elements based on the first non-empty row
if (columnCount === null) {
columnCount = rowColumnCount;
@ -365,14 +381,14 @@ define(
// determine position of email address inside an array; this is
// done once and then email regex is run just on that element for each row
if (emailColumnPosition === null) {
for (var column in rowData) {
var email = detectAndCleanupEmail(rowData[column]);
for (column in rowData) {
emailAddress = detectAndCleanupEmail(rowData[column]);
if (emailColumnPosition === null
&& emailRegex.test(email)) {
&& window.emailRegex.test(emailAddress)) {
emailColumnPosition = column;
parsedEmails[email] = true; // add current e-mail to an object index
rowData[column] = email;
processedSubscribers[email] = rowData;
parsedEmails[emailAddress] = true; // add current e-mail to an object index
rowData[column] = emailAddress;
processedSubscribers[emailAddress] = rowData;
}
}
if (emailColumnPosition === null
@ -383,11 +399,11 @@ define(
}
}
else if (rowData[emailColumnPosition] !== '') {
var email = detectAndCleanupEmail(rowData[emailColumnPosition]);
email = detectAndCleanupEmail(rowData[emailColumnPosition]);
if (_.has(parsedEmails, email)) {
duplicateEmails.push(email);
}
else if (!emailRegex.test(email)) {
else if (!window.emailRegex.test(email)) {
invalidEmails.push(rowData[emailColumnPosition]);
}
// if we haven't yet processed this e-mail and it passed
@ -410,8 +426,8 @@ define(
) {
// since we assume that the header line is always present, we need
// to detect the header by checking if it contains a valid e-mail address
importData.step1 = {
header: (!emailRegex.test(
window.importData.step1 = {
header: (!window.emailRegex.test(
processedSubscribers[0][emailColumnPosition])
) ? processedSubscribers.shift() : null,
subscribers: processedSubscribers,
@ -427,7 +443,7 @@ define(
}
else {
MailPoet.Modal.loading(false);
var errorNotice = MailPoet.I18n.t('noValidRecords');
errorNotice = MailPoet.I18n.t('noValidRecords');
errorNotice = errorNotice.replace('[link]', MailPoet.I18n.t('csvKBLink'));
errorNotice = errorNotice.replace('[/link]', '</a>');
MailPoet.Notice.error(errorNotice);
@ -438,37 +454,41 @@ define(
});
router.on('route:step2', function () {
if (typeof (importData.step1) === 'undefined') {
var nextStepButton;
var previousStepButton;
var subscribers;
var subscribersDataTemplate;
var subscribersDataTemplatePartial;
var subscribersDataParseResultsTemplate;
var segmentSelectElement;
var maxRowsToShow;
var filler;
var fillerArray;
var fillerPosition;
var import_results;
var duplicates;
var email;
if (typeof (window.importData.step1) === 'undefined') {
router.navigate('step1', { trigger: true });
return;
}
// define reusable variables
var nextStepButton = jQuery('#step2_process'),
previousStepButton = jQuery('#return_to_step1'),
nextStepButton = jQuery('#step2_process');
previousStepButton = jQuery('#return_to_step1');
// create a copy of subscribers object for further manipulation
subscribers = jQuery.extend(true, {}, importData.step1),
subscribersDataTemplate =
Handlebars
.compile(jQuery('#subscribers_data_template')
.html()),
subscribersDataTemplatePartial =
Handlebars
.compile(jQuery('#subscribers_data_template_partial')
.html()),
subscribersDataParseResultsTemplate =
Handlebars
.compile(jQuery('#subscribers_data_parse_results_template')
.html()),
segmentSelectElement = jQuery('#mailpoet_segments_select'),
maxRowsToShow = 10,
filler = '. . .',
subscribers = jQuery.extend(true, {}, window.importData.step1);
subscribersDataTemplate = Handlebars.compile(jQuery('#subscribers_data_template').html());
subscribersDataTemplatePartial = Handlebars.compile(jQuery('#subscribers_data_template_partial').html());
subscribersDataParseResultsTemplate = Handlebars.compile(jQuery('#subscribers_data_parse_results_template').html());
segmentSelectElement = jQuery('#mailpoet_segments_select');
maxRowsToShow = 10;
filler = '. . .';
// create an array of filler data with the same number of
// elements as in the subscribers' data row
fillerArray = Array.apply(
null,
new Array(subscribers.subscribers[0].length)
).map(String.prototype.valueOf, filler),
fillerPosition;
).map(String.prototype.valueOf, filler);
showCurrentStep();
@ -480,12 +500,12 @@ define(
if (subscribers.invalid.length || subscribers.duplicate.length) {
// count repeating e-mails inside duplicate array and present them in
// 'email (xN)' format
var duplicates = {};
duplicates = {};
subscribers.duplicate.forEach(function (email) {
duplicates[email] = (duplicates[email] || 0) + 1;
});
subscribers.duplicate = [];
for (var email in duplicates) {
for (email in duplicates) {
if (duplicates[email] > 1) {
subscribers.duplicate.push(email + ' (x' + duplicates[email] + ')');
}
@ -494,7 +514,7 @@ define(
}
}
var import_results = {
import_results = {
notice: MailPoet.I18n.t('importNoticeSkipped').replace(
'%1$s',
'<strong>' + (subscribers.invalid.length + subscribers.duplicate.length) + '</strong>'
@ -526,7 +546,7 @@ define(
});
// show available segments
if (mailpoetSegments.length) {
if (window.mailpoetSegments.length) {
jQuery('.mailpoet_segments').show();
}
else {
@ -599,20 +619,21 @@ define(
description: segmentDescription
}
}).done(function (response) {
mailpoetSegments.push({
var selected_values;
window.mailpoetSegments.push({
id: response.data.id,
name: response.data.name,
subscriberCount: 0
});
var selected_values = segmentSelectElement.val();
selected_values = segmentSelectElement.val();
if (selected_values === null) {
selected_values = [response.data.id];
} else {
selected_values.push(response.data.id);
}
enableSegmentSelection(mailpoetSegments);
enableSegmentSelection(window.mailpoetSegments);
segmentSelectElement.val(selected_values).trigger('change');
jQuery('.mailpoet_segments:hidden').show();
jQuery('.mailpoet_no_segments:visible').hide();
@ -642,23 +663,28 @@ define(
Handlebars.registerHelper(
'show_and_match_columns',
function (subscribers, options) {
var displayedColumns = [],
displayedColumnsIds = [];
var displayedColumns = [];
var displayedColumnsIds = [];
var i;
var columnData;
var columnId;
var headerName;
var headerNameMatch;
// go through all elements of the first row in subscribers data
for (var i in subscribers.subscribers[0]) {
var columnData = subscribers.subscribers[0][i],
for (i in subscribers.subscribers[0]) {
columnData = subscribers.subscribers[0][i];
columnId = 'ignore'; // set default column type
// if the column is not undefined and has a valid e-mail, set type as email
if (columnData % 1 !== 0 && emailRegex.test(columnData)) {
if (columnData % 1 !== 0 && window.emailRegex.test(columnData)) {
columnId = 'email';
} else if (subscribers.header) {
var headerName = subscribers.header[i],
headerNameMatch = mailpoetColumns.map(function (el) {
headerName = subscribers.header[i];
headerNameMatch = window.mailpoetColumns.map(function (el) {
return el.name;
}).indexOf(headerName);
// set column type using header
if (headerNameMatch !== -1) {
columnId = mailpoetColumns[headerNameMatch].id;
columnId = window.mailpoetColumns[headerNameMatch].id;
}// set column type using header name
else if (headerName) {
if (/first|first name|given name/i.test(headerName)) {
@ -723,7 +749,7 @@ define(
// filter displayed data
jQuery('select.mailpoet_subscribers_column_data_match')
.select2({
data: mailpoetColumnsSelect2,
data: window.mailpoetColumnsSelect2,
width: '15em',
templateResult: function (item) {
return item.name;
@ -733,8 +759,8 @@ define(
}
})
.on('select2:selecting', function (selectEvent) {
var selectElement = this,
selectedOptionId = selectEvent.params.args.data.id;
var selectElement = this;
var selectedOptionId = selectEvent.params.args.data.id;
// CREATE CUSTOM FIELD
if (selectedOptionId === 'create') {
selectEvent.preventDefault();
@ -743,7 +769,7 @@ define(
title: MailPoet.I18n.t('addNewField'),
template: jQuery('#form_template_field_form').html()
});
jQuery('#form_field_new').parsley().on('form:submit', function(parsley) {
jQuery('#form_field_new').parsley().on('form:submit', function () {
// get data
var data = jQuery(this.$element).serializeObject();
@ -762,21 +788,21 @@ define(
custom: true
};
// if this is the first custom column, create an "optgroup"
if (mailpoetColumnsSelect2.length === 2) {
mailpoetColumnsSelect2.push({
if (window.mailpoetColumnsSelect2.length === 2) {
window.mailpoetColumnsSelect2.push({
name: MailPoet.I18n.t('userColumns'),
children: []
});
}
mailpoetColumnsSelect2[2].children.push(new_column_data);
mailpoetColumns.push(new_column_data);
window.mailpoetColumnsSelect2[2].children.push(new_column_data);
window.mailpoetColumns.push(new_column_data);
jQuery('select.mailpoet_subscribers_column_data_match')
.each(function () {
jQuery(this)
.html('')
.select2('destroy')
.select2({
data: mailpoetColumnsSelect2,
data: window.mailpoetColumnsSelect2,
width: '15em',
templateResult: function (item) {
return item.name;
@ -807,8 +833,8 @@ define(
// check for duplicate values in all select options
jQuery('select.mailpoet_subscribers_column_data_match')
.each(function () {
var element = this,
elementId = jQuery(element).val();
var element = this;
var elementId = jQuery(element).val();
// if another column has the same value and it's not an 'ignore', prompt user
if (elementId === selectedOptionId
&& elementId !== 'ignore') {
@ -824,19 +850,20 @@ define(
}
})
.on('select2:select', function (selectEvent) {
var selectElement = this,
selectedOptionId = selectEvent.params.data.id;
var selectElement = this;
var selectedOptionId = selectEvent.params.data.id;
jQuery(selectElement).data('column-id', selectedOptionId);
filterSubscribers();
});
// filter subscribers' data to detect dates, emails, etc.
function filterSubscribers() {
var subscribersClone = jQuery.extend(true, {}, subscribers);
var preventNextStep = false;
var displayedColumns;
jQuery(
'[data-id="notice_invalidEmail"], [data-id="notice_invalidDate"]')
.remove();
var subscribersClone = jQuery.extend(true, {}, subscribers),
preventNextStep = false,
displayedColumns = jQuery.map(
jQuery('.mailpoet_subscribers_column_data_match'), function (element, elementIndex) {
var columnId = jQuery(element).data('column-id');
@ -845,14 +872,19 @@ define(
return { id: columnId, index: elementIndex, validationRule: validationRule, element: element };
});
// iterate through the object of mailpoet columns
jQuery.map(mailpoetColumns, function (column, columnIndex) {
jQuery.map(window.mailpoetColumns, function (column) {
var firstRowData;
var validationRule;
var testedFormat;
var format;
var allowedDateFormats;
// check if the column id matches the selected id of one of the
// subscriber's data columns
var matchedColumn = _.find(displayedColumns, function (data) { return data.id === column.id; });
// EMAIL filter: if the first value in the column doesn't have a valid
// email, hide the next button
if (column.id === 'email') {
if (!emailRegex.test(subscribersClone.subscribers[0][matchedColumn.index])) {
if (!window.emailRegex.test(subscribersClone.subscribers[0][matchedColumn.index])) {
preventNextStep = true;
if (!jQuery('[data-id="notice_invalidEmail"]').length) {
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidElement'), {
@ -869,7 +901,7 @@ define(
}
// DATE filter: if column type is date, check if we can recognize it
if (column.type === 'date' && matchedColumn) {
var allowedDateFormats = [
allowedDateFormats = [
Moment.ISO_8601,
'YYYY/MM/DD',
'MM/DD/YYYY',
@ -880,8 +912,8 @@ define(
'YYYY/MM',
'YYYY'
];
var firstRowData = subscribersClone.subscribers[0][matchedColumn.index];
var validationRule = false;
firstRowData = subscribersClone.subscribers[0][matchedColumn.index];
validationRule = false;
// check if date exists
if (firstRowData.trim() === '') {
subscribersClone.subscribers[0][matchedColumn.index] =
@ -892,10 +924,10 @@ define(
preventNextStep = true;
}
else {
for (var format in allowedDateFormats) {
var testedFormat = allowedDateFormats[format];
for (format in allowedDateFormats) {
testedFormat = allowedDateFormats[format];
if (Moment(firstRowData, testedFormat, true).isValid()) {
var validationRule = (typeof(testedFormat) === 'function') ?
validationRule = (typeof (testedFormat) === 'function') ?
'datetime' :
testedFormat;
// set validation on the column element
@ -910,8 +942,8 @@ define(
jQuery.map(subscribersClone.subscribers, function (dataSubscribers, index) {
var data = dataSubscribers;
var rowData = data[matchedColumn.index];
if (index === fillerPosition || rowData.trim() === '') return;
var date = Moment(rowData, testedFormat, true);
if (index === fillerPosition || rowData.trim() === '') return;
// validate date
if (date.isValid()) {
data[matchedColumn.index] = new Handlebars.SafeString(
@ -970,23 +1002,25 @@ define(
});
nextStepButton.off().on('click', function () {
if (jQuery(this).hasClass('button-disabled')) {
return;
}
MailPoet.Modal.loading(true);
var columns = {},
queue = new jQuery.AsyncQueue(),
batchNumber = 0,
batchSize = 2000,
timestamp = Date.now() / 1000,
subscribers = [],
importResults = {
var columns = {};
var queue = new jQuery.AsyncQueue();
var batchNumber = 0;
var batchSize = 2000;
var timestamp = Date.now() / 1000;
var subscribers = [];
var importResults = {
created: 0,
updated: 0,
errors: [],
segments: []
},
};
var subscribers;
var splitSubscribers;
if (jQuery(this).hasClass('button-disabled')) {
return;
}
MailPoet.Modal.loading(true);
splitSubscribers = function (subscribers, size) {
return subscribers.reduce(function (res, item, index) {
if (index % size === 0) {
@ -995,8 +1029,8 @@ define(
res[res.length - 1].push(item);
return res;
}, []);
},
subscribers = splitSubscribers(importData.step1.subscribers, batchSize);
};
subscribers = splitSubscribers(window.importData.step1.subscribers, batchSize);
_.each(jQuery('select.mailpoet_subscribers_column_data_match'),
function (column, columnIndex) {
@ -1020,7 +1054,7 @@ define(
subscribers: subscribers[batchNumber],
timestamp: timestamp,
segments: segmentSelectElement.val(),
updateSubscribers: (jQuery(':radio[name="subscriber_update_option"]:checked').val() === 'yes') ? true : false
updateSubscribers: (jQuery(':radio[name="subscriber_update_option"]:checked').val() === 'yes')
})
}).done(function (response) {
importResults.created += response.data.created;
@ -1050,59 +1084,60 @@ define(
);
}
else {
mailpoetSegments = importResults.segments;
window.mailpoetSegments = importResults.segments;
importResults.segments = _.map(segmentSelectElement.select2('data'),
function (data) {
return data.name;
});
importData.step2 = importResults;
enableSegmentSelection(mailpoetSegments);
window.importData.step2 = importResults;
enableSegmentSelection(window.mailpoetSegments);
router.navigate('step3', { trigger: true });
}
});
});
filterSubscribers();
enableSegmentSelection(mailpoetSegments);
enableSegmentSelection(window.mailpoetSegments);
});
router.on('route:step3', function () {
if (typeof (importData.step2) === 'undefined') {
var subscribersDataImportResultsTemplate;
var exportMenuElement;
var importResults;
if (typeof (window.importData.step2) === 'undefined') {
router.navigate('step2', { trigger: true });
return;
}
showCurrentStep();
if (importData.step2.errors.length > 0) {
MailPoet.Notice.error(_.flatten(importData.step2.errors));
if (window.importData.step2.errors.length > 0) {
MailPoet.Notice.error(_.flatten(window.importData.step2.errors));
}
MailPoet.trackEvent('Subscribers import finished', {
'Subscribers created': importData.step2.created,
'Subscribers updated': importData.step2.updated,
'Subscribers created': window.importData.step2.created,
'Subscribers updated': window.importData.step2.updated,
'MailPoet Free version': window.mailpoet_version
});
// display statistics
var subscribersDataImportResultsTemplate =
Handlebars
.compile(jQuery('#subscribers_data_import_results_template')
.html()),
exportMenuElement = jQuery('span.mailpoet_export'),
subscribersDataImportResultsTemplate =
Handlebars.compile(jQuery('#subscribers_data_import_results_template').html());
exportMenuElement = jQuery('span.mailpoet_export');
importResults = {
created: (importData.step2.created)
created: (window.importData.step2.created)
? MailPoet.I18n.t('subscribersCreated')
.replace('%1$s', '<strong>' + importData.step2.created.toLocaleString() + '</strong>')
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
.replace('%1$s', '<strong>' + window.importData.step2.created.toLocaleString() + '</strong>')
.replace('%2$s', '"' + window.importData.step2.segments.join('", "') + '"')
: false,
updated: (importData.step2.updated)
updated: (window.importData.step2.updated)
? MailPoet.I18n.t('subscribersUpdated')
.replace('%1$s', '<strong>' + importData.step2.updated.toLocaleString() + '</strong>')
.replace('%2$s', '"' + importData.step2.segments.join('", "') + '"')
.replace('%1$s', '<strong>' + window.importData.step2.updated.toLocaleString() + '</strong>')
.replace('%2$s', '"' + window.importData.step2.segments.join('", "') + '"')
: false,
no_action: (!importData.step2.created && !importData.step2.updated),
added_to_segment_with_welcome_notification: importData.step2.added_to_segment_with_welcome_notification
no_action: (!window.importData.step2.created && !window.importData.step2.updated),
added_to_segment_with_welcome_notification: window.importData.step2.added_to_segment_with_welcome_notification
};
jQuery('#subscribers_data_import_results')
@ -1125,7 +1160,7 @@ define(
}
// reset previous step's data so that coming back to this step is prevented
importData.step2 = undefined;
window.importData.step2 = undefined;
});
if (!Backbone.History.started) {

View File

@ -83,7 +83,7 @@ const messages = {
MailPoet.Notice.success(message);
},
onNoItemsFound: (group) => {
if (group === 'bounced' && !mailpoet_premium_active) {
if (group === 'bounced' && !window.mailpoet_premium_active) {
return (
<div>
<p>{MailPoet.I18n.t('bouncedSubscribersHelp')}</p>
@ -245,7 +245,7 @@ const item_actions = [
const SubscriberList = React.createClass({
getSegmentFromId: function (segment_id) {
let result = false;
mailpoet_segments.map((segment) => {
window.mailpoet_segments.map((segment) => {
if (segment.id === segment_id) {
result = segment;
}
@ -350,7 +350,7 @@ const SubscriberList = React.createClass({
</h1>
<Listing
limit={ mailpoet_listing_per_page }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="subscribers"

View File

@ -57,7 +57,7 @@ class API {
$this->setRequestData($_POST);
if($this->checkToken() === false) {
$error_message = __('Invalid API request.', 'mailpoet');
$error_message = __('Sorry, but we couldn\'t connect to the MailPoet server. Please refresh the web page and try again.', 'mailpoet');
$error_response = $this->createErrorResponse(Error::UNAUTHORIZED, $error_message, Response::STATUS_UNAUTHORIZED);
return $error_response->send();
}

View File

@ -1,4 +1,5 @@
<?php
namespace MailPoet\API\JSON;
if(!defined('ABSPATH')) exit;
@ -12,23 +13,19 @@ class ErrorResponse extends Response {
}
function getData() {
if(empty($this->errors)) {
return null;
} else {
return array(
'errors' => $this->errors
);
}
return (empty($this->errors)) ? null : array('errors' => $this->errors);
}
function formatErrors($errors = array()) {
$formatted_errors = array();
foreach($errors as $error => $message) {
$formatted_errors[] = array(
return array_map(function($error, $message) {
// sanitize SQL error
if(preg_match('/^SQLSTATE/i', $message)) {
$message = __('An unknown error occurred.', 'mailpoet');
}
return array(
'error' => $error,
'message' => $message
);
}
return $formatted_errors;
}, array_keys($errors), array_values($errors));
}
}

View File

@ -20,13 +20,14 @@ class AutomatedLatestContent extends APIEndpoint {
function getPostTypes() {
$post_types = array_map(function($post_type) {
if(!empty($post_type->exclude_from_search)) return;
return array(
'name' => $post_type->name,
'label' => $post_type->label
);
}, get_post_types(array(), 'objects'));
return $this->successResponse(
$post_types
array_filter($post_types)
);
}

View File

@ -29,7 +29,7 @@ class NewsletterTemplates extends APIEndpoint {
}
function getAll() {
$collection = NewsletterTemplate::findMany();
$collection = NewsletterTemplate::orderByDesc('created_at')->orderByAsc('name')->findMany();
$templates = array_map(function($item) {
return $item->asArray();
}, $collection);

View File

@ -65,13 +65,11 @@ class Newsletters extends APIEndpoint {
$newsletter = Newsletter::createOrUpdate($data);
$errors = $newsletter->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
if(!empty($errors)) return $this->badRequest($errors);
if(!empty($segments)) {
NewsletterSegment::where('newsletter_id', $newsletter->id)
->deleteMany();
foreach($segments as $segment) {
if(!is_array($segment)) continue;
$relation = NewsletterSegment::create();
@ -86,7 +84,6 @@ class Newsletters extends APIEndpoint {
'newsletter_type',
$newsletter->type
)->findMany();
// update newsletter options
foreach($option_fields as $option_field) {
if(isset($options[$option_field->name])) {
@ -99,11 +96,9 @@ class Newsletters extends APIEndpoint {
);
}
}
// reload newsletter with updated options
$newsletter = Newsletter::filter('filterWithOptions')
->findOne($newsletter->id);
// if this is a post notification, process newsletter options and update its schedule
if($newsletter->type === Newsletter::TYPE_NOTIFICATION) {
// generate the new schedule from options and get the new "next run" date
@ -120,16 +115,22 @@ class Newsletters extends APIEndpoint {
$queue = $newsletter->getQueue();
if($queue) {
// if newsletter was previously scheduled and is now unscheduled, set its status to DRAFT and delete associated queue record
if($newsletter->status === Newsletter::STATUS_SCHEDULED && isset($options['isScheduled']) && empty($options['isScheduled'])) {
$queue->delete();
$newsletter->status = Newsletter::STATUS_DRAFT;
$newsletter->save();
} else {
$queue->newsletter_rendered_body = null;
$queue->newsletter_rendered_subject = null;
$queue->save();
}
}
Hooks::doAction('mailpoet_api_newsletters_save_after', $newsletter);
return $this->successResponse($newsletter->asArray());
}
}
function setStatus($data = array()) {
$status = (isset($data['status']) ? $data['status'] : null);

View File

@ -10,10 +10,13 @@ use MailPoet\Form\Util\FieldNameObfuscator;
use MailPoet\Models\Form;
use MailPoet\Models\StatisticsForms;
use MailPoet\Models\Subscriber;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit;
class Subscribers extends APIEndpoint {
const SUBSCRIPTION_LIMIT_COOLDOWN = 60;
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
'methods' => array('subscribe' => AccessControl::NO_ACCESS_RESTRICTION)
@ -94,6 +97,19 @@ class Subscribers extends APIEndpoint {
$form_fields = $form->getFieldList();
$data = array_intersect_key($data, array_flip($form_fields));
// make sure we don't allow too many subscriptions with the same ip address
$subscription_count = Subscriber::where(
'subscribed_ip',
Helpers::getIP()
)->whereRaw(
'(TIME_TO_SEC(TIMEDIFF(NOW(), created_at)) < ? OR TIME_TO_SEC(TIMEDIFF(NOW(), updated_at)) < ?)',
array(self::SUBSCRIPTION_LIMIT_COOLDOWN, self::SUBSCRIPTION_LIMIT_COOLDOWN)
)->count();
if($subscription_count > 0) {
throw new \Exception(__('You need to wait before subscribing again.', 'mailpoet'));
}
$subscriber = Subscriber::subscribe($data, $segment_ids);
$errors = $subscriber->getErrors();

View File

@ -8,26 +8,25 @@ if(!defined('ABSPATH')) exit;
require_once(ABSPATH . 'wp-includes/pluggable.php');
class AccessControl {
const PERMISSION_ACCESS_PLUGIN_ADMIN = 'access_plugin_admin';
const PERMISSION_MANAGE_SETTINGS = 'manage_settings';
const PERMISSION_MANAGE_EMAILS = 'manage_emails';
const PERMISSION_MANAGE_SUBSCRIBERS = 'manage_subscribers';
const PERMISSION_MANAGE_FORMS = 'manage_forms';
const PERMISSION_MANAGE_SEGMENTS = 'manage_segments';
const PERMISSION_UPDATE_PLUGIN = 'update_plugin';
const NO_ACCESS_RESTRICTION = 'no_access_restriction';
const PERMISSION_ACCESS_PLUGIN_ADMIN = 'mailpoet_access_plugin_admin';
const PERMISSION_MANAGE_SETTINGS = 'mailpoet_manage_settings';
const PERMISSION_MANAGE_EMAILS = 'mailpoet_manage_emails';
const PERMISSION_MANAGE_SUBSCRIBERS = 'mailpoet_manage_subscribers';
const PERMISSION_MANAGE_FORMS = 'mailpoet_manage_forms';
const PERMISSION_MANAGE_SEGMENTS = 'mailpoet_manage_segments';
const NO_ACCESS_RESTRICTION = 'mailpoet_no_access_restriction';
public $permissions;
public $current_user_roles;
public $user_roles;
public $user_capabilities;
function __construct() {
$this->permissions = $this->getDefaultPermissions();
$this->permissions = self::getDefaultPermissions();
$this->user_roles = $this->getUserRoles();
$this->user_capabilities = $this->getUserCapabilities();
}
private function getDefaultPermissions() {
static function getDefaultPermissions() {
return array(
self::PERMISSION_ACCESS_PLUGIN_ADMIN => WPHooks::applyFilters(
'mailpoet_permission_access_plugin_admin',
@ -67,12 +66,17 @@ class AccessControl {
'administrator'
)
),
self::PERMISSION_UPDATE_PLUGIN => WPHooks::applyFilters(
'mailpoet_permission_update_plugin',
array(
'administrator'
)
),
);
}
static function getPermissionLabels() {
return array(
self::PERMISSION_ACCESS_PLUGIN_ADMIN => __('Admin menu item', 'mailpoet'),
self::PERMISSION_MANAGE_SETTINGS => __('Manage settings', 'mailpoet'),
self::PERMISSION_MANAGE_EMAILS => __('Manage emails', 'mailpoet'),
self::PERMISSION_MANAGE_SUBSCRIBERS => __('Manage subscribers', 'mailpoet'),
self::PERMISSION_MANAGE_FORMS => __('Manage forms', 'mailpoet'),
self::PERMISSION_MANAGE_SEGMENTS => __('Manage segments', 'mailpoet'),
);
}
@ -94,11 +98,12 @@ class AccessControl {
function validatePermission($permission) {
if($permission === self::NO_ACCESS_RESTRICTION) return true;
if(empty($this->permissions[$permission])) return false;
$permitted_roles = array_intersect(
$this->user_roles,
$this->permissions[$permission]
);
return (!empty($permitted_roles));
foreach($this->user_roles as $role) {
$role_object = get_role($role);
if($role_object && $role_object->has_cap($permission)) {
return true;
}
}
return false;
}
}

View File

@ -2,6 +2,8 @@
namespace MailPoet\Config;
use MailPoet\Models\Setting;
if(!defined('ABSPATH')) exit;
class Activator {
@ -11,12 +13,17 @@ class Activator {
$populator = new Populator();
$populator->up();
Setting::setValue('db_version', Env::$version);
update_option('mailpoet_db_version', Env::$version);
$caps = new Capabilities();
$caps->setupWPCapabilities();
}
function deactivate() {
$migrator = new Migrator();
$migrator->down();
$caps = new Capabilities();
$caps->removeWPCapabilities();
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace MailPoet\Config;
use MailPoet\WP\Hooks;
class Capabilities {
const MEMBERS_CAP_GROUP_NAME = 'mailpoet';
private $renderer = null;
function __construct($renderer = null) {
if($renderer !== null) {
$this->renderer = $renderer;
}
}
function init() {
$this->setupMembersCapabilities();
}
function setupWPCapabilities() {
$permissions = AccessControl::getDefaultPermissions();
$role_objects = array();
foreach($permissions as $name => $roles) {
foreach($roles as $role) {
if(!isset($role_objects[$role])) {
$role_objects[$role] = get_role($role);
}
$role_objects[$role]->add_cap($name);
}
}
}
function removeWPCapabilities() {
$permissions = AccessControl::getDefaultPermissions();
$role_objects = array();
foreach($permissions as $name => $roles) {
foreach($roles as $role) {
if(!isset($role_objects[$role])) {
$role_objects[$role] = get_role($role);
}
$role_objects[$role]->remove_cap($name);
}
}
}
function setupMembersCapabilities() {
Hooks::addAction('admin_enqueue_scripts', array($this, 'enqueueMembersStyles'));
Hooks::addAction('members_register_cap_groups', array($this, 'registerMembersCapGroup'));
Hooks::addAction('members_register_caps', array($this, 'registerMembersCapabilities'));
}
function enqueueMembersStyles() {
wp_enqueue_style(
'mailpoet-admin-global',
Env::$assets_url . '/css/' . $this->renderer->getCssAsset('admin-global.css')
);
}
function registerMembersCapGroup() {
members_register_cap_group(
self::MEMBERS_CAP_GROUP_NAME,
array(
'label' => __('MailPoet', 'mailpoet'),
'caps' => array(),
'icon' => 'mailpoet-icon-logo',
'priority' => 30
)
);
}
function registerMembersCapabilities() {
$permissions = AccessControl::getPermissionLabels();
foreach($permissions as $name => $label) {
members_register_cap(
$name,
array(
'label' => $label,
'group' => self::MEMBERS_CAP_GROUP_NAME
)
);
}
}
}

View File

@ -4,6 +4,7 @@ namespace MailPoet\Config;
use MailPoet\API;
use MailPoet\Cron\CronTrigger;
use MailPoet\Models\Setting;
use MailPoet\Router;
use MailPoet\Util\ConflictResolver;
use MailPoet\Util\Helpers;
@ -61,12 +62,17 @@ class Initializer {
add_action('init', array(
$this,
'onInit'
'preInitialize'
), 0);
add_action('init', array(
$this,
'initialize'
));
add_action('wp_loaded', array(
$this,
'setupHooks'
'postInitialize'
));
add_action('admin_init', array(
@ -90,7 +96,27 @@ class Initializer {
$database->init();
}
function onInit() {
function preInitialize() {
try {
$this->setupRenderer();
$this->setupWidget();
} catch(\Exception $e) {
$this->handleFailedInitialization($e);
}
}
function setupRenderer() {
$caching = !WP_DEBUG;
$debugging = WP_DEBUG;
$this->renderer = new Renderer($caching, $debugging);
}
function setupWidget() {
$widget = new Widget($this->renderer);
$widget->init();
}
function initialize() {
try {
$this->setupAccessControl();
@ -98,9 +124,8 @@ class Initializer {
$this->setupInstaller();
$this->setupUpdater();
$this->setupRenderer();
$this->setupWidget();
$this->setupLocalizer();
$this->setupCapabilities();
$this->setupMenu();
$this->setupShortcodes();
$this->setupImages();
@ -109,8 +134,6 @@ class Initializer {
$this->setupCronTrigger();
$this->setupConflictResolver();
$this->setupJSONAPI();
$this->setupRouter();
$this->setupPages();
do_action('mailpoet_initialized', MAILPOET_VERSION);
@ -122,13 +145,14 @@ class Initializer {
}
function maybeDbUpdate() {
$current_db_version = get_option('mailpoet_db_version', false);
try {
$current_db_version = Setting::getValue('db_version');
} catch(\Exception $e) {
$current_db_version = null;
}
// if current db version and plugin version differ
if(version_compare($current_db_version, Env::$version) !== 0) {
if(!$this->access_control->validatePermission(AccessControl::PERMISSION_UPDATE_PLUGIN)) {
throw new \Exception(__('You do not have permission to activate/deactivate MailPoet plugin.', 'mailpoet'));
}
$this->runActivator();
}
}
@ -158,22 +182,16 @@ class Initializer {
$updater->init();
}
function setupRenderer() {
$caching = !WP_DEBUG;
$debugging = WP_DEBUG;
$this->renderer = new Renderer($caching, $debugging);
}
function setupWidget() {
$widget = new Widget($this->renderer);
$widget->init();
}
function setupLocalizer() {
$localizer = new Localizer($this->renderer);
$localizer = new Localizer();
$localizer->init();
}
function setupCapabilities() {
$caps = new Capabilities($this->renderer);
$caps->init();
}
function setupMenu() {
$menu = new Menu($this->renderer, Env::$assets_url, $this->access_control);
$menu->init();
@ -206,6 +224,17 @@ class Initializer {
$conflict_resolver->init();
}
function postInitialize() {
if(!defined(self::INITIALIZED)) return;
try {
$this->setupHooks();
$this->setupJSONAPI();
$this->setupRouter();
} catch(\Exception $e) {
$this->handleFailedInitialization($e);
}
}
function setupJSONAPI() {
$json_api = API\API::JSON($this->access_control);
$json_api->init();
@ -222,13 +251,8 @@ class Initializer {
}
function setupHooks() {
if(!defined(self::INITIALIZED)) return;
try {
$hooks = new Hooks();
$hooks->init();
} catch(\Exception $e) {
$this->handleFailedInitialization($e);
}
}
function handleFailedInitialization($exception) {

View File

@ -1,32 +1,21 @@
<?php
namespace MailPoet\Config;
if(!defined('ABSPATH')) exit;
class Localizer {
function __construct($renderer) {
$this->renderer = $renderer;
}
function init() {
add_action(
'init',
array($this, 'setup')
);
}
function setup() {
$this->loadGlobalText();
$this->loadPluginText();
$this->setGlobalRtl();
}
function loadGlobalText() {
$language_path =
Env::$languages_path
. '/'
. $this->locale()
. '.mo';
$language_path = sprintf(
'%s/%s.mo',
Env::$languages_path,
$this->locale()
);
load_textdomain(Env::$plugin_name, $language_path);
}
@ -38,10 +27,6 @@ class Localizer {
);
}
function setGlobalRtl() {
$this->renderer->addGlobal('is_rtl', is_rtl());
}
function locale() {
$locale = apply_filters(
'plugin_locale',

View File

@ -148,7 +148,7 @@ class MP2Migrator {
}
ob_start();
$datetime = new \MailPoet\WP\DateTime();
$this->log(sprintf('=== ' . __('START IMPORT', 'mailpoet') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT)));
$this->log(sprintf('=== ' . mb_strtoupper(__('Start import', 'mailpoet'), 'UTF-8') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT)));
Setting::setValue('import_stopped', false); // Reset the stop import action
if(!Setting::getValue('mailpoet_migration_started', false)) {
@ -165,10 +165,10 @@ class MP2Migrator {
if(!$this->importStopped()) {
Setting::setValue('mailpoet_migration_complete', true);
$this->log(__('IMPORT COMPLETE', 'mailpoet'));
$this->log(mb_strtoupper(__('Import complete', 'mailpoet'), 'UTF-8'));
}
$this->log(sprintf('=== ' . __('END IMPORT', 'mailpoet') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT)));
$this->log(sprintf('=== ' . mb_strtoupper(__('End import', 'mailpoet'), 'UTF-8') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT)));
$result = ob_get_contents();
ob_clean();
return $result;
@ -223,7 +223,7 @@ class MP2Migrator {
*/
public function stopImport() {
Setting::setValue('import_stopped', true);
$this->log(__('IMPORT STOPPED BY USER', 'mailpoet'));
$this->log(mb_strtoupper(__('Import stopped by user', 'mailpoet'), 'UTF-8'));
}
/**
@ -486,7 +486,7 @@ class MP2Migrator {
break;
default:
$params['date_format'] = strtoupper($params['date_order']);
$params['date_format'] = mb_strtoupper($params['date_order'], 'UTF-8');
}
unset($params['date_order']);
}

View File

@ -37,7 +37,6 @@ class Menu {
$this->renderer = $renderer;
$this->assets_url = $assets_url;
$this->access_control = $access_control;
$this->user_capability = $this->access_control->getUserFirstCapability();
$subscribers_feature = new SubscribersFeature();
$this->subscribers_over_limit = $subscribers_feature->check();
$this->checkMailPoetAPIKey();
@ -70,7 +69,7 @@ class Menu {
add_menu_page(
'MailPoet',
'MailPoet',
$this->user_capability,
AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
self::MAIN_PAGE_SLUG,
null,
$this->assets_url . '/img/menu_icon.png',
@ -78,12 +77,11 @@ class Menu {
);
// Emails page
if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_EMAILS)) {
$newsletters_page = add_submenu_page(
self::MAIN_PAGE_SLUG,
$this->setPageTitle(__('Emails', 'mailpoet')),
__('Emails', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_EMAILS,
self::MAIN_PAGE_SLUG,
array(
$this,
@ -108,22 +106,20 @@ class Menu {
true,
$this->setPageTitle(__('Newsletter', 'mailpoet')),
__('Newsletter Editor', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_EMAILS,
'mailpoet-newsletter-editor',
array(
$this,
'newletterEditor'
)
);
}
// Forms page
if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_FORMS)) {
$forms_page = add_submenu_page(
self::MAIN_PAGE_SLUG,
$this->setPageTitle(__('Forms', 'mailpoet')),
__('Forms', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_FORMS,
'mailpoet-forms',
array(
$this,
@ -148,22 +144,20 @@ class Menu {
true,
$this->setPageTitle(__('Form Editor', 'mailpoet')),
__('Form Editor', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_FORMS,
'mailpoet-form-editor',
array(
$this,
'formEditor'
)
);
}
// Subscribers page
if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_SUBSCRIBERS)) {
$subscribers_page = add_submenu_page(
self::MAIN_PAGE_SLUG,
$this->setPageTitle(__('Subscribers', 'mailpoet')),
__('Subscribers', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
'mailpoet-subscribers',
array(
$this,
@ -188,7 +182,7 @@ class Menu {
'admin.php?page=mailpoet-subscribers',
$this->setPageTitle(__('Import', 'mailpoet')),
__('Import', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
'mailpoet-import',
array(
$this,
@ -201,22 +195,20 @@ class Menu {
true,
$this->setPageTitle(__('Export', 'mailpoet')),
__('Export', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
'mailpoet-export',
array(
$this,
'export'
)
);
}
// Segments page
if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_SEGMENTS)) {
$segments_page = add_submenu_page(
self::MAIN_PAGE_SLUG,
$this->setPageTitle(__('Lists', 'mailpoet')),
__('Lists', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_SEGMENTS,
'mailpoet-segments',
array(
$this,
@ -235,29 +227,26 @@ class Menu {
'option' => 'mailpoet_segments_per_page'
));
});
}
// Settings page
if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_SETTINGS)) {
add_submenu_page(
self::MAIN_PAGE_SLUG,
$this->setPageTitle(__('Settings', 'mailpoet')),
__('Settings', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_MANAGE_SETTINGS,
'mailpoet-settings',
array(
$this,
'settings'
)
);
}
// Help page
add_submenu_page(
self::MAIN_PAGE_SLUG,
$this->setPageTitle(__('Help', 'mailpoet')),
__('Help', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
'mailpoet-help',
array(
$this,
@ -271,7 +260,7 @@ class Menu {
License::getLicense() ? true : self::MAIN_PAGE_SLUG,
$this->setPageTitle(__('Premium', 'mailpoet')),
__('Premium', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
'mailpoet-premium',
array(
$this,
@ -284,7 +273,7 @@ class Menu {
true,
$this->setPageTitle(__('Welcome', 'mailpoet')),
__('Welcome', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
'mailpoet-welcome',
array(
$this,
@ -297,7 +286,7 @@ class Menu {
true,
$this->setPageTitle(__('Update', 'mailpoet')),
__('Update', 'mailpoet'),
$this->user_capability,
AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
'mailpoet-update',
array(
$this,
@ -310,7 +299,7 @@ class Menu {
true,
$this->setPageTitle(__('Migration', 'mailpoet')),
'',
$this->user_capability,
AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
'mailpoet-migration',
array(
$this,
@ -422,6 +411,7 @@ class Menu {
'premium_key_valid' => !empty($this->premium_key_valid),
'mss_active' => Bridge::isMPSendingServiceEnabled(),
'mss_key_valid' => !empty($mp_api_key_valid),
'members_plugin_active' => is_plugin_active('members/members.php'),
'pages' => Pages::getAll(),
'flags' => $flags,
'current_user' => wp_get_current_user(),
@ -658,7 +648,7 @@ class Menu {
true,
'MailPoet',
'MailPoet',
$access_control->getUserFirstCapability(),
AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
$_REQUEST['page'],
array(
__CLASS__,

View File

@ -172,7 +172,8 @@ class Migrator {
'deleted_at TIMESTAMP NULL,',
'unconfirmed_data longtext,',
'PRIMARY KEY (id),',
'UNIQUE KEY email (email)'
'UNIQUE KEY email (email),',
'KEY wp_user_id (wp_user_id)',
);
return $this->sqlify(__FUNCTION__, $attributes);
}
@ -186,7 +187,8 @@ class Migrator {
'created_at TIMESTAMP NULL,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'PRIMARY KEY (id),',
'UNIQUE KEY subscriber_segment (subscriber_id,segment_id)'
'UNIQUE KEY subscriber_segment (subscriber_id,segment_id),',
'KEY segment_id (segment_id)',
);
return $this->sqlify(__FUNCTION__, $attributes);
}

View File

@ -3,8 +3,6 @@
namespace MailPoet\Config;
class PluginActivatedHook {
/** @var DeferredAdminNotices */
private $deferred_admin_notices;
public function __construct(DeferredAdminNotices $deferred_admin_notices) {
@ -13,8 +11,7 @@ class PluginActivatedHook {
public function action($plugin, $network_wide) {
if($plugin === plugin_basename(Env::$file) && $network_wide) {
$this->deferred_admin_notices->addNetworkAdminNotice(__('We noticed that you\'re using an unsupported environment. While MailPoet might work within a MultiSite environment, we dont support it.', 'mailpoet'));
$this->deferred_admin_notices->addNetworkAdminNotice(__("We noticed that you're using an unsupported environment. While MailPoet might work within a MultiSite environment, we dont support it.", 'mailpoet'));
}
}
}

View File

@ -337,7 +337,7 @@ class Populator {
function convertExistingDataToUTF8() {
global $wpdb;
if(!version_compare(get_option('mailpoet_db_version', '3.0.0-beta.33'), '3.0.0-beta.32', '<=')) {
if(!version_compare(Setting::getValue('db_version', '3.0.0-beta.33'), '3.0.0-beta.32', '<=')) {
// Data conversion should only be performed only once, when migrating from
// older version
return false;
@ -402,7 +402,7 @@ class Populator {
global $wpdb;
// perform once for versions below 3.0.0-beta.36.2.1
if(version_compare(get_option('mailpoet_db_version', '3.0.0-beta.36.2.3'), '3.0.0-beta.36.2.1', '>=')) {
if(version_compare(Setting::getValue('db_version', '3.0.0-beta.36.2.3'), '3.0.0-beta.36.2.1', '>=')) {
return false;
}
@ -455,7 +455,7 @@ class Populator {
global $wpdb;
// perform once for versions below 3.0.0-beta.36.2.1
if(version_compare(get_option('mailpoet_db_version', '3.0.0-beta.36.2.3'), '3.0.0-beta.36.2.1', '>=')) {
if(version_compare(Setting::getValue('db_version', '3.0.0-beta.36.2.3'), '3.0.0-beta.36.2.1', '>=')) {
return false;
}

View File

@ -8,7 +8,7 @@ class AppWelcome {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/app_welcome';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/app_welcome';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -8,7 +8,7 @@ class BurgerJoint {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = 'http://ps.w.org/mailpoet/assets/newsletter-templates/burger_joint';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/burger_joint';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -8,7 +8,7 @@ class ChocolateStore {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/chocolate_store';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/chocolate_store';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -8,7 +8,7 @@ class CoffeeShop {
private $template_image_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/franks-roast-house';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/franks-roast-house';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -8,7 +8,7 @@ class Discount {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/discount';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/discount';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -8,7 +8,7 @@ class Faith {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/faith';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/faith';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -8,7 +8,7 @@ class FestivalEvent {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/festival_event';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/festival_event';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -9,7 +9,7 @@ class FoodBox {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/food_box';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/food_box';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

View File

@ -8,7 +8,7 @@ class KickOff {
private $social_icon_url;
function __construct($assets_url) {
$this->template_image_url = '//ps.w.org/mailpoet/assets/newsletter-templates/kick_off';
$this->template_image_url = 'https://ps.w.org/mailpoet/assets/newsletter-templates/kick_off';
$this->social_icon_url = $assets_url . '/img/newsletter_editor/social-icons';
}

Some files were not shown because too many files have changed in this diff Show More