Compare commits

...

363 Commits

Author SHA1 Message Date
a03891895c Bump up release version to 0.0.50 and update changelog 2016-10-25 13:04:55 +03:00
3368e84a99 Merge pull request #668 from mailpoet/export_confirmed_subscribers_option_update
Fixes minor export UI issues
2016-10-25 12:46:13 +03:00
e90df2f08d - Fixes Select2 not dislaying multiple options in the list of export
fields
- Sets default "export confirmed subscriber" option to "no"
2016-10-24 13:09:48 -04:00
2391ae1cad Merge pull request #665 from mailpoet/post_notification_fix
Fixes post notification issues
2016-10-24 16:02:19 +03:00
83114a8be4 - Removes unused class declarations 2016-10-24 08:55:22 -04:00
d08d5a3b6c - Updates unit tests 2016-10-24 08:55:22 -04:00
8330bfc884 - Fixes "completed" status update of notification history
newsletters
- Fixes detection of post notification newsletters that do not contain any posts (i.e., blank ALC blocks)
- Updates unit test
2016-10-24 08:55:22 -04:00
ef21a8cca7 - Enables post notification schedule update upon newsletter saving during
step 3
2016-10-24 08:55:22 -04:00
e32c46a755 - Detaches posts_where action after posts are pulled from the database 2016-10-24 08:55:22 -04:00
092f69538a Merge pull request #667 from mailpoet/sending_to_trashed_subscribers_fix
Prevents newsletters from being sent to trashed subscribers
2016-10-24 15:26:55 +03:00
7a75367d75 Merge pull request #666 from mailpoet/export_filename_update
Increases export filename length and randomness
2016-10-24 13:36:36 +03:00
0b2701ade2 Merge pull request #656 from mailpoet/security_issue_636
API Token
2016-10-24 13:26:44 +03:00
1ac288d286 - Prevents newsletters from being sent to trashed subscribers
- Updates unit tests
- Addresses #629
2016-10-21 14:36:44 -04:00
516bc73092 - Increases export filename length and randomness 2016-10-21 11:42:13 -04:00
4088abef68 removed useless 'use' in unit test 2016-10-21 13:42:19 +02:00
f6cefc3f5c wrong email address in unit test 2016-10-21 13:38:23 +02:00
202e4b90e1 added unit test for API::checkPermissions 2016-10-21 13:36:41 +02:00
ee89bf0722 refactored API class 2016-10-21 13:36:41 +02:00
876d21300a fixed duplicated lines due to faulty rebase 2016-10-21 13:36:41 +02:00
0ca5b7a79f API Security
- added APIAccess class to define access levels of API Endpoints (permissions)
- use "mailpoet_token" for all nonce (just as before)
- merged setupPublic/setupAdmin methods in API in order to avoid duplication
- check permission if access level is not all
- fixed ABSPATH check in some classes
2016-10-21 13:36:41 +02:00
5d0ee43921 removed checkToken for admin ajax 2016-10-21 13:36:41 +02:00
cc523a3c0b ability to specify action for generateToken() method 2016-10-21 13:36:41 +02:00
2787998d32 Merge pull request #664 from mailpoet/editor_fixes
Editor fixes
2016-10-20 17:29:55 +02:00
38f6c95059 Update newsletter saving to reflect code review comments
- Switch to using full segment objects when saving newsletters
- Fix stale comment in newsletter editor's Newsletter model
- Fix typo in newsletter editor tests
2016-10-20 17:52:05 +03:00
cc03b631ff Allow newsletters.save endpoint to accept segments as list of objects 2016-10-20 16:08:41 +03:00
a3c77fb685 Fix PHP to JS date format converter to handle escaped symbols 2016-10-20 15:19:04 +03:00
3817e28960 Change newsletter not found error to a static one in editor 2016-10-20 13:38:07 +03:00
c3a78b1ea3 Fix newsletter editor to only save properties it changes 2016-10-20 13:37:32 +03:00
42877236c8 Merge pull request #663 from mailpoet/wp_repo_files
Preparation for plugin repo
2016-10-19 09:08:54 -04:00
6e87f3539c Update license.txt, readme.txt and link to plugin's repo page 2016-10-19 13:46:14 +03:00
7704ea4b68 Bump up release version to 0.0.49 2016-10-19 13:23:00 +03:00
12a3931b7b Merge pull request #662 from mailpoet/security_issue_634
PHP Object injection in front Router
2016-10-18 16:46:14 +03:00
25a55dbb67 Merge pull request #661 from mailpoet/security_issue_633
Import SQL injection
2016-10-18 14:50:08 +02:00
6758f60a81 Merge pull request #659 from mailpoet/import_data_sanitization
Sanitize import data
2016-10-18 12:35:52 +02:00
5e9e53ec41 - Updates router to use json_encode() instead of serialize() for publicly modified data payload
- Updates unit tests
- Fixes #634
2016-10-17 22:39:36 -04:00
1285252a8c - Adds unit tests 2016-10-17 20:27:58 -04:00
98f95f72ad - Adds validation for import data, including column names (fixes #633)
- Prevents nonexistent custom fields from being associated with subscribers
2016-10-17 20:22:25 -04:00
09ca788371 - Fixes subscriber count not being shown when new segment is created 2016-10-17 20:12:57 -04:00
b48cc5a959 - Updates import UI to escape HTML text
- Allows mixing of escaped and unescaped HTML text
- Removes server-side text escaping
2016-10-17 11:01:54 -04:00
812d138c4e Merge pull request #658 from mailpoet/import_and_mailer_host_restriction
Import and mailer host restriction
2016-10-17 16:19:42 +02:00
07bc35d4cd Merge pull request #625 from mailpoet/unit_tests
Adds unit test for newsletter scheduler
2016-10-17 11:37:17 +02:00
90b95a2c25 fixed 'newletter' typo and replaced integer weekdays by their carbon constant equivalent 2016-10-17 11:35:57 +02:00
78c50c41e3 - Fixes unit test
- Updates code as per code review comments
2016-10-18 14:29:53 -04:00
7eee7def63 Merge pull request #657 from mailpoet/security_issue_635
Security issue #635
2016-10-16 16:42:11 -04:00
9ba6e9806f - Adds data sanitization on the client and server side
- Closes #641
2016-10-16 13:02:49 -04:00
8c28dc3d8a - Restricts Amazon SES region to a specific list of hosts
- Updates unit tests
- Closes #647
2016-10-16 12:19:47 -04:00
9197e39fb4 - Restricts MailChimp API key to specific format
- Updates unit test
2016-10-16 11:57:56 -04:00
37f59814e5 removed unused methods in Util/CSS -> fixes security issue #635 2016-10-13 10:34:36 +02:00
bf894fc26f Bump up release version to 0.0.48, update changelog 2016-10-11 13:02:08 +03:00
0b2b42cf4d Merge pull request #654 from mailpoet/security_issue_1
Security issues round 1
2016-10-11 12:51:11 +03:00
542015a4f6 Improved removal of useless files in vendor folder during build process
- moved sort_order constraining logic to Listing handler's construct
2016-10-10 14:52:09 +02:00
f5a8323f5d removed 'test*' from removed folders in vendor as it was creating issues with Twig 2016-10-07 15:12:58 +02:00
55942cd88b prevent odd values for sort_order in listing.jsx 2016-10-07 14:38:25 +02:00
f26a2cbd26 fixes issue #651 2016-10-06 13:18:46 +02:00
4402f826c3 fixed issue with namespace AND fixed issue #649 2016-10-06 12:54:04 +02:00
b9745b555a make sure ABSPATH is defined before using it - fixes issue #648 2016-10-06 12:52:53 +02:00
f923a8063b cleanup useless files in vendor folder when building release (fixes issue #637) 2016-10-06 11:24:18 +02:00
f4367b9146 optimized the composer install a bit 2016-10-06 09:52:42 +02:00
a3395e41c9 fixes issue #632 2016-10-06 09:25:09 +02:00
be61135daf Merge pull request #627 from mailpoet/translations
Translations
2016-10-05 12:26:03 +03:00
21b4187a11 added missing text domains in _e functions 2016-10-05 10:26:59 +02:00
1c3c1e35e7 added 'lang' to gitignore 2016-10-05 10:08:24 +02:00
ded373557e Bump up release version to 0.0.47 and update changelog 2016-10-04 12:05:34 +03:00
280c4762bb Merge pull request #630 from mailpoet/subscribers_count_in_segments
Subscribers count in segments
2016-10-04 11:58:44 +03:00
bbd02260be Fix showing segment subscriber counts on newsletter creation pages 2016-10-04 11:54:07 +03:00
1b1e9abd68 Merge pull request #631 from mailpoet/issue_629
Bugs in latest release (0.0.46) - issue 629
2016-10-03 15:42:57 +03:00
b0ab9e0408 fixed import/export unit tests + added specific method for getting segments for import 2016-09-30 15:52:17 +02:00
d32abff78d display subscribers count in segments selection 2016-09-30 15:23:18 +02:00
7fbf84db1f converted text domain to string instead of constant 2016-09-30 09:58:26 +02:00
8c5aebc7d6 Don't send signup confirmation when signup confirmation is disabled
Fixed issue with select2 not selecting values by default on newsletter send step
2016-09-29 15:42:44 +02:00
42202f676a updated Env::plugin_name to constant for text domain 2016-09-27 14:54:23 +02:00
ba6198f956 added textdomain to __() calls 2016-09-27 14:53:44 +02:00
120af4170b fixed do makepot + removed mailpoet.pot from repo 2016-09-27 14:53:44 +02:00
1faa53b978 Bump up release version to 0.0.46 2016-09-27 14:10:38 +02:00
e565a7a234 - Uses Codeception's native methods to verify expectations
- Updates next run date test conditions to use account for possible time
  difference
2016-09-26 12:35:00 -04:00
90b6b57a8d Merge branch 'copy-edit' 2016-09-26 13:17:08 +01:00
548253d68e Merge branch 'master' into copy-edit 2016-09-26 11:14:21 +01:00
e1c5f609ff - Adds unit test 2016-09-23 20:16:53 -04:00
226befdef6 Merge pull request #624 from mailpoet/unit_tests
Unit tests
2016-09-23 20:15:45 +03:00
a9d57654b4 - Rebases master
- Fixes newsletter schedule options not being saved
2016-09-23 12:54:18 -04:00
ed00ae0516 - Adds unit test 2016-09-23 12:30:29 -04:00
48d738e8c4 - Updates scheduler 2016-09-23 12:30:29 -04:00
132b4ed2e8 - Passes full model object to class method 2016-09-23 12:30:29 -04:00
9a513cb27b Merge branch 'master' into copy-edit 2016-09-23 16:39:56 +01:00
5d692c0395 Merge pull request #623 from mailpoet/drag_drop
Enable dragging text blocks
2016-09-23 15:13:09 +02:00
991ab67fff Allow dragging from the first time 2016-09-23 15:38:23 +03:00
dd00640119 Merge pull request #620 from mailpoet/subscription_forms
Subscription Forms
2016-09-23 15:20:58 +03:00
fa04173cfb Activate TinyMCE on click, to fix Interact blocking 2nd and further
focus events
2016-09-23 15:07:04 +03:00
a328d3b48a avoid duplicating code 2016-09-23 12:56:27 +02:00
d5cff4f0d3 fixed indentation 2016-09-23 12:14:54 +02:00
52bf24b6db Revert back to auto preventDefault for drag&drop 2016-09-22 18:39:07 +03:00
50e134d696 Allow dragging text blocks before activating TinyMCE 2016-09-22 17:44:43 +03:00
ea5c73721b remove doing_ajax logic from API and created dedicated class for subscription form non ajax submission 2016-09-22 16:24:13 +02:00
4799882b80 Merge pull request #621 from mailpoet/unit_tests
Unit tests
2016-09-22 13:04:05 +03:00
2e4c5ca39a - Updates Mailer Log class and adds unit tests 2016-09-21 19:53:26 -04:00
13ed3aa3b9 - Adds unit test 2016-09-21 14:09:24 -04:00
6091751a4b Closes issue 480 2016-09-21 11:54:16 +02:00
c4d9e85dff - Adds unit test 2016-09-20 20:43:49 -04:00
1a85914c1b - Adds unit test 2016-09-20 20:08:44 -04:00
0ba48234de Merge pull request #616 from mailpoet/unit_tests
Final set of cron unit tests
2016-09-20 19:38:46 +03:00
1c2a532949 - Adds test to detect empty newsletter body when sending 2016-09-20 12:03:57 -04:00
9087be6ee8 - Fixes condition that checks for existance of rendered newsletter body 2016-09-20 10:33:48 -04:00
5b2ede8b83 Bump up release version to 0.0.45 2016-09-20 12:53:33 +03:00
2fa5e5ead2 - Moves logic of the Subscribers task to the Sending Queue model 2016-09-19 21:53:13 -04:00
d5107be65e - Updates Sending Queue Worker and Mailer task to allow dependency
injection via constructor
- Updates unit tests to use dependency injection instead of modifying
  object's internals
2016-09-19 21:00:47 -04:00
379dfb5f6e - Removes leftover private variable 2016-09-19 20:51:08 -04:00
8360377992 - Replaces custom method to get newsletter with ORM's native one-to-one model
relationship
2016-09-19 20:47:49 -04:00
4538cab6c8 - Adds newsletter body/subject as a reusable template through
Codeception's Fixture utility class
2016-09-19 20:40:17 -04:00
1bf0988297 - Updates Sending Queue worker/tasks/unit tests use model's method to get/save rendered newsletter body 2016-09-19 20:11:58 -04:00
e1caf49ea5 - Updates depreciated method name 2016-09-19 20:10:47 -04:00
0dfae97b32 - Updates model to serialize rendered newsletter body on save 2016-09-19 20:09:44 -04:00
ef2187c175 - Updates code formatting 2016-09-19 11:10:03 -04:00
6157d17c5b - Removes transient object from the model 2016-09-19 10:55:58 -04:00
8e879047c2 - Adds additional DB tables to be cleaned during unit testing 2016-09-19 10:51:10 -04:00
bff6aecd0d Merge pull request #617 from mailpoet/copy-edit
Updated text
2016-09-19 17:08:19 +03:00
a121583c2d Updated text 2016-09-19 10:13:34 +01:00
e11fd66fec - Adds unit tests for cron's sending queue worker and associated tasks 2016-09-18 23:16:19 -04:00
b37e85eeb5 - Removes unused method 2016-09-18 23:15:41 -04:00
f88dabffe8 - Updates cron's sending queue worker to use model objects
- Adds new method to render newsletter to the newsletter model
- Adds new transient object to newsletter model that will hold temporary
  values (i.e., rendered body) when working with the model
2016-09-18 23:14:17 -04:00
8c436180d9 Merge pull request #615 from mailpoet/unit_tests
Adds unit tests for cron scheduler worker
2016-09-15 13:21:34 +03:00
b834a6af4d - Updates cron scheduler worker
- Adds unit tests
2016-09-14 19:00:08 -04:00
1bd8aed192 Bump up release version to 0.0.44, add changelog 2016-09-13 15:59:18 +03:00
cfdf72867e Merge pull request #612 from mailpoet/subscribers_limit
Subscribers limit
2016-09-13 08:49:06 -04:00
5888620fc1 - Updates link to support area 2016-09-13 08:41:37 -04:00
55ba605eb0 fixed typo in test function name 2016-09-13 11:45:33 +02:00
7a73ca7d1a Merge pull request #608 from mailpoet/api_uniform_h
Listing method update for Newsletters/Forms/Segments/Subscribers
2016-09-12 10:12:18 -04:00
1918894c5c fix status code in API + PHP 5.3 errors on object instantiation 2016-09-12 15:59:30 +02:00
0c5589a3e3 Listing method update for Newsletters/Forms/Segments/Subscribers
- updated unit tests
2016-09-12 15:57:16 +02:00
d6eaa4ac8a Merge pull request #614 from mailpoet/links_to_support_articles
Updates links to KB articles
2016-09-12 14:37:32 +02:00
b0571b97f5 added missing KB link in Send with 3rd party 2016-09-12 14:32:59 +02:00
6d51ca8011 Merge pull request #613 from mailpoet/class_instance_creation_update
Class instance creation fix for PHP 5.3
2016-09-12 14:07:38 +02:00
d3289dfb84 Merge pull request #609 from mailpoet/unit_tests
Cron unit tests (batch 1 of 2)
2016-09-12 14:30:29 +03:00
bfffdd7274 - Updates links to KB articles
- Closes #571
2016-09-10 21:12:43 -04:00
c5b8b2aef0 - Fixes "class not found" error in Daemon
- Moves ignore_user_abort() to the run() method
- Updates unit tests
2016-09-10 18:06:48 -04:00
d7bcf1b817 - Updates the way errorResponse class is instantiated 2016-09-10 10:49:20 -04:00
f30ed153ce - Updates the way template classes are instantiated 2016-09-10 10:44:24 -04:00
f436088a16 Subscribers limit
- added "limit.html" template
- subscribers_limit set in Env class
2016-09-09 16:12:59 +02:00
db8cb7499d Merge pull request #611 from mailpoet/copy-editing
Update September 9 2016
2016-09-09 16:49:42 +03:00
49c4adc754 Increase the width of subject and preheader inputs 2016-09-09 16:45:19 +03:00
405e743171 update September 9 2016 2016-09-09 15:04:00 +02:00
3508ac36b4 - Removes daemon status logic and updates tests
- Refactors daemon
- Adds daemon unit tests
2016-09-08 19:22:42 -04:00
f17c8228cd - Adds units tests for cron triggers 2016-09-07 18:21:31 -04:00
3dd5ac0536 Merge pull request #607 from mailpoet/api_uniform_g
Forms / Newsletters / Segments / Subscribers
2016-09-07 14:52:21 -04:00
4ebdff49e0 make Model::setTimestamp() public 2016-09-07 10:26:08 +02:00
4a72995bf4 fix bulk actions and messages 2016-09-06 17:21:15 +02:00
ef27ac0b84 Update changelog for 0.0.43 2016-09-06 12:27:58 +03:00
2b4adef6c2 Bump up release version to 0.0.43 2016-09-06 12:13:21 +03:00
f650455a90 forms & newsletters endpoints 2016-09-05 11:55:01 +02:00
afbe25e215 Segments & Subscribers endpoints
- unit tests
2016-09-05 11:51:58 +02:00
d93249f077 form & listing jsx update + Segment endpoint conversion 2016-09-05 11:51:58 +02:00
6223ef77d9 Merge pull request #605 from mailpoet/editor_fixes
Editor fixes
2016-09-02 08:30:59 -04:00
a423123b66 Add 3 new sample templates Becs prepared 2016-09-02 14:12:19 +03:00
1b3d3082b0 Fix text in template selection boxes to not overflow 2016-09-02 12:48:44 +03:00
fa117cc7dd Add an animation to display tools 2016-09-02 12:48:44 +03:00
acd407c1f1 Clarify label of preheader field 2016-09-02 12:48:44 +03:00
9baf4b068f Swapped block tool default and hover colors. Dark normally, light on
hover
2016-09-02 12:48:44 +03:00
18d852e147 Changed Trash and Move SVG icons to new ones for newsletter editor 2016-09-02 12:48:44 +03:00
b8dc306741 Merge pull request #604 from mailpoet/unit_tests
Unit tests (Cron Supervisor and Trigger)
2016-09-02 12:46:39 +03:00
6ea056c042 - Removes references to cron from webpack's configuration 2016-09-01 19:19:47 -04:00
bcf1b37c6a - Adds unit tests for Cron Trigger class 2016-09-01 19:19:47 -04:00
2986cdba85 - Removes Cron status from MailPoet's WP admin panel 2016-09-01 19:19:47 -04:00
53a8ae74e2 - Adds unit tests for Supervisor class
- Updates execution limit condition check in Supervisor
2016-09-01 19:19:47 -04:00
8bab01506c - Updates CircleCI configuration to run Apache 2016-09-01 19:18:47 -04:00
c664045444 Merge pull request #603 from mailpoet/welcome_page
Welcome and Update pages
2016-09-01 14:02:20 +03:00
6b8149210d Remove installed_at default value from default settings 2016-08-31 16:59:50 +03:00
f31d30b318 Merge pull request #602 from mailpoet/cron_update
Cron update
2016-08-31 16:48:05 +03:00
d9fbbdc02d - Updates code comments 2016-08-31 09:23:12 -04:00
8136ee2d9b Add a timestamp to log when the plugin was installed 2016-08-31 14:42:43 +03:00
f7cf6e2131 Welcome and Update pages 2016-08-31 13:51:33 +03:00
f2d1787bd5 - Updates site URL detection logic
- Adds unit test for Cron Helper class
2016-08-30 12:37:30 -04:00
fb51765d3f Bump up release version to 0.0.42 2016-08-30 13:04:08 +03:00
088ad5fb42 Merge pull request #597 from mailpoet/editor_fixes
Editor fixes
2016-08-29 15:43:47 -04:00
2f5b3c0c0a Merge pull request #600 from mailpoet/circle_ci
Adds CircleCI support
2016-08-29 15:15:39 -04:00
04ac4d896c Remove the build testing error 2016-08-29 21:38:26 +03:00
f3b96af863 Attempt to fix command status codes for Robo commands 2016-08-29 21:32:57 +03:00
eb42b0b98d Merge branch 'circle_ci' of github.com:mailpoet/mailpoet into circle_ci 2016-08-29 21:32:14 +03:00
304667eb49 - Testing commit e-mail 2016-08-29 14:27:40 -04:00
dad1082cd7 - Fixes JS unit test 2016-08-29 14:26:44 -04:00
37cf0f3d29 - Fixes JS unit test
:
2016-08-29 13:58:20 -04:00
d61c6dff58 - Fixes PHP unit test
- Fails JS unit test to check if CircleCI will detect it
2016-08-29 13:52:17 -04:00
3734ac578d - Fails test to check if CircleCI will detect it 2016-08-29 13:48:33 -04:00
b3f56c9d8e Merge pull request #599 from mailpoet/router_unit_tests
Router refactoring and unit tests
2016-08-25 17:33:44 +03:00
3603eeee77 - Updates remaining router endpoints to use constructor and new constants 2016-08-25 10:03:52 -04:00
59d30cc139 - Renames router URL query parameter and router class
- Updates other classes to use the new name
- Updates unit tests
2016-08-25 09:57:14 -04:00
6ff3bbbb72 - Fixes type in method name 2016-08-24 23:35:45 -04:00
a561e10156 - Updates tests for view in browser and statistics tracking 2016-08-24 23:35:34 -04:00
99f2cf6702 - Adds unit tests for front router 2016-08-24 23:27:12 -04:00
c6b72e729b - Refactors front router and endpoints to use dynamic methods 2016-08-24 23:26:13 -04:00
c5bc0f36a4 Disable running PHP coverage reports 2016-08-25 00:46:29 +03:00
efc5c34bf9 Add running PHP unit test coverage reports in CircleCI 2016-08-25 00:34:58 +03:00
3929efbdd9 Enable running JS tests 2016-08-25 00:09:34 +03:00
0e0c41882e Generate XML report for unit tests and add it to CircleCI tracking 2016-08-25 00:05:41 +03:00
79cc708fc6 Set UTC timezone for CircleCI PHP version 2016-08-24 23:50:59 +03:00
8fa98879b8 Enable debugging when running tests 2016-08-24 23:46:22 +03:00
331ba385e9 Switch MySQL host to 127.0.0.1 instead of localhost 2016-08-24 23:30:19 +03:00
71ce46d78d Add running PHP tests 2016-08-24 23:13:06 +03:00
c493de6569 Try to output JS test results in jUnit format for CircleCI 2016-08-24 21:44:22 +03:00
ff2c2ace86 Add running JS tests in CircleCI 2016-08-24 21:29:58 +03:00
7fa789cfd1 Merge pull request #598 from mailpoet/view_in_browser_update
View in browser update
2016-08-24 19:02:15 +03:00
ae6269eb63 - Restricts router access to explicitly defined endpoint actions 2016-08-24 11:23:12 -04:00
a8f4779bfe - Updates code formatting 2016-08-24 10:22:10 -04:00
6868142e35 - Extracts view in browser response to the endpoint
- Updates unit tests
2016-08-24 10:20:35 -04:00
133d123919 - Updates front router and endpoints to use dynamic methods 2016-08-24 10:20:10 -04:00
05c128d12d - Fixes errors thrown when there are no shortcodes in the newsletter body 2016-08-24 09:29:17 -04:00
bdab0c12fa Fix debouncing for ALC refresh to not update multiple times immediately 2016-08-24 16:15:53 +03:00
75b94690e2 - Adds unit tests 2016-08-23 23:42:56 -04:00
80fddd6c58 - Refactors view in browser 2016-08-23 23:42:26 -04:00
c807ead5fd - Prepares newsletter renderer for conversion to using modal objects
instead of arrays
2016-08-23 12:48:38 -04:00
f004bb5368 - Set default preview email to be current user's email;
- Change "Preview in browser" form to autocomplete used emails.
2016-08-23 19:32:10 +03:00
1d756e95a7 Bump up release version to 0.0.41 2016-08-23 12:27:14 +03:00
1fb0da9fda Merge pull request #587 from mailpoet/open_stats_fix
Prevents tracking opens/clicks from subscribers who the newsletter was not sent to
2016-08-23 12:17:51 +03:00
a0017b91ee Merge pull request #592 from mailpoet/editor_fixes
Editor fixes
2016-08-22 20:43:24 -04:00
444ab17342 - Updates statistics tracking unit tests 2016-08-22 16:24:33 -04:00
44f3058326 - Adds unit test for tracker router endpoint 2016-08-22 16:24:13 -04:00
ec09fbcb78 - Converts static classes to dynamic 2016-08-22 16:22:33 -04:00
ed352bb1d3 - Passes wp_user_preview parameter to custom link shortcode filter 2016-08-22 09:26:25 -04:00
375bbd2759 - Calls an open tracking class when tracking clicks 2016-08-22 09:26:25 -04:00
9fb9d25132 - Uses model method to get queue 2016-08-22 09:26:25 -04:00
30f79aa589 - Updates unsubscribe tracking logic 2016-08-22 09:26:25 -04:00
69f8daac95 - Updates wp user & preview check condition 2016-08-22 09:26:25 -04:00
03f3a6080c - Returns empty response or an image in all cases 2016-08-22 09:26:25 -04:00
44f84c6cdb - Updates method names 2016-08-22 09:26:25 -04:00
31008a6895 - Updates queue and subscriber check condition 2016-08-22 09:26:25 -04:00
2490d8c919 - Refactors browser preview 2016-08-22 09:26:25 -04:00
5886dbfd25 - Refactors statistics tracking 2016-08-22 09:26:25 -04:00
e48d55f0b1 - Adds new model methods 2016-08-22 09:26:25 -04:00
42339927cf - Extends ORM's isNew() method to work on saved models 2016-08-22 09:26:25 -04:00
b492bcecc0 - Removes requirement of passing newsletter id when tracking clicks
- Extracts common tracking data processing/validation code into the Track
  class
- Refactors Clicks, Opens and View in Browser classes to enforce
  subscriber id and token check
- Allows admin users to preview newsletters without tracking statistics
2016-08-22 09:26:25 -04:00
6ab7debb7b - Fixes code formatting 2016-08-22 09:26:25 -04:00
b76ce6c26f - Adds verification of newsletter-to-queue and subscriber-to-queue
- Prevents tracking open/click rates for subscribers who the newsletter
  was not sent to
2016-08-22 09:26:25 -04:00
6fbc7b1593 Add "View in browser" to happen on the same page, instead of opening new
window
2016-08-19 18:48:29 +03:00
69c8670b01 Add an option to open settings by clicking on the block for image,
button, social, divider and spacer blocks
2016-08-19 14:57:14 +03:00
da44a87415 Change onkeyup to oninput events to correctly detect pasting into
inputs
2016-08-18 16:55:53 +03:00
9fb17d4a6b Fix "Preview in browser" notice to display a proper success message 2016-08-18 15:07:20 +03:00
16dd286f9d Merge pull request #591 from mailpoet/missing_response
missing response in fail and prevent next on MC import
2016-08-18 12:07:05 +03:00
5025f10f9f missing response in fail and prevent next on MC import 2016-08-17 16:15:54 +02:00
1278d9648c Merge pull request #590 from mailpoet/api_uniform_c
Custom fields & Import & Export
2016-08-17 16:18:53 +03:00
289811a595 Updated Import & MailChimp tests 2016-08-17 13:32:29 +02:00
916ae97f73 Updated export unit test 2016-08-17 12:51:50 +02:00
876e386966 converted export 2016-08-17 12:23:15 +02:00
9582e58dda converted import 2016-08-17 12:16:58 +02:00
213bca8050 fixed rendering of date block + fixed validation for dates 2016-08-16 14:41:53 +02:00
dc97d3115e updated Custom Field endpoint + Unit tests + form editor update 2016-08-16 12:40:10 +02:00
90eb443965 Merge pull request #582 from mailpoet/custom_field_fix
Custom field fix
2016-08-16 12:00:28 +02:00
1b40f02715 Bump up release version to 0.0.40 2016-08-16 12:30:53 +03:00
c5a02c6136 - Allows setting empty value for date custom fields 2016-08-14 13:00:28 -04:00
492cd8c96b Merge pull request #583 from mailpoet/editor_fixes
Editor fixes
2016-08-12 16:40:08 +02:00
7f091d7188 - Fixes rebase screwup 2016-08-12 10:38:15 -04:00
1c081623b9 When there's no social icon image URL, revert to "Image not found" image 2016-08-12 17:30:11 +03:00
87332037c2 Do not render images or social icons if image src is not defined 2016-08-12 16:18:44 +03:00
62023397f4 Remove example URLs from social icons, leave placeholders 2016-08-12 15:47:53 +03:00
37ec6dc1a6 Fix handling of images with empty src in newsletter editor 2016-08-12 14:40:21 +03:00
81c277ca93 - Update import to autodetect dates (UI) and convert them to datetime
format (backend)
- Fixes unit test
- Fixes code formatting in Date class
2016-08-12 00:29:57 -04:00
f8fea75130 - Updates date conversion method
- Uses Moment to parse dates in UI
- Updates Custom Field model to utilize date conversion method
- Adds unit test
2016-08-11 21:11:57 -04:00
a4457649f7 Fix saving on last newsletter step to JSON encode newsletter body 2016-08-11 18:58:55 +03:00
1d6a09f010 Modify ALC to ignore posts published before notification newsletter is
created
2016-08-11 16:46:47 +03:00
faec553521 Enable closing of a sidebar section in newsletter editor 2016-08-11 16:46:47 +03:00
37fcf3a234 Fix newsletter template titles to not overlap Delete controls 2016-08-11 16:46:47 +03:00
68a56aada8 Fix default footer to allow toggling bold and italic on sentences 2016-08-11 16:46:47 +03:00
f744305834 - Change default URLs to blank;
- Fix image, button, social icon URL placeholders;
- Remove links to example.org.
2016-08-11 16:46:47 +03:00
7a9402f5b5 Merge pull request #586 from mailpoet/api_uniform_f
updated cron endpoint + cron.jsx
2016-08-11 16:42:31 +03:00
de6d7e0cae updated cron endpoint + cron.jsx 2016-08-11 12:36:17 +02:00
a3c56b84ce Merge pull request #585 from mailpoet/api_uniform_e
Api uniform (NewsletterTemplates)
2016-08-11 12:34:16 +03:00
3d4defd563 Fixed unit tests for newletter templates
- changed null to false for default value of id in nltemplates endpoint
2016-08-10 16:51:04 +02:00
52da08abb2 converted newsletterTemplates endpoint + react 2016-08-10 15:50:07 +02:00
b9637b52e9 Merge pull request #584 from mailpoet/api_uniform_d
Api uniform (Mailer & SendingQueue)
2016-08-10 15:04:17 +03:00
0369a23fe8 Call different actions for standard and automated newsletters on Send step
- converted save and setStatus method of Newsletters endpoint
- updated pause/resume mixin for notification & welcome listings
- use 'newsletter_id' instead of 'id' in SendingQueue endpoint (less confusing)
- added NOT_FOUND constant to APIError
- fixed unit test for Newsletters endpoint save and added test for setStatus
2016-08-10 13:09:35 +02:00
f690e1a095 return sending queue object for standard / newsletter for automated\n- bugfix loading screen not going away\n- fixed not being used in sending queue endpoint 2016-08-10 13:09:35 +02:00
22e8e34213 unify getData() response 2016-08-10 13:09:35 +02:00
12b46736c5 updated sending queue endpoint + react (pause/resume/send) 2016-08-10 13:09:35 +02:00
4950e47297 updated mailer endpoint 2016-08-10 13:09:35 +02:00
d7c5c8c3e7 Bump up release version to 0.0.39 2016-08-09 12:09:38 +03:00
46b0fcf37b - Adds subscriber data validation; specifically for custom fields with
date type
2016-08-08 18:23:11 -04:00
b07c4d0e6e - Adds date validation based on date format 2016-08-08 18:23:11 -04:00
eb107799a7 - Fixes varable name typo
- Declares a new variable during date validate
2016-08-08 18:23:11 -04:00
4eec0a42f9 - Forces date validation to use custom custom field parameter 2016-08-08 18:23:11 -04:00
9a5a3a08c6 - Fixes default date format not being set 2016-08-08 18:23:11 -04:00
151683c632 - Updates Import to use the existing custom field creation code
- Closes #499
2016-08-08 18:23:11 -04:00
fd2103d1aa - Extracts custom field specific templates/code into a separate template
file
2016-08-08 18:23:11 -04:00
7696b6ec5d - Replaces depreciated Notice .error() method with .fail() 2016-08-08 18:23:11 -04:00
d972b96255 - Updates custom field editor to display errors inside the form 2016-08-08 18:23:11 -04:00
35ccfb8bcf Merge pull request #564 from mailpoet/cron_update
Cron update
2016-08-08 16:59:27 +03:00
7ff036b1e9 - Removes depreciated variables
- Updates method names
2016-08-08 09:45:16 -04:00
983d56c29b - Updates default cron trigger method in Populator and Settings 2016-08-08 09:07:01 -04:00
a2528939ba Merge pull request #581 from mailpoet/api_uniform_b
updated ALC endpoint + nl editor + js tests
2016-08-08 15:00:26 +03:00
c136d91dd2 encapsulating in communication component + update js tests 2016-08-08 11:36:29 +02:00
bf00e82596 - Fixes sending limits not being enforced 2016-08-07 11:39:05 -04:00
0e10f6c820 - Fixes merge conflict 2016-08-05 13:03:31 -04:00
c056e95249 - Rebases master
- Updates sending limit logic
2016-08-05 13:03:31 -04:00
1be7fda1cf - Updates daemon request timeouts 2016-08-05 13:03:31 -04:00
0b0c0f5759 - Fixes conditional statement 2016-08-05 13:03:31 -04:00
59a4428965 - Fixes class naming conflict 2016-08-05 13:03:31 -04:00
3f5c36d2d4 - Fixes blocking HTTP request issue
- Simplifies cron supervisor
2016-08-05 13:03:31 -04:00
3cc5812c1d - Removes exception throwing that can disable plugin 2016-08-05 13:03:31 -04:00
3e616201ad - Encasupsulates trigger methods logic into separate classes
- Updates cron router
2016-08-05 13:03:31 -04:00
5558ebad45 - Updates the name of the setting const 2016-08-05 13:03:31 -04:00
63bd093f35 - Renames TaskScheduler to CronTrigger and updates relevant code
- Standardizes setting value const naming convention
2016-08-05 13:03:31 -04:00
ec6559b8be - Removes unused method from Settings model
- Renames method to delete value
2016-08-05 13:03:31 -04:00
3421406dc7 - Removes unused const 2016-08-05 13:03:31 -04:00
a2917c08f6 - Switches methods used to get cron settings 2016-08-05 13:03:31 -04:00
5fa9b5a8dd - Updates method name that returns mailer configuration 2016-08-05 13:03:31 -04:00
41ad86ba1f - Fixes code style 2016-08-05 13:03:31 -04:00
067b3ff3e6 - Updates Mailer class to use default values from Settings 2016-08-05 13:03:31 -04:00
9b9cb1455a - Updates cron/mailer/scheduler code to work with the new sending queue
task scheduler and mailer log
2016-08-05 13:03:31 -04:00
a5569a6a55 - Adds new sendiing queue task responsible for managing task scheduler 2016-08-05 13:03:31 -04:00
71c1026729 - Adds new class responsible for managing mailer log 2016-08-05 13:03:31 -04:00
f102e847bf - Stops cron daemon when settings are changed from MailPoet to WordPress
task scheduler
2016-08-05 13:03:31 -04:00
3158e2c460 - Updates cron router to properly return the daemon status 2016-08-05 13:03:31 -04:00
a438f13bb0 - Modifies cron router/UI to display proper status message when WP task
scheduler is configured and cron is not running
- Updates sending queue worker and related components to stop (delete)
  cron when all processing is done
2016-08-05 13:03:31 -04:00
5ed0a5819c - Updates settings to use task scheduler method names from the newly
introduced config class
2016-08-05 13:03:31 -04:00
6dd3c6acda - Adds new task scheduler configuration class
- Introduces method to start cron on demand when there are
  scheduled newsletters or queues in progress
2016-08-05 13:03:31 -04:00
ca2c1c2e6f Merge pull request #580 from mailpoet/alc_posts
ALC Post filtering
2016-08-05 11:53:55 -04:00
1305a10ee0 updated ALC endpoint + nl editor + js tests 2016-08-05 15:25:54 +02:00
5e36eb818b Fix sending first notification newsletter with ALC posts 2016-08-05 13:40:54 +03:00
cfde82ff5f Declaring class properties of AutomatedLatestContent 2016-08-04 18:32:30 +03:00
af98ade650 Add ALC filter to use posts created after last newsletter was sent 2016-08-04 18:17:49 +03:00
598432466e - Rename wysija-newsetters.pot to mailpoet.pot
- Add pot file regeneration on plugin build
2016-08-04 18:16:43 +03:00
9469ce83f1 Fix creation and update timestamps for notification history newsletters 2016-08-04 18:16:43 +03:00
5624f4c7a0 Add new Robo task to run all QA tasks in one go 2016-08-04 18:16:43 +03:00
82a001dc05 Add timestamp based ALC filter to ignore older posts 2016-08-04 18:16:43 +03:00
a9b424fb79 Merge pull request #579 from mailpoet/notification_history_preview
Enables preview of notification history newsletters
2016-08-04 18:12:50 +03:00
d31af9d71c - Adds additional logic to not exclude sent posts when previewing from
within the newsletter editor
2016-08-04 10:30:53 -04:00
ff7a24590f - Removes unnecessary condition 2016-08-04 09:46:05 -04:00
ea87a7acf8 - Fixes code style
- Removes unnecessary condition
- Closes #576
2016-08-04 09:36:15 -04:00
9d36a17261 - Fixes preview of newsletters with ALC 2016-08-03 21:36:03 -04:00
9c3cb5a509 - Enables preview of notification history newsletters 2016-08-03 20:42:35 -04:00
4dd7f32f3a Merge pull request #578 from mailpoet/api_uniform
Api unification - Step 1
2016-08-03 17:27:09 +03:00
1c6fca7f83 fixed ErrorResponse call in API::setupPublic()
- removed empty constructors in updated endpoints
- added missing keys to Error class (unauthorized, forbidden)
2016-08-03 16:04:45 +02:00
c5b376bd21 satisfy code sniffer rule 2016-08-03 15:08:27 +02:00
5d2800bc25 added API/Error class to hold error keys as constants
- re-added Setting::getAll() to API/Setting::set() in response
- updated settings/setup tests
2016-08-03 15:04:25 +02:00
6675d5a20d added default error messages to errorResponse and badRequest 2016-08-03 14:08:22 +02:00
28c39d301c Added default error response in case no errors were specified
- converted Setup endpoint
- unit tests for Setup endpoint
2016-08-03 12:41:21 +02:00
afa0d3af63 Updated Ajax.js to avoid promise workaround
- Removed get method in ajax.js as it's useless
2016-08-02 18:08:12 +02:00
b05344b1d3 added missing data in deferred.resolve() 2016-08-02 17:18:18 +02:00
2e88d7cce0 Added API/Endpoint abstract class
- (re)Added Endpoints folder to both API and Router
- fixed syntax in namespaces
- xhr.responseJSON is returned to the fail()
- fixed Router endpoints (view in browser, cron,...)
2016-08-02 17:08:43 +02:00
cb558ce2ab Bump release version up to 0.0.38 2016-08-02 16:49:11 +03:00
ed30d8f639 externalize Success/ErrorResponse classes into their own files 2016-08-01 17:22:23 +02:00
9410d4f10a Reorganized new API + added legacy API support + new API
- Updated Settings Router to new standards
- Updated settings.html to reflect API change with better error handling
- Updated Settings API unit tests
2016-08-01 17:00:32 +02:00
354d249e1d Moved current Router files to API
- updated Unit tests to reflect the change
2016-08-01 17:00:32 +02:00
008fdb94c5 Moved lib/API to lib/Router
- renamed lib/API/API.php to lib/Router/Front.php
- updated namespaces in various file to account for namespace change
2016-08-01 17:00:32 +02:00
d0fb94b3f8 Merge pull request #577 from mailpoet/newsletter_templates
Newsletter templates
2016-07-29 16:23:12 +02:00
a451f00ed3 Remove obsolete function 2016-07-29 17:21:14 +03:00
0e0c371b28 Swap Preview and Select buttons in template select page 2016-07-29 17:15:20 +03:00
2e52f3bb92 Add a "Preview" button in template select page 2016-07-29 17:11:30 +03:00
a3a5016278 Allow template titles to be displayed in multiple lines w\o ellipsis 2016-07-29 16:56:07 +03:00
cb5d7cb9a0 Fix incorrect post notification template logo URL 2016-07-29 16:52:55 +03:00
a44d4ed0b5 Add new newsletter sample templates 2016-07-29 16:29:44 +03:00
7bd23288f6 Add newsletter blank 1 column template 2016-07-29 16:28:44 +03:00
08c663759c Merge pull request #574 from mailpoet/copy-edit
Copy edit
2016-07-29 13:34:57 +03:00
c46ee07674 Change form editor page title, swap "New" to "Add New" 2016-07-29 13:30:17 +03:00
18398a3bfb Finish changing segments to lists and columns to fields 2016-07-29 13:30:17 +03:00
88d9315f8b Finish converting Segment to List in language strings 2016-07-29 13:30:17 +03:00
8bc95db0c9 Change items to item(s), fix Twig syntax errors 2016-07-29 13:29:05 +03:00
c05a20cff9 Update 28 July 2016 2016-07-29 13:29:05 +03:00
08cb994252 Merge pull request #573 from mailpoet/text_version_fix
Fixes link rendering in text version of the newsletter
2016-07-28 16:17:13 +03:00
543ad81e28 Merge pull request #575 from mailpoet/archives_page
Newsletter Archives page
2016-07-28 15:23:50 +03:00
641ba04685 Added Newsletter::getArchives() in order to return proper archives
- Archives page: replaced created_at by processed_at as the issue date
2016-07-28 11:52:56 +02:00
8e4d07c658 - Updates regex to not match http/ftp links as shortcodes
- Updates regex to properly replace links in text version of newsletter
2016-07-27 21:57:55 -04:00
420650f37f Merge pull request #572 from mailpoet/error_handling
Display plugin initialization errors to admin
2016-07-27 15:38:57 +02:00
775f7faee4 Declare private properties and swap strings for named constants 2016-07-27 16:35:21 +03:00
13b91ad051 Encapsulate showing WP notices into a separate Notice class 2016-07-27 15:07:09 +03:00
2d3ec13473 Stringify exception to include the stack trace as well 2016-07-27 13:58:44 +03:00
3094cfc076 Prevent plugin from disabling itself on error, display that error to
admin instead
2016-07-26 16:18:33 +03:00
342 changed files with 15163 additions and 11431 deletions

View File

@ -0,0 +1,15 @@
Listen 8080
<VirtualHost *:8080>
UseCanonicalName Off
ServerName mailpoet.loc
DocumentRoot /home/ubuntu/mailpoet/wordpress
DirectoryIndex index.php
LogLevel notice
<Directory /home/ubuntu/mailpoet/wordpress>
AllowOverride All
Allow from All
</Directory>
</VirtualHost>

3
.gitignore vendored
View File

@ -12,8 +12,9 @@ npm-debug.log
/views/cache/**
temp
.idea
wysija-newsletters.zip
mailpoet.zip
tests/javascript/testBundles
assets/css/*.css
assets/js/*.js
.vagrant
lang

View File

@ -102,31 +102,51 @@ class RoboFile extends \Robo\Tasks {
);
}
function testUnit($file = null) {
function testUnit($opts=['file' => null, 'xml' => false]) {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : ''));
$command = 'vendor/bin/codecept run unit -f '.(($opts['file']) ? $opts['file'] : '');
if($opts['xml']) {
$command .= ' --xml';
}
return $this->_exec($command);
}
function testCoverage($file = null) {
function testCoverage($opts=['file' => null, 'xml' => false]) {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$this->_exec(join(' ', array(
$command = join(' ', array(
'vendor/bin/codecept run',
(($file) ? $file : ''),
(($opts['file']) ? $opts['file'] : ''),
'--coverage',
'--coverage-html'
)));
($opts['xml']) ? '--coverage-xml' : '--coverage-html'
));
if($opts['xml']) {
$command .= ' --xml';
}
return $this->_exec($command);
}
function testJavascript() {
function testJavascript($xml_output_file = null) {
$this->compileJs();
$this->_exec(join(' ', array(
$command = join(' ', array(
'./node_modules/.bin/mocha',
'-r tests/javascript/mochaTestHelper.js',
'tests/javascript/testBundles/**/*.js'
)));
));
if(!empty($xml_output_file)) {
$command .= sprintf(
' --reporter xunit --reporter-options output="%s"',
$xml_output_file
);
}
return $this->_exec($command);
}
function testDebug() {
@ -141,8 +161,13 @@ class RoboFile extends \Robo\Tasks {
$this->_exec('vendor/bin/codecept run -g failed');
}
function qa() {
$this->qaLint();
$this->qaCodeSniffer('all');
}
function qaLint() {
$this->_exec('./tasks/php_lint.sh lib/ tests/');
$this->_exec('./tasks/php_lint.sh lib/ tests/ mailpoet.php');
}
function qaCodeSniffer($severity='errors') {

View File

@ -60,16 +60,20 @@
.mailpoet_boxes .mailpoet_description
float:left
width: 245px
max-height: calc(110px - 2em)
max-height: calc(115px - 2em)
padding-bottom: 2em
overflow: hidden
.mailpoet_boxes .mailpoet_description h3
margin: 0 0 1em 0
overflow: hidden
white-space: nowrap
text-overflow: ellipsis
max-width: 220px
h3
margin: 0 0 0.7em 0
overflow: hidden
max-width: 210px
line-height: 1.4em
p
font-size: 13px
line-height: 1.5
margin: 1em 0
.mailpoet_boxes .mailpoet_actions
position: absolute

View File

@ -1,6 +1,6 @@
$tool-inactive-color = #bbbbbb
$tool-inactive-color = #333333
$tool-inactive-secondary-color = #ffffff
$tool-hover-color = #333333
$tool-hover-color = #bbbbbb
$tool-hover-secondary-color = #ffffff
$tool-active-color = #d2d2d4
$tool-active-secondary-color = #ffffff
@ -12,21 +12,42 @@ $master-column-tool-width = 24px
position: absolute
top: 0
right: 0
display: none
z-index: 20
padding: 2px
text-align: right
overflow: hidden
.mailpoet_tool_slider
position: relative
right: -100%
transition: all 250ms cubic-bezier(0.420, 0.000, 0.580, 1.000)
opacity: 0
&.mailpoet_display_tools
.mailpoet_tool_slider
right: 0
opacity: 1
a
vertical-align: top
.mailpoet_container_horizontal + &
left: 100%
right: initial
padding-left: 5px
.mailpoet_tool_slider
left: -100%
right: initial
&.mailpoet_display_tools
.mailpoet_tool_slider
left: 0
.mailpoet_tool
width: $master-column-tool-width
height: $master-column-tool-width
display: block
.mailpoet_tool_icon
width: $master-column-tool-width

View File

@ -4,7 +4,7 @@
.mailpoet_input_title,
.mailpoet_input_preheader
width: 400px
width: 500px
padding: 3px
line-height: normal

View File

@ -5,8 +5,8 @@ $active-social-icon-set-border-color = #adadad
$active-social-icon-set-background-color = #daebf2
$social-icon-set-hover-border-color = $primary-active-color
$tool-inactive-color = #bbbbbb
$tool-hover-color = #333333
$tool-inactive-color = #333333
$tool-hover-color = #bbbbbb
$tool-active-color = #d2d2d4
$tool-width = 16px

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 178 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -8,19 +8,11 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
endpoint: null,
action: null,
token: null,
data: {},
onSuccess: function(data, textStatus, xhr) {},
onError: function(xhr, textStatus, errorThrown) {}
},
get: function(options) {
return this.request('get', options);
data: {}
},
post: function(options) {
return this.request('post', options);
},
delete: function(options) {
return this.request('delete', options);
},
init: function(options) {
// merge options
this.options = jQuery.extend({}, this.defaults, options);
@ -50,7 +42,7 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
// set request params
var params = this.getParams();
var jqXHR;
var deferred = jQuery.Deferred();
// remove null values from the data object
if (_.isObject(params.data)) {
@ -59,29 +51,22 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
})
}
// make ajax request depending on method
if(method === 'get') {
jqXHR = jQuery.get(
this.options.url,
params,
this.options.onSuccess,
'json'
);
} else {
jqXHR = jQuery.ajax({
url: this.options.url,
type : 'post',
data: params,
dataType: 'json',
success : this.options.onSuccess,
error : this.options.onError
});
}
// ajax request
deferred = jQuery.post(
this.options.url,
params,
null,
'json'
).then(function(data) {
return data;
}, function(xhr) {
return xhr.responseJSON;
});
// clear options
this.options = {};
return jqXHR;
return deferred;
}
};
});

View File

@ -1,100 +0,0 @@
define(
[
'react',
'react-dom',
'mailpoet'
],
function(
React,
ReactDOM,
MailPoet
) {
var CronControl = React.createClass({
getInitialState: function() {
return {
status: 'loading'
};
},
getCronData: function() {
MailPoet.Ajax.post({
endpoint: 'cron',
action: 'getStatus'
})
.done(function(response) {
jQuery('.button-primary')
.removeClass('disabled');
if(response.status !== undefined) {
this.setState(response);
} else {
this.replaceState();
}
}.bind(this));
},
componentDidMount: function() {
if(this.isMounted()) {
this.getCronData();
setInterval(this.getCronData, 5000);
}
},
controlCron: function(action) {
if(jQuery('.button-primary').hasClass('disabled')) {
return;
}
jQuery('.button-primary')
.addClass('disabled');
MailPoet.Ajax.post({
endpoint: 'cron',
action: action,
})
.done(function(response) {
if(!response.result) {
MailPoet.Notice.error(MailPoet.I18n.t('daemonControlError'));
}
}.bind(this));
},
render: function() {
if(this.state.status === 'loading') {
return(<div>{MailPoet.I18n.t('loadingDaemonStatus')}</div>);
}
switch(this.state.status) {
case 'started':
return(
<div>
{MailPoet.I18n.t('cronDaemonIsRunning')}
<br/>
<br/>
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'stop')}>{MailPoet.I18n.t('stop')}</a>
</div>
);
break;
case 'starting':
case 'stopping':
return(
<div>
{MailPoet.I18n.t('cronDaemonState').replace('%$1s', this.state.status)}
</div>
);
break;
case 'stopped':
return(
<div>
{MailPoet.I18n.t('cronDaemonState').replace('%$1s', this.state.status)}
<br />
<br />
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'start')}>{MailPoet.I18n.t('start')}</a>
</div>
);
break;
}
}
});
const container = document.getElementById('cron_container');
if(container) {
ReactDOM.render(
<CronControl />,
container
);
}
});

View File

@ -71,30 +71,43 @@ define('date',
convertFormat: function(format) {
var format_mappings = {
date: {
D: 'ddd',
l: 'dddd',
d: 'DD',
D: 'ddd',
j: 'D',
z: 'DDDD',
l: 'dddd',
N: 'E',
S: '',
M: 'MMM',
S: 'o',
w: 'e',
z: 'DDD',
W: 'W',
F: 'MMMM',
m: 'MM',
n: '',
t: '',
y: 'YY',
M: 'MMM',
n: 'M',
t: '', // no equivalent
L: '', // no equivalent
o: 'YYYY',
Y: 'YYYY',
H: 'HH',
h: 'hh',
g: 'h',
y: 'YY',
a: 'a',
A: 'A',
B: '', // no equivalent
g: 'h',
G: 'H',
h: 'hh',
H: 'HH',
i: 'mm',
s: 'ss',
T: 'z',
O: 'ZZ',
w: 'd',
W: 'WW'
u: 'SSS',
e: 'zz', // deprecated since version 1.6.0 of moment.js
I: '', // no equivalent
O: '', // no equivalent
P: '', // no equivalent
T: '', // no equivalent
Z: '', // no equivalent
c: '', // no equivalent
r: '', // no equivalent
U: 'X'
},
strftime: {
a: 'ddd',
@ -127,20 +140,29 @@ define('date',
var replacements = format_mappings['date'];
var outputFormat = '';
var convertedFormat = [];
var escapeToken = false;
Object.keys(replacements).forEach(function(key) {
if (format.indexOf(key) !== -1) {
format = format.replace(key, '%'+key);
for (var index in format) {
var token = format[index];
if (escapeToken === true) {
convertedFormat.push('['+token+']');
escapeToken = false;
} else {
if (token === '\\') {
// Slash escapes the next symbol to be treated as literal
escapeToken = true;
continue;
} else if (replacements[token] !== undefined) {
convertedFormat.push(replacements[token]);
} else {
convertedFormat.push('['+token+']');
}
}
});
outputFormat = format;
Object.keys(replacements).forEach(function(key) {
if (outputFormat.indexOf('%'+key) !== -1) {
outputFormat = outputFormat.replace('%'+key, replacements[key]);
}
});
return outputFormat;
}
return convertedFormat.join('');
}
};
});

View File

@ -127,37 +127,12 @@ define([
return;
}
const dateType = this.props.field.params.date_type;
const dateParts = value.split('-');
let year = '';
let month = '';
let day = '';
switch(dateType) {
case 'year_month_day':
year = ~~(dateParts[0]);
month = ~~(dateParts[1]);
day = ~~(dateParts[2]);
break;
case 'year_month':
year = ~~(dateParts[0]);
month = ~~(dateParts[1]);
break;
case 'month':
month = ~~(dateParts[0]);
break;
case 'year':
year = ~~(dateParts[0]);
break;
}
const dateTime = Moment(value);
this.setState({
year: year,
month: month,
day: day
year: dateTime.format('YYYY'),
month: dateTime.format('M'),
day: dateTime.format('D')
});
}
formatValue() {
@ -228,7 +203,7 @@ define([
const fields = dateSelects.map(type => {
switch(type) {
case 'yyyy':
case 'YYYY':
return (<FormFieldDateYear
onValueChange={ this.onValueChange.bind(this) }
ref={ 'year' }
@ -239,7 +214,7 @@ define([
/>);
break;
case 'mm':
case 'MM':
return (<FormFieldDateMonth
onValueChange={ this.onValueChange.bind(this) }
ref={ 'month' }
@ -251,7 +226,7 @@ define([
/>);
break;
case 'dd':
case 'DD':
return (<FormFieldDateDay
onValueChange={ this.onValueChange.bind(this) }
ref={ 'day' }

View File

@ -89,10 +89,17 @@ function(
if(this.props.field['selected'] !== undefined) {
return this.props.field['selected'](this.props.item);
} else if(this.props.item !== undefined && this.props.field.name !== undefined) {
return this.props.item[this.props.field.name];
} else {
return null;
if (this.allowMultipleValues()) {
if (Array.isArray(this.props.item[this.props.field.name])) {
return this.props.item[this.props.field.name].map(function(item) {
return item.id;
});
}
} else {
return this.props.item[this.props.field.name];
}
}
return null;
},
loadCachedItems: function() {
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
@ -115,9 +122,10 @@ function(
} else {
value = e.target.value;
}
var transformedValue = this.transformChangedValue(value);
this.props.onValueChange({
target: {
value: value,
value: transformedValue,
name: this.props.field.name
}
});
@ -141,6 +149,16 @@ function(
}
return item.id;
},
// When it's impossible to represent the desired value in DOM,
// this function may be used to transform the placeholder value into
// desired value.
transformChangedValue: function(value) {
if(typeof this.props.field['transformChangedValue'] === 'function') {
return this.props.field.transformChangedValue.call(this, value);
} else {
return value;
}
},
render: function() {
const options = this.state.items.map((item, index) => {
let label = this.getLabel(item);

View File

@ -66,22 +66,22 @@ define(
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'get',
data: id
}).done(function(response) {
if(response === false) {
this.setState({
loading: false,
item: {}
}, function() {
this.context.router.push('/new');
}.bind(this));
} else {
this.setState({
loading: false,
item: response
});
data: {
id: id
}
}.bind(this));
}).done((response) => {
this.setState({
loading: false,
item: response.data
});
}).fail((response) => {
this.setState({
loading: false,
item: {}
}, function() {
this.context.router.push('/new');
});
});
},
handleSubmit: function(e) {
e.preventDefault();
@ -115,29 +115,25 @@ define(
endpoint: this.props.endpoint,
action: 'save',
data: item
}).done(function(response) {
}).always(() => {
this.setState({ loading: false });
if(response.result === true) {
if(this.props.onSuccess !== undefined) {
this.props.onSuccess();
} else {
this.context.router.push('/');
}
if(this.props.params.id !== undefined) {
this.props.messages.onUpdate();
} else {
this.props.messages.onCreate();
}
}).done((response) => {
if(this.props.onSuccess !== undefined) {
this.props.onSuccess();
} else {
if(response.result === false) {
if(response.errors.length > 0) {
this.setState({ errors: response.errors });
}
}
this.context.router.push('/');
}
}.bind(this));
if(this.props.params.id !== undefined) {
this.props.messages.onUpdate();
} else {
this.props.messages.onCreate();
}
}).fail((response) => {
if(response.errors.length > 0) {
this.setState({ errors: response.errors });
}
});
},
handleValueChange: function(e) {
if (this.props.onChange) {
@ -159,7 +155,7 @@ define(
var errors = this.getErrors().map(function(error, index) {
return (
<p key={ 'error-'+index } className="mailpoet_error">
{ error }
{ error.message }
</p>
);
});

View File

@ -27,48 +27,48 @@ const columns = [
];
const messages = {
onTrash: function(response) {
var count = ~~response;
var message = null;
onTrash: (response) => {
const count = ~~response.meta.count;
let message = null;
if(count === 1) {
if (count === 1) {
message = (
MailPoet.I18n.t('oneFormTrashed')
);
} else {
message = (
MailPoet.I18n.t('multipleFormsTrashed')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onDelete: function(response) {
var count = ~~response;
var message = null;
onDelete: (response) => {
const count = ~~response.meta.count;
let message = null;
if(count === 1) {
if (count === 1) {
message = (
MailPoet.I18n.t('oneFormDeleted')
);
} else {
message = (
MailPoet.I18n.t('multipleFormsDeleted')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onRestore: function(response) {
var count = ~~response;
var message = null;
onRestore: (response) => {
const count = ~~response.meta.count;
let message = null;
if(count === 1) {
if (count === 1) {
message = (
MailPoet.I18n.t('oneFormRestored')
);
} else {
message = (
MailPoet.I18n.t('multipleFormsRestored')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
}
@ -99,14 +99,21 @@ const item_actions = [
return MailPoet.Ajax.post({
endpoint: 'forms',
action: 'duplicate',
data: item.id
}).done(function(response) {
if (response !== false && response['name'] !== undefined) {
MailPoet.Notice.success(
(MailPoet.I18n.t('formDuplicated')).replace('%$1s', response.name)
data: {
id: item.id
}
}).done((response) => {
MailPoet.Notice.success(
(MailPoet.I18n.t('formDuplicated')).replace('%$1s', response.data.name)
);
refresh();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
refresh();
});
}
},
@ -120,9 +127,14 @@ const FormList = React.createClass({
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'create'
}).done(function(response) {
if(response.result && response.form_id) {
window.location = mailpoet_form_edit_url + response.form_id;
}).done((response) => {
window.location = mailpoet_form_edit_url + response.data.id;
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
});
},
@ -139,6 +151,10 @@ const FormList = React.createClass({
return segment.name;
}).join(', ');
if (form.settings.segments_selected_by === 'user') {
segments = MailPoet.I18n.t('userChoice') + ' ' + segments;
}
return (
<div>
<td className={ row_classes }>

View File

@ -53,7 +53,10 @@ function(
}
if(data.action) {
this.props.onBulkAction(selected_ids, data).then(onSuccess);
const promise = this.props.onBulkAction(selected_ids, data);
if (promise !== false) {
promise.then(onSuccess);
};
}
this.setState({

View File

@ -456,22 +456,29 @@ const Listing = React.createClass({
sort_by: this.state.sort_by,
sort_order: this.state.sort_order
}
}).done(function(response) {
}).always(() => {
this.setState({ loading: false });
}).done((response) => {
this.setState({
items: response.items || [],
filters: response.filters || {},
groups: response.groups || [],
count: response.count || 0,
loading: false
}, function() {
if (this.props['onGetItems'] !== undefined) {
const count = (response.groups[0] !== undefined)
? ~~(response.groups[0].count)
: 0;
this.props.onGetItems(count);
items: response.data || [],
filters: response.meta.filters || {},
groups: response.meta.groups || [],
count: response.meta.count || 0
}, () => {
// if viewing an empty trash
if (this.state.group === 'trash' && response.meta.count === 0) {
// redirect to default group
this.handleGroup('all');
}
}.bind(this));
}.bind(this));
});
}).fail(function(response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
});
}
},
handleRestoreItem: function(id) {
@ -483,8 +490,10 @@ const Listing = React.createClass({
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'restore',
data: id
}).done(function(response) {
data: {
id: id
}
}).done((response) => {
if (
this.props.messages !== undefined
&& this.props.messages['onRestore'] !== undefined
@ -492,7 +501,12 @@ const Listing = React.createClass({
this.props.messages.onRestore(response);
}
this.getItems();
}.bind(this));
}).fail((response) => {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
});
},
handleTrashItem: function(id) {
this.setState({
@ -503,8 +517,10 @@ const Listing = React.createClass({
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'trash',
data: id
}).done(function(response) {
data: {
id: id
}
}).done((response) => {
if (
this.props.messages !== undefined
&& this.props.messages['onTrash'] !== undefined
@ -512,7 +528,12 @@ const Listing = React.createClass({
this.props.messages.onTrash(response);
}
this.getItems();
}.bind(this));
}).fail((response) => {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
});
},
handleDeleteItem: function(id) {
this.setState({
@ -523,8 +544,10 @@ const Listing = React.createClass({
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'delete',
data: id
}).done(function(response) {
data: {
id: id
}
}).done((response) => {
if (
this.props.messages !== undefined
&& this.props.messages['onDelete'] !== undefined
@ -532,22 +555,29 @@ const Listing = React.createClass({
this.props.messages.onDelete(response);
}
this.getItems();
}.bind(this));
}).fail((response) => {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
});
},
handleEmptyTrash: function() {
return this.handleBulkAction('all', {
action: 'delete',
group: 'trash'
}).then(function(response) {
if (~~(response) > 0) {
MailPoet.Notice.success(
MailPoet.I18n.t('permanentlyDeleted').replace('%d', response)
);
}
}).done((response) => {
MailPoet.Notice.success(
MailPoet.I18n.t('permanentlyDeleted').replace('%d', response.meta.count)
);
// redirect to default group
this.handleGroup('all');
}.bind(this));
}).fail((response) => {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
});
},
handleBulkAction: function(selected_ids, params) {
if (
@ -555,7 +585,7 @@ const Listing = React.createClass({
&& this.state.selected_ids.length === 0
&& selected_ids !== 'all'
) {
return;
return false;
}
this.setState({ loading: true });
@ -594,7 +624,7 @@ const Listing = React.createClass({
handleSort: function(sort_by, sort_order = 'asc') {
this.setState({
sort_by: sort_by,
sort_order: sort_order,
sort_order: (sort_order === 'asc') ? 'asc' : 'desc',
}, function() {
this.setParams();
}.bind(this));

View File

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

View File

@ -35,7 +35,12 @@ define([
Module.ALCSupervisor = SuperModel.extend({
initialize: function() {
this.listenTo(App.getChannel(), 'automatedLatestContentRefresh', this.refresh);
var DELAY_REFRESH_FOR_MS = 500;
this.listenTo(
App.getChannel(),
'automatedLatestContentRefresh',
_.debounce(this.refresh, DELAY_REFRESH_FOR_MS)
);
},
refresh: function() {
var models = App.findModels(function(model) {
@ -107,9 +112,7 @@ define([
this.on('change:amount change:contentType change:terms change:inclusionType change:displayType change:titleFormat change:featuredImagePosition change:titleAlignment change:titleIsLink change:imageFullWidth change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:sortBy change:showDivider', this._scheduleFetchPosts, this);
this.listenTo(this.get('readMoreButton'), 'change', this._scheduleFetchPosts);
this.listenTo(this.get('divider'), 'change', this._scheduleFetchPosts);
this.on('add remove update reset', function(model, collection, options) {
App.getChannel().trigger('automatedLatestContentRefresh');
});
this.on('add remove update reset', this._scheduleFetchPosts);
this.on('refreshPosts', this.updatePosts, this);
},
updatePosts: function(posts) {
@ -120,16 +123,7 @@ define([
* ALC posts on each model change
*/
_scheduleFetchPosts: function() {
var TIMEOUT = 500,
that = this;
if (this._fetchPostsTimer !== undefined) {
clearTimeout(this._fetchPostsTimer);
}
this._fetchPostsTimer = setTimeout(function() {
//that.fetchPosts();
App.getChannel().trigger('automatedLatestContentRefresh');
that._fetchPostsTimer = undefined;
}, TIMEOUT);
App.getChannel().trigger('automatedLatestContentRefresh');
},
});
@ -180,17 +174,17 @@ define([
"change .mailpoet_automated_latest_content_title_format": 'changeTitleFormat',
"change .mailpoet_automated_latest_content_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'),
"change .mailpoet_automated_latest_content_show_divider": _.partial(this.changeBoolField, 'showDivider'),
"keyup .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_include_or_exclude": _.partial(this.changeField, "inclusionType"),
"change .mailpoet_automated_latest_content_title_alignment": _.partial(this.changeField, "titleAlignment"),
"change .mailpoet_automated_latest_content_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
"change .mailpoet_automated_latest_content_featured_image_position": _.partial(this.changeField, "featuredImagePosition"),
"change .mailpoet_automated_latest_content_show_author": _.partial(this.changeField, "showAuthor"),
"keyup .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"),
"keyup .mailpoet_automated_latest_content_categories": _.partial(this.changeField, "categoriesPrecededBy"),
"keyup .mailpoet_automated_latest_content_read_more_text": _.partial(this.changeField, "readMoreText"),
"input .mailpoet_automated_latest_content_categories": _.partial(this.changeField, "categoriesPrecededBy"),
"input .mailpoet_automated_latest_content_read_more_text": _.partial(this.changeField, "readMoreText"),
"change .mailpoet_automated_latest_content_sort_by": _.partial(this.changeField, "sortBy"),
"click .mailpoet_done_editing": "close",
};
@ -217,8 +211,10 @@ define([
};
},
transport: function(options, success, failure) {
var taxonomies,
promise = CommunicationComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
var taxonomies;
var promise = CommunicationComponent.getTaxonomies(
that.model.get('contentType')
).then(function(tax) {
taxonomies = tax;
// Fetch available terms based on the list of taxonomies already fetched
var promise = CommunicationComponent.getTerms({
@ -227,7 +223,7 @@ define([
}).then(function(terms) {
return {
taxonomies: taxonomies,
terms: terms,
terms: terms
};
});
return promise;

View File

@ -99,12 +99,12 @@ define([
},
showTools: function(_event) {
if (!this.showingToolsDisabled) {
this.$('> .mailpoet_tools').show();
this.$('> .mailpoet_tools').addClass('mailpoet_display_tools');
this.toolsView.triggerMethod('showTools');
}
},
hideTools: function(e) {
this.$('> .mailpoet_tools').hide();
this.$('> .mailpoet_tools').removeClass('mailpoet_display_tools');
this.toolsView.triggerMethod('hideTools');
},
enableShowingTools: function() {

View File

@ -19,7 +19,7 @@ define([
return this._getDefaults({
type: 'button',
text: 'Button',
url: 'http://google.com',
url: '',
styles: {
block: {
backgroundColor: '#ff0000',
@ -44,6 +44,9 @@ define([
className: "mailpoet_block mailpoet_button_block mailpoet_droppable_block",
getTemplate: function() { return templates.buttonBlock; },
onDragSubstituteBy: function() { return Module.ButtonWidgetView; },
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
ShowSettingsBehavior: {},
}),
initialize: function() {
base.BlockView.prototype.initialize.apply(this, arguments);
@ -65,8 +68,8 @@ define([
getTemplate: function() { return templates.buttonBlockSettings; },
events: function() {
return {
"keyup .mailpoet_field_button_text": _.partial(this.changeField, "text"),
"keyup .mailpoet_field_button_url": _.partial(this.changeField, "url"),
"input .mailpoet_field_button_text": _.partial(this.changeField, "text"),
"input .mailpoet_field_button_url": _.partial(this.changeField, "url"),
"change .mailpoet_field_button_alignment": _.partial(this.changeField, "styles.block.textAlign"),
"change .mailpoet_field_button_font_color": _.partial(this.changeColorField, "styles.block.fontColor"),
"change .mailpoet_field_button_font_family": _.partial(this.changeField, "styles.block.fontFamily"),
@ -77,23 +80,19 @@ define([
"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_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
"keyup .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)),
"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_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)),
"keyup .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)),
"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_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width', _.partial(this.changePixelField, "styles.block.width").bind(this)),
"keyup .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)),
"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_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)),
"keyup .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_done_editing": "close",

View File

@ -186,13 +186,13 @@ define([
},
showTools: function() {
if (this.renderOptions.depth === 1 && !this.$el.hasClass('mailpoet_container_layer_active')) {
this.$(this.ui.tools).show();
this.$(this.ui.tools).addClass('mailpoet_display_tools');
this.toolsView.triggerMethod('showTools');
}
},
hideTools: function() {
if (this.renderOptions.depth === 1 && !this.$el.hasClass('mailpoet_container_layer_active')) {
this.$(this.ui.tools).hide();
this.$(this.ui.tools).removeClass('mailpoet_display_tools');
this.toolsView.triggerMethod('hideTools');
}
},

View File

@ -43,6 +43,9 @@ define([
minLength: 0, // TODO: Move this number to editor configuration
modelField: 'styles.block.padding',
},
ShowSettingsBehavior: {
ignoreFrom: '.mailpoet_resize_handle'
},
}, base.BlockView.prototype.behaviors),
onDragSubstituteBy: function() { return Module.DividerWidgetView; },
initialize: function() {
@ -88,8 +91,7 @@ define([
"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_input": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
"keyup .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_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),

View File

@ -71,11 +71,17 @@ define([
that.model.set('text', editor.getContent());
});
editor.on('click', function(e) {
editor.focus();
});
editor.on('focus', function(e) {
that.disableDragging();
that.disableShowingTools();
});
editor.on('blur', function(e) {
that.enableDragging();
that.enableShowingTools();
});
},
@ -84,6 +90,12 @@ define([
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
},
disableDragging: function() {
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');
},
enableDragging: function() {
this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag');
},
});
Module.FooterBlockToolsView = base.BlockToolsView.extend({

View File

@ -71,11 +71,17 @@ define([
that.model.set('text', editor.getContent());
});
editor.on('click', function(e) {
editor.focus();
});
editor.on('focus', function(e) {
that.disableDragging();
that.disableShowingTools();
});
editor.on('blur', function(e) {
that.enableDragging();
that.enableShowingTools();
});
},
@ -84,6 +90,12 @@ define([
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
},
disableDragging: function() {
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');
},
enableDragging: function() {
this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag');
},
});
Module.HeaderBlockToolsView = base.BlockToolsView.extend({

View File

@ -17,8 +17,8 @@ define([
defaults: function() {
return this._getDefaults({
type: 'image',
link: 'http://example.org',
src: 'no-image.png',
link: '',
src: '',
alt: 'An image of...',
fullWidth: true, // true | false
width: '64px',
@ -41,6 +41,9 @@ define([
imageMissingSrc: App.getConfig().get('urls.imageMissing'),
}, base.BlockView.prototype.templateHelpers.apply(this));
},
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
ShowSettingsBehavior: {},
}),
onRender: function() {
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
this.toolsRegion.show(this.toolsView);
@ -61,9 +64,9 @@ define([
getTemplate: function() { return templates.imageBlockSettings; },
events: function() {
return {
"keyup .mailpoet_field_image_link": _.partial(this.changeField, "link"),
"keyup .mailpoet_field_image_address": _.partial(this.changeField, "src"),
"keyup .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
"input .mailpoet_field_image_link": _.partial(this.changeField, "link"),
"input .mailpoet_field_image_address": _.partial(this.changeField, "src"),
"input .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
"change .mailpoet_field_image_full_width": _.partial(this.changeBoolCheckboxField, "fullWidth"),
"change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"),
"click .mailpoet_field_image_select_another_image": "showMediaManager",

View File

@ -273,7 +273,7 @@ define([
return {
'change .mailpoet_settings_posts_content_type': _.partial(this.changeField, 'contentType'),
'change .mailpoet_posts_post_status': _.partial(this.changeField, 'postStatus'),
'keyup .mailpoet_posts_search_term': _.partial(this.changeField, 'search'),
'input .mailpoet_posts_search_term': _.partial(this.changeField, 'search'),
};
},
constructor: function() {
@ -302,8 +302,10 @@ define([
};
},
transport: function(options, success, failure) {
var taxonomies,
promise = CommunicationComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
var taxonomies;
var promise = CommunicationComponent.getTaxonomies(
that.model.get('contentType')
).then(function(tax) {
taxonomies = tax;
// Fetch available terms based on the list of taxonomies already fetched
var promise = CommunicationComponent.getTerms({
@ -312,7 +314,7 @@ define([
}).then(function(terms) {
return {
taxonomies: taxonomies,
terms: terms,
terms: terms
};
});
return promise;
@ -412,17 +414,17 @@ define([
"change .mailpoet_posts_title_format": 'changeTitleFormat',
"change .mailpoet_posts_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'),
"change .mailpoet_posts_show_divider": _.partial(this.changeBoolField, 'showDivider'),
"keyup .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_include_or_exclude": _.partial(this.changeField, "inclusionType"),
"change .mailpoet_posts_title_alignment": _.partial(this.changeField, "titleAlignment"),
"change .mailpoet_posts_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
"change .mailpoet_posts_featured_image_position": _.partial(this.changeField, "featuredImagePosition"),
"change .mailpoet_posts_show_author": _.partial(this.changeField, "showAuthor"),
"keyup .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"),
"keyup .mailpoet_posts_categories": _.partial(this.changeField, "categoriesPrecededBy"),
"keyup .mailpoet_posts_read_more_text": _.partial(this.changeField, "readMoreText"),
"input .mailpoet_posts_categories": _.partial(this.changeField, "categoriesPrecededBy"),
"input .mailpoet_posts_read_more_text": _.partial(this.changeField, "readMoreText"),
"change .mailpoet_posts_sort_by": _.partial(this.changeField, "sortBy"),
};
},

View File

@ -93,6 +93,7 @@ define([
return {
model: this.model.toJSON(),
allIconSets: allIconSets.toJSON(),
imageMissingSrc: App.getConfig().get('urls.imageMissing'),
};
},
});
@ -140,6 +141,7 @@ define([
},
},
HighlightEditingBehavior: {},
ShowSettingsBehavior: {},
},
onDragSubstituteBy: function() { return Module.SocialWidgetView; },
constructor: function() {
@ -148,6 +150,7 @@ define([
Marionette.CompositeView.apply(this, arguments);
},
initialize: function() {
this.on('showSettings', this.showSettings, this);
this.on('dom:refresh', this.showBlock, this);
this._isFirstRender = true;
},
@ -168,13 +171,16 @@ define([
this.regionManager.destroy();
},
showTools: function(_event) {
this.$(this.ui.tools).show();
this.$(this.ui.tools).addClass('mailpoet_display_tools');
_event.stopPropagation();
},
hideTools: function(_event) {
this.$(this.ui.tools).hide();
this.$(this.ui.tools).removeClass('mailpoet_display_tools');
_event.stopPropagation();
},
showSettings: function(options) {
this.toolsView.triggerMethod('showSettings', options);
},
getDropFunc: function() {
return function() {
return this.model.clone();
@ -274,9 +280,9 @@ define([
return {
"click .mailpoet_delete_block": "deleteIcon",
"change .mailpoet_social_icon_field_type": _.partial(this.changeField, "iconType"),
"keyup .mailpoet_social_icon_field_image": _.partial(this.changeField, "image"),
"keyup .mailpoet_social_icon_field_link": this.changeLink,
"keyup .mailpoet_social_icon_field_text": _.partial(this.changeField, "text"),
"input .mailpoet_social_icon_field_image": _.partial(this.changeField, "image"),
"input .mailpoet_social_icon_field_link": this.changeLink,
"input .mailpoet_social_icon_field_text": _.partial(this.changeField, "text"),
};
},
modelEvents: {
@ -383,7 +389,7 @@ define([
{
type: 'socialIcon',
iconType: 'facebook',
link: 'http://example.com',
link: 'http://www.facebook.com',
image: App.getAvailableStyles().get('socialIconSets.default.facebook'),
height: '32px',
width: '32px',
@ -392,7 +398,7 @@ define([
{
type: 'socialIcon',
iconType: 'twitter',
link: 'http://example.com',
link: 'http://www.twitter.com',
image: App.getAvailableStyles().get('socialIconSets.default.twitter'),
height: '32px',
width: '32px',

View File

@ -36,6 +36,9 @@ define([
minLength: 20, // TODO: Move this number to editor configuration
modelField: 'styles.block.height',
},
ShowSettingsBehavior: {
ignoreFrom: '.mailpoet_resize_handle'
},
}, base.BlockView.prototype.behaviors),
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
onDragSubstituteBy: function() { return Module.SpacerWidgetView; },

View File

@ -69,11 +69,17 @@ define([
that.model.set('text', editor.getContent());
});
editor.on('click', function(e) {
editor.focus();
});
editor.on('focus', function(e) {
that.disableDragging();
that.disableShowingTools();
});
editor.on('blur', function(e) {
that.enableDragging();
that.enableShowingTools();
});
},
@ -83,6 +89,12 @@ define([
});
}
},
disableDragging: function() {
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');
},
enableDragging: function() {
this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag');
},
});
Module.TextBlockToolsView = base.BlockToolsView.extend({

View File

@ -11,7 +11,7 @@ define([
return MailPoet.Ajax.post({
endpoint: 'automatedLatestContent',
action: args.action,
data: args.options || {},
data: args.options || {}
});
};
Module._cachedQuery = _.memoize(Module._query, JSON.stringify);
@ -19,16 +19,16 @@ define([
Module.getNewsletter = function(options) {
return Module._query({
action: 'get',
options: options,
options: options
});
};
Module.getPostTypes = function() {
return Module._cachedQuery({
action: 'getPostTypes',
options: {},
}).then(function(types) {
return _.values(types);
options: {}
}).then(function(response) {
return _.values(response.data);
});
};
@ -36,36 +36,46 @@ define([
return Module._cachedQuery({
action: 'getTaxonomies',
options: {
postType: postType,
},
postType: postType
}
}).then(function(response) {
return response.data;
});
};
Module.getTerms = function(options) {
return Module._cachedQuery({
action: 'getTerms',
options: options,
options: options
}).then(function(response) {
return response.data;
});
};
Module.getPosts = function(options) {
return Module._cachedQuery({
action: 'getPosts',
options: options,
options: options
}).then(function(response) {
return response.data;
});
};
Module.getTransformedPosts = function(options) {
return Module._cachedQuery({
action: 'getTransformedPosts',
options: options,
options: options
}).then(function(response) {
return response.data;
});
};
Module.getBulkTransformedPosts = function(options) {
return Module._query({
action: 'getBulkTransformedPosts',
options: options,
options: options
}).then(function(response) {
return response.data;
});
};
@ -73,7 +83,7 @@ define([
return MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'save',
data: options || {},
data: options || {}
});
};
@ -81,7 +91,7 @@ define([
return MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'sendPreview',
data: options || {},
data: options || {}
});
};

View File

@ -11,15 +11,16 @@ define([
// Does not hold newsletter content nor newsletter styles, those are
// handled by other components.
Module.NewsletterModel = SuperModel.extend({
stale: ['body', 'created_at', 'deleted_at', 'updated_at'],
whitelisted: ['id', 'subject', 'preheader'],
initialize: function(options) {
this.on('change', function() {
App.getChannel().trigger('autoSave');
});
},
toJSON: function() {
// Remove stale attributes from resulting JSON object
return _.omit(SuperModel.prototype.toJSON.call(this), this.stale);
// Use only whitelisted properties to ensure properties editor
// doesn't control don't change.
return _.pick(SuperModel.prototype.toJSON.call(this), this.whitelisted);
},
});

View File

@ -104,7 +104,7 @@ define([
return MailPoet.Ajax.post({
endpoint: 'newsletterTemplates',
action: 'save',
data: data,
data: data
});
});

View File

@ -65,10 +65,6 @@ define([
var $openRegion = this.$el.find('.mailpoet_sidebar_region:not(.closed)'),
$targetRegion = this.$el.find(event.target).closest('.mailpoet_sidebar_region');
if ($openRegion.get(0) === $targetRegion.get(0)) {
return;
}
$openRegion.find('.mailpoet_region_content').velocity(
'slideUp',
{
@ -79,16 +75,19 @@ define([
}.bind(this)
}
);
$targetRegion.find('.mailpoet_region_content').velocity(
'slideDown',
{
duration: 250,
easing: "easeIn",
complete: function() {
$targetRegion.removeClass('closed');
},
}
);
if ($openRegion.get(0) !== $targetRegion.get(0)) {
$targetRegion.find('.mailpoet_region_content').velocity(
'slideDown',
{
duration: 250,
easing: "easeIn",
complete: function() {
$targetRegion.removeClass('closed');
},
}
);
}
},
},
initialize: function(options) {
@ -233,6 +232,12 @@ define([
'click .mailpoet_show_preview': 'showPreview',
'click #mailpoet_send_preview': 'sendPreview',
},
onBeforeDestroy: function() {
if (this.previewView) {
this.previewView.destroy();
this.previewView = null;
}
},
showPreview: function() {
var json = App.toJSON();
@ -247,18 +252,31 @@ define([
endpoint: 'newsletters',
action: 'showPreview',
data: json,
}).done(function(response){
}).always(function() {
MailPoet.Modal.loading(false);
}).done(function(response) {
this.previewView = new Module.NewsletterPreviewView({
previewUrl: response.meta.preview_url
});
if (response.result === true) {
window.open(response.data.url, '_blank')
var view = this.previewView.render();
MailPoet.Modal.popup({
template: '',
element: this.previewView.$el,
title: MailPoet.I18n.t('newsletterPreview'),
onCancel: function() {
this.previewView.destroy();
this.previewView = null;
}.bind(this)
});
}.bind(this)).fail(function(response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
MailPoet.Notice.error(response.errors);
}).fail(function(error) {
MailPoet.Modal.loading(false);
MailPoet.Notice.error(
MailPoet.I18n.t('newsletterPreviewFailed')
);
});
},
sendPreview: function() {
@ -283,32 +301,39 @@ define([
// send test email
MailPoet.Modal.loading(true);
CommunicationComponent.previewNewsletter(data).done(function(response) {
if(response.result !== undefined && response.result === true) {
MailPoet.Notice.success(MailPoet.I18n.t('newsletterPreviewSent'), { scroll: true });
} else {
if (_.isArray(response.errors)) {
response.errors.map(function(error) {
MailPoet.Notice.error(error, { scroll: true });
});
} else {
MailPoet.Notice.error(
MailPoet.I18n.t('newsletterPreviewFailedToSend'),
{
scroll: true,
static: true,
}
);
}
}
CommunicationComponent.previewNewsletter(data).always(function() {
MailPoet.Modal.loading(false);
}).done(function(response) {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterPreviewSent'),
{ scroll: true });
}).fail(function(response) {
// an error occurred
MailPoet.Modal.loading(false);
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true, static: true }
);
}
});
},
});
Module.NewsletterPreviewView = Marionette.ItemView.extend({
getTemplate: function() { return templates.newsletterPreview; },
initialize: function(options) {
this.previewUrl = options.previewUrl;
this.width = App.getConfig().get('newsletterPreview.width');
this.height = App.getConfig().get('newsletterPreview.height')
},
templateHelpers: function() {
return {
previewUrl: this.previewUrl,
width: this.width,
height: this.height,
};
}
});
App.on('before:start', function(options) {
App.registerWidget = Module.registerWidget;
App.getWidgets = Module.getWidgets;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -8,20 +8,38 @@ const _QueueMixin = {
MailPoet.Ajax.post({
endpoint: 'sendingQueue',
action: 'pause',
data: newsletter.id
data: {
newsletter_id: newsletter.id
}
}).done(function() {
jQuery('#resume_'+newsletter.id).show();
jQuery('#pause_'+newsletter.id).hide();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
});
},
resumeSending: function(newsletter) {
MailPoet.Ajax.post({
endpoint: 'sendingQueue',
action: 'resume',
data: newsletter.id
data: {
newsletter_id: newsletter.id
}
}).done(function() {
jQuery('#pause_'+newsletter.id).show();
jQuery('#resume_'+newsletter.id).hide();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
});
},
renderQueueStatus: function(newsletter) {

View File

@ -17,8 +17,8 @@ import {
} from 'newsletters/scheduling/common.jsx'
const messages = {
onTrash(response) {
const count = ~~response;
onTrash: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -28,12 +28,12 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersTrashed')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onDelete(response) {
const count = ~~response;
onDelete: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -43,12 +43,12 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersDeleted')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onRestore(response) {
const count = ~~response;
onRestore: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -58,7 +58,7 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersRestored')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
}
@ -127,16 +127,23 @@ const newsletter_actions = [
return MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'duplicate',
data: newsletter.id
}).done(function(response) {
if (response !== false && response.subject !== undefined) {
MailPoet.Notice.success(
(MailPoet.I18n.t('newsletterDuplicated')).replace(
'%$1s', response.subject
)
data: {
id: newsletter.id
}
}).done((response) => {
MailPoet.Notice.success(
(MailPoet.I18n.t('newsletterDuplicated')).replace(
'%$1s', response.data.subject
)
);
refresh();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
refresh();
});
}
},
@ -158,20 +165,18 @@ const NewsletterListNotification = React.createClass({
id: ~~(e.target.getAttribute('data-id')),
status: e.target.value
}
}).done(function(response) {
if (response.result === false) {
MailPoet.Notice.error(MailPoet.I18n.t('postNotificationActivationFailed'));
// reset value to actual newsletter's status
e.target.value = response.status;
} else {
if (response.status === 'active') {
MailPoet.Notice.success(MailPoet.I18n.t('postNotificationActivated'));
}
// force refresh of listing so that groups are updated
this.forceUpdate();
}).done((response) => {
if (response.data.status === 'active') {
MailPoet.Notice.success(MailPoet.I18n.t('postNotificationActivated'));
}
}.bind(this));
// force refresh of listing so that groups are updated
this.forceUpdate();
}).fail((response) => {
MailPoet.Notice.error(MailPoet.I18n.t('postNotificationActivationFailed'));
// reset value to actual newsletter's status
e.target.value = response.status;
});
},
renderStatus: function(newsletter) {
return (

View File

@ -12,8 +12,8 @@ import { QueueMixin, StatisticsMixin } from 'newsletters/listings/mixins.jsx'
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
const messages = {
onTrash(response) {
const count = ~~response;
onTrash: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -23,12 +23,12 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersTrashed')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onDelete(response) {
const count = ~~response;
onDelete: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -38,12 +38,12 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersDeleted')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onRestore(response) {
const count = ~~response;
onRestore: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -53,7 +53,7 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersRestored')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
}
@ -122,16 +122,23 @@ const newsletter_actions = [
return MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'duplicate',
data: newsletter.id
}).done(function(response) {
if (response !== false && response.subject !== undefined) {
MailPoet.Notice.success(
(MailPoet.I18n.t('newsletterDuplicated')).replace(
'%$1s', response.subject
)
data: {
id: newsletter.id
}
}).done((response) => {
MailPoet.Notice.success(
(MailPoet.I18n.t('newsletterDuplicated')).replace(
'%$1s', response.data.subject
)
);
refresh();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
refresh();
});
}
},

View File

@ -15,8 +15,8 @@ const mailpoet_segments = window.mailpoet_segments || {};
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
const messages = {
onTrash(response) {
const count = ~~response;
onTrash: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -26,12 +26,12 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersTrashed')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onDelete(response) {
const count = ~~response;
onDelete: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -41,12 +41,12 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersDeleted')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onRestore(response) {
const count = ~~response;
onRestore: (response) => {
const count = ~~response.meta.count;
let message = null;
if (count === 1) {
@ -56,7 +56,7 @@ const messages = {
} else {
message = (
MailPoet.I18n.t('multipleNewslettersRestored')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
}
@ -125,16 +125,23 @@ const newsletter_actions = [
return MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'duplicate',
data: newsletter.id
}).done(function(response) {
if (response !== false && response.subject !== undefined) {
MailPoet.Notice.success(
(MailPoet.I18n.t('newsletterDuplicated')).replace(
'%$1s', response.subject
)
data: {
id: newsletter.id
}
}).done((response) => {
MailPoet.Notice.success(
(MailPoet.I18n.t('newsletterDuplicated')).replace(
'%$1s', response.data.subject
)
);
refresh();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
refresh();
});
}
},
@ -156,20 +163,18 @@ const NewsletterListWelcome = React.createClass({
id: ~~(e.target.getAttribute('data-id')),
status: e.target.value
}
}).done(function(response) {
if (response.result === false) {
MailPoet.Notice.error(MailPoet.I18n.t('welcomeEmailActivationFailed'));
// reset value to actual newsletter's status
e.target.value = response.status;
} else {
if (response.status === 'active') {
MailPoet.Notice.success(MailPoet.I18n.t('welcomeEmailActivated'));
}
// force refresh of listing so that groups are updated
this.forceUpdate();
}).done((response) => {
if (response.data.status === 'active') {
MailPoet.Notice.success(MailPoet.I18n.t('welcomeEmailActivated'));
}
}.bind(this));
// force refresh of listing so that groups are updated
this.forceUpdate();
}).fail((response) => {
MailPoet.Notice.error(MailPoet.I18n.t('welcomeEmailActivationFailed'));
// reset value to actual newsletter's status
e.target.value = response.status;
});
},
renderStatus: function(newsletter) {
let total_sent;

View File

@ -66,22 +66,22 @@ define(
MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'get',
data: id
}).done((response) => {
if(response === false) {
this.setState({
loading: false,
item: {},
}, function() {
this.context.router.push('/new');
}.bind(this));
} else {
this.setState({
loading: false,
item: response,
fields: this.getFieldsByNewsletter(response),
});
data: {
id: id
}
}).done((response) => {
this.setState({
loading: false,
item: response.data,
fields: this.getFieldsByNewsletter(response.data)
});
}).fail((response) => {
this.setState({
loading: false,
item: {}
}, () => {
this.context.router.push('/new');
});
});
},
handleSend: function(e) {
@ -90,78 +90,110 @@ define(
if(!this.isValid()) {
jQuery('#mailpoet_newsletter').parsley().validate();
} else {
this.setState({ loading: true });
MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'save',
data: this.state.item,
}).then((response) => {
if (response.result === true) {
return MailPoet.Ajax.post({
endpoint: 'sendingQueue',
action: 'add',
data: _.extend({}, this.state.item, {
newsletter_id: this.props.params.id,
}),
});
} else {
return response;
}
this._save(e).done(() => {
this.setState({ loading: true });
}).done((response) => {
this.setState({ loading: false });
switch (response.data.type) {
case 'notification':
case 'welcome':
return MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'setStatus',
data: {
id: this.props.params.id,
status: 'active'
}
}).done((response) => {
// redirect to listing based on newsletter type
this.context.router.push(`/${ this.state.item.type || '' }`);
if(response.result === true) {
this.context.router.push(`/${ this.state.item.type || '' }`);
MailPoet.Notice.success(response.data.message);
} else {
if(response.errors) {
MailPoet.Notice.error(response.errors);
} else {
MailPoet.Notice.error(
MailPoet.I18n.t('newsletterSendingError').replace("%$1s", '?page=mailpoet-settings')
);
}
// display success message depending on newsletter type
if (response.data.type === 'welcome') {
MailPoet.Notice.success(
MailPoet.I18n.t('welcomeEmailActivated')
);
} else if (response.data.type === 'notification') {
MailPoet.Notice.success(
MailPoet.I18n.t('postNotificationActivated')
);
}
}).fail(this._showError);
default:
return MailPoet.Ajax.post({
endpoint: 'sendingQueue',
action: 'add',
data: {
newsletter_id: this.props.params.id
}
}).done((response) => {
// redirect to listing based on newsletter type
this.context.router.push(`/${ this.state.item.type || '' }`);
if (response.data.status === 'scheduled') {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterHasBeenScheduled')
);
} else {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterBeingSent')
);
}
}).fail(this._showError);
}
}).fail(this._showError).always(() => {
this.setState({ loading: false });
});
}
return false;
},
handleSave: function(e) {
e.preventDefault();
this._save(e).done(() => {
this._save(e).done((response) => {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterUpdated')
);
}).done(() => {
this.context.router.push(`/${ this.state.item.type || '' }`);
});
}).fail(this._showError);
},
handleRedirectToDesign: function(e) {
e.preventDefault();
var redirectTo = e.target.href;
this._save(e).done(() => {
this._save(e).done((response) => {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterUpdated')
);
}).done(() => {
window.location = redirectTo;
});
}).fail(this._showError);
},
_save: function(e) {
var data = this.state.item;
this.setState({ loading: true });
// Ensure that body is JSON encoded
if (!_.isUndefined(data.body)) {
data.body = JSON.stringify(data.body);
}
return MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'save',
data: this.state.item,
}).done((response) => {
data: data,
}).always(() => {
this.setState({ loading: false });
if(response.result === true) {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterUpdated')
);
} else {
if(response.errors) {
MailPoet.Notice.error(response.errors);
}
}
});
},
_showError: (response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
},
handleFormChange: function(e) {
var item = this.state.item,
field = e.target.name;

View File

@ -1,11 +1,13 @@
define(
[
'mailpoet',
'newsletters/types/notification/scheduling.jsx'
'newsletters/types/notification/scheduling.jsx',
'underscore'
],
function(
MailPoet,
Scheduling
Scheduling,
_
) {
var settings = window.mailpoet_settings || {};
@ -40,11 +42,15 @@ define(
return !!(!segment.deleted_at);
},
getLabel: function(segment) {
var name = segment.name;
if (segment.subscribers > 0) {
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
}
return name;
return segment.name + ' (' + parseInt(segment.subscribers).toLocaleString() + ')';
},
transformChangedValue: function(segment_ids) {
var all_segments = this.state.items;
return _.map(segment_ids, function(id) {
return _.find(all_segments, function(segment) {
return segment.id === id;
});
});
},
validation: {
'data-parsley-required': true,

View File

@ -346,11 +346,15 @@ define(
return !!(!segment.deleted_at);
},
getLabel: function(segment) {
var name = segment.name;
if (segment.subscribers > 0) {
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
}
return name;
return segment.name + ' (' + parseInt(segment.subscribers).toLocaleString() + ')';
},
transformChangedValue: function(segment_ids) {
var all_segments = this.state.items;
return _.map(segment_ids, function(id) {
return _.find(all_segments, function(segment) {
return segment.id === id;
});
});
},
validation: {
'data-parsley-required': true,

View File

@ -30,33 +30,35 @@ define(
endpoint: 'newsletterTemplates',
action: 'save',
data: template
}).done(function(response) {
}).always(function() {
MailPoet.Modal.loading(false);
if(response.result === true) {
this.props.onImport(template);
} else {
response.map(function(error) {
MailPoet.Notice.error(error);
});
}).done((response) => {
this.props.onImport(response.data);
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
}.bind(this));
});
},
handleSubmit: function(e) {
e.preventDefault();
if (_.size(this.refs.templateFile.files) <= 0) return false;
var file = _.first(this.refs.templateFile.files),
reader = new FileReader(),
saveTemplate = this.saveTemplate;
var file = _.first(this.refs.templateFile.files);
var reader = new FileReader();
var saveTemplate = this.saveTemplate;
reader.onload = function(e) {
reader.onload = (e) => {
try {
saveTemplate(JSON.parse(e.target.result));
} catch (err) {
MailPoet.Notice.error(MailPoet.I18n.t('templateFileMalformedError'));
}
}.bind(this);
};
reader.readAsText(file);
},
@ -97,12 +99,12 @@ define(
MailPoet.Ajax.post({
endpoint: 'newsletterTemplates',
action: 'getAll',
}).done(function(response) {
}).always(() => {
MailPoet.Modal.loading(false);
if(this.isMounted()) {
if(response.length === 0) {
response = [
}).done((response) => {
if (this.isMounted()) {
if (response.data.length === 0) {
response.data = [
{
name:
MailPoet.I18n.t('mailpoetGuideTemplateTitle'),
@ -110,14 +112,14 @@ define(
MailPoet.I18n.t('mailpoetGuideTemplateDescription'),
readonly: "1"
}
]
];
}
this.setState({
templates: response,
templates: response.data,
loading: false
});
}
}.bind(this));
});
},
handleSelectTemplate: function(template) {
var body = template.body;
@ -134,19 +136,17 @@ define(
id: this.props.params.id,
body: body
}
}).done(function(response) {
if(response.result === true) {
// TODO: Move this URL elsewhere
window.location = 'admin.php?page=mailpoet-newsletter-editor&id=' + this.props.params.id;
} else {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
}).done((response) => {
// TODO: Move this URL elsewhere
window.location = 'admin.php?page=mailpoet-newsletter-editor&id=' + response.data.id;
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
}.bind(this));
},
handlePreviewTemplate: function(template) {
console.log('preview template #'+template.id);
});
},
handleDeleteTemplate: function(template) {
this.setState({ loading: true });
@ -160,10 +160,12 @@ define(
MailPoet.Ajax.post({
endpoint: 'newsletterTemplates',
action: 'delete',
data: template.id
}).done(function(response) {
data: {
id: template.id
}
}).done((response) => {
this.getTemplates();
}.bind(this));
});
} else {
this.setState({ loading: false });
}
@ -172,7 +174,7 @@ define(
MailPoet.Modal.popup({
title: template.name,
template: '<div class="mailpoet_boxes_preview" style="background-color: {{ body.globalStyles.body.backgroundColor }}"><img src="{{ thumbnail }}" /></div>',
data: template,
data: template
});
},
handleTemplateImport: function() {
@ -213,20 +215,19 @@ define(
</div>
<div className="mailpoet_actions">
<a
className="button button-secondary"
onClick={ this.handleShowTemplate.bind(null, template) }
>
{MailPoet.I18n.t('preview')}
</a>
&nbsp;
<a
className="button button-primary"
onClick={ this.handleSelectTemplate.bind(null, template) }
>
{MailPoet.I18n.t('select')}
</a>
&nbsp;
<a
style={ { display: 'none' }}
className="button button-secondary"
onClick={ this.handlePreviewTemplate.bind(null, template) }
>
{MailPoet.I18n.t('preview')}
</a>
</div>
{ (template.readonly === "1") ? false : deleteLink }
</li>

View File

@ -28,17 +28,16 @@ define(
type: type,
subject: MailPoet.I18n.t('draftNewsletterTitle'),
}
}).done(function(response) {
if(response.result && response.newsletter.id) {
this.context.router.push(`/template/${response.newsletter.id}`);
} else {
if(response.errors.length > 0) {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
}
}).done((response) => {
this.context.router.push(`/template/${response.data.id}`);
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
}.bind(this));
});
},
render: function() {
return (

View File

@ -50,17 +50,16 @@ define(
type: 'notification',
subject: MailPoet.I18n.t('draftNewsletterTitle'),
}),
}).done(function(response) {
if(response.result && response.newsletter.id) {
this.showTemplateSelection(response.newsletter.id);
} else {
if(response.errors.length > 0) {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
}
}).done((response) => {
this.showTemplateSelection(response.data.id);
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
}.bind(this));
});
},
showTemplateSelection: function(newsletterId) {
this.context.router.push(`/template/${newsletterId}`);

View File

@ -25,19 +25,18 @@ define(
endpoint: 'newsletters',
action: 'create',
data: {
type: 'standard',
type: 'standard'
}
}).done(function(response) {
if(response.result && response.newsletter.id) {
this.showTemplateSelection(response.newsletter.id);
} else {
if(response.errors.length > 0) {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
}
}).done((response) => {
this.showTemplateSelection(response.data.id);
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
}.bind(this));
});
},
render: function() {
return (

View File

@ -27,10 +27,7 @@ const events = {
const availableSegmentValues = _.object(_.map(
availableSegments,
function(segment) {
let name = segment.name;
if (segment.subscribers > 0) {
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
}
let name = segment.name + ' (' + parseInt(segment.subscribers).toLocaleString() + ')';
return [segment.id, name];
}
));
@ -113,17 +110,16 @@ const WelcomeScheduling = React.createClass({
type: 'welcome',
options: this.state
}
}).done(function(response) {
if (response.result && response.newsletter.id) {
this.showTemplateSelection(response.newsletter.id);
} else {
}).done((response) => {
this.showTemplateSelection(response.data.id);
}).fail((response) => {
if (response.errors.length > 0) {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
}
}.bind(this));
});
},
showTemplateSelection: function(newsletterId) {
this.context.router.push(`/template/${ newsletterId }`);

View File

@ -57,18 +57,17 @@ define(
data: _.extend({}, this.state, {
type: 'welcome',
subject: MailPoet.I18n.t('draftNewsletterTitle'),
}),
}).done(function(response) {
if(response.result && response.newsletter.id) {
this.showTemplateSelection(response.newsletter.id);
} else {
if(response.errors.length > 0) {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
}
})
}).done((response) => {
this.showTemplateSelection(response.data.id);
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
}.bind(this));
});
},
showTemplateSelection: function(newsletterId) {
this.context.router.push(`/template/${newsletterId}`);

View File

@ -40,33 +40,40 @@ function(
// ajax request
MailPoet.Ajax.post({
url: MailPoetForm.ajax_url,
token: MailPoetForm.token,
token: data.token,
endpoint: 'subscribers',
action: 'subscribe',
data: data
}).fail(function(response) {
form.find('.mailpoet_validate_error').html(
response.errors.map(function(error) {
return error.message;
}).join('<br />')
).show();
}).done(function(response) {
if(response.result === false) {
form.find('.mailpoet_validate_error').html(
response.errors.join('<br />')
).show();
// successfully subscribed
if (
response.meta !== undefined
&& response.meta.redirect_url !== undefined
) {
// go to page
window.location.href = response.meta.redirect_url;
} else {
// successfully subscribed
if(response.page !== undefined) {
// go to page
window.location.href = response.page;
} else {
// display success message
form.find('.mailpoet_validate_success').show();
}
// reset form
form.trigger('reset');
// reset validation
parsley.reset();
// display success message
form.find('.mailpoet_validate_success').show();
}
// reset form
form.trigger('reset');
// reset validation
parsley.reset();
// resize iframe
if(window.frameElement !== null) {
if (
window.frameElement !== null
&& MailPoet !== undefined
&& MailPoet['Iframe']
) {
MailPoet.Iframe.autoSize(window.frameElement);
}
});

View File

@ -36,48 +36,48 @@ var columns = [
];
const messages = {
onTrash: function(response) {
var count = ~~response;
var message = null;
onTrash: (response) => {
const count = ~~response.meta.count;
let message = null;
if(count === 1) {
if (count === 1) {
message = (
MailPoet.I18n.t('oneSegmentTrashed')
);
} else {
message = (
MailPoet.I18n.t('multipleSegmentsTrashed')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onDelete: function(response) {
var count = ~~response;
var message = null;
onDelete: (response) => {
const count = ~~response.meta.count;
let message = null;
if(count === 1) {
if (count === 1) {
message = (
MailPoet.I18n.t('oneSegmentDeleted')
);
} else {
message = (
MailPoet.I18n.t('multipleSegmentsDeleted')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onRestore: function(response) {
var count = ~~response;
var message = null;
onRestore: (response) => {
const count = ~~response.meta.count;
let message = null;
if(count === 1) {
if (count === 1) {
message = (
MailPoet.I18n.t('oneSegmentRestored')
);
} else {
message = (
MailPoet.I18n.t('multipleSegmentsRestored')
).replace('%$1d', count);
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
}
@ -106,16 +106,23 @@ const item_actions = [
{
name: 'duplicate_segment',
label: MailPoet.I18n.t('duplicate'),
onClick: function(item, refresh) {
onClick: (item, refresh) => {
return MailPoet.Ajax.post({
endpoint: 'segments',
action: 'duplicate',
data: item.id
}).done(function(response) {
data: {
id: item.id
}
}).done((response) => {
MailPoet.Notice.success(
(MailPoet.I18n.t('listDuplicated')).replace('%$1s', response.name)
MailPoet.I18n.t('listDuplicated').replace('%$1s', response.data.name)
);
refresh();
}).fail((response) => {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
});
},
display: function(segment) {
@ -127,7 +134,7 @@ const item_actions = [
link: function(item) {
return (
<a
href="https://www.mailpoet.com/#TODO"
href="http://docs.mailpoet.com/article/133-the-wordpress-users-list"
target="_blank"
>{MailPoet.I18n.t('readMore')}</a>
);

View File

@ -75,6 +75,9 @@ define(
filter: function(segment) {
return !!(!segment.deleted_at && segment.type === 'default');
},
getLabel: function(segment) {
return segment.name + ' ('+ segment.subscribers +')';
},
getSearchLabel: function(segment, subscriber) {
let label = '';

View File

@ -95,15 +95,18 @@ define(
});
};
// set confirmed subscribers export option to false
exportData.exportConfirmedOption = false;
renderSegmentsAndFields(subscriberFieldsContainerElement, subscriberFieldsSelect2);
renderSegmentsAndFields(segmentsContainerElement, segments);
subscriberFieldsContainerElement.select2('val', [
'status',
subscriberFieldsContainerElement.val([
'email',
'first_name',
'last_name'
]);
'last_name',
'status'
]).trigger("change");
exportConfirmedOptionElement.change(function () {
var selectedSegments = segmentsContainerElement.val();
@ -133,8 +136,7 @@ define(
return;
}
MailPoet.Modal.loading(true);
MailPoet.Ajax
.post({
MailPoet.Ajax.post({
endpoint: 'ImportExport',
action: 'processExport',
data: JSON.stringify({
@ -144,25 +146,22 @@ define(
'segments': (exportData.segments) ? segmentsContainerElement.val() : false,
'subscriber_fields': subscriberFieldsContainerElement.val()
})
})
.done(function (response) {
}).always(function(response) {
MailPoet.Modal.loading(false);
if (response.result === false) {
MailPoet.Notice.error(response.errors);
} else {
resultMessage = MailPoet.I18n.t('exportMessage')
.replace('%1$s', '<strong>' + parseInt(response.data.totalExported).toLocaleString() + '</strong>')
.replace('[link]', '<a href="' + response.data.exportFileURL + '" target="_blank" >')
.replace('[/link]', '</a>');
jQuery('#export_result_notice').html('<p>' + resultMessage + '</p>').show();
window.location.href = response.data.exportFileURL;
}).done(function(response) {
resultMessage = MailPoet.I18n.t('exportMessage')
.replace('%1$s', '<strong>' + parseInt(response.data.totalExported).toLocaleString() + '</strong>')
.replace('[link]', '<a href="' + response.data.exportFileURL + '" target="_blank" >')
.replace('[/link]', '</a>');
jQuery('#export_result_notice').html('<p>' + resultMessage + '</p>').show();
window.location.href = response.data.exportFileURL;
}).fail(function(response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
})
.error(function (error) {
MailPoet.Modal.loading(false);
MailPoet.Notice.error(
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
);
});
});
});

View File

@ -7,7 +7,6 @@ define(
'handlebars',
'papaparse',
'asyncqueue',
'xss',
'moment',
'select2'
],
@ -19,7 +18,6 @@ define(
Handlebars,
Papa,
AsyncQueue,
xss,
Moment
) {
if (!jQuery('#mailpoet_subscribers_import').length) {
@ -51,6 +49,12 @@ define(
* STEP 1 (upload or copy/paste)
*/
router.on('route:step1', function () {
// set or reset temporary validation rule on all columns
mailpoetColumns = jQuery.map(mailpoetColumns, function (column, columnIndex) {
column.validation_rule = false;
return column;
});
if (typeof (importData.step1) !== 'undefined') {
showCurrentStep();
return;
@ -185,68 +189,59 @@ define(
mailChimpKeyVerifyButtonElement.click(function () {
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
endpoint: 'ImportExport',
endpoint: 'importExport',
action: 'getMailChimpLists',
data: {api_key: mailChimpKeyInputElement.val()}
}).done(function (response) {
if (response.result === false) {
MailPoet.Notice.hide();
MailPoet.Notice.error(response.errors);
jQuery('.mailpoet_mailchimp-key-status')
.removeClass()
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-error');
data: {
api_key: mailChimpKeyInputElement.val()
}
}).always(function() {
MailPoet.Modal.loading(false);
}).done(function(response) {
jQuery('.mailpoet_mailchimp-key-status')
.html('')
.removeClass()
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-ok');
if (response.data.length === 0) {
jQuery('.mailpoet_mailchimp-key-status').html(MailPoet.I18n.t('noMailChimpLists'));
mailChimpListsContainerElement.hide();
toggleNextStepButton(mailChimpProcessButtonElement, 'off');
} else {
jQuery('.mailpoet_mailchimp-key-status')
.html('')
.removeClass()
.addClass('mailpoet_mailchimp-key-status mailpoet_mailchimp-ok');
if (!response.data) {
jQuery('.mailpoet_mailchimp-key-status').html(MailPoet.I18n.t('noMailChimpLists'));
mailChimpListsContainerElement.hide();
toggleNextStepButton(mailChimpProcessButtonElement, 'off');
} else {
displayMailChimpLists(response.data);
}
displayMailChimpLists(response.data);
}
}).fail(function(response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
MailPoet.Modal.loading(false);
}).error(function (error) {
MailPoet.Modal.loading(false);
MailPoet.Notice.error(
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
);
});
MailPoet.Modal.loading(false);
});
mailChimpProcessButtonElement.click(function () {
if (mailChimpProcessButtonElement.closest('table a').hasClass('disabled')) {
if (mailChimpProcessButtonElement.closest('table a').hasClass('button-disabled')) {
return;
}
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
endpoint: 'ImportExport',
endpoint: 'importExport',
action: 'getMailChimpSubscribers',
data: {
api_key: mailChimpKeyInputElement.val(),
lists: mailChimpListsContainerElement.find('select').val()
}
}).done(function (response) {
if (response.result === true) {
importData.step1 = response.data;
router.navigate('step2', {trigger: true});
}
else {
MailPoet.Notice.hide();
MailPoet.Notice.error(response.errors);
}
}).always(function(response) {
MailPoet.Modal.loading(false);
}).error(function () {
MailPoet.Modal.loading(false);
MailPoet.Notice.error(
MailPoet.I18n.t('serverError') + result.statusText.toLowerCase() + '.'
);
}).done(function(response) {
importData.step1 = response.data;
router.navigate('step2', {trigger: true});
}).fail(function(response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
}
});
});
@ -340,9 +335,9 @@ define(
complete: function (CSV) {
for (var rowCount in CSV.data) {
var rowData = CSV.data[rowCount].map(function (el) {
return filterXSS(el.trim());
}),
rowColumnCount = rowData.length;
return el.trim();
});
var rowColumnCount = rowData.length;
// set the number of row elements based on the first non-empty row
if (columnCount === null) {
columnCount = rowColumnCount;
@ -455,7 +450,7 @@ define(
null,
new Array(subscribers.subscribers[0].length)
).map(String.prototype.valueOf, filler),
fillterPosition;
fillerPosition;
showCurrentStep();
@ -533,15 +528,11 @@ define(
width: '20em',
templateResult: function (item) {
item.subscriberCount = parseInt(item.subscriberCount);
return (item.subscriberCount > 0)
? item.name + ' (' + item.subscriberCount.toLocaleString() + ')'
: item.name;
return item.name + ' (' + item.subscriberCount.toLocaleString() + ')';
},
templateSelection: function (item) {
item.subscriberCount = parseInt(item.subscriberCount);
return (item.subscriberCount > 0)
? item.name + ' (' + item.subscriberCount.toLocaleString() + ')'
: item.name;
return item.name + ' (' + item.subscriberCount.toLocaleString() + ')';
}
})
.change(function () {
@ -565,79 +556,55 @@ define(
})
}
jQuery('.mailpoet_create_segment').click(function () {
jQuery('.mailpoet_create_segment').click(function() {
MailPoet.Modal.popup({
title: MailPoet.I18n.t('addNewList'),
template: jQuery('#new_segment_template').html()
})
jQuery('#new_segment_name').keypress(function (e) {
jQuery('#new_segment_name').keypress(function(e) {
if (e.which == 13) {
jQuery('#new_segment_process').click();
}
});
jQuery('#new_segment_process').click(function () {
var segmentName = jQuery('#new_segment_name').val().trim(),
segmentDescription = jQuery('#new_segment_description').val().trim(),
isDuplicateListName = ( jQuery.map(mailpoetSegments, function (el) {
if (el.name.toLowerCase() === segmentName.toLowerCase()) {
return true;
}
}).length && segmentName) ? true : false;
if (segmentName === '') {
jQuery('.mailpoet_validation_error[data-error="segment_name_required"]:hidden').show();
} else {
jQuery('.mailpoet_validation_error[data-error="segment_name_required"]:visible').hide();
}
if (isDuplicateListName) {
jQuery('.mailpoet_validation_error[data-error="segment_name_not_unique"]:hidden').show();
} else {
jQuery('.mailpoet_validation_error[data-error="segment_name_not_unique"]:visible').hide();
}
if (segmentName && !isDuplicateListName) {
jQuery('.mailpoet_validation_error[data-error="segment_name_required"]:visible').hide();
MailPoet.Ajax
.post({
endpoint: 'ImportExport',
action: 'addSegment',
data: {
name: segmentName,
description: segmentDescription
}
})
.done(function (response) {
if (response.result === true) {
mailpoetSegments.push({
'id': response.segment.id,
'name': response.segment.name
});
var segmentName = jQuery('#new_segment_name').val().trim();
var segmentDescription = jQuery('#new_segment_description').val().trim();
var selected_values = segmentSelectElement.val();
if (selected_values === null) {
selected_values = [response.segment.id]
} else {
selected_values.push(response.segment.id);
}
MailPoet.Ajax.post({
endpoint: 'ImportExport',
action: 'addSegment',
data: {
name: segmentName,
description: segmentDescription
}
}).done(function(response) {
mailpoetSegments.push({
'id': response.data.id,
'name': response.data.name,
'subscriberCount': 0
});
enableSegmentSelection(mailpoetSegments);
segmentSelectElement.val(selected_values).trigger('change');
jQuery('.mailpoet_segments:hidden').show();
jQuery('.mailpoet_no_segments:visible').hide();
MailPoet.Modal.close();
}
else {
MailPoet.Modal.close();
MailPoet.Notice.error(
MailPoet.I18n.t('segmentCreateError') + response.message + '.'
);
}
})
.error(function (error) {
MailPoet.Modal.close();
MailPoet.Notice.error(
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
);
});
}
var selected_values = segmentSelectElement.val();
if (selected_values === null) {
selected_values = [response.data.id]
} else {
selected_values.push(response.data.id);
}
enableSegmentSelection(mailpoetSegments);
segmentSelectElement.val(selected_values).trigger('change');
jQuery('.mailpoet_segments:hidden').show();
jQuery('.mailpoet_no_segments:visible').hide();
MailPoet.Modal.close();
}).fail(function(response) {
if (response.errors.length > 0) {
MailPoet.Notice.hide();
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ positionAfter: '#new_segment_name' }
);
}
});
});
jQuery('#new_segment_cancel').click(function () {
MailPoet.Modal.close();
@ -701,13 +668,20 @@ define(
return options.fn(displayedColumns);
});
// sanitize unsafe data
Handlebars.registerHelper('sanitize_data', function(data) {
return (data instanceof Handlebars.SafeString) ?
data :
new Handlebars.SafeString(Handlebars.Utils.escapeExpression(data));
});
// start array index from 1
Handlebars.registerHelper('show_real_index', function (index) {
Handlebars.registerHelper('calculate_index', function (index) {
var index = parseInt(index);
// display filler data (e.g., ellipsis) if we've reached the maximum number of rows and
// subscribers count is greater than the maximum number of rows we're displaying
if (index === maxRowsToShow && subscribers.subscribersCount > (maxRowsToShow + 1)) {
fillterPosition = index;
fillerPosition = index;
return filler;
}
// if we're on the last line, show the total count of subscribers data
@ -745,114 +719,70 @@ define(
.on('select2:selecting', function (selectEvent) {
var selectElement = this,
selectedOptionId = selectEvent.params.args.data.id;
// CREATE CUSTOM FIELD
if (selectedOptionId === 'create') {
selectEvent.preventDefault();
jQuery(selectElement).select2('close');
MailPoet.Modal.popup({
title: MailPoet.I18n.t('addNewColumn'),
template: jQuery('#new_column_template').html()
title: MailPoet.I18n.t('addNewField'),
template: jQuery('#form_template_field_form').html()
});
jQuery('#new_column_name').keypress(function (e) {
if (e.which == 13) {
jQuery('#new_column_process').click();
}
});
jQuery('#new_column_process').click(function () {
var name = jQuery('#new_column_name').val().trim(),
type = jQuery('#new_column_type').val().trim(),
columnNames = mailpoetColumns.map(function (el) {
return el.name.toLowerCase();
jQuery('#form_field_new').parsley().on('form:submit', function(parsley) {
// get data
var data = jQuery(this.$element).serializeObject();
// save custom field
MailPoet.Ajax.post({
endpoint: 'customFields',
action: 'save',
data: data
}).done(function(response) {
var new_column_data = {
'id': response.data.id,
'name': response.data.name,
'type': response.data.type,
'params': response.data.params,
'custom': true
};
// if this is the first custom column, create an "optgroup"
if (mailpoetColumnsSelect2.length === 2) {
mailpoetColumnsSelect2.push({
'name': MailPoet.I18n.t('userColumns'),
'children': []
});
isDuplicateColumnName =
(name && columnNames.indexOf(name.toLowerCase()) > -1)
? true
: false;
if (name === '') {
jQuery('.mailpoet_validation_error[data-error="name_required"]')
.show();
} else {
jQuery('.mailpoet_validation_error[data-error="name_required"]')
.hide();
}
if (type === '') {
jQuery('.mailpoet_validation_error[data-error="type_required"]')
.show();
} else {
jQuery('.mailpoet_validation_error[data-error="type_required"]')
.hide();
}
if (isDuplicateColumnName) {
jQuery('.mailpoet_validation_error[data-error="name_not_unique"]')
.show();
} else {
jQuery('.mailpoet_validation_error[data-error="name_not_unique"]')
.hide();
}
// create new field
if (name && type && !isDuplicateColumnName) {
MailPoet.Modal
.close()
.loading(true);
MailPoet.Ajax
.post({
endpoint: 'ImportExport',
action: 'addCustomField',
data: {
name: name,
type: type
}
})
.done(function (response) {
if (response.result === true) {
var new_column_data = {
'id': response.customField.id,
'name': name,
'type': type,
'custom': true,
};
// if this is the first custom column, create an "optgroup"
if (mailpoetColumnsSelect2.length === 2) {
mailpoetColumnsSelect2.push({
'name': MailPoet.I18n.t('userColumns'),
'children': []
});
}
mailpoetColumnsSelect2[2].children.push(new_column_data);
mailpoetColumns.push(new_column_data);
jQuery('select.mailpoet_subscribers_column_data_match')
.each(function () {
jQuery(this)
.html('')
.select2('destroy')
.select2({
data: mailpoetColumnsSelect2,
width: '15em',
templateResult: function (item) {
return item.name;
},
templateSelection: function (item) {
return item.name;
}
mailpoetColumnsSelect2[2].children.push(new_column_data);
mailpoetColumns.push(new_column_data);
jQuery('select.mailpoet_subscribers_column_data_match')
.each(function () {
jQuery(this)
.html('')
.select2('destroy')
.select2({
data: mailpoetColumnsSelect2,
width: '15em',
templateResult: function (item) {
return item.name;
},
templateSelection: function (item) {
return item.name;
}
})
});
jQuery(selectElement).data('column-id', new_column_data.id);
filterSubscribers();
}
else {
MailPoet.Notice.error(MailPoet.I18n.t('customFieldCreateError'));
}
MailPoet.Modal.loading(false);
})
.error(function (error) {
MailPoet.Modal.loading(false);
MailPoet.Notice.error(
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
);
});
}
});
jQuery('#new_column_cancel').click(function () {
MailPoet.Modal.close();
})
});
jQuery(selectElement).data('column-id', new_column_data.id);
jQuery(selectElement).data('validation-rule', false);
filterSubscribers();
// close popup
MailPoet.Modal.close();
}).fail(function(response) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ positionAfter: '#field_name' }
);
}
});
return false;
});
}
// CHANGE COLUMN
@ -890,22 +820,22 @@ define(
.remove();
var subscribersClone = jQuery.extend(true, {}, subscribers),
preventNextStep = false,
displayedColumnsIds = jQuery.map(
jQuery('.mailpoet_subscribers_column_data_match'), function (data) {
var columnId = jQuery(data).data('column-id');
jQuery(data).val(columnId).trigger('change');
return columnId;
displayedColumns = jQuery.map(
jQuery('.mailpoet_subscribers_column_data_match'), function (element, elementIndex) {
var columnId = jQuery(element).data('column-id');
var validationRule = jQuery(element).data('validation-rule');
jQuery(element).val(columnId).trigger('change');
return { id: columnId, index: elementIndex, validationRule: validationRule, element: element };
});
// iterate through the object of mailpoet columns
jQuery.map(mailpoetColumns, function (column) {
jQuery.map(mailpoetColumns, function (column, columnIndex) {
// check if the column id matches the selected id of one of the
// subscriber's data columns
var matchedColumn = jQuery.inArray(column.id, displayedColumnsIds);
// EMAIL filter: if the last value in the column doesn't have a valid
var matchedColumn = _.find(displayedColumns, function(data) { return data.id === column.id; });
// EMAIL filter: if the first value in the column doesn't have a valid
// email, hide the next button
if (column.id === "email") {
if (!emailRegex.test(subscribersClone.subscribers[0][matchedColumn])) {
if (column.id === 'email') {
if (!emailRegex.test(subscribersClone.subscribers[0][matchedColumn.index])) {
preventNextStep = true;
if (!jQuery('[data-id="notice_invalidEmail"]').length) {
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidElement'), {
@ -921,35 +851,69 @@ define(
}
}
// DATE filter: if column type is date, check if we can recognize it
if (column.type === 'date' && matchedColumn !== -1) {
jQuery.map(subscribersClone.subscribers, function (data, position) {
var rowData = data[matchedColumn];
if (position !== fillterPosition) {
// check if date exists
if (rowData.trim() === '') {
data[matchedColumn] =
'<span class="mailpoet_data_match mailpoet_import_error" title="'
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
+ MailPoet.I18n.t('emptyDate')
+ '</span>';
preventNextStep = true;
return;
if (column.type === 'date' && matchedColumn) {
var allowedDateFormats = [
Moment.ISO_8601,
'YYYY/MM/DD',
'MM/DD/YYYY',
'DD/MM/YYYY',
'YYYY/MM/DD',
'YYYY/DD/MM',
'MM/YYYY',
'YYYY/MM',
'YYYY'
];
var firstRowData = subscribersClone.subscribers[0][matchedColumn.index];
var validationRule = false;
// check if date exists
if (firstRowData.trim() === '') {
subscribersClone.subscribers[0][matchedColumn.index] =
'<span class="mailpoet_data_match mailpoet_import_error" title="'
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
+ MailPoet.I18n.t('emptyFirstRowDate')
+ '</span>';
preventNextStep = true;
}
else {
for (var format in allowedDateFormats) {
var testedFormat = allowedDateFormats[format]
if (Moment(firstRowData, testedFormat, true).isValid()) {
var validationRule = (typeof(testedFormat) === 'function') ?
'datetime' :
testedFormat
// set validation on the column element
jQuery(matchedColumn.element).data('validation-rule', validationRule);
break;
}
// check if date is valid and is before today
if (Moment(rowData).isValid() && Moment(rowData).isBefore(Moment())) {
data[matchedColumn] +=
'<span class="mailpoet_data_match" title="'
+ MailPoet.I18n.t('verifyDateMatch') + '">'
+ MailPoet.Date.format(rowData) + '</span>';
}
else {
data[matchedColumn] +=
'<span class="mailpoet_data_match mailpoet_import_error" title="'
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
+ MailPoet.I18n.t('dateMatchError') + '</span>';
preventNextStep = true;
if (validationRule === 'datetime') {
validationRule = Moment.ISO_8601;
}
}
}
jQuery.map(subscribersClone.subscribers, function (data, index) {
var rowData = data[matchedColumn.index];
if (index === fillerPosition || rowData.trim() === '') return;
var date = Moment(rowData, testedFormat, true);
// validate date
if (date.isValid()) {
data[matchedColumn.index] = new Handlebars.SafeString(
Handlebars.Utils.escapeExpression(data[matchedColumn.index])
+ '<span class="mailpoet_data_match" title="'
+ MailPoet.I18n.t('verifyDateMatch') + '">'
+ MailPoet.Date.format(date)
+ '</span>'
);
}
else {
data[matchedColumn.index] = new Handlebars.SafeString(
Handlebars.Utils.escapeExpression(data[matchedColumn.index])
+ '<span class="mailpoet_data_match mailpoet_import_error" title="'
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
+ (new Handlebars.SafeString(MailPoet.I18n.t('dateMatchError')))
+ '</span>'
);
preventNextStep = true;
};
});
if (preventNextStep && !jQuery('.mailpoet_invalidDate').length) {
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidDate'), {
@ -983,11 +947,11 @@ define(
nextStepButton.addClass(disabled);
}
previousStepButton.off().click(function () {
router.navigate('step1', {trigger: true});
previousStepButton.off().on('click', function () {
router.navigate('step1', { trigger: true });
});
nextStepButton.off().click(function () {
nextStepButton.off().on('click', function () {
if (jQuery(this).hasClass('button-disabled')) {
return;
}
@ -1019,44 +983,41 @@ define(
_.each(jQuery('select.mailpoet_subscribers_column_data_match'),
function (column, columnIndex) {
var columnId = jQuery(column).data('column-id');
var validationRule = jQuery(column).data('validation-rule');
if (columnId === 'ignore') {
return;
}
columns[columnId] = columnIndex;
columns[columnId] = { index: columnIndex, validation_rule: validationRule };
});
_.each(subscribers, function () {
queue.add(function (queue) {
queue.add(function(queue) {
queue.pause();
MailPoet.Ajax
.post({
endpoint: 'ImportExport',
action: 'processImport',
data: JSON.stringify({
columns: columns,
subscribers: subscribers[batchNumber],
timestamp: timestamp,
segments: segmentSelectElement.val(),
updateSubscribers: (jQuery(':radio[name="subscriber_update_option"]:checked').val() === 'yes') ? true : false
})
MailPoet.Ajax.post({
endpoint: 'ImportExport',
action: 'processImport',
data: JSON.stringify({
columns: columns,
subscribers: subscribers[batchNumber],
timestamp: timestamp,
segments: segmentSelectElement.val(),
updateSubscribers: (jQuery(':radio[name="subscriber_update_option"]:checked').val() === 'yes') ? true : false
})
.done(function (response) {
if (response.result === false) {
importResults.errors.push(response.errors);
} else {
importResults.created = response.data.created;
importResults.updated = response.data.updated;
importResults.segments = response.data.segments;
importResults.added_to_segment_with_welcome_notification = response.data.added_to_segment_with_welcome_notification;
}
queue.run();
})
.error(function (error) {
importResults.errors.push(
MailPoet.I18n.t('serverError') + error.statusText.toLowerCase() + '.'
}).done(function(response) {
importResults.created = response.data.created;
importResults.updated = response.data.updated;
importResults.segments = response.data.segments;
importResults.added_to_segment_with_welcome_notification = response.data.added_to_segment_with_welcome_notification;
queue.run();
}).fail(function(response) {
MailPoet.Modal.loading(false);
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }),
{ scroll: true }
);
queue.run();
});
}
});
batchNumber++;
})
});
@ -1146,4 +1107,4 @@ define(
Backbone.history.start();
}
});
});
});

View File

@ -37,59 +37,50 @@ const columns = [
];
const messages = {
onTrash: function(response) {
if (response) {
var message = null;
if (~~response === 1) {
message = (
MailPoet.I18n.t('oneSubscriberTrashed')
);
} else if (~~response > 1) {
message = (
MailPoet.I18n.t('multipleSubscribersTrashed')
).replace('%$1d', (~~response).toLocaleString());
}
onTrash: (response) => {
const count = ~~response.meta.count;
let message = null;
if (message !== null) {
MailPoet.Notice.success(message);
}
if (count === 1) {
message = (
MailPoet.I18n.t('oneSubscriberTrashed')
);
} else {
message = (
MailPoet.I18n.t('multipleSubscribersTrashed')
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onDelete: function(response) {
if (response) {
var message = null;
if (~~response === 1) {
message = (
MailPoet.I18n.t('oneSubscriberDeleted')
);
} else if (~~response > 1) {
message = (
MailPoet.I18n.t('multipleSubscribersDeleted')
).replace('%$1d', ~~response);
}
onDelete: (response) => {
const count = ~~response.meta.count;
let message = null;
if (message !== null) {
MailPoet.Notice.success(message);
}
if (count === 1) {
message = (
MailPoet.I18n.t('oneSubscriberDeleted')
);
} else {
message = (
MailPoet.I18n.t('multipleSubscribersDeleted')
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
},
onRestore: function(response) {
if (response) {
var message = null;
if (~~response === 1) {
message = (
MailPoet.I18n.t('oneSubscriberRestored')
);
} else if (~~response > 1) {
message = (
MailPoet.I18n.t('multipleSubscribersRestored')
).replace('%$1d', (~~response).toLocaleString());
}
onRestore: (response) => {
const count = ~~response.meta.count;
let message = null;
if (message !== null) {
MailPoet.Notice.success(message);
}
if (count === 1) {
message = (
MailPoet.I18n.t('oneSubscriberRestored')
);
} else {
message = (
MailPoet.I18n.t('multipleSubscribersRestored')
).replace('%$1d', count.toLocaleString());
}
MailPoet.Notice.success(message);
}
};
@ -120,8 +111,8 @@ const bulk_actions = [
onSuccess: function(response) {
MailPoet.Notice.success(
MailPoet.I18n.t('multipleSubscribersMovedToList')
.replace('%$1d', (~~(response.subscribers)).toLocaleString())
.replace('%$2s', response.segment)
.replace('%$1d', (~~(response.meta.count)).toLocaleString())
.replace('%$2s', response.meta.segment)
);
}
},
@ -151,8 +142,8 @@ const bulk_actions = [
onSuccess: function(response) {
MailPoet.Notice.success(
MailPoet.I18n.t('multipleSubscribersAddedToList')
.replace('%$1d', (~~response.subscribers).toLocaleString())
.replace('%$2s', response.segment)
.replace('%$1d', (~~response.meta.count).toLocaleString())
.replace('%$2s', response.meta.segment)
);
}
},
@ -182,8 +173,8 @@ const bulk_actions = [
onSuccess: function(response) {
MailPoet.Notice.success(
MailPoet.I18n.t('multipleSubscribersRemovedFromList')
.replace('%$1d', (~~response.subscribers).toLocaleString())
.replace('%$2s', response.segment)
.replace('%$1d', (~~response.meta.count).toLocaleString())
.replace('%$2s', response.meta.segment)
);
}
},
@ -193,7 +184,7 @@ const bulk_actions = [
onSuccess: function(response) {
MailPoet.Notice.success(
MailPoet.I18n.t('multipleSubscribersRemovedFromAllLists')
.replace('%$1d', (~~response).toLocaleString())
.replace('%$1d', (~~response.meta.count).toLocaleString())
);
}
},
@ -203,7 +194,7 @@ const bulk_actions = [
onSuccess: function(response) {
MailPoet.Notice.success(
MailPoet.I18n.t('multipleConfirmationEmailsSent')
.replace('%$1d', (~~response).toLocaleString())
.replace('%$1d', (~~response.meta.count).toLocaleString())
);
}
},
@ -330,16 +321,23 @@ const SubscriberList = React.createClass({
</div>
);
},
onGetItems: function(count) {
jQuery('#mailpoet_export_button')[(count > 0) ? 'show' : 'hide']();
},
render: function() {
return (
<div>
<h1 className="title">
{MailPoet.I18n.t('pageTitle')} <Link className="page-title-action" to="/new">{MailPoet.I18n.t('new')}</Link>
<a className="page-title-action" href="?page=mailpoet-import#step1">{MailPoet.I18n.t('import')}</a>
<a id="mailpoet_export_button" className="page-title-action" href="?page=mailpoet-export">{MailPoet.I18n.t('export')}</a>
{MailPoet.I18n.t('pageTitle')} <Link
className="page-title-action"
to="/new"
>{MailPoet.I18n.t('new')}</Link>
<a
className="page-title-action"
href="?page=mailpoet-import#step1"
>{MailPoet.I18n.t('import')}</a>
<a
id="mailpoet_export_button"
className="page-title-action"
href="?page=mailpoet-export"
>{MailPoet.I18n.t('export')}</a>
</h1>
<Listing
@ -352,7 +350,6 @@ const SubscriberList = React.createClass({
bulk_actions={ bulk_actions }
item_actions={ item_actions }
messages={ messages }
onGetItems={ this.onGetItems }
sort_by={ 'created_at' }
sort_order={ 'desc' }
/>

View File

@ -1,5 +1,8 @@
#!/bin/sh
# Translations (npm install & composer install need to be run before)
./do makepot
plugin_name='mailpoet'
# Remove previous build.
@ -14,7 +17,7 @@ npm install
./do compile:all
# Production libraries.
./composer.phar install --no-dev
./composer.phar install --no-dev --prefer-dist --optimize-autoloader
# Copy release folders.
cp -Rf lang $plugin_name
@ -25,8 +28,23 @@ cp -Rf views $plugin_name
rm -Rf $plugin_name/assets/css/src
rm -Rf $plugin_name/assets/js/src
# Remove extra files (docs, examples,...) from 3rd party extensions
find $plugin_name/vendor -type f -regextype posix-egrep -iregex ".*\/*\.(markdown|md|txt)" -print0 | xargs -0 rm -f
find $plugin_name/vendor -type f -regextype posix-egrep -iregex ".*\/(readme|license|version|changes|changelog)" -print0 | xargs -0 rm -f
find $plugin_name/vendor -type d -regextype posix-egrep -iregex ".*\/(docs?|examples?|\.git)" -print0 | xargs -0 rm -rf
# Remove unit tests from 3rd party extensions
rm $plugin_name/vendor/j4mie/idiorm/demo.php
rm -rf $plugin_name/vendor/twig/twig/test
rm -rf $plugin_name/vendor/symfony/translation/Tests
rm -rf $plugin_name/vendor/phpmailer/phpmailer/test
rm -rf $plugin_name/vendor/soundasleep/html2text/tests
rm -rf $plugin_name/vendor/mtdowling/cron-expression/tests
rm -rf $plugin_name/vendor/swiftmailer/swiftmailer/tests
rm -rf $plugin_name/vendor/cerdic/css-tidy/testing
# Copy release files.
cp LICENSE $plugin_name
cp license.txt $plugin_name
cp index.php $plugin_name
cp $plugin_name.php $plugin_name
cp readme.txt $plugin_name

61
circle.yml Normal file
View File

@ -0,0 +1,61 @@
machine:
timezone:
UTC
hosts:
mailpoet.loc: 127.0.0.1
## Customize dependencies
dependencies:
pre:
# install PHP dependencies for WordPress
- sudo apt-get update
- sudo apt-get --assume-yes install php5-mysql
# configure Apache
- sudo cp ./.circle_ci/apache/mailpoet.loc.conf /etc/apache2/sites-available
- sudo a2ensite mailpoet.loc
- sudo a2enmod rewrite
- sudo service apache2 restart
# install Phoenix dependencies
- composer install
- ./do install
# Set up Wordpress
# No password is required for the MySQL user `ubuntu`
- mysql -u ubuntu -e "create database wordpress"
# Use cURL to fetch WP-CLI
- curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
# Make sure WP-CLI is executable
- chmod +x wp-cli.phar
# Download WordPress into `wordpress` directory
- ./wp-cli.phar core download --allow-root --path=wordpress
# Generate `wp-config.php` file
- echo "define(\"WP_DEBUG\", true);" | ./wp-cli.phar core config --allow-root --dbname=wordpress --dbuser=ubuntu --dbhost=127.0.0.1:3306 --path=wordpress --extra-php
# Install WordPress
- ./wp-cli.phar core install --allow-root --admin_name=admin --admin_password=admin --admin_email=admin@mailpoet.loc --url=http://mailpoet.loc:8080 --title=WordPress --path=wordpress
# Softlink MailPoet to plugin path
- ln -s ../../.. wordpress/wp-content/plugins/mailpoet
# Activate MailPoet
- ./wp-cli.phar plugin activate mailpoet --path=wordpress
# Create .env file with correct path to WP installation
- echo "WP_TEST_PATH=\"/home/ubuntu/mailpoet/wordpress\"" > .env
# Enable XDebug for coverage reports.
# Comment out if not running PHP coverage reports, for performance
#- sed -i 's/^;//' /opt/circleci/php/$(phpenv global)/etc/conf.d/xdebug.ini
## tests override
test:
override:
# Run JS tests
- mkdir $CIRCLE_TEST_REPORTS/mocha
- ./do t:j $CIRCLE_TEST_REPORTS/mocha/junit.xml
# Run PHP tests
- ./do t:u --xml
# Uncomment to run coverage tests instead
#- ./do t:c --xml
# Copy the report
- mkdir $CIRCLE_TEST_REPORTS/codeception
- cp tests/_output/report.xml $CIRCLE_TEST_REPORTS/codeception/report.xml
# Uncomment to copy PHP coverage report
#- cp tests/_output/coverage.xml $CIRCLE_TEST_REPORTS/codeception/coverage.xml

View File

@ -10,6 +10,7 @@ settings:
colors: true
memory_limit: 1024M
log: true
strict_xml: true
extensions:
enabled:
- Codeception\Extension\RunFailed

264
composer.lock generated
View File

@ -407,12 +407,12 @@
"source": {
"type": "git",
"url": "https://github.com/mailpoet/html2text.git",
"reference": "6e6c48d07a542f4b4ae24341cc6ab92335c32922"
"reference": "5ba872ab9a96c7b74fdaffbb42c78ee8dc12745a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailpoet/html2text/zipball/6e6c48d07a542f4b4ae24341cc6ab92335c32922",
"reference": "6e6c48d07a542f4b4ae24341cc6ab92335c32922",
"url": "https://api.github.com/repos/mailpoet/html2text/zipball/5ba872ab9a96c7b74fdaffbb42c78ee8dc12745a",
"reference": "5ba872ab9a96c7b74fdaffbb42c78ee8dc12745a",
"shasum": ""
},
"require": {
@ -452,7 +452,7 @@
"email": "support@jevon.org",
"source": "https://github.com/mailpoet/html2text/tree/master"
},
"time": "2016-06-13 18:24:35"
"time": "2016-07-28 01:09:53"
},
{
"name": "sunra/php-simple-html-dom-parser",
@ -499,23 +499,23 @@
},
{
"name": "swiftmailer/swiftmailer",
"version": "v5.4.2",
"version": "v5.4.3",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "d8db871a54619458a805229a057ea2af33c753e8"
"reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/d8db871a54619458a805229a057ea2af33c753e8",
"reference": "d8db871a54619458a805229a057ea2af33c753e8",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153",
"reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1,<0.9.4"
"mockery/mockery": "~0.9.1"
},
"type": "library",
"extra": {
@ -548,7 +548,7 @@
"mail",
"mailer"
],
"time": "2016-05-01 08:45:47"
"time": "2016-07-08 11:51:25"
},
{
"name": "symfony/polyfill-mbstring",
@ -611,16 +611,16 @@
},
{
"name": "symfony/translation",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1"
"reference": "00334ef0b9317e5d7c7641a2b56671a1df23b7a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1",
"reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1",
"url": "https://api.github.com/repos/symfony/translation/zipball/00334ef0b9317e5d7c7641a2b56671a1df23b7a0",
"reference": "00334ef0b9317e5d7c7641a2b56671a1df23b7a0",
"shasum": ""
},
"require": {
@ -671,7 +671,7 @@
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2016-06-06 11:11:27"
"time": "2016-06-29 05:29:29"
},
{
"name": "tburry/pquery",
@ -848,16 +848,16 @@
},
{
"name": "codeception/codeception",
"version": "2.2.2",
"version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
"reference": "8d80bb4ec7470e8df5de0e4c401785bc3fa1f4f6"
"reference": "34c268ae5872105c0c218296487650ab08e3991b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/8d80bb4ec7470e8df5de0e4c401785bc3fa1f4f6",
"reference": "8d80bb4ec7470e8df5de0e4c401785bc3fa1f4f6",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/34c268ae5872105c0c218296487650ab08e3991b",
"reference": "34c268ae5872105c0c218296487650ab08e3991b",
"shasum": ""
},
"require": {
@ -935,20 +935,20 @@
"functional testing",
"unit testing"
],
"time": "2016-06-29 00:59:28"
"time": "2016-07-24 19:31:22"
},
{
"name": "codeception/verify",
"version": "0.3.0",
"version": "0.3.1",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Verify.git",
"reference": "d3721cfc668d96b41acbda3ecd01d3499381db64"
"reference": "dc19c8722f3756341e5b0ce0590f09fda1d63719"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Verify/zipball/d3721cfc668d96b41acbda3ecd01d3499381db64",
"reference": "d3721cfc668d96b41acbda3ecd01d3499381db64",
"url": "https://api.github.com/repos/Codeception/Verify/zipball/dc19c8722f3756341e5b0ce0590f09fda1d63719",
"reference": "dc19c8722f3756341e5b0ce0590f09fda1d63719",
"shasum": ""
},
"require-dev": {
@ -968,7 +968,7 @@
}
],
"description": "BDD assertion library for PHPUnit",
"time": "2015-11-26 23:23:25"
"time": "2016-07-13 09:34:15"
},
{
"name": "codegyre/robo",
@ -1125,27 +1125,27 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "6.2.0",
"version": "6.2.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "d094e337976dff9d8e2424e8485872194e768662"
"reference": "3f808fba627f2c5b69e2501217bf31af349c1427"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662",
"reference": "d094e337976dff9d8e2424e8485872194e768662",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/3f808fba627f2c5b69e2501217bf31af349c1427",
"reference": "3f808fba627f2c5b69e2501217bf31af349c1427",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "~1.0",
"guzzlehttp/psr7": "~1.1",
"php": ">=5.5.0"
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.3.1",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "~4.0",
"psr/log": "~1.0"
"phpunit/phpunit": "^4.0",
"psr/log": "^1.0"
},
"type": "library",
"extra": {
@ -1183,7 +1183,7 @@
"rest",
"web service"
],
"time": "2016-03-21 20:02:09"
"time": "2016-07-15 17:22:37"
},
{
"name": "guzzlehttp/promises",
@ -1605,16 +1605,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "4.0.0",
"version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "900370c81280cc0d942ffbc5912d80464eaee7e9"
"reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/900370c81280cc0d942ffbc5912d80464eaee7e9",
"reference": "900370c81280cc0d942ffbc5912d80464eaee7e9",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5f3f7e736d6319d5f1fc402aff8b026da26709a3",
"reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3",
"shasum": ""
},
"require": {
@ -1623,7 +1623,7 @@
"phpunit/php-text-template": "~1.2",
"phpunit/php-token-stream": "^1.4.2",
"sebastian/code-unit-reverse-lookup": "~1.0",
"sebastian/environment": "^1.3.2",
"sebastian/environment": "^1.3.2 || ^2.0",
"sebastian/version": "~1.0|~2.0"
},
"require-dev": {
@ -1664,7 +1664,7 @@
"testing",
"xunit"
],
"time": "2016-06-03 05:03:56"
"time": "2016-07-26 14:39:29"
},
{
"name": "phpunit/php-file-iterator",
@ -1849,16 +1849,16 @@
},
{
"name": "phpunit/phpunit",
"version": "5.4.6",
"version": "5.4.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "2f1fc94b77ea6418bd6a06c64a1dac0645fbce59"
"reference": "3132365e1430c091f208e120b8845d39c25f20e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2f1fc94b77ea6418bd6a06c64a1dac0645fbce59",
"reference": "2f1fc94b77ea6418bd6a06c64a1dac0645fbce59",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3132365e1430c091f208e120b8845d39c25f20e6",
"reference": "3132365e1430c091f208e120b8845d39c25f20e6",
"shasum": ""
},
"require": {
@ -1870,7 +1870,7 @@
"myclabs/deep-copy": "~1.3",
"php": "^5.6 || ^7.0",
"phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "^4.0",
"phpunit/php-code-coverage": "^4.0.1",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "^1.0.6",
@ -1923,7 +1923,7 @@
"testing",
"xunit"
],
"time": "2016-06-16 06:01:15"
"time": "2016-07-26 14:48:00"
},
{
"name": "phpunit/phpunit-mock-objects",
@ -2599,16 +2599,16 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "2.6.1",
"version": "2.6.2",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d"
"reference": "4edb770cb853def6e60c93abb088ad5ac2010c83"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
"reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4edb770cb853def6e60c93abb088ad5ac2010c83",
"reference": "4edb770cb853def6e60c93abb088ad5ac2010c83",
"shasum": ""
},
"require": {
@ -2673,20 +2673,20 @@
"phpcs",
"standards"
],
"time": "2016-05-30 22:24:32"
"time": "2016-07-13 23:29:13"
},
{
"name": "symfony/browser-kit",
"version": "v3.1.1",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "b645a9b23d6c0eeba5ac823fa87bf010db9aff22"
"reference": "dcf41ed026b0499254385b5c88f03247b2ba010b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/b645a9b23d6c0eeba5ac823fa87bf010db9aff22",
"reference": "b645a9b23d6c0eeba5ac823fa87bf010db9aff22",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/dcf41ed026b0499254385b5c88f03247b2ba010b",
"reference": "dcf41ed026b0499254385b5c88f03247b2ba010b",
"shasum": ""
},
"require": {
@ -2730,20 +2730,20 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
"time": "2016-03-04 07:56:56"
"time": "2016-06-29 05:41:56"
},
{
"name": "symfony/config",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05"
"reference": "0926e69411eba491803dbafb9f1f233e2ced58d0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/a2edd59c2163c65747fc3f35d132b5a39266bd05",
"reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05",
"url": "https://api.github.com/repos/symfony/config/zipball/0926e69411eba491803dbafb9f1f233e2ced58d0",
"reference": "0926e69411eba491803dbafb9f1f233e2ced58d0",
"shasum": ""
},
"require": {
@ -2783,20 +2783,20 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2016-06-06 11:11:27"
"time": "2016-06-29 05:31:50"
},
{
"name": "symfony/console",
"version": "v3.1.1",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "64a4d43b045f07055bb197650159769604cb2a92"
"reference": "747154aa69b0f83cd02fc9aa554836dee417631a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/64a4d43b045f07055bb197650159769604cb2a92",
"reference": "64a4d43b045f07055bb197650159769604cb2a92",
"url": "https://api.github.com/repos/symfony/console/zipball/747154aa69b0f83cd02fc9aa554836dee417631a",
"reference": "747154aa69b0f83cd02fc9aa554836dee417631a",
"shasum": ""
},
"require": {
@ -2843,20 +2843,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2016-06-14 11:18:07"
"time": "2016-06-29 07:02:31"
},
{
"name": "symfony/css-selector",
"version": "v3.1.1",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "c526d7b3cb4fe1673c6a34e13be2ff63f519df99"
"reference": "2851e1932d77ce727776154d659b232d061e816a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/c526d7b3cb4fe1673c6a34e13be2ff63f519df99",
"reference": "c526d7b3cb4fe1673c6a34e13be2ff63f519df99",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/2851e1932d77ce727776154d659b232d061e816a",
"reference": "2851e1932d77ce727776154d659b232d061e816a",
"shasum": ""
},
"require": {
@ -2896,20 +2896,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
"time": "2016-06-06 11:42:41"
"time": "2016-06-29 05:41:56"
},
{
"name": "symfony/dom-crawler",
"version": "v3.1.1",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "12aa63fd41b060d2bee9a34623d29eda70bc8fe3"
"reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/12aa63fd41b060d2bee9a34623d29eda70bc8fe3",
"reference": "12aa63fd41b060d2bee9a34623d29eda70bc8fe3",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0",
"reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0",
"shasum": ""
},
"require": {
@ -2952,20 +2952,20 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
"time": "2016-05-13 15:49:09"
"time": "2016-06-29 05:41:56"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "2a6b8713f8bdb582058cfda463527f195b066110"
"reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110",
"reference": "2a6b8713f8bdb582058cfda463527f195b066110",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b180b70439dca70049b6b9b7e21d75e6e5d7aca9",
"reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9",
"shasum": ""
},
"require": {
@ -3012,20 +3012,20 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2016-06-06 11:11:27"
"time": "2016-06-29 05:29:29"
},
{
"name": "symfony/filesystem",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "dee379131dceed90a429e951546b33edfe7dccbb"
"reference": "7258ddd6f987053f21fa43d03430580ba54e6096"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb",
"reference": "dee379131dceed90a429e951546b33edfe7dccbb",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7258ddd6f987053f21fa43d03430580ba54e6096",
"reference": "7258ddd6f987053f21fa43d03430580ba54e6096",
"shasum": ""
},
"require": {
@ -3061,20 +3061,20 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2016-04-12 18:01:21"
"time": "2016-06-29 05:31:50"
},
{
"name": "symfony/finder",
"version": "v3.1.1",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "40d17ed287bf51a2f884c4619ce8ff2a1c5cd219"
"reference": "8201978de88a9fa0923e18601bb17f1df9c721e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/40d17ed287bf51a2f884c4619ce8ff2a1c5cd219",
"reference": "40d17ed287bf51a2f884c4619ce8ff2a1c5cd219",
"url": "https://api.github.com/repos/symfony/finder/zipball/8201978de88a9fa0923e18601bb17f1df9c721e7",
"reference": "8201978de88a9fa0923e18601bb17f1df9c721e7",
"shasum": ""
},
"require": {
@ -3110,20 +3110,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2016-05-13 18:06:41"
"time": "2016-06-29 05:41:56"
},
{
"name": "symfony/form",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/form.git",
"reference": "edfb109ac1ebb755ad0ce964f32e43ddbddae7bb"
"reference": "fd24c42112a3c434a083c498b9550331bb96eaa3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/form/zipball/edfb109ac1ebb755ad0ce964f32e43ddbddae7bb",
"reference": "edfb109ac1ebb755ad0ce964f32e43ddbddae7bb",
"url": "https://api.github.com/repos/symfony/form/zipball/fd24c42112a3c434a083c498b9550331bb96eaa3",
"reference": "fd24c42112a3c434a083c498b9550331bb96eaa3",
"shasum": ""
},
"require": {
@ -3184,20 +3184,20 @@
],
"description": "Symfony Form Component",
"homepage": "https://symfony.com",
"time": "2016-06-06 11:11:27"
"time": "2016-06-29 05:29:29"
},
{
"name": "symfony/intl",
"version": "v3.0.7",
"version": "v3.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/intl.git",
"reference": "96ce72abb3538c4256585ce278cf30ceb1e86f16"
"reference": "330c95b92989c1a515794bb87aabfe7492148f61"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/intl/zipball/96ce72abb3538c4256585ce278cf30ceb1e86f16",
"reference": "96ce72abb3538c4256585ce278cf30ceb1e86f16",
"url": "https://api.github.com/repos/symfony/intl/zipball/330c95b92989c1a515794bb87aabfe7492148f61",
"reference": "330c95b92989c1a515794bb87aabfe7492148f61",
"shasum": ""
},
"require": {
@ -3259,20 +3259,20 @@
"l10n",
"localization"
],
"time": "2016-05-13 18:03:36"
"time": "2016-06-29 05:40:45"
},
{
"name": "symfony/options-resolver",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "ddad0be20d6f2cb266cded8c349e046731df09b8"
"reference": "b6f982782a0624d37b5416c2c96fb99ce5ab74d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/ddad0be20d6f2cb266cded8c349e046731df09b8",
"reference": "ddad0be20d6f2cb266cded8c349e046731df09b8",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/b6f982782a0624d37b5416c2c96fb99ce5ab74d5",
"reference": "b6f982782a0624d37b5416c2c96fb99ce5ab74d5",
"shasum": ""
},
"require": {
@ -3313,7 +3313,7 @@
"configuration",
"options"
],
"time": "2016-05-24 10:00:02"
"time": "2016-06-29 05:29:29"
},
{
"name": "symfony/polyfill-intl-icu",
@ -3375,16 +3375,16 @@
},
{
"name": "symfony/process",
"version": "v3.1.1",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "6350e63ed9c232da50e00f00a7e0330f066387a2"
"reference": "5c11a1a4d4016662eeaf0f8757958c7de069f9a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/6350e63ed9c232da50e00f00a7e0330f066387a2",
"reference": "6350e63ed9c232da50e00f00a7e0330f066387a2",
"url": "https://api.github.com/repos/symfony/process/zipball/5c11a1a4d4016662eeaf0f8757958c7de069f9a0",
"reference": "5c11a1a4d4016662eeaf0f8757958c7de069f9a0",
"shasum": ""
},
"require": {
@ -3420,20 +3420,20 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2016-06-06 11:42:41"
"time": "2016-06-29 05:42:25"
},
{
"name": "symfony/property-access",
"version": "v3.0.7",
"version": "v3.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/property-access.git",
"reference": "6a958de831366005603432ef438c22cd93fad1ef"
"reference": "dedc1109b7c4f0454dffb00b7caa449a39a3c5dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/property-access/zipball/6a958de831366005603432ef438c22cd93fad1ef",
"reference": "6a958de831366005603432ef438c22cd93fad1ef",
"url": "https://api.github.com/repos/symfony/property-access/zipball/dedc1109b7c4f0454dffb00b7caa449a39a3c5dd",
"reference": "dedc1109b7c4f0454dffb00b7caa449a39a3c5dd",
"shasum": ""
},
"require": {
@ -3480,20 +3480,20 @@
"property path",
"reflection"
],
"time": "2016-05-29 09:50:11"
"time": "2016-06-29 05:40:00"
},
{
"name": "symfony/routing",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "4cbc81aa378869445fbd2d18c8c8b4a056c632a0"
"reference": "cdd298b1d45b9882de0905856e89171bf487c6d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/4cbc81aa378869445fbd2d18c8c8b4a056c632a0",
"reference": "4cbc81aa378869445fbd2d18c8c8b4a056c632a0",
"url": "https://api.github.com/repos/symfony/routing/zipball/cdd298b1d45b9882de0905856e89171bf487c6d5",
"reference": "cdd298b1d45b9882de0905856e89171bf487c6d5",
"shasum": ""
},
"require": {
@ -3555,20 +3555,20 @@
"uri",
"url"
],
"time": "2016-05-30 06:57:11"
"time": "2016-06-29 05:29:29"
},
{
"name": "symfony/twig-bridge",
"version": "v2.8.7",
"version": "v2.8.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bridge.git",
"reference": "360f3330e1df67edde1bb5d72fe5aa7c1bc74b9d"
"reference": "b2db0187b7b805bb349ffe2714fbc846124c71ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/360f3330e1df67edde1bb5d72fe5aa7c1bc74b9d",
"reference": "360f3330e1df67edde1bb5d72fe5aa7c1bc74b9d",
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/b2db0187b7b805bb349ffe2714fbc846124c71ba",
"reference": "b2db0187b7b805bb349ffe2714fbc846124c71ba",
"shasum": ""
},
"require": {
@ -3636,20 +3636,20 @@
],
"description": "Symfony Twig Bridge",
"homepage": "https://symfony.com",
"time": "2016-06-06 11:11:27"
"time": "2016-06-29 05:29:29"
},
{
"name": "symfony/yaml",
"version": "v3.1.1",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "c5a7e7fc273c758b92b85dcb9c46149ccda89623"
"reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/c5a7e7fc273c758b92b85dcb9c46149ccda89623",
"reference": "c5a7e7fc273c758b92b85dcb9c46149ccda89623",
"url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de",
"reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de",
"shasum": ""
},
"require": {
@ -3685,7 +3685,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2016-06-14 11:18:07"
"time": "2016-06-29 05:41:56"
},
{
"name": "twig/extensions",

Binary file not shown.

View File

@ -1,199 +0,0 @@
# Copyright (C) 2015
# This file is distributed under the same license as the package.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: http://support.mailpoet.com/\n"
"POT-Creation-Date: 2015-07-29 16:59:53+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2015-07-29 19:00+0100\n"
"Last-Translator: MailPoet i18n (https://www.transifex.com/organization/wysija)\n"
"Language-Team: MailPoet i18n <https://www.transifex.com/organization/wysija>\n"
"X-Generator: Poedit 1.7.4\n"
"X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-Basepath: ../\n"
"X-Textdomain-Support: yes\n"
"Language: en\n"
"X-Poedit-SearchPath-0: .\n"
#: lib/form/renderer.php:91
msgid "Year, month, day"
msgstr ""
#: lib/form/renderer.php:92
msgid "Year, month"
msgstr ""
#: lib/form/renderer.php:93
msgid "Month (January, February,...)"
msgstr ""
#: lib/form/renderer.php:94 lib/form/renderer.php:519
msgid "Year"
msgstr ""
#: lib/form/renderer.php:108
msgid "January"
msgstr ""
#: lib/form/renderer.php:109
msgid "February"
msgstr ""
#: lib/form/renderer.php:110
msgid "March"
msgstr ""
#: lib/form/renderer.php:111
msgid "April"
msgstr ""
#: lib/form/renderer.php:112
msgid "May"
msgstr ""
#: lib/form/renderer.php:113
msgid "June"
msgstr ""
#: lib/form/renderer.php:114
msgid "July"
msgstr ""
#: lib/form/renderer.php:115
msgid "August"
msgstr ""
#: lib/form/renderer.php:116
msgid "September"
msgstr ""
#: lib/form/renderer.php:117
msgid "October"
msgstr ""
#: lib/form/renderer.php:118
msgid "November"
msgstr ""
#: lib/form/renderer.php:119
msgid "December"
msgstr ""
#: lib/form/renderer.php:509
msgid "Day"
msgstr ""
#: lib/form/renderer.php:514
msgid "Month"
msgstr ""
#: lib/form/widget.php:11
msgid "MailPoet Subscription Form"
msgstr ""
#: lib/form/widget.php:13
msgid "Newsletter subscription form"
msgstr ""
#: lib/form/widget.php:36
msgid "Subscribe to our Newsletter"
msgstr ""
#: lib/form/widget.php:56
msgid "Title:"
msgstr ""
#: lib/form/widget.php:76
msgid "Create a new form"
msgstr ""
#: lib/form/widget.php:109
msgid "Newsletter"
msgstr ""
#: views/form/editor.html:4 views/form/editor.html:26
msgid "Save"
msgstr ""
#: views/form/editor.html:5
msgid "Translatable string with a link %shere%s"
msgstr ""
#: views/form/editor.html:6
msgid "deleted one message"
msgid_plural "deleted %d messages"
msgstr[0] ""
msgstr[1] ""
#: views/form/editor.html:34
msgid "Settings"
msgstr ""
#: views/form/editor.html:42
msgid "This form adds subscribers to these lists:"
msgstr ""
#: views/form/editor.html:44
msgid "Choose a list"
msgstr ""
#: views/form/editor.html:57
msgid "You have to select at least 1 list"
msgstr ""
#: views/form/editor.html:63
msgid "After submit..."
msgstr ""
#: views/form/editor.html:65
msgid "Show message"
msgstr ""
#: views/form/editor.html:69
msgid "Go to page"
msgstr ""
#: views/form/editor.html:76
msgid "Check your inbox now to confirm your subscription."
msgstr ""
#: views/form/editor.html:98
msgid "Shortcodes"
msgstr ""
#: views/form/editor.html:103
msgid "You can easily add this form to your theme's in the"
msgstr ""
#: views/form/editor.html:103
msgid "Widgets areas"
msgstr ""
#: views/form/editor.html:126
msgid "[link_html]HTML[/link_html]"
msgstr ""
#: views/form/editor.html:138
msgid "Fields"
msgstr ""
#: views/form/editor.html:144
msgid "Add New Field"
msgstr ""
#: views/form/editor.html:153
msgid "Styles"
msgstr ""
#: views/form/editor.html:157
msgid "Preview"
msgstr ""
#: views/index.html:4
msgid "monvier"
msgstr ""

Binary file not shown.

View File

@ -1,215 +0,0 @@
# Copyright (C) 2015
# This file is distributed under the same license as the package.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: http://support.mailpoet.com/\n"
"POT-Creation-Date: 2015-07-30 14:08:29+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2015-07-30 16:19+0100\n"
"Last-Translator: MailPoet i18n (https://www.transifex.com/organization/wysija)\n"
"Language-Team: MailPoet i18n <https://www.transifex.com/organization/wysija>\n"
"X-Generator: Poedit 1.7.4\n"
"X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-Basepath: ../\n"
"X-Textdomain-Support: yes\n"
"Language: fr\n"
"X-Poedit-SearchPath-0: .\n"
#: lib/config/initializer.php:259
msgid "New form"
msgstr ""
#: lib/config/initializer.php:264
msgid "Check your inbox or spam folder now to confirm your subscription."
msgstr ""
#: lib/config/initializer.php:270 lib/config/initializer.php:275
msgid "Email"
msgstr ""
#: lib/config/initializer.php:280
msgid "Submit"
msgstr ""
#: lib/config/initializer.php:285
msgid "Subscribe!"
msgstr ""
#: lib/form/renderer.php:91
msgid "Year, month, day"
msgstr ""
#: lib/form/renderer.php:92
msgid "Year, month"
msgstr ""
#: lib/form/renderer.php:93
msgid "Month (January, February,...)"
msgstr ""
#: lib/form/renderer.php:94 lib/form/renderer.php:519
msgid "Year"
msgstr ""
#: lib/form/renderer.php:108
msgid "January"
msgstr ""
#: lib/form/renderer.php:109
msgid "February"
msgstr ""
#: lib/form/renderer.php:110
msgid "March"
msgstr ""
#: lib/form/renderer.php:111
msgid "April"
msgstr ""
#: lib/form/renderer.php:112
msgid "May"
msgstr ""
#: lib/form/renderer.php:113
msgid "June"
msgstr ""
#: lib/form/renderer.php:114
msgid "July"
msgstr ""
#: lib/form/renderer.php:115
msgid "August"
msgstr ""
#: lib/form/renderer.php:116
msgid "September"
msgstr ""
#: lib/form/renderer.php:117
msgid "October"
msgstr ""
#: lib/form/renderer.php:118
msgid "November"
msgstr ""
#: lib/form/renderer.php:119
msgid "December"
msgstr ""
#: lib/form/renderer.php:509
msgid "Day"
msgstr ""
#: lib/form/renderer.php:514
msgid "Month"
msgstr ""
#: lib/form/widget.php:11
msgid "MailPoet Subscription Form"
msgstr ""
#: lib/form/widget.php:13
msgid "Newsletter subscription form"
msgstr ""
#: lib/form/widget.php:36
msgid "Subscribe to our Newsletter"
msgstr ""
#: lib/form/widget.php:56
msgid "Title:"
msgstr ""
#: lib/form/widget.php:76
msgid "Create a new form"
msgstr ""
#: lib/form/widget.php:109
msgid "Newsletter"
msgstr ""
#: views/form/editor.html:8
msgid "Edit name' "
msgstr ""
#: views/form/editor.html:23
msgid "Save"
msgstr "Sauvegarder"
#: views/form/editor.html:31
msgid "Settings"
msgstr "Réglages"
#: views/form/editor.html:39
msgid "This form adds subscribers to these lists:"
msgstr ""
#: views/form/editor.html:41
msgid "Choose a list"
msgstr ""
#: views/form/editor.html:46
msgid "You have to select at least 1 list"
msgstr ""
#: views/form/editor.html:52
msgid "After submit..."
msgstr "Après l'inscription"
#: views/form/editor.html:54
msgid "Show message"
msgstr "Afficher le message"
#: views/form/editor.html:58
msgid "Go to page"
msgstr "Aller à la page"
#: views/form/editor.html:65
msgid "Check your inbox now to confirm your subscription."
msgstr ""
#: views/form/editor.html:85
msgid "Shortcodes"
msgstr ""
#: views/form/editor.html:90
msgid "You can easily add this form to your theme's in the %sWidgets area%s"
msgstr ""
#: views/form/editor.html:96
msgid "%sHTML%s"
msgstr ""
#: views/form/editor.html:119
msgid "Fields"
msgstr ""
#: views/form/editor.html:125
msgid "Add New Field"
msgstr ""
#: views/form/editor.html:134
msgid "Styles"
msgstr ""
#: views/form/editor.html:138
msgid "Preview"
msgstr ""
#: views/index.html:5
msgid "Translatable string with a link %shere%s"
msgstr ""
#: views/index.html:6 views/index.html:7
msgid "deleted one message"
msgid_plural "deleted %d messages"
msgstr[0] ""
msgstr[1] ""

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +1,152 @@
<?php
namespace MailPoet\API;
use MailPoet\Util\Helpers;
use \MailPoet\Util\Security;
if(!defined('ABSPATH')) exit;
class API {
public $api_request;
public $endpoint;
public $action;
public $data;
const NAME = 'mailpoet_api';
const ENDPOINT_NAMESPACE = '\MailPoet\API\Endpoints\\';
const RESPONSE_ERROR = 404;
private $_endpoint;
private $_method;
private $_token;
function __construct($api_data = false) {
$api_data = ($api_data) ? $api_data : $_GET;
$this->api_request = isset($api_data[self::NAME]);
$this->endpoint = isset($api_data['endpoint']) ?
Helpers::underscoreToCamelCase($api_data['endpoint']) :
false;
$this->action = isset($api_data['action']) ?
Helpers::underscoreToCamelCase($api_data['action']) :
false;
$this->data = isset($api_data['data']) ?
self::decodeRequestData($api_data['data']) :
false;
}
private $_endpoint_class;
private $_data = array();
function init() {
$endpoint = self::ENDPOINT_NAMESPACE . ucfirst($this->endpoint);
if(!$this->api_request) return;
if(!$this->endpoint || !class_exists($endpoint)) {
self::terminateRequest(self::RESPONSE_ERROR, __('Invalid API endpoint.'));
}
$this->callEndpoint(
$endpoint,
$this->action,
$this->data
// Admin Security token
add_action(
'admin_head',
array($this, 'setToken')
);
// ajax (logged in users)
add_action(
'wp_ajax_mailpoet',
array($this, 'setupAjax')
);
// ajax (logged out users)
add_action(
'wp_ajax_nopriv_mailpoet',
array($this, 'setupAjax')
);
}
function callEndpoint($endpoint, $action, $data) {
if(!method_exists($endpoint, $action)) {
self::terminateRequest(self::RESPONSE_ERROR, __('Invalid API action.'));
}
call_user_func(
array(
$endpoint,
$action
),
$data
);
}
function setupAjax() {
$this->getRequestData();
static function decodeRequestData($data) {
$data = base64_decode($data);
if(is_serialized($data)) {
$data = unserialize($data);
if($this->checkToken() === false) {
$error_response = new ErrorResponse(
array(
Error::UNAUTHORIZED => __('Invalid request.', 'mailpoet')
),
array(),
Response::STATUS_UNAUTHORIZED
);
$error_response->send();
}
if(!is_array($data)) {
$data = array();
$this->processRoute();
}
function getRequestData() {
$this->_endpoint = isset($_POST['endpoint'])
? trim($_POST['endpoint'])
: null;
$this->_method = isset($_POST['method'])
? trim($_POST['method'])
: null;
$this->_token = isset($_POST['token'])
? trim($_POST['token'])
: null;
if(!$this->_endpoint || !$this->_method) {
// throw exception bad request
$error_response = new ErrorResponse(
array(
Error::BAD_REQUEST => __('Invalid request.', 'mailpoet')
),
array(),
Response::STATUS_BAD_REQUEST
);
$error_response->send();
} else {
$this->_endpoint_class = (
__NAMESPACE__."\\Endpoints\\".ucfirst($this->_endpoint)
);
$this->_data = isset($_POST['data'])
? stripslashes_deep($_POST['data'])
: array();
// remove reserved keywords from data
if(is_array($this->_data) && !empty($this->_data)) {
// filter out reserved keywords from data
$reserved_keywords = array(
'token',
'endpoint',
'method',
'mailpoet_redirect'
);
$this->_data = array_diff_key(
$this->_data,
array_flip($reserved_keywords)
);
}
}
return $data;
}
static function encodeRequestData($data) {
return rtrim(base64_encode(serialize($data)), '=');
function processRoute() {
try {
$endpoint = new $this->_endpoint_class();
// check the accessibility of the requested endpoint's action
// by default, an endpoint's action is considered "private"
$permissions = $endpoint->permissions;
if(
array_key_exists($this->_method, $permissions) === false
||
$permissions[$this->_method] !== Access::ALL
) {
if($this->checkPermissions() === false) {
$error_response = new ErrorResponse(
array(
Error::FORBIDDEN => __(
'You do not have the required permissions.',
'mailpoet'
)
),
array(),
Response::STATUS_FORBIDDEN
);
$error_response->send();
}
}
$response = $endpoint->{$this->_method}($this->_data);
$response->send();
} catch(\Exception $e) {
$error_response = new ErrorResponse(
array($e->getCode() => $e->getMessage())
);
$error_response->send();
}
}
static function buildRequest($endpoint, $action, $data) {
$data = self::encodeRequestData($data);
$params = array(
self::NAME => '',
'endpoint' => $endpoint,
'action' => $action,
'data' => $data
);
return add_query_arg($params, home_url());
function checkPermissions() {
return current_user_can('manage_options');
}
static function terminateRequest($code, $message) {
status_header($code, $message);
exit;
function checkToken() {
return wp_verify_nonce($this->_token, 'mailpoet_token');
}
function setToken() {
$global = '<script type="text/javascript">';
$global .= 'var mailpoet_token = "';
$global .= Security::generateToken();
$global .= '";';
$global .= '</script>';
echo $global;
}
}

12
lib/API/Access.php Normal file
View File

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

35
lib/API/Endpoint.php Normal file
View File

@ -0,0 +1,35 @@
<?php
namespace MailPoet\API;
if(!defined('ABSPATH')) exit;
abstract class Endpoint {
public $permissions = array();
function successResponse(
$data = array(), $meta = array(), $status = Response::STATUS_OK
) {
return new SuccessResponse($data, $meta, $status);
}
function errorResponse(
$errors = array(), $meta = array(), $status = Response::STATUS_NOT_FOUND
) {
if(empty($errors)) {
$errors = array(
Error::UNKNOWN => __('An unknown error occurred.', 'mailpoet')
);
}
return new ErrorResponse($errors, $meta, $status);
}
function badRequest($errors = array(), $meta = array()) {
if(empty($errors)) {
$errors = array(
Error::BAD_REQUEST => __('Invalid request parameters.', 'mailpoet')
);
}
return new ErrorResponse($errors, $meta, Response::STATUS_BAD_REQUEST);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace MailPoet\API\Endpoints;
use \MailPoet\API\Endpoint as APIEndpoint;
use \MailPoet\API\Error as APIError;
if(!defined('ABSPATH')) exit;
class AutomatedLatestContent extends APIEndpoint {
public $ALC;
function __construct() {
$this->ALC = new \MailPoet\Newsletter\AutomatedLatestContent();
}
function getPostTypes() {
return $this->successResponse(
get_post_types(array(), 'objects')
);
}
function getTaxonomies($data = array()) {
$post_type = (isset($data['postType'])) ? $data['postType'] : 'post';
return $this->successResponse(
get_object_taxonomies($post_type, 'objects')
);
}
function getTerms($data = array()) {
$taxonomies = (isset($data['taxonomies'])) ? $data['taxonomies'] : array();
$search = (isset($data['search'])) ? $data['search'] : '';
$limit = (isset($data['limit'])) ? (int)$data['limit'] : 10;
$page = (isset($data['page'])) ? (int)$data['page'] : 1;
return $this->successResponse(
get_terms(
$taxonomies,
array(
'hide_empty' => false,
'search' => $search,
'number' => $limit,
'offset' => $limit * ($page - 1)
)
)
);
}
function getPosts($data = array()) {
return $this->successResponse(
$this->ALC->getPosts($data)
);
}
function getTransformedPosts($data = array()) {
$posts = $this->ALC->getPosts($data);
return $this->successResponse(
$this->ALC->transformPosts($data, $posts)
);
}
function getBulkTransformedPosts($data = array()) {
$alc = new \MailPoet\Newsletter\AutomatedLatestContent();
$used_posts = array();
$rendered_posts = array();
foreach($data['blocks'] as $block) {
$posts = $alc->getPosts($block, $used_posts);
$rendered_posts[] = $alc->transformPosts($block, $posts);
foreach($posts as $post) {
$used_posts[] = $post->ID;
}
}
return $this->successResponse($rendered_posts);
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace MailPoet\API\Endpoints;
use \MailPoet\API\Endpoint as APIEndpoint;
use \MailPoet\API\Error as APIError;
use \MailPoet\Models\CustomField;
if(!defined('ABSPATH')) exit;
class CustomFields extends APIEndpoint {
function getAll() {
$collection = CustomField::orderByAsc('created_at')->findMany();
$custom_fields = array_map(function($custom_field) {
return $custom_field->asArray();
}, $collection);
return $this->successResponse($custom_fields);
}
function delete($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : null);
$custom_field = CustomField::findOne($id);
if($custom_field === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This custom field does not exist.', 'mailpoet')
));
} else {
$custom_field->delete();
return $this->successResponse($custom_field->asArray());
}
}
function save($data = array()) {
$custom_field = CustomField::createOrUpdate($data);
$errors = $custom_field->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
return $this->successResponse(
CustomField::findOne($custom_field->id)->asArray()
);
}
}
function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : null);
$custom_field = CustomField::findOne($id);
if($custom_field === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This custom field does not exist.', 'mailpoet')
));
} else {
return $this->successResponse($custom_field->asArray());
}
}
}

289
lib/API/Endpoints/Forms.php Normal file
View File

@ -0,0 +1,289 @@
<?php
namespace MailPoet\API\Endpoints;
use MailPoet\API\Endpoint as APIEndpoint;
use MailPoet\API\Error as APIError;
use \MailPoet\Models\Form;
use \MailPoet\Models\StatisticsForms;
use \MailPoet\Form\Renderer as FormRenderer;
use \MailPoet\Listing;
use \MailPoet\Form\Util;
if(!defined('ABSPATH')) exit;
class Forms extends APIEndpoint {
function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$form = Form::findOne($id);
if($form === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This form does not exist.', 'mailpoet')
));
} else {
return $this->successResponse($form->asArray());
}
}
function listing($data = array()) {
$listing = new Listing\Handler(
'\MailPoet\Models\Form',
$data
);
$listing_data = $listing->get();
$data = array();
foreach($listing_data['items'] as $form) {
$form = $form->asArray();
$form['signups'] = StatisticsForms::getTotalSignups($form['id']);
$form['segments'] = (
!empty($form['settings']['segments'])
? $form['settings']['segments']
: array()
);
$data[] = $form;
}
return $this->successResponse($data, array(
'count' => $listing_data['count'],
'filters' => $listing_data['filters'],
'groups' => $listing_data['groups']
));
}
function create() {
// create new form
$form_data = array(
'name' => __('New form', 'mailpoet'),
'body' => array(
array(
'id' => 'email',
'name' => __('Email', 'mailpoet'),
'type' => 'text',
'static' => true,
'params' => array(
'label' => __('Email', 'mailpoet'),
'required' => true
)
),
array(
'id' => 'submit',
'name' => __('Submit', 'mailpoet'),
'type' => 'submit',
'static' => true,
'params' => array(
'label' => __('Subscribe!', 'mailpoet')
)
)
),
'settings' => array(
'on_success' => 'message',
'success_message' => __('Check your inbox or spam folder to confirm your subscription.', 'mailpoet'),
'segments' => null,
'segments_selected_by' => 'admin'
)
);
return $this->save($form_data);
}
function save($data = array()) {
$form = Form::createOrUpdate($data);
$errors = $form->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
return $this->successResponse(
Form::findOne($form->id)->asArray()
);
}
}
function previewEditor($data = array()) {
// html
$html = FormRenderer::renderHTML($data);
// convert shortcodes
$html = do_shortcode($html);
// styles
$css = new Util\Styles(FormRenderer::getStyles($data));
return $this->successResponse(array(
'html' => $html,
'css' => $css->render()
));
}
function exportsEditor($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$form = Form::findOne($id);
if($form === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This form does not exist.', 'mailpoet')
));
} else {
$exports = Util\Export::getAll($form->asArray());
return $this->successResponse($exports);
}
}
function saveEditor($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$form_id = (isset($data['id']) ? (int)$data['id'] : 0);
$name = (isset($data['name']) ? $data['name'] : __('New form', 'mailpoet'));
$body = (isset($data['body']) ? $data['body'] : array());
$settings = (isset($data['settings']) ? $data['settings'] : array());
$styles = (isset($data['styles']) ? $data['styles'] : '');
// check if the form is used as a widget
$is_widget = false;
$widgets = get_option('widget_mailpoet_form');
if(!empty($widgets)) {
foreach($widgets as $widget) {
if(isset($widget['form']) && (int)$widget['form'] === $form_id) {
$is_widget = true;
break;
}
}
}
// check if the user gets to pick his own lists
// or if it's selected by the admin
$has_segment_selection = false;
foreach($body as $i => $block) {
if($block['type'] === 'segment') {
$has_segment_selection = true;
if(!empty($block['params']['values'])) {
$list_selection = array_filter(
array_map(function($segment) {
return (isset($segment['id'])
? $segment['id']
: null
);
}, $block['params']['values'])
);
}
break;
}
}
// check list selection
if($has_segment_selection === true) {
$settings['segments_selected_by'] = 'user';
$settings['segments'] = $list_selection;
} else {
$settings['segments_selected_by'] = 'admin';
}
$form = Form::createOrUpdate(array(
'id' => $form_id,
'name' => $name,
'body' => $body,
'settings' => $settings,
'styles' => $styles
));
$errors = $form->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
return $this->successResponse(
Form::findOne($form->id)->asArray(),
array('is_widget' => $is_widget)
);
}
}
function restore($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$form = Form::findOne($id);
if($form === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This form does not exist.', 'mailpoet')
));
} else {
$form->restore();
return $this->successResponse(
Form::findOne($form->id)->asArray(),
array('count' => 1)
);
}
}
function trash($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$form = Form::findOne($id);
if($form === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This form does not exist.', 'mailpoet')
));
} else {
$form->trash();
return $this->successResponse(
Form::findOne($form->id)->asArray(),
array('count' => 1)
);
}
}
function delete($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$form = Form::findOne($id);
if($form === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This form does not exist.', 'mailpoet')
));
} else {
$form->delete();
return $this->successResponse(null, array('count' => 1));
}
}
function duplicate($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$form = Form::findOne($id);
if($form === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This form does not exist.', 'mailpoet')
));
} else {
$data = array(
'name' => sprintf(__('Copy of %s', 'mailpoet'), $form->name)
);
$duplicate = $form->duplicate($data);
$errors = $duplicate->getErrors();
if(!empty($errors)) {
return $this->errorResponse($errors);
} else {
return $this->successResponse(
Form::findOne($duplicate->id)->asArray(),
array('count' => 1)
);
}
}
}
function bulkAction($data = array()) {
try {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Form',
$data
);
$meta = $bulk_action->apply();
return $this->successResponse(null, $meta);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace MailPoet\API\Endpoints;
use \MailPoet\API\Endpoint as APIEndpoint;
use \MailPoet\API\Error as APIError;
use MailPoet\Subscribers\ImportExport\Import\MailChimp;
use MailPoet\Models\CustomField;
use MailPoet\Models\Segment;
if(!defined('ABSPATH')) exit;
class ImportExport extends APIEndpoint {
function getMailChimpLists($data) {
try {
$mailChimp = new MailChimp($data['api_key']);
$lists = $mailChimp->getLists();
return $this->successResponse($lists);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
function getMailChimpSubscribers($data) {
try {
$mailChimp = new MailChimp($data['api_key']);
$subscribers = $mailChimp->getSubscribers($data['lists']);
return $this->successResponse($subscribers);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
function addSegment($data) {
$segment = Segment::createOrUpdate($data);
$errors = $segment->getErrors();
if(!empty($errors)) {
return $this->errorResponse($errors);
} else {
return $this->successResponse(
Segment::findOne($segment->id)->asArray()
);
}
}
function processImport($data) {
try {
$import = new \MailPoet\Subscribers\ImportExport\Import\Import(
json_decode($data, true)
);
$process = $import->process();
return $this->successResponse($process);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
function processExport($data) {
try {
$export = new \MailPoet\Subscribers\ImportExport\Export\Export(
json_decode($data, true)
);
$process = $export->process();
return $this->successResponse($process);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace MailPoet\API\Endpoints;
use MailPoet\API\Endpoint as APIEndpoint;
use MailPoet\API\Error as APIError;
if(!defined('ABSPATH')) exit;
class Mailer extends APIEndpoint {
function send($data = array()) {
try {
$mailer = new \MailPoet\Mailer\Mailer(
(isset($data['mailer'])) ? $data['mailer'] : false,
(isset($data['sender'])) ? $data['sender'] : false,
(isset($data['reply_to'])) ? $data['reply_to'] : false
);
$result = $mailer->send($data['newsletter'], $data['subscriber']);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
if($result === false) {
return $this->errorResponse(array(
APIError::BAD_REQUEST => __("The email could not be sent. Please check your settings.", 'mailpoet')
));
} else {
return $this->successResponse(null);
}
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace MailPoet\API\Endpoints;
use \MailPoet\API\Endpoint as APIEndpoint;
use \MailPoet\API\Error as APIError;
use MailPoet\Models\NewsletterTemplate;
if(!defined('ABSPATH')) exit;
class NewsletterTemplates extends APIEndpoint {
function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$template = NewsletterTemplate::findOne($id);
if($template === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This template does not exist.', 'mailpoet')
));
} else {
return $this->successResponse(
$template->asArray()
);
}
}
function getAll() {
$collection = NewsletterTemplate::findMany();
$templates = array_map(function($item) {
return $item->asArray();
}, $collection);
return $this->successResponse($templates);
}
function save($data = array()) {
$template = NewsletterTemplate::createOrUpdate($data);
$errors = $template->getErrors();
if(!empty($errors)) {
return $this->errorResponse($errors);
} else {
return $this->successResponse(
NewsletterTemplate::findOne($template->id)->asArray()
);
}
}
function delete($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$template = NewsletterTemplate::findOne($id);
if($template === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This template does not exist.', 'mailpoet')
));
} else {
$template->delete();
return $this->successResponse(null, array('count' => 1));
}
}
}

View File

@ -0,0 +1,422 @@
<?php
namespace MailPoet\API\Endpoints;
use MailPoet\API\Endpoint as APIEndpoint;
use MailPoet\API\Error as APIError;
use MailPoet\Listing;
use MailPoet\Models\Newsletter;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\Setting;
use MailPoet\Models\NewsletterTemplate;
use MailPoet\Models\NewsletterSegment;
use MailPoet\Models\NewsletterOptionField;
use MailPoet\Models\NewsletterOption;
use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Renderer\Renderer;
use MailPoet\Newsletter\Scheduler\Scheduler;
use MailPoet\Newsletter\Url as NewsletterUrl;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit;
require_once(ABSPATH . 'wp-includes/pluggable.php');
class Newsletters extends APIEndpoint {
function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
} else {
return $this->successResponse(
$newsletter
->withSegments()
->withOptions()
->asArray()
);
}
}
function save($data = array()) {
$segments = array();
if(isset($data['segments'])) {
$segments = $data['segments'];
unset($data['segments']);
}
$options = array();
if(isset($data['options'])) {
$options = $data['options'];
unset($data['options']);
}
$newsletter = Newsletter::createOrUpdate($data);
$errors = $newsletter->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
if(!empty($segments)) {
NewsletterSegment::where('newsletter_id', $newsletter->id)
->deleteMany();
foreach($segments as $segment) {
if(!is_array($segment)) continue;
$relation = NewsletterSegment::create();
$relation->segment_id = (int)$segment['id'];
$relation->newsletter_id = $newsletter->id;
$relation->save();
}
}
if(!empty($options)) {
NewsletterOption::where('newsletter_id', $newsletter->id)
->deleteMany();
$option_fields = NewsletterOptionField::where(
'newsletter_type',
$data['type']
)->findArray();
foreach($option_fields as $option_field) {
if(isset($options[$option_field['name']])) {
$relation = NewsletterOption::create();
$relation->newsletter_id = $newsletter->id;
$relation->option_field_id = $option_field['id'];
$relation->value = $options[$option_field['name']];
$relation->save();
}
}
}
$newsletter = Newsletter::filter('filterWithOptions')->findOne($newsletter->id);
// if this is a post notification, process options and update its schedule
if($newsletter->type === Newsletter::TYPE_NOTIFICATION) {
Scheduler::processPostNotificationSchedule($newsletter);
}
return $this->successResponse($newsletter->asArray());
}
}
function setStatus($data = array()) {
$status = (isset($data['status']) ? $data['status'] : null);
if(!$status) {
return $this->badRequest(array(
APIError::BAD_REQUEST => __('You need to specify a status.', 'mailpoet')
));
}
$id = (isset($data['id'])) ? (int)$data['id'] : false;
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
}
$newsletter->setStatus($status);
$errors = $newsletter->getErrors();
if(!empty($errors)) {
return $this->errorResponse($errors);
} else {
return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray()
);
}
}
function restore($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
} else {
$newsletter->restore();
return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray(),
array('count' => 1)
);
}
}
function trash($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
} else {
$newsletter->trash();
return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray(),
array('count' => 1)
);
}
}
function delete($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
} else {
$newsletter->delete();
return $this->successResponse(null, array('count' => 1));
}
}
function duplicate($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
} else {
$data = array(
'subject' => sprintf(__('Copy of %s', 'mailpoet'), $newsletter->subject)
);
$duplicate = $newsletter->duplicate($data);
$errors = $duplicate->getErrors();
if(!empty($errors)) {
return $this->errorResponse($errors);
} else {
return $this->successResponse(
Newsletter::findOne($duplicate->id)->asArray(),
array('count' => 1)
);
}
}
}
function showPreview($data = array()) {
if(empty($data['body'])) {
return $this->badRequest(array(
APIError::BAD_REQUEST => __('Newsletter data is missing.', 'mailpoet')
));
}
$id = (isset($data['id'])) ? (int)$data['id'] : false;
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
} else {
$newsletter->body = $data['body'];
$newsletter->save();
$subscriber = Subscriber::getCurrentWPUser();
$preview_url = NewsletterUrl::getViewInBrowserUrl(
$data, $subscriber, $queue = false, $preview = true
);
return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray(),
array('preview_url' => $preview_url)
);
}
}
function sendPreview($data = array()) {
if(empty($data['subscriber'])) {
return $this->badRequest(array(
APIError::BAD_REQUEST => __('Please specify receiver information.', 'mailpoet')
));
}
$id = (isset($data['id'])) ? (int)$data['id'] : false;
$newsletter = Newsletter::findOne($id);
if($newsletter === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet')
));
} else {
$newsletter = $newsletter->asArray();
$renderer = new Renderer($newsletter, $preview = true);
$rendered_newsletter = $renderer->render();
$divider = '***MailPoet***';
$data_for_shortcodes = array_merge(
array($newsletter['subject']),
$rendered_newsletter
);
$body = implode($divider, $data_for_shortcodes);
$subscriber = Subscriber::getCurrentWPUser();
$subscriber = ($subscriber) ? $subscriber->asArray() : false;
$shortcodes = new \MailPoet\Newsletter\Shortcodes\Shortcodes(
$newsletter,
$subscriber
);
list(
$newsletter['subject'],
$newsletter['body']['html'],
$newsletter['body']['text']
) = explode($divider, $shortcodes->replace($body));
try {
$mailer = new \MailPoet\Mailer\Mailer(
$mailer = false,
$sender = false,
$reply_to = false
);
$mailer->send($newsletter, $data['subscriber']);
return $this->successResponse(
Newsletter::findOne($id)->asArray()
);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
}
function listing($data = array()) {
$listing = new Listing\Handler(
'\MailPoet\Models\Newsletter',
$data
);
$listing_data = $listing->get();
$data = array();
foreach($listing_data['items'] as $newsletter) {
$queue = false;
if($newsletter->type === Newsletter::TYPE_STANDARD) {
$newsletter
->withSegments()
->withSendingQueue()
->withStatistics();
} else if($newsletter->type === Newsletter::TYPE_WELCOME) {
$newsletter
->withOptions()
->withTotalSent()
->withStatistics();
} else if($newsletter->type === Newsletter::TYPE_NOTIFICATION) {
$newsletter
->withOptions()
->withSegments()
->withChildrenCount();
} else if($newsletter->type === Newsletter::TYPE_NOTIFICATION_HISTORY) {
$newsletter
->withSegments()
->withSendingQueue()
->withStatistics();
}
if($newsletter->status === Newsletter::STATUS_SENT ||
$newsletter->status === Newsletter::STATUS_SENDING
) {
$queue = $newsletter->getQueue();
}
// get preview url
$subscriber = Subscriber::getCurrentWPUser();
$newsletter->preview_url = NewsletterUrl::getViewInBrowserUrl(
$newsletter, $subscriber, $queue, $preview = true);
$data[] = $newsletter->asArray();
}
return $this->successResponse($data, array(
'count' => $listing_data['count'],
'filters' => $listing_data['filters'],
'groups' => $listing_data['groups']
));
}
function bulkAction($data = array()) {
try {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Newsletter',
$data
);
$meta = $bulk_action->apply();
return $this->successResponse(null, $meta);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
function create($data = array()) {
$options = array();
if(isset($data['options'])) {
$options = $data['options'];
unset($data['options']);
}
$newsletter = Newsletter::createOrUpdate($data);
$errors = $newsletter->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
// try to load template data
$template_id = (isset($data['template']) ? (int)$data['template'] : false);
$template = NewsletterTemplate::findOne($template_id);
if($template === false) {
$newsletter->body = array();
} else {
$newsletter->body = $template->body;
}
}
$newsletter->save();
$errors = $newsletter->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
if(!empty($options)) {
$option_fields = NewsletterOptionField::where(
'newsletter_type', $newsletter->type
)->findArray();
foreach($option_fields as $option_field) {
if(isset($options[$option_field['name']])) {
$relation = NewsletterOption::create();
$relation->newsletter_id = $newsletter->id;
$relation->option_field_id = $option_field['id'];
$relation->value = $options[$option_field['name']];
$relation->save();
}
}
}
if(
empty($data['id'])
&&
isset($data['type'])
&&
$data['type'] === Newsletter::TYPE_NOTIFICATION
) {
$newsletter = Newsletter::filter('filterWithOptions')->findOne($newsletter->id);
Scheduler::processPostNotificationSchedule($newsletter);
}
return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray()
);
}
}
}

View File

@ -1,16 +0,0 @@
<?php
namespace MailPoet\API\Endpoints;
use MailPoet\Cron\Daemon;
if(!defined('ABSPATH')) exit;
class Queue {
const ENDPOINT = 'queue';
const ACTION_RUN = 'run';
static function run($data) {
$queue = new Daemon($data);
$queue->run();
}
}

View File

@ -0,0 +1,163 @@
<?php
namespace MailPoet\API\Endpoints;
use \MailPoet\API\Endpoint as APIEndpoint;
use \MailPoet\API\Error as APIError;
use \MailPoet\Models\Segment;
use \MailPoet\Models\SubscriberSegment;
use \MailPoet\Models\SegmentFilter;
use \MailPoet\Listing;
use \MailPoet\Segments\WP;
if(!defined('ABSPATH')) exit;
class Segments extends APIEndpoint {
function get($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$segment = Segment::findOne($id);
if($segment === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet')
));
} else {
return $this->successResponse($segment->asArray());
}
}
function listing($data = array()) {
$listing = new Listing\Handler(
'\MailPoet\Models\Segment',
$data
);
$listing_data = $listing->get();
$data = array();
foreach($listing_data['items'] as $segment) {
$segment->subscribers_url = admin_url(
'admin.php?page=mailpoet-subscribers#/filter[segment='.$segment->id.']'
);
$data[] = $segment
->withSubscribersCount()
->asArray();
}
return $this->successResponse($data, array(
'count' => $listing_data['count'],
'filters' => $listing_data['filters'],
'groups' => $listing_data['groups']
));
}
function save($data = array()) {
$segment = Segment::createOrUpdate($data);
$errors = $segment->getErrors();
if(!empty($errors)) {
return $this->badRequest($errors);
} else {
return $this->successResponse(
Segment::findOne($segment->id)->asArray()
);
}
}
function restore($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$segment = Segment::findOne($id);
if($segment === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet')
));
} else {
$segment->restore();
return $this->successResponse(
Segment::findOne($segment->id)->asArray(),
array('count' => 1)
);
}
}
function trash($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$segment = Segment::findOne($id);
if($segment === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet')
));
} else {
$segment->trash();
return $this->successResponse(
Segment::findOne($segment->id)->asArray(),
array('count' => 1)
);
}
}
function delete($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$segment = Segment::findOne($id);
if($segment === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet')
));
} else {
$segment->delete();
return $this->successResponse(null, array('count' => 1));
}
}
function duplicate($data = array()) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$segment = Segment::findOne($id);
if($segment === false) {
return $this->errorResponse(array(
APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet')
));
} else {
$data = array(
'name' => sprintf(__('Copy of %s', 'mailpoet'), $segment->name)
);
$duplicate = $segment->duplicate($data);
$errors = $duplicate->getErrors();
if(!empty($errors)) {
return $this->errorResponse($errors);
} else {
return $this->successResponse(
Segment::findOne($duplicate->id)->asArray(),
array('count' => 1)
);
}
}
}
function synchronize() {
try {
WP::synchronizeUsers();
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
return $this->successResponse(null);
}
function bulkAction($data = array()) {
try {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Segment',
$data
);
$meta = $bulk_action->apply();
return $this->successResponse(null, $meta);
} catch(\Exception $e) {
return $this->errorResponse(array(
$e->getCode() => $e->getMessage()
));
}
}
}

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