Compare commits

..

214 Commits

Author SHA1 Message Date
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
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
e012bd6cbe Updates changelog & bumps up release version to 3.0.0-rc.2.0.2 2017-09-05 11:17:32 -04:00
a02e64e805 Merge pull request #1084 from mailpoet/editor_get_post_type_optimization
Removes unused properties from the object used to display post types in editor [MAILPOET-1086]
2017-09-05 17:43:27 +03:00
e4bb3e1133 Adds unit test 2017-09-05 10:33:10 -04:00
998795e0e0 Fix tests semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
ec44b84cc9 Fix ES6 no-extra-semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
efece061d0 Fix ES5 semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
e347fc74a2 Fix ES5 no-extra-semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
027418a86c Fix ES5 semi-spacing eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
864187aa02 Merge pull request #1080 from mailpoet/json_api_method_check_fix
Throws error when JSON API endpoint method is not found [MAILPOET-1074]
2017-09-05 13:08:37 +03:00
59ae6619c0 Browser preview mixed content error fix
Strips protocol from preview URL

[MAILPOET-1080]
2017-09-05 08:54:23 +01:00
6aa0be8d01 Removes unused properties from the object 2017-09-04 21:07:15 -04:00
657658ea2b Adds new poll 2017-09-04 10:49:11 +02:00
8647128e12 Merge pull request #1081 from mailpoet/default_status_update
Default status is set depending on the signup confirmation option [MAILPOET-1079]
2017-09-04 10:02:45 +03:00
c8d92b3cd2 Default status is set depending on the signup confirmation option 2017-08-31 18:48:43 -04:00
cc8b7b45ed Throws error when endpoint method is not found 2017-08-31 15:18:22 -04:00
5b8b8c8441 Merge pull request #1077 from mailpoet/helpscout
Split support inquiries into Free and Premium inboxes [MAILPOET-869]
2017-08-31 12:38:18 -04:00
7106c640ef Refactor HelpScout Beacon embed script 2017-08-31 19:24:32 +03:00
300b84983d Merge pull request #1078 from mailpoet/spellchecker
Enable browser spellchecker [MAILPOET-1078]
2017-08-31 18:14:47 +03:00
49c1b92838 Enable browser spellchecker 2017-08-31 18:03:19 +03:00
d900827850 Merge pull request #1076 from mailpoet/lint-lines
Lint lines [MAILPOET-1031]
2017-08-31 12:49:10 +03:00
1688d4dbe1 Split support inquiries into Free and Premium inboxes [MAILPOET-869] 2017-08-31 12:02:20 +03:00
f438eee842 Fix ESLint newline-per-chained-call in tests
[MAILPOET-1031]
2017-08-30 15:26:02 +02:00
33733219f6 Fix ESLint object-property-newline in tests
[MAILPOET-1031]
2017-08-30 15:20:39 +02:00
737a83cdf3 Fix ESLint linebreak-style in tests
[MAILPOET-1031]
2017-08-30 15:19:15 +02:00
9061e1b495 Fix ESLint no-multipe-empty-lines ES6
[MAILPOET-1031]
2017-08-30 15:11:56 +02:00
09199e41a1 Fix ESLint linebreak-style ES5
[MAILPOET-1031]
2017-08-30 14:59:34 +02:00
4e91932613 Fix ESLint lines-around-directive ES5
[MAILPOET-1031]
2017-08-30 14:45:25 +02:00
227de4ecfa Fix ESLint newline-per-chained-call ES5
[MAILPOET-1031]
2017-08-30 14:40:42 +02:00
c1ccacf851 Fix ESLint newline-per-chained-call
[MAILPOET-1031]
2017-08-30 14:30:48 +02:00
228 changed files with 5365 additions and 4163 deletions

View File

@ -9,51 +9,32 @@
},
"rules": {
"import/no-amd": 0,
"space-before-function-paren": 0,
"prefer-arrow-callback": 0,
"no-undef": 0,
"key-spacing": 0,
"radix": 0,
"no-alert": 0,
"block-scoped-var": 0,
"guard-for-in": 0,
"no-prototype-builtins": 0,
"no-restricted-syntax": 0,
"newline-per-chained-call": 0,
"no-useless-concat": 0,
"no-multi-spaces": 0,
"no-nested-ternary": 0,
"semi-spacing": 0,
"no-sequences": 0,
"no-useless-return": 0,
"array-callback-return": 0,
"new-cap": 0,
"no-continue": 0,
"no-new": 0,
"space-unary-ops": 0,
"no-redeclare": 0,
"no-console": 0,
"no-empty": 0,
"no-extra-semi": 0,
"no-useless-escape": 0,
"wrap-iife": 0,
"no-unused-expressions": 0,
"block-spacing": 0,
"computed-property-spacing": 0,
"no-plusplus": 0,
"array-bracket-spacing": 0,
"lines-around-directive": 0,
"no-unreachable": 0,
"default-case": 0,
"no-lonely-if": 0,
"space-before-blocks": 0,
"no-unneeded-ternary": 0,
"no-mixed-operators": 0,
"eqeqeq": 0,
"space-in-parens": 0,
"semi": 0,
"max-len": 0,
"no-trailing-spaces": 0,
"global-require": 0,
"no-throw-literal": 0,
"no-extra-bind": 0,
@ -66,21 +47,15 @@
"no-use-before-define": 0,
"one-var": 0,
"camelcase": 0,
"spaced-comment": 0,
"padded-blocks": 0,
"object-curly-spacing": 0,
"strict": 0,
"vars-on-top": 0,
"no-var": 0,
"space-infix-ops": 0,
"no-unused-vars": 0,
"object-shorthand": 0,
"new-parens": 0,
"keyword-spacing": 0,
"eol-last": 0,
"dot-notation": 0,
"linebreak-style": 0,
"indent": 0,
"prefer-template": 0,
"func-names": 0
}

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,34 +40,21 @@
"no-bitwise": 0,
"arrow-body-style": 0,
"prefer-template": 0,
"keyword-spacing": 0,
"default-case": 0,
"array-callback-return": 0,
"consistent-return": 0,
"no-unreachable": 0,
"no-extra-semi": 0,
"import/no-unresolved": 0,
"import/extensions": 0,
"import/no-extraneous-dependencies": 0,
"camelcase": 0,
"template-curly-spacing": 0,
"eqeqeq": 0,
"no-lonely-if": 0,
"space-unary-ops": 0,
"block-scoped-var": 0,
"no-extra-bind": 0,
"no-multi-spaces": 0,
"class-methods-use-this": 0,
"key-spacing": 0,
"no-multiple-empty-lines": 0,
"space-in-parens": 0,
"no-case-declarations": 0,
"array-bracket-spacing": 0,
"newline-per-chained-call": 0,
"no-else-return": 0,
"max-len": 0,
"no-useless-concat": 0,
"no-unused-expressions": 0,
"no-sequences": 0,
"no-extra-boolean-cast": 0,
"dot-notation": 0,
@ -79,10 +65,7 @@
"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,23 +9,16 @@
},
"rules": {
"import/no-amd": 0,
"no-undef": 0,
"one-var": 0,
"indent": 0,
"linebreak-style": 0,
"no-whitespace-before-property": 0,
"object-property-newline": 0,
"global-require": 0,
"semi": 0,
"keyword-spacing": 0,
"no-bitwise": 0,
"newline-per-chained-call": 0,
"no-spaced-func": 0,
"func-call-spacing": 0,
"max-len": 0,
"space-unary-ops": 0,
"no-unused-vars": 0,
"no-unused-expressions": 0,
"no-underscore-dangle": 0,
"no-shadow": 0,
"padded-blocks": 0,

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,8 +23,10 @@ $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

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
cursor: all-scroll
.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

@ -1,12 +1,12 @@
define('admin', [
'jquery'
],
function(jQuery) {
jQuery(function($) {
// dom ready
$(function() {
});
});
}
);
define('admin', [
'jquery'
],
function (jQuery) {
jQuery(function ($) {
// dom ready
$(function () {
});
});
}
);

View File

@ -12,75 +12,75 @@ function requestFailed(errorMessage, xhr) {
};
}
define('ajax', ['mailpoet', 'jquery', 'underscore'], function(mp, jQuery, _) {
define('ajax', ['mailpoet', 'jquery', 'underscore'], function (mp, jQuery, _) {
var MailPoet = mp;
MailPoet.Ajax = {
version: 0.5,
options: {},
defaults: {
url: null,
api_version: null,
endpoint: null,
action: null,
token: null,
data: {}
},
post: function(options) {
return this.request('post', options);
},
init: function(options) {
// merge options
this.options = jQuery.extend({}, this.defaults, options);
version: 0.5,
options: {},
defaults: {
url: null,
api_version: null,
endpoint: null,
action: null,
token: null,
data: {}
},
post: function (options) {
return this.request('post', options);
},
init: function (options) {
// merge options
this.options = jQuery.extend({}, this.defaults, options);
// set default url
if(this.options.url === null) {
this.options.url = ajaxurl;
}
// set default url
if (this.options.url === null) {
this.options.url = window.ajaxurl;
}
// set default token
if(this.options.token === null) {
this.options.token = window.mailpoet_token;
}
},
getParams: function() {
return {
action: 'mailpoet',
api_version: this.options.api_version,
token: this.options.token,
endpoint: this.options.endpoint,
method: this.options.action,
data: this.options.data || {}
};
},
request: function(method, options) {
// set default token
if (this.options.token === null) {
this.options.token = window.mailpoet_token;
}
},
getParams: function () {
return {
action: 'mailpoet',
api_version: this.options.api_version,
token: this.options.token,
endpoint: this.options.endpoint,
method: this.options.action,
data: this.options.data || {}
};
},
request: function (method, options) {
// set options
this.init(options);
this.init(options);
// set request params
var params = this.getParams();
var params = this.getParams();
// remove null values from the data object
if (_.isObject(params.data)) {
params.data = _.pick(params.data, function(value) {
return (value !== null);
});
}
if (_.isObject(params.data)) {
params.data = _.pick(params.data, function (value) {
return (value !== null);
});
}
// ajax request
var deferred = jQuery.post(
var deferred = jQuery.post(
this.options.url,
params,
null,
'json'
).then(function(data) {
).then(function (data) {
return data;
}, _.partial(requestFailed, MailPoet.I18n.t('ajaxFailedErrorMessage')));
// clear options
this.options = {};
this.options = {};
return deferred;
}
return deferred;
}
};
});

View File

@ -17,7 +17,7 @@
*/
var eventsCache = [];
function track(name, data){
function track(name, data) {
if (typeof window.mixpanel.track !== 'function') {
window.mixpanel.init(window.mixpanelTrackingId);
}
@ -38,20 +38,11 @@ function exportMixpanel(mp) {
function trackCachedEvents() {
eventsCache.map(function (event) {
if (window.mailpoet_analytics_enabled || event.forced) {
window.mixpanel.track(event.name, event.data)
window.mixpanel.track(event.name, event.data);
}
});
}
function initializeMixpanelWhenLoaded() {
if (typeof window.mixpanel === 'object') {
exportMixpanel(MailPoet);
trackCachedEvents();
} else {
setTimeout(initializeMixpanelWhenLoaded, 100);
}
}
function cacheEvent(forced, name, data) {
eventsCache.push({
name: name,
@ -62,9 +53,18 @@ function cacheEvent(forced, name, data) {
define(
['mailpoet', 'underscore'],
function(mp, _) {
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

@ -3,167 +3,167 @@ define('date',
'mailpoet',
'jquery',
'moment'
], function(
], function (
mp,
jQuery,
Moment
) {
'use strict';
'use strict';
var MailPoet = mp;
var MailPoet = mp;
MailPoet.Date = {
version: 0.1,
options: {},
defaults: {
offset: 0,
format: 'F, d Y H:i:s'
},
init: function (opts) {
var options = opts || {};
MailPoet.Date = {
version: 0.1,
options: {},
defaults: {
offset: 0,
format: 'F, d Y H:i:s'
},
init: function (opts) {
var options = opts || {};
// set UTC offset
if (
if (
options.offset === undefined
&& window.mailpoet_date_offset !== undefined
) {
options.offset = window.mailpoet_date_offset;
}
options.offset = window.mailpoet_date_offset;
}
// set date format
if (
if (
options.format === undefined
&& window.mailpoet_date_format !== undefined
) {
options.format = window.mailpoet_date_format;
}
// merge options
this.options = jQuery.extend({}, this.defaults, options);
return this;
},
format: function(date, opts) {
var options = opts || {};
this.init(options);
var momentDate = Moment(date, this.convertFormat(options.parseFormat));
if (options.offset === 0) momentDate = momentDate.utc();
return momentDate.format(this.convertFormat(this.options.format));
},
toDate: function(date, opts) {
var options = opts || {};
this.init(options);
return Moment(date, this.convertFormat(options.parseFormat)).toDate();
},
short: function(date) {
return this.format(date, {
format: 'F, j Y'
});
},
full: function(date) {
return this.format(date, {
format: 'F, j Y H:i:s'
});
},
time: function(date) {
return this.format(date, {
format: 'H:i:s'
});
},
convertFormat: function(format) {
var format_mappings = {
date: {
d: 'DD',
D: 'ddd',
j: 'D',
l: 'dddd',
N: 'E',
S: 'o',
w: 'e',
z: 'DDD',
W: 'W',
F: 'MMMM',
m: 'MM',
M: 'MMM',
n: 'M',
t: '', // no equivalent
L: '', // no equivalent
o: 'YYYY',
Y: 'YYYY',
y: 'YY',
a: 'a',
A: 'A',
B: '', // no equivalent
g: 'h',
G: 'H',
h: 'hh',
H: 'HH',
i: 'mm',
s: 'ss',
u: 'SSS',
e: 'zz', // deprecated since version 1.6.0 of moment.js
I: '', // no equivalent
O: '', // no equivalent
P: '', // no equivalent
T: '', // no equivalent
Z: '', // no equivalent
c: '', // no equivalent
r: '', // no equivalent
U: 'X'
},
strftime: {
a: 'ddd',
A: 'dddd',
b: 'MMM',
B: 'MMMM',
d: 'DD',
e: 'D',
F: 'YYYY-MM-DD',
H: 'HH',
I: 'hh',
j: 'DDDD',
k: 'H',
l: 'h',
m: 'MM',
M: 'mm',
p: 'A',
S: 'ss',
u: 'E',
w: 'd',
W: 'WW',
y: 'YY',
Y: 'YYYY',
z: 'ZZ',
Z: 'z'
options.format = window.mailpoet_date_format;
}
};
// merge options
this.options = jQuery.extend({}, this.defaults, options);
if (!format || format.length <= 0) return format;
return this;
},
format: function (date, opts) {
var options = opts || {};
this.init(options);
var replacements = format_mappings['date'];
var momentDate = Moment(date, this.convertFormat(options.parseFormat));
if (options.offset === 0) momentDate = momentDate.utc();
return momentDate.format(this.convertFormat(this.options.format));
},
toDate: function (date, opts) {
var options = opts || {};
this.init(options);
var convertedFormat = [];
var escapeToken = false;
return Moment(date, this.convertFormat(options.parseFormat)).toDate();
},
short: function (date) {
return this.format(date, {
format: 'F, j Y'
});
},
full: function (date) {
return this.format(date, {
format: 'F, j Y H:i:s'
});
},
time: function (date) {
return this.format(date, {
format: 'H:i:s'
});
},
convertFormat: function (format) {
var format_mappings = {
date: {
d: 'DD',
D: 'ddd',
j: 'D',
l: 'dddd',
N: 'E',
S: 'o',
w: 'e',
z: 'DDD',
W: 'W',
F: 'MMMM',
m: 'MM',
M: 'MMM',
n: 'M',
t: '', // no equivalent
L: '', // no equivalent
o: 'YYYY',
Y: 'YYYY',
y: 'YY',
a: 'a',
A: 'A',
B: '', // no equivalent
g: 'h',
G: 'H',
h: 'hh',
H: 'HH',
i: 'mm',
s: 'ss',
u: 'SSS',
e: 'zz', // deprecated since version 1.6.0 of moment.js
I: '', // no equivalent
O: '', // no equivalent
P: '', // no equivalent
T: '', // no equivalent
Z: '', // no equivalent
c: '', // no equivalent
r: '', // no equivalent
U: 'X'
},
strftime: {
a: 'ddd',
A: 'dddd',
b: 'MMM',
B: 'MMMM',
d: 'DD',
e: 'D',
F: 'YYYY-MM-DD',
H: 'HH',
I: 'hh',
j: 'DDDD',
k: 'H',
l: 'h',
m: 'MM',
M: 'mm',
p: 'A',
S: 'ss',
u: 'E',
w: 'd',
W: 'WW',
y: 'YY',
Y: 'YYYY',
z: 'ZZ',
Z: 'z'
}
};
for(var index = 0, token = ''; format.charAt(index); index += 1){
token = format.charAt(index);
if (escapeToken === true) {
convertedFormat.push('['+token+']');
escapeToken = false;
} else {
if (token === '\\') {
// Slash escapes the next symbol to be treated as literal
escapeToken = true;
continue;
} else if (replacements[token] !== undefined) {
convertedFormat.push(replacements[token]);
if (!format || format.length <= 0) return format;
var replacements = format_mappings['date'];
var convertedFormat = [];
var escapeToken = false;
for (var index = 0, token = ''; format.charAt(index); index += 1) {
token = format.charAt(index);
if (escapeToken === true) {
convertedFormat.push('[' + token + ']');
escapeToken = false;
} else {
convertedFormat.push('['+token+']');
if (token === '\\') {
// Slash escapes the next symbol to be treated as literal
escapeToken = true;
continue;
} else if (replacements[token] !== undefined) {
convertedFormat.push(replacements[token]);
} else {
convertedFormat.push('[' + token + ']');
}
}
}
}
return convertedFormat.join('');
}
};
});
return convertedFormat.join('');
}
};
});

View File

@ -20,15 +20,15 @@ define([
const options = Object.keys(this.props.field.values).map(
(value, index) => {
return (
<p key={ 'checkbox-' + index }>
<p key={'checkbox-' + index}>
<label>
<input
ref="checkbox"
type="checkbox"
value="1"
checked={ isChecked }
onChange={ this.onValueChange }
name={ this.props.field.name }
checked={isChecked}
onChange={this.onValueChange}
name={this.props.field.name}
/>
{ this.props.field.values[value] }
</label>

View File

@ -12,7 +12,7 @@ define([
if (this.props.placeholder !== undefined) {
years.push((
<option value="" key={ 0 }>{ this.props.placeholder }</option>
<option value="" key={0}>{ this.props.placeholder }</option>
));
}
@ -20,16 +20,16 @@ define([
for (let i = currentYear; i >= currentYear - yearsRange; i -= 1) {
years.push((
<option
key={ i }
value={ i }
key={i}
value={i}
>{ i }</option>
));
}
return (
<select
name={ `${this.props.name}[year]` }
value={ this.props.year }
onChange={ this.props.onValueChange }
name={`${this.props.name}[year]`}
value={this.props.year}
onChange={this.props.onValueChange}
>
{ years }
</select>
@ -43,23 +43,23 @@ define([
if (this.props.placeholder !== undefined) {
months.push((
<option value="" key={ 0 }>{ this.props.placeholder }</option>
<option value="" key={0}>{ this.props.placeholder }</option>
));
}
for (let i = 1; i <= 12; i += 1) {
months.push((
<option
key={ i }
value={ i }
key={i}
value={i}
>{ this.props.monthNames[i - 1] }</option>
));
}
return (
<select
name={ `${this.props.name}[month]` }
value={ this.props.month }
onChange={ this.props.onValueChange }
name={`${this.props.name}[month]`}
value={this.props.month}
onChange={this.props.onValueChange}
>
{ months }
</select>
@ -73,24 +73,24 @@ define([
if (this.props.placeholder !== undefined) {
days.push((
<option value="" key={ 0 }>{ this.props.placeholder }</option>
<option value="" key={0}>{ this.props.placeholder }</option>
));
}
for (let i = 1; i <= 31; i += 1) {
days.push((
<option
key={ i }
value={ i }
key={i}
value={i}
>{ i }</option>
));
}
return (
<select
name={ `${this.props.name}[day]` }
value={ this.props.day }
onChange={ this.props.onValueChange }
name={`${this.props.name}[day]`}
value={this.props.day}
onChange={this.props.onValueChange}
>
{ days }
</select>
@ -123,7 +123,7 @@ define([
? this.props.item[this.props.field.name].trim()
: '';
if(value === '') {
if (value === '') {
return;
}
@ -140,7 +140,7 @@ define([
let value;
switch(dateType) {
switch (dateType) {
case 'year_month_day':
value = {
year: this.state.year,
@ -202,40 +202,37 @@ define([
const dateSelects = dateFormats[dateType][0].split('/');
const fields = dateSelects.map((type) => {
switch(type) {
switch (type) {
case 'YYYY':
return (<FormFieldDateYear
onValueChange={ this.onValueChange.bind(this) }
ref={ 'year' }
key={ 'year' }
name={ this.props.field.name }
year={ this.state.year }
placeholder={ this.props.field.year_placeholder }
onValueChange={this.onValueChange.bind(this)}
ref={'year'}
key={'year'}
name={this.props.field.name}
year={this.state.year}
placeholder={this.props.field.year_placeholder}
/>);
break;
case 'MM':
return (<FormFieldDateMonth
onValueChange={ this.onValueChange.bind(this) }
ref={ 'month' }
key={ 'month' }
name={ this.props.field.name }
month={ this.state.month }
monthNames={ monthNames }
placeholder={ this.props.field.month_placeholder }
onValueChange={this.onValueChange.bind(this)}
ref={'month'}
key={'month'}
name={this.props.field.name}
month={this.state.month}
monthNames={monthNames}
placeholder={this.props.field.month_placeholder}
/>);
break;
case 'DD':
return (<FormFieldDateDay
onValueChange={ this.onValueChange.bind(this) }
ref={ 'day' }
key={ 'day' }
name={ this.props.field.name }
day={ this.state.day }
placeholder={ this.props.field.day_placeholder }
onValueChange={this.onValueChange.bind(this)}
ref={'day'}
key={'day'}
name={this.props.field.name}
day={this.state.day}
placeholder={this.props.field.day_placeholder}
/>);
break;
}
});
@ -245,7 +242,7 @@ define([
</div>
);
}
};
}
return FormFieldDate;
});

View File

@ -7,6 +7,7 @@ define([
'form/fields/checkbox.jsx',
'form/fields/selection.jsx',
'form/fields/date.jsx',
'jquery',
],
(
React,
@ -16,12 +17,13 @@ define([
FormFieldRadio,
FormFieldCheckbox,
FormFieldSelection,
FormFieldDate
FormFieldDate,
jQuery
) => {
const FormField = React.createClass({
renderField: function (data, inline = false) {
let description = false;
if(data.field.description) {
if (data.field.description) {
description = (
<p className="description">{ data.field.description }</p>
);
@ -30,11 +32,11 @@ define([
let field = false;
let dataField = data.field;
if(data.field['field'] !== undefined) {
if (data.field['field'] !== undefined) {
dataField = jQuery.merge(dataField, data.field.field);
}
switch(dataField.type) {
switch (dataField.type) {
case 'text':
field = (<FormFieldText {...data} />);
break;
@ -68,16 +70,16 @@ define([
break;
}
if(inline === true) {
if (inline === true) {
return (
<span key={ 'field-' + (data.index || 0) }>
<span key={'field-' + (data.index || 0)}>
{ field }
{ description }
</span>
);
} else {
return (
<div key={ 'field-' + (data.index || 0) }>
<div key={'field-' + (data.index || 0)}>
{ field }
{ description }
</div>
@ -87,7 +89,7 @@ define([
render: function () {
let field = false;
if(this.props.field['fields'] !== undefined) {
if (this.props.field['fields'] !== undefined) {
field = this.props.field.fields.map((subfield, index) => {
return this.renderField({
index: index,
@ -101,7 +103,7 @@ define([
}
let tip = false;
if(this.props.field.tip) {
if (this.props.field.tip) {
tip = (
<p className="description">{ this.props.field.tip }</p>
);
@ -111,7 +113,7 @@ define([
<tr>
<th scope="row">
<label
htmlFor={ 'field_'+this.props.field.name }
htmlFor={'field_' + this.props.field.name}
>
{ this.props.field.label }
{ tip }

View File

@ -14,14 +14,14 @@ define([
const options = Object.keys(this.props.field.values).map(
(value, index) => {
return (
<p key={ 'radio-' + index }>
<p key={'radio-' + index}>
<label>
<input
type="radio"
checked={ selected_value === value }
value={ value }
onChange={ this.props.onValueChange }
name={ this.props.field.name } />
checked={selected_value === value}
value={value}
onChange={this.props.onValueChange}
name={this.props.field.name} />
{ this.props.field.values[value] }
</label>
</p>

View File

@ -50,8 +50,8 @@ const FormFieldSelect = React.createClass({
return (
<option
key={ 'option-' + index }
value={ value }>
key={'option-' + index}
value={value}>
{ this.props.field.values[value] }
</option>
);
@ -60,10 +60,10 @@ const FormFieldSelect = React.createClass({
return (
<select
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
onChange={ this.props.onValueChange }
name={this.props.field.name}
id={'field_' + this.props.field.name}
value={this.props.item[this.props.field.name]}
onChange={this.props.onValueChange}
{...this.props.field.validation}
>
{placeholder}

View File

@ -26,42 +26,42 @@ define([
return (this.state.select2 === true);
},
componentDidMount: function () {
if(this.allowMultipleValues()) {
if (this.allowMultipleValues()) {
this.setupSelect2();
}
},
componentDidUpdate: function (prevProps) {
if(
if (
(this.props.item !== undefined && prevProps.item !== undefined)
&& (this.props.item.id !== prevProps.item.id)
) {
jQuery('#'+this.refs.select.id)
jQuery('#' + this.refs.select.id)
.val(this.getSelectedValues())
.trigger('change');
}
},
componentWillUnmount: function () {
if(this.allowMultipleValues()) {
if (this.allowMultipleValues()) {
this.destroySelect2();
}
},
destroySelect2: function () {
if(this.isSelect2Initialized()) {
jQuery('#'+this.refs.select.id).select2('destroy');
if (this.isSelect2Initialized()) {
jQuery('#' + this.refs.select.id).select2('destroy');
}
},
setupSelect2: function () {
if(this.isSelect2Initialized()) {
if (this.isSelect2Initialized()) {
return;
}
const select2 = jQuery('#'+this.refs.select.id).select2({
const select2 = jQuery('#' + this.refs.select.id).select2({
width: (this.props.width || ''),
templateResult: function (item) {
if(item.element && item.element.selected) {
if (item.element && item.element.selected) {
return null;
} else {
if(item.title) {
if (item.title) {
return item.title;
} else {
return item.text;
@ -75,7 +75,7 @@ define([
hasRemoved = true;
});
select2.on('select2:opening', (e) => {
if(hasRemoved === true) {
if (hasRemoved === true) {
hasRemoved = false;
e.preventDefault();
}
@ -86,9 +86,9 @@ define([
this.setState({ select2: true });
},
getSelectedValues: function () {
if(this.props.field['selected'] !== undefined) {
if (this.props.field['selected'] !== undefined) {
return this.props.field['selected'](this.props.item);
} else if(this.props.item !== undefined && this.props.field.name !== undefined) {
} else if (this.props.item !== undefined && this.props.field.name !== undefined) {
if (this.allowMultipleValues()) {
if (Array.isArray(this.props.item[this.props.field.name])) {
return this.props.item[this.props.field.name].map((item) => {
@ -102,11 +102,11 @@ define([
return null;
},
loadCachedItems: function () {
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
let items = window['mailpoet_'+this.props.field.endpoint];
if (typeof (window['mailpoet_' + this.props.field.endpoint]) !== 'undefined') {
let items = window['mailpoet_' + this.props.field.endpoint];
if(this.props.field['filter'] !== undefined) {
if (this.props.field['filter'] !== undefined) {
items = items.filter(this.props.field.filter);
}
@ -116,9 +116,10 @@ define([
}
},
handleChange: function (e) {
if(this.props.onValueChange !== undefined) {
if(this.props.field.multiple) {
value = jQuery('#'+this.refs.select.id).val();
let value;
if (this.props.onValueChange !== undefined) {
if (this.props.field.multiple) {
value = jQuery('#' + this.refs.select.id).val();
} else {
value = e.target.value;
}
@ -132,19 +133,19 @@ define([
}
},
getLabel: function (item) {
if(this.props.field['getLabel'] !== undefined) {
if (this.props.field['getLabel'] !== undefined) {
return this.props.field.getLabel(item, this.props.item);
}
return item.name;
},
getSearchLabel: function (item) {
if(this.props.field['getSearchLabel'] !== undefined) {
if (this.props.field['getSearchLabel'] !== undefined) {
return this.props.field.getSearchLabel(item, this.props.item);
}
return null;
},
getValue: function (item) {
if(this.props.field['getValue'] !== undefined) {
if (this.props.field['getValue'] !== undefined) {
return this.props.field.getValue(item, this.props.item);
}
return item.id;
@ -153,7 +154,7 @@ define([
// this function may be used to transform the placeholder value into
// desired value.
transformChangedValue: function (value) {
if(typeof this.props.field['transformChangedValue'] === 'function') {
if (typeof this.props.field['transformChangedValue'] === 'function') {
return this.props.field.transformChangedValue.call(this, value);
} else {
return value;
@ -167,9 +168,9 @@ define([
return (
<option
key={ 'option-'+index }
value={ value }
title={ searchLabel }
key={'option-' + index}
value={value}
title={searchLabel}
>
{ label }
</option>
@ -178,12 +179,12 @@ define([
return (
<select
id={ this.props.field.id || this.props.field.name }
id={this.props.field.id || this.props.field.name}
ref="select"
disabled={this.props.field.disabled}
data-placeholder={ this.props.field.placeholder }
multiple={ this.props.field.multiple }
defaultValue={ this.getSelectedValues() }
data-placeholder={this.props.field.placeholder}
multiple={this.props.field.multiple}
defaultValue={this.getSelectedValues()}
{...this.props.field.validation}
>{ options }</select>
);

View File

@ -15,17 +15,17 @@ const FormFieldText = React.createClass({
? this.props.field.disabled(this.props.item)
: false
}
className={ (this.props.field.size) ? '' : 'regular-text' }
className={(this.props.field.size) ? '' : 'regular-text'}
size={
(this.props.field.size !== 'auto' && this.props.field.size > 0)
? this.props.field.size
: false
}
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ value }
placeholder={ this.props.field.placeholder }
onChange={ this.props.onValueChange }
name={this.props.field.name}
id={'field_' + this.props.field.name}
value={value}
placeholder={this.props.field.placeholder}
onChange={this.props.onValueChange}
{...this.props.field.validation}
/>
);

View File

@ -10,12 +10,12 @@ define([
<textarea
type="text"
className="regular-text"
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
placeholder={ this.props.field.placeholder }
defaultValue={ this.props.field.defaultValue }
onChange={ this.props.onValueChange }
name={this.props.field.name}
id={'field_' + this.props.field.name}
value={this.props.item[this.props.field.name]}
placeholder={this.props.field.placeholder}
defaultValue={this.props.field.defaultValue}
onChange={this.props.onValueChange}
{...this.props.field.validation}
/>
);

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({
@ -37,8 +39,8 @@ define(
return this.props.errors ? this.props.errors : this.state.errors;
},
componentDidMount: function () {
if(this.isMounted()) {
if(this.props.params.id !== undefined) {
if (this.isMounted()) {
if (this.props.params.id !== undefined) {
this.loadItem(this.props.params.id);
} else {
this.setState({
@ -48,7 +50,7 @@ define(
}
},
componentWillReceiveProps: function (props) {
if(props.params.id === undefined) {
if (props.params.id === undefined) {
this.setState({
loading: false,
item: {},
@ -88,8 +90,8 @@ define(
e.preventDefault();
// handle validation
if(this.props.isValid !== undefined) {
if(this.props.isValid() === false) {
if (this.props.isValid !== undefined) {
if (this.props.isValid() === false) {
return;
}
}
@ -99,7 +101,7 @@ define(
// only get values from displayed fields
const item = {};
this.props.fields.map((field) => {
if(field['fields'] !== undefined) {
if (field['fields'] !== undefined) {
field.fields.map((subfield) => {
item[subfield.name] = this.state.item[subfield.name];
});
@ -108,7 +110,7 @@ define(
}
});
// set id if specified
if(this.props.params.id !== undefined) {
if (this.props.params.id !== undefined) {
item.id = this.props.params.id;
}
@ -120,19 +122,19 @@ define(
}).always(() => {
this.setState({ loading: false });
}).done(() => {
if(this.props.onSuccess !== undefined) {
if (this.props.onSuccess !== undefined) {
this.props.onSuccess();
} else {
this.context.router.push('/');
}
if(this.props.params.id !== undefined) {
if (this.props.params.id !== undefined) {
this.props.messages.onUpdate();
} else {
this.props.messages.onCreate();
}
}).fail((response) => {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
this.setState({ errors: response.errors });
}
});
@ -154,10 +156,10 @@ define(
},
render: function () {
let errors;
if(this.getErrors() !== undefined) {
if (this.getErrors() !== undefined) {
errors = this.getErrors().map((error, index) => {
return (
<p key={ 'error-'+index } className="mailpoet_error">
<p key={'error-' + index} className="mailpoet_error">
{ error.message }
</p>
);
@ -192,15 +194,15 @@ define(
return (
<FormField
field={ field }
item={ this.getValues() }
onValueChange={ onValueChange }
key={ 'field-'+i } />
field={field}
item={this.getValues()}
onValueChange={onValueChange}
key={'field-' + i} />
);
});
let actions = false;
if(this.props.children) {
if (this.props.children) {
actions = this.props.children;
} else {
actions = (
@ -216,9 +218,9 @@ define(
<div>
{ beforeFormContent }
<form
id={ this.props.id }
id={this.props.id}
ref="form"
className={ formClasses }
className={formClasses}
onSubmit={
(this.props.onSubmit !== undefined)
? this.props.onSubmit

File diff suppressed because it is too large Load Diff

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 });
@ -14,12 +14,12 @@ const App = React.createClass({
const container = document.getElementById('forms_container');
if(container) {
if (container) {
ReactDOM.render((
<Router history={ history }>
<Route path="/" component={ App }>
<IndexRoute component={ FormList } />
<Route path="*" component={ FormList } />
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={FormList} />
<Route path="*" component={FormList} />
</Route>
</Router>
), container);

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 = [
{
@ -86,7 +87,7 @@ const item_actions = [
label: MailPoet.I18n.t('edit'),
link: function (item) {
return (
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>{MailPoet.I18n.t('edit')}</a>
<a href={`admin.php?page=mailpoet-form-editor&id=${item.id}`}>{MailPoet.I18n.t('edit')}</a>
);
},
},
@ -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;
@ -157,11 +158,11 @@ const FormList = React.createClass({
return (
<div>
<td className={ row_classes }>
<td className={row_classes}>
<strong>
<a
className="row-title"
href={ `admin.php?page=mailpoet-form-editor&id=${form.id}` }
href={`admin.php?page=mailpoet-form-editor&id=${form.id}`}
>{ form.name }</a>
</strong>
{ actions }
@ -185,21 +186,21 @@ const FormList = React.createClass({
{MailPoet.I18n.t('pageTitle')} <a
className="page-title-action"
href="javascript:;"
onClick={ this.createForm }
onClick={this.createForm}
>{MailPoet.I18n.t('new')}</a>
</h1>
<Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location }
params={ this.props.params }
messages={ messages }
search={ false }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
messages={messages}
search={false}
endpoint="forms"
onRenderItem={ this.renderItem }
columns={ columns }
bulk_actions={ bulk_actions }
item_actions={ item_actions }
onRenderItem={this.renderItem}
columns={columns}
bulk_actions={bulk_actions}
item_actions={item_actions}
/>
</div>
);

View File

@ -1,117 +1,117 @@
define('handlebars_helpers', ['handlebars'], function(Handlebars) {
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++) {
output += arguments[i];
};
return output;
Handlebars.registerHelper('concat', function () {
var size = (arguments.length - 1),
output = '';
for (var i = 0; i < size; i++) {
output += arguments[i];
}
return output;
});
Handlebars.registerHelper('number_format', function(value, block) {
return Number(value).toLocaleString();
Handlebars.registerHelper('number_format', function (value, block) {
return Number(value).toLocaleString();
});
Handlebars.registerHelper('date_format', function(timestamp, block) {
if(window.moment) {
if(timestamp === undefined || isNaN(timestamp) || timestamp <= 0) {
return;
}
Handlebars.registerHelper('date_format', function (timestamp, block) {
if (window.moment) {
if (timestamp === undefined || isNaN(timestamp) || timestamp <= 0) {
return;
}
// set date format
var f = block.hash.format || 'MMM Do, YYYY';
var f = block.hash.format || 'MMM Do, YYYY';
// check if we passed a timestamp
if(parseInt(timestamp, 10) == timestamp) {
return moment.unix(timestamp).format(f);
} else {
return moment.utc(timestamp).format(f);
}
if (parseInt(timestamp, 10) == timestamp) {
return window.moment.unix(timestamp).format(f);
} else {
return window.moment.utc(timestamp).format(f);
}
} else {
return timestamp;
};
}
});
Handlebars.registerHelper('cycle', function(value, block) {
Handlebars.registerHelper('cycle', function (value, block) {
var values = value.split(' ');
return values[block.data.index % (values.length + 1)];
});
Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {
switch (operator) {
case '==':
return (v1 == v2) ? options.fn(this) : options.inverse(this);
case '===':
return (v1 === v2) ? options.fn(this) : options.inverse(this);
case '!=':
return (v1 != v2) ? options.fn(this) : options.inverse(this);
case '!==':
return (v1 !== v2) ? options.fn(this) : options.inverse(this);
case '<':
return (v1 < v2) ? options.fn(this) : options.inverse(this);
case '<=':
return (v1 <= v2) ? options.fn(this) : options.inverse(this);
case '>':
return (v1 > v2) ? options.fn(this) : options.inverse(this);
case '>=':
return (v1 >= v2) ? options.fn(this) : options.inverse(this);
case '&&':
return (v1 && v2) ? options.fn(this) : options.inverse(this);
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);
}
switch (operator) {
case '==':
return (v1 == v2) ? options.fn(this) : options.inverse(this);
case '===':
return (v1 === v2) ? options.fn(this) : options.inverse(this);
case '!=':
return (v1 != v2) ? options.fn(this) : options.inverse(this);
case '!==':
return (v1 !== v2) ? options.fn(this) : options.inverse(this);
case '<':
return (v1 < v2) ? options.fn(this) : options.inverse(this);
case '<=':
return (v1 <= v2) ? options.fn(this) : options.inverse(this);
case '>':
return (v1 > v2) ? options.fn(this) : options.inverse(this);
case '>=':
return (v1 >= v2) ? options.fn(this) : options.inverse(this);
case '&&':
return (v1 && v2) ? options.fn(this) : options.inverse(this);
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) {
return value.gsub('\n', '<br />');
Handlebars.registerHelper('nl2br', function (value, block) {
return value.gsub('\n', '<br />');
});
Handlebars.registerHelper('json_encode', function(value, block) {
return JSON.stringify(value);
Handlebars.registerHelper('json_encode', function (value, block) {
return JSON.stringify(value);
});
Handlebars.registerHelper('json_decode', function(value, block) {
return JSON.parse(value);
Handlebars.registerHelper('json_decode', function (value, block) {
return JSON.parse(value);
});
Handlebars.registerHelper('url', function(value, block) {
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
Handlebars.registerHelper('url', function (value, block) {
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
return url + value;
return url + value;
});
Handlebars.registerHelper('emailFromMailto', function(value) {
var mailtoMatchingRegex = /^mailto\:/i;
if (typeof value === 'string' && value.match(mailtoMatchingRegex)) {
return value.replace(mailtoMatchingRegex, '');
} else {
return value;
}
Handlebars.registerHelper('emailFromMailto', function (value) {
var mailtoMatchingRegex = /^mailto\:/i;
if (typeof value === 'string' && value.match(mailtoMatchingRegex)) {
return value.replace(mailtoMatchingRegex, '');
} else {
return value;
}
});
Handlebars.registerHelper('lookup', function(obj, field, options) {
return obj && obj[field];
Handlebars.registerHelper('lookup', function (obj, field, options) {
return obj && obj[field];
});
Handlebars.registerHelper('rsa_key', function(value, block) {
Handlebars.registerHelper('rsa_key', function (value, block) {
// extract all lines into an array
if(value === undefined) return '';
if (value === undefined) return '';
var lines = value.trim().split('\n');
var lines = value.trim().split('\n');
// remove header & footer
lines.shift();
lines.pop();
lines.shift();
lines.pop();
// return concatenated lines
return lines.join('');
return lines.join('');
});
Handlebars.registerHelper('trim', function(value, block) {
if(value === null || value === undefined) return '';
return value.trim();
Handlebars.registerHelper('trim', function (value, block) {
if (value === null || value === undefined) return '';
return value.trim();
});
/**
@ -125,24 +125,24 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
* @return {String} The truncated string.
*/
Handlebars.registerHelper('ellipsis', function (str, limit, append) {
var strAppend = append;
if (strAppend === undefined) {
strAppend = '';
}
var sanitized = str.replace(/(<([^>]+)>)/g, '');
if (sanitized.length > limit) {
return sanitized.substr(0, limit - strAppend.length) + strAppend;
} else {
return sanitized;
}
var strAppend = append;
if (strAppend === undefined) {
strAppend = '';
}
var sanitized = str.replace(/(<([^>]+)>)/g, '');
if (sanitized.length > limit) {
return sanitized.substr(0, limit - strAppend.length) + strAppend;
} else {
return sanitized;
}
});
Handlebars.registerHelper('getNumber', function (string) {
return parseInt(string, 10);
return parseInt(string, 10);
});
Handlebars.registerHelper('fontWithFallback', function(font) {
switch(font) {
Handlebars.registerHelper('fontWithFallback', function (font) {
switch (font) {
case 'Arial': return new Handlebars.SafeString("Arial, 'Helvetica Neue', Helvetica, sans-serif");
case 'Comic Sans MS': return new Handlebars.SafeString("'Comic Sans MS', 'Marker Felt-Thin', Arial, sans-serif");
case 'Courier New': return new Handlebars.SafeString("'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace");

View File

@ -1,6 +1,7 @@
define('helpTooltip', ['mailpoet', 'react', 'react-dom', 'help-tooltip.jsx'],
function (mp, React, ReactDOM, TooltipComponent) {
'use strict';
var MailPoet = mp;
MailPoet.helpTooltip = {

View File

@ -6,11 +6,11 @@ function Tooltip(props) {
let tooltipId = props.tooltipId;
let tooltip = props.tooltip;
// tooltip ID must be unique, defaults to tooltip text
if(!props.tooltipId && typeof props.tooltip === 'string') {
if (!props.tooltipId && typeof props.tooltip === 'string') {
tooltipId = props.tooltip;
}
if(typeof props.tooltip === 'string') {
if (typeof props.tooltip === 'string') {
tooltip = (<span
style={{
pointerEvents: 'all',
@ -34,15 +34,15 @@ function Tooltip(props) {
data-for={tooltipId}
>
</span>
<ReactTooltip
globalEventOff="click"
multiline={true}
id={tooltipId}
efect="solid"
place={props.place}
<ReactTooltip
globalEventOff="click"
multiline={true}
id={tooltipId}
efect="solid"
place={props.place}
>
{tooltip}
</ReactTooltip>
{tooltip}
</ReactTooltip>
</span>
);
}

View File

@ -16,15 +16,15 @@ const App = React.createClass({
const container = document.getElementById('help_container');
if(container) {
if (container) {
ReactDOM.render((
<Router history={ history }>
<Route path="/" component={ App }>
<Router history={history}>
<Route path="/" component={App}>
<IndexRedirect to="knowledgeBase" />
{/* Pages */}
<Route path="knowledgeBase(/)**" params={{ tab: 'knowledgeBase' }} component={ KnowledgeBase } />
<Route path="systemInfo(/)**" params={{ tab: 'systemInfo' }} component={ SystemInfo } />
<Route path="knowledgeBase(/)**" params={{ tab: 'knowledgeBase' }} component={KnowledgeBase} />
<Route path="systemInfo(/)**" params={{ tab: 'systemInfo' }} component={SystemInfo} />
</Route>
</Router>
), container);

View File

@ -24,6 +24,6 @@ function KnowledgeBase() {
<a target="_blank" href="http://beta.docs.mailpoet.com/" className="button button-primary">{MailPoet.I18n.t('knowledgeBaseButton')}</a>
</div>
);
};
}
module.exports = KnowledgeBase;

View File

@ -42,6 +42,6 @@ function KnowledgeBase() {
{printData(data)}
</div>
);
};
}
module.exports = KnowledgeBase;

View File

@ -26,9 +26,9 @@ function Tabs(props) {
return (
<Link
key={ 'tab-'+index }
className={ tabClasses }
to={ tab.link }
key={'tab-' + index}
className={tabClasses}
to={tab.link}
>{ tab.label }</Link>
);
});
@ -38,7 +38,7 @@ function Tabs(props) {
{ tabLinks }
</h2>
);
};
}
Tabs.propTypes = { tab: React.PropTypes.string };
Tabs.defaultProps = { tab: 'knowledgeBase' };

View File

@ -1,3 +0,0 @@
define([], function() {
!function(e, o, n){window.HSCW=o, window.HS=n, n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={}, t.readyQueue=[], t.config=function(e){this.userConfig=e}, t.ready=function(e){this.readyQueue.push(e)}, o.config={docs:{enabled:!0, baseUrl:"//mailpoet3.helpscoutdocs.com/"}, contact:{enabled:!0, formId:"aa21ca80-a4f5-11e6-91aa-0a5fecc78a4d"}};var r=e.getElementsByTagName("script")[0], c=e.createElement("script");c.type="text/javascript", c.async=!0, c.src="https://djtflbt20bdde.cloudfront.net/", r.parentNode.insertBefore(c, r)}(document, window.HSCW||{}, window.HS||{});
});

View File

@ -1,24 +1,25 @@
define('i18n',
[
'mailpoet'
], function(
], function (
mp
) {
'use strict';
var MailPoet = mp;
'use strict';
var translations = {};
var MailPoet = mp;
MailPoet.I18n = {
add: function(key, value) {
translations[key] = value;
},
t: function(key) {
return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace('%$1s', key);
},
all: function() {
return translations;
}
};
var translations = {};
});
MailPoet.I18n = {
add: function (key, value) {
translations[key] = value;
},
t: function (key) {
return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace('%$1s', key);
},
all: function () {
return translations;
}
};
});

View File

@ -1,19 +1,20 @@
define('iframe', ['mailpoet'], function(mp) {
define('iframe', ['mailpoet'], function (mp) {
'use strict';
var MailPoet = mp;
MailPoet.Iframe = {
marginY: 20,
autoSize: function(iframe) {
if(!iframe) return;
autoSize: function (iframe) {
if (!iframe) return;
this.setSize(
iframe,
iframe.contentWindow.document.body.scrollHeight
);
},
setSize: function(sizeIframe, i) {
setSize: function (sizeIframe, i) {
var iframe = sizeIframe;
if(!iframe) return;
if (!iframe) return;
iframe.style.height = (
parseInt(i, 10) + this.marginY

View File

@ -2,7 +2,7 @@ define(
[
'jquery'
],
function(
function (
jQuery
) {
var $ = jQuery;
@ -23,12 +23,12 @@ define(
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
$.fn.serializeObject = function(coerce) {
$.fn.serializeObject = function (coerce) {
var obj = {},
coerce_types = { true: !0, false: !1, null: null };
// Iterate over all name=value pairs.
$.each( this.serializeArray(), function(j, v){
$.each(this.serializeArray(), function (j, v) {
var key = v.name,
val = v.value,
cur = obj,
@ -36,18 +36,18 @@ define(
// If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
// into its component parts.
keys = key.split( '][' ),
keys = key.split(']['),
keys_last = keys.length - 1;
// If the first keys part contains [ and the last ends with ], then []
// are correctly balanced.
if ( /\[/.test( keys[0] ) && /\]$/.test( keys[ keys_last ] ) ) {
if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) {
// Remove the trailing ] from the last keys part.
keys[ keys_last ] = keys[ keys_last ].replace( /\]$/, '' );
keys[keys_last] = keys[keys_last].replace(/\]$/, '');
// Split first keys part into two parts on the [ and add them back onto
// the beginning of the keys array.
keys = keys.shift().split('[').concat( keys );
keys = keys.shift().split('[').concat(keys);
keys_last = keys.length - 1;
} else {
@ -56,14 +56,14 @@ define(
}
// Coerce values.
if ( coerce ) {
val = val && !isNaN(val) ? +val // number
: val === 'undefined' ? undefined // undefined
if (coerce) {
val = val && !isNaN(val) ? +val // number
: val === 'undefined' ? undefined // undefined
: coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
: val; // string
}
if ( keys_last ) {
if (keys_last) {
// Complex key, build deep object structure based on a few rules:
// * The 'cur' pointer starts at the object top-level.
// * [] = array push (n is set to array length), [n] = array if n is
@ -73,10 +73,10 @@ define(
// object or array based on the type of the next keys part.
// * Move the 'cur' pointer to the next level.
// * Rinse & repeat.
for ( ; i <= keys_last; i++ ) {
for (; i <= keys_last; i++) {
key = keys[i] === '' ? cur.length : keys[i];
cur[key] = i < keys_last
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : [])
: val;
cur = cur[key];
}
@ -85,14 +85,14 @@ define(
// Simple key, even simpler rules, since only scalars and shallow
// arrays are allowed.
if ( $.isArray( obj[key] ) ) {
if ($.isArray(obj[key])) {
// val is already an array, so push on the next value.
obj[key].push( val );
obj[key].push(val);
} else if ( obj[key] !== undefined ) {
} else if (obj[key] !== undefined) {
// val isn't an array, but since a second value has been specified,
// convert val into an array.
obj[key] = [ obj[key], val ];
obj[key] = [obj[key], val];
} else {
// val is a scalar.

View File

@ -21,7 +21,7 @@ define([
const action = this.getSelectedAction();
// action on select callback
if(action !== null && action['onSelect'] !== undefined) {
if (action !== null && action['onSelect'] !== undefined) {
this.setState({
extra: action.onSelect(e),
});
@ -33,7 +33,7 @@ define([
const action = this.getSelectedAction();
if(action === null) {
if (action === null) {
return;
}
@ -48,15 +48,15 @@ define([
data.action = this.state.action;
let onSuccess = function () {};
if(action['onSuccess'] !== undefined) {
if (action['onSuccess'] !== undefined) {
onSuccess = action.onSuccess;
}
if(data.action) {
if (data.action) {
const promise = this.props.onBulkAction(selected_ids, data);
if (promise !== false) {
promise.then(onSuccess);
};
}
}
this.setState({
@ -66,19 +66,19 @@ define([
},
getSelectedAction: function () {
const selected_action = this.refs.action.value;
if(selected_action.length > 0) {
if (selected_action.length > 0) {
const action = this.props.bulk_actions.filter((action) => {
return (action.name === selected_action);
});
if(action.length > 0) {
if (action.length > 0) {
return action[0];
}
}
return null;
},
render: function () {
if(this.props.bulk_actions.length === 0) {
if (this.props.bulk_actions.length === 0) {
return null;
}
@ -93,26 +93,26 @@ define([
<select
name="bulk_actions"
ref="action"
value={ this.state.action }
value={this.state.action}
onChange={this.handleChangeAction}
>
<option value="">{MailPoet.I18n.t('bulkActions')}</option>
{ this.props.bulk_actions.map((action, index) => {
return (
<option
value={ action.name }
key={ 'action-' + index }
value={action.name}
key={'action-' + index}
>{ action.label }</option>
);
}) }
</select>
<input
onClick={ this.handleApplyAction }
onClick={this.handleApplyAction}
type="submit"
defaultValue={MailPoet.I18n.t('apply')}
className="button action" />
{ this.state.extra }
{ this.state.extra }
</div>
);
},

View File

@ -12,7 +12,7 @@ define([
handleFilterAction: function () {
const filters = {};
this.getAvailableFilters().map((filter, i) => {
filters[this.refs['filter-'+i].name] = this.refs['filter-'+i].value;
filters[this.refs['filter-' + i].name] = this.refs['filter-' + i].value;
});
if (this.props.onBeforeSelectFilter) {
this.props.onBeforeSelectFilter(filters);
@ -39,7 +39,7 @@ define([
this.getAvailableFilters().map(
(filter, i) => {
if (selected_filters[filter] !== undefined && selected_filters[filter]) {
jQuery(this.refs['filter-'+i])
jQuery(this.refs['filter-' + i])
.val(selected_filters[filter])
.trigger('change');
}
@ -52,18 +52,18 @@ define([
.map((filter, i) => {
return (
<select
ref={ `filter-${i}` }
key={ `filter-${i}` }
name={ filter }
ref={`filter-${i}`}
key={`filter-${i}`}
name={filter}
>
{ filters[filter].map((option, j) => {
return (
<option
value={ option.value }
key={ 'filter-option-' + j }
{ filters[filter].map((option, j) => {
return (
<option
value={option.value}
key={'filter-option-' + j}
>{ option.label }</option>
);
}) }
);
}) }
</select>
);
});
@ -74,7 +74,7 @@ define([
button = (
<input
id="post-query-submit"
onClick={ this.handleFilterAction }
onClick={this.handleFilterAction}
type="submit"
defaultValue={MailPoet.I18n.t('filter')}
className="button" />
@ -85,7 +85,7 @@ define([
if (this.props.group === 'trash') {
empty_trash = (
<input
onClick={ this.handleEmptyTrash }
onClick={this.handleEmptyTrash}
type="submit"
value={MailPoet.I18n.t('emptyTrash')}
className="button"

View File

@ -6,31 +6,31 @@ define(['react', 'classnames'], (React, classNames) => {
},
render: function () {
const groups = this.props.groups.map((group, index) => {
if(group.name === 'trash' && group.count === 0) {
if (group.name === 'trash' && group.count === 0) {
return false;
}
const classes = classNames(
{ current : (group.name === this.props.group) }
{ current: (group.name === this.props.group) }
);
return (
<li key={index}>
{(index > 0) ? ' |' : ''}
<a
href="javascript:;"
className={classes}
onClick={this.handleSelect.bind(this, group.name)} >
{group.label} <span className="count">({ group.count.toLocaleString() })</span>
</a>
</li>
<li key={index}>
{(index > 0) ? ' |' : ''}
<a
href="javascript:;"
className={classes}
onClick={this.handleSelect.bind(this, group.name)} >
{group.label} <span className="count">({ group.count.toLocaleString() })</span>
</a>
</li>
);
});
return (
<ul className="subsubsub">
{ groups }
</ul>
<ul className="subsubsub">
{ groups }
</ul>
);
},
});

View File

@ -19,14 +19,14 @@ const ListingHeader = React.createClass({
<ListingColumn
onSort={this.props.onSort}
sort_by={this.props.sort_by}
key={ 'column-' + index }
key={'column-' + index}
column={renderColumn} />
);
});
let checkbox;
if(this.props.is_selectable === true) {
if (this.props.is_selectable === true) {
checkbox = (
<th
className="manage-column column-cb check-column">
@ -37,8 +37,8 @@ const ListingHeader = React.createClass({
type="checkbox"
name="select_all"
ref="toggle"
checked={ this.props.selection }
onChange={ this.handleSelectItems } />
checked={this.props.selection}
onChange={this.handleSelectItems} />
</th>
);
}
@ -68,9 +68,9 @@ const ListingColumn = React.createClass({
);
let label;
if(this.props.column.sortable === true) {
if (this.props.column.sortable === true) {
label = (
<a onClick={ this.handleSort }>
<a onClick={this.handleSort}>
<span>{ this.props.column.label }</span>
<span className="sorting-indicator"></span>
</a>
@ -80,10 +80,10 @@ const ListingColumn = React.createClass({
}
return (
<th
className={ classes }
id={this.props.column.name }
className={classes}
id={this.props.column.name}
scope="col"
width={ this.props.column.width || null }
width={this.props.column.width || null}
>{label}</th>
);
},

View File

@ -48,12 +48,12 @@ const ListingItem = React.createClass({
}</label>
<input
type="checkbox"
value={ this.props.item.id }
value={this.props.item.id}
checked={
this.props.item.selected || this.props.selection === 'all'
}
onChange={ this.handleSelectItem }
disabled={ this.props.selection === 'all' } />
onChange={this.handleSelectItem}
disabled={this.props.selection === 'all'} />
</th>
);
}
@ -74,14 +74,14 @@ const ListingItem = React.createClass({
if (action.name === 'trash') {
custom_action = (
<span key={ 'action-'+index } className="trash">
<span key={'action-' + index} className="trash">
{(!is_first) ? ' | ' : ''}
<a
href="javascript:;"
onClick={ this.handleTrashItem.bind(
onClick={this.handleTrashItem.bind(
null,
this.props.item.id
) }>
)}>
{MailPoet.I18n.t('moveToTrash')}
</a>
</span>
@ -89,8 +89,8 @@ const ListingItem = React.createClass({
} else if (action.refresh) {
custom_action = (
<span
onClick={ this.props.onRefreshItems }
key={ 'action-'+index } className={ action.name }>
onClick={this.props.onRefreshItems}
key={'action-' + index} className={action.name}>
{(!is_first) ? ' | ' : ''}
{ action.link(this.props.item) }
</span>
@ -98,7 +98,7 @@ const ListingItem = React.createClass({
} else if (action.link) {
custom_action = (
<span
key={ 'action-'+index } className={ action.name }>
key={'action-' + index} className={action.name}>
{(!is_first) ? ' | ' : ''}
{ action.link(this.props.item) }
</span>
@ -106,7 +106,7 @@ const ListingItem = React.createClass({
} else {
custom_action = (
<span
key={ 'action-'+index } className={ action.name }>
key={'action-' + index} className={action.name}>
{(!is_first) ? ' | ' : ''}
<a href="javascript:;" onClick={
(action.onClick !== undefined)
@ -129,7 +129,7 @@ const ListingItem = React.createClass({
} else {
item_actions = (
<span className="edit">
<Link to={ `/edit/${ this.props.item.id }` }>{MailPoet.I18n.t('edit')}</Link>
<Link to={`/edit/${this.props.item.id}`}>{MailPoet.I18n.t('edit')}</Link>
</span>
);
}
@ -143,7 +143,7 @@ const ListingItem = React.createClass({
<span>
<a
href="javascript:;"
onClick={ this.handleRestoreItem.bind(
onClick={this.handleRestoreItem.bind(
null,
this.props.item.id
)}
@ -154,7 +154,7 @@ const ListingItem = React.createClass({
<a
className="submitdelete"
href="javascript:;"
onClick={ this.handleDeleteItem.bind(
onClick={this.handleDeleteItem.bind(
null,
this.props.item.id
)}
@ -162,7 +162,7 @@ const ListingItem = React.createClass({
</span>
</div>
<button
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
onClick={this.handleToggleItem.bind(null, this.props.item.id)}
className="toggle-row" type="button">
<span className="screen-reader-text">{MailPoet.I18n.t('showMoreDetails')}</span>
</button>
@ -175,7 +175,7 @@ const ListingItem = React.createClass({
{ item_actions }
</div>
<button
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
onClick={this.handleToggleItem.bind(null, this.props.item.id)}
className="toggle-row" type="button">
<span className="screen-reader-text">{MailPoet.I18n.t('showMoreDetails')}</span>
</button>
@ -186,7 +186,7 @@ const ListingItem = React.createClass({
const row_classes = classNames({ 'is-expanded': this.state.expanded });
return (
<tr className={ row_classes }>
<tr className={row_classes}>
{ checkbox }
{ this.props.onRenderItem(this.props.item, actions) }
</tr>
@ -235,7 +235,7 @@ const ListingItems = React.createClass({
return (
<tbody>
<tr className={ select_all_classes }>
<tr className={select_all_classes}>
<td colSpan={
this.props.columns.length
+ (this.props.is_selectable ? 1 : 0)
@ -250,7 +250,7 @@ const ListingItems = React.createClass({
}
&nbsp;
<a
onClick={ this.props.onSelectAll }
onClick={this.props.onSelectAll}
href="javascript:;">{
(this.props.selection !== 'all')
? MailPoet.I18n.t('selectAllLink')
@ -266,19 +266,19 @@ const ListingItems = React.createClass({
return (
<ListingItem
columns={ this.props.columns }
onSelectItem={ this.props.onSelectItem }
onRenderItem={ this.props.onRenderItem }
onDeleteItem={ this.props.onDeleteItem }
onRestoreItem={ this.props.onRestoreItem }
onTrashItem={ this.props.onTrashItem }
onRefreshItems={ this.props.onRefreshItems }
selection={ this.props.selection }
is_selectable={ this.props.is_selectable }
item_actions={ this.props.item_actions }
group={ this.props.group }
key={ `item-${renderItem.id}-${index}` }
item={ renderItem } />
columns={this.props.columns}
onSelectItem={this.props.onSelectItem}
onRenderItem={this.props.onRenderItem}
onDeleteItem={this.props.onDeleteItem}
onRestoreItem={this.props.onRestoreItem}
onTrashItem={this.props.onTrashItem}
onRefreshItems={this.props.onRefreshItems}
selection={this.props.selection}
is_selectable={this.props.is_selectable}
item_actions={this.props.item_actions}
group={this.props.group}
key={`item-${renderItem.id}-${index}`}
item={renderItem} />
);
})}
</tbody>
@ -321,7 +321,7 @@ const Listing = React.createClass({
if (params.splat) {
params.splat.split('/').map((param) => {
const [key, value] = this.getParam(param);
switch(key) {
switch (key) {
case 'filter':
const filters = {};
value.split('&').map((pair) => {
@ -413,9 +413,9 @@ const Listing = React.createClass({
if (base_url !== null) {
base_url = this.setBaseUrlParams(base_url);
return `/${ base_url }/${ params }`;
return `/${base_url}/${params}`;
} else {
return `/${ params }`;
return `/${params}`;
}
},
setBaseUrlParams: function (base_url) {
@ -423,8 +423,8 @@ const Listing = React.createClass({
if (ret.indexOf(':') !== -1) {
const params = this.getParams();
Object.keys(params).map((key) => {
if (ret.indexOf(':'+key) !== -1) {
ret = ret.replace(':'+key, params[key]);
if (ret.indexOf(':' + key) !== -1) {
ret = ret.replace(':' + key, params[key]);
}
});
}
@ -489,7 +489,7 @@ const Listing = React.createClass({
}
});
}).fail((response) => {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map((error) => { return error.message; }),
{ scroll: true }
@ -631,7 +631,7 @@ const Listing = React.createClass({
}).done(() => {
this.getItems();
}).fail((response) => {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map((error) => { return error.message; }),
{ scroll: true }
@ -662,7 +662,7 @@ const Listing = React.createClass({
selection = false;
if (is_checked) {
selected_ids = jQuery.merge(selected_ids, [ id ]);
selected_ids = jQuery.merge(selected_ids, [id]);
// check whether all items on the page are selected
if (
jQuery('tbody .check-column :checkbox:not(:checked)').length === 0
@ -789,8 +789,8 @@ const Listing = React.createClass({
// search
let search = (
<ListingSearch
onSearch={ this.handleSearch }
search={ this.state.search }
onSearch={this.handleSearch}
search={this.state.search}
/>
);
if (this.props.search === false) {
@ -800,9 +800,9 @@ const Listing = React.createClass({
// groups
let groups = (
<ListingGroups
groups={ this.state.groups }
group={ this.state.group }
onSelectGroup={ this.handleGroup }
groups={this.state.groups}
group={this.state.group}
onSelectGroup={this.handleGroup}
/>
);
if (this.props.groups === false) {
@ -821,81 +821,81 @@ const Listing = React.createClass({
{ search }
<div className="tablenav top clearfix">
<ListingBulkActions
count={ this.state.count }
bulk_actions={ bulk_actions }
selection={ this.state.selection }
selected_ids={ this.state.selected_ids }
onBulkAction={ this.handleBulkAction } />
count={this.state.count}
bulk_actions={bulk_actions}
selection={this.state.selection}
selected_ids={this.state.selected_ids}
onBulkAction={this.handleBulkAction} />
<ListingFilters
filters={ this.state.filters }
filter={ this.state.filter }
group={ this.state.group }
onBeforeSelectFilter={ this.props.onBeforeSelectFilter || null }
onSelectFilter={ this.handleFilter }
onEmptyTrash={ this.handleEmptyTrash }
filters={this.state.filters}
filter={this.state.filter}
group={this.state.group}
onBeforeSelectFilter={this.props.onBeforeSelectFilter || null}
onSelectFilter={this.handleFilter}
onEmptyTrash={this.handleEmptyTrash}
/>
<ListingPages
count={ this.state.count }
page={ this.state.page }
limit={ this.state.limit }
onSetPage={ this.handleSetPage } />
count={this.state.count}
page={this.state.page}
limit={this.state.limit}
onSetPage={this.handleSetPage} />
</div>
<table className={ table_classes }>
<table className={table_classes}>
<thead>
<ListingHeader
onSort={ this.handleSort }
onSelectItems={ this.handleSelectItems }
selection={ this.state.selection }
sort_by={ sort_by }
sort_order={ sort_order }
columns={ columns }
is_selectable={ bulk_actions.length > 0 } />
onSort={this.handleSort}
onSelectItems={this.handleSelectItems}
selection={this.state.selection}
sort_by={sort_by}
sort_order={sort_order}
columns={columns}
is_selectable={bulk_actions.length > 0} />
</thead>
<ListingItems
onRenderItem={ this.handleRenderItem }
onDeleteItem={ this.handleDeleteItem }
onRestoreItem={ this.handleRestoreItem }
onTrashItem={ this.handleTrashItem }
onRefreshItems={ this.handleRefreshItems }
columns={ columns }
is_selectable={ bulk_actions.length > 0 }
onSelectItem={ this.handleSelectItem }
onSelectAll={ this.handleSelectAll }
selection={ this.state.selection }
selected_ids={ this.state.selected_ids }
loading={ this.state.loading }
group={ this.state.group }
count={ this.state.count }
limit={ this.state.limit }
item_actions={ item_actions }
messages={ messages }
items={ items } />
onRenderItem={this.handleRenderItem}
onDeleteItem={this.handleDeleteItem}
onRestoreItem={this.handleRestoreItem}
onTrashItem={this.handleTrashItem}
onRefreshItems={this.handleRefreshItems}
columns={columns}
is_selectable={bulk_actions.length > 0}
onSelectItem={this.handleSelectItem}
onSelectAll={this.handleSelectAll}
selection={this.state.selection}
selected_ids={this.state.selected_ids}
loading={this.state.loading}
group={this.state.group}
count={this.state.count}
limit={this.state.limit}
item_actions={item_actions}
messages={messages}
items={items} />
<tfoot>
<ListingHeader
onSort={ this.handleSort }
onSelectItems={ this.handleSelectItems }
selection={ this.state.selection }
sort_by={ sort_by }
sort_order={ sort_order }
columns={ columns }
is_selectable={ bulk_actions.length > 0 } />
onSort={this.handleSort}
onSelectItems={this.handleSelectItems}
selection={this.state.selection}
sort_by={sort_by}
sort_order={sort_order}
columns={columns}
is_selectable={bulk_actions.length > 0} />
</tfoot>
</table>
<div className="tablenav bottom">
<ListingBulkActions
count={ this.state.count }
bulk_actions={ bulk_actions }
selection={ this.state.selection }
selected_ids={ this.state.selected_ids }
onBulkAction={ this.handleBulkAction } />
count={this.state.count}
bulk_actions={bulk_actions}
selection={this.state.selection}
selected_ids={this.state.selected_ids}
onBulkAction={this.handleBulkAction} />
<ListingPages
count={ this.state.count }
page={ this.state.page }
limit={ this.state.limit }
onSetPage={ this.handleSetPage } />
count={this.state.count}
page={this.state.page}
limit={this.state.limit}
onSetPage={this.handleSetPage} />
</div>
</div>
);

View File

@ -41,7 +41,7 @@ define([
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
},
handleSetManualPage: function (e) {
if(e.which === 13) {
if (e.which === 13) {
this.setPage(this.state.page);
}
},
@ -57,7 +57,7 @@ define([
return Math.ceil(this.props.count / this.props.limit);
},
render: function () {
if(this.props.count === 0) {
if (this.props.count === 0) {
return false;
} else {
let pagination = false;
@ -74,11 +74,11 @@ define([
<span aria-hidden="true" className="tablenav-pages-navspan">»</span>
);
if(this.props.limit > 0 && this.props.count > this.props.limit) {
if(this.props.page > 1) {
if (this.props.limit > 0 && this.props.count > this.props.limit) {
if (this.props.page > 1) {
previousPage = (
<a href="javascript:;"
onClick={ this.setPreviousPage }
onClick={this.setPreviousPage}
className="prev-page">
<span className="screen-reader-text">{MailPoet.I18n.t('previousPage')}</span>
<span aria-hidden="true"></span>
@ -86,10 +86,10 @@ define([
);
}
if(this.props.page > 2) {
if (this.props.page > 2) {
firstPage = (
<a href="javascript:;"
onClick={ this.setFirstPage }
onClick={this.setFirstPage}
className="first-page">
<span className="screen-reader-text">{MailPoet.I18n.t('firstPage')}</span>
<span aria-hidden="true">«</span>
@ -97,10 +97,10 @@ define([
);
}
if(this.props.page < this.getLastPage()) {
if (this.props.page < this.getLastPage()) {
nextPage = (
<a href="javascript:;"
onClick={ this.setNextPage }
onClick={this.setNextPage}
className="next-page">
<span className="screen-reader-text">{MailPoet.I18n.t('nextPage')}</span>
<span aria-hidden="true"></span>
@ -108,10 +108,10 @@ define([
);
}
if(this.props.page < this.getLastPage() - 1) {
if (this.props.page < this.getLastPage() - 1) {
lastPage = (
<a href="javascript:;"
onClick={ this.setLastPage }
onClick={this.setLastPage}
className="last-page">
<span className="screen-reader-text">{MailPoet.I18n.t('lastPage')}</span>
<span aria-hidden="true">»</span>
@ -119,8 +119,8 @@ define([
);
}
let pageValue = this.props.page;
if(this.state.page !== null) {
let pageValue = this.props.page;
if (this.state.page !== null) {
pageValue = this.state.page;
}
@ -136,13 +136,13 @@ define([
htmlFor="current-page-selector">{MailPoet.I18n.t('currentPage')}</label>
<input
type="text"
onChange={ this.handleChangeManualPage }
onKeyUp={ this.handleSetManualPage }
onBlur={ this.handleBlurManualPage }
onChange={this.handleChangeManualPage}
onKeyUp={this.handleSetManualPage}
onBlur={this.handleBlurManualPage}
aria-describedby="table-paging"
size="2"
ref="page"
value={ pageValue }
value={pageValue}
name="paged"
id="current-page-selector"
className="current-page" />
@ -172,7 +172,7 @@ define([
.replace('%$1d', this.props.count.toLocaleString());
}
return (
<div className={ classes }>
<div className={classes}>
<span className="displaying-num">{ numberOfItemsLabel }</span>
{ pagination }
</div>

View File

@ -17,14 +17,14 @@ define([
this.refs.search.value = nextProps.search;
},
render: function () {
if(this.props.search === false) {
if (this.props.search === false) {
return false;
} else {
return (
<form name="search" onSubmit={this.handleSearch}>
<p className="search-box">
<label htmlFor="search_input" className="screen-reader-text">
{MailPoet.I18n.t('searchLabel')}
{MailPoet.I18n.t('searchLabel')}
</label>
<input
type="search"

View File

@ -1,4 +1,4 @@
define('mailpoet', [], function() {
define('mailpoet', [], function () {
// A placeholder for MailPoet object
var MailPoet = {};

View File

@ -1,8 +1,9 @@
define('modal', ['mailpoet', 'jquery'],
function(mp, jQuery) {
function (mp, jQuery) {
'use strict';
var MailPoet = mp;
/***************************************************************************
/** *************************************************************************
MailPoet Modal:
version: 0.9
@ -19,7 +20,7 @@ define('modal', ['mailpoet', 'jquery'],
// loading mode
MailPoet.Modal.loading(bool);
***************************************************************************/
************************************************************************** */
MailPoet.Modal = {
version: 0.9,
@ -78,45 +79,44 @@ define('modal', ['mailpoet', 'jquery'],
options: {},
templates: {
overlay: '<div id="mailpoet_modal_overlay" style="display:none;"></div>',
popup: '<div id="mailpoet_popup" tabindex="-1">'+
'<div class="mailpoet_popup_wrapper">'+
'<a href="javascript:;" id="mailpoet_modal_close"></a>'+
'<div id="mailpoet_popup_title"><h2></h2></div>'+
'<div class="mailpoet_popup_body clearfix"></div>'+
'</div>'+
popup: '<div id="mailpoet_popup" tabindex="-1">' +
'<div class="mailpoet_popup_wrapper">' +
'<a href="javascript:;" id="mailpoet_modal_close"></a>' +
'<div id="mailpoet_popup_title"><h2></h2></div>' +
'<div class="mailpoet_popup_body clearfix"></div>' +
'</div>' +
'</div>',
loading: '<div id="mailpoet_loading" style="display:none;">'+
'<div id="mailpoet_modal_loading_1" class="mailpoet_modal_loading"></div>'+
'<div id="mailpoet_modal_loading_2" class="mailpoet_modal_loading"></div>'+
'<div id="mailpoet_modal_loading_3" class="mailpoet_modal_loading"></div>'+
loading: '<div id="mailpoet_loading" style="display:none;">' +
'<div id="mailpoet_modal_loading_1" class="mailpoet_modal_loading"></div>' +
'<div id="mailpoet_modal_loading_2" class="mailpoet_modal_loading"></div>' +
'<div id="mailpoet_modal_loading_3" class="mailpoet_modal_loading"></div>' +
'</div>',
panel: '<div id="mailpoet_panel">'+
'<a href="javascript:;" id="mailpoet_modal_close"></a>'+
'<div class="mailpoet_panel_wrapper" tabindex="-1">'+
'<div class="mailpoet_panel_body clearfix"></div>'+
'</div>'+
panel: '<div id="mailpoet_panel">' +
'<a href="javascript:;" id="mailpoet_modal_close"></a>' +
'<div class="mailpoet_panel_wrapper" tabindex="-1">' +
'<div class="mailpoet_panel_body clearfix"></div>' +
'</div>' +
'</div>',
subpanel: '<div class="mailpoet_panel_wrapper" tabindex="-1">'+
'<div class="mailpoet_panel_body clearfix"></div>'+
subpanel: '<div class="mailpoet_panel_wrapper" tabindex="-1">' +
'<div class="mailpoet_panel_body clearfix"></div>' +
'</div>'
},
getContentContainer: function() {
return jQuery('.mailpoet_'+this.options.type+'_body');
getContentContainer: function () {
return jQuery('.mailpoet_' + this.options.type + '_body');
},
setRenderer: function(renderer) {
setRenderer: function (renderer) {
this.renderer = renderer;
return this;
},
compileTemplate: function(template) {
if(this.renderer === 'html') {
return function() { return template; };
compileTemplate: function (template) {
if (this.renderer === 'html') {
return function () { return template; };
} else {
return Handlebars.compile(template);
return window.Handlebars.compile(template);
}
return false;
},
init: function(options) {
if(this.initialized === true) {
init: function (options) {
if (this.initialized === true) {
this.close();
}
// merge options
@ -131,9 +131,9 @@ define('modal', ['mailpoet', 'jquery'],
// toggle overlay
this.toggleOverlay(this.options.overlay);
if(this.options.type !== null) {
if (this.options.type !== null) {
// insert modal depending on its type
if(this.options.type === 'popup') {
if (this.options.type === 'popup') {
var modal = this.compileTemplate(
this.templates[this.options.type]
);
@ -143,7 +143,7 @@ define('modal', ['mailpoet', 'jquery'],
// set title
jQuery('#mailpoet_popup_title h2')
.html(this.options.title);
} else if(this.options.type === 'panel') {
} else if (this.options.type === 'panel') {
// create panel
jQuery('#mailpoet_modal_overlay')
.after(this.templates[this.options.type]);
@ -152,16 +152,16 @@ define('modal', ['mailpoet', 'jquery'],
// add proper overlay class
jQuery('#mailpoet_modal_overlay')
.removeClass('mailpoet_popup_overlay mailpoet_panel_overlay')
.addClass('mailpoet_'+this.options.type+'_overlay');
.addClass('mailpoet_' + this.options.type + '_overlay');
}
// set "success" callback if specified
if(options.onSuccess !== undefined) {
if (options.onSuccess !== undefined) {
this.options.onSuccess = options.onSuccess;
}
// set "cancel" callback if specified
if(options.onCancel !== undefined) {
if (options.onCancel !== undefined) {
this.options.onCancel = options.onCancel;
}
@ -178,111 +178,111 @@ define('modal', ['mailpoet', 'jquery'],
return this;
},
initOverlay: function(toggle) {
if(jQuery('#mailpoet_modal_overlay').length === 0) {
initOverlay: function (toggle) {
if (jQuery('#mailpoet_modal_overlay').length === 0) {
// insert overlay into the DOM
jQuery('body').append(this.templates.overlay);
jQuery('body').append(this.templates.overlay);
// insert loading indicator into overlay
jQuery('#mailpoet_modal_overlay').append(this.templates.loading);
}
return this;
},
toggleOverlay: function(toggle) {
if(toggle === true) {
jQuery('#mailpoet_modal_overlay')
jQuery('#mailpoet_modal_overlay').append(this.templates.loading);
}
return this;
},
toggleOverlay: function (toggle) {
if (toggle === true) {
jQuery('#mailpoet_modal_overlay')
.removeClass('mailpoet_overlay_hidden');
} else {
jQuery('#mailpoet_modal_overlay')
} else {
jQuery('#mailpoet_modal_overlay')
.addClass('mailpoet_overlay_hidden');
}
}
return this;
},
setupEvents: function() {
return this;
},
setupEvents: function () {
// close popup when user clicks on close button
jQuery('#mailpoet_modal_close').on('click', this.cancel.bind(this));
// close popup when user clicks on overlay
jQuery('#mailpoet_modal_overlay').on('click', function(e) {
jQuery('#mailpoet_modal_overlay').on('click', function (e) {
// we need to make sure that we are actually clicking on the overlay
// because when clicking on the popup content, it will trigger
// the click event on the overlay
if(e.target.id === 'mailpoet_modal_overlay') { this.cancel(); }
if (e.target.id === 'mailpoet_modal_overlay') { this.cancel(); }
}.bind(this));
// close popup when user presses ESC key
jQuery(document).on('keyup.mailpoet_modal', function(e) {
if(this.opened === false) { return false; }
if(e.keyCode === 27) { this.cancel(); }
jQuery(document).on('keyup.mailpoet_modal', function (e) {
if (this.opened === false) { return false; }
if (e.keyCode === 27) { this.cancel(); }
}.bind(this));
// make sure the popup is repositioned when the window is resized
jQuery(window).on('resize.mailpoet_modal', function() {
jQuery(window).on('resize.mailpoet_modal', function () {
this.setPosition();
}.bind(this));
return this;
},
removeEvents: function() {
removeEvents: function () {
jQuery(document).unbind('keyup.mailpoet_modal');
jQuery(window).unbind('resize.mailpoet_modal');
jQuery('#mailpoet_modal_close').off('click');
if(this.options.overlay === true) {
if (this.options.overlay === true) {
jQuery('#mailpoet_modal_overlay').off('click');
}
return this;
},
lock: function() {
lock: function () {
this.locked = true;
return this;
},
unlock: function() {
unlock: function () {
this.locked = false;
return this;
},
isLocked: function() {
isLocked: function () {
return this.locked;
},
loadTemplate: function() {
if(this.subpanels.length > 0) {
loadTemplate: function () {
if (this.subpanels.length > 0) {
// hide panel
jQuery('.mailpoet_'+this.options.type+'_wrapper').hide();
jQuery('.mailpoet_' + this.options.type + '_wrapper').hide();
// add sub panel wrapper
jQuery('#mailpoet_'+this.options.type)
jQuery('#mailpoet_' + this.options.type)
.append(this.templates['subpanel']);
// add sub panel content
jQuery('.mailpoet_'+this.options.type+'_body').last()
jQuery('.mailpoet_' + this.options.type + '_body').last()
.html(this.subpanels[(this.subpanels.length - 1)].element);
// focus on sub panel
if(this.options.focus) {
this.focus();
}
} else if (this.options.element) {
jQuery('.mailpoet_'+this.options.type+'_body').empty();
jQuery('.mailpoet_'+this.options.type+'_body')
if (this.options.focus) {
this.focus();
}
} else if (this.options.element) {
jQuery('.mailpoet_' + this.options.type + '_body').empty();
jQuery('.mailpoet_' + this.options.type + '_body')
.append(this.options.element);
} else {
jQuery('.mailpoet_'+this.options.type+'_body')
} else {
jQuery('.mailpoet_' + this.options.type + '_body')
.html(
this.options.body_template(
this.options.data
)
);
}
}
return this;
},
loadUrl: function() {
if(this.options.method === 'get') {
return this;
},
loadUrl: function () {
if (this.options.method === 'get') {
// make ajax request
jQuery.getJSON(this.options.url,
function(data) {
jQuery.getJSON(this.options.url,
function (data) {
this.options.data = jQuery.extend({}, this.options.data, data);
// load template using fetched data
this.loadTemplate();
@ -290,10 +290,10 @@ define('modal', ['mailpoet', 'jquery'],
this.showModal();
}.bind(this)
);
} else if(this.options.method === 'post') {
} else if (this.options.method === 'post') {
// make ajax request
jQuery.post(this.options.url, JSON.stringify(this.options.params),
function(data) {
jQuery.post(this.options.url, JSON.stringify(this.options.params),
function (data) {
this.options.data = jQuery.extend({}, this.options.data, data);
// load template using fetched data
this.loadTemplate();
@ -302,342 +302,342 @@ define('modal', ['mailpoet', 'jquery'],
}.bind(this),
'json'
);
}
}
return this;
},
setDimensions: function() {
switch(this.options.type) {
case 'popup':
return this;
},
setDimensions: function () {
switch (this.options.type) {
case 'popup':
// set popup dimensions
jQuery('#mailpoet_popup').css({
width: this.options.width,
height: this.options.height
});
jQuery('#mailpoet_popup').css({
width: this.options.width,
height: this.options.height
});
// set popup wrapper height
jQuery('#mailpoet_popup_wrapper').css({
height: this.options.height
});
jQuery('#mailpoet_popup_wrapper').css({
height: this.options.height
});
break;
case 'panel':
case 'panel':
// set dimensions
if(this.options.position === 'right') {
jQuery('#mailpoet_panel').css({
width: this.options.width,
right: 0,
marginRight: '-' + this.options.width,
left: 'auto'
});
} else if(this.options.position === 'left') {
jQuery('#mailpoet_panel').css({
width: this.options.width,
left: 0,
marginLeft: '-' + this.options.width,
right: 'auto'
});
}
jQuery('#mailpoet_panel').css({ minHeight: 'auto' });
if (this.options.position === 'right') {
jQuery('#mailpoet_panel').css({
width: this.options.width,
right: 0,
marginRight: '-' + this.options.width,
left: 'auto'
});
} else if (this.options.position === 'left') {
jQuery('#mailpoet_panel').css({
width: this.options.width,
left: 0,
marginLeft: '-' + this.options.width,
right: 'auto'
});
}
jQuery('#mailpoet_panel').css({ minHeight: 'auto' });
break;
}
}
return this;
},
setPosition: function() {
switch(this.options.type) {
case 'popup':
var screenWidth = jQuery(window).width(),
return this;
},
setPosition: function () {
switch (this.options.type) {
case 'popup':
var screenWidth = jQuery(window).width(),
screenHeight = jQuery(window).height(),
modalWidth = jQuery('.mailpoet_'+ this.options.type +'_wrapper').width(),
modalHeight = jQuery('.mailpoet_'+ this.options.type +'_wrapper').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))),
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
});
jQuery('#mailpoet_popup').css({
top: top,
left: left
});
break;
case 'panel':
setTimeout(function() {
case 'panel':
setTimeout(function () {
// set position of popup depending on screen dimensions.
if(this.options.position === 'right') {
jQuery('#mailpoet_panel').css({
marginRight: 0
});
} else if(this.options.position === 'left') {
jQuery('#mailpoet_panel').css({
marginLeft: 0
});
}
}.bind(this), 0);
if (this.options.position === 'right') {
jQuery('#mailpoet_panel').css({
marginRight: 0
});
} else if (this.options.position === 'left') {
jQuery('#mailpoet_panel').css({
marginLeft: 0
});
}
}.bind(this), 0);
break;
}
}
return this;
},
showModal: function() {
return this;
},
showModal: function () {
// set modal dimensions
this.setDimensions();
this.setDimensions();
// remember the previously focused element
this.prevFocus = jQuery(':focus');
this.prevFocus = jQuery(':focus');
// add a flag on the body so that we can prevent scrolling
jQuery('body').addClass('mailpoet_modal_opened');
jQuery('body').addClass('mailpoet_modal_opened');
// show popup
jQuery('#mailpoet_'+this.options.type).show();
jQuery('#mailpoet_' + this.options.type).show();
// display overlay
this.showOverlay();
this.showOverlay();
// set modal position
this.setPosition();
this.setPosition();
// add class on highlighted elements
if(this.options.highlight !== null) {
if(this.options.highlight.length > 0) {
this.highlightOn(this.options.highlight);
}
if (this.options.highlight !== null) {
if (this.options.highlight.length > 0) {
this.highlightOn(this.options.highlight);
}
}
if(this.options.focus) {
if (this.options.focus) {
this.focus();
}
// set popup as opened
this.opened = true;
// trigger init event if specified
if (this.options.onInit !== null) {
this.options.onInit(this);
}
return this;
},
focus: function () {
if (this.options.type == 'popup') {
jQuery('#mailpoet_' + this.options.type).focus();
} else {
// panel and subpanel
jQuery('#mailpoet_' + this.options.type + ' .mailpoet_panel_wrapper')
.filter(':visible').focus();
}
return this;
},
highlightOn: function (element) {
jQuery(element).addClass('mailpoet_modal_highlight');
return this;
},
highlightOff: function () {
jQuery('.mailpoet_modal_highlight')
.removeClass('mailpoet_modal_highlight');
return this;
},
hideModal: function (callback) {
// set modal as closed
this.opened = false;
// hide modal
jQuery('#mailpoet_' + this.options.type).hide();
// remove class on highlighted elements
this.highlightOff();
// remove class from body to let it be scrollable
jQuery('body').removeClass('mailpoet_modal_opened');
return this;
},
showOverlay: function (force) {
jQuery('#mailpoet_modal_overlay').show();
return this;
},
hideOverlay: function () {
jQuery('#mailpoet_modal_overlay').hide();
return this;
},
popup: function (opts) {
// get options
var options = opts || {};
// set modal type
options.type = 'popup';
// set overlay state
options.overlay = options.overlay || true;
// initialize modal
this.init(options);
// open modal
this.open();
return this;
},
panel: function (opts) {
// get options
var options = opts || {};
// reset subpanels
this.subpanels = [];
// set modal type
options.type = 'panel';
// set overlay state
options.overlay = options.overlay || false;
// set highlighted element
options.highlight = options.highlight || null;
// set modal dimensions
options.width = options.width || '40%';
options.height = options.height || 'auto';
// initialize modal
this.init(options);
// open modal
this.open();
return this;
},
subpanel: function (options) {
if (this.opened === false) {
// if no panel is already opened, let's create one instead
this.panel(options);
} else {
// if a panel is already opened, add a sub panel to it
this.subpanels.push(options);
this.loadTemplate();
}
return this;
},
loading: function (toggle) {
// make sure the overlay is initialized and that it's visible
this.initOverlay(true);
if (toggle === true) {
this.showLoading();
} else {
this.hideLoading();
}
return this;
},
showLoading: function () {
jQuery('#mailpoet_loading').show();
// add loading class to overlay
jQuery('#mailpoet_modal_overlay')
.addClass('mailpoet_overlay_loading');
return this;
},
hideLoading: function () {
jQuery('#mailpoet_loading').hide();
// remove loading class from overlay
jQuery('#mailpoet_modal_overlay')
.removeClass('mailpoet_overlay_loading');
return this;
},
open: function () {
// load template if specified
if (this.options.template !== null) {
// check if a url was specified to get extra data
if (this.options.url !== null) {
this.loadUrl();
} else {
// load template
this.loadTemplate();
// show modal window
this.showModal();
}
} else {
this.cancel();
}
return this;
},
success: function () {
if (this.subpanels.length > 0) {
if (this.subpanels[(this.subpanels.length - 1)].onSuccess !== undefined) {
this.subpanels[(this.subpanels.length - 1)].onSuccess(this.subpanels[(this.subpanels.length - 1)].data);
}
} else {
if (this.options.onSuccess !== null) {
this.options.onSuccess(this.options.data);
}
}
this.close();
return this;
},
cancel: function () {
if (this.subpanels.length > 0) {
if (this.subpanels[(this.subpanels.length - 1)].onCancel !== undefined) {
this.subpanels[(this.subpanels.length - 1)].onCancel(this.subpanels[(this.subpanels.length - 1)].data);
}
} else {
if (this.options.onCancel !== null) {
this.options.onCancel(this.options.data);
}
}
this.close();
return this;
},
destroy: function () {
this.hideOverlay();
// remove extra modal
if (jQuery('#mailpoet_' + this.options.type).length > 0) {
jQuery('#mailpoet_' + this.options.type).remove();
}
this.initialized = false;
return this;
},
close: function () {
if (this.isLocked() === true) { return this; }
if (this.subpanels.length > 0) {
// close subpanel
jQuery('.mailpoet_' + this.options.type + '_wrapper').last().remove();
// show previous panel
jQuery('.mailpoet_' + this.options.type + '_wrapper').last().show();
// remove last subpanels
this.subpanels.pop();
// focus on previous panel
if (this.options.focus) {
this.focus();
}
// set popup as opened
this.opened = true;
// trigger init event if specified
if(this.options.onInit !== null) {
this.options.onInit(this);
}
return this;
},
focus: function() {
if(this.options.type == 'popup') {
jQuery('#mailpoet_'+this.options.type).focus();
} else {
// panel and subpanel
jQuery('#mailpoet_'+this.options.type+' .mailpoet_panel_wrapper')
.filter(':visible').focus();
}
return this;
},
highlightOn: function(element) {
jQuery(element).addClass('mailpoet_modal_highlight');
return this;
},
highlightOff: function() {
jQuery('.mailpoet_modal_highlight')
.removeClass('mailpoet_modal_highlight');
return this;
},
hideModal: function(callback) {
// set modal as closed
this.opened = false;
// hide modal
jQuery('#mailpoet_'+this.options.type).hide();
// remove class on highlighted elements
this.highlightOff();
// remove class from body to let it be scrollable
jQuery('body').removeClass('mailpoet_modal_opened');
return this;
},
showOverlay: function(force) {
jQuery('#mailpoet_modal_overlay').show();
return this;
},
hideOverlay: function() {
jQuery('#mailpoet_modal_overlay').hide();
return this;
},
popup: function(opts) {
// get options
var options = opts || {};
// set modal type
options.type = 'popup';
// set overlay state
options.overlay = options.overlay || true;
// initialize modal
this.init(options);
// open modal
this.open();
return this;
},
panel: function(opts) {
// get options
var options = opts || {};
// reset subpanels
this.subpanels = [];
// set modal type
options.type = 'panel';
// set overlay state
options.overlay = options.overlay || false;
// set highlighted element
options.highlight = options.highlight || null;
// set modal dimensions
options.width = options.width || '40%';
options.height = options.height || 'auto';
// initialize modal
this.init(options);
// open modal
this.open();
return this;
},
subpanel: function(options) {
if(this.opened === false) {
// if no panel is already opened, let's create one instead
this.panel(options);
} else {
// if a panel is already opened, add a sub panel to it
this.subpanels.push(options);
this.loadTemplate();
}
return this;
},
loading: function(toggle) {
// make sure the overlay is initialized and that it's visible
this.initOverlay(true);
if(toggle === true) {
this.showLoading();
} else {
this.hideLoading();
}
return this;
},
showLoading: function() {
jQuery('#mailpoet_loading').show();
// add loading class to overlay
jQuery('#mailpoet_modal_overlay')
.addClass('mailpoet_overlay_loading');
return this;
},
hideLoading: function() {
jQuery('#mailpoet_loading').hide();
// remove loading class from overlay
jQuery('#mailpoet_modal_overlay')
.removeClass('mailpoet_overlay_loading');
return this;
},
open: function() {
// load template if specified
if(this.options.template !== null) {
// check if a url was specified to get extra data
if(this.options.url !== null) {
this.loadUrl();
} else {
// load template
this.loadTemplate();
// show modal window
this.showModal();
}
} else {
this.cancel();
}
return this;
},
success: function() {
if(this.subpanels.length > 0) {
if(this.subpanels[(this.subpanels.length - 1)].onSuccess !== undefined) {
this.subpanels[(this.subpanels.length - 1)].onSuccess(this.subpanels[(this.subpanels.length - 1)].data);
}
} else {
if(this.options.onSuccess !== null) {
this.options.onSuccess(this.options.data);
}
}
this.close();
return this;
},
cancel: function() {
if(this.subpanels.length > 0) {
if(this.subpanels[(this.subpanels.length - 1)].onCancel !== undefined) {
this.subpanels[(this.subpanels.length - 1)].onCancel(this.subpanels[(this.subpanels.length - 1)].data);
}
} else {
if(this.options.onCancel !== null) {
this.options.onCancel(this.options.data);
}
}
this.close();
return this;
},
destroy: function() {
this.hideOverlay();
// remove extra modal
if(jQuery('#mailpoet_'+this.options.type).length > 0) {
jQuery('#mailpoet_'+this.options.type).remove();
}
this.initialized = false;
return this;
},
close: function() {
if(this.isLocked() === true) { return this; }
if(this.subpanels.length > 0) {
// close subpanel
jQuery('.mailpoet_'+this.options.type+'_wrapper').last().remove();
// show previous panel
jQuery('.mailpoet_'+this.options.type+'_wrapper').last().show();
// remove last subpanels
this.subpanels.pop();
// focus on previous panel
if(this.options.focus) {
this.focus();
}
return this;
}
// remove event handlers
this.removeEvents();
// hide modal window
this.hideModal();
// destroy modal element
this.destroy();
// restore the previously focused element
if(this.prevFocus !== undefined){
this.prevFocus.focus();
}
// reset options
this.options = {
onSuccess: null,
onCancel: null
};
return this;
}
// remove event handlers
this.removeEvents();
// hide modal window
this.hideModal();
// destroy modal element
this.destroy();
// restore the previously focused element
if (this.prevFocus !== undefined) {
this.prevFocus.focus();
}
// reset options
this.options = {
onSuccess: null,
onCancel: null
};
return this;
}
};
}
);

View File

@ -1,5 +1,6 @@
define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
define('mp2migrator', ['mailpoet', 'jquery'], function (mp, jQuery) {
'use strict';
var MailPoet = mp;
MailPoet.MP2Migrator = {
@ -11,7 +12,7 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
clearTimeout(MailPoet.MP2Migrator.displayLogs_timeout);
clearTimeout(MailPoet.MP2Migrator.updateProgressbar_timeout);
clearTimeout(MailPoet.MP2Migrator.update_wordpress_info_timeout);
setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000)
setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000);
},
stopLogger: function () {
@ -25,17 +26,17 @@ 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('');
result.split('\n').forEach(function (resultRow) {
var row = resultRow;
if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
if (row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
}
// Test if the import is complete
else if(row === MailPoet.I18n.t('import_complete')) {
else if (row === MailPoet.I18n.t('import_complete')) {
jQuery('#import-actions').hide();
jQuery('#upgrade-completed').show();
}
@ -44,7 +45,7 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
});
jQuery('#logger').append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span>' + '<br />\n');
}).always(function () {
if(MailPoet.MP2Migrator.is_logging) {
if (MailPoet.MP2Migrator.is_logging) {
MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000);
}
});
@ -52,23 +53,23 @@ 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) {
// Move the progress bar
var progress = 0;
if((result.total !== undefined) && (Number(result.total) !== 0)) {
if ((result.total !== undefined) && (Number(result.total) !== 0)) {
progress = Math.round(Number(result.current) / Number(result.total) * 100);
}
jQuery('#progressbar').progressbar('option', 'value', progress);
jQuery('#progresslabel').html(progress + '%');
if(Number(result.current) !== 0) {
if (Number(result.current) !== 0) {
jQuery('#skip-import').hide();
jQuery('#progressbar').show();
jQuery('#logger-container').show();
}
if(MailPoet.MP2Migrator.is_logging) {
if (MailPoet.MP2Migrator.is_logging) {
MailPoet.MP2Migrator.updateProgressbar_timeout = setTimeout(MailPoet.MP2Migrator.updateProgressbar, 1000);
}
});
@ -99,16 +100,16 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped
MailPoet.MP2Migrator.reactivateImportButton();
}).done(function (response) {
if(response) {
if (response) {
MailPoet.MP2Migrator.fatal_error = response.data;
}
}).fail(function (response) {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function (error) {
return error.message;
}),
{scroll: true}
{ scroll: true }
);
}
});
@ -134,12 +135,12 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
MailPoet.MP2Migrator.reactivateImportButton();
MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped
}).fail(function (response) {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function (error) {
return error.message;
}),
{scroll: true}
{ scroll: true }
);
}
});
@ -157,12 +158,12 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
}).done(function () {
MailPoet.MP2Migrator.gotoWelcomePage();
}).fail(function (response) {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function (error) {
return error.message;
}),
{scroll: true}
{ scroll: true }
);
}
});
@ -175,33 +176,33 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
}
};
/**
* Actions to run when the DOM is ready
*/
jQuery(function () {
jQuery('#progressbar').progressbar({value: 0});
jQuery('#progressbar').progressbar({ value: 0 });
// Import button
jQuery('#import').click(function() {
jQuery('#import').click(function () {
MailPoet.MP2Migrator.startImport();
});
// Stop import button
jQuery('#stop-import').click(function() {
jQuery('#stop-import').click(function () {
MailPoet.MP2Migrator.stopImport();
});
// Skip import link
jQuery('#skip-import').click(function() {
jQuery('#skip-import').click(function () {
MailPoet.MP2Migrator.skipImport();
});
// Go to welcome page
jQuery('#goto-welcome').click(function() {
jQuery('#goto-welcome').click(function () {
MailPoet.MP2Migrator.gotoWelcomePage();
});
// Update the display
MailPoet.MP2Migrator.updateDisplay();
});

View File

@ -1,12 +1,12 @@
define([
'backbone',
'backbone.marionette',
'backbone.radio',
'jquery',
'underscore',
'handlebars',
'handlebars_helpers'
], function(Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
'backbone',
'backbone.marionette',
'backbone.radio',
'jquery',
'underscore',
'handlebars',
'handlebars_helpers'
], function (Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
var Radio = BackboneRadio;
var AppView = Marionette.View.extend({
@ -23,12 +23,12 @@ define([
var EditorApplication = Marionette.Application.extend({
region: '#mailpoet_editor',
onStart: function() {
onStart: function () {
this._appView = new AppView();
this.showView(this._appView);
},
getChannel: function(channel) {
getChannel: function (channel) {
if (channel === undefined) {
return Radio.channel('global');
}

View File

@ -5,11 +5,11 @@
* For more check: http://marionettejs.com/docs/marionette.behaviors.html#behaviorslookup
*/
define([
'backbone.marionette'
], function(BackboneMarionette) {
'backbone.marionette'
], function (BackboneMarionette) {
var Marionette = BackboneMarionette;
var BehaviorsLookup = {};
Marionette.Behaviors.behaviorsLookup = function() {
Marionette.Behaviors.behaviorsLookup = function () {
return BehaviorsLookup;
};

View File

@ -4,23 +4,43 @@
* Adds a color picker integration with the view
*/
define([
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup',
'mailpoet',
'spectrum'
], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) {
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup',
'mailpoet',
'spectrum'
], function (Marionette, BehaviorsLookup, MailPoet, Spectrum) {
var BL = BehaviorsLookup;
BL.ColorPickerBehavior = Marionette.Behavior.extend({
onRender: function() {
this.view.$('.mailpoet_color').spectrum({
clickoutFiresChange: true,
showInput: true,
showInitial: true,
preferredFormat: 'hex6',
allowEmpty: true,
chooseText: MailPoet.I18n.t('selectColor'),
cancelText: MailPoet.I18n.t('cancelColorSelection')
onRender: function () {
var that = this,
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,
showPalette: true,
showSelectionPalette: true,
palette: [],
localStorageKey: 'newsletter_editor.spectrum.palette',
preferredFormat: preferredFormat,
allowEmpty: true,
chooseText: MailPoet.I18n.t('selectColor'),
cancelText: MailPoet.I18n.t('cancelColorSelection'),
change: updateColorInput,
move: updateColorInput,
hide: updateColorInput
});
});
}
});

View File

@ -1,3 +1,4 @@
/**
* ContainerDropZoneBehavior
*
@ -6,25 +7,25 @@
* accept droppables
*/
define([
'backbone.marionette',
'underscore',
'jquery',
'newsletter_editor/behaviors/BehaviorsLookup',
'interact'
], function(Marionette, _, jQuery, BL, interact) {
'backbone.marionette',
'underscore',
'jquery',
'newsletter_editor/behaviors/BehaviorsLookup',
'interact'
], function (Marionette, _, jQuery, BL, interact) {
var BehaviorsLookup = BL;
BehaviorsLookup.ContainerDropZoneBehavior = Marionette.Behavior.extend({
defaults: {
columnLimit: 3
},
onRender: function() {
onRender: function () {
var dragAndDropDisabled = _.isObject(this.view.options.renderOptions) && this.view.options.renderOptions.disableDragAndDrop === true;
if (!dragAndDropDisabled) {
this.addDropZone();
this.addDropZone();
}
},
addDropZone: function(_event) {
addDropZone: function (_event) {
var that = this,
view = this.view,
domElement = that.$el.get(0),
@ -46,16 +47,16 @@ define([
interact(domElement).dropzone({
accept: acceptableElementSelector,
overlap: 'pointer', // Mouse pointer denotes location of a droppable
ondragenter: function(event) {
ondragenter: function (event) {
// 1. Visually mark block as active for dropping
view.$el.addClass('mailpoet_drop_active');
},
ondragleave: function(event) {
ondragleave: function (event) {
// 1. Remove visual markings of active dropping container
// 2. Remove visual markings of drop position visualization
that.cleanup();
},
ondropmove: function(event) {
ondropmove: function (event) {
// 1. Compute actual location of the mouse within the container
// 2. Check if insertion is regular (between blocks) or special (with container insertion)
// 3a. If insertion is regular, compute position where insertion should happen
@ -149,7 +150,7 @@ define([
// compensated for to position marker right in the middle of two
// blocks
if (dropPosition.position === 'before') {
$targetBlock = that.getChildren().findByModel(viewCollection.at(dropPosition.index-1)).$el;
$targetBlock = that.getChildren().findByModel(viewCollection.at(dropPosition.index - 1)).$el;
} else {
$targetBlock = that.getChildren().findByModel(viewCollection.at(dropPosition.index)).$el;
}
@ -162,7 +163,7 @@ define([
element.append(marker);
},
ondrop: function(event) {
ondrop: function (event) {
// 1. Compute actual location of the mouse
// 2. Check if insertion is regular (between blocks) or special (with container insertion)
// 3a. If insertion is regular
@ -195,13 +196,14 @@ define([
if (view.model.get('orientation') === 'horizontal' && droppableModel.get('type') !== 'container') {
// Regular blocks always need to be inserted into columns - vertical containers
tempCollection = new (EditorApplication.getBlockTypeModel('container'))({
orientation: 'vertical'
tempCollection = new (window.EditorApplication.getBlockTypeModel('container'))({
orientation: 'vertical'
});
tempCollection.get('blocks').add(droppableModel);
viewCollection.add(tempCollection, {at: index});
viewCollection.add(tempCollection, { at: index });
} else {
viewCollection.add(droppableModel, {at: index});
viewCollection.add(droppableModel, { at: index });
}
droppedView = that.getChildren().findByModel(droppableModel);
@ -210,27 +212,27 @@ define([
// and inserting dropModel into that
var tempModel = viewCollection.at(dropPosition.index);
tempCollection = new (EditorApplication.getBlockTypeModel('container'))({
orientation: (view.model.get('orientation') === 'vertical') ? 'horizontal' : 'vertical'
tempCollection = new (window.EditorApplication.getBlockTypeModel('container'))({
orientation: (view.model.get('orientation') === 'vertical') ? 'horizontal' : 'vertical'
});
viewCollection.remove(tempModel);
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);
@ -245,7 +247,7 @@ define([
tempCollection.get('blocks').add(droppableModel);
}
}
viewCollection.add(tempCollection, {at: dropPosition.index});
viewCollection.add(tempCollection, { at: dropPosition.index });
// Call post add actions
droppedView = that.getChildren().findByModel(tempCollection).children.findByModel(droppableModel);
@ -262,14 +264,14 @@ define([
}
});
},
cleanup: function() {
cleanup: function () {
// 1. Remove visual markings of active dropping container
this.view.$el.removeClass('mailpoet_drop_active');
// 2. Remove visual markings of drop position visualization
this.view.$('.mailpoet_drop_marker').remove();
},
getDropPosition: function(eventX, eventY, is_unsafe) {
getDropPosition: function (eventX, eventY, is_unsafe) {
var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3
element = this.view.$el,
@ -291,7 +293,7 @@ define([
insertionType, index, position, indexAndPosition;
unsafe = !!is_unsafe;
var unsafe = !!is_unsafe;
if (this.getCollection().length === 0) {
return {
@ -351,7 +353,7 @@ define([
position: position // 'inside'|'before'|'after'
};
},
_computeNormalIndex: function(eventX, eventY) {
_computeNormalIndex: function (eventX, eventY) {
// Normal insertion inserts dropModel before target element if
// event happens on the first half of the element and after the
// target element if event happens on the second half of the element.
@ -377,24 +379,24 @@ define([
if (eventOffset <= closeOffset + elementDimension / 2) {
// First half of the element
return {
index: index,
position: 'before'
index: index,
position: 'before'
};
} else {
// Second half of the element
return {
index: index,
position: 'after'
index: index,
position: 'after'
};
}
},
_computeSpecialIndex: function(eventX, eventY) {
_computeSpecialIndex: function (eventX, eventY) {
return this._computeCellIndex(eventX, eventY);
},
_computeCellIndex: function(eventX, eventY) {
_computeCellIndex: function (eventX, eventY) {
var orientation = this.view.model.get('orientation'),
eventOffset = (orientation === 'vertical') ? eventY : eventX,
resultView = this.getChildren().find(function(view) {
resultView = this.getChildren().find(function (view) {
var element = view.$el,
closeOffset, farOffset;
@ -414,26 +416,26 @@ define([
return index;
},
_canAcceptNormalInsertion: function() {
_canAcceptNormalInsertion: function () {
var orientation = this.view.model.get('orientation'),
depth = this.view.renderOptions.depth,
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() {
_canAcceptSpecialInsertion: function () {
var orientation = this.view.model.get('orientation'),
depth = this.view.renderOptions.depth,
childCount = this.getChildren().length;
return depth === 0 || (depth === 1 && orientation === 'horizontal' && childCount <= this.options.columnLimit);
},
getCollectionView: function() {
getCollectionView: function () {
return this.view.getChildView('blocks');
},
getChildren: function() {
getChildren: function () {
return this.getCollectionView().children;
},
getCollection: function() {
getCollection: function () {
return this.getCollectionView().collection;
}
});

View File

@ -5,12 +5,12 @@
* Part of the drag&drop behavior.
*/
define([
'backbone.marionette',
'underscore',
'jquery',
'newsletter_editor/behaviors/BehaviorsLookup',
'interact'
], function(Marionette, _, jQuery, BehaviorsLookup, interact) {
'backbone.marionette',
'underscore',
'jquery',
'newsletter_editor/behaviors/BehaviorsLookup',
'interact'
], function (Marionette, _, jQuery, BehaviorsLookup, interact) {
var BL = BehaviorsLookup;
BL.DraggableBehavior = Marionette.Behavior.extend({
@ -24,22 +24,22 @@ define([
*
* @return Backbone.Model A model that will be passed to the receiver
*/
getDropModel: function() {
getDropModel: function () {
throw "Missing 'drop' function for DraggableBehavior";
},
onDrop: function(model, view) {},
testAttachToInstance: function(model, view) { return true; }
onDrop: function (model, view) {},
testAttachToInstance: function (model, view) { return true; }
},
onRender: function() {
onRender: function () {
var that = this,
interactable;
interactable;
// Give instances more control over whether Draggable should be applied
if (!this.options.testAttachToInstance(this.view.model, this.view)) return;
interactable = interact(this.$el.get(0), {
ignoreFrom: this.options.ignoreSelector
ignoreFrom: this.options.ignoreSelector
}).draggable({
// allow dragging of multple elements at the same time
max: Infinity,
@ -47,14 +47,14 @@ define([
// Scroll when dragging near edges of a window
autoScroll: true,
onstart: function(startEvent) {
onstart: function (startEvent) {
var event = startEvent;
if (that.options.cloneOriginal === true) {
// Use substitution instead of a clone
var tempClone = (_.isFunction(that.options.onDragSubstituteBy)) ? that.options.onDragSubstituteBy(that) : undefined,
// Or use a clone
clone = tempClone ? tempClone : event.target.cloneNode(true),
clone = tempClone || event.target.cloneNode(true),
$original = jQuery(event.target),
$clone = jQuery(clone),
@ -71,7 +71,7 @@ define([
// Accurate dimensions can only be taken after insertion to document
centerXOffset = $clone.width() / 2;
centerYOffset = $clone.height() / 2;
$clone.css('top', event.pageY - centerYOffset);
$clone.css('top', event.pageY - centerYOffset);
$clone.css('left', event.pageX - centerXOffset);
event.interaction.element = clone;
@ -131,7 +131,7 @@ define([
} else {
interactable.getDropModel = this.view.getDropFunc();
}
interactable.onDrop = function(opts) {
interactable.onDrop = function (opts) {
var options = opts;
if (_.isObject(options)) {
// Inject Draggable behavior if possible

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

@ -4,9 +4,9 @@
* Highlights a block that is being edited
*/
define([
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, BehaviorsLookup) {
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup'
], function (Marionette, BehaviorsLookup) {
var BL = BehaviorsLookup;
BL.HighlightEditingBehavior = Marionette.Behavior.extend({
@ -14,10 +14,12 @@ define([
startEditing: 'enableHighlight',
stopEditing: 'disableHighlight'
},
enableHighlight: function() {
enableHighlight: function () {
this.view._isBeingEdited = true;
this.$el.addClass('mailpoet_highlight');
},
disableHighlight: function() {
disableHighlight: function () {
this.view._isBeingEdited = false;
this.$el.removeClass('mailpoet_highlight');
}
});

View File

@ -4,63 +4,68 @@
* Allows resizing elements within a block
*/
define([
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup',
'interact'
], function(Marionette, BehaviorsLookup, interact) {
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup',
'interact'
], function (Marionette, BehaviorsLookup, interact) {
var BL = BehaviorsLookup;
BL.ResizableBehavior = Marionette.Behavior.extend({
defaults: {
elementSelector: null,
resizeHandleSelector: true, // true will use edges of the element itself
transformationFunction: function(y) { return y; },
minLength: 0,
modelField: 'styles.block.height'
maxLength: Infinity,
modelField: 'styles.block.height',
onResize: function (event) {
var currentLength = parseFloat(this.view.model.get(this.options.modelField)),
newLength = currentLength + event.y;
newLength = Math.min(this.options.maxLength, Math.max(this.options.minLength, newLength));
this.view.model.set(this.options.modelField, newLength + 'px');
}
},
events: {
mouseenter: 'showResizeHandle',
mouseleave: 'hideResizeHandle'
},
onRender: function() {
onRender: function () {
this.attachResize();
if (this.isBeingResized !== true) {
this.hideResizeHandle();
}
},
attachResize: function() {
attachResize: function () {
var domElement = (this.options.elementSelector === null) ? this.view.$el.get(0) : this.view.$(this.options.elementSelector).get(0),
that = this;
that = this;
interact(domElement).resizable({
//axis: 'y',
// axis: 'y',
edges: {
top: false,
left: false,
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 (event) {
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 (event) {
that.isBeingResized = null;
that.$el.removeClass('mailpoet_resize_active');
});
},
showResizeHandle: function() {
showResizeHandle: function () {
if (typeof this.options.resizeHandleSelector === 'string') {
this.view.$(this.options.resizeHandleSelector).removeClass('mailpoet_hidden');
}
},
hideResizeHandle: function() {
hideResizeHandle: function () {
if (typeof this.options.resizeHandleSelector === 'string') {
this.view.$(this.options.resizeHandleSelector).addClass('mailpoet_hidden');
}

View File

@ -4,10 +4,10 @@
* Opens up settings of a BlockView if contents are clicked upon
*/
define([
'backbone.marionette',
'jquery',
'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, jQuery, BehaviorsLookup) {
'backbone.marionette',
'jquery',
'newsletter_editor/behaviors/BehaviorsLookup'
], function (Marionette, jQuery, BehaviorsLookup) {
var BL = BehaviorsLookup;
BL.ShowSettingsBehavior = Marionette.Behavior.extend({
@ -17,12 +17,12 @@ define([
events: {
'click .mailpoet_content': 'showSettings'
},
showSettings: function(event) {
if(!this.isIgnoredElement(event.target)) {
showSettings: function (event) {
if (!this.isIgnoredElement(event.target)) {
this.view.triggerMethod('showSettings');
}
},
isIgnoredElement: function(element) {
isIgnoredElement: function (element) {
return this.options.ignoreFrom
&& this.options.ignoreFrom.length > 0
&& jQuery(element).is(this.options.ignoreFrom);

View File

@ -4,26 +4,26 @@
* Allows sorting elements within a collection
*/
define([
'backbone.marionette',
'underscore',
'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, _, BehaviorsLookup) {
'backbone.marionette',
'underscore',
'newsletter_editor/behaviors/BehaviorsLookup'
], function (Marionette, _, BehaviorsLookup) {
var BL = BehaviorsLookup;
BL.SortableBehavior = Marionette.Behavior.extend({
onRender: function() {
onRender: function () {
var collection = this.view.collection;
if (_.isFunction(this.$el.sortable)) {
this.$el.sortable({
cursor: 'move',
start: function(event, ui) {
start: function (event, ui) {
ui.item.data('previousIndex', ui.item.index());
},
end: function(event, ui) {
end: function (event, ui) {
ui.item.removeData('previousIndex');
},
update: function(event, ui) {
update: function (event, ui) {
var previousIndex = ui.item.data('previousIndex'),
newIndex = ui.item.index(),
model = collection.at(previousIndex);

View File

@ -4,10 +4,10 @@
* Adds TinyMCE text editing capabilities to a view
*/
define([
'backbone.marionette',
'underscore',
'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, _, BehaviorsLookup) {
'backbone.marionette',
'underscore',
'newsletter_editor/behaviors/BehaviorsLookup'
], function (Marionette, _, BehaviorsLookup) {
var BL = BehaviorsLookup;
BL.TextEditorBehavior = Marionette.Behavior.extend({
@ -19,9 +19,9 @@ define([
invalidElements: 'script',
blockFormats: 'Paragraph=p',
plugins: 'link textcolor colorpicker mailpoet_shortcodes',
configurationFilter: function(originalConfig) { return originalConfig; }
configurationFilter: function (originalConfig) { return originalConfig; }
},
onDomRefresh: function() {
onDomRefresh: function () {
var that = this;
if (this.view.disableTextEditor === true) {
return;
@ -34,13 +34,15 @@ define([
toolbar1: this.options.toolbar1,
toolbar2: this.options.toolbar2,
browser_spellcheck: true,
valid_elements: this.options.validElements,
invalid_elements: this.options.invalidElements,
block_formats: this.options.blockFormats,
relative_urls: false,
remove_script_host: false,
convert_urls: true,
urlconverter_callback: function(url, node, on_save, name) {
urlconverter_callback: function (url, node, on_save, name) {
if (url.match(/\[.+\]/g)) {
// Do not convert URLs with shortcodes
return url;
@ -54,27 +56,27 @@ define([
plugins: this.options.plugins,
setup: function(editor) {
editor.on('change', function(e) {
setup: function (editor) {
editor.on('change', function (e) {
that.view.triggerMethod('text:editor:change', editor.getContent());
});
editor.on('click', function(e) {
editor.on('click', function (e) {
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 (e) {
that.view.triggerMethod('text:editor:focus');
that._isActivationClick = true;
that._isActivationClick = true;
});
editor.on('blur', function(e) {
editor.on('blur', function (e) {
that.view.triggerMethod('text:editor:blur');
});
}

View File

@ -7,34 +7,34 @@
* block settings view.
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'newsletter_editor/blocks/button',
'newsletter_editor/blocks/divider',
'newsletter_editor/components/communication',
'mailpoet',
'backbone.supermodel',
'underscore',
'jquery'
], function(
App,
BaseBlock,
ButtonBlock,
DividerBlock,
CommunicationComponent,
MailPoet,
SuperModel,
_,
jQuery
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'newsletter_editor/blocks/button',
'newsletter_editor/blocks/divider',
'newsletter_editor/components/communication',
'mailpoet',
'backbone.supermodel',
'underscore',
'jquery'
], function (
App,
BaseBlock,
ButtonBlock,
DividerBlock,
CommunicationComponent,
MailPoet,
SuperModel,
_,
jQuery
) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.ALCSupervisor = SuperModel.extend({
initialize: function() {
initialize: function () {
var DELAY_REFRESH_FOR_MS = 500;
this.listenTo(
App.getChannel(),
@ -42,13 +42,13 @@ define([
_.debounce(this.refresh, DELAY_REFRESH_FOR_MS)
);
},
refresh: function() {
var models = App.findModels(function(model) {
refresh: function () {
var models = App.findModels(function (model) {
return model.get('type') === 'automatedLatestContent';
}) || [];
if (models.length === 0) return;
var blocks = _.map(models, function(model) {
var blocks = _.map(models, function (model) {
return model.toJSON();
});
@ -56,12 +56,12 @@ define([
blocks: blocks
}).then(_.partial(this.refreshBlocks, models));
},
refreshBlocks: function(models, renderedBlocks) {
refreshBlocks: function (models, renderedBlocks) {
_.each(
_.zip(models, renderedBlocks),
function(args) {
function (args) {
var model = args[0],
contents = args[1];
contents = args[1];
model.trigger('refreshPosts', contents);
}
);
@ -70,7 +70,7 @@ define([
Module.AutomatedLatestContentBlockModel = base.BlockModel.extend({
stale: ['_container'],
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'automatedLatestContent',
amount: '5',
@ -83,7 +83,7 @@ define([
titleIsLink: false, // false|true
imageFullWidth: false, // true|false
featuredImagePosition: 'belowTitle', // 'aboveTitle'|'belowTitle'|'none'
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
// imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
authorPrecededBy: 'Author:',
showCategories: 'no', // 'no'|'aboveText'|'belowText'
@ -100,14 +100,14 @@ define([
_container: new (App.getBlockTypeModel('container'))()
}, App.getConfig().get('blockDefaults.automatedLatestContent'));
},
relations: function() {
relations: function () {
return {
readMoreButton: App.getBlockTypeModel('button'),
divider: App.getBlockTypeModel('divider'),
_container: App.getBlockTypeModel('container')
};
},
initialize: function() {
initialize: function () {
base.BlockView.prototype.initialize.apply(this, arguments);
this.on('change:amount change:contentType change:terms change:inclusionType change:displayType change:titleFormat change:featuredImagePosition change:titleAlignment change:titleIsLink change:imageFullWidth change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:sortBy change:showDivider', this._scheduleFetchPosts, this);
this.listenTo(this.get('readMoreButton'), 'change', this._scheduleFetchPosts);
@ -115,27 +115,27 @@ define([
this.on('add remove update reset', this._scheduleFetchPosts);
this.on('refreshPosts', this.updatePosts, this);
},
updatePosts: function(posts) {
this.get('_container.blocks').reset(posts, {parse: true});
updatePosts: function (posts) {
this.get('_container.blocks').reset(posts, { parse: true });
},
/**
* Batch more changes during a specific time, instead of fetching
* ALC posts on each model change
*/
_scheduleFetchPosts: function() {
_scheduleFetchPosts: function () {
App.getChannel().trigger('automatedLatestContentRefresh');
}
});
Module.AutomatedLatestContentBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_automated_latest_content_block mailpoet_droppable_block',
initialize: function() {
initialize: function () {
function replaceButtonStylesHandler(data) {
this.model.set({readMoreButton: data});
this.model.set({ readMoreButton: data });
}
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'
@ -148,8 +148,8 @@ define([
events: _.extend(base.BlockView.prototype.events, {
'click .mailpoet_automated_latest_content_block_overlay': 'showSettings'
}),
onDragSubstituteBy: function() { return Module.AutomatedLatestContentWidgetView; },
onRender: function() {
onDragSubstituteBy: function () { return Module.AutomatedLatestContentWidgetView; },
onRender: function () {
var ContainerView = App.getBlockTypeView('container'),
renderOptions = {
disableTextEditor: true,
@ -163,13 +163,13 @@ define([
});
Module.AutomatedLatestContentBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.AutomatedLatestContentBlockSettingsView; }
getSettingsView: function () { return Module.AutomatedLatestContentBlockSettingsView; }
});
// Sidebar view container
Module.AutomatedLatestContentBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.automatedLatestContentBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.automatedLatestContentBlockSettings; },
events: function () {
return {
'click .mailpoet_automated_latest_content_hide_display_options': 'toggleDisplayOptions',
'click .mailpoet_automated_latest_content_show_display_options': 'toggleDisplayOptions',
@ -195,7 +195,7 @@ define([
'click .mailpoet_done_editing': 'close'
};
},
onRender: function() {
onRender: function () {
var that = this;
// Dynamically update available post types
@ -211,17 +211,17 @@ define([
term: params.term
};
},
transport: function(options, success, failure) {
transport: function (options, success, failure) {
var taxonomies;
var promise = CommunicationComponent.getTaxonomies(
that.model.get('contentType')
).then(function(tax) {
).then(function (tax) {
taxonomies = tax;
// Fetch available terms based on the list of taxonomies already fetched
var promise = CommunicationComponent.getTerms({
search: options.data.term,
taxonomies: _.keys(taxonomies)
}).then(function(terms) {
}).then(function (terms) {
return {
taxonomies: taxonomies,
terms: terms
@ -234,12 +234,12 @@ define([
promise.fail(failure);
return promise;
},
processResults: function(data) {
processResults: function (data) {
// Transform taxonomies and terms into select2 compatible format
return {
results: _.map(
data.terms,
function(item) {
function (item) {
return _.defaults({
text: data.taxonomies[item.taxonomy].labels.singular_name + ': ' + item.name,
id: item.term_id
@ -250,21 +250,21 @@ define([
}
}
}).on({
'select2:select': function(event) {
'select2:select': function (event) {
var terms = that.model.get('terms');
terms.add(event.params.data);
// Reset whole model in order for change events to propagate properly
that.model.set('terms', terms.toJSON());
},
'select2:unselect': function(event) {
'select2:unselect': function (event) {
var terms = that.model.get('terms');
terms.remove(event.params.data);
// Reset whole model in order for change events to propagate properly
that.model.set('terms', terms.toJSON());
}
}).trigger( 'change' );
}).trigger('change');
},
toggleDisplayOptions: function(event) {
toggleDisplayOptions: function (event) {
var el = this.$('.mailpoet_automated_latest_content_display_options'),
showControl = this.$('.mailpoet_automated_latest_content_show_display_options');
if (el.hasClass('mailpoet_closed')) {
@ -275,7 +275,7 @@ define([
showControl.removeClass('mailpoet_hidden');
}
},
showButtonSettings: function(event) {
showButtonSettings: function (event) {
var buttonModule = ButtonBlock;
(new buttonModule.ButtonBlockSettingsView({
model: this.model.get('readMoreButton'),
@ -286,7 +286,7 @@ define([
}
})).render();
},
showDividerSettings: function(event) {
showDividerSettings: function (event) {
var dividerModule = DividerBlock;
(new dividerModule.DividerBlockSettingsView({
model: this.model.get('divider'),
@ -296,7 +296,7 @@ define([
}
})).render();
},
changeReadMoreType: function(event) {
changeReadMoreType: function (event) {
var value = jQuery(event.target).val();
if (value == 'link') {
this.$('.mailpoet_automated_latest_content_read_more_text').removeClass('mailpoet_hidden');
@ -307,7 +307,7 @@ define([
}
this.changeField('readMoreType', event);
},
changeDisplayType: function(event) {
changeDisplayType: function (event) {
var value = jQuery(event.target).val();
if (value == 'titleOnly') {
@ -334,7 +334,7 @@ define([
}
this.changeField('displayType', event);
},
changeTitleFormat: function(event) {
changeTitleFormat: function (event) {
var value = jQuery(event.target).val();
if (value == 'ul') {
this.$('.mailpoet_automated_latest_content_non_title_list_options').addClass('mailpoet_hidden');
@ -348,12 +348,12 @@ define([
}
this.changeField('titleFormat', event);
},
_updateContentTypes: function(postTypes) {
_updateContentTypes: function (postTypes) {
var select = this.$('.mailpoet_automated_latest_content_content_type'),
selectedValue = this.model.get('contentType');
selectedValue = this.model.get('contentType');
select.find('option').remove();
_.each(postTypes, function(type) {
_.each(postTypes, function (type) {
select.append(jQuery('<option>', {
value: type.name,
text: type.label
@ -364,21 +364,21 @@ define([
});
Module.AutomatedLatestContentWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.automatedLatestContentInsertion; },
getTemplate: function () { return window.templates.automatedLatestContentInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.AutomatedLatestContentBlockModel({}, { parse: true });
},
onDrop: function(options) {
onDrop: function (options) {
options.droppedView.triggerMethod('showSettings');
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('automatedLatestContent', {
blockModel: Module.AutomatedLatestContentBlockModel,
blockView: Module.AutomatedLatestContentBlockView
@ -391,7 +391,7 @@ define([
});
});
App.on('start', function(App, options) {
App.on('start', function (App, options) {
var Application = App;
Application._ALCSupervisor = new Module.ALCSupervisor();
Application._ALCSupervisor.refresh();

View File

@ -5,29 +5,29 @@
* BlockToolsView, BlockSettingsView and BlockWidgetView are optional.
*/
define([
'newsletter_editor/App',
'backbone.marionette',
'backbone.supermodel',
'underscore',
'jquery',
'mailpoet',
'modal'
], function(App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
'newsletter_editor/App',
'backbone.marionette',
'backbone.supermodel',
'underscore',
'jquery',
'mailpoet',
'modal'
], function (App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
'use strict';
var Module = {},
AugmentedView = Marionette.View.extend({});
AugmentedView = Marionette.View.extend({});
Module.BlockModel = SuperModel.extend({
stale: [], // Attributes to be removed upon saving
initialize: function() {
initialize: function () {
var that = this;
this.on('change', function() {
this.on('change', function () {
App.getChannel().trigger('autoSave');
});
},
_getDefaults: function(blockDefaults, configDefaults) {
_getDefaults: function (blockDefaults, configDefaults) {
var defaults = (_.isObject(configDefaults) && _.isFunction(configDefaults.toJSON)) ? configDefaults.toJSON() : configDefaults;
// Patch the resulting JSON object and fix it's constructors to be Object.
@ -36,11 +36,11 @@ define([
// TODO: Investigate for a better solution
return JSON.parse(JSON.stringify(jQuery.extend(blockDefaults, defaults || {})));
},
toJSON: function() {
toJSON: function () {
// Remove stale attributes from resulting JSON object
return _.omit(SuperModel.prototype.toJSON.call(this), this.stale);
},
getChildren: function() {
getChildren: function () {
return [];
}
});
@ -62,12 +62,12 @@ define([
DraggableBehavior: {
cloneOriginal: true,
hideOriginal: true,
onDrop: function(options) {
onDrop: function (options) {
// After a clone of model has been dropped, cleanup
// and destroy self
options.dragBehavior.view.model.destroy();
},
onDragSubstituteBy: function(behavior) {
onDragSubstituteBy: function (behavior) {
var WidgetView, node;
// When block is being dragged, display the widget icon instead.
// This will create an instance of block's widget view and
@ -83,76 +83,76 @@ define([
},
HighlightEditingBehavior: {}
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON(),
viewCid: this.cid
};
},
constructor: function() {
constructor: function () {
AugmentedView.apply(this, arguments);
this.$el.addClass('mailpoet_editor_view_' + this.cid);
},
initialize: function() {
initialize: function () {
this.on('showSettings', this.showSettings, this);
this.on('dom:refresh', this.showBlock, this);
this._isFirstRender = true;
},
showTools: function(_event) {
showTools: function (_event) {
if (!this.showingToolsDisabled) {
this.$('> .mailpoet_tools').addClass('mailpoet_display_tools');
this.toolsView.triggerMethod('showTools');
}
},
hideTools: function(e) {
hideTools: function (e) {
this.$('> .mailpoet_tools').removeClass('mailpoet_display_tools');
this.toolsView.triggerMethod('hideTools');
},
enableShowingTools: function() {
enableShowingTools: function () {
this.showingToolsDisabled = false;
},
disableShowingTools: function() {
disableShowingTools: function () {
this.showingToolsDisabled = true;
this.hideTools();
},
showSettings: function(options) {
showSettings: function (options) {
this.toolsView.triggerMethod('showSettings', options);
},
/**
* Defines drop behavior of BlockView instance
*/
getDropFunc: function() {
return function() {
getDropFunc: function () {
return function () {
return this.model.clone();
}.bind(this);
},
disableDragging: function() {
disableDragging: function () {
this.$el.addClass('mailpoet_ignore_drag');
},
enableDragging: function() {
enableDragging: function () {
this.$el.removeClass('mailpoet_ignore_drag');
},
showBlock: function() {
showBlock: function () {
if (this._isFirstRender) {
this.transitionIn();
this._isFirstRender = false;
}
},
deleteBlock: function() {
this.transitionOut().then(function() {
deleteBlock: function () {
this.transitionOut().then(function () {
this.model.destroy();
}.bind(this));
},
duplicateBlock: function() {
this.model.collection.add(this.model.toJSON(), {at: this.model.collection.findIndex(this.model)});
duplicateBlock: function () {
this.model.collection.add(this.model.toJSON(), { at: this.model.collection.findIndex(this.model) });
},
transitionIn: function() {
transitionIn: function () {
return this._transition('slideDown', 'fadeIn', 'easeOut');
},
transitionOut: function() {
transitionOut: function () {
return this._transition('slideUp', 'fadeOut', 'easeIn');
},
_transition: function(slideDirection, fadeDirection, easing) {
_transition: function (slideDirection, fadeDirection, easing) {
var promise = jQuery.Deferred();
this.$el.velocity(
@ -160,7 +160,7 @@ define([
{
duration: 250,
easing: easing,
complete: function() {
complete: function () {
promise.resolve();
}.bind(this)
}
@ -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',
@ -193,8 +193,8 @@ define([
duplicate: true,
move: true
},
getSettingsView: function() { return Module.BlockSettingsView; },
initialize: function(opts) {
getSettingsView: function () { return Module.BlockSettingsView; },
initialize: function (opts) {
var options = opts || {};
if (!_.isUndefined(options.tools)) {
// Make a new block specific tool config object
@ -205,29 +205,29 @@ define([
this.on('hideTools', this.hideDeletionConfirmation, this);
this.on('showSettings', this.changeSettings);
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON(),
viewCid: this.cid,
tools: this.tools
};
},
changeSettings: function(options) {
changeSettings: function (options) {
var ViewType = this.getSettingsView();
(new ViewType(_.extend({ model: this.model }, options || {}))).render();
},
showDeletionConfirmation: function() {
showDeletionConfirmation: function () {
this.$('.mailpoet_delete_block').addClass('mailpoet_delete_block_activated');
},
hideDeletionConfirmation: function() {
hideDeletionConfirmation: function () {
this.$('.mailpoet_delete_block').removeClass('mailpoet_delete_block_activated');
},
deleteBlock: function(event) {
deleteBlock: function (event) {
event.preventDefault();
this.model.trigger('delete');
return false;
},
duplicateBlock: function(event) {
duplicateBlock: function (event) {
event.preventDefault();
this.model.trigger('duplicate');
return false;
@ -239,14 +239,14 @@ define([
behaviors: {
ColorPickerBehavior: {}
},
initialize: function(params) {
initialize: function (params) {
this.model.trigger('startEditing');
var panelParams = {
element: this.$el,
template: '',
position: 'right',
width: App.getConfig().get('sidepanelWidth'),
onCancel: function() {
onCancel: function () {
this.destroy();
}.bind(this)
};
@ -257,37 +257,37 @@ define([
MailPoet.Modal.panel(panelParams);
}
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON()
};
},
close: function(event) {
close: function (event) {
this.destroy();
},
changeField: function(field, event) {
changeField: function (field, event) {
this.model.set(field, jQuery(event.target).val());
},
changePixelField: function(field, event) {
changePixelField: function (field, event) {
this.changeFieldWithSuffix(field, event, 'px');
},
changeFieldWithSuffix: function(field, event, suffix) {
changeFieldWithSuffix: function (field, event, suffix) {
this.model.set(field, jQuery(event.target).val() + suffix);
},
changeBoolField: function(field, event) {
this.model.set(field, (jQuery(event.target).val() === 'true') ? true : false);
changeBoolField: function (field, event) {
this.model.set(field, (jQuery(event.target).val() === 'true'));
},
changeBoolCheckboxField: function(field, event) {
changeBoolCheckboxField: function (field, event) {
this.model.set(field, (!!jQuery(event.target).prop('checked')));
},
changeColorField: function(field, event) {
changeColorField: function (field, event) {
var value = jQuery(event.target).val();
if (value === '') {
value = 'transparent';
}
this.model.set(field, value);
},
onBeforeDestroy: function() {
onBeforeDestroy: function () {
MailPoet.Modal.close();
this.model.trigger('stopEditing');
}
@ -297,7 +297,7 @@ define([
className: 'mailpoet_widget mailpoet_droppable_block mailpoet_droppable_widget',
behaviors: {
DraggableBehavior: {
drop: function() {
drop: function () {
throw 'Unsupported operation';
}
}

View File

@ -2,20 +2,20 @@
* Button content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'mailpoet',
'underscore',
'jquery'
], function(App, BaseBlock, MailPoet, _, jQuery) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'mailpoet',
'underscore',
'jquery'
], function (App, BaseBlock, MailPoet, _, jQuery) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.ButtonBlockModel = base.BlockModel.extend({
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'button',
text: 'Button',
@ -42,31 +42,31 @@ define([
Module.ButtonBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_button_block mailpoet_droppable_block',
getTemplate: function() { return templates.buttonBlock; },
onDragSubstituteBy: function() { return Module.ButtonWidgetView; },
getTemplate: function () { return window.templates.buttonBlock; },
onDragSubstituteBy: function () { return Module.ButtonWidgetView; },
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
ShowSettingsBehavior: {}
}),
initialize: function() {
initialize: function () {
base.BlockView.prototype.initialize.apply(this, arguments);
// Listen for attempts to change all dividers in one go
this._replaceButtonStylesHandler = function(data) { this.model.set(data); }.bind(this);
this._replaceButtonStylesHandler = function (data) { this.model.set(data); }.bind(this);
App.getChannel().on('replaceAllButtonStyles', this._replaceButtonStylesHandler);
},
onRender: function() {
onRender: function () {
this.toolsView = new Module.ButtonBlockToolsView({ model: this.model });
this.showChildView('toolsRegion', this.toolsView);
}
});
Module.ButtonBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.ButtonBlockSettingsView; }
getSettingsView: function () { return Module.ButtonBlockSettingsView; }
});
Module.ButtonBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.buttonBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.buttonBlockSettings; },
events: function () {
return {
'input .mailpoet_field_button_text': _.partial(this.changeField, 'text'),
'input .mailpoet_field_button_url': _.partial(this.changeField, 'url'),
@ -98,20 +98,20 @@ define([
'click .mailpoet_done_editing': 'close'
};
},
templateContext: function() {
templateContext: function () {
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
availableStyles: App.getAvailableStyles().toJSON(),
renderOptions: this.renderOptions
});
},
applyToAll: function() {
applyToAll: function () {
App.getChannel().trigger('replaceAllButtonStyles', _.pick(this.model.toJSON(), 'styles', 'type'));
},
updateValueAndCall: function(fieldToUpdate, callable, event) {
updateValueAndCall: function (fieldToUpdate, callable, event) {
this.$(fieldToUpdate).val(jQuery(event.target).val());
callable(event);
},
changeFontWeight: function(event) {
changeFontWeight: function (event) {
var checked = !!jQuery(event.target).prop('checked');
this.model.set(
'styles.block.fontWeight',
@ -121,18 +121,18 @@ define([
});
Module.ButtonWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.buttonInsertion; },
getTemplate: function () { return window.templates.buttonInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.ButtonBlockModel();
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('button', {
blockModel: Module.ButtonBlockModel,
blockView: Module.ButtonBlockView

View File

@ -4,31 +4,31 @@
* as other containers.
*/
define([
'backbone',
'backbone.marionette',
'underscore',
'jquery',
'newsletter_editor/App',
'newsletter_editor/blocks/base'
], function(Backbone, Marionette, _, jQuery, App, BaseBlock) {
'backbone',
'backbone.marionette',
'underscore',
'jquery',
'newsletter_editor/App',
'newsletter_editor/blocks/base'
], function (Backbone, Marionette, _, jQuery, App, BaseBlock) {
'use strict';
var Module = {},
base = BaseBlock,
BlockCollection;
base = BaseBlock,
BlockCollection;
BlockCollection = Backbone.Collection.extend({
model: base.BlockModel,
initialize: function() {
this.on('add change remove', function() { App.getChannel().trigger('autoSave'); });
initialize: function () {
this.on('add change remove', function () { App.getChannel().trigger('autoSave'); });
},
parse: function(response) {
parse: function (response) {
var self = this;
return _.map(response, function(block) {
return _.map(response, function (block) {
var Type = App.getBlockTypeModel(block.type);
// TODO: If type has no registered model, use a backup one
return new Type(block, {parse: true});
return new Type(block, { parse: true });
});
}
});
@ -37,7 +37,7 @@ define([
relations: {
blocks: BlockCollection
},
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'container',
orientation: 'vertical',
@ -49,14 +49,14 @@ define([
blocks: new BlockCollection()
}, App.getConfig().get('blockDefaults.container'));
},
validate: function() {
validate: function () {
// Recursively propagate validation checks to blocks in the tree
var invalidBlock = this.get('blocks').find(function(block) { return !block.isValid(); });
var invalidBlock = this.get('blocks').find(function (block) { return !block.isValid(); });
if (invalidBlock) {
return invalidBlock.validationError;
}
},
parse: function(response) {
parse: function (response) {
// If container has any blocks - add them to a collection
if (response.type === 'container' && _.has(response, 'blocks')) {
response.blocks = new BlockCollection(response.blocks, {
@ -65,8 +65,8 @@ define([
}
return response;
},
getChildren: function() {
var models = this.get('blocks').map(function(model, index, list) {
getChildren: function () {
var models = this.get('blocks').map(function (model, index, list) {
return [model, model.getChildren()];
});
@ -76,10 +76,10 @@ define([
Module.ContainerBlocksView = Marionette.CollectionView.extend({
className: 'mailpoet_container',
childView: function(model) {
childView: function (model) {
return App.getBlockTypeView(model.get('type'));
},
childViewOptions: function() {
childViewOptions: function () {
var newRenderOptions = _.clone(this.renderOptions);
if (newRenderOptions.depth !== undefined) {
newRenderOptions.depth += 1;
@ -88,9 +88,9 @@ define([
renderOptions: newRenderOptions
};
},
emptyView: function() { return Module.ContainerBlockEmptyView; },
emptyViewOptions: function() { return { renderOptions: this.renderOptions }; },
initialize: function(options) {
emptyView: function () { return Module.ContainerBlockEmptyView; },
emptyViewOptions: function () { return { renderOptions: this.renderOptions }; },
initialize: function (options) {
this.renderOptions = options.renderOptions;
}
});
@ -103,7 +103,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'
}),
@ -115,12 +115,12 @@ define([
DraggableBehavior: {
cloneOriginal: true,
hideOriginal: true,
onDrop: function(options) {
onDrop: function (options) {
// After a clone of model has been dropped, cleanup
// and destroy self
options.dragBehavior.view.model.destroy();
},
onDragSubstituteBy: function(behavior) {
onDragSubstituteBy: function (behavior) {
var WidgetView, node;
// When block is being dragged, display the widget icon instead.
// This will create an instance of block's widget view and
@ -133,14 +133,15 @@ define([
return node;
}
},
testAttachToInstance: function(model, view) {
testAttachToInstance: function (model, view) {
// Attach Draggable only to layout containers and disable it
// for root and column containers.
return view.renderOptions.depth === 1;
}
}
},
HighlightContainerBehavior: {}
}),
onDragSubstituteBy: function() {
onDragSubstituteBy: function () {
// For two and three column layouts display their respective widgets,
// otherwise always default to one column layout widget
if (this.renderOptions.depth === 1) {
@ -150,12 +151,12 @@ define([
return Module.OneColumnContainerWidgetView;
},
initialize: function(options) {
initialize: function (options) {
base.BlockView.prototype.initialize.apply(this, arguments);
this.renderOptions = _.defaults(options.renderOptions || {}, {});
},
onRender: function() {
onRender: function () {
this.toolsView = new Module.ContainerBlockToolsView({
model: this.model,
tools: {
@ -176,31 +177,31 @@ define([
// Sets child container orientation HTML class here, as child CollectionView won't have access to model and will overwrite existing region element instead
this.$('> .mailpoet_container').attr('class', 'mailpoet_container mailpoet_container_' + this.model.get('orientation'));
},
showTools: function() {
showTools: function () {
if (this.renderOptions.depth === 1 && !this.$el.hasClass('mailpoet_container_layer_active')) {
this.$(this.ui.tools).addClass('mailpoet_display_tools');
this.toolsView.triggerMethod('showTools');
}
},
hideTools: function() {
hideTools: function () {
if (this.renderOptions.depth === 1 && !this.$el.hasClass('mailpoet_container_layer_active')) {
this.$(this.ui.tools).removeClass('mailpoet_display_tools');
this.toolsView.triggerMethod('hideTools');
}
},
toggleEditingLayer: function(event) {
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() {
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() {
disableContainerLayer = function () {
that.$el.removeClass('mailpoet_container_layer_active');
$toggleButton.removeClass('mailpoet_container_layer_active');
$container.removeClass('mailpoet_layer_highlight');
@ -217,11 +218,11 @@ define([
});
Module.ContainerBlockEmptyView = Marionette.View.extend({
getTemplate: function() { return templates.containerEmpty; },
initialize: function(options) {
getTemplate: function () { return window.templates.containerEmpty; },
initialize: function (options) {
this.renderOptions = _.defaults(options.renderOptions || {}, {});
},
templateContext: function() {
templateContext: function () {
return {
isRoot: this.renderOptions.depth === 0,
emptyContainerMessage: this.renderOptions.emptyContainerMessage || ''
@ -230,12 +231,12 @@ define([
});
Module.ContainerBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.ContainerBlockSettingsView; }
getSettingsView: function () { return Module.ContainerBlockSettingsView; }
});
Module.ContainerBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.containerBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.containerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_container_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
'click .mailpoet_done_editing': 'close'
@ -244,21 +245,21 @@ define([
regions: {
columnsSettingsRegion: '.mailpoet_container_columns_settings'
},
initialize: function() {
initialize: function () {
base.BlockSettingsView.prototype.initialize.apply(this, arguments);
this._columnsSettingsView = new (Module.ContainerBlockColumnsSettingsView)({
collection: this.model.get('blocks')
});
},
onRender: function() {
onRender: function () {
this.showChildView('columnsSettingsRegion', this._columnsSettingsView);
}
});
Module.ContainerBlockColumnsSettingsView = Marionette.CollectionView.extend({
childView: function() { return Module.ContainerBlockColumnSettingsView; },
childViewOptions: function(model, index) {
childView: function () { return Module.ContainerBlockColumnSettingsView; },
childViewOptions: function (model, index) {
return {
columnIndex: index
};
@ -266,11 +267,11 @@ define([
});
Module.ContainerBlockColumnSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.containerBlockColumnSettings; },
initialize: function(options) {
getTemplate: function () { return window.templates.containerBlockColumnSettings; },
initialize: function (options) {
this.columnNumber = (options.columnIndex || 0) + 1;
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON(),
columnNumber: this.columnNumber
@ -280,11 +281,11 @@ 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,
drop: function() {
drop: function () {
return new Module.ContainerBlockModel({
orientation: 'horizontal',
blocks: [
@ -298,11 +299,11 @@ 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,
drop: function() {
drop: function () {
return new Module.ContainerBlockModel({
orientation: 'horizontal',
blocks: [
@ -317,11 +318,11 @@ 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,
drop: function() {
drop: function () {
return new Module.ContainerBlockModel({
orientation: 'horizontal',
blocks: [
@ -335,7 +336,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('container', {
blockModel: Module.ContainerBlockModel,
blockView: Module.ContainerBlockView

View File

@ -2,20 +2,20 @@
* Divider content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'jquery',
'mailpoet'
], function(App, BaseBlock, _, jQuery, MailPoet) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'jquery',
'mailpoet'
], function (App, BaseBlock, _, jQuery, MailPoet) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.DividerBlockModel = base.BlockModel.extend({
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'divider',
styles: {
@ -33,13 +33,13 @@ 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: {
elementSelector: '.mailpoet_content',
resizeHandleSelector: '.mailpoet_resize_handle',
transformationFunction: function(y) { return y / 2; },
transformationFunction: function (y) { return y / 2; },
minLength: 0, // TODO: Move this number to editor configuration
modelField: 'styles.block.padding'
},
@ -47,45 +47,45 @@ define([
ignoreFrom: '.mailpoet_resize_handle'
}
}, base.BlockView.prototype.behaviors),
onDragSubstituteBy: function() { return Module.DividerWidgetView; },
initialize: function() {
onDragSubstituteBy: function () { return Module.DividerWidgetView; },
initialize: function () {
base.BlockView.prototype.initialize.apply(this, arguments);
var that = this;
// Listen for attempts to change all dividers in one go
this._replaceDividerHandler = function(data) { that.model.set(data); that.model.trigger('applyToAll'); };
this._replaceDividerHandler = function (data) { that.model.set(data); that.model.trigger('applyToAll'); };
App.getChannel().on('replaceAllDividers', this._replaceDividerHandler);
this.listenTo(this.model, 'change:src change:styles.block.backgroundColor change:styles.block.borderStyle change:styles.block.borderWidth change:styles.block.borderColor applyToAll', this.render);
this.listenTo(this.model, 'change:styles.block.padding', this.changePadding);
},
templateContext: function() {
templateContext: function () {
return _.extend({
totalHeight: parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px'
totalHeight: parseInt(this.model.get('styles.block.padding'), 10) * 2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px'
}, base.BlockView.prototype.templateContext.apply(this));
},
onRender: function() {
onRender: function () {
this.toolsView = new Module.DividerBlockToolsView({ model: this.model });
this.showChildView('toolsRegion', this.toolsView);
},
onBeforeDestroy: function() {
onBeforeDestroy: function () {
App.getChannel().off('replaceAllDividers', this._replaceDividerHandler);
this.stopListening(this.model);
},
changePadding: function() {
changePadding: function () {
this.$('.mailpoet_content').css('padding-top', this.model.get('styles.block.padding'));
this.$('.mailpoet_content').css('padding-bottom', this.model.get('styles.block.padding'));
this.$('.mailpoet_resize_handle_text').text(parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px');
this.$('.mailpoet_resize_handle_text').text(parseInt(this.model.get('styles.block.padding'), 10) * 2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px');
}
});
Module.DividerBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.DividerBlockSettingsView; }
getSettingsView: function () { return Module.DividerBlockSettingsView; }
});
Module.DividerBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.dividerBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.dividerBlockSettings; },
events: function () {
return {
'click .mailpoet_field_divider_style': 'changeStyle',
@ -99,47 +99,47 @@ define([
'click .mailpoet_done_editing': 'close'
};
},
modelEvents: function() {
modelEvents: function () {
return {
'change:styles.block.borderColor': 'repaintDividerStyleOptions'
};
},
templateContext: function() {
templateContext: function () {
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
availableStyles: App.getAvailableStyles().toJSON(),
renderOptions: this.renderOptions
});
},
changeStyle: function(event) {
changeStyle: function (event) {
var style = jQuery(event.currentTarget).data('style');
this.model.set('styles.block.borderStyle', style);
this.$('.mailpoet_field_divider_style').removeClass('mailpoet_active_divider_style');
this.$('.mailpoet_field_divider_style[data-style="' + style + '"]').addClass('mailpoet_active_divider_style');
},
repaintDividerStyleOptions: function() {
repaintDividerStyleOptions: function () {
this.$('.mailpoet_field_divider_style > div').css('border-top-color', this.model.get('styles.block.borderColor'));
},
applyToAll: function(event) {
applyToAll: function (event) {
App.getChannel().trigger('replaceAllDividers', this.model.toJSON());
},
updateValueAndCall: function(fieldToUpdate, callable, event) {
updateValueAndCall: function (fieldToUpdate, callable, event) {
this.$(fieldToUpdate).val(jQuery(event.target).val());
callable(event);
}
});
Module.DividerWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.dividerInsertion; },
getTemplate: function () { return window.templates.dividerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.DividerBlockModel();
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('divider', {
blockModel: Module.DividerBlockModel,
blockView: Module.DividerBlockView

View File

@ -2,18 +2,19 @@
* Footer content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function(App, BaseBlock, _) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'mailpoet'
], function (App, BaseBlock, _, MailPoet) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.FooterBlockModel = base.BlockModel.extend({
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'footer',
text: '<a href="[link:subscription_unsubscribe_url]">Unsubscribe</a> | <a href="[link:subscription_manage_url]">Manage subscription</a><br /><b>Add your postal address here!</b>',
@ -38,13 +39,13 @@ 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')),
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
TextEditorBehavior: {
configurationFilter: function(originalSettings) {
configurationFilter: function (originalSettings) {
return _.extend({}, originalSettings, {
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle')
@ -52,45 +53,45 @@ define([
}
}
}),
onDragSubstituteBy: function() { return Module.FooterWidgetView; },
onRender: function() {
onDragSubstituteBy: function () { return Module.FooterWidgetView; },
onRender: function () {
this.toolsView = new Module.FooterBlockToolsView({ model: this.model });
this.showChildView('toolsRegion', this.toolsView);
},
onTextEditorChange: function(newContent) {
onTextEditorChange: function (newContent) {
this.model.set('text', newContent);
},
onTextEditorFocus: function() {
onTextEditorFocus: function () {
this.disableDragging();
this.disableShowingTools();
},
onTextEditorBlur: function() {
onTextEditorBlur: function () {
this.enableDragging();
this.enableShowingTools();
}
});
Module.FooterBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.FooterBlockSettingsView; }
getSettingsView: function () { return Module.FooterBlockSettingsView; }
});
Module.FooterBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.footerBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.footerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_footer_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
'change .mailpoet_field_footer_text_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
'change .mailpoet_field_footer_text_size': _.partial(this.changeField, 'styles.text.fontSize'),
'change #mailpoet_field_footer_link_color': _.partial(this.changeColorField, 'styles.link.fontColor'),
'change #mailpoet_field_footer_link_underline': function(event) {
this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
},
'change #mailpoet_field_footer_link_underline': function (event) {
this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
},
'change .mailpoet_field_footer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
'change .mailpoet_field_footer_alignment': _.partial(this.changeField, 'styles.text.textAlign'),
'click .mailpoet_done_editing': 'close'
};
},
templateContext: function() {
templateContext: function () {
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
availableStyles: App.getAvailableStyles().toJSON()
});
@ -98,18 +99,18 @@ define([
});
Module.FooterWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.footerInsertion; },
getTemplate: function () { return window.templates.footerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.FooterBlockModel();
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('footer', {
blockModel: Module.FooterBlockModel,
blockView: Module.FooterBlockView

View File

@ -2,18 +2,19 @@
* Header content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function(App, BaseBlock, _) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'mailpoet'
], function (App, BaseBlock, _, MailPoet) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.HeaderBlockModel = base.BlockModel.extend({
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'header',
text: 'Display problems? <a href="[link:newsletter_view_in_browser_url]">View it in your browser</a>',
@ -38,13 +39,13 @@ 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')),
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
TextEditorBehavior: {
configurationFilter: function(originalSettings) {
configurationFilter: function (originalSettings) {
return _.extend({}, originalSettings, {
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle')
@ -52,37 +53,37 @@ define([
}
}
}),
onDragSubstituteBy: function() { return Module.HeaderWidgetView; },
onRender: function() {
onDragSubstituteBy: function () { return Module.HeaderWidgetView; },
onRender: function () {
this.toolsView = new Module.HeaderBlockToolsView({ model: this.model });
this.showChildView('toolsRegion', this.toolsView);
},
onTextEditorChange: function(newContent) {
onTextEditorChange: function (newContent) {
this.model.set('text', newContent);
},
onTextEditorFocus: function() {
onTextEditorFocus: function () {
this.disableDragging();
this.disableShowingTools();
},
onTextEditorBlur: function() {
onTextEditorBlur: function () {
this.enableDragging();
this.enableShowingTools();
}
});
Module.HeaderBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.HeaderBlockSettingsView; }
getSettingsView: function () { return Module.HeaderBlockSettingsView; }
});
Module.HeaderBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.headerBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.headerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_header_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
'change .mailpoet_field_header_text_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
'change .mailpoet_field_header_text_size': _.partial(this.changeField, 'styles.text.fontSize'),
'change #mailpoet_field_header_link_color': _.partial(this.changeColorField, 'styles.link.fontColor'),
'change #mailpoet_field_header_link_underline': function(event) {
'change #mailpoet_field_header_link_underline': function (event) {
this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
},
'change .mailpoet_field_header_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
@ -90,7 +91,7 @@ define([
'click .mailpoet_done_editing': 'close'
};
},
templateContext: function() {
templateContext: function () {
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
availableStyles: App.getAvailableStyles().toJSON()
});
@ -98,18 +99,18 @@ define([
});
Module.HeaderWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.headerInsertion; },
getTemplate: function () { return window.templates.headerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.HeaderBlockModel();
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('header', {
blockModel: Module.HeaderBlockModel,
blockView: Module.HeaderBlockView

View File

@ -2,20 +2,21 @@
* Image content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'mailpoet'
], function(App, BaseBlock, _, MailPoet) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'mailpoet',
'jquery'
], function (App, BaseBlock, _, MailPoet, jQuery) {
'use strict';
var Module = {},
base = BaseBlock,
ImageWidgetView;
base = BaseBlock,
ImageWidgetView;
Module.ImageBlockModel = base.BlockModel.extend({
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'image',
link: '',
@ -35,34 +36,45 @@ define([
Module.ImageBlockView = base.BlockView.extend({
className: 'mailpoet_block mailpoet_image_block mailpoet_droppable_block',
getTemplate: function() { return templates.imageBlock; },
onDragSubstituteBy: function() { return Module.ImageWidgetView; },
templateContext: function() {
getTemplate: function () { return window.templates.imageBlock; },
onDragSubstituteBy: function () { return Module.ImageWidgetView; },
templateContext: function () {
return _.extend({
imageMissingSrc: App.getConfig().get('urls.imageMissing')
}, 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(),
width = event.pageX - corner.left;
this.view.model.set('width', width + 'px');
}
},
ShowSettingsBehavior: {
ignoreFrom: '.mailpoet_image_resize_handle'
}
}),
onRender: function() {
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'));
}
});
Module.ImageBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.ImageBlockSettingsView; }
getSettingsView: function () { return Module.ImageBlockSettingsView; }
});
Module.ImageBlockSettingsView = base.BlockSettingsView.extend({
onRender: function() {
onRender: function () {
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-full-width'), {
tooltipId: 'tooltip-editor-full-width',
tooltip: MailPoet.I18n.t('helpTooltipDesignerFullWidth')
@ -72,8 +84,8 @@ define([
tooltip: MailPoet.I18n.t('helpTooltipDesignerIdealWidth')
});
},
getTemplate: function() { return templates.imageBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.imageBlockSettings; },
events: function () {
return {
'input .mailpoet_field_image_link': _.partial(this.changeField, 'link'),
'input .mailpoet_field_image_address': 'changeAddress',
@ -81,27 +93,50 @@ 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))
};
},
initialize: function(options) {
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);
if (options.showImageManager) {
this.showMediaManager();
}
},
showMediaManager: function() {
showMediaManager: function () {
if (this._mediaManager) {
this._mediaManager.resetSelections();
this._mediaManager.open();
return;
}
var MediaManager = wp.media.view.MediaFrame.Select.extend({
var MediaManager = window.wp.media.view.MediaFrame.Select.extend({
initialize: function() {
wp.media.view.MediaFrame.prototype.initialize.apply(this, arguments);
initialize: function () {
window.wp.media.view.MediaFrame.prototype.initialize.apply(this, arguments);
_.defaults(this.options, {
multiple: true,
@ -118,22 +153,22 @@ define([
this.$el.addClass('hide-title');
},
resetSelections: function() {
resetSelections: function () {
this.state().get('selection').reset();
},
createQuery: function(options) {
var query = wp.media.query(options);
createQuery: function (options) {
var query = window.wp.media.query(options);
return query;
},
createStates: function() {
createStates: function () {
var options = this.options;
// 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 +190,12 @@ 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() {
bindHandlers: function () {
// from Select
this.on('router:create:browse', this.createRouter, this);
this.on('router:render:browse', this.browseRouter, this);
@ -176,30 +211,30 @@ define([
this.on('updateExcluded', this.browseContent, this);
var handlers = {
content: {
embed: 'embedContent',
'edit-selection': 'editSelectionContent'
},
toolbar: {
'main-insert': 'mainInsertToolbar'
}
};
content: {
embed: 'embedContent',
'edit-selection': 'editSelectionContent'
},
toolbar: {
'main-insert': 'mainInsertToolbar'
}
};
_.each(handlers, function(regionHandlers, region) {
_.each(regionHandlers, function(callback, handler) {
_.each(handlers, function (regionHandlers, region) {
_.each(regionHandlers, function (callback, handler) {
this.on(region + ':render:' + handler, this[callback], this);
}, this);
}, this);
},
uploadContent: function() {
wp.media.view.MediaFrame.Select.prototype.uploadContent.apply(this, arguments);
uploadContent: function () {
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({
embedContent: function () {
var view = new window.wp.media.view.Embed({
controller: this,
model: this.state()
}).render();
@ -208,12 +243,12 @@ define([
view.url.focus();
},
editSelectionContent: function() {
editSelectionContent: function () {
var state = this.state(),
selection = state.get('selection'),
view;
view = new wp.media.view.AttachmentsBrowser({
view = new window.wp.media.view.AttachmentsBrowser({
controller: this,
collection: selection,
selection: selection,
@ -222,14 +257,14 @@ define([
search: false,
dragInfo: true,
AttachmentView: wp.media.view.Attachment.EditSelection
AttachmentView: window.wp.media.view.Attachment.EditSelection
}).render();
view.toolbar.set('backToLibrary', {
text: 'Return to library',
priority: -100,
click: function() {
click: function () {
this.controller.content.mode('browse');
}
});
@ -239,23 +274,23 @@ define([
},
// Toolbars
selectionStatusToolbar: function(view) {
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,
// If the selection is editable, pass the callback to
// switch the content mode.
editable: editable && function() {
editable: editable && function () {
this.controller.content.mode('edit-selection');
}
}).render() );
}).render());
},
mainInsertToolbar: function(view) {
mainInsertToolbar: function (view) {
var controller = this;
this.selectionStatusToolbar(view);
@ -266,7 +301,7 @@ define([
text: 'Select Image',
requires: { selection: true },
click: function() {
click: function () {
var state = controller.state(),
selection = state.get('selection');
@ -276,9 +311,9 @@ define([
});
},
mainEmbedToolbar: function(toolbar) {
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'
});
@ -301,12 +336,12 @@ define([
}
}),
that = this;
this._mediaManager = theFrame;
this._mediaManager = theFrame;
this._mediaManager.on('insert', function() {
this._mediaManager.on('insert', function () {
// Append media manager image selections to Images tab
var selection = theFrame.state().get('selection');
selection.each(function(attachment) {
selection.each(function (attachment) {
var sizes = attachment.get('sizes'),
// Following advice from Becs, the target width should
// be a double of one column width to render well on
@ -319,13 +354,13 @@ define([
// Pick the width that is closest to target width
increasingByWidthDifference = _.sortBy(
_.keys(sizes),
function(size) { return Math.abs(targetImageWidth - sizes[size].width); }
function (size) { return Math.abs(targetImageWidth - sizes[size].width); }
),
bestWidth = sizes[_.first(increasingByWidthDifference)].width,
imagesOfBestWidth = _.filter(_.values(sizes), function(size) { return size.width === bestWidth; }),
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; });
mainSize = _.max(imagesOfBestWidth, function (size) { return size.height; });
that.model.set({
height: mainSize.height + 'px',
@ -340,11 +375,11 @@ define([
this._mediaManager.open();
},
changeAddress: function(event) {
changeAddress: function (event) {
var src = jQuery(event.target).val();
var image = new Image();
image.onload = function() {
image.onload = function () {
this.model.set({
src: src,
width: image.naturalWidth + 'px',
@ -354,7 +389,7 @@ define([
image.src = src;
},
onBeforeDestroy: function() {
onBeforeDestroy: function () {
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
if (typeof this._mediaManager === 'object') {
this._mediaManager.remove();
@ -363,14 +398,14 @@ define([
});
ImageWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.imageInsertion; },
getTemplate: function () { return window.templates.imageInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.ImageBlockModel();
},
onDrop: function(options) {
onDrop: function (options) {
options.droppedView.triggerMethod('showSettings', { showImageManager: true });
}
}
@ -378,7 +413,7 @@ define([
});
Module.ImageWidgetView = ImageWidgetView;
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('image', {
blockModel: Module.ImageBlockModel,
blockView: Module.ImageBlockView

View File

@ -11,40 +11,40 @@
* block settings view.
*/
define([
'backbone',
'backbone.marionette',
'backbone.radio',
'underscore',
'jquery',
'mailpoet',
'newsletter_editor/App',
'newsletter_editor/components/communication',
'newsletter_editor/blocks/base',
'newsletter_editor/blocks/button',
'newsletter_editor/blocks/divider',
'select2'
], function(
Backbone,
Marionette,
Radio,
_,
jQuery,
MailPoet,
App,
CommunicationComponent,
BaseBlock,
ButtonBlock,
DividerBlock
'backbone',
'backbone.marionette',
'backbone.radio',
'underscore',
'jquery',
'mailpoet',
'newsletter_editor/App',
'newsletter_editor/components/communication',
'newsletter_editor/blocks/base',
'newsletter_editor/blocks/button',
'newsletter_editor/blocks/divider',
'select2'
], function (
Backbone,
Marionette,
Radio,
_,
jQuery,
MailPoet,
App,
CommunicationComponent,
BaseBlock,
ButtonBlock,
DividerBlock
) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.PostsBlockModel = base.BlockModel.extend({
stale: ['_selectedPosts', '_availablePosts', '_transformedPosts'],
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'posts',
amount: '10',
@ -60,7 +60,7 @@ define([
titleIsLink: false, // false|true
imageFullWidth: false, // true|false
featuredImagePosition: 'belowTitle', // 'aboveTitle'|'belowTitle'|'none'
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
// imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
showAuthor: 'no', // 'no'|'aboveText'|'belowText'
authorPrecededBy: 'Author:',
showCategories: 'no', // 'no'|'aboveText'|'belowText'
@ -79,7 +79,7 @@ define([
_transformedPosts: new (App.getBlockTypeModel('container'))()
}, App.getConfig().get('blockDefaults.posts'));
},
relations: function() {
relations: function () {
return {
readMoreButton: App.getBlockTypeModel('button'),
divider: App.getBlockTypeModel('divider'),
@ -88,7 +88,7 @@ define([
_transformedPosts: App.getBlockTypeModel('container')
};
},
initialize: function() {
initialize: function () {
var that = this,
POST_REFRESH_DELAY_MS = 500,
refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS),
@ -108,39 +108,39 @@ define([
this.on('insertSelectedPosts', this._insertSelectedPosts, this);
},
fetchAvailablePosts: function() {
fetchAvailablePosts: function () {
var that = this;
this.set('offset', 0);
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
CommunicationComponent.getPosts(this.toJSON()).done(function (posts) {
that.get('_availablePosts').reset(posts);
that.get('_selectedPosts').reset(); // Empty out the collection
that.trigger('change:_availablePosts');
}).fail(function() {
}).fail(function () {
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
});
},
_loadMorePosts: function() {
_loadMorePosts: function () {
var that = this,
postCount = this.get('_availablePosts').length,
nextOffset = this.get('offset') + Number(this.get('amount'));
if(postCount === 0 || postCount < nextOffset) {
if (postCount === 0 || postCount < nextOffset) {
// No more posts to load
return false;
}
this.set('offset', nextOffset);
this.trigger('loadingMorePosts');
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
CommunicationComponent.getPosts(this.toJSON()).done(function (posts) {
that.get('_availablePosts').add(posts);
that.trigger('change:_availablePosts');
}).fail(function() {
}).fail(function () {
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchAvailablePosts'));
}).always(function() {
}).always(function () {
that.trigger('morePostsLoaded');
});
},
_refreshTransformedPosts: function() {
_refreshTransformedPosts: function () {
var that = this,
data = this.toJSON();
@ -151,13 +151,13 @@ define([
return;
}
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
}).fail(function() {
CommunicationComponent.getTransformedPosts(data).done(function (posts) {
that.get('_transformedPosts').get('blocks').reset(posts, { parse: true });
}).fail(function () {
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
});
},
_insertSelectedPosts: function() {
_insertSelectedPosts: function () {
var that = this,
data = this.toJSON(),
index = this.collection.indexOf(this),
@ -167,9 +167,9 @@ define([
if (data.posts.length === 0) return;
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
CommunicationComponent.getTransformedPosts(data).done(function (posts) {
collection.add(posts, { at: index });
}).fail(function() {
}).fail(function () {
MailPoet.Notice.error(MailPoet.I18n.t('failedToFetchRenderedPosts'));
});
}
@ -177,19 +177,19 @@ 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'
}, base.BlockView.prototype.regions),
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
initialize: function() {
onDragSubstituteBy: function () { return Module.PostsWidgetView; },
initialize: function () {
base.BlockView.prototype.initialize.apply(this, arguments);
this.toolsView = new Module.PostsBlockToolsView({ model: this.model });
this.model.reply('blockView', this.notifyAboutSelf, this);
},
onRender: function() {
onRender: function () {
if (!this.getRegion('toolsRegion').hasView()) {
this.showChildView('toolsRegion', this.toolsView);
}
@ -203,20 +203,20 @@ define([
};
this.showChildView('postsRegion', new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions }));
},
notifyAboutSelf: function() {
notifyAboutSelf: function () {
return this;
},
onBeforeDestroy: function() {
onBeforeDestroy: function () {
this.model.stopReplying('blockView', this.notifyAboutSelf, this);
}
});
Module.PostsBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.PostsBlockSettingsView; }
getSettingsView: function () { return Module.PostsBlockSettingsView; }
});
Module.PostsBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.postsBlockSettings; },
getTemplate: function () { return window.templates.postsBlockSettings; },
regions: {
selectionRegion: '.mailpoet_settings_posts_selection',
displayOptionsRegion: '.mailpoet_settings_posts_display_options'
@ -226,17 +226,17 @@ define([
'click .mailpoet_settings_posts_show_post_selection': 'switchToPostSelection',
'click .mailpoet_settings_posts_insert_selected': 'insertPosts'
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON()
};
},
initialize: function() {
initialize: function () {
this.model.trigger('startEditing');
this.selectionView = new PostSelectionSettingsView({ model: this.model });
this.displayOptionsView = new PostsDisplayOptionsSettingsView({ model: this.model });
},
onRender: function() {
onRender: function () {
var that = this,
blockView = this.model.request('blockView');
@ -248,7 +248,7 @@ define([
template: '',
position: 'right',
width: App.getConfig().get('sidepanelWidth'),
onCancel: function() {
onCancel: function () {
// Self destroy the block if the user closes settings modal
that.model.destroy();
}
@ -258,7 +258,7 @@ define([
this.selectionView.triggerMethod('attach');
this.displayOptionsView.triggerMethod('attach');
},
switchToDisplayOptions: function() {
switchToDisplayOptions: function () {
// Switch content view
this.$('.mailpoet_settings_posts_selection').addClass('mailpoet_closed');
this.$('.mailpoet_settings_posts_display_options').removeClass('mailpoet_closed');
@ -267,7 +267,7 @@ define([
this.$('.mailpoet_settings_posts_show_display_options').addClass('mailpoet_hidden');
this.$('.mailpoet_settings_posts_show_post_selection').removeClass('mailpoet_hidden');
},
switchToPostSelection: function() {
switchToPostSelection: function () {
// Switch content view
this.$('.mailpoet_settings_posts_display_options').addClass('mailpoet_closed');
this.$('.mailpoet_settings_posts_selection').removeClass('mailpoet_closed');
@ -276,7 +276,7 @@ define([
this.$('.mailpoet_settings_posts_show_post_selection').addClass('mailpoet_hidden');
this.$('.mailpoet_settings_posts_show_display_options').removeClass('mailpoet_hidden');
},
insertPosts: function() {
insertPosts: function () {
this.model.trigger('insertSelectedPosts');
this.model.destroy();
this.close();
@ -285,22 +285,22 @@ define([
var PostsSelectionCollectionView = Marionette.CollectionView.extend({
className: 'mailpoet_post_scroll_container',
childView: function() { return SinglePostSelectionSettingsView; },
emptyView: function() { return EmptyPostSelectionSettingsView; },
childViewOptions: function() {
childView: function () { return SinglePostSelectionSettingsView; },
emptyView: function () { return EmptyPostSelectionSettingsView; },
childViewOptions: function () {
return {
blockModel: this.blockModel
};
},
initialize: function(options) {
initialize: function (options) {
this.blockModel = options.blockModel;
},
events: {
scroll: 'onPostsScroll'
},
onPostsScroll: function(event) {
onPostsScroll: function (event) {
var $postsBox = jQuery(event.target);
if($postsBox.scrollTop() + $postsBox.innerHeight() >= $postsBox[0].scrollHeight){
if ($postsBox.scrollTop() + $postsBox.innerHeight() >= $postsBox[0].scrollHeight) {
// Load more posts if scrolled to bottom
this.blockModel.trigger('loadMorePosts');
}
@ -308,11 +308,11 @@ define([
});
var PostSelectionSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.postSelectionPostsBlockSettings; },
getTemplate: function () { return window.templates.postSelectionPostsBlockSettings; },
regions: {
posts: '.mailpoet_post_selection_container'
},
events: function() {
events: function () {
return {
'change .mailpoet_settings_posts_content_type': _.partial(this.changeField, 'contentType'),
'change .mailpoet_posts_post_status': _.partial(this.changeField, 'postStatus'),
@ -320,20 +320,20 @@ define([
};
},
modelEvents: {
'change:offset': function(model, value) {
'change:offset': function (model, value) {
// Scroll posts view to top if settings are changed
if (value === 0) {
this.$('.mailpoet_post_scroll_container').scrollTop(0);
}
},
loadingMorePosts: function() {
loadingMorePosts: function () {
this.$('.mailpoet_post_selection_loading').css('visibility', 'visible');
},
morePostsLoaded: function() {
morePostsLoaded: function () {
this.$('.mailpoet_post_selection_loading').css('visibility', 'hidden');
}
},
onRender: function() {
onRender: function () {
// Dynamically update available post types
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
var postsView = new PostsSelectionCollectionView({
@ -343,7 +343,7 @@ define([
this.showChildView('posts', postsView);
},
onAttach: function() {
onAttach: function () {
var that = this;
this.$('.mailpoet_posts_categories_and_tags').select2({
@ -356,17 +356,17 @@ define([
term: params.term
};
},
transport: function(options, success, failure) {
transport: function (options, success, failure) {
var taxonomies;
var promise = CommunicationComponent.getTaxonomies(
that.model.get('contentType')
).then(function(tax) {
).then(function (tax) {
taxonomies = tax;
// Fetch available terms based on the list of taxonomies already fetched
var promise = CommunicationComponent.getTerms({
search: options.data.term,
taxonomies: _.keys(taxonomies)
}).then(function(terms) {
}).then(function (terms) {
return {
taxonomies: taxonomies,
terms: terms
@ -379,12 +379,12 @@ define([
promise.fail(failure);
return promise;
},
processResults: function(data) {
processResults: function (data) {
// Transform taxonomies and terms into select2 compatible format
return {
results: _.map(
data.terms,
function(item) {
function (item) {
return _.defaults({
text: data.taxonomies[item.taxonomy].labels.singular_name + ': ' + item.name,
id: item.term_id
@ -395,29 +395,29 @@ define([
}
}
}).on({
'select2:select': function(event) {
'select2:select': function (event) {
var terms = that.model.get('terms');
terms.add(event.params.data);
// Reset whole model in order for change events to propagate properly
that.model.set('terms', terms.toJSON());
},
'select2:unselect': function(event) {
'select2:unselect': function (event) {
var terms = that.model.get('terms');
terms.remove(event.params.data);
// Reset whole model in order for change events to propagate properly
that.model.set('terms', terms.toJSON());
}
}).trigger( 'change' );
}).trigger('change');
},
changeField: function(field, event) {
changeField: function (field, event) {
this.model.set(field, jQuery(event.target).val());
},
_updateContentTypes: function(postTypes) {
_updateContentTypes: function (postTypes) {
var select = this.$('.mailpoet_settings_posts_content_type'),
selectedValue = this.model.get('contentType');
selectedValue = this.model.get('contentType');
select.find('option').remove();
_.each(postTypes, function(type) {
_.each(postTypes, function (type) {
select.append(jQuery('<option>', {
value: type.name,
text: type.label
@ -428,26 +428,26 @@ define([
});
var EmptyPostSelectionSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.emptyPostPostsBlockSettings; }
getTemplate: function () { return window.templates.emptyPostPostsBlockSettings; }
});
var SinglePostSelectionSettingsView = Marionette.View.extend({
getTemplate: function() { return templates.singlePostPostsBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.singlePostPostsBlockSettings; },
events: function () {
return {
'change .mailpoet_select_post_checkbox': 'postSelectionChange'
};
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON(),
index: this._index
};
},
initialize: function(options) {
initialize: function (options) {
this.blockModel = options.blockModel;
},
postSelectionChange: function(event) {
postSelectionChange: function (event) {
var checkBox = jQuery(event.target),
selectedPostsCollection = this.blockModel.get('_selectedPosts');
if (checkBox.prop('checked')) {
@ -459,8 +459,8 @@ define([
});
var PostsDisplayOptionsSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.displayOptionsPostsBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.displayOptionsPostsBlockSettings; },
events: function () {
return {
'click .mailpoet_posts_select_button': 'showButtonSettings',
'click .mailpoet_posts_select_divider': 'showDividerSettings',
@ -483,12 +483,12 @@ define([
'change .mailpoet_posts_sort_by': _.partial(this.changeField, 'sortBy')
};
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON()
};
},
showButtonSettings: function(event) {
showButtonSettings: function (event) {
var buttonModule = ButtonBlock;
(new buttonModule.ButtonBlockSettingsView({
model: this.model.get('readMoreButton'),
@ -499,7 +499,7 @@ define([
}
})).render();
},
showDividerSettings: function(event) {
showDividerSettings: function (event) {
var dividerModule = DividerBlock;
(new dividerModule.DividerBlockSettingsView({
model: this.model.get('divider'),
@ -509,7 +509,7 @@ define([
}
})).render();
},
changeReadMoreType: function(event) {
changeReadMoreType: function (event) {
var value = jQuery(event.target).val();
if (value == 'link') {
this.$('.mailpoet_posts_read_more_text').removeClass('mailpoet_hidden');
@ -520,7 +520,7 @@ define([
}
this.changeField('readMoreType', event);
},
changeDisplayType: function(event) {
changeDisplayType: function (event) {
var value = jQuery(event.target).val();
if (value == 'titleOnly') {
this.$('.mailpoet_posts_title_as_list').removeClass('mailpoet_hidden');
@ -547,7 +547,7 @@ define([
this.changeField('displayType', event);
},
changeTitleFormat: function(event) {
changeTitleFormat: function (event) {
var value = jQuery(event.target).val();
if (value == 'ul') {
this.$('.mailpoet_posts_non_title_list_options').addClass('mailpoet_hidden');
@ -564,18 +564,18 @@ define([
});
Module.PostsWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.postsInsertion; },
getTemplate: function () { return window.templates.postsInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.PostsBlockModel({}, { parse: true });
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('posts', {
blockModel: Module.PostsBlockModel,
blockView: Module.PostsBlockView

View File

@ -2,26 +2,26 @@
* Social icons content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'backbone',
'backbone.marionette',
'backbone.supermodel',
'underscore',
'jquery'
], function(App, BaseBlock, Backbone, Marionette, SuperModel, _, jQuery) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'backbone',
'backbone.marionette',
'backbone.supermodel',
'underscore',
'jquery'
], function (App, BaseBlock, Backbone, Marionette, SuperModel, _, jQuery) {
'use strict';
var Module = {},
base = BaseBlock,
SocialBlockSettingsIconSelectorView,
SocialBlockSettingsIconView,
SocialBlockSettingsIconCollectionView,
SocialBlockSettingsStylesView;
base = BaseBlock,
SocialBlockSettingsIconSelectorView,
SocialBlockSettingsIconView,
SocialBlockSettingsIconCollectionView,
SocialBlockSettingsStylesView;
Module.SocialIconModel = SuperModel.extend({
defaults: function() {
defaults: function () {
var defaultValues = App.getConfig().get('socialIcons.custom');
return {
type: 'socialIcon',
@ -33,10 +33,10 @@ define([
text: defaultValues.get('title')
};
},
initialize: function(options) {
initialize: function (options) {
var that = this;
// Make model swap to default values for that type when iconType changes
this.on('change:iconType', function() {
this.on('change:iconType', function () {
var defaultValues = App.getConfig().get('socialIcons').get(that.get('iconType')),
iconSet = that.collection.iconBlockModel.getIconSet();
this.set({
@ -45,7 +45,7 @@ define([
text: defaultValues.get('title')
});
}, this);
this.on('change', function() { App.getChannel().trigger('autoSave'); });
this.on('change', function () { App.getChannel().trigger('autoSave'); });
}
});
@ -55,7 +55,7 @@ define([
Module.SocialBlockModel = base.BlockModel.extend({
name: 'iconBlockModel',
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'social',
iconSet: 'default',
@ -65,31 +65,31 @@ define([
relations: {
icons: Module.SocialIconCollectionModel
},
initialize: function() {
initialize: function () {
this.get('icons').on('add remove change', this._iconsChanged, this);
this.on('change:iconSet', this.changeIconSet, this);
},
getIconSet: function() {
getIconSet: function () {
return App.getAvailableStyles().get('socialIconSets').get(this.get('iconSet'));
},
changeIconSet: function() {
changeIconSet: function () {
var iconSet = this.getIconSet();
_.each(this.get('icons').models, function(model) {
_.each(this.get('icons').models, function (model) {
model.set('image', iconSet.get(model.get('iconType')));
});
},
_iconsChanged: function() {
App.getChannel().trigger('autoSave');
_iconsChanged: function () {
App.getChannel().trigger('autoSave');
}
});
var SocialIconView = Marionette.View.extend({
tagName: 'span',
getTemplate: function() { return templates.socialIconBlock; },
getTemplate: function () { return window.templates.socialIconBlock; },
modelEvents: {
change: 'render'
},
templateContext: function() {
templateContext: function () {
var allIconSets = App.getAvailableStyles().get('socialIconSets');
return {
model: this.model.toJSON(),
@ -105,7 +105,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'
}),
@ -115,39 +115,39 @@ define([
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
ShowSettingsBehavior: {}
}),
onDragSubstituteBy: function() { return Module.SocialWidgetView; },
onRender: function() {
onDragSubstituteBy: function () { return Module.SocialWidgetView; },
onRender: function () {
this.toolsView = new Module.SocialBlockToolsView({ model: this.model });
this.showChildView('toolsRegion', this.toolsView);
this.showChildView('icons', new Module.SocialIconCollectionView({
collection: this.model.get('icons')
}))
}));
}
});
Module.SocialBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.SocialBlockSettingsView; }
getSettingsView: function () { return Module.SocialBlockSettingsView; }
});
// Sidebar view container
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'
},
events: function() {
events: function () {
return {
'click .mailpoet_done_editing': 'close'
};
},
initialize: function() {
initialize: function () {
base.BlockSettingsView.prototype.initialize.apply(this, arguments);
this._iconSelectorView = new SocialBlockSettingsIconSelectorView({ model: this.model });
this._stylesView = new SocialBlockSettingsStylesView({ model: this.model });
},
onRender: function() {
onRender: function () {
this.showChildView('iconRegion', this._iconSelectorView);
this.showChildView('stylesRegion', this._stylesView);
}
@ -155,8 +155,8 @@ define([
// Single icon settings view, used by the selector view
SocialBlockSettingsIconView = Marionette.View.extend({
getTemplate: function() { return templates.socialSettingsIcon; },
events: function() {
getTemplate: function () { return window.templates.socialSettingsIcon; },
events: function () {
return {
'click .mailpoet_delete_block': 'deleteIcon',
'change .mailpoet_social_icon_field_type': _.partial(this.changeField, 'iconType'),
@ -167,17 +167,17 @@ define([
},
modelEvents: {
'change:iconType': 'render',
'change:image': function() {
'change:image': function () {
this.$('.mailpoet_social_icon_image').attr('src', this.model.get('image'));
},
'change:text': function() {
'change:text': function () {
this.$('.mailpoet_social_icon_image').attr('alt', this.model.get('text'));
}
},
templateContext: function() {
templateContext: function () {
var icons = App.getConfig().get('socialIcons'),
// Construct icon type list of format [{iconType: 'type', title: 'Title'}, ...]
availableIconTypes = _.map(_.keys(icons.attributes), function(key) { return { iconType: key, title: icons.get(key).get('title') }; }),
availableIconTypes = _.map(_.keys(icons.attributes), function (key) { return { iconType: key, title: icons.get(key).get('title') }; }),
allIconSets = App.getAvailableStyles().get('socialIconSets');
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
iconTypes: availableIconTypes,
@ -185,17 +185,17 @@ define([
allIconSets: allIconSets.toJSON()
});
},
deleteIcon: function() {
deleteIcon: function () {
this.model.destroy();
},
changeLink: function(event) {
changeLink: function (event) {
if (this.model.get('iconType') === 'email') {
this.model.set('link', 'mailto:' + jQuery(event.target).val());
} else {
return this.changeField('link', event);
}
},
changeField: function(field, event) {
changeField: function (field, event) {
this.model.set(field, jQuery(event.target).val());
}
});
@ -212,7 +212,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'
},
@ -222,11 +222,11 @@ define([
modelEvents: {
'change:iconSet': 'render'
},
addSocialIcon: function() {
addSocialIcon: function () {
// Add a social icon with default values
this.model.get('icons').add({});
},
onRender: function() {
onRender: function () {
this.showChildView('icons', new SocialBlockSettingsIconCollectionView({
collection: this.model.get('icons')
}));
@ -235,17 +235,17 @@ define([
});
SocialBlockSettingsStylesView = Marionette.View.extend({
getTemplate: function() { return templates.socialSettingsStyles; },
getTemplate: function () { return window.templates.socialSettingsStyles; },
modelEvents: {
change: 'render'
},
events: {
'click .mailpoet_social_icon_set': 'changeSocialIconSet'
},
initialize: function() {
initialize: function () {
this.listenTo(this.model.get('icons'), 'add remove change', this.render);
},
templateContext: function() {
templateContext: function () {
var allIconSets = App.getAvailableStyles().get('socialIconSets');
return {
activeSet: this.model.get('iconSet'),
@ -254,20 +254,20 @@ define([
availableSocialIcons: this.model.get('icons').pluck('iconType')
};
},
changeSocialIconSet: function(event) {
changeSocialIconSet: function (event) {
this.model.set('iconSet', jQuery(event.currentTarget).data('setname'));
},
onBeforeDestroy: function() {
onBeforeDestroy: function () {
this.model.get('icons').off('add remove', this.render, this);
}
});
Module.SocialWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.socialInsertion; },
getTemplate: function () { return window.templates.socialInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.SocialBlockModel({
type: 'social',
iconSet: 'default',
@ -297,7 +297,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('social', {
blockModel: Module.SocialBlockModel,
blockView: Module.SocialBlockView

View File

@ -2,18 +2,18 @@
* Spacer content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function(App, BaseBlock, _) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function (App, BaseBlock, _) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.SpacerBlockModel = base.BlockModel.extend({
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'spacer',
styles: {
@ -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',
@ -41,33 +41,33 @@ define([
}
}, base.BlockView.prototype.behaviors),
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
onDragSubstituteBy: function() { return Module.SpacerWidgetView; },
initialize: function() {
onDragSubstituteBy: function () { return Module.SpacerWidgetView; },
initialize: function () {
base.BlockView.prototype.initialize.apply(this, arguments);
this.listenTo(this.model, 'change:styles.block.backgroundColor', this.render);
this.listenTo(this.model, 'change:styles.block.height', this.changeHeight);
},
onRender: function() {
onRender: function () {
this.toolsView = new Module.SpacerBlockToolsView({ model: this.model });
this.showChildView('toolsRegion', this.toolsView);
},
changeHeight: function() {
changeHeight: function () {
this.$('.mailpoet_spacer').css('height', this.model.get('styles.block.height'));
this.$('.mailpoet_resize_handle_text').text(this.model.get('styles.block.height'));
},
onBeforeDestroy: function() {
onBeforeDestroy: function () {
this.stopListening(this.model);
}
});
Module.SpacerBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.SpacerBlockSettingsView; }
getSettingsView: function () { return Module.SpacerBlockSettingsView; }
});
Module.SpacerBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.spacerBlockSettings; },
events: function() {
getTemplate: function () { return window.templates.spacerBlockSettings; },
events: function () {
return {
'change .mailpoet_field_spacer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
'click .mailpoet_done_editing': 'close'
@ -76,18 +76,18 @@ define([
});
Module.SpacerWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.spacerInsertion; },
getTemplate: function () { return window.templates.spacerInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.SpacerBlockModel();
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('spacer', {
blockModel: Module.SpacerBlockModel,
blockView: Module.SpacerBlockView

View File

@ -2,18 +2,19 @@
* Text content block
*/
define([
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore'
], function(App, BaseBlock, _) {
'newsletter_editor/App',
'newsletter_editor/blocks/base',
'underscore',
'mailpoet'
], function (App, BaseBlock, _, MailPoet) {
'use strict';
var Module = {},
base = BaseBlock;
base = BaseBlock;
Module.TextBlockModel = base.BlockModel.extend({
defaults: function() {
defaults: function () {
return this._getDefaults({
type: 'text',
text: 'Edit this to insert text'
@ -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: {
@ -33,7 +34,7 @@ define([
invalidElements: 'script',
blockFormats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
plugins: 'link lists code textcolor colorpicker mailpoet_shortcodes paste',
configurationFilter: function(originalSettings) {
configurationFilter: function (originalSettings) {
return _.extend({}, originalSettings, {
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle')
@ -41,7 +42,7 @@ define([
}
}
}),
initialize: function(options) {
initialize: function (options) {
base.BlockView.prototype.initialize.apply(this, arguments);
this.renderOptions = _.defaults(options.renderOptions || {}, {
@ -50,8 +51,8 @@ define([
this.disableTextEditor = this.renderOptions.disableTextEditor;
},
onDragSubstituteBy: function() { return Module.TextWidgetView; },
onRender: function() {
onDragSubstituteBy: function () { return Module.TextWidgetView; },
onRender: function () {
this.toolsView = new Module.TextBlockToolsView({
model: this.model,
tools: {
@ -60,40 +61,40 @@ define([
});
this.showChildView('toolsRegion', this.toolsView);
},
onTextEditorChange: function(newContent) {
onTextEditorChange: function (newContent) {
this.model.set('text', newContent);
},
onTextEditorFocus: function() {
onTextEditorFocus: function () {
this.disableDragging();
this.disableShowingTools();
},
onTextEditorBlur: function() {
onTextEditorBlur: function () {
this.enableDragging();
this.enableShowingTools();
}
});
Module.TextBlockToolsView = base.BlockToolsView.extend({
getSettingsView: function() { return Module.TextBlockSettingsView; }
getSettingsView: function () { return Module.TextBlockSettingsView; }
});
Module.TextBlockSettingsView = base.BlockSettingsView.extend({
getTemplate: function() { return templates.textBlockSettings; }
getTemplate: function () { return window.templates.textBlockSettings; }
});
Module.TextWidgetView = base.WidgetView.extend({
getTemplate: function() { return templates.textInsertion; },
getTemplate: function () { return window.templates.textInsertion; },
behaviors: {
DraggableBehavior: {
cloneOriginal: true,
drop: function() {
drop: function () {
return new Module.TextBlockModel();
}
}
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
App.registerBlockType('text', {
blockModel: Module.TextBlockModel,
blockView: Module.TextBlockView

View File

@ -6,9 +6,9 @@
* Courtesy of https://gist.github.com/jmeas/7992474cdb1c5672d88b
*/
(function(root, factory) {
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['backbone.marionette', 'backbone.radio', 'underscore'], function(Marionette, Radio, _) {
define(['backbone.marionette', 'backbone.radio', 'underscore'], function (Marionette, Radio, _) {
return factory(Marionette, Radio, _);
});
}
@ -21,8 +21,9 @@
else {
factory(root.Backbone.Marionette, root.Backbone.Radio, root._);
}
}(this, function(Marionette, Radio, _) {
}(this, function (Marionette, Radio, _) {
'use strict';
var MarionetteApplication = Marionette.Application;
MarionetteApplication.prototype._initChannel = function () {
this.channelName = _.result(this, 'channelName') || 'global';

View File

@ -1,13 +1,13 @@
define([
'newsletter_editor/App',
'underscore',
'mailpoet',
'ajax'
], function(App, _, MailPoet) {
'newsletter_editor/App',
'underscore',
'mailpoet',
'ajax'
], function (App, _, MailPoet) {
var Module = {};
Module._query = function(args) {
Module._query = function (args) {
return MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'automatedLatestContent',
@ -17,70 +17,70 @@ define([
};
Module._cachedQuery = _.memoize(Module._query, JSON.stringify);
Module.getNewsletter = function(options) {
Module.getNewsletter = function (options) {
return Module._query({
action: 'get',
options: options
});
};
Module.getPostTypes = function() {
Module.getPostTypes = function () {
return Module._cachedQuery({
action: 'getPostTypes',
options: {}
}).then(function(response) {
}).then(function (response) {
return _.values(response.data);
});
};
Module.getTaxonomies = function(postType) {
Module.getTaxonomies = function (postType) {
return Module._cachedQuery({
action: 'getTaxonomies',
options: {
postType: postType
}
}).then(function(response) {
}).then(function (response) {
return response.data;
});
};
Module.getTerms = function(options) {
Module.getTerms = function (options) {
return Module._cachedQuery({
action: 'getTerms',
options: options
}).then(function(response) {
}).then(function (response) {
return response.data;
});
};
Module.getPosts = function(options) {
Module.getPosts = function (options) {
return Module._cachedQuery({
action: 'getPosts',
options: options
}).then(function(response) {
}).then(function (response) {
return response.data;
});
};
Module.getTransformedPosts = function(options) {
Module.getTransformedPosts = function (options) {
return Module._cachedQuery({
action: 'getTransformedPosts',
options: options
}).then(function(response) {
}).then(function (response) {
return response.data;
});
};
Module.getBulkTransformedPosts = function(options) {
Module.getBulkTransformedPosts = function (options) {
return Module._query({
action: 'getBulkTransformedPosts',
options: options
}).then(function(response) {
}).then(function (response) {
return response.data;
});
};
Module.saveNewsletter = function(options) {
Module.saveNewsletter = function (options) {
return MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
@ -89,7 +89,7 @@ define([
});
};
Module.previewNewsletter = function(options) {
Module.previewNewsletter = function (options) {
return MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
@ -98,7 +98,7 @@ define([
});
};
App.on('start', function(App, options) {
App.on('start', function (App, options) {
// Prefetch post types
Module.getPostTypes();
});

View File

@ -1,7 +1,7 @@
define([
'newsletter_editor/App',
'backbone.supermodel'
], function(App, SuperModel) {
'newsletter_editor/App',
'backbone.supermodel'
], function (App, SuperModel) {
var Module = {};
@ -18,13 +18,13 @@ define([
// Global and available styles for access in blocks and their settings
Module._config = {};
Module.getConfig = function() { return Module._config; };
Module.setConfig = function(options) {
Module.getConfig = function () { return Module._config; };
Module.setConfig = function (options) {
Module._config = new Module.ConfigModel(options, { parse: true });
return Module._config;
};
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
var Application = App;
// Expose config methods globally
Application.getConfig = Module.getConfig;

View File

@ -1,9 +1,9 @@
define([
'newsletter_editor/App',
'backbone.supermodel',
'underscore',
'mailpoet'
], function(App, SuperModel, _, MailPoet) {
'newsletter_editor/App',
'backbone.supermodel',
'underscore',
'mailpoet'
], function (App, SuperModel, _, MailPoet) {
'use strict';
var Module = {};
@ -13,12 +13,12 @@ define([
// handled by other components.
Module.NewsletterModel = SuperModel.extend({
whitelisted: ['id', 'subject', 'preheader'],
initialize: function(options) {
this.on('change', function() {
App.getChannel().trigger('autoSave');
initialize: function (options) {
this.on('change', function () {
App.getChannel().trigger('autoSave');
});
},
toJSON: function() {
toJSON: function () {
// Use only whitelisted properties to ensure properties editor
// doesn't control don't change.
return _.pick(SuperModel.prototype.toJSON.call(this), this.whitelisted);
@ -27,17 +27,17 @@ define([
// Content block view and model handlers for different content types
Module._blockTypes = {};
Module.registerBlockType = function(type, data) {
Module.registerBlockType = function (type, data) {
Module._blockTypes[type] = data;
};
Module.getBlockTypeModel = function(type) {
Module.getBlockTypeModel = function (type) {
if (type in Module._blockTypes) {
return Module._blockTypes[type].blockModel;
} else {
throw 'Block type not supported: ' + type;
}
};
Module.getBlockTypeView = function(type) {
Module.getBlockTypeView = function (type) {
if (type in Module._blockTypes) {
return Module._blockTypes[type].blockView;
} else {
@ -45,29 +45,29 @@ define([
}
};
Module.getBody = function() {
Module.getBody = function () {
return {
content: App._contentContainer.toJSON(),
globalStyles: App.getGlobalStyles().toJSON()
};
};
Module.toJSON = function() {
Module.toJSON = function () {
return _.extend({
body: Module.getBody()
}, App.getNewsletter().toJSON());
};
Module.getNewsletter = function() {
return Module.newsletter;
Module.getNewsletter = function () {
return Module.newsletter;
};
Module.findModels = function(predicate) {
Module.findModels = function (predicate) {
var blocks = App._contentContainer.getChildren();
return _.filter(blocks, predicate);
};
App.on('before:start', function(Application, options) {
App.on('before:start', function (Application, options) {
var App = Application;
// Expose block methods globally
App.registerBlockType = Module.registerBlockType;
@ -81,7 +81,7 @@ define([
Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body']));
});
App.on('start', function(Application, options) {
App.on('start', function (Application, options) {
var App = Application;
var body = options.newsletter.body;
var content = (_.has(body, 'content')) ? body.content : {};
@ -93,7 +93,7 @@ define([
);
}
App._contentContainer = new (App.getBlockTypeModel('container'))(content, {parse: true});
App._contentContainer = new (App.getBlockTypeModel('container'))(content, { parse: true });
App._contentContainerView = new (App.getBlockTypeView('container'))({
model: App._contentContainer,
renderOptions: { depth: 0 }

View File

@ -1,34 +1,35 @@
define([
'newsletter_editor/App',
'backbone',
'backbone.marionette',
'underscore',
'jquery'
], function(App, Backbone, Marionette, _, jQuery) {
'newsletter_editor/App',
'backbone',
'backbone.marionette',
'underscore',
'jquery',
'mailpoet'
], function (App, Backbone, Marionette, _, jQuery, MailPoet) {
'use strict';
var Module = {};
Module.HeadingView = Marionette.View.extend({
getTemplate: function() { return templates.heading; },
templateContext: function() {
getTemplate: function () { return window.templates.heading; },
templateContext: function () {
return {
model: this.model.toJSON()
};
},
events: function() {
events: function () {
return {
'keyup .mailpoet_input_title': _.partial(this.changeField, 'subject'),
'keyup .mailpoet_input_preheader': _.partial(this.changeField, 'preheader')
};
},
changeField: function(field, event) {
changeField: function (field, event) {
this.model.set(field, jQuery(event.target).val());
}
});
App.on('start', function(App, options) {
App.on('start', function (App, options) {
App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() }));
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-subject-line'), {
tooltipId: 'tooltip-designer-subject-line-ti',

View File

@ -1,34 +1,38 @@
define([
'newsletter_editor/App',
'newsletter_editor/components/communication',
'mailpoet',
'notice',
'backbone',
'backbone.marionette',
'jquery',
'blob',
'file-saver',
'html2canvas'
], function(
App,
CommunicationComponent,
MailPoet,
Notice,
Backbone,
Marionette,
jQuery,
Blob,
FileSaver,
html2canvas
) {
'newsletter_editor/App',
'newsletter_editor/components/communication',
'mailpoet',
'notice',
'backbone',
'backbone.marionette',
'jquery',
'blob',
'file-saver',
'html2canvas',
'underscore',
'jquery'
], function (
App,
CommunicationComponent,
MailPoet,
Notice,
Backbone,
Marionette,
jQuery,
Blob,
FileSaver,
html2canvas,
_,
$
) {
'use strict';
var Module = {},
saveTimeout;
saveTimeout;
// Save editor contents to server
Module.save = function() {
Module.save = function () {
var json = App.toJSON();
@ -40,12 +44,12 @@ define([
App.getChannel().trigger('beforeEditorSave', json);
// save newsletter
return CommunicationComponent.saveNewsletter(json).done(function(response) {
if(response.success !== undefined && response.success === true) {
return CommunicationComponent.saveNewsletter(json).done(function (response) {
if (response.success !== undefined && response.success === true) {
// TODO: Handle translations
//MailPoet.Notice.success("<?php _e('Newsletter has been saved.'); ?>");
} else if(response.error !== undefined) {
if(response.error.length === 0) {
// MailPoet.Notice.success("<?php _e('Newsletter has been saved.'); ?>");
} else if (response.error !== undefined) {
if (response.error.length === 0) {
MailPoet.Notice.error(
MailPoet.I18n.t('templateSaveFailed'),
{
@ -53,29 +57,29 @@ define([
}
);
} else {
$(response.error).each(function(i, error) {
$(response.error).each(function (i, error) {
MailPoet.Notice.error(error, { scroll: true });
});
}
}
App.getChannel().trigger('afterEditorSave', json, response);
}).fail(function(response) {
}).fail(function (response) {
// TODO: Handle saving errors
App.getChannel().trigger('afterEditorSave', {}, response);
});
};
Module.getThumbnail = function(element, options) {
Module.getThumbnail = function (element, options) {
var promise = html2canvas(element, options || {});
return promise.then(function(oldCanvas) {
return promise.then(function (oldCanvas) {
// Temporary workaround for html2canvas-alpha2.
// Removes 1px left transparent border from resulting canvas.
var oldContext = oldCanvas.getContext('2d'),
newCanvas = document.createElement('canvas'),
newContext = newCanvas.getContext('2d'),
leftBorderWidth = 1;
newCanvas = document.createElement('canvas'),
newContext = newCanvas.getContext('2d'),
leftBorderWidth = 1;
newCanvas.width = oldCanvas.width;
newCanvas.height = oldCanvas.height;
@ -90,11 +94,11 @@ define([
});
};
Module.saveTemplate = function(options) {
Module.saveTemplate = function (options) {
var that = this,
promise = jQuery.Deferred();
promise = jQuery.Deferred();
promise.then(function(thumbnail) {
promise.then(function (thumbnail) {
var data = _.extend(options || {}, {
thumbnail: thumbnail.toDataURL('image/jpeg'),
body: JSON.stringify(App.getBody())
@ -110,18 +114,18 @@ define([
Module.getThumbnail(
jQuery('#mailpoet_editor_content > .mailpoet_block').get(0)
).then(function(thumbnail) {
).then(function (thumbnail) {
promise.resolve(thumbnail);
});
return promise;
};
Module.exportTemplate = function(options) {
Module.exportTemplate = function (options) {
var that = this;
return Module.getThumbnail(
jQuery('#mailpoet_editor_content > .mailpoet_block').get(0)
).then(function(thumbnail) {
).then(function (thumbnail) {
var data = _.extend(options || {}, {
thumbnail: thumbnail.toDataURL('image/jpeg'),
body: App.getBody()
@ -139,7 +143,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,46 +155,46 @@ define([
'click .mailpoet_save_export': 'toggleExportTemplate',
'click .mailpoet_export_template': 'exportTemplate'
},
initialize: function(options) {
initialize: function (options) {
App.getChannel().on('beforeEditorSave', this.beforeSave, this);
App.getChannel().on('afterEditorSave', this.afterSave, this);
},
onRender: function() {
onRender: function () {
this.validateNewsletter(App.toJSON());
},
save: function() {
save: function () {
this.hideOptionContents();
App.getChannel().request('save');
},
beforeSave: function() {
beforeSave: function () {
// TODO: Add a loading animation instead
this.$('.mailpoet_autosaved_at').text(MailPoet.I18n.t('saving'));
},
afterSave: function(json, response) {
afterSave: function (json, response) {
this.validateNewsletter(json);
// Update 'Last saved timer'
this.$('.mailpoet_editor_last_saved').removeClass('mailpoet_hidden');
this.$('.mailpoet_autosaved_at').text('');
},
toggleSaveOptions: function() {
toggleSaveOptions: function () {
this.$('.mailpoet_save_options').toggleClass('mailpoet_hidden');
this.$('.mailpoet_save_show_options').toggleClass('mailpoet_save_show_options_active');
},
toggleSaveAsTemplate: function() {
toggleSaveAsTemplate: function () {
this.$('.mailpoet_save_as_template_container').toggleClass('mailpoet_hidden');
this.toggleSaveOptions();
},
showSaveAsTemplate: function() {
showSaveAsTemplate: function () {
this.$('.mailpoet_save_as_template_container').removeClass('mailpoet_hidden');
this.toggleSaveOptions();
},
hideSaveAsTemplate: function() {
hideSaveAsTemplate: function () {
this.$('.mailpoet_save_as_template_container').addClass('mailpoet_hidden');
},
saveAsTemplate: function() {
saveAsTemplate: function () {
var templateName = this.$('.mailpoet_save_as_template_name').val(),
templateDescription = this.$('.mailpoet_save_as_template_description').val(),
that = this;
templateDescription = this.$('.mailpoet_save_as_template_description').val(),
that = this;
if (templateName === '') {
MailPoet.Notice.error(
@ -212,7 +216,7 @@ define([
Module.saveTemplate({
name: templateName,
description: templateDescription
}).done(function() {
}).done(function () {
MailPoet.Notice.success(
MailPoet.I18n.t('templateSaved'),
{
@ -223,7 +227,7 @@ define([
MailPoet.trackEvent('Editor > Template saved', {
'MailPoet Free version': window.mailpoet_version
});
}).fail(function() {
}).fail(function () {
MailPoet.Notice.error(
MailPoet.I18n.t('templateSaveFailed'),
{
@ -236,17 +240,17 @@ define([
}
},
toggleExportTemplate: function() {
toggleExportTemplate: function () {
this.$('.mailpoet_export_template_container').toggleClass('mailpoet_hidden');
this.toggleSaveOptions();
},
hideExportTemplate: function() {
hideExportTemplate: function () {
this.$('.mailpoet_export_template_container').addClass('mailpoet_hidden');
},
exportTemplate: function() {
exportTemplate: function () {
var templateName = this.$('.mailpoet_export_template_name').val(),
templateDescription = this.$('.mailpoet_export_template_description').val(),
that = this;
templateDescription = this.$('.mailpoet_export_template_description').val(),
that = this;
if (templateName === '') {
MailPoet.Notice.error(
@ -272,21 +276,21 @@ define([
this.hideExportTemplate();
}
},
hideOptionContents: function() {
hideOptionContents: function () {
this.hideSaveAsTemplate();
this.hideExportTemplate();
this.$('.mailpoet_save_options').addClass('mailpoet_hidden');
},
next: function() {
next: function () {
this.hideOptionContents();
if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
if (!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
Module._cancelAutosave();
Module.save().done(function(response) {
Module.save().done(function (response) {
window.location.href = App.getConfig().get('urls.send');
});
}
},
validateNewsletter: function(jsonObject) {
validateNewsletter: function (jsonObject) {
if (!App._contentContainer.isValid()) {
this.showValidationError(App._contentContainer.validationError);
return;
@ -302,40 +306,40 @@ define([
this.hideValidationError();
},
showValidationError: function(message) {
showValidationError: function (message) {
var $el = this.$('.mailpoet_save_error');
$el.text(message);
$el.removeClass('mailpoet_hidden');
this.$('.mailpoet_save_next').addClass('button-disabled');
},
hideValidationError: function() {
hideValidationError: function () {
this.$('.mailpoet_save_error').addClass('mailpoet_hidden');
this.$('.mailpoet_save_next').removeClass('button-disabled');
}
});
Module.autoSave = function() {
Module.autoSave = function () {
// Delay in saving editor contents, during which a new autosave
// may be requested
var AUTOSAVE_DELAY_DURATION = 1000;
Module._cancelAutosave();
saveTimeout = setTimeout(function() {
App.getChannel().request('save').always(function() {
saveTimeout = setTimeout(function () {
App.getChannel().request('save').always(function () {
Module._cancelAutosave();
});
}, AUTOSAVE_DELAY_DURATION);
};
Module._cancelAutosave = function() {
Module._cancelAutosave = function () {
if (!saveTimeout) return;
clearTimeout(saveTimeout);
saveTimeout = undefined;
};
Module.beforeExitWithUnsavedChanges = function(e) {
Module.beforeExitWithUnsavedChanges = function (e) {
if (saveTimeout) {
var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
var event = e || window.event;
@ -348,7 +352,7 @@ define([
}
};
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
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, options) {
var saveView = new Module.SaveView();
App._appView.showChildView('bottomRegion', saveView);
});

View File

@ -1,23 +1,23 @@
define([
'newsletter_editor/App',
'newsletter_editor/components/communication',
'mailpoet',
'backbone',
'backbone.marionette',
'backbone.supermodel',
'underscore',
'jquery',
'sticky-kit'
], function(
App,
CommunicationComponent,
MailPoet,
Backbone,
Marionette,
SuperModel,
_,
jQuery,
StickyKit
'newsletter_editor/App',
'newsletter_editor/components/communication',
'mailpoet',
'backbone',
'backbone.marionette',
'backbone.supermodel',
'underscore',
'jquery',
'sticky-kit'
], function (
App,
CommunicationComponent,
MailPoet,
Backbone,
Marionette,
SuperModel,
_,
jQuery,
StickyKit
) {
'use strict';
@ -35,8 +35,8 @@ define([
}),
comparator: 'priority'
}))();
Module.registerWidget = function(widget) { return Module._contentWidgets.add(widget); };
Module.getWidgets = function() { return Module._contentWidgets; };
Module.registerWidget = function (widget) { return Module._contentWidgets.add(widget); };
Module.getWidgets = function () { return Module._contentWidgets; };
// Layout widget handlers for use to create new layout blocks via drag&drop
Module._layoutWidgets = new (Backbone.Collection.extend({
@ -49,11 +49,11 @@ define([
}),
comparator: 'priority'
}))();
Module.registerLayoutWidget = function(widget) { return Module._layoutWidgets.add(widget); };
Module.getLayoutWidgets = function() { return Module._layoutWidgets; };
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; },
getTemplate: function () { return window.templates.sidebar; },
regions: {
contentRegion: '.mailpoet_content_region',
layoutRegion: '.mailpoet_layout_region',
@ -61,7 +61,7 @@ define([
previewRegion: '.mailpoet_preview_region'
},
events: {
'click .mailpoet_sidebar_region h3, .mailpoet_sidebar_region .handlediv': function(event) {
'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');
@ -70,7 +70,7 @@ define([
{
duration: 250,
easing: 'easeOut',
complete: function() {
complete: function () {
$openRegion.addClass('closed');
}.bind(this)
}
@ -82,7 +82,7 @@ define([
{
duration: 250,
easing: 'easeIn',
complete: function() {
complete: function () {
$targetRegion.removeClass('closed');
}
}
@ -90,12 +90,12 @@ define([
}
}
},
initialize: function(options) {
initialize: function (options) {
jQuery(window)
.on('resize', this.updateHorizontalScroll.bind(this))
.on('scroll', this.updateHorizontalScroll.bind(this));
},
onRender: function() {
onRender: function () {
this.showChildView('contentRegion', new Module.SidebarWidgetsView(
App.getWidgets()
));
@ -108,7 +108,7 @@ define([
}));
this.showChildView('previewRegion', new Module.SidebarPreviewView());
},
updateHorizontalScroll: function() {
updateHorizontalScroll: function () {
// Fixes the sidebar so that on narrower screens the horizontal
// position of the sidebar would be scrollable and not fixed
// partially out of visible screen
@ -125,7 +125,7 @@ define([
}
});
},
onDomRefresh: function() {
onDomRefresh: function () {
this.$el.parent().stick_in_parent({
offset_top: 32
});
@ -140,23 +140,23 @@ define([
* Draggable widget collection view
*/
Module.SidebarWidgetsCollectionView = Marionette.CollectionView.extend({
childView: function(item) { return item.get('widgetView'); }
childView: function (item) { return item.get('widgetView'); }
});
/**
* 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'
},
initialize: function(widgets) {
initialize: function (widgets) {
this.widgets = widgets;
},
onRender: function() {
onRender: function () {
this.showChildView('widgets', new Module.SidebarWidgetsCollectionView({
collection: this.widgets
}));
@ -167,68 +167,68 @@ 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: {}
},
events: function() {
events: function () {
return {
'change #mailpoet_text_font_color': _.partial(this.changeColorField, 'text.fontColor'),
'change #mailpoet_text_font_family': function(event) {
'change #mailpoet_text_font_family': function (event) {
this.model.set('text.fontFamily', event.target.value);
},
'change #mailpoet_text_font_size': function(event) {
'change #mailpoet_text_font_size': function (event) {
this.model.set('text.fontSize', event.target.value);
},
'change #mailpoet_h1_font_color': _.partial(this.changeColorField, 'h1.fontColor'),
'change #mailpoet_h1_font_family': function(event) {
'change #mailpoet_h1_font_family': function (event) {
this.model.set('h1.fontFamily', event.target.value);
},
'change #mailpoet_h1_font_size': function(event) {
'change #mailpoet_h1_font_size': function (event) {
this.model.set('h1.fontSize', event.target.value);
},
'change #mailpoet_h2_font_color': _.partial(this.changeColorField, 'h2.fontColor'),
'change #mailpoet_h2_font_family': function(event) {
'change #mailpoet_h2_font_family': function (event) {
this.model.set('h2.fontFamily', event.target.value);
},
'change #mailpoet_h2_font_size': function(event) {
'change #mailpoet_h2_font_size': function (event) {
this.model.set('h2.fontSize', event.target.value);
},
'change #mailpoet_h3_font_color': _.partial(this.changeColorField, 'h3.fontColor'),
'change #mailpoet_h3_font_family': function(event) {
'change #mailpoet_h3_font_family': function (event) {
this.model.set('h3.fontFamily', event.target.value);
},
'change #mailpoet_h3_font_size': function(event) {
'change #mailpoet_h3_font_size': function (event) {
this.model.set('h3.fontSize', event.target.value);
},
'change #mailpoet_a_font_color': _.partial(this.changeColorField, 'link.fontColor'),
'change #mailpoet_a_font_underline': function(event) {
'change #mailpoet_a_font_underline': function (event) {
this.model.set('link.textDecoration', (event.target.checked) ? event.target.value : 'none');
},
'change #mailpoet_newsletter_background_color': _.partial(this.changeColorField, 'wrapper.backgroundColor'),
'change #mailpoet_background_color': _.partial(this.changeColorField, 'body.backgroundColor')
};
},
templateContext: function() {
templateContext: function () {
return {
model: this.model.toJSON(),
availableStyles: this.availableStyles.toJSON()
};
},
initialize: function(options) {
initialize: function (options) {
this.availableStyles = options.availableStyles;
},
changeField: function(field, event) {
changeField: function (field, event) {
this.model.set(field, jQuery(event.target).val());
},
changeColorField: function(field, event) {
changeColorField: function (field, event) {
var value = jQuery(event.target).val();
if (value === '') {
value = 'transparent';
@ -238,18 +238,18 @@ 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'
},
onBeforeDestroy: function() {
onBeforeDestroy: function () {
if (this.previewView) {
this.previewView.destroy();
this.previewView = null;
}
},
showPreview: function() {
showPreview: function () {
var json = App.toJSON();
// Stringify to enable transmission of primitive non-string value types
@ -264,23 +264,23 @@ define([
endpoint: 'newsletters',
action: 'showPreview',
data: json
}).always(function() {
}).always(function () {
MailPoet.Modal.loading(false);
}).done(function(response) {
}).done(function (response) {
this.previewView = new Module.NewsletterPreviewView({
previewUrl: response.meta.preview_url
});
var view = this.previewView.render();
this.previewView.$el.css('height', '100%');
MailPoet.Modal.popup({
template: '',
element: this.previewView.$el,
width: '95%',
height: '94%',
title: MailPoet.I18n.t('newsletterPreview'),
onCancel: function() {
onCancel: function () {
this.previewView.destroy();
this.previewView = null;
}.bind(this)
@ -289,16 +289,16 @@ define([
MailPoet.trackEvent('Editor > Browser Preview', {
'MailPoet Free version': window.mailpoet_version
});
}.bind(this)).fail(function(response) {
}.bind(this)).fail(function (response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
response.errors.map(function (error) { return error.message; }),
{ scroll: true }
);
}
});
},
sendPreview: function() {
sendPreview: function () {
// get form data
var $emailField = this.$('#mailpoet_preview_to_email');
var data = {
@ -321,10 +321,10 @@ define([
MailPoet.Modal.loading(true);
// save before sending
App.getChannel().request('save').always(function() {
CommunicationComponent.previewNewsletter(data).always(function() {
App.getChannel().request('save').always(function () {
CommunicationComponent.previewNewsletter(data).always(function () {
MailPoet.Modal.loading(false);
}).done(function(response) {
}).done(function (response) {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterPreviewSent'),
{ scroll: true }
@ -333,10 +333,10 @@ define([
'MailPoet Free version': window.mailpoet_version,
'Domain name': data.subscriber.substring(data.subscriber.indexOf('@') + 1)
});
}).fail(function(response) {
}).fail(function (response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
response.errors.map(function (error) { return error.message; }),
{ scroll: true, static: true }
);
}
@ -346,15 +346,15 @@ define([
});
Module.NewsletterPreviewView = Marionette.View.extend({
getTemplate: function() { return templates.newsletterPreview; },
initialize: function(options) {
getTemplate: function () { return window.templates.newsletterPreview; },
initialize: function (options) {
this.previewUrl = options.previewUrl;
this.width = '100%';
this.height = '100%';
// this.width = App.getConfig().get('newsletterPreview.width');
// this.height = App.getConfig().get('newsletterPreview.height')
},
templateContext: function() {
templateContext: function () {
return {
previewUrl: this.previewUrl,
width: this.width,
@ -363,7 +363,7 @@ define([
}
});
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
var Application = App;
Application.registerWidget = Module.registerWidget;
Application.getWidgets = Module.getWidgets;
@ -371,7 +371,7 @@ define([
Application.getLayoutWidgets = Module.getLayoutWidgets;
});
App.on('start', function(App, options) {
App.on('start', function (App, options) {
var stylesModel = App.getGlobalStyles(),
sidebarView = new SidebarView();

View File

@ -1,8 +1,9 @@
define([
'newsletter_editor/App',
'backbone.marionette',
'backbone.supermodel'
], function(App, Marionette, SuperModel) {
'newsletter_editor/App',
'backbone.marionette',
'backbone.supermodel',
'underscore'
], function (App, Marionette, SuperModel, _) {
'use strict';
@ -41,34 +42,34 @@ define([
backgroundColor: '#cccccc'
}
},
initialize: function() {
this.on('change', function() { App.getChannel().trigger('autoSave'); });
initialize: function () {
this.on('change', function () { App.getChannel().trigger('autoSave'); });
}
});
Module.StylesView = Marionette.View.extend({
getTemplate: function() { return templates.styles; },
getTemplate: function () { return window.templates.styles; },
modelEvents: {
change: 'render'
},
serializeData: function() {
serializeData: function () {
return this.model.toJSON();
}
});
Module._globalStyles = new SuperModel();
Module.getGlobalStyles = function() {
Module.getGlobalStyles = function () {
return Module._globalStyles;
};
Module.setGlobalStyles = function(options) {
Module.setGlobalStyles = function (options) {
Module._globalStyles = new Module.StylesModel(options);
return Module._globalStyles;
};
Module.getAvailableStyles = function() {
Module.getAvailableStyles = function () {
return App.getConfig().get('availableStyles');
};
App.on('before:start', function(App, options) {
App.on('before:start', function (App, options) {
var Application = App;
// Expose style methods to global application
Application.getGlobalStyles = Module.getGlobalStyles;
@ -80,7 +81,7 @@ define([
this.setGlobalStyles(globalStyles);
});
App.on('start', function(App, options) {
App.on('start', function (App, options) {
var stylesView = new Module.StylesView({ model: App.getGlobalStyles() });
App._appView.showChildView('stylesRegion', stylesView);
});

View File

@ -8,22 +8,22 @@
* its placeholder into editor text.
*/
/*jshint unused:false */
/*global tinymce:true */
tinymce.PluginManager.add('mailpoet_shortcodes', function(editor, url) {
var appendLabelAndClose = function(shortcode) {
/* jshint unused:false */
/* global tinymce:true */
tinymce.PluginManager.add('mailpoet_shortcodes', function (editor, url) {
var appendLabelAndClose = function (shortcode) {
editor.insertContent(shortcode);
editor.windowManager.close();
},
generateOnClickFunc = function(shortcode) {
return function() {
generateOnClickFunc = function (shortcode) {
return function () {
appendLabelAndClose(shortcode);
};
};
editor.addButton('mailpoet_shortcodes', {
icon: 'mailpoet_shortcodes',
onclick: function() {
onclick: function () {
var shortcodes = [],
configShortcodes = editor.settings.mailpoet_shortcodes;

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

@ -46,18 +46,18 @@ define(
let label = step.label;
if(step['link'] !== undefined && this.props.step !== step.name) {
if (step['link'] !== undefined && this.props.step !== step.name) {
label = (
<Link to={ step.link }>{ step.label }</Link>
<Link to={step.link}>{ step.label }</Link>
);
}
return (
<span key={ 'step-'+index }>
<span className={ stepClasses }>
<span key={'step-' + index}>
<span className={stepClasses}>
{ label }
</span>
{ (index < (this.state.steps.length - 1) ) ? ' > ' : '' }
{ (index < (this.state.steps.length - 1)) ? ' > ' : '' }
</span>
);
});

View File

@ -19,8 +19,8 @@ const _QueueMixin = {
newsletter_id: newsletter.id,
},
}).done(() => {
jQuery('#resume_'+newsletter.id).show();
jQuery('#pause_'+newsletter.id).hide();
jQuery('#resume_' + newsletter.id).show();
jQuery('#pause_' + newsletter.id).hide();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
@ -39,8 +39,8 @@ const _QueueMixin = {
newsletter_id: newsletter.id,
},
}).done(() => {
jQuery('#pause_'+newsletter.id).show();
jQuery('#resume_'+newsletter.id).hide();
jQuery('#pause_' + newsletter.id).show();
jQuery('#resume_' + newsletter.id).hide();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
@ -95,20 +95,20 @@ const _QueueMixin = {
{ newsletter.queue.count_processed } / { newsletter.queue.count_total }
&nbsp;&nbsp;
<a
id={ 'resume_'+newsletter.id }
id={'resume_' + newsletter.id}
className="button"
style={{ display: (newsletter.queue.status === 'paused')
? 'inline-block': 'none' }}
? 'inline-block' : 'none' }}
href="javascript:;"
onClick={ this.resumeSending.bind(null, newsletter) }
onClick={this.resumeSending.bind(null, newsletter)}
>{MailPoet.I18n.t('resume')}</a>
<a
id={ 'pause_'+newsletter.id }
id={'pause_' + newsletter.id}
className="button mailpoet_pause"
style={{ display: (newsletter.queue.status === null)
? 'inline-block': 'none' }}
? 'inline-block' : 'none' }}
href="javascript:;"
onClick={ this.pauseSending.bind(null, newsletter) }
onClick={this.pauseSending.bind(null, newsletter)}
>{MailPoet.I18n.t('pause')}</a>
</span>
);
@ -125,16 +125,16 @@ const _QueueMixin = {
return (
<div>
<div className={ progressClasses }>
<span
className="mailpoet_progress_bar"
style={ { width: progress_bar_width + '%' } }
<div className={progressClasses}>
<span
className="mailpoet_progress_bar"
style={{ width: progress_bar_width + '%' }}
></span>
<span className="mailpoet_progress_label">
{ percentage }
</span>
<span className="mailpoet_progress_label">
{ percentage }
</span>
</div>
<p style={{ textAlign:'center' }}>
<p style={{ textAlign: 'center' }}>
{ label }
</p>
</div>
@ -285,9 +285,9 @@ const _StatisticsMixin = {
return (
<div>
<Link
key={ `stats-${newsletter.id}` }
to={ params.link }
onClick={ params.onClick || null }
key={`stats-${newsletter.id}`}
to={params.link}
onClick={params.onClick || null}
>
{content}
</Link>
@ -346,8 +346,8 @@ const _MailerMixin = {
<p>{ mailer_check_settings_notice }</p>
<p>
<a href="javascript:;"
className="button"
onClick={ this.resumeMailerSending }
className="button"
onClick={this.resumeMailerSending}
>{ MailPoet.I18n.t('mailerResumeSendingButton') }</a>
</p>
</div>
@ -374,8 +374,6 @@ const _MailerMixin = {
};
export { _QueueMixin as QueueMixin };
export { _StatisticsMixin as StatisticsMixin };
export { _MailerMixin as MailerMixin };

View File

@ -104,7 +104,7 @@ const newsletter_actions = [
name: 'view',
link: function (newsletter) {
return (
<a href={ newsletter.preview_url } target="_blank">
<a href={newsletter.preview_url} target="_blank">
{MailPoet.I18n.t('preview')}
</a>
);
@ -114,7 +114,7 @@ const newsletter_actions = [
name: 'edit',
link: function (newsletter) {
return (
<a href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }>
<a href={`?page=mailpoet-newsletter-editor&id=${newsletter.id}`}>
{MailPoet.I18n.t('edit')}
</a>
);
@ -154,7 +154,7 @@ const newsletter_actions = [
];
const NewsletterListNotification = React.createClass({
mixins: [ MailerMixin ],
mixins: [MailerMixin],
updateStatus: function (e) {
// make the event persist so that we can still override the selected value
// in the ajax callback
@ -184,9 +184,9 @@ const NewsletterListNotification = React.createClass({
renderStatus: function (newsletter) {
return (
<select
data-id={ newsletter.id }
defaultValue={ newsletter.status }
onChange={ this.updateStatus }
data-id={newsletter.id}
defaultValue={newsletter.status}
onChange={this.updateStatus}
>
<option value="active">{ MailPoet.I18n.t('active') }</option>
<option value="draft">{ MailPoet.I18n.t('inactive') }</option>
@ -203,7 +203,7 @@ const NewsletterListNotification = React.createClass({
});
// check if the user has specified segments to send to
if(segments.length === 0) {
if (segments.length === 0) {
return (
<span className="mailpoet_error">
{ MailPoet.I18n.t('sendingToSegmentsNotSpecified') }
@ -269,7 +269,7 @@ const NewsletterListNotification = React.createClass({
} else {
return (
<Link
to={ `/notification/history/${ newsletter.id }` }
to={`/notification/history/${newsletter.id}`}
>{ MailPoet.I18n.t('viewHistory') }</Link>
);
}
@ -283,25 +283,25 @@ const NewsletterListNotification = React.createClass({
return (
<div>
<td className={ rowClasses }>
<td className={rowClasses}>
<strong>
<a
className="row-title"
href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }
href={`?page=mailpoet-newsletter-editor&id=${newsletter.id}`}
>{ newsletter.subject }</a>
</strong>
{ actions }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
<td className="column" data-colname={MailPoet.I18n.t('status')}>
{ this.renderStatus(newsletter) }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('settings') }>
<td className="column" data-colname={MailPoet.I18n.t('settings')}>
{ this.renderSettings(newsletter) }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('history') }>
<td className="column" data-colname={MailPoet.I18n.t('history')}>
{ this.renderHistoryLink(newsletter) }
</td>
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
<td className="column-date" data-colname={MailPoet.I18n.t('lastModifiedOn')}>
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
</td>
</div>
@ -317,21 +317,21 @@ const NewsletterListNotification = React.createClass({
<ListingTabs tab="notification" />
<Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location }
params={ this.props.params }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"
type="notification"
base_url="notification"
onRenderItem={ this.renderItem }
columns={ columns }
bulk_actions={ bulk_actions }
item_actions={ newsletter_actions }
messages={ messages }
auto_refresh={ true }
onRenderItem={this.renderItem}
columns={columns}
bulk_actions={bulk_actions}
item_actions={newsletter_actions}
messages={messages}
auto_refresh={true}
sort_by="updated_at"
sort_order="desc"
afterGetItems={ this.checkMailerStatus }
afterGetItems={this.checkMailerStatus}
/>
</div>
);

View File

@ -44,7 +44,7 @@ let newsletter_actions = [
name: 'view',
link: function (newsletter) {
return (
<a href={ newsletter.preview_url } target="_blank">
<a href={newsletter.preview_url} target="_blank">
{MailPoet.I18n.t('preview')}
</a>
);
@ -55,7 +55,7 @@ let newsletter_actions = [
newsletter_actions = Hooks.applyFilters('mailpoet_newsletters_listings_notification_history_actions', newsletter_actions);
const NewsletterListNotificationHistory = React.createClass({
mixins: [ QueueMixin, StatisticsMixin, MailerMixin ],
mixins: [QueueMixin, StatisticsMixin, MailerMixin],
renderItem: function (newsletter, actions, meta) {
const rowClasses = classNames(
'manage-column',
@ -69,27 +69,27 @@ const NewsletterListNotificationHistory = React.createClass({
return (
<div>
<td className={ rowClasses }>
<td className={rowClasses}>
<strong>
<a
href={ newsletter.preview_url }
href={newsletter.preview_url}
target="_blank"
>{ newsletter.queue.newsletter_rendered_subject || newsletter.subject }</a>
</strong>
{ actions }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
<td className="column" data-colname={MailPoet.I18n.t('status')}>
{ this.renderQueueStatus(newsletter, meta.mta_log) }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
<td className="column" data-colname={MailPoet.I18n.t('lists')}>
{ segments }
</td>
{ (mailpoet_tracking_enabled === true) ? (
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
<td className="column" data-colname={MailPoet.I18n.t('statistics')}>
{ this.renderStatistics(newsletter, undefined, meta.current_time) }
</td>
) : null }
<td className="column-date" data-colname={ MailPoet.I18n.t('sentOn') }>
<td className="column-date" data-colname={MailPoet.I18n.t('sentOn')}>
{ (newsletter.sent_at) ? MailPoet.Date.format(newsletter.sent_at) : MailPoet.I18n.t('notSentYet') }
</td>
</div>
@ -110,19 +110,19 @@ const NewsletterListNotificationHistory = React.createClass({
>{MailPoet.I18n.t('backToPostNotifications')}</Link>
<Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location }
params={ this.props.params }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"
type="notification_history"
base_url="notification/history/:parent_id"
onRenderItem={ this.renderItem }
onRenderItem={this.renderItem}
columns={columns}
item_actions={ newsletter_actions }
auto_refresh={ true }
item_actions={newsletter_actions}
auto_refresh={true}
sort_by="sent_at"
sort_order="desc"
afterGetItems={ this.checkMailerStatus }
afterGetItems={this.checkMailerStatus}
/>
</div>
);

View File

@ -98,13 +98,13 @@ const bulk_actions = [
];
const confirmEdit = (newsletter) => {
if(
if (
!newsletter.queue
|| newsletter.status != 'sending'
|| newsletter.queue.status !== null
|| window.confirm(MailPoet.I18n.t('confirmEdit'))
) {
window.location.href = `?page=mailpoet-newsletter-editor&id=${ newsletter.id }`;
window.location.href = `?page=mailpoet-newsletter-editor&id=${newsletter.id}`;
}
};
@ -113,7 +113,7 @@ let newsletter_actions = [
name: 'view',
link: function (newsletter) {
return (
<a href={ newsletter.preview_url } target="_blank">
<a href={newsletter.preview_url} target="_blank">
{MailPoet.I18n.t('preview')}
</a>
);
@ -160,7 +160,7 @@ let newsletter_actions = [
newsletter_actions = Hooks.applyFilters('mailpoet_newsletters_listings_standard_actions', newsletter_actions);
const NewsletterListStandard = React.createClass({
mixins: [ QueueMixin, StatisticsMixin, MailerMixin ],
mixins: [QueueMixin, StatisticsMixin, MailerMixin],
renderItem: function (newsletter, actions, meta) {
const rowClasses = classNames(
'manage-column',
@ -174,7 +174,7 @@ const NewsletterListStandard = React.createClass({
return (
<div>
<td className={ rowClasses }>
<td className={rowClasses}>
<strong>
<a
className="row-title"
@ -184,18 +184,18 @@ const NewsletterListStandard = React.createClass({
</strong>
{ actions }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
<td className="column" data-colname={MailPoet.I18n.t('status')}>
{ this.renderQueueStatus(newsletter, meta.mta_log) }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
<td className="column" data-colname={MailPoet.I18n.t('lists')}>
{ segments }
</td>
{ (mailpoet_tracking_enabled === true) ? (
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
<td className="column" data-colname={MailPoet.I18n.t('statistics')}>
{ this.renderStatistics(newsletter, undefined, meta.current_time) }
</td>
) : null }
<td className="column-date" data-colname={ MailPoet.I18n.t('sentOn') }>
<td className="column-date" data-colname={MailPoet.I18n.t('sentOn')}>
<abbr>{ (newsletter.sent_at) ? MailPoet.Date.format(newsletter.sent_at) : MailPoet.I18n.t('notSentYet') }</abbr>
</td>
</div>
@ -218,21 +218,21 @@ const NewsletterListStandard = React.createClass({
<ListingTabs tab="standard" />
<Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location }
params={ this.props.params }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"
type="standard"
base_url="standard"
onRenderItem={this.renderItem}
columns={columns}
bulk_actions={ bulk_actions }
item_actions={ newsletter_actions }
messages={ messages }
auto_refresh={ true }
bulk_actions={bulk_actions}
item_actions={newsletter_actions}
messages={messages}
auto_refresh={true}
sort_by="sent_at"
sort_order="desc"
afterGetItems={ this.checkMailerStatus }
afterGetItems={this.checkMailerStatus}
/>
</div>
);

View File

@ -35,9 +35,9 @@ const ListingTabs = React.createClass({
return (
<Link
key={ 'tab-'+index }
className={ tabClasses }
to={ tab.link }
key={'tab-' + index}
className={tabClasses}
to={tab.link}
onClick={() => MailPoet.trackEvent(`Tab Emails > ${tab.name} clicked`,
{ 'MailPoet Free version': window.mailpoet_version }
)}

View File

@ -103,7 +103,7 @@ let newsletter_actions = [
name: 'view',
link: function (newsletter) {
return (
<a href={ newsletter.preview_url } target="_blank">
<a href={newsletter.preview_url} target="_blank">
{MailPoet.I18n.t('preview')}
</a>
);
@ -113,7 +113,7 @@ let newsletter_actions = [
name: 'edit',
link: function (newsletter) {
return (
<a href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }>
<a href={`?page=mailpoet-newsletter-editor&id=${newsletter.id}`}>
{MailPoet.I18n.t('edit')}
</a>
);
@ -127,7 +127,7 @@ let newsletter_actions = [
newsletter_actions = Hooks.applyFilters('mailpoet_newsletters_listings_welcome_notification_actions', newsletter_actions);
const NewsletterListWelcome = React.createClass({
mixins: [ StatisticsMixin, MailerMixin ],
mixins: [StatisticsMixin, MailerMixin],
updateStatus: function (e) {
// make the event persist so that we can still override the selected value
// in the ajax callback
@ -164,9 +164,9 @@ const NewsletterListWelcome = React.createClass({
<div>
<p>
<select
data-id={ newsletter.id }
defaultValue={ newsletter.status }
onChange={ this.updateStatus }
data-id={newsletter.id}
defaultValue={newsletter.status}
onChange={this.updateStatus}
>
<option value="active">{ MailPoet.I18n.t('active') }</option>
<option value="draft">{ MailPoet.I18n.t('inactive') }</option>
@ -256,30 +256,30 @@ const NewsletterListWelcome = React.createClass({
return (
<div>
<td className={ rowClasses }>
<td className={rowClasses}>
<strong>
<a
className="row-title"
href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }
href={`?page=mailpoet-newsletter-editor&id=${newsletter.id}`}
>{ newsletter.subject }</a>
</strong>
{ actions }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
<td className="column" data-colname={MailPoet.I18n.t('status')}>
{ this.renderStatus(newsletter) }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('settings') }>
<td className="column" data-colname={MailPoet.I18n.t('settings')}>
{ this.renderSettings(newsletter) }
</td>
{ (mailpoet_tracking_enabled === true) ? (
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
<td className="column" data-colname={MailPoet.I18n.t('statistics')}>
{ this.renderStatistics(
newsletter,
newsletter.total_sent > 0 && newsletter.statistics
) }
</td>
) : null }
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
<td className="column-date" data-colname={MailPoet.I18n.t('lastModifiedOn')}>
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
</td>
</div>
@ -295,21 +295,21 @@ const NewsletterListWelcome = React.createClass({
<ListingTabs tab="welcome" />
<Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location }
params={ this.props.params }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
endpoint="newsletters"
type="welcome"
base_url="welcome"
onRenderItem={ this.renderItem }
columns={ columns }
bulk_actions={ bulk_actions }
item_actions={ newsletter_actions }
messages={ messages }
auto_refresh={ true }
onRenderItem={this.renderItem}
columns={columns}
bulk_actions={bulk_actions}
item_actions={newsletter_actions}
messages={messages}
auto_refresh={true}
sort_by="updated_at"
sort_order="desc"
afterGetItems={ this.checkMailerStatus }
afterGetItems={this.checkMailerStatus}
/>
</div>
);

View File

@ -26,28 +26,28 @@ const App = React.createClass({
const container = document.getElementById('newsletters_container');
if(container) {
if (container) {
let extra_routes = [];
extra_routes = Hooks.applyFilters('mailpoet_newsletters_before_router', extra_routes);
const mailpoet_listing = ReactDOM.render((
<Router history={ history }>
<Route path="/" component={ App }>
<Router history={history}>
<Route path="/" component={App}>
<IndexRedirect to="standard" />
{/* Listings */}
<Route path="standard(/)**" params={{ tab: 'standard' }} component={ NewsletterListStandard } />
<Route path="welcome(/)**" component={ NewsletterListWelcome } />
<Route path="notification/history/:parent_id(/)**" component={ NewsletterListNotificationHistory } />
<Route path="notification(/)**" component={ NewsletterListNotification } />
<Route path="standard(/)**" params={{ tab: 'standard' }} component={NewsletterListStandard} />
<Route path="welcome(/)**" component={NewsletterListWelcome} />
<Route path="notification/history/:parent_id(/)**" component={NewsletterListNotificationHistory} />
<Route path="notification(/)**" component={NewsletterListNotification} />
{/* Newsletter: type selection */}
<Route path="new" component={ NewsletterTypes } />
<Route path="new" component={NewsletterTypes} />
{/* New newsletter: types */}
<Route path="new/standard" component={ NewsletterTypeStandard } />
<Route path="new/notification" component={ NewsletterTypeNotification } />
<Route path="new/standard" component={NewsletterTypeStandard} />
<Route path="new/notification" component={NewsletterTypeNotification} />
{/* Template selection */}
<Route name="template" path="template/:id" component={ NewsletterTemplates } />
<Route name="template" path="template/:id" component={NewsletterTemplates} />
{/* Sending options */}
<Route path="send/:id" component={ NewsletterSend } />
<Route path="send/:id" component={NewsletterSend} />
{/* Extra routes */}
{ extra_routes.map(rt => <Route key={rt.path} path={rt.path} component={rt.component} />) }
</Route>

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({
@ -44,7 +46,7 @@ define(
return type.getSendButtonOptions(this.state.item);
},
getSubtype: function (newsletter) {
switch(newsletter.type) {
switch (newsletter.type) {
case 'notification': return NotificationNewsletterFields;
case 'welcome': return WelcomeNewsletterFields;
default: return StandardNewsletterFields;
@ -54,7 +56,7 @@ define(
return jQuery('#mailpoet_newsletter').parsley().isValid();
},
componentDidMount: function () {
if(this.isMounted()) {
if (this.isMounted()) {
this.loadItem(this.props.params.id);
}
jQuery('#mailpoet_newsletter').parsley();
@ -90,7 +92,7 @@ define(
handleSend: function (e) {
e.preventDefault();
if(!this.isValid()) {
if (!this.isValid()) {
jQuery('#mailpoet_newsletter').parsley().validate();
} else {
this._save(e).done(() => {
@ -109,7 +111,7 @@ define(
},
}).done((response) => {
// redirect to listing based on newsletter type
this.context.router.push(`/${ this.state.item.type || '' }`);
this.context.router.push(`/${this.state.item.type || ''}`);
const opts = this.state.item.options;
// display success message depending on newsletter type
if (response.data.type === 'welcome') {
@ -141,7 +143,7 @@ define(
},
}).done((response) => {
// redirect to listing based on newsletter type
this.context.router.push(`/${ this.state.item.type || '' }`);
this.context.router.push(`/${this.state.item.type || ''}`);
if (response.data.status === 'scheduled') {
MailPoet.Notice.success(
@ -162,7 +164,9 @@ define(
}
}).fail(this._showError);
}
}).fail(this._showError).always(() => {
})
.fail(this._showError)
.always(() => {
this.setState({ loading: false });
});
}
@ -170,7 +174,7 @@ define(
},
handleResume: function (e) {
e.preventDefault();
if(!this.isValid()) {
if (!this.isValid()) {
jQuery('#mailpoet_newsletter').parsley().validate();
} else {
this._save(e).done(() => {
@ -184,7 +188,7 @@ define(
newsletter_id: this.state.item.id,
},
}).done(() => {
this.context.router.push(`/${ this.state.item.type || '' }`);
this.context.router.push(`/${this.state.item.type || ''}`);
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterSendingHasBeenResumed')
);
@ -196,7 +200,9 @@ define(
);
}
});
}).fail(this._showError).always(() => {
})
.fail(this._showError)
.always(() => {
this.setState({ loading: false });
});
}
@ -210,7 +216,7 @@ define(
MailPoet.I18n.t('newsletterUpdated')
);
}).done(() => {
this.context.router.push(`/${ this.state.item.type || '' }`);
this.context.router.push(`/${this.state.item.type || ''}`);
}).fail(this._showError);
},
handleRedirectToDesign: function (e) {
@ -279,6 +285,7 @@ define(
}
return newField;
});
const sendButtonOptions = this.getSendButtonOptions();
return (
<div>
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
@ -287,27 +294,27 @@ define(
<Form
id="mailpoet_newsletter"
fields={ fields }
item={ this.state.item }
loading={ this.state.loading }
fields={fields}
item={this.state.item}
loading={this.state.loading}
onChange={this.handleFormChange}
onSubmit={this.handleSave}
>
<p className="submit">
{
isPaused ?
<input
className="button button-primary"
type="button"
onClick={ this.handleResume }
value={MailPoet.I18n.t('resume')} />
<input
className="button button-primary"
type="button"
onClick={this.handleResume}
value={MailPoet.I18n.t('resume')} />
:
<input
className="button button-primary"
type="button"
onClick={ this.handleSend }
value={MailPoet.I18n.t('send')}
{...this.getSendButtonOptions()}
<input
className="button button-primary"
type="button"
onClick={this.handleSend}
value={MailPoet.I18n.t('send')}
{...sendButtonOptions}
/>
}
&nbsp;
@ -318,16 +325,18 @@ define(
&nbsp;{MailPoet.I18n.t('orSimply')}&nbsp;
<a
href={
'?page=mailpoet-newsletter-editor&id='+this.props.params.id
'?page=mailpoet-newsletter-editor&id=' + this.props.params.id
}
onClick={this.handleRedirectToDesign}>
{MailPoet.I18n.t('goBackToDesign')}
</a>.
</p>
<HelpTooltip
tooltip={MailPoet.I18n.t('helpTooltipSendEmail')}
tooltipId="helpTooltipSendEmail"
/>
{ !isPaused && sendButtonOptions['disabled'] && sendButtonOptions['disabled'] === 'disabled' && (
<HelpTooltip
tooltip={MailPoet.I18n.t('helpTooltipSendEmail')}
tooltipId="helpTooltipSendEmail"
/>
) }
</Form>
</div>
);

View File

@ -157,7 +157,7 @@ define(
size="10"
name={this.getFieldName()}
value={this.getDisplayDate(this.props.value)}
readOnly={ true }
readOnly={true}
disabled={this.props.disabled}
onChange={this.onChange}
ref="dateInput"
@ -172,8 +172,8 @@ define(
(value, index) => {
return (
<option
key={ 'option-' + index }
value={ value }>
key={'option-' + index}
value={value}>
{ timeOfDayItems[value] }
</option>
);
@ -241,7 +241,7 @@ define(
displayFormat={dateDisplayFormat}
storageFormat={dateStorageFormat}
disabled={this.props.disabled}
validation={this.props.dateValidation}/>
validation={this.props.dateValidation} />
<TimeSelect
name="time"
value={this.state.time}

View File

@ -132,7 +132,7 @@ define(
});
}
}).fail((response) => {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map((error) => { return error.message; }),
{ scroll: true }
@ -175,7 +175,7 @@ define(
},
handleDeleteTemplate: function (template) {
this.setState({ loading: true });
if(
if (
window.confirm(
(
MailPoet.I18n.t('confirmTemplateDeletion')
@ -219,7 +219,7 @@ define(
<div className="mailpoet_delete">
<a
href="javascript:;"
onClick={ this.handleDeleteTemplate.bind(null, template) }
onClick={this.handleDeleteTemplate.bind(null, template)}
>
{MailPoet.I18n.t('delete')}
</a>
@ -231,37 +231,37 @@ define(
&& template.thumbnail.length > 0) {
thumbnail = (
<a href="javascript:;" onClick={this.handleShowTemplate.bind(null, template)}>
<img src={ template.thumbnail } />
<img src={template.thumbnail} />
<div className="mailpoet_overlay"></div>
</a>
);
}
return (
<li key={ 'template-'+index }>
<li key={'template-' + index}>
<div className="mailpoet_thumbnail">
{ thumbnail }
</div>
<div className="mailpoet_description">
<h3>{ template.name }</h3>
<p>{ template.description }</p>
<h3>{ template.name }</h3>
<p>{ template.description }</p>
</div>
<div className="mailpoet_actions">
<a
className="button button-secondary"
onClick={ this.handleShowTemplate.bind(null, template) }
<a
className="button button-secondary"
onClick={this.handleShowTemplate.bind(null, template)}
>
{MailPoet.I18n.t('preview')}
</a>
{MailPoet.I18n.t('preview')}
</a>
&nbsp;
<a
className="button button-primary"
onClick={ this.handleSelectTemplate.bind(null, template) }
<a
className="button button-primary"
onClick={this.handleSelectTemplate.bind(null, template)}
>
{MailPoet.I18n.t('select')}
</a>
{MailPoet.I18n.t('select')}
</a>
</div>
{ (template.readonly === '1') ? false : deleteLink }
</li>
@ -280,7 +280,7 @@ define(
<Breadcrumb step="template" />
<ul className={ boxClasses }>
<ul className={boxClasses}>
{ templates }
</ul>

View File

@ -18,7 +18,7 @@ define(
router: React.PropTypes.object.isRequired,
},
setupNewsletter: function (type) {
if(type !== undefined) {
if (type !== undefined) {
this.context.router.push(`/new/${type}`);
MailPoet.trackEvent('Emails > Type selected', {
'MailPoet Free version': window.mailpoet_version,
@ -58,7 +58,7 @@ define(
description: MailPoet.I18n.t('regularNewsletterTypeDescription'),
action: function () {
return (
<a className="button button-primary" onClick={ this.createNewsletter.bind(null, 'standard') }>
<a className="button button-primary" onClick={this.createNewsletter.bind(null, 'standard')}>
{MailPoet.I18n.t('create')}
</a>
);
@ -84,7 +84,7 @@ define(
description: MailPoet.I18n.t('postNotificationNewsletterTypeDescription'),
action: function () {
return (
<a className="button button-primary" onClick={ this.setupNewsletter.bind(null, 'notification') }>
<a className="button button-primary" onClick={this.setupNewsletter.bind(null, 'notification')}>
{MailPoet.I18n.t('setUp')}
</a>
);

View File

@ -82,7 +82,7 @@ define(
<input
className="button button-primary"
type="button"
onClick={ this.handleNext }
onClick={this.handleNext}
value={MailPoet.I18n.t('next')} />
</p>
</div>

View File

@ -120,7 +120,7 @@ const WelcomeScheduling = React.createClass({
});
},
showTemplateSelection: function (newsletterId) {
this.context.router.push(`/template/${ newsletterId }`);
this.context.router.push(`/template/${newsletterId}`);
},
render: function () {
const value = this._getCurrentValue();
@ -130,42 +130,42 @@ const WelcomeScheduling = React.createClass({
if (value.event === 'user') {
roleSegmentSelection = (
<Select
field={ roleField }
item={ this._getCurrentValue() }
onValueChange={ this.handleRoleChange } />
field={roleField}
item={this._getCurrentValue()}
onValueChange={this.handleRoleChange} />
);
} else {
roleSegmentSelection = (
<Select
field={ segmentField }
item={ this._getCurrentValue() }
onValueChange={ this.handleSegmentChange } />
field={segmentField}
item={this._getCurrentValue()}
onValueChange={this.handleSegmentChange} />
);
}
if (value.afterTimeType !== 'immediate') {
timeNumber = (
<Text
field={ afterTimeNumberField }
item={ this._getCurrentValue() }
onValueChange={ this.handleAfterTimeNumberChange } />
field={afterTimeNumberField}
item={this._getCurrentValue()}
onValueChange={this.handleAfterTimeNumberChange} />
);
}
return (
<div>
<Select
field={ events }
item={ this._getCurrentValue() }
onValueChange={ this.handleEventChange } />
field={events}
item={this._getCurrentValue()}
onValueChange={this.handleEventChange} />
{ roleSegmentSelection }
{ timeNumber }
<Select
field={ afterTimeTypeField }
item={ this._getCurrentValue() }
onValueChange={ this.handleAfterTimeTypeChange } />
field={afterTimeTypeField}
item={this._getCurrentValue()}
onValueChange={this.handleAfterTimeTypeChange} />
</div>
);
},

View File

@ -1,6 +1,7 @@
define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
define('notice', ['mailpoet', 'jquery'], function (mp, jQuery) {
'use strict';
/*==================================================================================================
/*= =================================================================================================
MailPoet Notice:
@ -21,7 +22,7 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
// system message (static: true)
MailPoet.Notice.system('You need to updated ASAP!');
==================================================================================================*/
================================================================================================== */
var MailPoet = mp;
MailPoet.Notice = {
version: 1.0,
@ -39,15 +40,15 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
onClose: null
},
options: {},
init: function(options) {
init: function (options) {
// set options
this.options = jQuery.extend({}, this.defaults, options);
return this;
},
createNotice: function() {
createNotice: function () {
// clone element
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
this.element = jQuery('#mailpoet_notice_' + this.options.type).clone();
// add data-id to the element
if (this.options.id) {
@ -67,22 +68,22 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
} else if (typeof this.options.positionAfter === 'string') {
positionAfter = jQuery(this.options.positionAfter);
} else {
positionAfter = jQuery('#mailpoet_notice_'+this.options.type);
positionAfter = jQuery('#mailpoet_notice_' + this.options.type);
}
positionAfter.after(this.element);
// setup onClose callback
var onClose = null;
if (this.options.onClose !== null) {
onClose = this.options.onClose;
onClose = this.options.onClose;
}
// listen to remove event
jQuery(this.element).on('close', function() {
jQuery(this).fadeOut(200, function() {
jQuery(this.element).on('close', function () {
jQuery(this).fadeOut(200, function () {
// on close callback
if (onClose !== null) {
onClose();
onClose();
}
// remove notice
jQuery(this).remove();
@ -90,41 +91,41 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
}.bind(this.element));
// listen to message event
jQuery(this.element).on('setMessage', function(e, message) {
jQuery(this.element).on('setMessage', function (e, message) {
MailPoet.Notice.setMessage(message);
}.bind(this.element));
return this;
},
updateNotice: function() {
updateNotice: function () {
// update notice's message
jQuery('[data-id="'+this.options.id+'"').first().trigger(
jQuery('[data-id="' + this.options.id + '"').first().trigger(
'setMessage', this.options.message
);
},
setMessage: function(message) {
setMessage: function (message) {
var formattedMessage = this.formatMessage(message);
// let's sugar coat the message with a fancy <p>
formattedMessage = '<p>'+formattedMessage+'</p>';
formattedMessage = '<p>' + formattedMessage + '</p>';
// set message
return this.element.html(formattedMessage);
},
formatMessage: function(message) {
formatMessage: function (message) {
if (Array.isArray(message)) {
return message.join('<br />');
} else {
return message;
}
},
show: function(options) {
show: function (options) {
// initialize
this.init(options);
if (
this.options.id !== null
&&
jQuery('[data-id="'+this.options.id+'"]').length > 0
jQuery('[data-id="' + this.options.id + '"]').length > 0
) {
this.updateNotice();
} else {
@ -132,7 +133,7 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
}
this.showNotice();
},
showNotice: function() {
showNotice: function () {
// set message
this.setMessage(this.options.message);
@ -143,13 +144,13 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
switch (this.options.type) {
case 'success':
this.element.addClass('notice notice-success');
break;
break;
case 'system':
this.element.addClass('notice notice-warning');
break;
break;
case 'error':
this.element.addClass('notice notice-error');
break;
break;
}
// make the notice appear
@ -165,8 +166,8 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
this.element.delay(this.options.timeout).trigger('close');
} else if (this.options.hideClose === false) {
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
this.element.find('.mailpoet_notice_close').on('click', function() {
jQuery(this).trigger('close');
this.element.find('.mailpoet_notice_close').on('click', function () {
jQuery(this).trigger('close');
});
}
@ -175,7 +176,7 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
this.options.onOpen(this.element);
}
},
hide: function(all) {
hide: function (all) {
if (all !== undefined && all === true) {
// all notices
jQuery('.mailpoet_notice:not([id])').trigger('close');
@ -192,19 +193,19 @@ define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
.trigger('close');
}
},
error: function(message, options) {
error: function (message, options) {
this.show(jQuery.extend({}, {
type: 'error',
message: message
}, options));
},
success: function(message, options) {
success: function (message, options) {
this.show(jQuery.extend({}, {
type: 'success',
message: message
}, options));
},
system: function(message, options) {
system: function (message, options) {
this.show(jQuery.extend({}, {
type: 'system',
static: true,

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