Compare commits

...

162 Commits

Author SHA1 Message Date
856c636089 Releasing 3.0.0-rc.2.0.1 2017-08-30 16:06:39 +00:00
8f9e8ea185 Merge pull request #1075 from mailpoet/forms-bug
Fix form issue when using list selection field [MAILPOET-1077]
2017-08-30 18:10:33 +03:00
b0b88693f1 Merge pull request #1071 from mailpoet/initializer_cleanup
Fixes activation on MS environments and cleans up Initializer [MAILPOET-1076]
2017-08-30 17:56:16 +03:00
9916eb9da8 updated tests 2017-08-30 14:52:17 +00:00
79b5426e01 Fix a constant name [MAILPOET-1076] 2017-08-30 17:47:53 +03:00
5807fd2e02 Merge pull request #1067 from mailpoet/emoji
Add emoji support to newsletter body [MAILPOET-1009]
2017-08-30 10:04:26 -04:00
0ee39143f4 Runs hooks setup only when plugin is initilized 2017-08-30 09:50:49 -04:00
10c39bd650 Removes unused constructor 2017-08-30 09:47:34 -04:00
20593cc5a5 Fix form issue when using list selection field 2017-08-30 13:29:41 +00:00
cb4b599d97 Merge pull request #1073 from mailpoet/fix-notice
Fix php notice
2017-08-30 16:25:50 +03:00
53f7953566 Fix browser preview bypassing emoji encoding [MAILPOET-1009] 2017-08-30 14:39:38 +03:00
61ae2da1e3 Fix a constant not defined in PHP 5.3 [MAILPOET-1009] 2017-08-30 14:02:29 +03:00
36abd8e5e6 Don't show network activation notice for other plugins
[MAILPOET-1072]
2017-08-30 11:39:42 +02:00
7e9de1fd07 Fix php notice 2017-08-30 11:25:42 +02:00
7ac5e65963 Fix php notice 2017-08-30 10:30:16 +02:00
cf992852b5 Validate for unsubscribe link only for MSS sending method [MAILPOET-1050] 2017-08-30 10:16:24 +02:00
59482b2bfa Uses init hook to initilize AccessControl 2017-08-29 23:30:35 -04:00
053f9e0cdf Adds higher priority to init hook so that it fires before the widgets hook 2017-08-29 23:20:46 -04:00
e1cc25239b Maintains code consistency when setting up JSON API
Updates exception handler return statement
2017-08-29 20:33:50 -04:00
2f4452ad36 Removes redundant exception handler 2017-08-29 20:28:20 -04:00
f453d685d6 Fixes translation not being picked up by makepot 2017-08-29 20:24:04 -04:00
2d2b4ca7f0 Moves setup actions from plugins_loaded hook to init hook
Rearranges class methods to follow the order by which they are called
2017-08-29 20:22:19 -04:00
546e012fbf releasing 3.0.0-rc.2.0.0 2017-08-29 13:43:15 +00:00
83adf089c5 Merge pull request #1070 from mailpoet/permissions
Fix Endpoint to use single global permission and not array of them [MAILPOET-1057]
2017-08-29 14:47:18 +02:00
2f45bb05d7 Fix Endpoint to use single global permission and not array of them
[MAILPOET-1057]
2017-08-29 15:34:35 +03:00
9ef8ab3e28 Merge pull request #1065 from mailpoet/events
Track extra events on MixPanel [MAILPOET-970]
2017-08-29 15:26:24 +03:00
f4db4f05c4 minor fixes 2017-08-29 12:18:12 +00:00
e7e08dbb3a minor fixes 2017-08-29 12:07:57 +00:00
02e2f0c07a Merge pull request #1066 from mailpoet/premium-update-warning
Premium update warning [PREMIUM-28]
2017-08-29 12:52:18 +03:00
c75b6bd7eb Show warning only on plugins page
[PREMIUM-28]
2017-08-29 11:22:51 +02:00
b74be8777a Display warning on Email pages
[PREMIUM-28]
2017-08-29 11:22:51 +02:00
7463e0d1f1 Update invalid key message
[PREMIUM-28]
2017-08-29 11:22:51 +02:00
a378880cf8 Merge pull request #1069 from mailpoet/bridge_forbidden_response
Adds 403 response code that mirrors 401 behavior [MAILPOET-1070]
2017-08-29 11:20:56 +03:00
33fa496913 Add a message for an already used MSS key [MAILPOET-1070] 2017-08-29 11:10:09 +03:00
eff996e1f8 Unify key state constant names, leave back compat with unlocker [MAILPOET-1070] 2017-08-29 10:58:16 +03:00
28b894b26b Add test cases [MAILPOET-1070] 2017-08-29 09:20:03 +03:00
c914aedc0d Simplify API response codes handling [MAILPOET-1070] 2017-08-29 09:18:08 +03:00
1745b67d64 Adds 403 response code that mirrors 401 behavior 2017-08-28 21:25:54 -04:00
2d25974fdc Merge pull request #1068 from mailpoet/helpscout
Update HS Beacon icon to question mark [MAILPOET-869]
2017-08-28 19:49:12 -04:00
51a02784e2 Update HS Beacon icon to question mark [MAILPOET-869] 2017-08-28 19:12:27 +03:00
b9bdc86fd9 Add emoji support to newsletter body [MAILPOET-1009] 2017-08-28 19:07:17 +03:00
e580e6b92b Merge pull request #1041 from mailpoet/access_control
Allows granular control of access to various parts of the plugin [MAILPOET-1057] [MAILPOET-1048]
2017-08-28 16:48:47 +03:00
96f77498f7 Merge pull request #1061 from mailpoet/safari-error-fix
Safari error fix [MAILPOET-1011]
2017-08-28 13:33:43 +02:00
62ce7c0437 Merge pull request #1062 from mailpoet/wp_user_subscription_update_fix
Prevents WP subscribers' first/last name from being erased [MAILPOET-1062]
2017-08-28 12:57:25 +03:00
c1e542cb5a Reschedules past due scheduled queues when reactivating notification 2017-08-28 09:20:17 +02:00
544bf0ddfd Merge pull request #1064 from mailpoet/welcome_alc_fix
Don't track sent ALC posts for welcome and standard emails, always send the latest posts [MAILPOET-1069]
2017-08-25 10:36:46 -04:00
609f1b5e67 Tracking new events 2017-08-25 13:19:52 +00:00
4616cf67bf Fix a test [MAILPOET-1069] 2017-08-25 16:10:01 +03:00
cc5227ca0d Don't track sent ALC posts for welcome and standard emails (always send the latest posts) [MAILPOET-1069] 2017-08-25 15:51:45 +03:00
26bccd95d4 Uses method vs. accessing class internals to get user capability 2017-08-24 13:58:54 -04:00
af58814fe7 Moves AccessControl intialization outside of Router to Initializer 2017-08-24 13:56:17 -04:00
7d9b4b31aa Removes unused constructor parameter 2017-08-24 13:37:49 -04:00
8a8108b41d Prevents WP subscribers' first/last name from being erased when updating
subscription
2017-08-24 13:19:42 -04:00
d92b1f57bd Merge pull request #1060 from mailpoet/mp2_forms_fix
Don't process the wysija_form shortcode to allow MP2 forms to work [MAILPOET-1067]
2017-08-24 10:40:10 -04:00
52ef7bece4 Merge pull request #1053 from mailpoet/editor_save
Save newsletter when clicked on "Next" button [MAILPOET-1051]
2017-08-24 09:03:34 -04:00
dc11046ad1 Fixes undefined JS error when vendor.js is loaded deferred
[MAILPOET-1026]
2017-08-24 13:37:15 +02:00
01f41b9798 Fix App and Application argument naming 2017-08-24 14:17:32 +03:00
9c0d9c31f8 Refactor cancelAutosave to return early 2017-08-24 13:48:13 +03:00
df499095c4 Fix test indentation 2017-08-24 13:40:46 +03:00
05dca3d2ce Excludes honeypot from subscription management form 2017-08-24 11:17:40 +02:00
ec35b90f3e Fix react warning
[MAILPOET-1011]
2017-08-24 11:01:33 +02:00
1b7e3a997f Fix not fully formated selector
[MAILPOET-1011]
2017-08-24 10:23:42 +02:00
c598537025 Remove empty lines 2017-08-24 09:16:51 +02:00
6f149e3ec4 tests: quote-props 2017-08-24 09:16:51 +02:00
d181bde0e9 tests: quotes 2017-08-24 09:16:51 +02:00
2985705b14 ES6: quote-props 2017-08-24 09:16:51 +02:00
6ce925fbe8 ES6: quotes 2017-08-24 09:16:51 +02:00
b8aceff61f ES5: quote-props 2017-08-24 09:16:51 +02:00
cd091c2af6 ES5: quotes 2017-08-24 09:16:51 +02:00
510cacf2fd Don't process the wysija_form shortcode to allow MP2 forms to work [MAILPOET-1067] 2017-08-24 08:22:10 +03:00
eac6b1b414 Corrects coding style 2017-08-23 11:45:33 -04:00
316fa91a10 Moves AccessControl initialization outside of API to Initializer 2017-08-23 11:28:09 -04:00
7c23415d26 Updates unit test as a result of AccessControl implementation 2017-08-23 11:28:09 -04:00
28320cdbb6 Updates permission validation method on AccessControl
Adds/updates unit tests
2017-08-23 11:28:08 -04:00
48f3ae4ea1 Adds access control unit tests 2017-08-23 11:28:08 -04:00
e47c8bc701 Adds access control tests for Router 2017-08-23 11:28:08 -04:00
78429d8f91 Validates global permission at the AccessControl level
Changes error response code on invalid permission
2017-08-23 11:27:54 -04:00
80c4eeed5e Merge pull request #1055 from mailpoet/new-poll
New poll [MAILPOET-1040]
2017-08-23 14:45:05 +02:00
5985d659f9 New poll
[MAILPOET-1040]
2017-08-23 14:11:35 +02:00
638de3cf55 Merge pull request #1054 from mailpoet/coverage-fix
Coverage fix [MAILPOET-1064]
2017-08-23 13:41:43 +03:00
967fa09f4f Remove redundant build
[MAILPOET-1064]
2017-08-23 12:32:34 +02:00
a15e1200b5 Upgrade codeception version
[MAILPOET-1064]
2017-08-23 12:32:34 +02:00
a15b46cbab Fix Code coverage reporting
[MAILPOET-1064]
2017-08-23 12:15:56 +02:00
dcb0b45c21 Save newsletter before navigating away when clicked on "Next" button 2017-08-22 17:34:23 +03:00
14810a22b5 Bump up release version to 3.0.0-rc.1.0.4 2017-08-22 16:26:48 +03:00
1b756ef0b2 Adds access management to router and updates endpoints accordingly 2017-08-22 09:06:20 -04:00
5553817f9a Creates method to get user's first capability 2017-08-22 09:06:20 -04:00
4b7fb3ae3d Updates access permission names to improve clarity 2017-08-22 09:06:20 -04:00
efa231b08f Removes AccessControl from Migrator and Changelog 2017-08-22 09:06:20 -04:00
8d8dfaa11f Uses Intializer to check permissions before running Activator 2017-08-22 09:06:20 -04:00
5ba2c4bc3a Removes AccessControl from individual API endpoints 2017-08-22 09:06:20 -04:00
788494ec47 Updates API initialization 2017-08-22 09:06:20 -04:00
5e7f9e3edf Passes AccessControl to JSON API via constructor parameter
Removes passing AccessControl to individual API endpoints
2017-08-22 09:06:20 -04:00
2e5554a3af Refactors AccessControl and passes it as dependency to JSON API and Menu 2017-08-22 09:06:20 -04:00
51fbf29031 Modifies Activator to use AccessControl 2017-08-22 09:06:19 -04:00
c3c6ce989c Modifies Menu to use AccessControl 2017-08-22 09:06:19 -04:00
a241d0c7bc Modifies JSON API to use AccessControl 2017-08-22 09:06:19 -04:00
632bce7894 Adds AccessControl class that defines permissions for major plugin
operations
2017-08-22 09:04:39 -04:00
1151354278 Conditionally uses set_time_limit() when function is not disabled 2017-08-22 09:04:39 -04:00
c12752403f Fix build 2017-08-22 13:40:11 +02:00
d3ff174e9f Fix inability to deactivate MSS [MAILPOET-1058] 2017-08-22 13:35:51 +02:00
03df7e723c Merge pull request #1051 from mailpoet/composer-fix
Fix composer.lock [PREMIUM-35]
2017-08-22 12:24:40 +03:00
6c8fe8413a Merge pull request #1047 from mailpoet/eslint-assignment
Eslint assignment [MAILPOET-1033]
2017-08-22 09:59:35 +02:00
89b0b51980 Merge pull request #1050 from mailpoet/new-poll
New poll [MAILPOET-1042]
2017-08-21 11:57:26 -04:00
fa1ab733f8 Fix composer.lock
[PREMIUM-35]
2017-08-21 16:34:43 +02:00
127022645e Revert "Update composer.lock"
This reverts commit b1d26b8cee.
2017-08-21 13:39:15 +02:00
b1d26b8cee Update composer.lock
[PREMIUM-35]
2017-08-21 13:26:13 +02:00
f07b90adde Merge pull request #1049 from mailpoet/safari-unsafe
This is a non-secure form. [MAILPOET-1063]
2017-08-21 13:31:50 +03:00
b3884d06a8 New poll
[MAILPOET-1042]
2017-08-21 11:02:49 +02:00
abf1d817f4 Remove form action
[MAILPOET-1063]
2017-08-21 10:37:13 +02:00
c7b7b0abad Merge pull request #1011 from mailpoet/acceptance-tests
Initial acceptance testing setup [MAILPOET-997]
2017-08-17 19:28:27 -04:00
8540e5eea9 Merge pull request #1017 from mailpoet/rerender-newsletter
Rerender newsletter [MAILPOET-675]
2017-08-17 16:19:16 +03:00
09ed3d4fa6 refactoring the code 2017-08-17 12:16:40 +00:00
b96dc8b3f7 Merge pull request #1048 from mailpoet/migration-fix
Skip migration on empty db
2017-08-17 14:04:47 +03:00
0a4dc3eb38 Skip all migration on empty db 2017-08-17 12:58:33 +02:00
a78af28943 Track newsletter UI events with MixPanel
[MAILPOET-999]
2017-08-17 12:45:12 +02:00
f035d12aaf Skip migration on empty db 2017-08-17 11:55:51 +02:00
6353075f1e Don't delete vendor
[MAILPOET-997]
2017-08-17 08:13:11 +02:00
6c91ca9d31 Reinstall vendor
[MAILPOET-997]
2017-08-17 08:13:11 +02:00
6f8634570c Replace repo directory
[MAILPOET-997]
2017-08-17 08:13:11 +02:00
0efcfad3d1 Increase docker compose timeout
[MAILPOET-997]
2017-08-17 08:13:11 +02:00
5d7b54ab22 Add circle ci configuration
[MAILPOET-997]
2017-08-17 08:13:11 +02:00
ad1f6e2a8e Fix caching problem
[MAILPOET-997]
2017-08-17 08:13:11 +02:00
d844b7e47f Initial acceptance testing setup
[MAILPOET-997]
2017-08-17 08:13:10 +02:00
36d4e3eb15 Merge pull request #1034 from mailpoet/ui-help-tooltips
Ui help tooltips [MAILPOET-976]
2017-08-16 19:23:13 -04:00
853f686dde List and scheduling inputs are disabled instead of being hidden 2017-08-16 14:44:42 +00:00
d17486bac4 Merge pull request #1046 from mailpoet/spambot-forms
Add honeypot field for spambot [MAILPOET-1014]
2017-08-16 16:47:21 +03:00
4226684c5a Make tests more obvious
[MAILPOET-1014]
2017-08-16 15:32:07 +02:00
364dd1b2a3 Move field obfuscation into own class
[MAILPOET-1014]
2017-08-16 14:58:31 +02:00
eaf10e8a96 Fix no-param-reassign in tests
[MAILPOET-1033]
2017-08-16 12:34:59 +02:00
bac494ac0d Fix no-multi-assign in tests
[MAILPOET-1033]
2017-08-16 12:25:15 +02:00
acd2b9f51e Fix no-param-reassign in ES5
[MAILPOET-1033]
2017-08-16 12:22:56 +02:00
27c6fa5ff4 Fix no-multi-assign in ES5
[MAILPOET-1033]
2017-08-16 10:44:33 +02:00
89b51b6215 Fix no-cond-assign in ES5
[MAILPOET-1033]
2017-08-16 10:39:43 +02:00
7725391eff Fix no-return-assign in ES5
[MAILPOET-1033]
2017-08-16 10:30:11 +02:00
a37117cfa3 Fix no-param-reassign in ES6
[MAILPOET-1033]
2017-08-16 10:25:18 +02:00
856331caa4 Merge pull request #1044 from mailpoet/post_excerpt_hook
Adds a hook to specify custom max post excerpt length [MAILPOET-1056]
2017-08-15 16:45:26 +02:00
9117ae1a27 Fixing more bugs. Lists and scheduling options are hidden when editing a newsletter that is being sent 2017-08-15 14:39:02 +00:00
4aae8d56e5 Tooltip improvements
[MAILPOET-976]
2017-08-15 16:08:30 +02:00
033d527db9 fix some bugs 2017-08-15 12:55:06 +00:00
b2b1f7ff71 tests fixed 2017-08-15 12:55:06 +00:00
de261d6179 Added confirmation when 'edit' is clicked 2017-08-15 12:55:05 +00:00
a587b0a966 Links are not re-hashed when re-rendering the same newsletter 2017-08-15 12:55:05 +00:00
441aa14bcb fix js typo 2017-08-15 12:55:04 +00:00
4b4b5dd556 show 'Resume' button if the Newsletter was paused. 2017-08-15 12:55:04 +00:00
df9ba7e6c8 clearing the sending queue rendered body and subject
The new body and subject would be automatically rendered when
resuming sending
2017-08-15 12:55:04 +00:00
ca4f1c9387 Pause sending queue when editting the newsletter
An ajax request is sent to pause the sending queue when the editor
is displayed. If the newsletter is still a draft or has been already
sent; the error reponse is simply ignored. Otherwise a notice is
displayed specifying that the Email sending has been paused.
2017-08-15 12:55:03 +00:00
8c151d2d11 Fix failling test
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
78fb9ba46f Fix "Unexpected trailing comma"
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
3a0669e1a2 Fix react/no-danger eslint problem
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
c466e53681 Add tooltip to image heading
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
d02aed870e Add tooltip to image full width
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
fad7ff0018 Add tooltip to preheader
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
84a3f98725 Add tooltip to subject line
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
1c3e968ec4 Add tooltip to editor styles
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
c090a8260b Add tooltip to editor previw
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
65726de7de Add tooltip to send
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
33fe302f0d Add tooltip to import a template
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
2d702dd5d3 Add simple tooltip to help
[MAILPOET-976]
2017-08-15 14:49:22 +02:00
18f208cf47 Add honeypot field for spambot
[MAILPOET-1014]
2017-08-15 14:33:45 +02:00
49318791fc Adds hook to modify max post excerpt 2017-08-14 20:55:49 -04:00
a5abdd28e1 Removes unused constructor parameter 2017-08-14 20:55:42 -04:00
217 changed files with 6044 additions and 2810 deletions

View File

@ -55,6 +55,48 @@ jobs:
- store_artifacts: - store_artifacts:
path: /tmp/fake-mailer/ path: /tmp/fake-mailer/
destination: fake-mailer destination: fake-mailer
acceptance_tests:
working_directory: /home/circleci/mailpoet
machine: true
steps:
- checkout
- run:
name: "Set up virtual host"
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
- restore_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
- restore_cache:
key: npm-{{ checksum "package.json" }}
- run:
name: "Set up test environment"
command: |
sudo apt-get update
sudo apt-get install circleci-php-5.6.23
sudo rm /usr/bin/php
sudo ln -s /opt/circleci/php/5.6.23/bin/php /usr/bin/php
# Install NodeJS+NPM
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install nodejs build-essential
# install plugin dependencies
curl -sS https://getcomposer.org/installer | php
php composer.phar install
./do install
- save_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
paths:
- vendor
- save_cache:
key: npm-{{ checksum "package.json" }}
paths:
- node_modules
- run:
name: Run acceptance tests
command: |
docker-compose run codeception --steps --debug -vvv --html --xml
- store_artifacts:
path: ~/mailpoet/tests/acceptance-tests/_output
- store_test_results:
path: ~/mailpoet/tests/acceptance-tests/_output
php7: php7:
working_directory: /home/circleci/mailpoet working_directory: /home/circleci/mailpoet
docker: docker:
@ -92,3 +134,4 @@ workflows:
jobs: jobs:
- qa_js_php5 - qa_js_php5
- php7 - php7
- acceptance_tests

View File

@ -9,11 +9,6 @@
}, },
"rules": { "rules": {
"import/no-amd": 0, "import/no-amd": 0,
"space-before-function-paren": 0, "space-before-function-paren": 0,
"prefer-arrow-callback": 0, "prefer-arrow-callback": 0,
"no-undef": 0, "no-undef": 0,
@ -33,10 +28,8 @@
"no-useless-return": 0, "no-useless-return": 0,
"array-callback-return": 0, "array-callback-return": 0,
"new-cap": 0, "new-cap": 0,
"no-return-assign": 0,
"no-continue": 0, "no-continue": 0,
"no-new": 0, "no-new": 0,
"no-cond-assign": 0,
"space-unary-ops": 0, "space-unary-ops": 0,
"no-redeclare": 0, "no-redeclare": 0,
"no-console": 0, "no-console": 0,
@ -60,7 +53,6 @@
"space-in-parens": 0, "space-in-parens": 0,
"semi": 0, "semi": 0,
"max-len": 0, "max-len": 0,
"no-multi-assign": 0,
"no-trailing-spaces": 0, "no-trailing-spaces": 0,
"global-require": 0, "global-require": 0,
"no-throw-literal": 0, "no-throw-literal": 0,
@ -75,7 +67,6 @@
"one-var": 0, "one-var": 0,
"camelcase": 0, "camelcase": 0,
"spaced-comment": 0, "spaced-comment": 0,
"quotes": 0,
"padded-blocks": 0, "padded-blocks": 0,
"object-curly-spacing": 0, "object-curly-spacing": 0,
"strict": 0, "strict": 0,
@ -85,13 +76,11 @@
"no-unused-vars": 0, "no-unused-vars": 0,
"object-shorthand": 0, "object-shorthand": 0,
"new-parens": 0, "new-parens": 0,
"no-param-reassign": 0,
"keyword-spacing": 0, "keyword-spacing": 0,
"eol-last": 0, "eol-last": 0,
"dot-notation": 0, "dot-notation": 0,
"linebreak-style": 0, "linebreak-style": 0,
"indent": 0, "indent": 0,
"quote-props": 0,
"prefer-template": 0, "prefer-template": 0,
"func-names": 0 "func-names": 0
} }

View File

@ -12,11 +12,7 @@
}, },
"rules": { "rules": {
"comma-dangle": ["error", "always-multiline"], "comma-dangle": ["error", "always-multiline"],
"import/no-amd": 0, "import/no-amd": 0,
"react/no-multi-comp": 0, "react/no-multi-comp": 0,
"react/sort-comp": 0, "react/sort-comp": 0,
"react/jsx-max-props-per-line": 0, "react/jsx-max-props-per-line": 0,
@ -37,11 +33,9 @@
"react/jsx-curly-spacing": 0, "react/jsx-curly-spacing": 0,
"react/no-did-mount-set-state": 0, "react/no-did-mount-set-state": 0,
"react/prefer-stateless-function": 0, "react/prefer-stateless-function": 0,
"jsx-a11y/label-has-for": 0, "jsx-a11y/label-has-for": 0,
"jsx-a11y/no-static-element-interactions": 0, "jsx-a11y/no-static-element-interactions": 0,
"jsx-a11y/alt-text": 0, "jsx-a11y/alt-text": 0,
"func-names": 0, "func-names": 0,
"object-shorthand": 0, "object-shorthand": 0,
"no-bitwise": 0, "no-bitwise": 0,
@ -49,7 +43,6 @@
"prefer-template": 0, "prefer-template": 0,
"keyword-spacing": 0, "keyword-spacing": 0,
"default-case": 0, "default-case": 0,
"quote-props": 0,
"array-callback-return": 0, "array-callback-return": 0,
"consistent-return": 0, "consistent-return": 0,
"no-unreachable": 0, "no-unreachable": 0,
@ -59,7 +52,6 @@
"import/no-extraneous-dependencies": 0, "import/no-extraneous-dependencies": 0,
"camelcase": 0, "camelcase": 0,
"template-curly-spacing": 0, "template-curly-spacing": 0,
"quotes": 0,
"eqeqeq": 0, "eqeqeq": 0,
"no-lonely-if": 0, "no-lonely-if": 0,
"space-unary-ops": 0, "space-unary-ops": 0,
@ -80,7 +72,6 @@
"no-sequences": 0, "no-sequences": 0,
"no-extra-boolean-cast": 0, "no-extra-boolean-cast": 0,
"dot-notation": 0, "dot-notation": 0,
"no-param-reassign": 0,
"no-shadow": 0, "no-shadow": 0,
"one-var": 0, "one-var": 0,
"no-alert": 0, "no-alert": 0,

View File

@ -9,9 +9,6 @@
}, },
"rules": { "rules": {
"import/no-amd": 0, "import/no-amd": 0,
"no-undef": 0, "no-undef": 0,
"one-var": 0, "one-var": 0,
"indent": 0, "indent": 0,
@ -22,23 +19,19 @@
"semi": 0, "semi": 0,
"keyword-spacing": 0, "keyword-spacing": 0,
"no-bitwise": 0, "no-bitwise": 0,
"no-multi-assign": 0,
"newline-per-chained-call": 0, "newline-per-chained-call": 0,
"no-spaced-func": 0, "no-spaced-func": 0,
"func-call-spacing": 0, "func-call-spacing": 0,
"max-len": 0, "max-len": 0,
"space-unary-ops": 0, "space-unary-ops": 0,
"quotes": 0,
"no-unused-vars": 0, "no-unused-vars": 0,
"no-unused-expressions": 0, "no-unused-expressions": 0,
"no-underscore-dangle": 0, "no-underscore-dangle": 0,
"quote-props": 0,
"no-shadow": 0, "no-shadow": 0,
"padded-blocks": 0, "padded-blocks": 0,
"vars-on-top": 0, "vars-on-top": 0,
"space-before-blocks": 0, "space-before-blocks": 0,
"object-curly-spacing": 0, "object-curly-spacing": 0,
"no-param-reassign": 0,
"one-var-declaration-per-line": 0, "one-var-declaration-per-line": 0,
"func-names": 0, "func-names": 0,
"space-before-function-paren": 0 "space-before-function-paren": 0

1
.gitignore vendored
View File

@ -3,7 +3,6 @@ TODO
composer.phar composer.phar
/vendor /vendor
tests/_output/* tests/_output/*
tests/acceptance.suite.yml
tests/_support/_generated/* tests/_support/_generated/*
node_modules node_modules
.env .env

39
Dockerfile Normal file
View File

@ -0,0 +1,39 @@
FROM php:5.6-cli
ENV COMPOSER_ALLOW_SUPERUSER=1
RUN apt-get update && \
apt-get -y install \
git \
zlib1g-dev \
libssl-dev \
mysql-client \
sudo less \
--no-install-recommends && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
docker-php-ext-install bcmath zip mysqli pdo pdo_mysql && \
echo "date.timezone = UTC" >> /usr/local/etc/php/php.ini && \
curl -sS https://getcomposer.org/installer | php -- \
--filename=composer \
--install-dir=/usr/local/bin && \
composer global require --optimize-autoloader "hirak/prestissimo" && \
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
chmod +x wp-cli.phar && \
mv wp-cli.phar /usr/local/bin/wp
# Prepare application
WORKDIR /repo
# Install vendor
COPY ./composer.json /repo/composer.json
# Add source-code
COPY . /repo
WORKDIR /wp-core/wp-content/plugins/mailpoet
ENV WP_TEST_PATH=/wp-core
ADD docker-entrypoint.sh /
RUN ["chmod", "+x", "/docker-entrypoint.sh"]

View File

@ -180,3 +180,21 @@ Run 'svn copy ...' to tag the release
It's quite literal: you can review the changes to be pushed and if you're satisfied, run the suggested command to finish the release publishing process. It's quite literal: you can review the changes to be pushed and if you're satisfied, run the suggested command to finish the release publishing process.
If you're confident, execute `./do publish --force` and your release will be published to the remote SVN repository without manual intervention (automatically). For easier authentication you might want to set `WP_SVN_USERNAME` and `WP_SVN_PASSWORD` environment variables. If you're confident, execute `./do publish --force` and your release will be published to the remote SVN repository without manual intervention (automatically). For easier authentication you might want to set `WP_SVN_USERNAME` and `WP_SVN_PASSWORD` environment variables.
# Acceptance testing
We are using Gravity Flow plugin's setup as an example for our acceptance test suite: https://www.stevenhenty.com/learn-acceptance-testing-deeply/
From the article above:
_Windows users only: enable hard drive sharing in the Docker settings._
The browser runs in a docker container. You can use a VNC client to watch the test run, follow instructions in official
repo: https://github.com/SeleniumHQ/docker-selenium
If youre on a Mac, you can open vnc://localhost:5900 in Safari to watch the tests running in Chrome. If youre on Windows, youll need a VNC client. Password: secret.
To run tests:
```sh
$ ./do test:acceptance
```

View File

@ -154,9 +154,8 @@ class RoboFile extends \Robo\Tasks {
function testUnit($opts=['file' => null, 'xml' => false]) { function testUnit($opts=['file' => null, 'xml' => false]) {
$this->loadEnv(); $this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$command = 'vendor/bin/codecept run unit -f '.(($opts['file']) ? $opts['file'] : ''); $command = 'vendor/bin/codecept run unit -c codeception.unit.yml -f '.(($opts['file']) ? $opts['file'] : '');
if($opts['xml']) { if($opts['xml']) {
$command .= ' --xml'; $command .= ' --xml';
@ -166,9 +165,8 @@ class RoboFile extends \Robo\Tasks {
function testCoverage($opts=['file' => null, 'xml' => false]) { function testCoverage($opts=['file' => null, 'xml' => false]) {
$this->loadEnv(); $this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$command = join(' ', array( $command = join(' ', array(
'vendor/bin/codecept run', 'vendor/bin/codecept run unit -c codeception.unit.yml ',
(($opts['file']) ? $opts['file'] : ''), (($opts['file']) ? $opts['file'] : ''),
'--coverage', '--coverage',
($opts['xml']) ? '--coverage-xml' : '--coverage-html' ($opts['xml']) ? '--coverage-xml' : '--coverage-html'
@ -201,9 +199,9 @@ class RoboFile extends \Robo\Tasks {
function testDebug($opts=['file' => null, 'xml' => false]) { function testDebug($opts=['file' => null, 'xml' => false]) {
$this->loadEnv(); $this->loadEnv();
$this->_exec('vendor/bin/codecept build'); $this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
$command = 'vendor/bin/codecept run unit --debug -f '.(($opts['file']) ? $opts['file'] : ''); $command = 'vendor/bin/codecept run unit -c codeception.unit.yml --debug -f '.(($opts['file']) ? $opts['file'] : '');
if($opts['xml']) { if($opts['xml']) {
$command .= ' --xml'; $command .= ' --xml';
@ -211,10 +209,14 @@ class RoboFile extends \Robo\Tasks {
return $this->_exec($command); return $this->_exec($command);
} }
function testAcceptance() {
return $this->_exec('COMPOSE_HTTP_TIMEOUT=200 docker-compose run codeception --steps --debug -vvv');
}
function testFailed() { function testFailed() {
$this->loadEnv(); $this->loadEnv();
$this->_exec('vendor/bin/codecept build'); $this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
return $this->_exec('vendor/bin/codecept run -g failed'); return $this->_exec('vendor/bin/codecept run -c codeception.unit.yml -g failed');
} }
function qa() { function qa() {

View File

@ -179,6 +179,28 @@ select.mailpoet_font-size
width: 100% width: 100%
box-sizing: border-box box-sizing: border-box
.tooltip-help-designer-subject-line div, .tooltip-help-designer-preheader div
z-index: 100001
.tooltip-help-send-preview
position: absolute
right: 15px
.tooltip-help-designer-ideal-width
color: #656565
text-transform: none
margin-left: 5px
font-weight: normal
.tooltip-help-designer-styles
position: absolute
top: 40px
.tooltip-help-designer-full-width .dashicons
line-height 34px
.tooltip-help-designer-full-width span
line-height 1.4em
.mailpoet_button_primary .mailpoet_button_primary
border-color: $button-primary-border-color border-color: $button-primary-border-color
background-color: $button-primary-background-color background-color: $button-primary-background-color

View File

@ -54,6 +54,9 @@
#mailpoet_mta_activate #mailpoet_mta_activate
visibility hidden visibility hidden
.tooltip.dashicons.dashicons-editor-help
line-height: 1.4
ul.sending-method-benefits ul.sending-method-benefits
list-style-type: none list-style-type: none
margin-bottom: 2em margin-bottom: 2em

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 B

After

Width:  |  Height:  |  Size: 814 B

View File

@ -2,7 +2,7 @@ function requestFailed(errorMessage, xhr) {
if (xhr.responseJSON) { if (xhr.responseJSON) {
return xhr.responseJSON; return xhr.responseJSON;
} }
var message = errorMessage.replace("%d", xhr.status); var message = errorMessage.replace('%d', xhr.status);
return { return {
errors: [ errors: [
{ {
@ -12,7 +12,8 @@ function requestFailed(errorMessage, xhr) {
}; };
} }
define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery, _) { define('ajax', ['mailpoet', 'jquery', 'underscore'], function(mp, jQuery, _) {
var MailPoet = mp;
MailPoet.Ajax = { MailPoet.Ajax = {
version: 0.5, version: 0.5,

View File

@ -18,13 +18,14 @@
var eventsCache = []; var eventsCache = [];
function track(name, data){ function track(name, data){
if (typeof window.mixpanel.track !== "function") { if (typeof window.mixpanel.track !== 'function') {
window.mixpanel.init(window.mixpanelTrackingId); window.mixpanel.init(window.mixpanelTrackingId);
} }
window.mixpanel.track(name, data); window.mixpanel.track(name, data);
} }
function exportMixpanel(MailPoet) { function exportMixpanel(mp) {
var MailPoet = mp;
MailPoet.forceTrackEvent = track; MailPoet.forceTrackEvent = track;
if (window.mailpoet_analytics_enabled) { if (window.mailpoet_analytics_enabled) {
@ -43,7 +44,7 @@ function trackCachedEvents() {
} }
function initializeMixpanelWhenLoaded() { function initializeMixpanelWhenLoaded() {
if (typeof window.mixpanel === "object") { if (typeof window.mixpanel === 'object') {
exportMixpanel(MailPoet); exportMixpanel(MailPoet);
trackCachedEvents(); trackCachedEvents();
} else { } else {
@ -61,7 +62,8 @@ function cacheEvent(forced, name, data) {
define( define(
['mailpoet', 'underscore'], ['mailpoet', 'underscore'],
function(MailPoet, _) { function(mp, _) {
var MailPoet = mp;
MailPoet.trackEvent = _.partial(cacheEvent, false); MailPoet.trackEvent = _.partial(cacheEvent, false);
MailPoet.forceTrackEvent = _.partial(cacheEvent, true); MailPoet.forceTrackEvent = _.partial(cacheEvent, true);

View File

@ -4,12 +4,14 @@ define('date',
'jquery', 'jquery',
'moment' 'moment'
], function( ], function(
MailPoet, mp,
jQuery, jQuery,
Moment Moment
) { ) {
'use strict'; 'use strict';
var MailPoet = mp;
MailPoet.Date = { MailPoet.Date = {
version: 0.1, version: 0.1,
options: {}, options: {},
@ -17,8 +19,8 @@ define('date',
offset: 0, offset: 0,
format: 'F, d Y H:i:s' format: 'F, d Y H:i:s'
}, },
init: function(options) { init: function (opts) {
options = options || {}; var options = opts || {};
// set UTC offset // set UTC offset
if ( if (
@ -39,16 +41,16 @@ define('date',
return this; return this;
}, },
format: function(date, options) { format: function(date, opts) {
options = options || {}; var options = opts || {};
this.init(options); this.init(options);
var date = Moment(date, this.convertFormat(options.parseFormat)); var momentDate = Moment(date, this.convertFormat(options.parseFormat));
if (options.offset === 0) date = date.utc(); if (options.offset === 0) momentDate = momentDate.utc();
return date.format(this.convertFormat(this.options.format)); return momentDate.format(this.convertFormat(this.options.format));
}, },
toDate: function(date, options) { toDate: function(date, opts) {
options = options || {}; var options = opts || {};
this.init(options); this.init(options);
return Moment(date, this.convertFormat(options.parseFormat)).toDate(); return Moment(date, this.convertFormat(options.parseFormat)).toDate();
@ -143,7 +145,8 @@ define('date',
var convertedFormat = []; var convertedFormat = [];
var escapeToken = false; var escapeToken = false;
for(var index = 0, token = ''; token = format.charAt(index); index++){ for(var index = 0, token = ''; format.charAt(index); index += 1){
token = format.charAt(index);
if (escapeToken === true) { if (escapeToken === true) {
convertedFormat.push('['+token+']'); convertedFormat.push('['+token+']');
escapeToken = false; escapeToken = false;

View File

@ -143,28 +143,28 @@ define([
switch(dateType) { switch(dateType) {
case 'year_month_day': case 'year_month_day':
value = { value = {
'year': this.state.year, year: this.state.year,
'month': this.state.month, month: this.state.month,
'day': this.state.day, day: this.state.day,
}; };
break; break;
case 'year_month': case 'year_month':
value = { value = {
'year': this.state.year, year: this.state.year,
'month': this.state.month, month: this.state.month,
}; };
break; break;
case 'month': case 'month':
value = { value = {
'month': this.state.month, month: this.state.month,
}; };
break; break;
case 'year': case 'year':
value = { value = {
'year': this.state.year, year: this.state.year,
}; };
break; break;
} }

View File

@ -28,12 +28,13 @@ define([
} }
let field = false; let field = false;
let dataField = data.field;
if(data.field['field'] !== undefined) { if(data.field['field'] !== undefined) {
data.field = jQuery.merge(data.field, data.field.field); dataField = jQuery.merge(dataField, data.field.field);
} }
switch(data.field.type) { switch(dataField.type) {
case 'text': case 'text':
field = (<FormFieldText {...data} />); field = (<FormFieldText {...data} />);
break; break;

View File

@ -180,6 +180,7 @@ define([
<select <select
id={ this.props.field.id || this.props.field.name } id={ this.props.field.id || this.props.field.name }
ref="select" ref="select"
disabled={this.props.field.disabled}
data-placeholder={ this.props.field.placeholder } data-placeholder={ this.props.field.placeholder }
multiple={ this.props.field.multiple } multiple={ this.props.field.multiple }
defaultValue={ this.getSelectedValues() } defaultValue={ this.getSelectedValues() }

View File

@ -166,7 +166,7 @@ define(
const formClasses = classNames( const formClasses = classNames(
'mailpoet_form', 'mailpoet_form',
{ 'mailpoet_form_loading': this.state.loading || this.props.loading } { mailpoet_form_loading: this.state.loading || this.props.loading }
); );
let beforeFormContent = false; let beforeFormContent = false;

View File

@ -11,12 +11,14 @@ Object.extend(document, (function() {
var cache = Event.cacheDelegated; var cache = Event.cacheDelegated;
function getCacheForSelector(selector) { function getCacheForSelector(selector) {
return cache[selector] = cache[selector] || {}; cache[selector] = cache[selector] || {};
return cache[selector];
} }
function getWrappersForSelector(selector, eventName) { function getWrappersForSelector(selector, eventName) {
var c = getCacheForSelector(selector); var c = getCacheForSelector(selector);
return c[eventName] = c[eventName] || []; c[eventName] = c[eventName] || [];
return c[eventName];
} }
function findWrapper(selector, eventName, handler) { function findWrapper(selector, eventName, handler) {
@ -79,8 +81,8 @@ Object.extend(document, (function() {
})()); })());
var Observable = (function() { var Observable = (function() {
function getEventName(name, namespace) { function getEventName(nameA, namespace) {
name = name.substring(2); var name = nameA.substring(2);
if(namespace) name = namespace + ':' + name; if(namespace) name = namespace + ':' + name;
return name.underscore().split('_').join(':'); return name.underscore().split('_').join(':');
} }
@ -317,10 +319,10 @@ var WysijaForm = {
save: function() { save: function() {
var position = 1, var position = 1,
data = { data = {
'name': $F('mailpoet_form_name'), name: $F('mailpoet_form_name'),
'settings': $('mailpoet_form_settings').serialize(true), settings: $('mailpoet_form_settings').serialize(true),
'body': [], body: [],
'styles': (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null styles: (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
}; };
// body // body
WysijaForm.getBlocks().each(function(b) { WysijaForm.getBlocks().each(function(b) {
@ -574,7 +576,8 @@ var WysijaForm = {
WysijaForm.locks.showingTools = false; WysijaForm.locks.showingTools = false;
}, },
instances: {}, instances: {},
get: function(element, type) { get: function(element, typ) {
var type = typ;
if(type === undefined) type = 'block'; if(type === undefined) type = 'block';
// identify element // identify element
var id = element.identify(); var id = element.identify();
@ -691,7 +694,7 @@ WysijaForm.DraggableItem = Class.create({
return this.element.up('ul'); return this.element.up('ul');
}, },
insert: function() { insert: function() {
$$("body")[0].insert(this.clone); $$('body')[0].insert(this.clone);
}, },
onMousedown: function(event) { onMousedown: function(event) {
var draggable = new Draggable(this.clone, { var draggable = new Draggable(this.clone, {
@ -893,7 +896,8 @@ WysijaForm.Block = Class.create({
}); });
/* Invoked on item dropped */ /* Invoked on item dropped */
WysijaForm.Block.create = function(block, target) { WysijaForm.Block.create = function(createBlock, target) {
var block = createBlock;
if($('form_template_' + block.type) === null) { if($('form_template_' + block.type) === null) {
return false; return false;
} }
@ -1050,7 +1054,8 @@ function info(value) {
var noop = function() {}; var noop = function() {};
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn']; var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
var length = methods.length; var length = methods.length;
var console = window.console = {}; window.console = {};
var console = {};
while(length--) { while(length--) {
console[methods[length]] = noop; console[methods[length]] = noop;
} }

View File

@ -19,7 +19,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
} }
// set date format // 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 // check if we passed a timestamp
if(parseInt(timestamp, 10) == timestamp) { if(parseInt(timestamp, 10) == timestamp) {
return moment.unix(timestamp).format(f); return moment.unix(timestamp).format(f);
@ -67,7 +67,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
}); });
Handlebars.registerHelper('nl2br', function(value, block) { Handlebars.registerHelper('nl2br', function(value, block) {
return value.gsub("\n", "<br />"); return value.gsub('\n', '<br />');
}); });
Handlebars.registerHelper('json_encode', function(value, block) { Handlebars.registerHelper('json_encode', function(value, block) {
@ -78,7 +78,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
return JSON.parse(value); return JSON.parse(value);
}); });
Handlebars.registerHelper('url', function(value, block) { Handlebars.registerHelper('url', function(value, block) {
var url = window.location.protocol + "//" + window.location.host + window.location.pathname; var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
return url + value; return url + value;
}); });
@ -99,7 +99,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
// extract all lines into an array // 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 // remove header & footer
lines.shift(); lines.shift();
@ -125,12 +125,13 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
* @return {String} The truncated string. * @return {String} The truncated string.
*/ */
Handlebars.registerHelper('ellipsis', function (str, limit, append) { Handlebars.registerHelper('ellipsis', function (str, limit, append) {
if (append === undefined) { var strAppend = append;
append = ''; if (strAppend === undefined) {
strAppend = '';
} }
var sanitized = str.replace(/(<([^>]+)>)/g, ''); var sanitized = str.replace(/(<([^>]+)>)/g, '');
if (sanitized.length > limit) { if (sanitized.length > limit) {
return sanitized.substr(0, limit - append.length) + append; return sanitized.substr(0, limit - strAppend.length) + strAppend;
} else { } else {
return sanitized; return sanitized;
} }
@ -147,10 +148,10 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
case 'Courier New': return new Handlebars.SafeString("'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace"); case 'Courier New': return new Handlebars.SafeString("'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace");
case 'Georgia': return new Handlebars.SafeString("Georgia, Times, 'Times New Roman', serif"); case 'Georgia': return new Handlebars.SafeString("Georgia, Times, 'Times New Roman', serif");
case 'Lucida': return new Handlebars.SafeString("'Lucida Sans Unicode', 'Lucida Grande', sans-serif"); case 'Lucida': return new Handlebars.SafeString("'Lucida Sans Unicode', 'Lucida Grande', sans-serif");
case 'Tahoma': return new Handlebars.SafeString("Tahoma, Verdana, Segoe, sans-serif"); case 'Tahoma': return new Handlebars.SafeString('Tahoma, Verdana, Segoe, sans-serif');
case 'Times New Roman': return new Handlebars.SafeString("'Times New Roman', Times, Baskerville, Georgia, serif"); case 'Times New Roman': return new Handlebars.SafeString("'Times New Roman', Times, Baskerville, Georgia, serif");
case 'Trebuchet MS': return new Handlebars.SafeString("'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif"); case 'Trebuchet MS': return new Handlebars.SafeString("'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif");
case 'Verdana': return new Handlebars.SafeString("Verdana, Geneva, sans-serif"); case 'Verdana': return new Handlebars.SafeString('Verdana, Geneva, sans-serif');
default: return font; default: return font;
} }
}); });

View File

@ -0,0 +1,21 @@
define('helpTooltip', ['mailpoet', 'react', 'react-dom', 'help-tooltip.jsx'],
function (mp, React, ReactDOM, TooltipComponent) {
'use strict';
var MailPoet = mp;
MailPoet.helpTooltip = {
show: function (domContainerNode, opts) {
ReactDOM.render(React.createElement(
TooltipComponent, {
tooltip: opts.tooltip,
tooltipId: opts.tooltipId,
place: opts.place
}
), domContainerNode);
}
};
}
);

View File

@ -0,0 +1,63 @@
import React from 'react';
import ReactTooltip from 'react-tooltip';
import ReactHtmlParser from 'react-html-parser';
function Tooltip(props) {
let tooltipId = props.tooltipId;
let tooltip = props.tooltip;
// tooltip ID must be unique, defaults to tooltip text
if(!props.tooltipId && typeof props.tooltip === 'string') {
tooltipId = props.tooltip;
}
if(typeof props.tooltip === 'string') {
tooltip = (<span
style={{
pointerEvents: 'all',
maxWidth: '400',
display: 'inline-block',
}}
>
{ReactHtmlParser(props.tooltip)}
</span>);
}
return (
<span className={props.className}>
<span
style={{
cursor: 'pointer',
}}
className="tooltip dashicons dashicons-editor-help"
data-event="click"
data-tip
data-for={tooltipId}
>
</span>
<ReactTooltip
globalEventOff="click"
multiline={true}
id={tooltipId}
efect="solid"
place={props.place}
>
{tooltip}
</ReactTooltip>
</span>
);
}
Tooltip.propTypes = {
tooltipId: React.PropTypes.string,
tooltip: React.PropTypes.node.isRequired,
place: React.PropTypes.string,
className: React.PropTypes.string,
};
Tooltip.defaultProps = {
tooltipId: undefined,
place: undefined,
className: undefined,
};
module.exports = Tooltip;

View File

@ -17,10 +17,10 @@ function printData(data) {
return (<textarea return (<textarea
readOnly={true} readOnly={true}
onFocus={handleFocus} onFocus={handleFocus}
value={printableData.join("\n")} value={printableData.join('\n')}
style={{ style={{
width: "100%", width: '100%',
height: "400px", height: '400px',
}} }}
/>); />);
} else { } else {
@ -35,7 +35,7 @@ function KnowledgeBase() {
<Tabs tab="systemInfo" /> <Tabs tab="systemInfo" />
<div className="mailpoet_notice notice inline notice-success" style={{ marginTop: "1em" }}> <div className="mailpoet_notice notice inline notice-success" style={{ marginTop: '1em' }}>
<p>{MailPoet.I18n.t('systemInfoIntro')}</p> <p>{MailPoet.I18n.t('systemInfoIntro')}</p>
</div> </div>

View File

@ -41,6 +41,6 @@ function Tabs(props) {
}; };
Tabs.propTypes = { tab: React.PropTypes.string }; Tabs.propTypes = { tab: React.PropTypes.string };
Tabs.defaultProps = { tab: "knowledgeBase" }; Tabs.defaultProps = { tab: 'knowledgeBase' };
module.exports = Tabs; module.exports = Tabs;

View File

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

View File

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

View File

@ -3,8 +3,9 @@ define(
'jquery' 'jquery'
], ],
function( function(
$ jQuery
) { ) {
var $ = jQuery;
// Combination of jQuery.deparam and jQuery.serializeObject by Ben Alman. // Combination of jQuery.deparam and jQuery.serializeObject by Ben Alman.
/*! /*!
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
@ -24,7 +25,7 @@ define(
*/ */
$.fn.serializeObject = function(coerce) { $.fn.serializeObject = function(coerce) {
var obj = {}, var obj = {},
coerce_types = { 'true': !0, 'false': !1, 'null': null }; coerce_types = { true: !0, false: !1, null: null };
// Iterate over all name=value pairs. // Iterate over all name=value pairs.
$.each( this.serializeArray(), function(j, v){ $.each( this.serializeArray(), function(j, v){
@ -74,9 +75,10 @@ define(
// * Rinse & repeat. // * Rinse & repeat.
for ( ; i <= keys_last; i++ ) { for ( ; i <= keys_last; i++ ) {
key = keys[i] === '' ? cur.length : keys[i]; key = keys[i] === '' ? cur.length : keys[i];
cur = cur[key] = i < keys_last cur[key] = i < keys_last
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ) ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
: val; : val;
cur = cur[key];
} }
} else { } else {

View File

@ -11,7 +11,7 @@ define(['react', 'classnames'], (React, classNames) => {
} }
const classes = classNames( const classes = classNames(
{ 'current' : (group.name === this.props.group) } { current : (group.name === this.props.group) }
); );
return ( return (

View File

@ -10,8 +10,9 @@ const ListingHeader = React.createClass({
}, },
render: function () { render: function () {
const columns = this.props.columns.map((column, index) => { const columns = this.props.columns.map((column, index) => {
column.is_primary = (index === 0); const renderColumn = column;
column.sorted = (this.props.sort_by === column.name) renderColumn.is_primary = (index === 0);
renderColumn.sorted = (this.props.sort_by === column.name)
? this.props.sort_order ? this.props.sort_order
: 'desc'; : 'desc';
return ( return (
@ -19,7 +20,7 @@ const ListingHeader = React.createClass({
onSort={this.props.onSort} onSort={this.props.onSort}
sort_by={this.props.sort_by} sort_by={this.props.sort_by}
key={ 'column-' + index } key={ 'column-' + index }
column={column} /> column={renderColumn} />
); );
}); });
@ -61,9 +62,9 @@ const ListingColumn = React.createClass({
const classes = classNames( const classes = classNames(
'manage-column', 'manage-column',
{ 'column-primary': this.props.column.is_primary }, { 'column-primary': this.props.column.is_primary },
{ 'sortable': this.props.column.sortable }, { sortable: this.props.column.sortable },
this.props.column.sorted, this.props.column.sorted,
{ 'sorted': (this.props.sort_by === this.props.column.name) } { sorted: (this.props.sort_by === this.props.column.name) }
); );
let label; let label;

View File

@ -226,7 +226,7 @@ const ListingItems = React.createClass({
} else { } else {
const select_all_classes = classNames( const select_all_classes = classNames(
'mailpoet_select_all', 'mailpoet_select_all',
{ 'mailpoet_hidden': ( { mailpoet_hidden: (
this.props.selection === false this.props.selection === false
|| (this.props.count <= this.props.limit) || (this.props.count <= this.props.limit)
), ),
@ -260,8 +260,9 @@ const ListingItems = React.createClass({
</tr> </tr>
{this.props.items.map((item, index) => { {this.props.items.map((item, index) => {
item.id = parseInt(item.id, 10); const renderItem = item;
item.selected = (this.props.selected_ids.indexOf(item.id) !== -1); renderItem.id = parseInt(item.id, 10);
renderItem.selected = (this.props.selected_ids.indexOf(renderItem.id) !== -1);
return ( return (
<ListingItem <ListingItem
@ -276,8 +277,8 @@ const ListingItems = React.createClass({
is_selectable={ this.props.is_selectable } is_selectable={ this.props.is_selectable }
item_actions={ this.props.item_actions } item_actions={ this.props.item_actions }
group={ this.props.group } group={ this.props.group }
key={ `item-${item.id}-${index}` } key={ `item-${renderItem.id}-${index}` }
item={ item } /> item={ renderItem } />
); );
})} })}
</tbody> </tbody>
@ -418,16 +419,17 @@ const Listing = React.createClass({
} }
}, },
setBaseUrlParams: function (base_url) { setBaseUrlParams: function (base_url) {
if (base_url.indexOf(':') !== -1) { let ret = base_url;
if (ret.indexOf(':') !== -1) {
const params = this.getParams(); const params = this.getParams();
Object.keys(params).map((key) => { Object.keys(params).map((key) => {
if (base_url.indexOf(':'+key) !== -1) { if (ret.indexOf(':'+key) !== -1) {
base_url = base_url.replace(':'+key, params[key]); ret = ret.replace(':'+key, params[key]);
} }
}); });
} }
return base_url; return ret;
}, },
componentDidMount: function () { componentDidMount: function () {
if (this.isMounted()) { if (this.isMounted()) {
@ -781,7 +783,7 @@ const Listing = React.createClass({
'widefat', 'widefat',
'fixed', 'fixed',
'striped', 'striped',
{ 'mailpoet_listing_loading': this.state.loading } { mailpoet_listing_loading: this.state.loading }
); );
// search // search

View File

@ -1,6 +1,7 @@
define('modal', ['mailpoet', 'jquery'], define('modal', ['mailpoet', 'jquery'],
function(MailPoet, jQuery) { function(mp, jQuery) {
'use strict'; 'use strict';
var MailPoet = mp;
/*************************************************************************** /***************************************************************************
MailPoet Modal: MailPoet Modal:
@ -308,7 +309,6 @@ define('modal', ['mailpoet', 'jquery'],
setDimensions: function() { setDimensions: function() {
switch(this.options.type) { switch(this.options.type) {
case 'popup': case 'popup':
console.log(this.options)
// set popup dimensions // set popup dimensions
jQuery('#mailpoet_popup').css({ jQuery('#mailpoet_popup').css({
width: this.options.width, width: this.options.width,
@ -459,9 +459,9 @@ define('modal', ['mailpoet', 'jquery'],
jQuery('#mailpoet_modal_overlay').hide(); jQuery('#mailpoet_modal_overlay').hide();
return this; return this;
}, },
popup: function(options) { popup: function(opts) {
// get options // get options
options = options || {}; var options = opts || {};
// set modal type // set modal type
options.type = 'popup'; options.type = 'popup';
// set overlay state // set overlay state
@ -473,9 +473,9 @@ define('modal', ['mailpoet', 'jquery'],
return this; return this;
}, },
panel: function(options) { panel: function(opts) {
// get options // get options
options = options || {}; var options = opts || {};
// reset subpanels // reset subpanels
this.subpanels = []; this.subpanels = [];
// set modal type // set modal type

View File

@ -1,5 +1,6 @@
define('mp2migrator', ['mailpoet', 'jquery'], function(MailPoet, jQuery) { define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
'use strict'; 'use strict';
var MailPoet = mp;
MailPoet.MP2Migrator = { MailPoet.MP2Migrator = {
fatal_error: '', fatal_error: '',
@ -27,8 +28,9 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
url: mailpoet_mp2_migrator.log_file_url, url: mailpoet_mp2_migrator.log_file_url,
cache: false cache: false
}).done(function (result) { }).done(function (result) {
jQuery("#logger").html(''); jQuery('#logger').html('');
result.split("\n").forEach(function (row) { 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 row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
} }
@ -37,10 +39,10 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
jQuery('#import-actions').hide(); jQuery('#import-actions').hide();
jQuery('#upgrade-completed').show(); jQuery('#upgrade-completed').show();
} }
jQuery("#logger").append(row + "<br />\n"); jQuery('#logger').append(row + '<br />\n');
}); });
jQuery("#logger").append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span>' + "<br />\n"); jQuery('#logger').append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span>' + '<br />\n');
}).always(function () { }).always(function () {
if(MailPoet.MP2Migrator.is_logging) { if(MailPoet.MP2Migrator.is_logging) {
MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000); MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000);

View File

@ -6,7 +6,8 @@ define([
'underscore', 'underscore',
'handlebars', 'handlebars',
'handlebars_helpers' 'handlebars_helpers'
], function(Backbone, Marionette, Radio, jQuery, _, Handlebars) { ], function(Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
var Radio = BackboneRadio;
var AppView = Marionette.View.extend({ var AppView = Marionette.View.extend({
el: '#mailpoet_editor', el: '#mailpoet_editor',
@ -28,7 +29,9 @@ define([
}, },
getChannel: function(channel) { getChannel: function(channel) {
if (channel === undefined) channel = 'global'; if (channel === undefined) {
return Radio.channel('global');
}
return Radio.channel(channel); return Radio.channel(channel);
} }
}); });

View File

@ -6,8 +6,8 @@
*/ */
define([ define([
'backbone.marionette' 'backbone.marionette'
], function(Marionette) { ], function(BackboneMarionette) {
var Marionette = BackboneMarionette;
var BehaviorsLookup = {}; var BehaviorsLookup = {};
Marionette.Behaviors.behaviorsLookup = function() { Marionette.Behaviors.behaviorsLookup = function() {
return BehaviorsLookup; return BehaviorsLookup;

View File

@ -9,14 +9,15 @@ define([
'mailpoet', 'mailpoet',
'spectrum' 'spectrum'
], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) { ], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) {
var BL = BehaviorsLookup;
BehaviorsLookup.ColorPickerBehavior = Marionette.Behavior.extend({ BL.ColorPickerBehavior = Marionette.Behavior.extend({
onRender: function() { onRender: function() {
this.view.$('.mailpoet_color').spectrum({ this.view.$('.mailpoet_color').spectrum({
clickoutFiresChange: true, clickoutFiresChange: true,
showInput: true, showInput: true,
showInitial: true, showInitial: true,
preferredFormat: "hex6", preferredFormat: 'hex6',
allowEmpty: true, allowEmpty: true,
chooseText: MailPoet.I18n.t('selectColor'), chooseText: MailPoet.I18n.t('selectColor'),
cancelText: MailPoet.I18n.t('cancelColorSelection') cancelText: MailPoet.I18n.t('cancelColorSelection')

View File

@ -11,7 +11,8 @@ define([
'jquery', 'jquery',
'newsletter_editor/behaviors/BehaviorsLookup', 'newsletter_editor/behaviors/BehaviorsLookup',
'interact' 'interact'
], function(Marionette, _, jQuery, BehaviorsLookup, interact) { ], function(Marionette, _, jQuery, BL, interact) {
var BehaviorsLookup = BL;
BehaviorsLookup.ContainerDropZoneBehavior = Marionette.Behavior.extend({ BehaviorsLookup.ContainerDropZoneBehavior = Marionette.Behavior.extend({
defaults: { defaults: {
@ -268,7 +269,7 @@ define([
// 2. Remove visual markings of drop position visualization // 2. Remove visual markings of drop position visualization
this.view.$('.mailpoet_drop_marker').remove(); this.view.$('.mailpoet_drop_marker').remove();
}, },
getDropPosition: function(eventX, eventY, unsafe) { getDropPosition: function(eventX, eventY, is_unsafe) {
var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3 var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3
element = this.view.$el, element = this.view.$el,
@ -290,7 +291,7 @@ define([
insertionType, index, position, indexAndPosition; insertionType, index, position, indexAndPosition;
unsafe = !!unsafe; unsafe = !!is_unsafe;
if (this.getCollection().length === 0) { if (this.getCollection().length === 0) {
return { return {

View File

@ -11,8 +11,9 @@ define([
'newsletter_editor/behaviors/BehaviorsLookup', 'newsletter_editor/behaviors/BehaviorsLookup',
'interact' 'interact'
], function(Marionette, _, jQuery, BehaviorsLookup, interact) { ], function(Marionette, _, jQuery, BehaviorsLookup, interact) {
var BL = BehaviorsLookup;
BehaviorsLookup.DraggableBehavior = Marionette.Behavior.extend({ BL.DraggableBehavior = Marionette.Behavior.extend({
defaults: { defaults: {
cloneOriginal: false, cloneOriginal: false,
hideOriginal: false, hideOriginal: false,
@ -46,7 +47,8 @@ define([
// Scroll when dragging near edges of a window // Scroll when dragging near edges of a window
autoScroll: true, autoScroll: true,
onstart: function(event) { onstart: function(startEvent) {
var event = startEvent;
if (that.options.cloneOriginal === true) { if (that.options.cloneOriginal === true) {
// Use substitution instead of a clone // Use substitution instead of a clone
@ -89,9 +91,8 @@ define([
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy; y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element // translate the element
target.style.webkitTransform = target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
target.style.transform = target.style.webkitTransform = target.style.transform;
'translate(' + x + 'px, ' + y + 'px)';
// update the posiion attributes // update the posiion attributes
target.setAttribute('data-x', x); target.setAttribute('data-x', x);
@ -99,7 +100,8 @@ define([
}, },
onend: function (event) { onend: function (event) {
var target = event.target; var target = event.target;
target.style.webkitTransform = target.style.transform = ''; target.style.transform = '';
target.style.webkitTransform = target.style.transform;
target.removeAttribute('data-x'); target.removeAttribute('data-x');
target.removeAttribute('data-y'); target.removeAttribute('data-y');
jQuery(event.interaction.element).addClass('mailpoet_droppable_active'); jQuery(event.interaction.element).addClass('mailpoet_droppable_active');
@ -129,7 +131,8 @@ define([
} else { } else {
interactable.getDropModel = this.view.getDropFunc(); interactable.getDropModel = this.view.getDropFunc();
} }
interactable.onDrop = function(options) { interactable.onDrop = function(opts) {
var options = opts;
if (_.isObject(options)) { if (_.isObject(options)) {
// Inject Draggable behavior if possible // Inject Draggable behavior if possible
options.dragBehavior = that; options.dragBehavior = that;

View File

@ -7,11 +7,12 @@ define([
'backbone.marionette', 'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup' 'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, BehaviorsLookup) { ], function(Marionette, BehaviorsLookup) {
var BL = BehaviorsLookup;
BehaviorsLookup.HighlightEditingBehavior = Marionette.Behavior.extend({ BL.HighlightEditingBehavior = Marionette.Behavior.extend({
modelEvents: { modelEvents: {
'startEditing': 'enableHighlight', startEditing: 'enableHighlight',
'stopEditing': 'disableHighlight' stopEditing: 'disableHighlight'
}, },
enableHighlight: function() { enableHighlight: function() {
this.$el.addClass('mailpoet_highlight'); this.$el.addClass('mailpoet_highlight');

View File

@ -8,8 +8,9 @@ define([
'newsletter_editor/behaviors/BehaviorsLookup', 'newsletter_editor/behaviors/BehaviorsLookup',
'interact' 'interact'
], function(Marionette, BehaviorsLookup, interact) { ], function(Marionette, BehaviorsLookup, interact) {
var BL = BehaviorsLookup;
BehaviorsLookup.ResizableBehavior = Marionette.Behavior.extend({ BL.ResizableBehavior = Marionette.Behavior.extend({
defaults: { defaults: {
elementSelector: null, elementSelector: null,
resizeHandleSelector: true, // true will use edges of the element itself resizeHandleSelector: true, // true will use edges of the element itself
@ -18,8 +19,8 @@ define([
modelField: 'styles.block.height' modelField: 'styles.block.height'
}, },
events: { events: {
"mouseenter": 'showResizeHandle', mouseenter: 'showResizeHandle',
"mouseleave": 'hideResizeHandle' mouseleave: 'hideResizeHandle'
}, },
onRender: function() { onRender: function() {
this.attachResize(); this.attachResize();

View File

@ -8,8 +8,9 @@ define([
'jquery', 'jquery',
'newsletter_editor/behaviors/BehaviorsLookup' 'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, jQuery, BehaviorsLookup) { ], function(Marionette, jQuery, BehaviorsLookup) {
var BL = BehaviorsLookup;
BehaviorsLookup.ShowSettingsBehavior = Marionette.Behavior.extend({ BL.ShowSettingsBehavior = Marionette.Behavior.extend({
defaults: { defaults: {
ignoreFrom: '' // selector ignoreFrom: '' // selector
}, },

View File

@ -8,14 +8,15 @@ define([
'underscore', 'underscore',
'newsletter_editor/behaviors/BehaviorsLookup' 'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, _, BehaviorsLookup) { ], function(Marionette, _, BehaviorsLookup) {
var BL = BehaviorsLookup;
BehaviorsLookup.SortableBehavior = Marionette.Behavior.extend({ BL.SortableBehavior = Marionette.Behavior.extend({
onRender: function() { onRender: function() {
var collection = this.view.collection; var collection = this.view.collection;
if (_.isFunction(this.$el.sortable)) { if (_.isFunction(this.$el.sortable)) {
this.$el.sortable({ this.$el.sortable({
cursor: "move", cursor: 'move',
start: function(event, ui) { start: function(event, ui) {
ui.item.data('previousIndex', ui.item.index()); ui.item.data('previousIndex', ui.item.index());
}, },

View File

@ -8,16 +8,17 @@ define([
'underscore', 'underscore',
'newsletter_editor/behaviors/BehaviorsLookup' 'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, _, BehaviorsLookup) { ], function(Marionette, _, BehaviorsLookup) {
var BL = BehaviorsLookup;
BehaviorsLookup.TextEditorBehavior = Marionette.Behavior.extend({ BL.TextEditorBehavior = Marionette.Behavior.extend({
defaults: { defaults: {
selector: '.mailpoet_content', selector: '.mailpoet_content',
toolbar1: "bold italic link unlink forecolor mailpoet_shortcodes", toolbar1: 'bold italic link unlink forecolor mailpoet_shortcodes',
toolbar2: "", toolbar2: '',
validElements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br", validElements: 'p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br',
invalidElements: "script", invalidElements: 'script',
blockFormats: 'Paragraph=p', blockFormats: 'Paragraph=p',
plugins: "link textcolor colorpicker mailpoet_shortcodes", plugins: 'link textcolor colorpicker mailpoet_shortcodes',
configurationFilter: function(originalConfig) { return originalConfig; } configurationFilter: function(originalConfig) { return originalConfig; }
}, },
onDomRefresh: function() { onDomRefresh: function() {

View File

@ -28,7 +28,7 @@ define([
jQuery jQuery
) { ) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -128,12 +128,12 @@ define([
}); });
Module.AutomatedLatestContentBlockView = base.BlockView.extend({ Module.AutomatedLatestContentBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_automated_latest_content_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_automated_latest_content_block mailpoet_droppable_block',
initialize: function() { initialize: function() {
function replaceButtonStylesHandler(data) { function replaceButtonStylesHandler(data) {
this.model.set({"readMoreButton": data}); this.model.set({readMoreButton: data});
} }
App.getChannel().on("replaceAllButtonStyles", replaceButtonStylesHandler.bind(this)); App.getChannel().on('replaceAllButtonStyles', replaceButtonStylesHandler.bind(this));
}, },
getTemplate: function() { return templates.automatedLatestContentBlock; }, getTemplate: function() { return templates.automatedLatestContentBlock; },
regions: { regions: {
@ -143,7 +143,7 @@ define([
modelEvents: _.extend( modelEvents: _.extend(
_.omit(base.BlockView.prototype.modelEvents, 'change'), _.omit(base.BlockView.prototype.modelEvents, 'change'),
{ {
'postsChanged': 'render' postsChanged: 'render'
}), }),
events: _.extend(base.BlockView.prototype.events, { events: _.extend(base.BlockView.prototype.events, {
'click .mailpoet_automated_latest_content_block_overlay': 'showSettings' 'click .mailpoet_automated_latest_content_block_overlay': 'showSettings'
@ -171,28 +171,28 @@ define([
getTemplate: function() { return templates.automatedLatestContentBlockSettings; }, getTemplate: function() { return templates.automatedLatestContentBlockSettings; },
events: function() { events: function() {
return { return {
"click .mailpoet_automated_latest_content_hide_display_options": 'toggleDisplayOptions', 'click .mailpoet_automated_latest_content_hide_display_options': 'toggleDisplayOptions',
"click .mailpoet_automated_latest_content_show_display_options": 'toggleDisplayOptions', 'click .mailpoet_automated_latest_content_show_display_options': 'toggleDisplayOptions',
"click .mailpoet_automated_latest_content_select_button": 'showButtonSettings', 'click .mailpoet_automated_latest_content_select_button': 'showButtonSettings',
"click .mailpoet_automated_latest_content_select_divider": 'showDividerSettings', 'click .mailpoet_automated_latest_content_select_divider': 'showDividerSettings',
"change .mailpoet_automated_latest_content_read_more_type": 'changeReadMoreType', 'change .mailpoet_automated_latest_content_read_more_type': 'changeReadMoreType',
"change .mailpoet_automated_latest_content_display_type": 'changeDisplayType', 'change .mailpoet_automated_latest_content_display_type': 'changeDisplayType',
"change .mailpoet_automated_latest_content_title_format": 'changeTitleFormat', 'change .mailpoet_automated_latest_content_title_format': 'changeTitleFormat',
"change .mailpoet_automated_latest_content_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'), 'change .mailpoet_automated_latest_content_title_as_links': _.partial(this.changeBoolField, 'titleIsLink'),
"change .mailpoet_automated_latest_content_show_divider": _.partial(this.changeBoolField, 'showDivider'), 'change .mailpoet_automated_latest_content_show_divider': _.partial(this.changeBoolField, 'showDivider'),
"input .mailpoet_automated_latest_content_show_amount": _.partial(this.changeField, "amount"), 'input .mailpoet_automated_latest_content_show_amount': _.partial(this.changeField, 'amount'),
"change .mailpoet_automated_latest_content_content_type": _.partial(this.changeField, "contentType"), 'change .mailpoet_automated_latest_content_content_type': _.partial(this.changeField, 'contentType'),
"change .mailpoet_automated_latest_content_include_or_exclude": _.partial(this.changeField, "inclusionType"), 'change .mailpoet_automated_latest_content_include_or_exclude': _.partial(this.changeField, 'inclusionType'),
"change .mailpoet_automated_latest_content_title_alignment": _.partial(this.changeField, "titleAlignment"), 'change .mailpoet_automated_latest_content_title_alignment': _.partial(this.changeField, 'titleAlignment'),
"change .mailpoet_automated_latest_content_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"), 'change .mailpoet_automated_latest_content_image_full_width': _.partial(this.changeBoolField, 'imageFullWidth'),
"change .mailpoet_automated_latest_content_featured_image_position": _.partial(this.changeField, "featuredImagePosition"), 'change .mailpoet_automated_latest_content_featured_image_position': _.partial(this.changeField, 'featuredImagePosition'),
"change .mailpoet_automated_latest_content_show_author": _.partial(this.changeField, "showAuthor"), 'change .mailpoet_automated_latest_content_show_author': _.partial(this.changeField, 'showAuthor'),
"input .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"), 'input .mailpoet_automated_latest_content_author_preceded_by': _.partial(this.changeField, 'authorPrecededBy'),
"change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"), 'change .mailpoet_automated_latest_content_show_categories': _.partial(this.changeField, 'showCategories'),
"input .mailpoet_automated_latest_content_categories": _.partial(this.changeField, "categoriesPrecededBy"), 'input .mailpoet_automated_latest_content_categories': _.partial(this.changeField, 'categoriesPrecededBy'),
"input .mailpoet_automated_latest_content_read_more_text": _.partial(this.changeField, "readMoreText"), 'input .mailpoet_automated_latest_content_read_more_text': _.partial(this.changeField, 'readMoreText'),
"change .mailpoet_automated_latest_content_sort_by": _.partial(this.changeField, "sortBy"), 'change .mailpoet_automated_latest_content_sort_by': _.partial(this.changeField, 'sortBy'),
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
onRender: function() { onRender: function() {
@ -392,8 +392,9 @@ define([
}); });
App.on('start', function(App, options) { App.on('start', function(App, options) {
App._ALCSupervisor = new Module.ALCSupervisor(); var Application = App;
App._ALCSupervisor.refresh(); Application._ALCSupervisor = new Module.ALCSupervisor();
Application._ALCSupervisor.refresh();
}); });
return Module; return Module;

View File

@ -14,7 +14,7 @@ define([
'modal' 'modal'
], function(App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) { ], function(App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
AugmentedView = Marionette.View.extend({}); AugmentedView = Marionette.View.extend({});
@ -50,13 +50,13 @@ define([
toolsRegion: '> .mailpoet_tools' toolsRegion: '> .mailpoet_tools'
}, },
modelEvents: { modelEvents: {
'change': 'render', change: 'render',
'delete': 'deleteBlock', delete: 'deleteBlock',
'duplicate': 'duplicateBlock' duplicate: 'duplicateBlock'
}, },
events: { events: {
"mouseenter": "showTools", mouseenter: 'showTools',
"mouseleave": "hideTools" mouseleave: 'hideTools'
}, },
behaviors: { behaviors: {
DraggableBehavior: { DraggableBehavior: {
@ -180,11 +180,11 @@ define([
Module.BlockToolsView = AugmentedView.extend({ Module.BlockToolsView = AugmentedView.extend({
getTemplate: function() { return templates.genericBlockTools; }, getTemplate: function() { return templates.genericBlockTools; },
events: { events: {
"click .mailpoet_edit_block": "changeSettings", 'click .mailpoet_edit_block': 'changeSettings',
"click .mailpoet_delete_block_activate": "showDeletionConfirmation", 'click .mailpoet_delete_block_activate': 'showDeletionConfirmation',
"click .mailpoet_delete_block_cancel": "hideDeletionConfirmation", 'click .mailpoet_delete_block_cancel': 'hideDeletionConfirmation',
"click .mailpoet_delete_block_confirm": "deleteBlock", 'click .mailpoet_delete_block_confirm': 'deleteBlock',
"click .mailpoet_duplicate_block": "duplicateBlock" 'click .mailpoet_duplicate_block': 'duplicateBlock'
}, },
// Markers of whether these particular tools will be used for this instance // Markers of whether these particular tools will be used for this instance
tools: { tools: {
@ -194,8 +194,8 @@ define([
move: true move: true
}, },
getSettingsView: function() { return Module.BlockSettingsView; }, getSettingsView: function() { return Module.BlockSettingsView; },
initialize: function(options) { initialize: function(opts) {
options = options || {}; var options = opts || {};
if (!_.isUndefined(options.tools)) { if (!_.isUndefined(options.tools)) {
// Make a new block specific tool config object // Make a new block specific tool config object
this.tools = jQuery.extend({}, this.tools, options.tools || {}); this.tools = jQuery.extend({}, this.tools, options.tools || {});
@ -298,7 +298,7 @@ define([
behaviors: { behaviors: {
DraggableBehavior: { DraggableBehavior: {
drop: function() { drop: function() {
throw "Unsupported operation"; throw 'Unsupported operation';
} }
} }
} }

View File

@ -9,7 +9,7 @@ define([
'jquery' 'jquery'
], function(App, BaseBlock, MailPoet, _, jQuery) { ], function(App, BaseBlock, MailPoet, _, jQuery) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -41,7 +41,7 @@ define([
}); });
Module.ButtonBlockView = base.BlockView.extend({ Module.ButtonBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_button_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_button_block mailpoet_droppable_block',
getTemplate: function() { return templates.buttonBlock; }, getTemplate: function() { return templates.buttonBlock; },
onDragSubstituteBy: function() { return Module.ButtonWidgetView; }, onDragSubstituteBy: function() { return Module.ButtonWidgetView; },
behaviors: _.extend({}, base.BlockView.prototype.behaviors, { behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
@ -68,34 +68,34 @@ define([
getTemplate: function() { return templates.buttonBlockSettings; }, getTemplate: function() { return templates.buttonBlockSettings; },
events: function() { events: function() {
return { return {
"input .mailpoet_field_button_text": _.partial(this.changeField, "text"), 'input .mailpoet_field_button_text': _.partial(this.changeField, 'text'),
"input .mailpoet_field_button_url": _.partial(this.changeField, "url"), 'input .mailpoet_field_button_url': _.partial(this.changeField, 'url'),
"change .mailpoet_field_button_alignment": _.partial(this.changeField, "styles.block.textAlign"), 'change .mailpoet_field_button_alignment': _.partial(this.changeField, 'styles.block.textAlign'),
"change .mailpoet_field_button_font_color": _.partial(this.changeColorField, "styles.block.fontColor"), 'change .mailpoet_field_button_font_color': _.partial(this.changeColorField, 'styles.block.fontColor'),
"change .mailpoet_field_button_font_family": _.partial(this.changeField, "styles.block.fontFamily"), 'change .mailpoet_field_button_font_family': _.partial(this.changeField, 'styles.block.fontFamily'),
"change .mailpoet_field_button_font_size": _.partial(this.changeField, "styles.block.fontSize"), 'change .mailpoet_field_button_font_size': _.partial(this.changeField, 'styles.block.fontSize'),
"change .mailpoet_field_button_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"), 'change .mailpoet_field_button_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
"change .mailpoet_field_button_border_color": _.partial(this.changeColorField, "styles.block.borderColor"), 'change .mailpoet_field_button_border_color': _.partial(this.changeColorField, 'styles.block.borderColor'),
"change .mailpoet_field_button_font_weight": "changeFontWeight", 'change .mailpoet_field_button_font_weight': 'changeFontWeight',
"input .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), 'input .mailpoet_field_button_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
"change .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), 'change .mailpoet_field_button_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
"input .mailpoet_field_button_border_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), 'input .mailpoet_field_button_border_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
"input .mailpoet_field_button_border_radius": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)), 'input .mailpoet_field_button_border_radius': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
"change .mailpoet_field_button_border_radius": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)), 'change .mailpoet_field_button_border_radius': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
"input .mailpoet_field_button_border_radius_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)), 'input .mailpoet_field_button_border_radius_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
"input .mailpoet_field_button_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, "styles.block.width").bind(this)), 'input .mailpoet_field_button_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
"change .mailpoet_field_button_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, "styles.block.width").bind(this)), 'change .mailpoet_field_button_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
"input .mailpoet_field_button_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width', _.partial(this.changePixelField, "styles.block.width").bind(this)), 'input .mailpoet_field_button_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
"input .mailpoet_field_button_line_height": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)), 'input .mailpoet_field_button_line_height': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
"change .mailpoet_field_button_line_height": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)), 'change .mailpoet_field_button_line_height': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
"input .mailpoet_field_button_line_height_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)), 'input .mailpoet_field_button_line_height_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
"click .mailpoet_field_button_replace_all_styles": "applyToAll", 'click .mailpoet_field_button_replace_all_styles': 'applyToAll',
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
templateContext: function() { templateContext: function() {

View File

@ -12,7 +12,7 @@ define([
'newsletter_editor/blocks/base' 'newsletter_editor/blocks/base'
], function(Backbone, Marionette, _, jQuery, App, BaseBlock) { ], function(Backbone, Marionette, _, jQuery, App, BaseBlock) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock, base = BaseBlock,
@ -105,7 +105,7 @@ define([
className: 'mailpoet_block mailpoet_container_block mailpoet_droppable_block mailpoet_droppable_layout_block', className: 'mailpoet_block mailpoet_container_block mailpoet_droppable_block mailpoet_droppable_layout_block',
getTemplate: function() { return templates.containerBlock; }, getTemplate: function() { return templates.containerBlock; },
events: _.extend({}, base.BlockView.prototype.events, { events: _.extend({}, base.BlockView.prototype.events, {
"click .mailpoet_newsletter_layer_selector": "toggleEditingLayer" 'click .mailpoet_newsletter_layer_selector': 'toggleEditingLayer'
}), }),
ui: { ui: {
tools: '> .mailpoet_tools' tools: '> .mailpoet_tools'
@ -237,8 +237,8 @@ define([
getTemplate: function() { return templates.containerBlockSettings; }, getTemplate: function() { return templates.containerBlockSettings; },
events: function() { events: function() {
return { return {
"change .mailpoet_field_container_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"), 'change .mailpoet_field_container_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
regions: { regions: {

View File

@ -9,7 +9,7 @@ define([
'mailpoet' 'mailpoet'
], function(App, BaseBlock, _, jQuery, MailPoet) { ], function(App, BaseBlock, _, jQuery, MailPoet) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -32,7 +32,7 @@ define([
}); });
Module.DividerBlockView = base.BlockView.extend({ Module.DividerBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_divider_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_divider_block mailpoet_droppable_block',
getTemplate: function() { return templates.dividerBlock; }, getTemplate: function() { return templates.dividerBlock; },
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
behaviors: _.defaults({ behaviors: _.defaults({
@ -87,16 +87,16 @@ define([
getTemplate: function() { return templates.dividerBlockSettings; }, getTemplate: function() { return templates.dividerBlockSettings; },
events: function() { events: function() {
return { return {
"click .mailpoet_field_divider_style": 'changeStyle', 'click .mailpoet_field_divider_style': 'changeStyle',
"input .mailpoet_field_divider_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), 'input .mailpoet_field_divider_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
"change .mailpoet_field_divider_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), 'change .mailpoet_field_divider_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
"input .mailpoet_field_divider_border_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), 'input .mailpoet_field_divider_border_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
"change .mailpoet_field_divider_border_color": _.partial(this.changeColorField, "styles.block.borderColor"), 'change .mailpoet_field_divider_border_color': _.partial(this.changeColorField, 'styles.block.borderColor'),
"change .mailpoet_field_divider_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"), 'change .mailpoet_field_divider_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
"click .mailpoet_button_divider_apply_to_all": "applyToAll", 'click .mailpoet_button_divider_apply_to_all': 'applyToAll',
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
modelEvents: function() { modelEvents: function() {

View File

@ -7,7 +7,7 @@ define([
'underscore' 'underscore'
], function(App, BaseBlock, _) { ], function(App, BaseBlock, _) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -37,7 +37,7 @@ define([
}); });
Module.FooterBlockView = base.BlockView.extend({ Module.FooterBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_footer_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_footer_block mailpoet_droppable_block',
getTemplate: function() { return templates.footerBlock; }, getTemplate: function() { return templates.footerBlock; },
modelEvents: _.extend({ modelEvents: _.extend({
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render' 'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render'
@ -78,16 +78,16 @@ define([
getTemplate: function() { return templates.footerBlockSettings; }, getTemplate: function() { return templates.footerBlockSettings; },
events: function() { events: function() {
return { return {
"change .mailpoet_field_footer_text_color": _.partial(this.changeColorField, "styles.text.fontColor"), '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_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
"change .mailpoet_field_footer_text_size": _.partial(this.changeField, "styles.text.fontSize"), '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_color': _.partial(this.changeColorField, 'styles.link.fontColor'),
"change #mailpoet_field_footer_link_underline": function(event) { 'change #mailpoet_field_footer_link_underline': function(event) {
this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none'); 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_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
"change .mailpoet_field_footer_alignment": _.partial(this.changeField, "styles.text.textAlign"), 'change .mailpoet_field_footer_alignment': _.partial(this.changeField, 'styles.text.textAlign'),
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
templateContext: function() { templateContext: function() {

View File

@ -7,7 +7,7 @@ define([
'underscore' 'underscore'
], function(App, BaseBlock, _) { ], function(App, BaseBlock, _) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -37,7 +37,7 @@ define([
}); });
Module.HeaderBlockView = base.BlockView.extend({ Module.HeaderBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_header_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_header_block mailpoet_droppable_block',
getTemplate: function() { return templates.headerBlock; }, getTemplate: function() { return templates.headerBlock; },
modelEvents: _.extend({ modelEvents: _.extend({
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render' 'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render'
@ -78,16 +78,16 @@ define([
getTemplate: function() { return templates.headerBlockSettings; }, getTemplate: function() { return templates.headerBlockSettings; },
events: function() { events: function() {
return { return {
"change .mailpoet_field_header_text_color": _.partial(this.changeColorField, "styles.text.fontColor"), '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_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
"change .mailpoet_field_header_text_size": _.partial(this.changeField, "styles.text.fontSize"), '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_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'); this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
}, },
"change .mailpoet_field_header_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"), 'change .mailpoet_field_header_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
"change .mailpoet_field_header_alignment": _.partial(this.changeField, "styles.text.textAlign"), 'change .mailpoet_field_header_alignment': _.partial(this.changeField, 'styles.text.textAlign'),
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
templateContext: function() { templateContext: function() {

View File

@ -4,10 +4,11 @@
define([ define([
'newsletter_editor/App', 'newsletter_editor/App',
'newsletter_editor/blocks/base', 'newsletter_editor/blocks/base',
'underscore' 'underscore',
], function(App, BaseBlock, _) { 'mailpoet'
], function(App, BaseBlock, _, MailPoet) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock, base = BaseBlock,
@ -33,7 +34,7 @@ define([
}); });
Module.ImageBlockView = base.BlockView.extend({ Module.ImageBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_image_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_image_block mailpoet_droppable_block',
getTemplate: function() { return templates.imageBlock; }, getTemplate: function() { return templates.imageBlock; },
onDragSubstituteBy: function() { return Module.ImageWidgetView; }, onDragSubstituteBy: function() { return Module.ImageWidgetView; },
templateContext: function() { templateContext: function() {
@ -61,16 +62,26 @@ define([
}); });
Module.ImageBlockSettingsView = base.BlockSettingsView.extend({ Module.ImageBlockSettingsView = base.BlockSettingsView.extend({
onRender: function() {
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-full-width'), {
tooltipId: 'tooltip-editor-full-width',
tooltip: MailPoet.I18n.t('helpTooltipDesignerFullWidth')
});
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-ideal-width'), {
tooltipId: 'tooltip-editor-ideal-width',
tooltip: MailPoet.I18n.t('helpTooltipDesignerIdealWidth')
});
},
getTemplate: function() { return templates.imageBlockSettings; }, getTemplate: function() { return templates.imageBlockSettings; },
events: function() { events: function() {
return { return {
"input .mailpoet_field_image_link": _.partial(this.changeField, "link"), 'input .mailpoet_field_image_link': _.partial(this.changeField, 'link'),
"input .mailpoet_field_image_address": 'changeAddress', 'input .mailpoet_field_image_address': 'changeAddress',
"input .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"), 'input .mailpoet_field_image_alt_text': _.partial(this.changeField, 'alt'),
"change .mailpoet_field_image_full_width": _.partial(this.changeBoolCheckboxField, "fullWidth"), 'change .mailpoet_field_image_full_width': _.partial(this.changeBoolCheckboxField, 'fullWidth'),
"change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"), 'change .mailpoet_field_image_alignment': _.partial(this.changeField, 'styles.block.textAlign'),
"click .mailpoet_field_image_select_another_image": "showMediaManager", 'click .mailpoet_field_image_select_another_image': 'showMediaManager',
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
initialize: function(options) { initialize: function(options) {
@ -166,7 +177,7 @@ define([
var handlers = { var handlers = {
content: { content: {
'embed': 'embedContent', embed: 'embedContent',
'edit-selection': 'editSelectionContent' 'edit-selection': 'editSelectionContent'
}, },
toolbar: { toolbar: {
@ -266,7 +277,8 @@ define([
}, },
mainEmbedToolbar: function(toolbar) { mainEmbedToolbar: function(toolbar) {
toolbar.view = new wp.media.view.Toolbar.Embed({ var tbar = toolbar;
tbar.view = new wp.media.view.Toolbar.Embed({
controller: this, controller: this,
text: 'Add images' text: 'Add images'
}); });
@ -274,7 +286,7 @@ define([
}); });
var theFrame = this._mediaManager = new MediaManager({ var theFrame = new MediaManager({
id: 'mailpoet-media-manager', id: 'mailpoet-media-manager',
frame: 'select', frame: 'select',
title: 'Select image', title: 'Select image',
@ -289,6 +301,7 @@ define([
} }
}), }),
that = this; that = this;
this._mediaManager = theFrame;
this._mediaManager.on('insert', function() { this._mediaManager.on('insert', function() {
// Append media manager image selections to Images tab // Append media manager image selections to Images tab
@ -318,7 +331,7 @@ define([
height: mainSize.height + 'px', height: mainSize.height + 'px',
width: mainSize.width + 'px', width: mainSize.width + 'px',
src: mainSize.url, src: mainSize.url,
alt: (attachment.get('alt') !== "" && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title') alt: (attachment.get('alt') !== '' && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title')
}); });
// Rerender settings view due to changes from outside of settings view // Rerender settings view due to changes from outside of settings view
that.render(); that.render();

View File

@ -37,7 +37,7 @@ define([
DividerBlock DividerBlock
) { ) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -176,7 +176,7 @@ define([
}); });
Module.PostsBlockView = base.BlockView.extend({ Module.PostsBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_posts_block mailpoet_droppable_block',
getTemplate: function() { return templates.postsBlock; }, getTemplate: function() { return templates.postsBlock; },
modelEvents: {}, // Forcefully disable all events modelEvents: {}, // Forcefully disable all events
regions: _.extend({ regions: _.extend({
@ -296,7 +296,7 @@ define([
this.blockModel = options.blockModel; this.blockModel = options.blockModel;
}, },
events: { events: {
'scroll': 'onPostsScroll' scroll: 'onPostsScroll'
}, },
onPostsScroll: function(event) { onPostsScroll: function(event) {
var $postsBox = jQuery(event.target); var $postsBox = jQuery(event.target);
@ -326,10 +326,10 @@ define([
this.$('.mailpoet_post_scroll_container').scrollTop(0); this.$('.mailpoet_post_scroll_container').scrollTop(0);
} }
}, },
'loadingMorePosts': function() { loadingMorePosts: function() {
this.$('.mailpoet_post_selection_loading').css('visibility', 'visible'); this.$('.mailpoet_post_selection_loading').css('visibility', 'visible');
}, },
'morePostsLoaded': function() { morePostsLoaded: function() {
this.$('.mailpoet_post_selection_loading').css('visibility', 'hidden'); this.$('.mailpoet_post_selection_loading').css('visibility', 'hidden');
} }
}, },
@ -462,25 +462,25 @@ define([
getTemplate: function() { return templates.displayOptionsPostsBlockSettings; }, getTemplate: function() { return templates.displayOptionsPostsBlockSettings; },
events: function() { events: function() {
return { return {
"click .mailpoet_posts_select_button": 'showButtonSettings', 'click .mailpoet_posts_select_button': 'showButtonSettings',
"click .mailpoet_posts_select_divider": 'showDividerSettings', 'click .mailpoet_posts_select_divider': 'showDividerSettings',
"change .mailpoet_posts_read_more_type": 'changeReadMoreType', 'change .mailpoet_posts_read_more_type': 'changeReadMoreType',
"change .mailpoet_posts_display_type": 'changeDisplayType', 'change .mailpoet_posts_display_type': 'changeDisplayType',
"change .mailpoet_posts_title_format": 'changeTitleFormat', 'change .mailpoet_posts_title_format': 'changeTitleFormat',
"change .mailpoet_posts_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'), 'change .mailpoet_posts_title_as_links': _.partial(this.changeBoolField, 'titleIsLink'),
"change .mailpoet_posts_show_divider": _.partial(this.changeBoolField, 'showDivider'), 'change .mailpoet_posts_show_divider': _.partial(this.changeBoolField, 'showDivider'),
"input .mailpoet_posts_show_amount": _.partial(this.changeField, "amount"), 'input .mailpoet_posts_show_amount': _.partial(this.changeField, 'amount'),
"change .mailpoet_posts_content_type": _.partial(this.changeField, "contentType"), 'change .mailpoet_posts_content_type': _.partial(this.changeField, 'contentType'),
"change .mailpoet_posts_include_or_exclude": _.partial(this.changeField, "inclusionType"), 'change .mailpoet_posts_include_or_exclude': _.partial(this.changeField, 'inclusionType'),
"change .mailpoet_posts_title_alignment": _.partial(this.changeField, "titleAlignment"), 'change .mailpoet_posts_title_alignment': _.partial(this.changeField, 'titleAlignment'),
"change .mailpoet_posts_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"), 'change .mailpoet_posts_image_full_width': _.partial(this.changeBoolField, 'imageFullWidth'),
"change .mailpoet_posts_featured_image_position": _.partial(this.changeField, "featuredImagePosition"), 'change .mailpoet_posts_featured_image_position': _.partial(this.changeField, 'featuredImagePosition'),
"change .mailpoet_posts_show_author": _.partial(this.changeField, "showAuthor"), 'change .mailpoet_posts_show_author': _.partial(this.changeField, 'showAuthor'),
"input .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"), 'input .mailpoet_posts_author_preceded_by': _.partial(this.changeField, 'authorPrecededBy'),
"change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"), 'change .mailpoet_posts_show_categories': _.partial(this.changeField, 'showCategories'),
"input .mailpoet_posts_categories": _.partial(this.changeField, "categoriesPrecededBy"), 'input .mailpoet_posts_categories': _.partial(this.changeField, 'categoriesPrecededBy'),
"input .mailpoet_posts_read_more_text": _.partial(this.changeField, "readMoreText"), 'input .mailpoet_posts_read_more_text': _.partial(this.changeField, 'readMoreText'),
"change .mailpoet_posts_sort_by": _.partial(this.changeField, "sortBy") 'change .mailpoet_posts_sort_by': _.partial(this.changeField, 'sortBy')
}; };
}, },
templateContext: function() { templateContext: function() {

View File

@ -11,7 +11,7 @@ define([
'jquery' 'jquery'
], function(App, BaseBlock, Backbone, Marionette, SuperModel, _, jQuery) { ], function(App, BaseBlock, Backbone, Marionette, SuperModel, _, jQuery) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock, base = BaseBlock,
@ -87,7 +87,7 @@ define([
tagName: 'span', tagName: 'span',
getTemplate: function() { return templates.socialIconBlock; }, getTemplate: function() { return templates.socialIconBlock; },
modelEvents: { modelEvents: {
'change': 'render' change: 'render'
}, },
templateContext: function() { templateContext: function() {
var allIconSets = App.getAvailableStyles().get('socialIconSets'); var allIconSets = App.getAvailableStyles().get('socialIconSets');
@ -138,7 +138,7 @@ define([
}, },
events: function() { events: function() {
return { return {
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
}, },
initialize: function() { initialize: function() {
@ -158,11 +158,11 @@ define([
getTemplate: function() { return templates.socialSettingsIcon; }, getTemplate: function() { return templates.socialSettingsIcon; },
events: function() { events: function() {
return { return {
"click .mailpoet_delete_block": "deleteIcon", 'click .mailpoet_delete_block': 'deleteIcon',
"change .mailpoet_social_icon_field_type": _.partial(this.changeField, "iconType"), 'change .mailpoet_social_icon_field_type': _.partial(this.changeField, 'iconType'),
"input .mailpoet_social_icon_field_image": _.partial(this.changeField, "image"), 'input .mailpoet_social_icon_field_image': _.partial(this.changeField, 'image'),
"input .mailpoet_social_icon_field_link": this.changeLink, 'input .mailpoet_social_icon_field_link': this.changeLink,
"input .mailpoet_social_icon_field_text": _.partial(this.changeField, "text") 'input .mailpoet_social_icon_field_text': _.partial(this.changeField, 'text')
}; };
}, },
modelEvents: { modelEvents: {
@ -214,7 +214,7 @@ define([
SocialBlockSettingsIconSelectorView = Marionette.View.extend({ SocialBlockSettingsIconSelectorView = Marionette.View.extend({
getTemplate: function() { return templates.socialSettingsIconSelector; }, getTemplate: function() { return templates.socialSettingsIconSelector; },
regions: { regions: {
'icons': '#mailpoet_social_icon_selector_contents' icons: '#mailpoet_social_icon_selector_contents'
}, },
events: { events: {
'click .mailpoet_add_social_icon': 'addSocialIcon' 'click .mailpoet_add_social_icon': 'addSocialIcon'
@ -237,7 +237,7 @@ define([
SocialBlockSettingsStylesView = Marionette.View.extend({ SocialBlockSettingsStylesView = Marionette.View.extend({
getTemplate: function() { return templates.socialSettingsStyles; }, getTemplate: function() { return templates.socialSettingsStyles; },
modelEvents: { modelEvents: {
'change': 'render' change: 'render'
}, },
events: { events: {
'click .mailpoet_social_icon_set': 'changeSocialIconSet' 'click .mailpoet_social_icon_set': 'changeSocialIconSet'

View File

@ -7,7 +7,7 @@ define([
'underscore' 'underscore'
], function(App, BaseBlock, _) { ], function(App, BaseBlock, _) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -27,7 +27,7 @@ define([
}); });
Module.SpacerBlockView = base.BlockView.extend({ Module.SpacerBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_spacer_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_spacer_block mailpoet_droppable_block',
getTemplate: function() { return templates.spacerBlock; }, getTemplate: function() { return templates.spacerBlock; },
behaviors: _.defaults({ behaviors: _.defaults({
ResizableBehavior: { ResizableBehavior: {
@ -69,8 +69,8 @@ define([
getTemplate: function() { return templates.spacerBlockSettings; }, getTemplate: function() { return templates.spacerBlockSettings; },
events: function() { events: function() {
return { return {
"change .mailpoet_field_spacer_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"), 'change .mailpoet_field_spacer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
"click .mailpoet_done_editing": "close" 'click .mailpoet_done_editing': 'close'
}; };
} }
}); });

View File

@ -7,7 +7,7 @@ define([
'underscore' 'underscore'
], function(App, BaseBlock, _) { ], function(App, BaseBlock, _) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
base = BaseBlock; base = BaseBlock;
@ -22,17 +22,17 @@ define([
}); });
Module.TextBlockView = base.BlockView.extend({ Module.TextBlockView = base.BlockView.extend({
className: "mailpoet_block mailpoet_text_block mailpoet_droppable_block", className: 'mailpoet_block mailpoet_text_block mailpoet_droppable_block',
getTemplate: function() { return templates.textBlock; }, getTemplate: function() { return templates.textBlock; },
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing
behaviors: _.extend({}, base.BlockView.prototype.behaviors, { behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
TextEditorBehavior: { TextEditorBehavior: {
toolbar1: "formatselect bold italic forecolor | link unlink", toolbar1: 'formatselect bold italic forecolor | link unlink',
toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes", toolbar2: 'alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes',
validElements: "p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]", validElements: 'p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]',
invalidElements: "script", invalidElements: 'script',
blockFormats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p', blockFormats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
plugins: "link lists code textcolor colorpicker mailpoet_shortcodes paste", plugins: 'link lists code textcolor colorpicker mailpoet_shortcodes paste',
configurationFilter: function(originalSettings) { configurationFilter: function(originalSettings) {
return _.extend({}, originalSettings, { return _.extend({}, originalSettings, {
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(), mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),

View File

@ -23,8 +23,8 @@
} }
}(this, function(Marionette, Radio, _) { }(this, function(Marionette, Radio, _) {
'use strict'; 'use strict';
var MarionetteApplication = Marionette.Application;
Marionette.Application.prototype._initChannel = function () { MarionetteApplication.prototype._initChannel = function () {
this.channelName = _.result(this, 'channelName') || 'global'; this.channelName = _.result(this, 'channelName') || 'global';
this.channel = _.result(this, 'channel') || Radio.channel(this.channelName); this.channel = _.result(this, 'channel') || Radio.channel(this.channelName);
}; };

View File

@ -25,11 +25,12 @@ define([
}; };
App.on('before:start', function(App, options) { App.on('before:start', function(App, options) {
var Application = App;
// Expose config methods globally // Expose config methods globally
App.getConfig = Module.getConfig; Application.getConfig = Module.getConfig;
App.setConfig = Module.setConfig; Application.setConfig = Module.setConfig;
App.setConfig(options.config); Application.setConfig(options.config);
}); });
return Module; return Module;

View File

@ -4,7 +4,7 @@ define([
'underscore', 'underscore',
'mailpoet' 'mailpoet'
], function(App, SuperModel, _, MailPoet) { ], function(App, SuperModel, _, MailPoet) {
"use strict"; 'use strict';
var Module = {}; var Module = {};
@ -34,14 +34,14 @@ define([
if (type in Module._blockTypes) { if (type in Module._blockTypes) {
return Module._blockTypes[type].blockModel; return Module._blockTypes[type].blockModel;
} else { } else {
throw "Block type not supported: " + type; throw 'Block type not supported: ' + type;
} }
}; };
Module.getBlockTypeView = function(type) { Module.getBlockTypeView = function(type) {
if (type in Module._blockTypes) { if (type in Module._blockTypes) {
return Module._blockTypes[type].blockView; return Module._blockTypes[type].blockView;
} else { } else {
throw "Block type not supported: " + type; throw 'Block type not supported: ' + type;
} }
}; };
@ -67,7 +67,8 @@ define([
return _.filter(blocks, predicate); return _.filter(blocks, predicate);
}; };
App.on('before:start', function(App, options) { App.on('before:start', function(Application, options) {
var App = Application;
// Expose block methods globally // Expose block methods globally
App.registerBlockType = Module.registerBlockType; App.registerBlockType = Module.registerBlockType;
App.getBlockTypeModel = Module.getBlockTypeModel; App.getBlockTypeModel = Module.getBlockTypeModel;
@ -80,7 +81,8 @@ define([
Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body'])); Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body']));
}); });
App.on('start', function(App, options) { App.on('start', function(Application, options) {
var App = Application;
var body = options.newsletter.body; var body = options.newsletter.body;
var content = (_.has(body, 'content')) ? body.content : {}; var content = (_.has(body, 'content')) ? body.content : {};

View File

@ -6,7 +6,7 @@ define([
'jquery' 'jquery'
], function(App, Backbone, Marionette, _, jQuery) { ], function(App, Backbone, Marionette, _, jQuery) {
"use strict"; 'use strict';
var Module = {}; var Module = {};
@ -19,8 +19,8 @@ define([
}, },
events: function() { events: function() {
return { return {
'keyup .mailpoet_input_title': _.partial(this.changeField, "subject"), 'keyup .mailpoet_input_title': _.partial(this.changeField, 'subject'),
'keyup .mailpoet_input_preheader': _.partial(this.changeField, "preheader") 'keyup .mailpoet_input_preheader': _.partial(this.changeField, 'preheader')
}; };
}, },
changeField: function(field, event) { changeField: function(field, event) {
@ -30,6 +30,15 @@ define([
App.on('start', function(App, options) { App.on('start', function(App, options) {
App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() })); App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() }));
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-subject-line'), {
tooltipId: 'tooltip-designer-subject-line-ti',
tooltip: MailPoet.I18n.t('helpTooltipDesignerSubjectLine'),
place: 'right'
});
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-preheader'), {
tooltipId: 'tooltip-designer-preheader-ti',
tooltip: MailPoet.I18n.t('helpTooltipDesignerPreheader')
});
}); });
return Module; return Module;

View File

@ -22,7 +22,7 @@ define([
html2canvas html2canvas
) { ) {
"use strict"; 'use strict';
var Module = {}, var Module = {},
saveTimeout; saveTimeout;
@ -65,14 +65,6 @@ define([
}); });
}; };
// For getting a promise after triggering save event
Module.saveAndProvidePromise = function(saveResult) {
var promise = Module.save();
if (saveResult !== undefined) {
saveResult.promise = promise;
}
};
Module.getThumbnail = function(element, options) { Module.getThumbnail = function(element, options) {
var promise = html2canvas(element, options || {}); var promise = html2canvas(element, options || {});
@ -81,8 +73,8 @@ define([
// Removes 1px left transparent border from resulting canvas. // Removes 1px left transparent border from resulting canvas.
var oldContext = oldCanvas.getContext('2d'), var oldContext = oldCanvas.getContext('2d'),
newCanvas = document.createElement("canvas"), newCanvas = document.createElement('canvas'),
newContext = newCanvas.getContext("2d"), newContext = newCanvas.getContext('2d'),
leftBorderWidth = 1; leftBorderWidth = 1;
newCanvas.width = oldCanvas.width; newCanvas.width = oldCanvas.width;
@ -140,6 +132,9 @@ define([
); );
FileSaver.saveAs(blob, 'template.json'); FileSaver.saveAs(blob, 'template.json');
MailPoet.trackEvent('Editor > Template exported', {
'MailPoet Free version': window.mailpoet_version
});
}); });
}; };
@ -165,7 +160,7 @@ define([
}, },
save: function() { save: function() {
this.hideOptionContents(); this.hideOptionContents();
App.getChannel().trigger('save'); App.getChannel().request('save');
}, },
beforeSave: function() { beforeSave: function() {
// TODO: Add a loading animation instead // TODO: Add a loading animation instead
@ -225,6 +220,9 @@ define([
scroll: true scroll: true
} }
); );
MailPoet.trackEvent('Editor > Template saved', {
'MailPoet Free version': window.mailpoet_version
});
}).fail(function() { }).fail(function() {
MailPoet.Notice.error( MailPoet.Notice.error(
MailPoet.I18n.t('templateSaveFailed'), MailPoet.I18n.t('templateSaveFailed'),
@ -282,7 +280,10 @@ define([
next: function() { next: function() {
this.hideOptionContents(); this.hideOptionContents();
if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) { if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
Module._cancelAutosave();
Module.save().done(function(response) {
window.location.href = App.getConfig().get('urls.send'); window.location.href = App.getConfig().get('urls.send');
});
} }
}, },
validateNewsletter: function(jsonObject) { validateNewsletter: function(jsonObject) {
@ -293,8 +294,8 @@ define([
var contents = JSON.stringify(jsonObject); var contents = JSON.stringify(jsonObject);
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') && if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
contents.indexOf("[link:subscription_unsubscribe_url]") < 0 && contents.indexOf('[link:subscription_unsubscribe_url]') < 0 &&
contents.indexOf("[link:subscription_unsubscribe]") < 0) { contents.indexOf('[link:subscription_unsubscribe]') < 0) {
this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing')); this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
return; return;
} }
@ -319,22 +320,28 @@ define([
// may be requested // may be requested
var AUTOSAVE_DELAY_DURATION = 1000; var AUTOSAVE_DELAY_DURATION = 1000;
// Cancel save timer if another change happens before it completes Module._cancelAutosave();
if (saveTimeout) clearTimeout(saveTimeout);
saveTimeout = setTimeout(function() { saveTimeout = setTimeout(function() {
App.getChannel().trigger('save'); App.getChannel().request('save').always(function() {
Module._cancelAutosave();
});
}, AUTOSAVE_DELAY_DURATION);
};
Module._cancelAutosave = function() {
if (!saveTimeout) return;
clearTimeout(saveTimeout); clearTimeout(saveTimeout);
saveTimeout = undefined; saveTimeout = undefined;
}, AUTOSAVE_DELAY_DURATION);
}; };
Module.beforeExitWithUnsavedChanges = function(e) { Module.beforeExitWithUnsavedChanges = function(e) {
if (saveTimeout) { if (saveTimeout) {
var message = MailPoet.I18n.t('unsavedChangesWillBeLost'); var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
e = e || window.event; var event = e || window.event;
if (e) { if (event) {
e.returnValue = message; event.returnValue = message;
} }
return message; return message;
@ -342,12 +349,13 @@ define([
}; };
App.on('before:start', function(App, options) { App.on('before:start', function(App, options) {
App.save = Module.saveAndProvidePromise; var Application = App;
App.getChannel().on('autoSave', Module.autoSave); Application.save = Module.save;
Application.getChannel().on('autoSave', Module.autoSave);
window.onbeforeunload = Module.beforeExitWithUnsavedChanges; window.onbeforeunload = Module.beforeExitWithUnsavedChanges;
App.getChannel().on('save', function(saveResult) { App.save(saveResult); }); Application.getChannel().reply('save', Application.save);
}); });
App.on('start', function(App, options) { App.on('start', function(App, options) {

View File

@ -20,7 +20,7 @@ define([
StickyKit StickyKit
) { ) {
"use strict"; 'use strict';
var Module = {}; var Module = {};
@ -69,7 +69,7 @@ define([
'slideUp', 'slideUp',
{ {
duration: 250, duration: 250,
easing: "easeOut", easing: 'easeOut',
complete: function() { complete: function() {
$openRegion.addClass('closed'); $openRegion.addClass('closed');
}.bind(this) }.bind(this)
@ -81,7 +81,7 @@ define([
'slideDown', 'slideDown',
{ {
duration: 250, duration: 250,
easing: "easeIn", easing: 'easeIn',
complete: function() { complete: function() {
$targetRegion.removeClass('closed'); $targetRegion.removeClass('closed');
} }
@ -180,40 +180,40 @@ define([
}, },
events: function() { events: function() {
return { return {
"change #mailpoet_text_font_color": _.partial(this.changeColorField, 'text.fontColor'), '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); 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); this.model.set('text.fontSize', event.target.value);
}, },
"change #mailpoet_h1_font_color": _.partial(this.changeColorField, 'h1.fontColor'), '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); 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); this.model.set('h1.fontSize', event.target.value);
}, },
"change #mailpoet_h2_font_color": _.partial(this.changeColorField, 'h2.fontColor'), '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); 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); this.model.set('h2.fontSize', event.target.value);
}, },
"change #mailpoet_h3_font_color": _.partial(this.changeColorField, 'h3.fontColor'), '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); 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); this.model.set('h3.fontSize', event.target.value);
}, },
"change #mailpoet_a_font_color": _.partial(this.changeColorField, 'link.fontColor'), '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'); this.model.set('link.textDecoration', (event.target.checked) ? event.target.value : 'none');
}, },
"change #mailpoet_newsletter_background_color": _.partial(this.changeColorField, 'wrapper.backgroundColor'), 'change #mailpoet_newsletter_background_color': _.partial(this.changeColorField, 'wrapper.backgroundColor'),
"change #mailpoet_background_color": _.partial(this.changeColorField, 'body.backgroundColor') 'change #mailpoet_background_color': _.partial(this.changeColorField, 'body.backgroundColor')
}; };
}, },
templateContext: function() { templateContext: function() {
@ -285,6 +285,10 @@ define([
this.previewView = null; this.previewView = null;
}.bind(this) }.bind(this)
}); });
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) { if (response.errors.length > 0) {
MailPoet.Notice.error( MailPoet.Notice.error(
@ -317,16 +321,18 @@ define([
MailPoet.Modal.loading(true); MailPoet.Modal.loading(true);
// save before sending // save before sending
var saveResult = {promise: null}; App.getChannel().request('save').always(function() {
App.getChannel().trigger('save', saveResult);
saveResult.promise.always(function() {
CommunicationComponent.previewNewsletter(data).always(function() { CommunicationComponent.previewNewsletter(data).always(function() {
MailPoet.Modal.loading(false); MailPoet.Modal.loading(false);
}).done(function(response) { }).done(function(response) {
MailPoet.Notice.success( MailPoet.Notice.success(
MailPoet.I18n.t('newsletterPreviewSent'), MailPoet.I18n.t('newsletterPreviewSent'),
{ scroll: true }); { scroll: true }
);
MailPoet.trackEvent('Editor > Preview sent', {
'MailPoet Free version': window.mailpoet_version,
'Domain name': data.subscriber.substring(data.subscriber.indexOf('@') + 1)
});
}).fail(function(response) { }).fail(function(response) {
if (response.errors.length > 0) { if (response.errors.length > 0) {
MailPoet.Notice.error( MailPoet.Notice.error(
@ -358,10 +364,11 @@ define([
}); });
App.on('before:start', function(App, options) { App.on('before:start', function(App, options) {
App.registerWidget = Module.registerWidget; var Application = App;
App.getWidgets = Module.getWidgets; Application.registerWidget = Module.registerWidget;
App.registerLayoutWidget = Module.registerLayoutWidget; Application.getWidgets = Module.getWidgets;
App.getLayoutWidgets = Module.getLayoutWidgets; Application.registerLayoutWidget = Module.registerLayoutWidget;
Application.getLayoutWidgets = Module.getLayoutWidgets;
}); });
App.on('start', function(App, options) { App.on('start', function(App, options) {
@ -369,6 +376,16 @@ define([
sidebarView = new SidebarView(); sidebarView = new SidebarView();
App._appView.showChildView('sidebarRegion', sidebarView); App._appView.showChildView('sidebarRegion', sidebarView);
MailPoet.helpTooltip.show(document.getElementById('tooltip-send-preview'), {
tooltipId: 'tooltip-editor-send-preview',
tooltip: MailPoet.I18n.t('helpTooltipSendPreview')
});
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-styles'), {
tooltipId: 'tooltip-editor-designer-styles',
tooltip: MailPoet.I18n.t('helpTooltipDesignerStyles')
});
}); });
return Module; return Module;

View File

@ -4,7 +4,7 @@ define([
'backbone.supermodel' 'backbone.supermodel'
], function(App, Marionette, SuperModel) { ], function(App, Marionette, SuperModel) {
"use strict"; 'use strict';
var Module = {}; var Module = {};
@ -49,7 +49,7 @@ define([
Module.StylesView = Marionette.View.extend({ Module.StylesView = Marionette.View.extend({
getTemplate: function() { return templates.styles; }, getTemplate: function() { return templates.styles; },
modelEvents: { modelEvents: {
'change': 'render' change: 'render'
}, },
serializeData: function() { serializeData: function() {
return this.model.toJSON(); return this.model.toJSON();
@ -69,10 +69,11 @@ define([
}; };
App.on('before:start', function(App, options) { App.on('before:start', function(App, options) {
var Application = App;
// Expose style methods to global application // Expose style methods to global application
App.getGlobalStyles = Module.getGlobalStyles; Application.getGlobalStyles = Module.getGlobalStyles;
App.setGlobalStyles = Module.setGlobalStyles; Application.setGlobalStyles = Module.setGlobalStyles;
App.getAvailableStyles = Module.getAvailableStyles; Application.getAvailableStyles = Module.getAvailableStyles;
var body = options.newsletter.body; var body = options.newsletter.body;
var globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {}; var globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};

View File

@ -46,8 +46,8 @@ tinymce.PluginManager.add('mailpoet_shortcodes', function(editor, url) {
// Open window // Open window
editor.windowManager.open({ editor.windowManager.open({
height: parseInt(editor.getParam("plugin_mailpoet_shortcodes_height", 400)), height: parseInt(editor.getParam('plugin_mailpoet_shortcodes_height', 400)),
width: parseInt(editor.getParam("plugin_mailpoet_shortcodes_width", 450)), width: parseInt(editor.getParam('plugin_mailpoet_shortcodes_width', 450)),
autoScroll: true, autoScroll: true,
title: editor.settings.mailpoet_shortcodes_window_title, title: editor.settings.mailpoet_shortcodes_window_title,
body: shortcodes, body: shortcodes,

View File

@ -41,7 +41,7 @@ define(
render: function () { render: function () {
const steps = this.state.steps.map((step, index) => { const steps = this.state.steps.map((step, index) => {
const stepClasses = classNames( const stepClasses = classNames(
{ 'mailpoet_current': (this.props.step === step.name) } { mailpoet_current: (this.props.step === step.name) }
); );
let label = step.label; let label = step.label;

View File

@ -69,7 +69,7 @@ const _QueueMixin = {
} }
const progressClasses = classNames( const progressClasses = classNames(
'mailpoet_progress', 'mailpoet_progress',
{ 'mailpoet_progress_complete': newsletter.queue.status === 'completed' } { mailpoet_progress_complete: newsletter.queue.status === 'completed' }
); );
// calculate percentage done // calculate percentage done
@ -84,8 +84,8 @@ const _QueueMixin = {
<span> <span>
{ {
MailPoet.I18n.t('newsletterQueueCompleted') MailPoet.I18n.t('newsletterQueueCompleted')
.replace("%$1d", newsletter.queue.count_processed) .replace('%$1d', newsletter.queue.count_processed)
.replace("%$2d", newsletter.queue.count_total) .replace('%$2d', newsletter.queue.count_total)
} }
</span> </span>
); );
@ -120,7 +120,7 @@ const _QueueMixin = {
percentage = MailPoet.I18n.t('noSubscribers'); percentage = MailPoet.I18n.t('noSubscribers');
} else { } else {
progress_bar_width = percentage; progress_bar_width = percentage;
percentage += "%"; percentage += '%';
} }
return ( return (
@ -128,7 +128,7 @@ const _QueueMixin = {
<div className={ progressClasses }> <div className={ progressClasses }>
<span <span
className="mailpoet_progress_bar" className="mailpoet_progress_bar"
style={ { width: progress_bar_width + "%" } } style={ { width: progress_bar_width + '%' } }
></span> ></span>
<span className="mailpoet_progress_label"> <span className="mailpoet_progress_label">
{ percentage } { percentage }
@ -145,13 +145,14 @@ const _QueueMixin = {
const _StatisticsMixin = { const _StatisticsMixin = {
renderStatistics: function (newsletter, is_sent, current_time) { renderStatistics: function (newsletter, is_sent, current_time) {
if (is_sent === undefined) { let sent = is_sent;
if (sent === undefined) {
// condition for standard and post notification listings // condition for standard and post notification listings
is_sent = newsletter.statistics sent = newsletter.statistics
&& newsletter.queue && newsletter.queue
&& newsletter.queue.status !== 'scheduled'; && newsletter.queue.status !== 'scheduled';
} }
if (!is_sent) { if (!sent) {
return ( return (
<span>{MailPoet.I18n.t('notSentYet')}</span> <span>{MailPoet.I18n.t('notSentYet')}</span>
); );
@ -238,7 +239,7 @@ const _StatisticsMixin = {
<div> <div>
<span className="mailpoet_stats_text"> <span className="mailpoet_stats_text">
{ percentage_opened_display }%, { percentage_opened_display }%,
{ " " } { ' ' }
{ percentage_clicked_display }% { percentage_clicked_display }%
<span className="mailpoet_stat_hidden"> <span className="mailpoet_stat_hidden">
, { percentage_unsubscribed_display }% , { percentage_unsubscribed_display }%
@ -326,7 +327,7 @@ const _MailerMixin = {
MailPoet.I18n.t('mailerCheckSettingsNotice'), MailPoet.I18n.t('mailerCheckSettingsNotice'),
/\[link\](.*?)\[\/link\]/g, /\[link\](.*?)\[\/link\]/g,
match => ( match => (
<a href={`?page=mailpoet-settings#mta`}>{ match }</a> <a href={'?page=mailpoet-settings#mta'} key="check-sending">{ match }</a>
) )
); );
if (state.meta.mta_log.error.operation === 'send') { if (state.meta.mta_log.error.operation === 'send') {

View File

@ -97,6 +97,17 @@ const bulk_actions = [
}, },
]; ];
const confirmEdit = (newsletter) => {
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 }`;
}
};
let newsletter_actions = [ let newsletter_actions = [
{ {
name: 'view', name: 'view',
@ -110,13 +121,8 @@ let newsletter_actions = [
}, },
{ {
name: 'edit', name: 'edit',
link: function (newsletter) { label: MailPoet.I18n.t('edit'),
return ( onClick: confirmEdit,
<a href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }>
{MailPoet.I18n.t('edit')}
</a>
);
},
}, },
{ {
name: 'duplicate', name: 'duplicate',
@ -172,7 +178,8 @@ const NewsletterListStandard = React.createClass({
<strong> <strong>
<a <a
className="row-title" className="row-title"
href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` } href="javascript:;"
onClick={() => confirmEdit(newsletter)}
>{ newsletter.queue.newsletter_rendered_subject || newsletter.subject }</a> >{ newsletter.queue.newsletter_rendered_subject || newsletter.subject }</a>
</strong> </strong>
{ actions } { actions }
@ -198,7 +205,14 @@ const NewsletterListStandard = React.createClass({
return ( return (
<div> <div>
<h1 className="title"> <h1 className="title">
{MailPoet.I18n.t('pageTitle')} <Link className="page-title-action" to="/new">{MailPoet.I18n.t('new')}</Link> {MailPoet.I18n.t('pageTitle')}
<Link className="page-title-action" to="/new"
onClick={() => MailPoet.trackEvent('Emails > Add New',
{ 'MailPoet Free version': window.mailpoet_version }
)}
>
{MailPoet.I18n.t('new')}
</Link>
</h1> </h1>
<ListingTabs tab="standard" /> <ListingTabs tab="standard" />

View File

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

View File

@ -5,18 +5,18 @@ const timeFormat = window.mailpoet_time_format || 'H:i';
// welcome emails // welcome emails
const _timeDelayValues = { const _timeDelayValues = {
'immediate': MailPoet.I18n.t('delayImmediately'), immediate: MailPoet.I18n.t('delayImmediately'),
'hours': MailPoet.I18n.t('delayHoursAfter'), hours: MailPoet.I18n.t('delayHoursAfter'),
'days': MailPoet.I18n.t('delayDaysAfter'), days: MailPoet.I18n.t('delayDaysAfter'),
'weeks': MailPoet.I18n.t('delayWeeksAfter'), weeks: MailPoet.I18n.t('delayWeeksAfter'),
}; };
const _intervalValues = { const _intervalValues = {
'daily': MailPoet.I18n.t('daily'), daily: MailPoet.I18n.t('daily'),
'weekly': MailPoet.I18n.t('weekly'), weekly: MailPoet.I18n.t('weekly'),
'monthly': MailPoet.I18n.t('monthly'), monthly: MailPoet.I18n.t('monthly'),
'nthWeekDay': MailPoet.I18n.t('monthlyEvery'), nthWeekDay: MailPoet.I18n.t('monthlyEvery'),
'immediately': MailPoet.I18n.t('immediately'), immediately: MailPoet.I18n.t('immediately'),
}; };
// notification emails // notification emails
@ -60,7 +60,7 @@ const _monthDayValues = _.object(
if (labels[day] !== undefined) { if (labels[day] !== undefined) {
label = labels[day]; label = labels[day];
} else { } else {
label = MailPoet.I18n.t('nth').replace("%$1d", day + 1); label = MailPoet.I18n.t('nth').replace('%$1d', day + 1);
} }
return [day + 1, label]; return [day + 1, label];
} }
@ -68,10 +68,10 @@ const _monthDayValues = _.object(
); );
const _nthWeekDayValues = { const _nthWeekDayValues = {
'1': MailPoet.I18n.t('first'), 1: MailPoet.I18n.t('first'),
'2': MailPoet.I18n.t('second'), 2: MailPoet.I18n.t('second'),
'3': MailPoet.I18n.t('third'), 3: MailPoet.I18n.t('third'),
'L': MailPoet.I18n.t('last'), L: MailPoet.I18n.t('last'),
}; };
export { _timeDelayValues as timeDelayValues }; export { _timeDelayValues as timeDelayValues };

View File

@ -9,6 +9,7 @@ define(
'newsletters/send/notification.jsx', 'newsletters/send/notification.jsx',
'newsletters/send/welcome.jsx', 'newsletters/send/welcome.jsx',
'newsletters/breadcrumb.jsx', 'newsletters/breadcrumb.jsx',
'help-tooltip.jsx',
], ],
( (
React, React,
@ -19,7 +20,8 @@ define(
StandardNewsletterFields, StandardNewsletterFields,
NotificationNewsletterFields, NotificationNewsletterFields,
WelcomeNewsletterFields, WelcomeNewsletterFields,
Breadcrumb Breadcrumb,
HelpTooltip
) => { ) => {
const NewsletterSend = React.createClass({ const NewsletterSend = React.createClass({
@ -108,16 +110,25 @@ define(
}).done((response) => { }).done((response) => {
// redirect to listing based on newsletter type // 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 // display success message depending on newsletter type
if (response.data.type === 'welcome') { if (response.data.type === 'welcome') {
MailPoet.Notice.success( MailPoet.Notice.success(
MailPoet.I18n.t('welcomeEmailActivated') MailPoet.I18n.t('welcomeEmailActivated')
); );
MailPoet.trackEvent('Emails > Welcome email activated', {
'MailPoet Free version': window.mailpoet_version,
'List type': opts.event,
Delay: opts.afterTimeNumber + ' ' + opts.afterTimeType,
});
} else if (response.data.type === 'notification') { } else if (response.data.type === 'notification') {
MailPoet.Notice.success( MailPoet.Notice.success(
MailPoet.I18n.t('postNotificationActivated') MailPoet.I18n.t('postNotificationActivated')
); );
MailPoet.trackEvent('Emails > Post notifications activated', {
'MailPoet Free version': window.mailpoet_version,
Frequency: opts.intervalType,
});
} }
}).fail(this._showError); }).fail(this._showError);
default: default:
@ -136,10 +147,18 @@ define(
MailPoet.Notice.success( MailPoet.Notice.success(
MailPoet.I18n.t('newsletterHasBeenScheduled') MailPoet.I18n.t('newsletterHasBeenScheduled')
); );
MailPoet.trackEvent('Emails > Newsletter sent', {
scheduled: true,
'MailPoet Free version': window.mailpoet_version,
});
} else { } else {
MailPoet.Notice.success( MailPoet.Notice.success(
MailPoet.I18n.t('newsletterBeingSent') MailPoet.I18n.t('newsletterBeingSent')
); );
MailPoet.trackEvent('Emails > Newsletter sent', {
scheduled: false,
'MailPoet Free version': window.mailpoet_version,
});
} }
}).fail(this._showError); }).fail(this._showError);
} }
@ -149,6 +168,40 @@ define(
} }
return false; return false;
}, },
handleResume: function (e) {
e.preventDefault();
if(!this.isValid()) {
jQuery('#mailpoet_newsletter').parsley().validate();
} else {
this._save(e).done(() => {
this.setState({ loading: true });
}).done(() => {
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'sendingQueue',
action: 'resume',
data: {
newsletter_id: this.state.item.id,
},
}).done(() => {
this.context.router.push(`/${ this.state.item.type || '' }`);
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterSendingHasBeenResumed')
);
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map((error) => { return error.message; }),
{ scroll: true }
);
}
});
}).fail(this._showError).always(() => {
this.setState({ loading: false });
});
}
return false;
},
handleSave: function (e) { handleSave: function (e) {
e.preventDefault(); e.preventDefault();
@ -174,6 +227,7 @@ define(
}, },
_save: function () { _save: function () {
const data = this.state.item; const data = this.state.item;
data.queue = undefined;
this.setState({ loading: true }); this.setState({ loading: true });
// Store only properties that can be changed on this page // Store only properties that can be changed on this page
@ -215,6 +269,16 @@ define(
return true; return true;
}, },
render: function () { render: function () {
const isPaused = this.state.item.status == 'sending'
&& this.state.item.queue
&& this.state.item.queue.status == 'paused';
const fields = this.state.fields.map((field) => {
const newField = field;
if (field.name == 'segments' || field.name == 'options') {
newField.disabled = isPaused;
}
return newField;
});
return ( return (
<div> <div>
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1> <h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
@ -223,13 +287,21 @@ define(
<Form <Form
id="mailpoet_newsletter" id="mailpoet_newsletter"
fields={ this.state.fields } fields={ fields }
item={ this.state.item } item={ this.state.item }
loading={ this.state.loading } loading={ this.state.loading }
onChange={this.handleFormChange} onChange={this.handleFormChange}
onSubmit={this.handleSave} onSubmit={this.handleSave}
> >
<p className="submit"> <p className="submit">
{
isPaused ?
<input
className="button button-primary"
type="button"
onClick={ this.handleResume }
value={MailPoet.I18n.t('resume')} />
:
<input <input
className="button button-primary" className="button button-primary"
type="button" type="button"
@ -237,6 +309,7 @@ define(
value={MailPoet.I18n.t('send')} value={MailPoet.I18n.t('send')}
{...this.getSendButtonOptions()} {...this.getSendButtonOptions()}
/> />
}
&nbsp; &nbsp;
<input <input
className="button button-secondary" className="button button-secondary"
@ -251,6 +324,10 @@ define(
{MailPoet.I18n.t('goBackToDesign')} {MailPoet.I18n.t('goBackToDesign')}
</a>. </a>.
</p> </p>
<HelpTooltip
tooltip={MailPoet.I18n.t('helpTooltipSendEmail')}
tooltipId="helpTooltipSendEmail"
/>
</Form> </Form>
</div> </div>
); );

View File

@ -8,12 +8,14 @@ define(
], ],
( (
React, React,
jQuery, jq,
_, _,
MailPoet, MailPoet,
Hooks Hooks
) => { ) => {
const jQuery = jq;
const currentTime = window.mailpoet_current_time || '00:00'; const currentTime = window.mailpoet_current_time || '00:00';
const defaultDateTime = window.mailpoet_current_date + ' ' + '00:00:00'; const defaultDateTime = window.mailpoet_current_date + ' ' + '00:00:00';
const timeOfDayItems = window.mailpoet_schedule_time_of_day; const timeOfDayItems = window.mailpoet_schedule_time_of_day;
@ -84,12 +86,13 @@ define(
const DateText = React.createClass({ const DateText = React.createClass({
onChange: function (event) { onChange: function (event) {
const changeEvent = event;
// Swap display format to storage format // Swap display format to storage format
const displayDate = event.target.value; const displayDate = changeEvent.target.value;
const storageDate = this.getStorageDate(displayDate); const storageDate = this.getStorageDate(displayDate);
event.target.value = storageDate; changeEvent.target.value = storageDate;
this.props.onChange(event); this.props.onChange(changeEvent);
}, },
componentDidMount: function () { componentDidMount: function () {
const $element = jQuery(this.refs.dateInput); const $element = jQuery(this.refs.dateInput);
@ -155,6 +158,7 @@ define(
name={this.getFieldName()} name={this.getFieldName()}
value={this.getDisplayDate(this.props.value)} value={this.getDisplayDate(this.props.value)}
readOnly={ true } readOnly={ true }
disabled={this.props.disabled}
onChange={this.onChange} onChange={this.onChange}
ref="dateInput" ref="dateInput"
{...this.props.validation} /> {...this.props.validation} />
@ -180,6 +184,7 @@ define(
<select <select
name={this.props.name || 'time'} name={this.props.name || 'time'}
value={this.props.value} value={this.props.value}
disabled={this.props.disabled}
onChange={this.props.onChange} onChange={this.props.onChange}
{...this.props.validation} {...this.props.validation}
> >
@ -190,7 +195,7 @@ define(
}); });
const DateTime = React.createClass({ const DateTime = React.createClass({
_DATE_TIME_SEPARATOR: " ", _DATE_TIME_SEPARATOR: ' ',
getInitialState: function () { getInitialState: function () {
return this._buildStateFromProps(this.props); return this._buildStateFromProps(this.props);
}, },
@ -235,11 +240,13 @@ define(
onChange={this.handleChange} onChange={this.handleChange}
displayFormat={dateDisplayFormat} displayFormat={dateDisplayFormat}
storageFormat={dateStorageFormat} storageFormat={dateStorageFormat}
disabled={this.props.disabled}
validation={this.props.dateValidation}/> validation={this.props.dateValidation}/>
<TimeSelect <TimeSelect
name="time" name="time"
value={this.state.time} value={this.state.time}
onChange={this.handleChange} onChange={this.handleChange}
disabled={this.props.disabled}
validation={this.props.timeValidation} /> validation={this.props.timeValidation} />
</span> </span>
); );
@ -269,8 +276,9 @@ define(
}); });
}, },
handleCheckboxChange: function (event) { handleCheckboxChange: function (event) {
event.target.value = this.refs.isScheduled.checked ? '1' : '0'; const changeEvent = event;
return this.handleValueChange(event); changeEvent.target.value = this.refs.isScheduled.checked ? '1' : '0';
return this.handleValueChange(changeEvent);
}, },
isScheduled: function () { isScheduled: function () {
return this._getCurrentValue().isScheduled === '1'; return this._getCurrentValue().isScheduled === '1';
@ -292,6 +300,7 @@ define(
name="scheduledAt" name="scheduledAt"
value={this._getCurrentValue().scheduledAt} value={this._getCurrentValue().scheduledAt}
onChange={this.handleValueChange} onChange={this.handleValueChange}
disabled={this.props.field.disabled}
dateValidation={this.getDateValidation()} /> dateValidation={this.getDateValidation()} />
&nbsp; &nbsp;
<span> <span>
@ -300,7 +309,6 @@ define(
</span> </span>
); );
} }
return ( return (
<div> <div>
<input <input
@ -308,6 +316,7 @@ define(
type="checkbox" type="checkbox"
value="1" value="1"
checked={this.isScheduled()} checked={this.isScheduled()}
disabled={this.props.field.disabled}
name="isScheduled" name="isScheduled"
onChange={this.handleCheckboxChange} /> onChange={this.handleCheckboxChange} />
@ -414,11 +423,11 @@ define(
return fields; return fields;
}, },
getSendButtonOptions: function (newsletter) { getSendButtonOptions: function (newsletter) {
newsletter = newsletter || {}; const newsletterOptions = newsletter || {};
const isScheduled = ( const isScheduled = (
typeof newsletter.options === 'object' typeof newsletterOptions.options === 'object'
&& newsletter.options.isScheduled === '1' && newsletterOptions.options.isScheduled === '1'
); );
const options = { const options = {
value: (isScheduled value: (isScheduled
@ -426,8 +435,8 @@ define(
: MailPoet.I18n.t('send')), : MailPoet.I18n.t('send')),
}; };
if (newsletter.status === 'sent' if (newsletterOptions.status === 'sent'
|| newsletter.status === 'sending') { || newsletterOptions.status === 'sending') {
options['disabled'] = 'disabled'; options['disabled'] = 'disabled';
} }

View File

@ -6,6 +6,7 @@ define(
'react-router', 'react-router',
'classnames', 'classnames',
'newsletters/breadcrumb.jsx', 'newsletters/breadcrumb.jsx',
'help-tooltip.jsx',
], ],
( (
React, React,
@ -13,11 +14,13 @@ define(
MailPoet, MailPoet,
Router, Router,
classNames, classNames,
Breadcrumb Breadcrumb,
HelpTooltip
) => { ) => {
const ImportTemplate = React.createClass({ const ImportTemplate = React.createClass({
saveTemplate: function (template) { saveTemplate: function (saveTemplate) {
const template = saveTemplate;
// Stringify to enable transmission of primitive non-string value types // Stringify to enable transmission of primitive non-string value types
if (!_.isUndefined(template.body)) { if (!_.isUndefined(template.body)) {
@ -49,6 +52,7 @@ define(
if (_.size(this.refs.templateFile.files) <= 0) return false; if (_.size(this.refs.templateFile.files) <= 0) return false;
const file = _.first(this.refs.templateFile.files); const file = _.first(this.refs.templateFile.files);
const reader = new FileReader(); const reader = new FileReader();
const saveTemplate = this.saveTemplate; const saveTemplate = this.saveTemplate;
@ -56,6 +60,9 @@ define(
reader.onload = (e) => { reader.onload = (e) => {
try { try {
saveTemplate(JSON.parse(e.target.result)); saveTemplate(JSON.parse(e.target.result));
MailPoet.trackEvent('Emails > Template imported', {
'MailPoet Free version': window.mailpoet_version,
});
} catch (err) { } catch (err) {
MailPoet.Notice.error(MailPoet.I18n.t('templateFileMalformedError')); MailPoet.Notice.error(MailPoet.I18n.t('templateFileMalformedError'));
} }
@ -66,10 +73,13 @@ define(
render: function () { render: function () {
return ( return (
<div> <div>
<h2>{MailPoet.I18n.t('importTemplateTitle')}</h2> <h2>{MailPoet.I18n.t('importTemplateTitle')} <HelpTooltip
tooltip={MailPoet.I18n.t('helpTooltipTemplateUpload')}
place="right"
className="tooltip-help-import-template"
/></h2>
<form onSubmit={this.handleSubmit}> <form onSubmit={this.handleSubmit}>
<input type="file" placeholder={MailPoet.I18n.t('selectJsonFileToUpload')} ref="templateFile" /> <input type="file" placeholder={MailPoet.I18n.t('selectJsonFileToUpload')} ref="templateFile" />
<p className="submit"> <p className="submit">
<input <input
className="button button-primary" className="button button-primary"
@ -112,7 +122,7 @@ define(
MailPoet.I18n.t('mailpoetGuideTemplateTitle'), MailPoet.I18n.t('mailpoetGuideTemplateTitle'),
description: description:
MailPoet.I18n.t('mailpoetGuideTemplateDescription'), MailPoet.I18n.t('mailpoetGuideTemplateDescription'),
readonly: "1", readonly: '1',
}, },
]; ];
} }
@ -138,6 +148,11 @@ define(
body = JSON.stringify(body); body = JSON.stringify(body);
} }
MailPoet.trackEvent('Emails > Template selected', {
'MailPoet Free version': window.mailpoet_version,
'Email name': template.name,
});
MailPoet.Ajax.post({ MailPoet.Ajax.post({
api_version: window.mailpoet_api_version, api_version: window.mailpoet_api_version,
endpoint: 'newsletters', endpoint: 'newsletters',
@ -164,7 +179,7 @@ define(
window.confirm( window.confirm(
( (
MailPoet.I18n.t('confirmTemplateDeletion') MailPoet.I18n.t('confirmTemplateDeletion')
).replace("%$1s", template.name) ).replace('%$1s', template.name)
) )
) { ) {
MailPoet.Ajax.post({ MailPoet.Ajax.post({
@ -248,7 +263,7 @@ define(
{MailPoet.I18n.t('select')} {MailPoet.I18n.t('select')}
</a> </a>
</div> </div>
{ (template.readonly === "1") ? false : deleteLink } { (template.readonly === '1') ? false : deleteLink }
</li> </li>
); );
}); });
@ -256,7 +271,7 @@ define(
const boxClasses = classNames( const boxClasses = classNames(
'mailpoet_boxes', 'mailpoet_boxes',
'clearfix', 'clearfix',
{ 'mailpoet_boxes_loading': this.state.loading } { mailpoet_boxes_loading: this.state.loading }
); );
return ( return (

View File

@ -20,9 +20,17 @@ define(
setupNewsletter: function (type) { setupNewsletter: function (type) {
if(type !== undefined) { if(type !== undefined) {
this.context.router.push(`/new/${type}`); this.context.router.push(`/new/${type}`);
MailPoet.trackEvent('Emails > Type selected', {
'MailPoet Free version': window.mailpoet_version,
'Email type': type,
});
} }
}, },
createNewsletter: function (type) { createNewsletter: function (type) {
MailPoet.trackEvent('Emails > Type selected', {
'MailPoet Free version': window.mailpoet_version,
'Email type': type,
});
MailPoet.Ajax.post({ MailPoet.Ajax.post({
api_version: window.mailpoet_api_version, api_version: window.mailpoet_api_version,
endpoint: 'newsletters', endpoint: 'newsletters',
@ -45,10 +53,10 @@ define(
render: function () { render: function () {
let types = [ let types = [
{ {
'id': 'standard', id: 'standard',
'title': MailPoet.I18n.t('regularNewsletterTypeTitle'), title: MailPoet.I18n.t('regularNewsletterTypeTitle'),
'description': MailPoet.I18n.t('regularNewsletterTypeDescription'), description: MailPoet.I18n.t('regularNewsletterTypeDescription'),
'action': function () { action: function () {
return ( 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')} {MailPoet.I18n.t('create')}
@ -57,10 +65,10 @@ define(
}.bind(this)(), }.bind(this)(),
}, },
{ {
'id': 'welcome', id: 'welcome',
'title': MailPoet.I18n.t('welcomeNewsletterTypeTitle'), title: MailPoet.I18n.t('welcomeNewsletterTypeTitle'),
'description': MailPoet.I18n.t('welcomeNewsletterTypeDescription'), description: MailPoet.I18n.t('welcomeNewsletterTypeDescription'),
'action': function () { action: function () {
return ( return (
<div> <div>
<a href="?page=mailpoet-premium" target="_blank"> <a href="?page=mailpoet-premium" target="_blank">
@ -71,10 +79,10 @@ define(
}(), }(),
}, },
{ {
'id': 'notification', id: 'notification',
'title': MailPoet.I18n.t('postNotificationNewsletterTypeTitle'), title: MailPoet.I18n.t('postNotificationNewsletterTypeTitle'),
'description': MailPoet.I18n.t('postNotificationNewsletterTypeDescription'), description: MailPoet.I18n.t('postNotificationNewsletterTypeDescription'),
'action': function () { action: function () {
return ( 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')} {MailPoet.I18n.t('setUp')}

View File

@ -16,8 +16,8 @@ const availableSegments = _.filter(
const events = { const events = {
name: 'event', name: 'event',
values: { values: {
'segment': MailPoet.I18n.t('onSubscriptionToList'), segment: MailPoet.I18n.t('onSubscriptionToList'),
'user': MailPoet.I18n.t('onWPUserRegistration'), user: MailPoet.I18n.t('onWPUserRegistration'),
}, },
}; };

View File

@ -1,5 +1,5 @@
define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) { define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
"use strict"; 'use strict';
/*================================================================================================== /*==================================================================================================
MailPoet Notice: MailPoet Notice:
@ -22,7 +22,7 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
MailPoet.Notice.system('You need to updated ASAP!'); MailPoet.Notice.system('You need to updated ASAP!');
==================================================================================================*/ ==================================================================================================*/
var MailPoet = mp;
MailPoet.Notice = { MailPoet.Notice = {
version: 1.0, version: 1.0,
// default options // default options
@ -103,12 +103,12 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
); );
}, },
setMessage: function(message) { setMessage: function(message) {
message = this.formatMessage(message); var formattedMessage = this.formatMessage(message);
// let's sugar coat the message with a fancy <p> // let's sugar coat the message with a fancy <p>
message = '<p>'+message+'</p>'; formattedMessage = '<p>'+formattedMessage+'</p>';
// set message // set message
return this.element.html(message); return this.element.html(formattedMessage);
}, },
formatMessage: function(message) { formatMessage: function(message) {
if (Array.isArray(message)) { if (Array.isArray(message)) {
@ -124,7 +124,7 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
if ( if (
this.options.id !== null this.options.id !== null
&& &&
jQuery('[data-id="'+this.options.id+'"').length > 0 jQuery('[data-id="'+this.options.id+'"]').length > 0
) { ) {
this.updateNotice(); this.updateNotice();
} else { } else {

View File

@ -2,13 +2,14 @@ define('num',
[ [
'mailpoet' 'mailpoet'
], function( ], function(
MailPoet mp
) { ) {
'use strict'; 'use strict';
var MailPoet = mp;
MailPoet.Num = { MailPoet.Num = {
toLocaleFixed: function (num, precision) { toLocaleFixed: function (num, precisionOpts) {
precision = precision || 0; var precision = precisionOpts || 0;
var factor = Math.pow(10, precision); var factor = Math.pow(10, precision);
return (Math.round(num * factor) / factor) return (Math.round(num * factor) / factor)
.toLocaleString( .toLocaleString(

View File

@ -32,6 +32,9 @@ define(
}, },
onCreate: function () { onCreate: function () {
MailPoet.Notice.success(MailPoet.I18n.t('segmentAdded')); MailPoet.Notice.success(MailPoet.I18n.t('segmentAdded'));
MailPoet.trackEvent('Lists > Add new', {
'MailPoet Free version': window.mailpoet_version,
});
}, },
}; };

View File

@ -15,9 +15,9 @@ define(
MailPoet.Modal.loading(true); MailPoet.Modal.loading(true);
MailPoet.Ajax.post({ MailPoet.Ajax.post({
'api_version': window.mailpoet_api_version, api_version: window.mailpoet_api_version,
'endpoint': 'setup', endpoint: 'setup',
'action': 'reset' action: 'reset'
}).always(function () { }).always(function () {
MailPoet.Modal.loading(false); MailPoet.Modal.loading(false);
}).done(function () { }).done(function () {

View File

@ -7,8 +7,9 @@ define(
function( function(
Backbone, Backbone,
jQuery, jQuery,
MailPoet mp
) { ) {
var MailPoet = mp;
if(jQuery('#mailpoet_settings').length === 0) { if(jQuery('#mailpoet_settings').length === 0) {
return; return;
} }
@ -50,9 +51,9 @@ define(
jQuery('#mailpoet_sending_method_setup').fadeIn(); jQuery('#mailpoet_sending_method_setup').fadeIn();
} }
}, },
tabs: function(tab, section) { tabs: function(tabStr, section) {
// set default tab // set default tab
tab = tab || 'mta'; var tab = tabStr || 'mta';
// reset all active tabs // reset all active tabs
jQuery('.nav-tab-wrapper a').removeClass('nav-tab-active'); jQuery('.nav-tab-wrapper a').removeClass('nav-tab-active');

View File

@ -43,10 +43,10 @@ define(
label: MailPoet.I18n.t('status'), label: MailPoet.I18n.t('status'),
type: 'select', type: 'select',
values: { values: {
'subscribed': MailPoet.I18n.t('subscribed'), subscribed: MailPoet.I18n.t('subscribed'),
'unconfirmed': MailPoet.I18n.t('unconfirmed'), unconfirmed: MailPoet.I18n.t('unconfirmed'),
'unsubscribed': MailPoet.I18n.t('unsubscribed'), unsubscribed: MailPoet.I18n.t('unsubscribed'),
'bounced': MailPoet.I18n.t('bounced'), bounced: MailPoet.I18n.t('bounced'),
}, },
filter: function (subscriber, value) { filter: function (subscriber, value) {
if (~~(subscriber.wp_user_id) > 0 && value === 'unconfirmed') { if (~~(subscriber.wp_user_id) > 0 && value === 'unconfirmed') {
@ -144,6 +144,9 @@ define(
}, },
onCreate: function () { onCreate: function () {
MailPoet.Notice.success(MailPoet.I18n.t('subscriberAdded')); MailPoet.Notice.success(MailPoet.I18n.t('subscriberAdded'));
MailPoet.trackEvent('Subscribers > Add new', {
'MailPoet Free version': window.mailpoet_version,
});
}, },
}; };

View File

@ -13,7 +13,7 @@ define(
Handlebars, Handlebars,
select2 select2
) { ) {
if (!jQuery("#mailpoet_subscribers_export").length) { if (!jQuery('#mailpoet_subscribers_export').length) {
return; return;
} }
jQuery(document).ready(function () { jQuery(document).ready(function () {
@ -27,11 +27,11 @@ define(
jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(exportData)); jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(exportData));
// define reusable variables // define reusable variables
var segmentsContainerElement = jQuery("#export_lists"), var segmentsContainerElement = jQuery('#export_lists'),
subscriberFieldsContainerElement = jQuery("#export_columns"), subscriberFieldsContainerElement = jQuery('#export_columns'),
exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]'), exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]'),
groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]'), groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]'),
nextStepButton = jQuery("a.mailpoet_export_process"), nextStepButton = jQuery('a.mailpoet_export_process'),
renderSegmentsAndFields = function (container, data) { renderSegmentsAndFields = function (container, data) {
if (container.data('select2')) { if (container.data('select2')) {
container container
@ -107,7 +107,7 @@ define(
'first_name', 'first_name',
'last_name', 'last_name',
'status' 'status'
]).trigger("change"); ]).trigger('change');
exportConfirmedOptionElement.change(function () { exportConfirmedOptionElement.change(function () {
var selectedSegments = segmentsContainerElement.val(); var selectedSegments = segmentsContainerElement.val();
@ -137,16 +137,17 @@ define(
return; return;
} }
MailPoet.Modal.loading(true); MailPoet.Modal.loading(true);
var exportFormat = jQuery(':radio[name="option_format"]:checked').val();
MailPoet.Ajax.post({ MailPoet.Ajax.post({
api_version: window.mailpoet_api_version, api_version: window.mailpoet_api_version,
endpoint: 'ImportExport', endpoint: 'ImportExport',
action: 'processExport', action: 'processExport',
data: JSON.stringify({ data: JSON.stringify({
'export_confirmed_option': exportData.exportConfirmedOption, export_confirmed_option: exportData.exportConfirmedOption,
'export_format_option': jQuery(':radio[name="option_format"]:checked').val(), export_format_option: exportFormat,
'group_by_segment_option': (groupBySegmentOptionElement.is(":visible")) ? groupBySegmentOptionElement.prop('checked') : false, group_by_segment_option: (groupBySegmentOptionElement.is(':visible')) ? groupBySegmentOptionElement.prop('checked') : false,
'segments': (exportData.segments) ? segmentsContainerElement.val() : false, segments: (exportData.segments) ? segmentsContainerElement.val() : false,
'subscriber_fields': subscriberFieldsContainerElement.val() subscriber_fields: subscriberFieldsContainerElement.val()
}) })
}).always(function(response) { }).always(function(response) {
MailPoet.Modal.loading(false); MailPoet.Modal.loading(false);
@ -157,6 +158,12 @@ define(
.replace('[/link]', '</a>'); .replace('[/link]', '</a>');
jQuery('#export_result_notice').html('<p>' + resultMessage + '</p>').show(); jQuery('#export_result_notice').html('<p>' + resultMessage + '</p>').show();
window.location.href = response.data.exportFileURL; window.location.href = response.data.exportFileURL;
MailPoet.trackEvent('Subscribers export completed', {
'Total exported': response.data.totalExported,
'Only confirmed?': exportData.exportConfirmedOption,
'File Format': exportFormat,
'MailPoet Free version': window.mailpoet_version
});
}).fail(function(response) { }).fail(function(response) {
if (response.errors.length > 0) { if (response.errors.length > 0) {
MailPoet.Notice.error( MailPoet.Notice.error(

View File

@ -30,9 +30,9 @@ define(
router = new (Backbone.Router.extend({ router = new (Backbone.Router.extend({
routes: { routes: {
'': 'home', '': 'home',
'step1': 'step1', step1: 'step1',
'step2': 'step2', step2: 'step2',
'step3': 'step3' step3: 'step3'
}, },
home: function () { home: function () {
this.navigate('step1', {trigger: true}); this.navigate('step1', {trigger: true});
@ -52,8 +52,9 @@ define(
router.on('route:step1', function () { router.on('route:step1', function () {
// set or reset temporary validation rule on all columns // set or reset temporary validation rule on all columns
mailpoetColumns = jQuery.map(mailpoetColumns, function (column, columnIndex) { mailpoetColumns = jQuery.map(mailpoetColumns, function (column, columnIndex) {
column.validation_rule = false; var col = column;
return column; col.validation_rule = false;
return col;
}); });
if (typeof (importData.step1) !== 'undefined') { if (typeof (importData.step1) !== 'undefined') {
@ -111,7 +112,7 @@ define(
* Paste * Paste
*/ */
pasteInputElement pasteInputElement
.attr('value', pasteInputPlaceholderElement).css('color', "#999") .attr('value', pasteInputPlaceholderElement).css('color', '#999')
.focus(function () { .focus(function () {
if (jQuery(this).val() === pasteInputPlaceholderElement) { if (jQuery(this).val() === pasteInputPlaceholderElement) {
jQuery(this).attr('value', '').css('color', '#222'); jQuery(this).attr('value', '').css('color', '#222');
@ -119,7 +120,7 @@ define(
}) })
.blur(function () { .blur(function () {
if (jQuery(this).val() === '') { if (jQuery(this).val() === '') {
jQuery(this).attr('value', pasteInputPlaceholderElement).css('color', "#999"); jQuery(this).attr('value', pasteInputPlaceholderElement).css('color', '#999');
} }
}) })
.keyup(function () { .keyup(function () {
@ -140,7 +141,7 @@ define(
// delay loading indicator for 10ms or else it's just too fast :) // delay loading indicator for 10ms or else it's just too fast :)
MailPoet.Modal.loading(true); MailPoet.Modal.loading(true);
setTimeout(function () { setTimeout(function () {
Papa.parse(pasteInputElement.val(), parseCSV()); Papa.parse(pasteInputElement.val(), parseCSV(false));
}, 10); }, 10);
}); });
@ -167,7 +168,7 @@ define(
MailPoet.Modal.loading(true); MailPoet.Modal.loading(true);
setTimeout(function () { setTimeout(function () {
uploadElement.parse({ uploadElement.parse({
config: parseCSV() config: parseCSV(true)
}) })
}, 10); }, 10);
} }
@ -237,6 +238,10 @@ define(
MailPoet.Modal.loading(false); MailPoet.Modal.loading(false);
}).done(function(response) { }).done(function(response) {
importData.step1 = response.data; importData.step1 = response.data;
MailPoet.trackEvent('Subscribers import started', {
source: 'MailChimp',
'MailPoet Free version': window.mailpoet_version
});
router.navigate('step2', {trigger: true}); router.navigate('step2', {trigger: true});
}).fail(function(response) { }).fail(function(response) {
if (response.errors.length > 0) { if (response.errors.length > 0) {
@ -288,7 +293,7 @@ define(
element.closest('table a').addClass(disabled); element.closest('table a').addClass(disabled);
} }
function parseCSV() { function parseCSV(isFile) {
var processedSubscribers = [], var processedSubscribers = [],
parsedEmails = [], parsedEmails = [],
duplicateEmails = [], duplicateEmails = [],
@ -302,10 +307,10 @@ define(
advancedOptionComments = false, advancedOptionComments = false,
// trim spaces, commas, periods, // trim spaces, commas, periods,
// single/double quotes and convert to lowercase // single/double quotes and convert to lowercase
detectAndCleanupEmail = function (email) { detectAndCleanupEmail = function (emailString) {
var test; var test;
// decode HTML entities // decode HTML entities
email = jQuery('<div />').html(email).text(); var email = jQuery('<div />').html(emailString).text();
email = email email = email
.toLowerCase() .toLowerCase()
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ") // left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
@ -315,11 +320,13 @@ define(
// remove urlencoded characters // remove urlencoded characters
.replace(/\s+|%\d+|,+/g, ''); .replace(/\s+|%\d+|,+/g, '');
// detect e-mails that will be otherwise rejected by email regex // detect e-mails that will be otherwise rejected by email regex
if (test = /<(.*?)>/.exec(email)) { test = /<(.*?)>/.exec(email);
if (test) {
// is the email inside angle brackets (e.g., 'some@email.com <some@email.com>')? // is the email inside angle brackets (e.g., 'some@email.com <some@email.com>')?
email = test[1].trim(); email = test[1].trim();
} }
if (test = /mailto:(?:\s+)?(.*)/.exec(email)) { test = /mailto:(?:\s+)?(.*)/.exec(email);
if (test) {
// is the email in 'mailto:email' format? // is the email in 'mailto:email' format?
email = test[1].trim(); email = test[1].trim();
} }
@ -375,7 +382,7 @@ define(
processedSubscribers[0] = rowData; processedSubscribers[0] = rowData;
} }
} }
else if (rowData[emailColumnPosition] !== "") { else if (rowData[emailColumnPosition] !== '') {
var email = detectAndCleanupEmail(rowData[emailColumnPosition]); var email = detectAndCleanupEmail(rowData[emailColumnPosition]);
if (_.has(parsedEmails, email)) { if (_.has(parsedEmails, email)) {
duplicateEmails.push(email); duplicateEmails.push(email);
@ -404,14 +411,18 @@ define(
// since we assume that the header line is always present, we need // since we assume that the header line is always present, we need
// to detect the header by checking if it contains a valid e-mail address // to detect the header by checking if it contains a valid e-mail address
importData.step1 = { importData.step1 = {
'header': (!emailRegex.test( header: (!emailRegex.test(
processedSubscribers[0][emailColumnPosition]) processedSubscribers[0][emailColumnPosition])
) ? processedSubscribers.shift() : null, ) ? processedSubscribers.shift() : null,
'subscribers': processedSubscribers, subscribers: processedSubscribers,
'subscribersCount': processedSubscribers.length, subscribersCount: processedSubscribers.length,
'duplicate': duplicateEmails, duplicate: duplicateEmails,
'invalid': invalidEmails invalid: invalidEmails
}; };
MailPoet.trackEvent('Subscribers import started', {
source: isFile ? 'file upload' : 'pasted data',
'MailPoet Free version': window.mailpoet_version
});
router.navigate('step2', {trigger: true}); router.navigate('step2', {trigger: true});
} }
else { else {
@ -509,7 +520,7 @@ define(
var details = jQuery('.mailpoet_subscribers_data_parse_results_details'); var details = jQuery('.mailpoet_subscribers_data_parse_results_details');
jQuery(details).toggle(); jQuery(details).toggle();
this.text = this.text =
(jQuery(details).is(":visible")) (jQuery(details).is(':visible'))
? MailPoet.I18n.t('hideDetails') ? MailPoet.I18n.t('hideDetails')
: MailPoet.I18n.t('showDetails'); : MailPoet.I18n.t('showDetails');
}); });
@ -534,12 +545,14 @@ define(
data: segments, data: segments,
width: '20em', width: '20em',
templateResult: function (item) { templateResult: function (item) {
item.subscriberCount = parseInt(item.subscriberCount); var i = item;
return item.name + ' (' + item.subscriberCount.toLocaleString() + ')'; i.subscriberCount = parseInt(i.subscriberCount, 10);
return i.name + ' (' + i.subscriberCount.toLocaleString() + ')';
}, },
templateSelection: function (item) { templateSelection: function (item) {
item.subscriberCount = parseInt(item.subscriberCount); var i = item;
return item.name + ' (' + item.subscriberCount.toLocaleString() + ')'; i.subscriberCount = parseInt(i.subscriberCount, 10);
return i.name + ' (' + i.subscriberCount.toLocaleString() + ')';
} }
}) })
.change(function () { .change(function () {
@ -587,9 +600,9 @@ define(
} }
}).done(function(response) { }).done(function(response) {
mailpoetSegments.push({ mailpoetSegments.push({
'id': response.data.id, id: response.data.id,
'name': response.data.name, name: response.data.name,
'subscriberCount': 0 subscriberCount: 0
}); });
var selected_values = segmentSelectElement.val(); var selected_values = segmentSelectElement.val();
@ -621,7 +634,7 @@ define(
// register partial template that will contain subscribers data // register partial template that will contain subscribers data
Handlebars.registerPartial( Handlebars.registerPartial(
"subscribers_data_template_partial", 'subscribers_data_template_partial',
subscribersDataTemplatePartial subscribersDataTemplatePartial
); );
@ -665,7 +678,7 @@ define(
&& displayedColumnsIds.indexOf(columnId) === -1) && displayedColumnsIds.indexOf(columnId) === -1)
? columnId ? columnId
: 'ignore'; : 'ignore';
displayedColumns[i] = {'column_id': columnId}; displayedColumns[i] = {column_id: columnId};
displayedColumnsIds.push(columnId); displayedColumnsIds.push(columnId);
} }
return options.fn(displayedColumns); return options.fn(displayedColumns);
@ -742,17 +755,17 @@ define(
data: data data: data
}).done(function(response) { }).done(function(response) {
var new_column_data = { var new_column_data = {
'id': response.data.id, id: response.data.id,
'name': response.data.name, name: response.data.name,
'type': response.data.type, type: response.data.type,
'params': response.data.params, params: response.data.params,
'custom': true custom: true
}; };
// if this is the first custom column, create an "optgroup" // if this is the first custom column, create an "optgroup"
if (mailpoetColumnsSelect2.length === 2) { if (mailpoetColumnsSelect2.length === 2) {
mailpoetColumnsSelect2.push({ mailpoetColumnsSelect2.push({
'name': MailPoet.I18n.t('userColumns'), name: MailPoet.I18n.t('userColumns'),
'children': [] children: []
}); });
} }
mailpoetColumnsSelect2[2].children.push(new_column_data); mailpoetColumnsSelect2[2].children.push(new_column_data);
@ -894,7 +907,8 @@ define(
} }
} }
} }
jQuery.map(subscribersClone.subscribers, function (data, index) { jQuery.map(subscribersClone.subscribers, function (dataSubscribers, index) {
var data = dataSubscribers;
var rowData = data[matchedColumn.index]; var rowData = data[matchedColumn.index];
if (index === fillerPosition || rowData.trim() === '') return; if (index === fillerPosition || rowData.trim() === '') return;
var date = Moment(rowData, testedFormat, true); var date = Moment(rowData, testedFormat, true);
@ -968,10 +982,10 @@ define(
timestamp = Date.now() / 1000, timestamp = Date.now() / 1000,
subscribers = [], subscribers = [],
importResults = { importResults = {
'created': 0, created: 0,
'updated': 0, updated: 0,
'errors': [], errors: [],
'segments': [] segments: []
}, },
splitSubscribers = function (subscribers, size) { splitSubscribers = function (subscribers, size) {
return subscribers.reduce(function (res, item, index) { return subscribers.reduce(function (res, item, index) {
@ -1064,6 +1078,12 @@ define(
MailPoet.Notice.error(_.flatten(importData.step2.errors)); MailPoet.Notice.error(_.flatten(importData.step2.errors));
} }
MailPoet.trackEvent('Subscribers import finished', {
'Subscribers created': importData.step2.created,
'Subscribers updated': importData.step2.updated,
'MailPoet Free version': window.mailpoet_version
});
// display statistics // display statistics
var subscribersDataImportResultsTemplate = var subscribersDataImportResultsTemplate =
Handlebars Handlebars

View File

@ -88,7 +88,7 @@ const messages = {
<div> <div>
<p>{MailPoet.I18n.t('bouncedSubscribersHelp')}</p> <p>{MailPoet.I18n.t('bouncedSubscribersHelp')}</p>
<p> <p>
<a href={ `admin.php?page=mailpoet-premium` } className="button-primary"> <a href={ 'admin.php?page=mailpoet-premium' } className="button-primary">
{MailPoet.I18n.t('bouncedSubscribersPremiumButtonText')} {MailPoet.I18n.t('bouncedSubscribersPremiumButtonText')}
</a> </a>
</p> </p>

View File

@ -0,0 +1,50 @@
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
settings:
colors: true
memory_limit: 1024M
log: true
strict_xml: true
extensions:
enabled:
- Codeception\Extension\RunFailed
modules:
config:
WPWebDriver:
host: chrome
url: 'http://wordpress'
browser: chrome
port: 4444
window_size: '1024x768'
restart: true
wait: 0
adminUsername: admin
adminPassword: password
adminPath: /wp-admin
WPLoader:
wpRootFolder: /wp-core
dbName: wordpress
dbHost: mysql
dbUser: wordpress
dbPassword: wordpress
wpDebug: false
tablePrefix: wp_
domain: wordpress
plugins: ['mailpoet/mailpoet.php']
activatePlugins: ['mailpoet/mailpoet.php']
coverage:
enabled: true
whitelist:
include:
- lib/*
exclude:
- lib/Config/PopulatorData/*
- lib/Util/Sudzy/*
- lib/Util/CSS.php
- lib/Util/Helpers.php
- lib/Util/XLSXWriter.php

View File

@ -20,10 +20,12 @@
}, },
"require-dev": { "require-dev": {
"codeception/aspect-mock": "^2.0", "codeception/aspect-mock": "^2.0",
"codeception/codeception": "2.2.11", "codeception/codeception": "2.3.5",
"codeception/verify": "^0.3.3", "codeception/verify": "^0.3.3",
"consolidation/robo": "^1.0.5", "consolidation/robo": "^1.0.5",
"henrikbjorn/lurker": "^1.2", "henrikbjorn/lurker": "^1.2",
"lucatume/wp-browser": "1.19.12",
"phpunit/phpunit": "4.8.21",
"vlucas/phpdotenv": "^2.4.0", "vlucas/phpdotenv": "^2.4.0",
"umpirsky/twig-gettext-extractor": "1.1.*", "umpirsky/twig-gettext-extractor": "1.1.*",
"raveren/kint": "^1.0", "raveren/kint": "^1.0",

2211
composer.lock generated

File diff suppressed because it is too large Load Diff

47
docker-compose.yml Normal file
View File

@ -0,0 +1,47 @@
version: '2'
services:
codeception:
build: .
depends_on:
- wordpress
volumes:
- ./:/project
- wp-core:/wp-core
- ./:/wp-core/wp-content/plugins/mailpoet
entrypoint: /docker-entrypoint.sh
wordpress:
build: ./tests/wordpressDockerfile
image: wordpress:latest
depends_on:
- mysql
- chrome
volumes:
- wp-core:/var/www/html
- ./:/var/www/html/wp-content/plugins/mailpoet
- /tmp:/var/www/html/wp-content/uploads/mailpoet/cache
ports:
- 8080:80
environment:
WORDPRESS_DB_PASSWORD: wordpress
mysql:
image: mysql:5.6
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
chrome:
environment:
- DBUS_SESSION_BUS_ADDRESS=/dev/null
volumes:
- /dev/shm:/dev/shm
image: selenium/standalone-chrome-debug
ports:
- '4444'
- '5900:5900'
volumes:
wp-core:

42
docker-entrypoint.sh Normal file
View File

@ -0,0 +1,42 @@
#!/bin/bash
# Allows WP CLI to run with the right permissions.
wp-su() {
sudo -E -u www-data wp "$@"
}
while ! mysqladmin ping -hmysql --silent; do
echo 'Waiting for the database'
sleep 1
done
# Make sure permissions are correct.
cd /wp-core
chown www-data:www-data wp-content/plugins
chmod 755 wp-content/plugins
# Make sure WordPress is installed.
if ! $(wp-su core is-installed); then
echo "Installing WordPress"
wp-su core install --url=wordpress --title=tests --admin_user=admin --admin_email=test@test.com
echo "Configuring WordPress"
# The development version of Gravity Flow requires SCRIPT_DEBUG
wp-su core config --dbhost=mysql --dbname=wordpress --dbuser=wordpress --dbpass=wordpress --extra-php="define( 'SCRIPT_DEBUG', true );" --force
fi
rm -rf /project/vendor_backup
mv /project/vendor /project/vendor_backup
cd /project
php composer.phar install
cd /wp-core/wp-content/plugins/mailpoet
/project/vendor/bin/codecept run acceptance -c codeception.acceptance.yml $@
rm -rf /project/vendor
mv /project/vendor_backup /project/vendor

View File

@ -1,11 +1,14 @@
<?php <?php
namespace MailPoet\API; namespace MailPoet\API;
use MailPoet\Config\AccessControl;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class API { class API {
static function JSON() { static function JSON(AccessControl $access_control) {
return new \MailPoet\API\JSON\API(); return new \MailPoet\API\JSON\API($access_control);
} }
static function MP($version) { static function MP($version) {

View File

@ -1,7 +1,7 @@
<?php <?php
namespace MailPoet\API\JSON; namespace MailPoet\API\JSON;
use MailPoet\Config\Env; use MailPoet\Config\AccessControl;
use MailPoet\Util\Helpers; use MailPoet\Util\Helpers;
use MailPoet\Util\Security; use MailPoet\Util\Security;
use MailPoet\WP\Hooks; use MailPoet\WP\Hooks;
@ -19,9 +19,11 @@ class API {
private $_available_api_versions = array( private $_available_api_versions = array(
'v1' 'v1'
); );
private $access_control;
const CURRENT_VERSION = 'v1'; const CURRENT_VERSION = 'v1';
function __construct() { function __construct(AccessControl $access_control) {
$this->access_control = $access_control;
foreach($this->_available_api_versions as $available_api_version) { foreach($this->_available_api_versions as $available_api_version) {
$this->addEndpointNamespace( $this->addEndpointNamespace(
sprintf('%s\%s', __NAMESPACE__, $available_api_version), sprintf('%s\%s', __NAMESPACE__, $available_api_version),
@ -130,17 +132,11 @@ class API {
// check the accessibility of the requested endpoint's action // check the accessibility of the requested endpoint's action
// by default, an endpoint's action is considered "private" // by default, an endpoint's action is considered "private"
$permissions = $endpoint->permissions; if(!$this->validatePermissions($this->_request_method, $endpoint->permissions)) {
if(array_key_exists($this->_request_method, $permissions) === false ||
$permissions[$this->_request_method] !== Access::ALL
) {
if($this->checkPermissions() === false) {
$error_message = __('You do not have the required permissions.', 'mailpoet'); $error_message = __('You do not have the required permissions.', 'mailpoet');
$error_response = $this->createErrorResponse(Error::FORBIDDEN, $error_message, Response::STATUS_FORBIDDEN); $error_response = $this->createErrorResponse(Error::FORBIDDEN, $error_message, Response::STATUS_FORBIDDEN);
return $error_response; return $error_response;
} }
}
$response = $endpoint->{$this->_request_method}($this->_request_data); $response = $endpoint->{$this->_request_method}($this->_request_data);
return $response; return $response;
} catch(\Exception $e) { } catch(\Exception $e) {
@ -150,8 +146,11 @@ class API {
} }
} }
function checkPermissions() { function validatePermissions($request_method, $permissions) {
return current_user_can(Env::$required_permission); // validate method permission if defined, otherwise validate global permission
return(!empty($permissions['methods'][$request_method])) ?
$this->access_control->validatePermission($permissions['methods'][$request_method]) :
$this->access_control->validatePermission($permissions['global']);
} }
function checkToken() { function checkToken() {

View File

@ -1,12 +0,0 @@
<?php
namespace MailPoet\API\JSON;
if(!defined('ABSPATH')) exit;
final class Access {
const ALL = 'all';
private function __construct() {
}
}

View File

@ -1,11 +1,16 @@
<?php <?php
namespace MailPoet\API\JSON; namespace MailPoet\API\JSON;
use MailPoet\Config\AccessControl;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
abstract class Endpoint { abstract class Endpoint {
public $permissions = array(
public $permissions = array(); 'global' => AccessControl::PERMISSION_MANAGE_SETTINGS,
'methods' => array()
);
function successResponse( function successResponse(
$data = array(), $meta = array(), $status = Response::STATUS_OK $data = array(), $meta = array(), $status = Response::STATUS_OK

View File

@ -1,12 +1,18 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\Config\AccessControl;
use MailPoet\WP\Posts as WPPosts; use MailPoet\WP\Posts as WPPosts;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class AutomatedLatestContent extends APIEndpoint { class AutomatedLatestContent extends APIEndpoint {
public $ALC; public $ALC;
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_EMAILS
);
function __construct() { function __construct() {
$this->ALC = new \MailPoet\Newsletter\AutomatedLatestContent(); $this->ALC = new \MailPoet\Newsletter\AutomatedLatestContent();

View File

@ -1,12 +1,19 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\Config\AccessControl;
use MailPoet\Models\CustomField; use MailPoet\Models\CustomField;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class CustomFields extends APIEndpoint { class CustomFields extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_FORMS
);
function getAll() { function getAll() {
$collection = CustomField::orderByAsc('created_at')->findMany(); $collection = CustomField::orderByAsc('created_at')->findMany();
$custom_fields = array_map(function($custom_field) { $custom_fields = array_map(function($custom_field) {

View File

@ -1,17 +1,23 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\Config\AccessControl;
use MailPoet\Form\Renderer as FormRenderer;
use MailPoet\Form\Util;
use MailPoet\Listing;
use MailPoet\Models\Form; use MailPoet\Models\Form;
use MailPoet\Models\StatisticsForms; use MailPoet\Models\StatisticsForms;
use MailPoet\Form\Renderer as FormRenderer;
use MailPoet\Listing;
use MailPoet\Form\Util;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class Forms extends APIEndpoint { class Forms extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_FORMS
);
function get($data = array()) { function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false); $id = (isset($data['id']) ? (int)$data['id'] : false);
$form = Form::findOne($id); $form = Form::findOne($id);

View File

@ -1,13 +1,19 @@
<?php <?php
namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\Subscribers\ImportExport\Import\MailChimp; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\Config\AccessControl;
use MailPoet\Models\Segment; use MailPoet\Models\Segment;
use MailPoet\Subscribers\ImportExport\Import\MailChimp;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class ImportExport extends APIEndpoint { class ImportExport extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_SUBSCRIBERS
);
function getMailChimpLists($data) { function getMailChimpLists($data) {
try { try {
$mailChimp = new MailChimp($data['api_key']); $mailChimp = new MailChimp($data['api_key']);

View File

@ -1,10 +1,16 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\Config\AccessControl;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class MP2Migrator extends APIEndpoint { class MP2Migrator extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_SETTINGS
);
public function __construct() { public function __construct() {
$this->MP2Migrator = new \MailPoet\Config\MP2Migrator(); $this->MP2Migrator = new \MailPoet\Config\MP2Migrator();

View File

@ -1,12 +1,19 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\Config\AccessControl;
use MailPoet\Mailer\MailerLog; use MailPoet\Mailer\MailerLog;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class Mailer extends APIEndpoint { class Mailer extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_EMAILS
);
function send($data = array()) { function send($data = array()) {
try { try {
$mailer = new \MailPoet\Mailer\Mailer( $mailer = new \MailPoet\Mailer\Mailer(

View File

@ -1,13 +1,19 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\Config\AccessControl;
use MailPoet\Models\NewsletterTemplate; use MailPoet\Models\NewsletterTemplate;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class NewsletterTemplates extends APIEndpoint { class NewsletterTemplates extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_EMAILS
);
function get($data = array()) { function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false); $id = (isset($data['id']) ? (int)$data['id'] : false);
$template = NewsletterTemplate::findOne($id); $template = NewsletterTemplate::findOne($id);

View File

@ -1,16 +1,19 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use Carbon\Carbon;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\Config\AccessControl;
use MailPoet\Listing; use MailPoet\Listing;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterOption;
use MailPoet\Models\NewsletterOptionField;
use MailPoet\Models\NewsletterSegment;
use MailPoet\Models\NewsletterTemplate;
use MailPoet\Models\SendingQueue; use MailPoet\Models\SendingQueue;
use MailPoet\Models\Setting; use MailPoet\Models\Setting;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterTemplate;
use MailPoet\Models\NewsletterSegment;
use MailPoet\Models\NewsletterOptionField;
use MailPoet\Models\NewsletterOption;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Renderer\Renderer; use MailPoet\Newsletter\Renderer\Renderer;
use MailPoet\Newsletter\Scheduler\Scheduler; use MailPoet\Newsletter\Scheduler\Scheduler;
@ -22,6 +25,10 @@ if(!defined('ABSPATH')) exit;
require_once(ABSPATH . 'wp-includes/pluggable.php'); require_once(ABSPATH . 'wp-includes/pluggable.php');
class Newsletters extends APIEndpoint { class Newsletters extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_EMAILS
);
function get($data = array()) { function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false); $id = (isset($data['id']) ? (int)$data['id'] : false);
$newsletter = Newsletter::findOne($id); $newsletter = Newsletter::findOne($id);
@ -33,6 +40,7 @@ class Newsletters extends APIEndpoint {
$newsletter = $newsletter $newsletter = $newsletter
->withSegments() ->withSegments()
->withOptions() ->withOptions()
->withSendingQueue()
->asArray(); ->asArray();
$newsletter = Hooks::applyFilters('mailpoet_api_newsletters_get_after', $newsletter); $newsletter = Hooks::applyFilters('mailpoet_api_newsletters_get_after', $newsletter);
return $this->successResponse($newsletter); return $this->successResponse($newsletter);
@ -110,6 +118,13 @@ class Newsletters extends APIEndpoint {
} }
} }
$queue = $newsletter->getQueue();
if($queue) {
$queue->newsletter_rendered_body = null;
$queue->newsletter_rendered_subject = null;
$queue->save();
}
Hooks::doAction('mailpoet_api_newsletters_save_after', $newsletter); Hooks::doAction('mailpoet_api_newsletters_save_after', $newsletter);
return $this->successResponse($newsletter->asArray()); return $this->successResponse($newsletter->asArray());
@ -126,7 +141,7 @@ class Newsletters extends APIEndpoint {
} }
$id = (isset($data['id'])) ? (int)$data['id'] : false; $id = (isset($data['id'])) ? (int)$data['id'] : false;
$newsletter = Newsletter::findOne($id); $newsletter = Newsletter::filter('filterWithOptions')->findOne($id);
if($newsletter === false) { if($newsletter === false) {
return $this->errorResponse(array( return $this->errorResponse(array(
@ -139,12 +154,23 @@ class Newsletters extends APIEndpoint {
if(!empty($errors)) { if(!empty($errors)) {
return $this->errorResponse($errors); return $this->errorResponse($errors);
} else { }
// if there are past due notifications, reschedule them for the next send date
if($newsletter->type === Newsletter::TYPE_NOTIFICATION && $status === Newsletter::STATUS_ACTIVE) {
$next_run_date = Scheduler::getNextRunDate($newsletter->schedule);
$newsletter->queue()
->whereLte('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
->where('status', SendingQueue::STATUS_SCHEDULED)
->findResultSet()
->set('scheduled_at', $next_run_date)
->save();
}
return $this->successResponse( return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray() Newsletter::findOne($newsletter->id)->asArray()
); );
} }
}
function restore($data = array()) { function restore($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false); $id = (isset($data['id']) ? (int)$data['id'] : false);

View File

@ -1,15 +1,21 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\Config\AccessControl;
use MailPoet\Models\Segment;
use MailPoet\Listing; use MailPoet\Listing;
use MailPoet\Models\Segment;
use MailPoet\Segments\WP; use MailPoet\Segments\WP;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class Segments extends APIEndpoint { class Segments extends APIEndpoint {
public $permissions = array(
'global' => AccessControl::PERMISSION_MANAGE_SEGMENTS
);
function get($data = array()) { function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false); $id = (isset($data['id']) ? (int)$data['id'] : false);
$segment = Segment::findOne($id); $segment = Segment::findOne($id);

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