Compare commits

..

1466 Commits

Author SHA1 Message Date
081f362799 Release 3.8.5 2018-08-14 17:12:59 +03:00
23c54824a6 Merge pull request #1465 from mailpoet/survey-catch
Catch error when rendering deactivation survey [MAILPOET-1491]
2018-08-14 16:19:13 +03:00
1a9e6b8dcb Try to fix failing test
[MAILPOET-1491]
2018-08-14 14:46:38 +02:00
33aa7180f3 Catch error when rendering survey
[MAILPOET-1491]
2018-08-14 13:46:48 +02:00
1516153846 Merge pull request #1464 from mailpoet/validation-error
Fix rendering an error in wrong place [MAILPOET-1463]
2018-08-14 12:19:04 +03:00
e73b12d6f0 Let parsley to render error where it needs to
[MAILPOET-1463]
2018-08-13 16:49:29 +02:00
084be79210 Merge pull request #1461 from mailpoet/fix-js-vuln
Update js dependency [MAILPOET-1470]
2018-08-13 15:58:25 +03:00
e2b40fee37 Add welcome wizard application
[MAILPOET-1439]
2018-08-13 10:34:34 +02:00
d8167692ee Add strings for welcome wizard
[MAILPOET-1439]
2018-08-13 10:34:34 +02:00
43d536e5c3 Add image assets for new wizard
[MAILPOET-1439]
2018-08-13 10:34:34 +02:00
7d47e97b51 Add a common component for stepped progress bar
[MAILPOET-1439]
2018-08-13 10:34:34 +02:00
e55df2ca2d Add filter for skipping welcome wizard
This was requested for the purposes of the demo page

[MAILPOET-1439]
2018-08-13 10:34:34 +02:00
406c8bb6bd Render welcome wizard page for a new installation
[MAILPOET-1439]
2018-08-13 10:34:34 +02:00
a8c7615013 Remove welcome page
The welcome page will be replaced by a new welcome wizard

[MAILPOET-1439]
2018-08-13 10:34:34 +02:00
9369e7883c Add acceptance test for post notification duplication [MQ-41] 2018-08-13 10:08:41 +02:00
51c89d5aa1 Requires PHP 5.5 or newer. 2018-08-09 14:12:58 +02:00
659f748dc9 Add cache headers to cron endpoints
[MAILPOET-1464]
2018-08-09 14:08:04 +02:00
2038643c2b Update js dependency
To fix vulnerability

[MAILPOET-1470]
2018-08-08 15:41:08 +02:00
c7aeca116f Add queue_id index into newsletter_links table
Missing index caused that it took to long when generating tracked unsubscribe URL.

[MAILPOET-1486]
2018-08-08 09:15:06 +02:00
5748dfe759 Merge pull request #1459 from mailpoet/wait-for-mysql
Wait for mysql [MAILPOET-1443]
2018-08-07 14:43:08 +01:00
cc294dd362 Releasing 3.8.4 2018-08-07 14:01:22 +02:00
4c79a400c5 Wait for mysql
[MAILPOET-1443]
2018-08-07 11:51:06 +02:00
348c740a35 Merge pull request #1458 from mailpoet/acceptance-tests-fix
Use ui to update settings
2018-08-07 10:09:21 +01:00
b6a367f770 Use ui to update settings 2018-08-07 10:21:35 +02:00
913dcb30c5 Merge pull request #1443 from mailpoet/duplicate-editor-save-button
Duplicate editor save button [MAILPOET-1448]
2018-08-06 09:24:44 -04:00
e9c79a1952 Merge pull request #1444 from mailpoet/tasks-status
Add latest sending tasks to help's page system status [MAILPOET-1460]
2018-08-06 08:45:47 -04:00
5d8522c83a Merge pull request #1451 from mailpoet/save-standard-as-template
Save standard newsletter as template [MQ-36]
2018-08-02 10:18:28 -04:00
e413f83dfa Save standard newsletter as template [MQ-36] 2018-08-02 09:34:40 -04:00
f202e9d21e Merge pull request #1445 from mailpoet/send_tab_revert_activation_logic
Removes automatic MSS activation [MAILPOET-1478]
2018-08-02 08:03:50 -04:00
e00c322040 Add rendering of latest sending tasks to help page
[MAILPOET-1460]
2018-08-02 09:46:00 +02:00
7186f4b13a Add fetching of latest sending tasks for help page
[MAILPOET-1460]
2018-08-02 08:06:06 +02:00
b1feb0c21a Save standard newsletter as template [MQ-36] 2018-08-01 14:12:23 -04:00
f7469b4307 Merge pull request #1450 from mailpoet/duplicate-newsletter-test
Duplicate Newsletter Acceptance [MQ-39]
2018-08-01 12:16:33 -04:00
a71e6cb7d9 Duplicate Newsletter Acceptance [MQ-39] 2018-08-01 11:49:30 -04:00
734e5577e3 Releasing 3.8.3 2018-08-01 14:39:16 +01:00
8cdb71ed91 Merge pull request #1447 from mailpoet/cron-override-fix
Fix overriding cron token [MAILPOET-1481]
2018-08-01 08:21:36 -04:00
cb45bf8d51 Merge pull request #1448 from mailpoet/delete-newsletter-test
Initial commit of acceptance test for newsletter deletion
2018-08-01 07:50:52 -04:00
a242c06990 Initial commit of acceptance test for newsletter deletion 2018-08-01 06:38:04 -04:00
cccf40e65f Use notice close button from WP
Notice close button looked different than the WP-native one. This reuses the WP button.

[MAILPOET-1448]
2018-07-31 21:11:20 +02:00
c5ee742b01 Display close button also for auto-disposable notices if hideClose === false
The notice component was ignoring "hideClose" setting when "static" was set to false
(= auto disposable notice after timeout). This commit makes the behavior more transparent
by always respecting each of the settings. Note that jQuery's "delay()" can't be used now
since it blocks also other close events with the timout (events from close button).

[MAILPOET-1448]
2018-07-31 21:11:20 +02:00
364facabd5 Display after-save notice always on top (& scroll there)
The save component was displaying notice just below the save buttons. This seems
inconsistent with WP behaviour for the save button in the bottom. This makes the
notices always display on top & scroll there if necessary.

[MAILPOET-1448]
2018-07-31 21:11:19 +02:00
5204bbc4af Fix notice right margin & make it compatible with editor
Notices didn't have correct margins due to overrides of some WP styles.
This makes them look the same as default WP notices.

[MAILPOET-1448]
2018-07-31 21:11:19 +02:00
4a84974ceb Make save-as-template & export-as-template toggable identically to options
There was no option how to close save-as-template and export-as-template windows.
This makes them closable in the same way as dropdown options are.

[MAILPOET-1448]
2018-07-31 21:11:19 +02:00
af0d18a734 Make save dropdown menu opening up in the bottom
This introduces setDropdownDirectionDown() and setDropdownDirectionUp() methods
on the save component to switch between dropdown/dropup functionality. Default
is dropdown, in the bottom of the page dropup is used.

[MAILPOET-1448]
2018-07-31 21:11:16 +02:00
e6269308d0 Make more space for beacon & save buttons in the bottom
[MAILPOET-1448]
2018-07-31 21:10:31 +02:00
8abf14b0c3 Put autosaved info below save button
[MAILPOET-1448]
2018-07-31 21:10:21 +02:00
3821a9719a Make save button dropdowns right-aligned & positioned absolutely
[MAILPOET-1448]
2018-07-31 21:09:50 +02:00
c1edee7f14 Duplicate save buttons on the top
[MAILPOET-1448]
2018-07-31 21:09:27 +02:00
80b370eed5 Move save buttons to the right
[MAILPOET-1448]
2018-07-31 21:09:27 +02:00
01aac4d602 Move editor breadcrumbs to top-left
[MAILPOET-1448]
2018-07-31 21:09:27 +02:00
a3b79a6907 Fix overriding cron token 2018-07-31 17:48:26 +02:00
38d078df5e Release 3.8.2 2018-07-31 12:47:29 +01:00
97c5c25628 Removes automatic MSS activation. 2018-07-30 22:10:38 -04:00
adbce928f8 Merge pull request #1441 from mailpoet/queue-status
Sending queue status on help page [MAILPOET-1459]
2018-07-27 10:04:12 -04:00
92d0dfc0e1 Merge pull request #1440 from mailpoet/post-notification-template
Acceptance test create post notification template [MQ-38]
2018-07-26 07:39:25 -04:00
d7f12b5973 Add context for translators on help page
[MAILPOET-1459]
2018-07-26 13:08:35 +02:00
490ea67d18 Refactor help page status tables into component
[MAILPOET-1459]
2018-07-26 13:08:35 +02:00
1252f35a23 Add sending queue status to help page
[MAILPOET-1459]
2018-07-26 13:08:15 +02:00
0d6e2a107a Merge pull request #1436 from mailpoet/cron-status-info
Cron status info in help section [MAILPOET-1457]
2018-07-25 10:17:22 -04:00
a8bfadf157 Swap tabs in help section
We decided to make the Knowledge Base tab the default one since it contains the information
which are easiest to understand for an user.

[MAILPOET-1457]
2018-07-25 13:40:08 +02:00
5f6fe1a7e5 Add cron status to admin help section
[MAILPOET-1457]
2018-07-25 13:39:55 +02:00
3184b43b3b Add status flag for cron deactivation
Cron daemon, which was triggered by WordPress method, was deactivated
by deletion from DB and it caused the lost of all log data about it.
This commit changes the implementation so that the daemon is deactivated by changing status flag.

[MAILPOET-1457]
2018-07-25 13:23:21 +02:00
a9c081ea5e Merge pull request #1437 from mailpoet/form-duplicate-at
Add form duplicate acceptance test [MQ-52]
2018-07-25 07:08:28 -04:00
65e0361cd0 Add test for creating template from post notification
[MQ-38]
2018-07-25 12:43:12 +02:00
9ed409194c Add helper for opening editor in acceptance test
[MQ-38]
2018-07-25 10:36:37 +02:00
165bf9c485 Add option keep-deps to acceptance test
The dependencies will be installed only once and it saves time for development.

[MQ-38]
2018-07-25 10:36:22 +02:00
76591a6552 Fix readme.txt syntax for 3.8.1 2018-07-24 15:56:36 +03:00
fb4c2f7082 Release 3.8.1 2018-07-24 15:13:44 +03:00
abd92dc287 Merge pull request #1439 from mailpoet/send_tab_adjustment
Activates MSS when key is verified/displays basics tab in settings by default [MAILPOET-1466]
2018-07-24 06:28:53 -04:00
976317163a Activates MSS by default only when key is verified. 2018-07-23 21:23:10 -04:00
032fd6575d Shows "basics" tab in settings by default. 2018-07-23 21:01:25 -04:00
65e49808c0 Merge pull request #1430 from mailpoet/improve-errors
Improve error reporting for MSS sending [MAILPOET-1445]
2018-07-23 11:16:53 -04:00
f991a78722 Save session between acceptance test runs
[MQ-52]
2018-07-23 16:09:22 +01:00
aff2a1feec Merge pull request #1423 from mailpoet/tls-support
updating the swiftmailer dependency [MAILPOET-1453]
2018-07-23 10:35:33 -04:00
82f176dc43 Add form duplicate acceptance test
[MQ-52]
2018-07-23 15:34:23 +01:00
d165732f66 Merge pull request #1431 from mailpoet/background-images
Column Background Images [MAILPOET-1403]
2018-07-23 09:33:08 -04:00
eac68e4032 Merge pull request #1435 from mailpoet/new-form-fix
Fix create new form link in WP widgets settings [MAILPOET-1452]
2018-07-23 07:44:22 -04:00
d165c44537 Merge pull request #1377 from mailpoet/best_mixpanel_integration
Better mixpanel integration [MAILPOET-1411]
2018-07-23 07:17:09 -04:00
27b9857e6a Improve error reporting for MSS sending
[MAILPOET-1445]
2018-07-19 16:21:23 +01:00
45b22f62d7 Fix create new form link in WP widgets settings [MAILPOET-1452] 2018-07-19 16:52:42 +02:00
c3e2b17aa1 Add background images support to renderer [MAILPOET-1403] 2018-07-19 14:13:06 +02:00
d8581f761f Add container background image support to editor [MAILPOET-1403] 2018-07-19 14:12:56 +02:00
a79db03cf7 Merge pull request #1434 from mailpoet/new_repo_pitch
improve plugin readme [MAILPOET-1467]
2018-07-19 06:35:18 -04:00
b0158ad5a6 Merge branch 'best_mixpanel_integration' of https://github.com/mailpoet/mailpoet into best_mixpanel_integration 2018-07-19 10:14:13 +01:00
80898a1bde remove console.log and sent user data even if no public_id is set 2018-07-19 10:13:48 +01:00
2e6a2233f2 don't identify mixpanel users if public_id is null 2018-07-19 10:13:48 +01:00
3a2ee709eb fix failing bridge tests 2018-07-19 10:13:48 +01:00
7b4e63c8c5 force user data to be resent on public_id change 2018-07-19 10:13:48 +01:00
43a0d92d2f fix tests 2018-07-19 10:13:48 +01:00
78e5c1866e fix errors 2018-07-19 10:13:48 +01:00
1d2fa78a4d split public id tests in two 2018-07-19 10:13:48 +01:00
506c78d068 fix errors 2018-07-19 10:13:48 +01:00
0d461c2e30 add tests 2018-07-19 10:13:48 +01:00
2851fa3a4a add comment to isPublicIdNew function 2018-07-19 10:13:48 +01:00
1e933df60b rm commented tests 2018-07-19 10:13:48 +01:00
f261d9881e rm non implemented tests 2018-07-19 10:13:48 +01:00
e5d30d1ad0 production mixpanel key 2018-07-19 10:13:48 +01:00
76686e08fe analytics : use a unique public id 2018-07-19 10:13:48 +01:00
e8b0e77d0e use mixpanel.people.set 2018-07-19 10:13:48 +01:00
2dc0557973 Merge branch 'master' of https://github.com/mailpoet/mailpoet into best_mixpanel_integration 2018-07-19 10:01:30 +01:00
b48c9bb84a fine tune readme text 2018-07-18 17:53:37 +01:00
f7f8b6e17d add tags 2018-07-18 16:54:07 +01:00
8088f95575 improve plugin readme 2018-07-18 16:17:07 +01:00
43813758eb Merge pull request #1433 from mailpoet/test-post-notificaions-edit
Edit Existing Post Notification Email Acceptance Test [MQ-29]
2018-07-18 09:59:16 -04:00
c868c39696 Add acceptance test for post notification edit [MQ-29] 2018-07-18 15:43:34 +02:00
33149d041c Add more robust check for send form presence to acceptance tests [MQ-29]
There is a short delay between rendering of a heading and the form fields.
It is safer to wait for form itself before manipulating it.
2018-07-18 15:41:02 +02:00
9b19858734 Merge pull request #1432 from mailpoet/forms-delete-at
Forms delete acceptance test [MQ-50]
2018-07-18 08:26:37 -04:00
d7bba0c678 Does not display "activate" button when MSS key is invalid 2018-07-17 15:43:34 -04:00
1f8e8424e8 Updates changelog and bumps up release version 2018-07-17 14:37:45 -04:00
9dc0e61603 remove console.log and sent user data even if no public_id is set 2018-07-17 17:18:16 +01:00
5818db1a23 don't identify mixpanel users if public_id is null 2018-07-17 16:04:38 +01:00
f314d5d706 Test fixing tests
[MQ-50]
2018-07-17 14:10:06 +01:00
427e826ee5 Revert "Fix data creation for first test run"
This reverts commit 4296cd5a3e.
2018-07-17 13:42:47 +01:00
d0f797f88c Revert "Remove factory, because it doesn't work"
This reverts commit d8b9b8e649.
2018-07-17 13:42:34 +01:00
42f91f5069 fix failing bridge tests 2018-07-17 13:03:50 +01:00
3318dd3ace Merge pull request #1395 from mailpoet/hackday-todo
Deleted TODOs after noting required actions [MAILPOET-1433]
2018-07-16 14:35:38 -04:00
c368b664a1 force user data to be resent on public_id change 2018-07-16 16:58:42 +01:00
d8b9b8e649 Remove factory, because it doesn't work
[MQ-50]
2018-07-16 16:25:16 +01:00
2d30a0884b Refactor media manager from image block to a behavior [MAILPOET-1403]
This will make the media manager reusable in other blocks like e.g. container.
2018-07-16 17:02:24 +02:00
8ee72bd8ed Add support for --debug flag for unit tests 2018-07-16 16:57:47 +02:00
5c66025633 Merge pull request #1418 from mailpoet/cron-ping-warning
Automatically test if cron can be pinged and display a notice [MAILPOET-801]
2018-07-16 10:36:34 -04:00
d87acdd783 Merge pull request #1419 from mailpoet/send_tab_update
Redesigns the "Send With..." tab [MAILPOET-1441]
2018-07-16 10:11:01 -04:00
97cb9dd912 Merge pull request #1427 from mailpoet/new-users-beacon
Premium HS mailbox for new users [MAILPOET-1456]
2018-07-16 09:30:32 -04:00
4296cd5a3e Fix data creation for first test run
[MQ-50]
2018-07-16 14:13:39 +01:00
184f38f186 fix tests 2018-07-16 11:36:54 +01:00
2f83a74b95 fix errors 2018-07-16 10:44:13 +01:00
8f05d88567 split public id tests in two 2018-07-16 10:41:42 +01:00
e523fa055e fix errors 2018-07-16 10:32:06 +01:00
aef52a18c0 Remove unintended .teamcity config files 2018-07-16 12:05:15 +03:00
411fe307d1 add tests 2018-07-15 22:19:51 +01:00
9bb6c2131a TeamCity change in 'Mailpoet' project: 'https://github.com/mailpoet/mailpoet.git#refs/heads/master' VCS root was updated 2018-07-15 16:49:33 -04:00
8d8d5d234d TeamCity change in 'Mailpoet' project: 'https://github.com/mailpoet/mailpoet.git#refs/heads/master' VCS root was updated 2018-07-15 16:45:06 -04:00
37baf3edae TeamCity change in 'Mailpoet' project: Versioned settings configuration updated 2018-07-15 16:44:04 -04:00
6505871eac add comment to isPublicIdNew function 2018-07-13 16:07:56 +01:00
b12fcce017 Merge branch 'master' of https://github.com/mailpoet/mailpoet into best_mixpanel_integration 2018-07-13 16:04:40 +01:00
b758ec0797 Modifies behavior when MSS is activated and key is invalid 2018-07-12 19:11:08 -04:00
96f36d0d1c Merge pull request #1426 from mailpoet/update-text
Update text [MAILPOET-1436]
2018-07-12 12:17:36 -04:00
eada699607 Merge pull request #1429 from mailpoet/email-thumbnails
Update email thumbnails [MAILPOET-1440]
2018-07-12 12:15:30 -04:00
38f8bec4c5 Add health check to docker compose
[MQ-50]
2018-07-12 16:04:16 +01:00
4229ba87f3 Create forms delete acceptance tests
[MQ-50]
2018-07-12 11:41:36 +01:00
255422e908 Merge pull request #1428 from mailpoet/form-create-at
Create Acceptance Test FormsCreation [MQ-49]
2018-07-11 11:26:11 -04:00
928be9d698 Update email thumbnails
[MAILPOET-1440]
2018-07-11 13:04:21 +01:00
f250807be5 Create Acceptance Test FormsCreation
[MQ-49]
2018-07-11 11:11:01 +01:00
03817657a0 Display warning for cron accessibility problem [MAILPOET-801] 2018-07-11 09:27:19 +02:00
3c7cd193b6 Detect not accessible cron daemon [MAILPOET-801]
This adds a function to a CronHelper which detect accessibility problem based on timestamps
which are stored during cron execution. The main idea is that the cron daemon should update run_started_at
within the REQUEST_TIMEOUT after it was accessed (run_accessed_at).
2018-07-11 09:27:19 +02:00
083372a391 Store timestamps and last error during cron process [MAILPOET-801] 2018-07-11 09:27:14 +02:00
42b353fa59 Merge pull request #1420 from mailpoet/mpre84
Automatic email type selected tracking [PREMIUM-84]
2018-07-10 14:18:03 -04:00
eeffaf9c88 Merge pull request #1424 from mailpoet/bounce-button
Remove button if MSS is active [MAILPOET-1435]
2018-07-10 13:00:29 -04:00
9c838f02a6 Rename styles labels
[MAILPOET-1436]
2018-07-10 16:44:41 +01:00
0a5c3f021f Update zoom button text
[MAILPOET-1436]
2018-07-10 16:44:41 +01:00
82baa6cdbe Clarify MP version in form widget
[MAILPOET-1436]
2018-07-10 16:44:41 +01:00
995d3db5ae Show numbers in local format
[MAILPOET-1436]
2018-07-10 16:44:41 +01:00
2f69a705d8 Add note when deleting lists
[MAILPOET-1436]
2018-07-10 16:44:41 +01:00
4465a36405 Add 'max' to shown posts in alc settings
[MAILPOET-1436]
2018-07-10 16:44:41 +01:00
21916c6863 update beacon id for new users 2018-07-10 16:43:42 +01:00
1baace589e Merge pull request #1425 from mailpoet/fix-posts-paragraphs
Fix spacing between paragraphs in full post [MAILPOET-1455]
2018-07-10 11:32:25 -04:00
b44fe6d522 Merge pull request #1422 from mailpoet/tasks-pausing
Pause scheduled tasks for deactivated emails [MAILPOET-1442]
2018-07-10 09:59:03 -04:00
90bdcd2213 Merge pull request #1411 from mailpoet/default-sender
Set default sender on newsletter save [MAILPOET-1415]
2018-07-10 09:42:38 -04:00
d670fe27ee Remove button if MSS is active
[MAILPOET-1435]
2018-07-10 14:22:40 +01:00
b0e6283bf6 Merge pull request #1387 from mailpoet/best_api_error_message
Best api key validation error message [MAILPOET-1410]
2018-07-10 09:04:40 -04:00
380fb91d8d updating swiftmailer 2018-07-10 14:04:04 +01:00
e8e8eaf74c Merge pull request #1421 from mailpoet/newsletters-opens-export-fix
Fix export of newsletters statistics [MAILPOET-1444]
2018-07-10 08:32:32 -04:00
35825c3432 Fix spacing between paragraphs in full post [MAILPOET-1455] 2018-07-10 14:26:36 +02:00
4ce6b399f4 Displays list of features when MSS is activated 2018-07-09 20:42:20 -04:00
2c0e187089 Removes italics from video badge 2018-07-09 20:29:53 -04:00
1f6e5e1717 Opens MSS plan purchase page in a new tab 2018-07-09 20:27:22 -04:00
0cf0c3f71f Removes partial tag 2018-07-09 20:26:54 -04:00
92dfa8c593 Adds link to get MSS key 2018-07-08 10:48:01 -04:00
a02f909627 Merge pull request #1402 from mailpoet/edit-newsletter
Edit newsletter
2018-06-29 18:44:00 -04:00
bd08a529db Update testVersions for PHP code sniffer 2018-06-29 16:30:32 +02:00
aab68bc0eb Extend pausing of scheduled tasks also for welcome and automatic emails [MAILPOET-1442]
Without setting the tasks status to paused they would stay sheduled but couldn't be sent.
2018-06-29 16:29:46 +02:00
edea5ecece Add tracking of automatic email type selection [PREMIUM-84] 2018-06-29 14:49:59 +02:00
dff9154e7d Fix export of newsletters statistics [MAILPOET-1444] 2018-06-29 14:40:13 +02:00
a8f75fb927 Export newsletter listings heading component for premium plugin [PREMIUM-84] 2018-06-29 11:54:16 +02:00
57abf91a06 Removes prompt/activates MSS automatically upon key validation 2018-06-28 18:21:35 -04:00
4bb06a949a Changes order of the Send With tab 2018-06-28 12:28:36 -04:00
7962a005b1 Modifies activation behavior/presentation 2018-06-28 11:36:04 -04:00
e4c1511653 Changes status background color/adds border around deactivated box 2018-06-27 14:04:26 -04:00
00df3ab248 Adds border around activated sending method box 2018-06-27 13:42:16 -04:00
01af61a93f Removes copy text that's displayed when MSS is activated 2018-06-27 12:55:11 -04:00
ab696a133b Updates copy text 2018-06-27 12:54:05 -04:00
0b973274af Removes copy text 2018-06-27 12:51:50 -04:00
ce24845896 Moves video badge under MSS box 2018-06-27 12:50:09 -04:00
ce17adf693 Removes "try for free" button / fixes HTML markup 2018-06-27 12:49:21 -04:00
732fdaf78c Removes monthly plans info button 2018-06-27 12:39:36 -04:00
f359ba1499 Removes copy text 2018-06-27 12:38:09 -04:00
289daf2edb repushing to make test pass 2018-06-26 09:34:40 -04:00
844687411e Release 3.7.8 2018-06-26 15:23:51 +02:00
bd33fc2aba adding different assertion 2018-06-26 09:17:53 -04:00
9b9f579e4c Fixing an error 2018-06-26 08:56:25 -04:00
37e7f0abc0 fixed spacing issue 2018-06-26 08:22:54 -04:00
35ea0d9c34 Updated methods for exposing and clicking react-hidden links 2018-06-26 07:27:31 -04:00
a1974c92a7 Merge pull request #1416 from mailpoet/url-length
Increase length of URL in links [MAILPOET-1438]
2018-06-26 07:17:34 -04:00
3dba3d3887 Merge pull request #1415 from mailpoet/acceptance-file-param
Add support for file parameter to acceptance tests [MAILPOET-1434]
2018-06-26 06:45:26 -04:00
acf74f65d1 Merge pull request #1413 from mailpoet/full-posts-fix
Fix rendering of posts in newsletter [MAILPOET-1416]
2018-06-25 09:06:26 -04:00
55affcb556 Set default sender on newsletter save
[MAILPOET-1415]
2018-06-25 12:45:02 +01:00
a27ee4c83b Merge pull request #1408 from mailpoet/js-warning-fix
Fix js/react warning on settings page [MAILPOET-1421]
2018-06-25 06:48:59 -04:00
4fba615d30 Fix rendering of posts in newsletter [MAILPOET-1416] 2018-06-25 12:45:45 +02:00
71e2cc16c3 Merge pull request #1412 from mailpoet/mp1424
Fix side toolbar display problems properly [MAILPOET-1432]
2018-06-25 06:21:36 -04:00
d9c9620a67 Increase length of URL in links [MAILPOET-1438] 2018-06-25 09:43:10 +02:00
6b78762bcf api validation localhost error message : display only if localhost 2018-06-23 15:10:16 +02:00
ad0e04a9c2 Revert "api validation localhost error message : display only if localhost"
This reverts commit 4992b65f14.
2018-06-23 15:07:37 +02:00
4992b65f14 api validation localhost error message : display only if localhost 2018-06-23 15:03:25 +02:00
84bde18fce Merge branch 'master' of https://github.com/mailpoet/mailpoet into best_api_error_message 2018-06-23 14:44:07 +02:00
8fc12dbcc4 Add support for file parameter to acceptance tests [MAILPOET-1434] 2018-06-22 14:58:04 +02:00
fe9038d5a0 Update required php version in composer [MAILPOET-1437] 2018-06-22 10:51:45 +01:00
6a52d3130d ... 2018-06-21 13:57:20 -04:00
feb14d22b4 and yet again another different fix to unhide edit link 2018-06-21 13:27:35 -04:00
cfa49d8e90 and yet another different fix to unhide edit link 2018-06-21 13:13:26 -04:00
f2baf1c996 rm commented tests 2018-06-21 17:43:18 +02:00
76876aebee and another different fix to unhide edit link 2018-06-21 10:24:29 -04:00
8626dff51c different fix to unhide edit link 2018-06-21 09:52:50 -04:00
699e08b1e7 fix to unhide the row actions so test can find edit link 2018-06-21 09:13:35 -04:00
3b9ac7b479 fixed indentation and renamed file to match convention 2018-06-21 08:48:03 -04:00
5d7a2e54c8 Fix side toolbar display problems properly [MAILPOET-1432] 2018-06-21 12:23:26 +02:00
43c010ecd0 Revert "Always display colum block controls on mouse over [MAILPOET-1399]"
This reverts commit 0f08c5fa37.
2018-06-21 12:13:56 +02:00
4bd68ebc5f Release 3.7.7 2018-06-20 13:27:18 +02:00
4dd9244194 Merge pull request #1410 from mailpoet/welcome-emails-fix
Fix for welcome emails [MAILPOET-1431]
2018-06-19 12:41:45 -04:00
9308cffd45 Refactor fetching newsletter options to respect its type [MAILPOET-1431] 2018-06-19 17:06:56 +02:00
9446e3cd50 Fix codeception deprecated call in API test 2018-06-19 16:07:10 +02:00
b387eedf7c Merge pull request #1407 from mailpoet/woocommerce_free_premium_link_fix
Displays "this is a premium feature" link when Premium is disabled [MAILPOET-1426]
2018-06-18 14:36:48 -04:00
36e29581ef Merge pull request #1389 from mailpoet/api-errors
Improve error reporting in API [MAILPOET-1290]
2018-06-18 14:35:42 -04:00
f17eb37525 Merge pull request #1405 from mailpoet/list-alc
Fix ALC preview [MAILPOET-1404]
2018-06-18 09:51:58 -04:00
3e84a4b4e4 Merge pull request #1406 from mailpoet/automatic_email_group_beta_fix
Fix duplicate Beta string + allow any email type to have beta attribute [MAILPOET-1427]
2018-06-18 09:51:05 -04:00
ee63ecaabb Merge pull request #1397 from mailpoet/php-libs-update
PHP libs update [MAILPOET-1429]
2018-06-18 08:34:55 -04:00
989cda7f0e Merge pull request #1399 from mailpoet/end-53
End PHP 5.3 support [MAILPOET-1423]
2018-06-18 08:33:18 -04:00
50a807c30f Merge pull request #1409 from mailpoet/retina-logos
Update logo assets to support retina [MAILPOET-1394]
2018-06-17 19:59:54 -04:00
8537796da9 Update logo assets to support retina [MAILPOET-1394] 2018-06-15 15:08:59 +02:00
6b028a43ad Fix js/react warning on settings page [MAILPOET-1421] 2018-06-15 13:39:36 +02:00
daeee55118 Update Codeception deprecated method calls 2018-06-15 10:35:51 +02:00
f1462b5f3e Update consolidation/robo, lucatume/wp-browser 2018-06-15 10:35:51 +02:00
2774b6c8dc Update codeception/codeception, codeception/verify, phpunit/phpunit 2018-06-15 10:35:51 +02:00
874fbc704c Remove unused simplyadmire/composer-plugins 2018-06-15 10:35:51 +02:00
8b067c31e5 Replace raveren/kint by kint-php/kint 2018-06-15 10:35:51 +02:00
7ab5717cc8 Update symfony/translation 2018-06-15 10:35:51 +02:00
f4f1b7b8b2 Update j4mie/idiorm 2018-06-15 10:35:51 +02:00
19655c7a21 Update sensiolabs/security-checker 2018-06-15 10:35:51 +02:00
3cc943fcfe Update symfony/polyfill-mbstring 2018-06-15 10:35:51 +02:00
9639400134 Switch from symfony/polyfill-xml to symfony/polyfill-php72
Polyfill-xml is deprecated and it was just "proxy" to polyfill-php72 see https://github.com/symfony/polyfill-xml/blob/master/composer.json
2018-06-15 10:35:51 +02:00
3a2c7b2f94 Update nesbot/carbon 2018-06-15 10:35:51 +02:00
86f5b99f54 Update swiftmailer/swiftmailer 2018-06-15 10:35:51 +02:00
2e2d6c05ac j4mie/paris updated 2018-06-15 10:35:51 +02:00
1e37265feb cerdic/css-tidy updated 2018-06-15 10:35:51 +02:00
5a94e0d780 Displays "this is a premium feature" link when Premium is disabled 2018-06-14 14:47:07 -04:00
b757218455 Fix duplicate Beta string + allow any email type to have beta attribute 2018-06-14 14:38:33 -04:00
31f607c4ae Merge pull request #1391 from mailpoet/deactivation-survey
Show a survey on plugin deactivation [MAILPOET-1386]
2018-06-14 13:06:19 -04:00
6c478cd017 Merge pull request #1401 from mailpoet/mp1397-redone
Fix: Using double quote break rendering [MAILPOET-1397]
2018-06-14 11:57:31 -04:00
d358621366 Merge pull request #1392 from mailpoet/renderer_font_family_fix
Uses full font-family name in element styles [MAILPOET-1393]
2018-06-14 11:25:23 -04:00
bb579370a8 Fix list ALC preview
[MAILPOET-1404]
2018-06-14 15:28:08 +01:00
75d8ab82e8 Merge pull request #1400 from mailpoet/remove-domain
Disable translations for translate.wordpress.org [MAILPOET-1425]
2018-06-14 16:18:27 +02:00
78e954df0e Merge pull request #1396 from mailpoet/js-dependencies-update
Js dependencies update [MAILPOET-1428]
2018-06-14 09:48:58 -04:00
00e18831ab Initial upload of new edit newsletter test 2018-06-14 07:39:51 -04:00
cc2a39ac26 Fix: Using double quote break rendering [MAILPOET-1397] 2018-06-14 11:56:03 +02:00
b135c342f1 Merge pull request #1394 from mailpoet/save-newsletter-as-draft
Save newsletter as draft
2018-06-14 05:55:44 -04:00
36cb7249cc Disable translations for translate.wordpress.org
[MAILPOET-1425]
2018-06-14 10:24:05 +01:00
8ed6c46ef9 Update php 5.4 warning message
[MAILPOET-1423]
2018-06-14 09:31:44 +01:00
5609384af0 Require PHP 5.4
[MAILPOET-1423]
2018-06-14 09:24:51 +01:00
09e82293ff Updates code format 2018-06-13 20:52:05 -04:00
8fce649d37 initial commit of autosave confirmation test 2018-06-13 12:13:35 -04:00
c2b98d93c3 Revert "Upgrade webpack manifest plugin"
This reverts commit e4947e1b77.
2018-06-13 15:59:48 +01:00
7640f4c912 adding assertion 2018-06-13 10:49:07 -04:00
2ee77e0034 Deleted TODOs after noting them as JIRA issues 2018-06-13 16:46:18 +02:00
66a0ddb321 fixing typos, again 2018-06-13 10:32:12 -04:00
9dc98ffa9e fixing typos 2018-06-13 10:18:53 -04:00
65904137c1 add new test to save newsletter as draft to new file 2018-06-13 10:13:51 -04:00
c37c459597 just a little cleanup of lines I commented out 2018-06-13 09:32:32 -04:00
fd6a283f24 Update minimatch 2018-06-13 13:58:48 +01:00
89b7813324 trying to get a test to pass, for the love of dog 2018-06-13 08:58:21 -04:00
e4947e1b77 Upgrade webpack manifest plugin 2018-06-13 13:53:21 +01:00
1005990588 Deleting leftover file 2018-06-13 14:49:29 +02:00
0f8b35ba0e Upgrade to webpack3 2018-06-13 13:47:57 +01:00
2916e4362e commented out a line that broke to see if it's necessary 2018-06-13 08:42:29 -04:00
8393bac51b Upgrade to webpack 2 2018-06-13 13:33:27 +01:00
0ea6afb38a defined a variable like a boss, which I had not previously done 2018-06-13 08:22:52 -04:00
0c2085864e Fixed a step that said click next when I meant click send. 2018-06-13 08:06:53 -04:00
a0818b3b9f Added function to test standard newsletter creation, fixed two typos in comments of previous file. 2018-06-13 07:44:26 -04:00
729d950e4e Return back amd loader 2018-06-13 11:10:03 +01:00
9a11d4cc82 Update babel 2018-06-13 10:57:40 +01:00
683e9c9fa1 Update eslint
Only indentation updated in this commit
2018-06-13 09:28:53 +01:00
2ad9ebf1d3 Uses full font-family name in element styles 2018-06-12 19:15:30 -04:00
0545e48f8e Updates changelog and bumps up release version 2018-06-12 17:09:26 +02:00
7e843b5fdf Show a survey on plugin deactivation
[MAILPOET-1386]
2018-06-12 15:52:25 +01:00
33de2d6a5d Merge pull request #1390 from mailpoet/mp1414
Broken woocommerce mail thumbnails [MAILPOET-1414]
2018-06-12 09:16:47 -04:00
3290df3bb8 Broken woocommerce mail thumbnails [MAILPOET-1414] 2018-06-12 14:45:39 +02:00
71fed489ec Improve error reporting in API
[MAILPOET-1290]
2018-06-12 10:32:20 +01:00
8c55fce938 Merge pull request #1338 from mailpoet/am_send_emails
Makes necessary changes to schedule and send automatic emails [PREMIUM-82]
2018-06-11 14:09:32 -04:00
ebc9c4db39 best api key error message 2018-06-11 18:54:27 +01:00
dde03e0ae6 Adds missing import after merge conflict resolution 2018-06-11 13:48:59 -04:00
581e1303d0 Display action link for each event if defined 2018-06-11 13:40:21 -04:00
04d676f9e3 Fixes test after rebase 2018-06-11 13:40:06 -04:00
fff6c966d8 Marks WooCommerce group as beta 2018-06-11 13:40:06 -04:00
20dbc3c74b Adds WooCommerce teaser 2018-06-11 13:40:06 -04:00
ca1be42ab8 Prevent breaking search when server does not return an object 2018-06-11 13:40:05 -04:00
77d2f0224b Fixes ESLint rules 2018-06-11 13:40:05 -04:00
6d74ba8bb0 Validates that subscriber exists when processing automatic email 2018-06-11 13:40:05 -04:00
8f758b11e1 Splits large tests into smaller ones 2018-06-11 13:40:05 -04:00
4611a7ea74 Updates method names 2018-06-11 13:40:05 -04:00
9aa796681a Processes stats for automatic emails 2018-06-11 13:40:05 -04:00
b3aae566d5 Adds cron scheduler unit tests for automatic emails 2018-06-11 13:40:05 -04:00
bf0c5abd4f Adds newsletter scheduler unit tests for automatic emails 2018-06-11 13:38:11 -04:00
e578b0a4ea Decodes meta option field if it exists on the object 2018-06-11 13:38:11 -04:00
08fa5b88b5 Removes unused condition 2018-06-11 13:38:11 -04:00
b75d4db412 Adds newsletter/cron scheduler for automatic emails 2018-06-11 13:38:11 -04:00
116ee51497 Does not use queue when previewing automatic emails in browser 2018-06-11 13:33:44 -04:00
b16cbf9e7d Updates column type since it may contain long meta object 2018-06-11 13:33:44 -04:00
32e02cbf52 Adds meta column to sending queues 2018-06-11 13:33:44 -04:00
9b9eaacafe rm non implemented tests 2018-06-11 18:10:56 +01:00
b7db18425a Merge pull request #1385 from mailpoet/add-new-button-fix
Emails listing: Add new button fix [MAILPOET-1408]
2018-06-11 11:38:44 -04:00
7cc165b3d1 Merge pull request #1379 from mailpoet/video-guide-badges
Video guides: add badges to UI [MAILPOET-1395]
2018-06-11 11:37:31 -04:00
658d989a60 Merge pull request #1382 from mailpoet/feedback-tooltips
Add feedback tooltips [MAILPOET-1320]
2018-06-11 11:36:15 -04:00
c841e5dc60 Merge pull request #1383 from mailpoet/form_template_update
Fixes always visible form subscription success message [MAILPOET-1406]
2018-06-11 10:29:43 -04:00
feb6e97eca Merge pull request #1386 from mailpoet/alc-bc-fix
ALC Backward compatibility fix for displaying images [MAILPOET-1409]
2018-06-11 10:27:49 -04:00
7091825893 production mixpanel key 2018-06-11 13:33:13 +01:00
313a5f8a4e analytics : use a unique public id 2018-06-11 13:28:32 +01:00
b00b42e4ca Refactor emails list heading to respect DRY [MAILPOET-1408] 2018-06-11 12:13:56 +02:00
e3a63b54cc Unify emails list heading code [MAILPOET-1408] 2018-06-11 12:13:12 +02:00
0af3be61dd renderer: Added basic unit test for PostTransformer structrure generation with layout 2018-06-11 09:44:59 +02:00
fdc5aad62a renderer: Added unit test for PostTransformer structrure generation without layout 2018-06-11 09:00:08 +02:00
efe4668f8c Merge branch 'master' of https://github.com/mailpoet/mailpoet into best_mixpanel_integration 2018-06-08 16:27:59 +01:00
b36537a4e8 renderer: Processing Post without layout renders featured_image only for excerpt display type [MAILPOET-1409] 2018-06-08 17:05:37 +02:00
62fd56400b renderer: Fixed notice in PostTransformer for older data without 'withLayout' property [MAILPOET-1409] 2018-06-08 17:02:03 +02:00
9521134376 Merge pull request #1384 from mailpoet/mp1399
Always display colum block controls on mouse over [MAILPOET-1399]
2018-06-07 14:02:21 -04:00
ccf027b336 Merge pull request #1378 from mailpoet/not-blocked-sending
Rotate scheduled tasks [MAILPOET-1391]
2018-06-07 10:54:13 -04:00
5977cb9d63 Merge pull request #1381 from mailpoet/mp1325
Stop blocking user on template save [MAILPOET-1325]
2018-06-07 10:06:34 -04:00
962baf71a8 Merge pull request #1380 from mailpoet/mp1364
Separate welcome/whats_new pages [MAILPOET-1364]
2018-06-07 10:04:45 -04:00
0f08c5fa37 Always display colum block controls on mouse over [MAILPOET-1399]
the div.mailpoet_tools is now behind the newsletter editor and
move to the right on mouse over instead of simply hidden which,
caused all the invisible elements to overlap.
2018-06-07 14:00:54 +02:00
20cecc885a Stop blocking user on template save
When the template save function throws an error
the newsletter is already being sent. We cannot
stop users.

[MAILPOET-1325]
2018-06-07 08:54:15 +01:00
87dbb7ff96 Updates HTML code/template formatting 2018-06-06 22:18:04 -04:00
4070a56547 camel case 2018-06-06 17:03:22 +01:00
df2cd9e6e3 Add feedback tooltips
[MAILPOET-1320]
2018-06-06 16:24:46 +01:00
d6f72087e9 video badges code review 2018-06-06 12:55:20 +01:00
506f2d0fbf Separate welcome/whats_new pages [MAILPOET-1364] 2018-06-06 11:51:22 +02:00
a41c327996 Updates changelog and bumps up release version 2018-06-05 12:40:12 -04:00
0f46ecc433 Merge pull request #1376 from mailpoet/mp1392
Dont call flush_rewrite in init [MAILPOET-1392]
2018-06-05 06:38:14 -04:00
03b36e6b86 Merge pull request #1374 from mailpoet/mp1365
Fix image fullwidth toggle [MAILPOET-1365]
2018-06-05 06:36:59 -04:00
2c290c6e4c Rotate sending queues
This should prevent sending queues to be stuck when a newsletter cannot be send.

[MAILPOET-1391]
2018-06-05 11:05:59 +01:00
b9ce9ecf28 Fix image fullwidth toggle [MAILPOET-1365]
Prevent WordPress $content_width global to override
mailpoet_image_size when calling wp_get_attachment_image_src()
in ACL generated posts.
2018-06-05 10:19:39 +02:00
ac47866295 Fix image fullwidth toggle [MAILPOET-1365]
Prevent WordPress $content_width global to override
mailpoet_image_size when calling wp_get_attachment_image_src()
in ACL generated posts.
2018-06-05 08:59:57 +02:00
705241d330 qa 2018-06-04 20:47:10 +01:00
c88c8a9c96 add video links 2018-06-04 18:12:48 +01:00
b8ce6ff88c Rotate scheduled tasks
Scheduled tasks should rotate so that they don't block
sending when they cannot be send.

[MAILPOET-1391]
2018-06-04 16:00:32 +01:00
b855e45817 Merge branch 'master' of https://github.com/mailpoet/mailpoet into best_mixpanel_integration 2018-06-04 15:04:46 +01:00
e7a994e09c use mixpanel.people.set 2018-06-04 15:04:40 +01:00
3589899d6b Dont call flush_rewrite in init [MAILPOET-1392]
Following http://wpengineer.com/2044/custom-post-type-and-permalink/
and validating with Tautvidas we concluded there was not
reason not to use flush_rewrite_rules() as recommended which is,
upon activating and deactivating the plugin.
2018-06-04 14:49:16 +02:00
e4b15fb9b9 Merge pull request #1375 from mailpoet/mp1341
Updates to readme.txt [MAILPOET-1341]
2018-06-04 07:41:09 -04:00
59d632895e Merge pull request #1369 from mailpoet/posts-alc-image
Multi-column layout in ALC/Posts [MAILPOET-1350]
2018-06-04 07:37:56 -04:00
67b66856f5 removing images and headings from the excerpt 2018-06-01 11:21:59 +00:00
bd76fa889a Updates to readme.txt [MAILPOET-1341] 2018-05-31 09:33:35 +02:00
8793d904fb allow sending of post notifications with either old or new ALC blocks 2018-05-30 09:31:04 +00:00
6914a9c224 excerpt are now displayed 2018-05-30 09:15:14 +00:00
24b63d324b release 3.7.4 2018-05-30 06:09:29 +00:00
76ac3b49d6 Merge pull request #1373 from mailpoet/template-description
Force migration to set default value for template description column [MAILPOET-1398]
2018-05-29 10:48:38 -04:00
2573e2f785 Change field type of newsletter_templates.description to force dbDelta
set the column's default value [MAILPOET-1398]
2018-05-29 16:35:12 +03:00
3872ffbbc4 fixing some bugs and updating template 2018-05-29 11:21:24 +00:00
b7e33aa997 Merge pull request #1372 from mailpoet/template-desc
not sending `description` when saving a template [MAILPOET-1398]
2018-05-29 06:05:28 -04:00
99dcd6fa0b Merge pull request #1371 from mailpoet/queue_rerender_fix
Prevents sending queue rerendering when post notification is updated [MAILPOET-1372]
2018-05-29 06:04:39 -04:00
f285cfcdc3 Add back wp_mailpoet_newsletter_templates.description field to avoid
breaking backwards compatibility to sites that still have template
descriptions.
Empty-string default value allows it not to break when field is not specified
or is null.
2018-05-28 16:51:46 +03:00
88be42fea1 fixing naming issues 2018-05-28 10:33:13 +00:00
32a5a4ef52 not sending description when saving a template 2018-05-28 09:41:42 +00:00
7b665acae3 Prevents sending queue rerendering when post notification is updated 2018-05-27 21:59:58 -04:00
2890b66cfd Merge pull request #1366 from mailpoet/live-chat
Live chat & better Helpscout integration [MAILPOET-1389]
2018-05-24 07:54:40 -04:00
913e070b32 Merge pull request #1370 from mailpoet/translations
fixing translations [MAILPOET-1380]
2018-05-24 07:52:37 -04:00
0fed3f8355 update default value for image position 2018-05-24 07:48:27 +00:00
2215b53141 removing top padding from excerpt text 2018-05-24 07:44:41 +00:00
3e84a1f8e1 fixing translations 2018-05-23 21:32:59 +00:00
74250b87f9 Merge pull request #1368 from mailpoet/mp1336
Skip the changelog page after update [MAILPOET-1336]
2018-05-23 07:07:56 -04:00
ec34a9efca Merge pull request #1360 from mailpoet/mp1306
Newsletter template thumbnail redesign [MAILPOET-1306]
2018-05-23 07:06:06 -04:00
5b077cfb54 adding styles to containers 2018-05-23 10:39:08 +00:00
cdac9afc64 fixing tests 2018-05-23 08:21:22 +00:00
0a298f5fad creating new ALC block and widget 2018-05-23 07:42:30 +00:00
4dd17e47ad add image alignment to Posts 2018-05-23 05:17:51 +00:00
d7ab03b1c7 rewrite PostTransformer to return old or new structure depending on the newVersion attribute 2018-05-23 05:15:40 +00:00
2e6be59d9d Fixed a bad string
While working on [MAILPOET-1344] if forgot to change a string
following review.

Both buttons should have the same text but did not.

This change is a bit useless given that we now skip the page.
Still wanted to fix this while at it.
2018-05-22 15:35:16 +02:00
e5a1af96cb Stop showing the what's new page
[MAILPOET-1336]
2018-05-22 15:09:45 +02:00
3a0a241a52 Release 3.7.3 2018-05-22 13:26:40 +01:00
bcbe89e558 update beacon icon img 2018-05-22 12:02:13 +02:00
75bad97b10 Newsletter template thumbnail redesign
Redesigned the template selection screen to
look like the WordPress theme selector.

The main changes relate to:
* style changes, to achieve the new look
* jsx templates, to work with new css changes
* template, removed the description field

[MAILPOET-1306]
2018-05-22 10:23:07 +02:00
59f9fdb3b6 fix failing tests 2018-05-21 19:03:13 +02:00
89a8f9ded4 add unit tests 2018-05-21 18:20:43 +02:00
62b5502eb1 use Carbon 2018-05-21 17:07:14 +02:00
9b7773e0a4 change beacon icon from question mark to message 2018-05-21 16:57:12 +02:00
498c014464 function wording & use Carbon 2018-05-21 16:53:20 +02:00
b3a23bdddc Merge pull request #1363 from mailpoet/fix-post-notification-update
Fix sending task reschedule [MAILPOET-1378]
2018-05-21 10:43:54 -04:00
587eaffc3c Merge pull request #1357 from mailpoet/unblock-paused
Pause sending tasks for inactive notifications [MAILPOET-1376]
2018-05-21 09:47:16 -04:00
2da6c2ec49 Merge pull request #1362 from mailpoet/welcome-email-fix
Fix welcome emails
2018-05-21 09:45:25 -04:00
8a1fe0df6b Merge pull request #1367 from mailpoet/bugfix
fixing fatal error when using `wp_add_privacy_policy_content` in init hook [MAILPOET-1390]
2018-05-21 08:18:28 -04:00
d56f2c59ef Merge pull request #1355 from mailpoet/subscriber-source
Subscriber source [MAILPOET-1377]
2018-05-21 08:17:00 -04:00
ad48aff5c1 Merge pull request #1364 from mailpoet/import_filename_fix
Fixes import issue when filename contains multiple periods [MAILPOET-1388]
2018-05-21 07:26:08 -04:00
fa7387c9e4 Merge pull request #1359 from mailpoet/fix-console-warning
Fix warning in console [PREMIUM-87]
2018-05-21 07:18:33 -04:00
fbd11cf848 fixing fatal error when using wp_add_privacy_policy_content in init hook 2018-05-21 07:47:17 +00:00
e469a32f9e Live chat & better Helpscout integration 2018-05-18 20:00:45 +02:00
2104451ec3 Adjusts regex to match extension after the last period 2018-05-17 18:21:46 -04:00
9b9abf5cde Fix sending task reschedule
The query returned data from the sending queue table
So the next update updated the wrong row in the tasks table

[MAILPOET-1378]
2018-05-17 16:13:51 +01:00
dbdf432c1d Merge pull request #1347 from mailpoet/queue_rendered_subject_improvement
Uses queue's rendered subject when sending newsletter [MAILPOET-1373]
2018-05-17 08:35:25 -04:00
8a877ed637 Merge pull request #1356 from mailpoet/welcome-email-scheduling
Add index based on subscriber_id to scheduled_task_subscribers [MAILPOET-1382]
2018-05-17 08:33:57 -04:00
4da7ed44e5 Merge pull request #1352 from mailpoet/less-info
Returning only the id and email on form's response [MAILPOET-1370]
2018-05-17 06:59:10 -04:00
952c0f5aa7 Merge pull request #1358 from mailpoet/vulnerable-dependencies
Update vulnerable jQuery 2.1.4 and hoek 4.2.0 dependencies [MAILPOET-1383]
2018-05-17 06:43:19 -04:00
5223687326 Fix welcome emails
Decreased priority. This was a conflict with Members plugin
Members plugin has priority 5 and we were checking
user roles before Members plugin correctly
assigned them.

[PREMIUM-83]
2018-05-17 11:13:34 +01:00
ee07f3e734 Fix warning in console 2018-05-16 14:03:38 +01:00
0c585d15e1 Refactor events_list.jsx to suppress lint6 warnings
Likely happened due to updated package-lock.json
2018-05-15 21:11:24 +03:00
1d362f9cf6 Update webpack 1.11.0 -> 1.12.9 to force a newer Uglify version 2018-05-15 19:56:12 +03:00
ff9f9a0a90 Update vulnerable jQuery 2.1.4 -> 3.3.1, and jsdom to update hoek
dependency [MAILPOET-1383]

Unless I missed something, judging based on the jQuery 3.0 upgrade guide
it appears we are compatible with jQuery 3.x, so I'm updating just the
library version.  We're using version bundled with WP anyways for the
most part, and only load 3.x in JS tests.

jsdom was updated to 11.10.0 to update dependency on hoek 4.2.0 -> 4.2.1
2018-05-15 19:21:54 +03:00
941b88495a Pause sending tasks for inactive notifications
[MAILPOET-1376]
2018-05-15 16:40:31 +01:00
859b87c7c9 Add index based on subscriber_id to scheduled_task_subscribers
[MAILPOET-1382]

This is done to avoid full table scans when scheduling welcome emails
and checking whether or not an email has been sent.
There we have to query based on `subscriber_id`, but without having a
`task_id`, so MySQL cannot make use of the `(task_id, subscriber_id)`
primary key.
2018-05-15 18:39:17 +03:00
d44c275790 Release 3.7.2 2018-05-15 15:47:57 +03:00
f942e98645 Merge pull request #1354 from mailpoet/custom-field-value-length
Fix custom fields to allow values longer than 255 characters [MAILPOET-1381]
2018-05-15 06:08:06 -04:00
3e9d7fc68d Add NOT NULL constraint to custom field value field type 2018-05-15 11:33:22 +03:00
1c6c275295 Passes single array with shortcode details 2018-05-14 19:16:24 -04:00
1d8e8e8786 Text field cannot have default values 2018-05-14 19:54:20 +03:00
6ad6190da3 Fix custom fields to allow values longer than 255 characters
[MAILPOET-1381]
2018-05-14 19:39:07 +03:00
3c499d0626 retuning empty response on subscribe 2018-05-14 15:24:39 +00:00
d4e3334f9e Add source to privacy exports
[MAILPOET-1377]
2018-05-14 16:22:51 +01:00
603062f23e Set source for existing subscribers
[MAILPOET-1377]
2018-05-14 15:56:36 +01:00
e55aab43b5 Merge pull request #1350 from mailpoet/gdpr-clicks
Export statistics clicks [MAILPOET-1357]
2018-05-14 10:19:37 -04:00
a4fdd32c48 Merge pull request #1353 from mailpoet/subscriber-source
Subscriber source [MAILPOET-1377]
2018-05-14 10:19:00 -04:00
3940381e30 Add source to wp users
[MAILPOET-1377]
2018-05-14 13:55:47 +01:00
582f241ea4 Add source to subscribed entered in admin
[MAILPOET-1377]
2018-05-14 13:55:47 +01:00
11b29a1efa Add source to subscribed entered in admin
[MAILPOET-1377]
2018-05-14 13:55:47 +01:00
f5d59eb00e Add source to imported subscribers
[MAILPOET-1377]
2018-05-14 13:55:47 +01:00
1af5802030 Add subscriber source
[MAILPOET-1377]
2018-05-14 13:55:47 +01:00
2627ea865a Merge pull request #1344 from mailpoet/mp1371
Fix: CPU usage and sending issue on slow host [MAILPOET-1371]
2018-05-14 07:54:55 -04:00
96b02cccc4 Merge pull request #1345 from mailpoet/react-warning
fixing the react select warning [MAILPOET-1310]
2018-05-14 07:29:04 -04:00
7d912e941f Merge pull request #1351 from mailpoet/gdpr-privacy-policy
Add privacy policy [MAILPOET-1360]
2018-05-14 07:27:26 -04:00
572cc1671b Merge branch 'master' into gdpr-privacy-policy 2018-05-14 12:13:21 +01:00
709de7dd54 Merge pull request #1348 from mailpoet/gdpr-opens
Export viewed emails [MAILPOET-1356]
2018-05-14 07:00:46 -04:00
24ce88c4d5 Merge pull request #1349 from mailpoet/gdpr-eraser
Gdpr eraser [MAILPOET-1359]
2018-05-14 07:00:03 -04:00
a664d3631b Export statistics clicks
[MAILPOET-1357]
2018-05-11 18:34:25 +01:00
5912004c10 Fix: CPU usage and sending issue on slow host
On some slow host, the `newsletter` table get filled with
duplicated `notification_history` marked as `sending` that
never get sent.

To prevent this we've made the two following changes:
* We prevent firing `publis_*` hooks on post_type which
are excluded from search.
* We do not schedule a new post notification email if one
has an `notification_history` entry marked as `sending`.

[MAILPOET-1371]
2018-05-10 15:25:23 +02:00
f5c56bf492 Add privacy policy
[MAILPOET-1360]
2018-05-10 11:39:14 +01:00
d5b9664bde Fix failing tests 2018-05-09 12:47:25 +01:00
bd01b5855e Add subscriber eraser for GDPR
[MAILPOET-1359]
2018-05-09 09:28:04 +01:00
a742dacf32 Updates changelog and bumps up release version to 3.7.1 2018-05-08 11:13:09 -04:00
e62444d34e Merge pull request #1346 from mailpoet/welcome_email_count_fix
Fixes sent count not being displayed in welcome listings [MAILPOET-1374]
2018-05-08 09:38:19 -04:00
d2f98bc2e5 text field warning 2018-05-08 13:40:38 +01:00
ee99195b30 Export viewed emails
[MAILPOET-1356]
2018-05-08 12:26:41 +01:00
2f2a651fd2 Merge pull request #1329 from mailpoet/old-php-warning
Show warning when customer uses an old PHP version [MAILPOET-1314]
2018-05-08 06:39:28 -04:00
28651227d5 Uses rendered subject from queue when preparing newsletter for sending 2018-05-07 20:06:03 -04:00
b57c8b7533 Returns shortcode when subscriber object is null 2018-05-07 19:07:58 -04:00
ee4aefb6e3 Passes full shortcode object as function argument 2018-05-07 19:07:53 -04:00
8a8b99ad54 Fixes sent count not being displayed in welcome listings 2018-05-07 19:02:29 -04:00
d0b1579731 fixing the react select warning 2018-05-07 20:16:25 +01:00
7c9943c463 Merge pull request #1342 from mailpoet/gdpr-export-newsletters
Gdpr export newsletters sent to a user [MAILPOET-1355]
2018-05-07 07:34:48 -04:00
68b091848c Export newsletters sent to a user
[MAILPOET-1355]
2018-05-07 14:19:44 +03:00
22d3d00841 Use transient instead of option
[MAILPOET-1314]
2018-05-04 15:43:13 +01:00
d68dffafd3 Fix typo and translation
[MAILPOET-1314]
2018-05-04 15:33:56 +01:00
df58322f0e Move old versions code to own class
[MAILPOET-1316]
2018-05-04 15:33:56 +01:00
ea47524cc4 Remove 5.5 warning for now
[MAILPOET-1316]
2018-05-04 15:32:29 +01:00
56f7b4d523 Show warning when customer uses an old PHP version
[MAILPOET-1314] [MAILPOET-1316]
2018-05-04 15:32:29 +01:00
1d1aa52fa8 Merge pull request #1341 from mailpoet/gdpr-export-subscriber
Gdpr data export subscriber [MAILPOET-1358]
2018-05-04 09:46:45 -04:00
39ae92e580 Merge pull request #1340 from mailpoet/data-fetching-limits
Add a limit to fetch 5 scheduled tasks at a time [MAILPOET-1366]
2018-05-04 09:45:56 -04:00
2dfb264ca6 Merge pull request #1343 from mailpoet/send_pause_fix
Fixes broken sending pause functionality [MAILPOET-1368]
2018-05-04 09:44:59 -04:00
ee2631dbf2 Fixes broken pause functionality 2018-05-03 20:10:28 -04:00
11067327a1 Add Subscriber exporter
[MAILPOET-1358]
2018-05-03 16:35:40 +01:00
8e13eb50bf Export lists for email
[MAILPOET-1354]
2018-05-03 16:33:22 +01:00
7bb2d86f93 Fix private constant being impossible 2018-05-03 13:16:34 +03:00
2b351e4f34 Use constants for magic numbers, clean up tests 2018-05-03 13:07:29 +03:00
1f30f6997e Refactor SendingTask creation within test 2018-05-03 12:44:00 +03:00
a588e95762 Add a limit to fetch 5 scheduled tasks at a time [MAILPOET-1366] 2018-05-02 23:27:30 +03:00
f8e443ed3c Merge pull request #1337 from mailpoet/mailpoet-1344
Easier "What's new" skipping [MAILPOET-1344]
2018-05-02 11:50:47 -04:00
73f51505a2 Close [MAILPOET-1344] "Easier what's new skipping"
* URL test now check for home URL instead of just 'http'
* Fixed a bug where getCurrentlURL() returned a broken path
* Added "I don't care about the update" button
* Update skip buttons now return to the previous page
2018-05-02 16:16:36 +02:00
576796db22 Release 3.7.0 2018-04-25 15:09:27 +01:00
72aaaaa94d Merge pull request #1336 from mailpoet/welcome-fix
Fix welcome emails [PREMIUM-81]
2018-04-25 08:15:43 -04:00
0470f773d5 Merge pull request #1335 from mailpoet/notification-fix
Fix notification settings [MAILPOET-1363]
2018-04-25 07:52:12 -04:00
e71355f73f Merge pull request #1334 from mailpoet/stats_fix
Use unique key for stats [MAILPOET-1362]
2018-04-25 07:39:40 -04:00
aa11af3cf8 Fix welcome emails
[PREMIUM-81]
2018-04-25 12:32:44 +01:00
535818fec4 Fix notification settings
[MAILPOET-1363]
2018-04-25 11:43:07 +01:00
eba06118a4 Merge pull request #1333 from mailpoet/subscriber_search_fix
Fixes JS error when searching for subscribers in listings [MAILPOET-1361]
2018-04-25 06:12:28 -04:00
32beb0dcd1 Use unique key for stats
[MAILPOET-1362]
2018-04-25 11:11:04 +01:00
a70405e76d Fixes "cannot read property 'props' of null" error 2018-04-24 19:51:07 -04:00
a78c9e2f99 Release: 3.6.7 2018-04-24 14:42:17 +02:00
ca8390ed43 Merge pull request #1332 from mailpoet/fix-scheduled-error
Fix: Cannot read property 'showError' of undefined [MAILPOET-1352]
2018-04-24 08:01:14 -04:00
f64cf728fe Fix: Cannot read property 'showError' of undefined
[MAILPOET-1352]
2018-04-24 12:33:11 +01:00
ed8c75dd06 Merge pull request #1331 from mailpoet/fix-duplicites
Don't crash on duplicit rows [MAILPOET-1351]
2018-04-23 11:36:40 -04:00
a640e52eaf Don't crash on duplicit rows
[MAILPOET-1351]
2018-04-23 16:20:59 +01:00
3b62367b18 Merge pull request #1330 from mailpoet/es5_es6_lint
Es5 es6 lint [MAILPOET-1348]
2018-04-23 08:52:09 -04:00
32a759eca5 Fix Lists edit form
[MAILPOET-1348]
2018-04-19 14:33:08 +01:00
c105df1635 fixing acceptance tests 2018-04-19 14:46:51 +02:00
76aa5678a8 enabling CircleCI 2018-04-18 19:31:14 +02:00
1855a3a481 ESLint rules 2018-04-18 19:24:38 +02:00
2c96f1902e ESLint rules 2018-04-18 18:52:40 +02:00
f3a5c6e406 ESLint rules 2018-04-18 18:45:04 +02:00
26d4be24c2 Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 18:34:22 +02:00
1b98604c90 ESLint rules 2018-04-18 18:34:12 +02:00
2b1eafc16f Fix eslint rules
[MAILPOET-1348]
2018-04-18 17:25:59 +01:00
1635c3aac3 Fix eslint rules
[MAILPOET-1348]
2018-04-18 17:22:58 +01:00
861d4ea9e1 Fix eslint rules
[MAILPOET-1348]
2018-04-18 17:15:57 +01:00
8890dac207 ES6 rules 2018-04-18 18:08:47 +02:00
940c1a66aa Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 18:00:53 +02:00
5300e338dc ES6 assets/js/src/help/knowledge_base.jsx 2018-04-18 18:00:46 +02:00
a73dda6690 Fix eslint rules
[MAILPOET-1348]
2018-04-18 16:56:12 +01:00
adff7f6f74 Fix eslint rules
[MAILPOET-1348]
2018-04-18 16:52:35 +01:00
c41fd4cb3b Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 17:50:50 +02:00
57de46cb29 ES6 assets/js/src/help-tooltip.jsx 2018-04-18 17:50:41 +02:00
6322932e25 Fix eslint rules
[MAILPOET-1348]
2018-04-18 16:49:29 +01:00
93143695c4 Fix eslint rules
[MAILPOET-1348]
2018-04-18 16:48:54 +01:00
a37cb31141 Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 17:46:46 +02:00
1dbd002df9 ES6 assets/js/src/form/form.jsx 2018-04-18 17:46:37 +02:00
6599914263 This is used in Mixin and mixins are removed in the future anyway
[MAILPOET-1348]
2018-04-18 16:30:05 +01:00
c974e80dc5 Disable ci 2018-04-18 16:05:42 +01:00
74211658e0 Fix ESLint rules [MAILPOET-1348] 2018-04-18 18:00:47 +03:00
72187fefdd Fix eslint rules
[MAILPOET-1348]
2018-04-18 15:51:32 +01:00
4165ad6959 Fix eslint rules
[MAILPOET-1348]
2018-04-18 15:42:29 +01:00
0ce72c05f3 Fix eslint rules
[MAILPOET-1348]
2018-04-18 15:40:51 +01:00
afd801694d Fix eslint rules
[MAILPOET-1348]
2018-04-18 15:35:08 +01:00
c20ff20f5c Fix eslint rules
[MAILPOET-1348]
2018-04-18 15:31:34 +01:00
d638273f47 ES6 assets/js/src/form/fields/textarea.jsx 2018-04-18 15:59:24 +02:00
b053bb395c Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 15:53:22 +02:00
788362f5b8 ES6 assets/js/src/form/fields/selection.jsx 2018-04-18 15:53:11 +02:00
c8782db74b Fix eslint rules
[MAILPOET-1348]
2018-04-18 14:52:34 +01:00
3b48bc7517 Fix eslint rules
[MAILPOET-1348]
2018-04-18 14:48:22 +01:00
bcb1f7e289 ES6 assets/js/src/form/fields/select.jsx 2018-04-18 15:37:59 +02:00
2d7555e79d ES6 assets/js/src/form/fields/radio.jsx 2018-04-18 15:35:33 +02:00
bd5be51b0e ES6 assets/js/src/form/fields/field.jsx 2018-04-18 15:31:43 +02:00
ae99a06717 Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 15:29:13 +02:00
80c2f8970a ES6 assets/js/src/form/fields/date.jsx 2018-04-18 15:29:00 +02:00
b073f95008 Fix eslint rules
[MAILPOET-1348]
2018-04-18 14:11:12 +01:00
b2473c9b65 Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 15:10:18 +02:00
e92ccdf5b1 adding prop-types 2018-04-18 15:09:57 +02:00
fc5b797738 Fix eslint rules
[MAILPOET-1348]
2018-04-18 13:44:12 +01:00
867e62d0e8 Fix eslint rules
[MAILPOET-1348]
2018-04-18 12:13:13 +01:00
566db67e8c Fix eslint rules
[MAILPOET-1348]
2018-04-18 11:16:09 +01:00
a535e59450 Merge branch 'es5_es6_lint' of github-mp:mailpoet/mailpoet into es5_es6_lint 2018-04-18 11:59:29 +02:00
5ac75591a9 ES6 assets/js/src/form/fields/checkbox.jsx 2018-04-18 11:58:57 +02:00
b993c47181 Fix eslint rules
[MAILPOET-1348]
2018-04-18 10:55:24 +01:00
d195cd9798 Fix eslint rules
[MAILPOET-1348]
2018-04-18 10:53:35 +01:00
5fb57b13e4 Fix eslint rules
[MAILPOET-1348]
2018-04-18 10:39:48 +01:00
9fce8aa126 Fix form_editor eslint rules
[MAILPOET-1348]
2018-04-18 10:23:30 +01:00
6892dbea91 Remove temporary eslint rules
[MAILPOET-1348]
2018-04-18 10:08:56 +01:00
154e88673c Release 3.6.6 2018-04-17 15:34:54 +03:00
086ef7429b Use node 9.x image for running circleci tests 2018-04-17 11:36:39 +01:00
2dd15438d8 Merge pull request #1325 from mailpoet/sending_task_fix
Fixes stuck sending [MAILPOET-1346]
2018-04-17 05:41:21 -04:00
937aaae2c4 Merge pull request #1319 from mailpoet/am_creating_emails
Makes necessary changes to create and display automatic emails [PREMIUM-75]
2018-04-14 00:49:17 +03:00
37a046a8e9 Merge pull request #1327 from mailpoet/export_test_fix
Fixes export test when Premium version is enabled [MAILPOET-1347]
2018-04-13 22:40:55 +03:00
6c64ba90c7 Abstracts WP's remove_all_filters function and fixes export test 2018-04-13 14:20:53 -04:00
e48a288fae Merge pull request #1326 from mailpoet/circleci-docker
Use pre-built docker containers for CircleCI [MAILPOET-1345]
2018-04-13 11:06:33 -04:00
abe231215b Use a prebuilt PHP 5.6-cli image instead of building one each time 2018-04-13 17:09:28 +03:00
7d43a41ed9 Use prebuilt docker images from mailpoet/wordpress for acceptance tests 2018-04-13 16:44:58 +03:00
a8443a3813 Switch builds to use prebuilt mailpoet/wordpress images 2018-04-13 13:36:03 +03:00
40526dd083 Fixes ESLint rule and updates variable names 2018-04-12 20:00:36 -04:00
cb648da677 Adds hook to filter each listings item 2018-04-11 23:20:07 -04:00
ea0676718e Filters data before other logic 2018-04-11 23:11:41 -04:00
f5cc1cfe3a Removes unused disabled flag 2018-04-11 22:30:45 -04:00
1cc28eb607 Splits send method into smaller chunks 2018-04-11 19:50:48 -04:00
f019eaf38e Filters newsletters by type and, if available, type group 2018-04-11 19:03:04 -04:00
ce45c8c553 Uses templatesCategory object to check for template category existenc]e 2018-04-11 19:03:04 -04:00
9b4e49123d Moves variable definition into the method that uses them 2018-04-11 19:03:04 -04:00
b2685f7591 Passes default breadcrumb to hook 2018-04-11 19:03:04 -04:00
7a3749e043 Fixes 'object-shorthand' lint rule 2018-04-11 19:03:04 -04:00
dbbb3862bc Adds hooks to return to custom URL after activating/sending email 2018-04-11 19:03:04 -04:00
a1009eff0d Corrects formatting of send event and other strings 2018-04-11 19:03:04 -04:00
3096c9a0ab Updates CSS rule to match data type that contains "woocommerce" 2018-04-11 19:03:04 -04:00
e93fc41281 Allows limiting listings query of automatic emails to specific group 2018-04-11 19:03:04 -04:00
adbebb39f1 Adds automatic email type to newsletter model/API listing method 2018-04-11 19:03:03 -04:00
4955673885 Exposes components needed for automatic emails listings 2018-04-11 19:03:03 -04:00
972e470d28 Adds hook to extend listings tabs 2018-04-11 19:03:03 -04:00
f1effc30ba Adds hooks to override send action and response 2018-04-11 19:03:03 -04:00
8728a69e69 Adds hooks to display fields for custom newsletter types 2018-04-11 19:03:03 -04:00
5383d16c22 Allows grabbing selection text/value pair 2018-04-11 19:03:03 -04:00
26f2630e1a Allows disabling input 2018-04-11 19:03:03 -04:00
98ac4d5508 Adds hook to change breadcrumbs 2018-04-11 19:03:03 -04:00
e4f417f595 Adds hook to extend editor view 2018-04-11 19:03:03 -04:00
bfaec09939 Adds hook to extend editor config 2018-04-11 19:03:03 -04:00
585f9bcc92 Extracts editor initialization and bundles with admin vendor
Allows displaying custom breadcrumbs based on email type
2018-04-11 19:03:03 -04:00
e7d7674e0e Displays loading screen before rendering page
Adds hook to change breadcrumbs

(cherry picked from commit 9bdb29b5bd959b24347625b2c87349d9173a05ca)
2018-04-11 19:03:02 -04:00
ba38c55e1f Uses "standard" templates for "automatic" email types
(cherry picked from commit 3c09c14524a663cc341cd6de7652cb2f23421a44)
2018-04-11 19:03:02 -04:00
3e432d7b5d Changes method visibility to allow extending class 2018-04-11 19:03:02 -04:00
afefa89466 Ensures that queues are instance of the scheduled task class 2018-04-11 18:58:29 -04:00
cb80b5ca69 Stops returning empty values when getting scheduled/running queues 2018-04-11 18:27:33 -04:00
8f6ae91924 Updates changelog and bumps up release version to 3.6.5 2018-04-10 10:46:14 -04:00
2bba10127d Merge pull request #1323 from mailpoet/fix-slow-hosts
Fix sending big emails on slow hosts [MAILPOET-1322]
2018-04-10 09:17:29 -04:00
586f6943e1 Merge pull request #1321 from mailpoet/fix-beacon
Fix beacon [MAILPOET-1343]
2018-04-09 09:48:34 -04:00
10ee48076a Merge pull request #1309 from mailpoet/export-segments
Export segments [PREMIUM-68]
2018-04-09 08:09:16 -04:00
ee04044676 Merge pull request #1324 from mailpoet/html2text_update
Updates html2text fork and composer references [MAILPOET-1337]
2018-04-09 05:35:28 -04:00
63022ccad7 Updates html2text fork and composer references 2018-04-08 11:32:49 -04:00
51d97ddda8 Fix sending on slow hosts
[MAILPOET-1322]
2018-04-06 22:09:07 -04:00
e8f55493d0 Merge pull request #1322 from mailpoet/revert-1320-fix-slow-hosts
Revert "Fix sending big emails on slow hosts [MAILPOET-1322]"
2018-04-06 22:03:03 -04:00
baab0840b7 Revert "Fix sending big emails on slow hosts [MAILPOET-1322]" 2018-04-06 22:00:45 -04:00
31c3907c8f Merge pull request #1320 from mailpoet/fix-slow-hosts
Fix sending big emails on slow hosts [MAILPOET-1322]
2018-04-06 21:55:27 -04:00
75a1c5f95b Fix beacon
[MAILPOET-1343]
2018-04-06 11:05:02 +01:00
66b5aeb578 Fix sending on slow hosts
[MAILPOET-1322]
2018-04-06 10:23:52 +01:00
18c90fed07 release 3.6.4 2018-04-03 13:52:35 +01:00
06dac13327 Merge pull request #1300 from mailpoet/archive-page-subject
Api/newsletter: Re-render email in queue on save  [MAILPOET-1305]
2018-04-03 13:46:10 +03:00
7c47b81569 fixing subscribers count 2018-04-02 17:07:15 +02:00
c25d4d4943 fix minors issues 2018-04-02 16:00:34 +02:00
d6749a591f release 3.6.3 2018-03-28 14:51:20 +00:00
251198cf9c Merge pull request #1317 from mailpoet/scheduled_sending_fix
Fixes issues associated with scheduling/rescheduling of newsletters [MAILPOET-1338]
2018-03-28 14:57:26 +03:00
ffb6243614 Merge pull request #1318 from mailpoet/segment-newsletters-fix
Fix segments newsletters sending [MAILPOET-1340]
2018-03-28 07:52:46 -04:00
0d11416f4e Ignore duplicities when adding subscribers tasks
[MAILPOET-1340]
2018-03-28 08:34:27 +01:00
662b033677 api/newsletters: Re-render newsletter with queue on save [MAILPOET-1305] 2018-03-27 19:24:59 +02:00
0d514a8084 Do not save defaults for containers 2018-03-26 14:22:55 +01:00
1756df0085 Fix segments newsletters sending
[MAILPOET-1340]
2018-03-26 13:59:29 +01:00
986cce4a92 Adds unit tests 2018-03-24 13:33:18 -04:00
a0947611fb Fixes the rescheduling of sending tasks 2018-03-24 11:36:00 -04:00
18a6a1c439 Removes call to method that marks sending queue task as complete
When sending queue is added, subscriber count is always 0 and
subscribers list is null. To that end, the removed code had no effect
and only introduced an issue.
2018-03-22 20:16:35 -04:00
eb4d2ab829 Release 3.6.2 2018-03-21 14:21:03 +02:00
cdc6d8a966 Merge pull request #1314 from mailpoet/add-index
Add index to task_id [MAILPOET-1334]
2018-03-21 13:39:41 +02:00
139354f3e6 Merge pull request #1315 from mailpoet/migration_task
Fix migration task to be done only when one hasn't been done [MAILPOET-1333]
2018-03-21 13:39:24 +02:00
37f70b900d Fix DB migration 2018-03-21 11:29:54 +02:00
511e07455f Fix migration task to be done only when one hasn't been done
[MAILPOET-1333]
2018-03-21 11:21:23 +02:00
d28b4fda58 Add index to task_id
[MAILPOET-1334]
2018-03-21 08:26:32 +00:00
09081631a4 Release 3.6.1 2018-03-20 23:20:34 +02:00
618723b2bf Merge pull request #1313 from mailpoet/migration_task_scheduling_fix
Uses WP time to schedule migration task [MAILPOET-1331]
2018-03-20 23:13:53 +02:00
5cb39b9bf9 Removes comment that triggers a lint warning 2018-03-20 16:41:36 -04:00
467cf350e9 Abstract WP's current_time() function in the code base 2018-03-20 16:34:50 -04:00
d317eb4fbd Adds unit test 2018-03-20 16:30:28 -04:00
44b96aa9a7 Uses WP time to schedule migration task 2018-03-20 15:48:21 -04:00
3b4edd5c95 Release 3.6.0 2018-03-20 16:30:01 +02:00
a5782a32bc Merge pull request #1310 from mailpoet/tracked_url_shortcodes
Processes shortcodes in tracked URLs [MAILPOET-1329]
2018-03-20 15:10:34 +02:00
a3cabad752 Merge pull request #1268 from mailpoet/sending_queue_refactoring
Refactor sending queues to use scheduled task and task subscriber tables [MAILPOET-903]
2018-03-20 08:47:26 -04:00
16b2b73727 Merge pull request #1307 from mailpoet/eslint6-4
Eslint6 4 [MAILPOET-1140]
2018-03-20 12:16:11 +01:00
c1f5bf9836 Declare depenency directly
[MAILPOET-1140]
2018-03-20 10:50:56 +00:00
5e49624685 Merge pull request #1306 from mailpoet/poll-update
Update polls [MAILPOET-1327] [MAILPOET-1302]
2018-03-19 17:41:13 +01:00
985e3a9a68 Merge pull request #1303 from mailpoet/automatic-block-defaults
Widgets in designer: save previous settings [MAILPOET-1304]
2018-03-19 12:42:46 +02:00
58f92045c0 Processes shortcodes in tracked URLs 2018-03-16 13:00:34 -04:00
82ec8d7ef9 adding tests 2018-03-16 15:31:29 +01:00
1af242c2dd adding subscribers getter from dynamic segments 2018-03-15 19:04:25 +01:00
8f9299afe3 Merge pull request #1308 from mailpoet/expiring-message-fix
Make message clearer [MAILPOET-1321]
2018-03-15 16:10:59 +02:00
7775b5ace3 Make message clearer
[MAILPOET-1321]
2018-03-15 13:48:09 +00:00
78f9fea2b0 Sends welcome notifications when subscribing to lists via MP's API
[MAILPOET-1295]
2018-03-15 13:04:30 +00:00
783f33b092 Fix eslint6 object-shorthand
[MAILPOET-1140]
2018-03-15 11:55:57 +00:00
d3250030ba Fix eslint6 func-names
[MAILPOET-1140]
2018-03-15 11:55:03 +00:00
9e685efd41 Fix eslint6 jsx-a11y/alt-text
[MAILPOET-1140]
2018-03-15 11:28:20 +00:00
756367dd50 Fix eslint6 jsx-a11y/no-static-element-interactions
[MAILPOET-1140]
2018-03-15 11:19:48 +00:00
b5a322a8e1 Fix eslint6 jsx-a11y/label-has-for
[MAILPOET-1140]
2018-03-15 10:56:31 +00:00
3f219379d5 Fix eslint6 react/no-string-refs
[MAILPOET-1140]
2018-03-15 10:47:03 +00:00
4037800c10 Fix eslint6 react/prefer-stateless-function
[MAILPOET-1140]
2018-03-15 10:44:13 +00:00
7144d4afa8 Fix eslint6 react/no-did-mount-set-state
[MAILPOET-1140]
2018-03-15 10:28:50 +00:00
658cdd37ac editor: Communication fix removed since bb.radio is in marionette since 3.0 2018-03-15 11:23:55 +01:00
05dcaeba76 editor: Store and load blockDefaults in newsletter data 2018-03-15 11:23:55 +01:00
fbfcfcc85b editor: Save button, divider defaults by its context of usage 2018-03-15 11:23:55 +01:00
8582c19ac0 editor: Update block defaults for ALC changes 2018-03-15 11:23:55 +01:00
5e35a724f0 editor: Fixed posts setting sellection view context and behavior 2018-03-15 11:23:55 +01:00
c7e83377ba editor: Update blockDefaults for posts on change 2018-03-15 11:23:55 +01:00
f6374d0602 editor: Update defaults in social block and use stored defaults for new social block 2018-03-15 11:23:54 +01:00
1df25aef76 editor: Disable update blockDefaults for texts and images 2018-03-15 11:23:54 +01:00
3a8b64e11c editor: Omit text property from block defaults for header and footer 2018-03-15 11:23:54 +01:00
1d9b4839f7 editor: Update config blockDefaults by latest used value per type 2018-03-15 11:23:54 +01:00
1c5a0bb5bd editor: Unified default config styles basic, post and ALC buttons 2018-03-15 11:23:54 +01:00
eca7de854d Fix eslint6 react/no-string-refs
[MAILPOET-1140]
2018-03-15 09:56:27 +00:00
0adaf22eef Fix eslint6 react/self-closing-bracket-location
[MAILPOET-1140]
2018-03-15 09:32:48 +00:00
c39aeb6283 Fix eslint6 react/self-closing-comp
[MAILPOET-1140]
2018-03-15 09:31:41 +00:00
7528aba2ef Update poll
[MAILPOET-1327]
2018-03-15 08:57:25 +00:00
c3fff8ddbe Update poll for new users
[MAILPOET-1302]
2018-03-15 08:52:44 +00:00
ca9e11a231 using apply_filters 2018-03-14 15:00:57 +01:00
4177701044 Merge pull request #1282 from mailpoet/screenshot
fixing the screenshot issue [MAILPOET-1276]
2018-03-14 12:52:29 +02:00
65a201c848 Bumps up release version and updates changelog 2018-03-13 20:16:03 -04:00
1c4b6a9ab6 Merge pull request #1304 from mailpoet/segment-admin-fix
Not pass undefined as default value for select [PREMIUM-72]
2018-03-13 18:17:09 -04:00
9173b114a7 Merge pull request #1301 from mailpoet/call-for-rating
Call for rating [MAILPOET-1299]
2018-03-13 19:21:39 +01:00
cd6828d19e Not pass undefined as default value for select
[PREMIUM-72]
2018-03-13 15:52:00 +00:00
1c021ac0a0 fixing chrome conflict 2018-03-13 16:09:39 +01:00
4469cef647 Fixes cast statement format 2018-03-13 11:28:25 +00:00
057f0376a5 Adds unit test 2018-03-13 11:28:25 +00:00
7e6b29896f Removes type check given that Newsletter model object is not persisted 2018-03-13 11:28:25 +00:00
4c4f6be59b Passes object as value instead of reference 2018-03-13 11:28:25 +00:00
669d072853 Not show call for rating if user already clicked
[MAILPOET-1299]
2018-03-12 11:36:19 +00:00
1033c1c1cf fixing width by removing scrollbar 2018-03-12 12:14:10 +01:00
330067c3f2 Save user clicked on rating button
[MAILPOET-1299]
2018-03-12 11:14:10 +00:00
9a942a0bd9 Merge pull request #1299 from mailpoet/sync-segments-collation-error
Sync segments collation error
2018-03-11 20:28:54 -04:00
b9c31698d5 moving subscribers fetching logic into a separated class. 2018-03-08 18:01:56 +01:00
d079002b09 Subscribers import: Step1 also uses the email regexp to validate emails [MAILPOET-1288] 2018-03-08 11:44:07 +01:00
cca4fc02c0 adding dynamic segments to export options 2018-03-07 15:14:29 +01:00
77248e6890 Ask for rating
[MAILPOET-1299]
2018-03-07 13:27:21 +00:00
755179e0d1 segments/migrate: Avoiding collation error in subscribers sync MAILPOET-1288 2018-03-06 21:17:16 +01:00
46493b991c Checking invalid emails on the input [MAILPOET-1288] 2018-03-06 19:54:44 +01:00
2f05eaf528 Release 3.5.0 2018-03-06 14:36:30 +00:00
f7397d04ed Merge pull request #1298 from mailpoet/revert-1290-invalid-email-MAILPOET-1288
Revert "Checking invalid emails on the input [MAILPOET-1288]"
2018-03-06 15:47:50 +02:00
3d43970fdc Revert "Checking invalid emails on the input [MAILPOET-1288]" 2018-03-06 13:24:42 +00:00
92864c2d4f Merge pull request #1296 from mailpoet/stats_badges_css_fix
Fixes word-wrapping of stats badges [MAILPOET-1323]
2018-03-06 14:57:43 +02:00
41e028c0d4 Merge pull request #1297 from mailpoet/polyfill
adding polyfill for `mb_detect_order` [MAILPOET-1303]
2018-03-06 07:52:46 -05:00
cfbf29b60a Merge pull request #1290 from mailpoet/invalid-email-MAILPOET-1288
Checking invalid emails on the input [MAILPOET-1288]
2018-03-06 07:50:21 -05:00
a5137c8d62 adding polyfill for mb_detect_order 2018-03-06 12:15:18 +01:00
aceb9bb031 Hardened UI email address check MAILPOET-1288 2018-03-06 09:51:41 +01:00
8bc0ad48c0 Email valiation added to reply-to on newsletter send screen 2018-03-06 09:50:55 +01:00
449568b37b Refactor JS email regexp to be accessible from every page MAILPOET-1288 2018-03-06 09:48:39 +01:00
c164066522 Check valid filled email addresses in plugin settings MAILPOET-1288 2018-03-06 09:15:48 +01:00
5c10a66444 Subscribers import: Email validation unified with subscribers sync MAILPOET-1288 2018-03-06 09:15:48 +01:00
afed408297 Synchronize segments removes updated/inserted subscribers with invalid emails MAILPOET-1288 2018-03-06 09:15:37 +01:00
6e7c7ae8c8 modelValidator: Add more strict Sudzy email validation next to is_email check MAILPOET-1288 2018-03-06 09:06:57 +01:00
d3f9fb5f06 fixing url 2018-03-05 18:51:52 +01:00
53b4a7ba31 Isolates white-space rule to badges displayed in boxes 2018-03-05 12:50:51 -05:00
39212a30e8 Merge pull request #1293 from mailpoet/redirect-to-404-403-MAILPOET-782
Show WP's 404/403 page instead of displaying a blank page [MAILPOET-782]
2018-03-05 11:16:43 -05:00
7c7e5bbaa6 Merge pull request #1292 from mailpoet/fixed-bulk-add-subscribers-created-at-MAILPOET-1311
Fixed created_at in bulk add action in subscribers [MAILPOET-1311]
2018-03-05 14:34:48 +01:00
831804d35e Fix eslint no-useless-escape in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
9af98f0afb Fix eslint no-empty in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
5b96789e04 Fix eslint no-console in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
3b2355d570 Fix eslint no-redeclare in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
fa44127efa Fix eslint no-new in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
86e01ce5de Fix eslint new-cap in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
981e4a56e3 Fix eslint new-cap in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
d89eb07b3c Fix eslint array-callback-return in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
e4b79616ee Fix eslint no-sequences in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
21e45a39b4 Fix eslint no-sequences in es5 files
[MAILPOET-1146]
2018-03-05 10:41:31 +01:00
b7e492e20e endpoints/track: Exit with 403 code and eventually display 403 page when subscriber token doesn't match [MAILPOET-782] 2018-03-03 16:46:01 +01:00
c2c74d7524 Show default WP 404 when aborting link with 404 code [MAILPOET-782] 2018-03-03 16:45:41 +01:00
4d80bdb322 Merge pull request #1287 from mailpoet/dynamic-segments-bulk
Handle bulk operations on subscribers filtered by dynamic segments [PREMIUM-69]
2018-03-02 16:59:33 +02:00
a58a3c9574 Fixed created_at date in bulk add action in subscribers list [MAILPOET-1311] 2018-03-02 13:52:29 +01:00
734d1ded1f Check processed subscribers for old and new queues differently [MAILPOET-903] 2018-03-01 21:17:51 +03:00
e0f989f6a8 Revert "Migrate subscribers for all tasks types [MAILPOET-903]"
This reverts commit f1f69c9835.
2018-03-01 21:17:40 +03:00
2265de454e Updates KB link and tip language 2018-03-01 08:50:14 +00:00
381fc76d52 Adds description with KB link 2018-03-01 08:50:14 +00:00
32fdc11c88 Adds glabal status to default export fields 2018-03-01 08:50:14 +00:00
99edc35b08 Handle bulk operations on subscribers filtered by dynamic segments
[PREMIUM-69]
2018-02-28 17:12:56 +00:00
66fa22d489 Merge pull request #1285 from mailpoet/am_display_events_chunk2
Makes necessary changes to enable the display of automatic emails [PREMIUM-65] [PREMIUM-63]]
2018-02-28 18:21:36 +02:00
f1f69c9835 Migrate subscribers for all tasks types [MAILPOET-903] 2018-02-28 11:21:23 +03:00
a6f8953bd3 Make migration mailer notice clearer [MAILPOET-903] 2018-02-28 10:26:29 +03:00
8b25acf82c Updates component's name 2018-02-27 16:43:41 -05:00
a9b40802a9 Uses 'slug' instead of 'id' for newsletter types 2018-02-27 16:43:41 -05:00
9eda024b02 release 3.4.4 2018-02-27 17:28:52 +00:00
003ddc3b92 Merge pull request #1281 from mailpoet/fix-mixpanel-segments
Fix analytics reporting on segments [MAILPOET-1279]
2018-02-27 10:44:29 +01:00
b381923903 Add a comment about adding large batches of subscribers [MAILPOET-903] 2018-02-27 11:39:24 +03:00
8837c9e14c Merge pull request #1284 from mailpoet/default-selection
Make sure preselected value is active [PREMIUM-59]
2018-02-26 16:48:41 +02:00
8cd83575f2 Make sure preselected value is active
[PREMIUM-59]
2018-02-26 14:04:42 +00:00
03015c0bde Fix code review syntax remarks [MAILPOET-903] 2018-02-26 16:30:53 +03:00
6b36156db5 Merge pull request #1283 from mailpoet/subscriber-to-list-migrate-fix-MAILPOET-1285
MP2Migration: Fixed null updated_at error in importSubscriberSegment [MAILPOET-1285]
2018-02-26 14:31:54 +02:00
4ed39c9620 Code fix
[MAILPOET-1279]
2018-02-26 09:36:55 +00:00
f210b15652 MP2Migration: Fixed null updated_at error by fallback to created_at in importSubscriberSegment MAILPOET-1285 2018-02-23 20:22:21 +01:00
ef5d777fac fixing tests 2018-02-23 15:23:37 +01:00
ab2b380f2d fixing the screenshot issue 2018-02-22 17:27:49 +01:00
c3f974a3c0 Make code compatible with 5.3 :(
[MAILPOET-1279]
2018-02-21 14:17:27 +00:00
2c020bf283 Fix analytics reporting on segments
[MAILPOET-1279]
2018-02-21 13:30:29 +00:00
17e13c0956 Merge pull request #1276 from mailpoet/post-labels-fix
Display only terms with labels [MAILPOET-1292]
2018-02-20 20:19:30 -05:00
52a6c4f701 Merge pull request #1277 from mailpoet/eslint-es5-3
Eslint es5 3  [MAILPOET-1145]
2018-02-20 17:27:33 +01:00
f09ad47911 bind methods in the constructor 2018-02-20 13:11:45 +00:00
0da2be21c8 fix code style issues 2018-02-20 13:11:45 +00:00
8603e2a96a seperating components into multiple files 2018-02-20 13:11:45 +00:00
ddbabcfcb5 don't show "No items" when loading 2018-02-20 13:11:45 +00:00
92f733d30d rename function to getEditorUrl 2018-02-20 13:11:45 +00:00
93a67e6882 make callbacks props consistent and generic 2018-02-20 13:11:45 +00:00
86aff26d5f fixing code quality 2018-02-20 13:11:45 +00:00
cfc425dfd7 sort templates by id desc 2018-02-20 13:11:45 +00:00
57b2c577c6 add imported templates to "Your saved templates"
select "Your saved templates" after importing a template
removing template from all categories when deleted
2018-02-20 13:11:45 +00:00
be4224411f refactoring the code and move import form to separate tab 2018-02-20 13:11:45 +00:00
b2fa79fcbf Release 3.4.3 2018-02-20 13:48:59 +02:00
1d3102e54b Merge pull request #1278 from mailpoet/new-poll
New poll [MAILPOET-1300]
2018-02-20 12:59:56 +02:00
847916eb1f New poll
[MAILPOET-1300]
2018-02-20 10:44:39 +00:00
adb579a26c Fix code issues
[MAILPOET-1145]
2018-02-20 09:39:14 +00:00
16607dd4be Merge pull request #1270 from mailpoet/woo-category
Allow select2 to be destroyed and re-rendered [PREMIUM-60]
2018-02-19 17:56:10 +01:00
485c6008c1 Merge pull request #1274 from mailpoet/segment-style
Update forms errors style [MAILPOET-1278]
2018-02-19 17:53:22 +01:00
8f9a0239b1 Allow select2 to be destroyed and re-rendered
[PREMIUM-60]
2018-02-19 16:19:13 +00:00
989baf2aa4 Fix eslint wrap-iife in es5 files
[MAILPOET-1145]
2018-02-19 16:09:27 +00:00
de91c90ac2 Fix eslint no-plusplus in es5 files
[MAILPOET-1145]
2018-02-19 16:08:29 +00:00
e10901d939 Fix eslint default-case in es5 files
[MAILPOET-1145]
2018-02-19 15:58:25 +00:00
426a72c557 Fix eslint no-lonely-if in es5 files
[MAILPOET-1145]
2018-02-19 15:54:19 +00:00
704e4e40f7 Fix eslint no-mixed-operators in es5 files
[MAILPOET-1145]
2018-02-19 15:51:01 +00:00
0ff9c006d8 Fix eslint eqeqeq in es5 files
[MAILPOET-1145]
2018-02-19 15:43:58 +00:00
f7fcec7953 Fix eslint max-len in es5 files
[MAILPOET-1145]
2018-02-19 15:17:57 +00:00
e484705ac1 Fix eslint errors and warnings
[MAILPOET-1145]
2018-02-19 13:40:01 +00:00
6a8337c67d Fix eslint errors and warnings
[MAILPOET-1145]
2018-02-19 13:23:09 +00:00
f98e58eb99 Fix eslint no-extra-bind
[MAILPOET-1145]
2018-02-19 13:05:43 +00:00
476af99130 Display only terms with labels
[MAILPOET-1292]
2018-02-19 11:59:41 +00:00
0d69b05ac0 Removes option to group by lists during export 2018-02-19 09:53:34 +00:00
e0052bbb93 Sanitize correct cron ping response [MAILPOET-1291] 2018-02-16 18:06:41 +00:00
b5b0a02ea4 Removes option to export only confirmed subscribers 2018-02-16 14:46:34 +00:00
3c43c04586 Imports all new subscribers with subscribed status as default 2018-02-16 14:46:34 +00:00
e87134eca4 Adds IP address field to export 2018-02-16 14:46:34 +00:00
c8f334d782 Prevents overwriting global subscription status 2018-02-16 14:46:34 +00:00
7cf63965a0 Adds distinction between global and list status
Exports subscribers with any list status
Limits "confirmed only" option to global status
2018-02-16 14:46:34 +00:00
eb3cf66958 Update forms errors style
[MAILPOET-1278]
2018-02-16 13:46:08 +00:00
ba306ecf66 Merge pull request #1271 from mailpoet/tooltip-fix
Update incorrect tooltip [MAILPOET-1274]
2018-02-15 18:30:38 +01:00
a58151fee6 Update incorrect tooltip
[MAILPOET-1274]
2018-02-15 14:50:42 +00:00
9eb20f96b2 Merge pull request #1263 from mailpoet/am_display_events_chunk2
Adds necessary changes in order to display automatic events in Free and Premium [PREMIUM-65] [PREMIUM-63]
2018-02-14 12:41:06 -05:00
57f00bbe0c Merge pull request #1267 from mailpoet/MAILPOET-1263-force-alc-for-notifications
[MAILPOET-1263] Force user to create ALC block for post notification
2018-02-14 19:28:19 +02:00
287c89749d Removes WooCommerce events until we're ready to release them 2018-02-14 12:20:32 -05:00
b9546b61a8 Fix acceptance tests, update counters [MAILPOET-903] 2018-02-14 19:57:14 +03:00
606177baaf Fix daemon ping timeout in tests [MAILPOET-903] 2018-02-14 01:29:14 +03:00
b7704c90e8 [MAILPOET-1263] Fixed inconsistency in type of body property on newsletter json after saving and little bit more strict validation check 2018-02-13 23:01:34 +01:00
9d4f996a6a [MAILPOET-1263] Force user to create ALC block for post notification 2018-02-13 23:01:29 +01:00
774e8d94b5 Displays automatic email types and events
Adds WooCommerce email type for testing purposes
2018-02-13 14:43:19 -05:00
4ffadc990e Exposes components necessary for displaying events' scheduling options 2018-02-13 14:41:30 -05:00
8ab2cd75c0 Prevents line breaks when badge has multiple words 2018-02-13 14:41:30 -05:00
d59ebbbc57 Allows dynamically changing breadcrumbs 2018-02-13 14:41:30 -05:00
84638b2818 Passes element id to the onChange callback 2018-02-13 14:41:30 -05:00
a8305adf8d Allows setting custom id and class 2018-02-13 14:41:30 -05:00
243ed9d61b Prevents error when item prop is not set
Allows setting custom value and defaultValue
2018-02-13 14:41:30 -05:00
84dfa88a1a Don't load subscriber IDs in memory when preparing tasks from static segments [MAILPOET-903] 2018-02-13 20:36:01 +03:00
f9204f289f Updates changelog and bumps up version to 3.4.2 2018-02-13 12:33:19 -05:00
408b64dc0d Merge pull request #1264 from mailpoet/preview-link
fixing the preview link issue with https [MAILPOET-1296]
2018-02-13 17:01:01 +03:00
83b24f053e Fix spelling in a string [MAILPOET-1296] 2018-02-13 16:35:12 +03:00
9acef55352 fixing the preview link issue with https 2018-02-13 09:56:46 +00:00
4c0f5bb456 Add new unit tests [MAILPOET-903] 2018-02-13 11:39:50 +03:00
be6647d763 Fix unit tests [MAILPOET-903] 2018-02-13 11:39:50 +03:00
99732ac14d Remove beta migrations [MAILPOET-903] 2018-02-13 11:39:50 +03:00
0b17a1099b Bring back a check from MAILPOET-1261 (was omitted during rebase) 2018-02-13 11:39:50 +03:00
c0c57f6b67 Sending queue refactoring WIP [MAILPOET-903] 2018-02-13 11:39:50 +03:00
bf8b0c81df Merge pull request #1262 from mailpoet/recently-sent-templates
limitting the recently sent templates to 12 [MAILPOET-1265]
2018-02-13 11:28:42 +03:00
d82e3a25ac Merge pull request #1260 from mailpoet/get-terms-filter
Use filter for getTerms search [MAILPOET-1293]
2018-02-13 03:03:39 +03:00
98ed295896 Merge pull request #1261 from mailpoet/refactoring-models
refactoring createOrUpdate method of models [MAILPOET-1294]
2018-02-12 13:59:26 +02:00
b076e03a75 using static instead of self
renaming `internalCreateOrUpdate` to `_createOrUpdate`
renaming `$conditions` to `$keys`
adding block comment for `_createOrUpdate` method.
2018-02-12 11:15:46 +00:00
a754cfaa52 limitting the recently sent templates to 12 2018-02-09 16:43:40 +00:00
3721694f4d Merge pull request #1259 from mailpoet/empty-trash-msg
"Empty Trash" now shows the correct notice message [MAILPOET-1289]
2018-02-09 09:36:41 -05:00
91622f8cd9 refactoring createOrUpdate method of models 2018-02-07 18:10:49 +00:00
4a3ba73406 Use filter for getTerms search
[MAILPOET-1293]
2018-02-07 12:58:00 +00:00
ab3a2f064f "Empty Trash" now shows the correct notice message 2018-02-06 14:35:37 +00:00
a2270d6689 Release 3.4.1 2018-02-06 13:23:16 +00:00
e09acbe649 Merge pull request #1258 from mailpoet/stats-segmentation
Return error code for duplication errors [PREMIUM-42]
2018-02-05 21:10:54 -05:00
b54f002635 Merge pull request #1254 from mailpoet/am_display_events_chunk1
Makes necessary changes for automatic emails feature to work [PREMIUM-63]
2018-02-05 17:48:23 +02:00
aaaf49d071 Merge pull request #1256 from mailpoet/bugfix
fixing Segment::bulkDelete not deleting subscribers assiciations [MAILPOET-1287]
2018-02-05 17:53:04 +03:00
8ff28fd974 Return error code for duplication errors
[PREMIUM-42]
2018-02-05 14:34:15 +00:00
126b37f2bb Merge pull request #1257 from mailpoet/scheduled_emails_to_dynamic_segments_fix
Fix sending of scheduled standard emails to dynamic segments [MAILPOET-1286]
2018-02-05 11:25:30 +01:00
bebd835790 Merge pull request #1253 from costasovo/jsdom-upgrade
js-tests: jsdom upgrade
2018-02-05 10:56:16 +01:00
9526a6b470 Fix sending of scheduled standard email to dynamic segments [MAILPOET-1286] 2018-02-02 19:19:49 +03:00
7eb8ff756b fixing Subscriber::bulkDelete not deleting subscribers assiciations 2018-02-02 12:43:34 +00:00
9159e8d21d Merge pull request #1249 from mailpoet/stats-segmentation
Stats segmentation [PREMIUM-42]
2018-02-01 20:34:39 -05:00
f4ba45490d Corrects identation 2018-02-01 18:27:57 -05:00
9f9b44fd7e Adds a method that cleans up after Select2 2018-02-01 18:26:30 -05:00
ae9f373cff Removes state and updates method to test if Select2 is initialized 2018-02-01 17:53:16 -05:00
80a3bbd030 Changes method name to get selection items 2018-02-01 17:46:26 -05:00
aba75849e1 Standardizes placeholder and border colors for Select2 elements 2018-02-01 08:59:12 -05:00
874a37303a Exposes Selection form field 2018-02-01 08:59:12 -05:00
f467479438 Allows overriding Select2 options 2018-02-01 08:59:12 -05:00
bb76a8c6aa Cleans up DOM elements manually added by Select2 and not tracked by
React
2018-02-01 08:59:12 -05:00
63000c48c4 Allows reinitializing Select2 upon component rerender 2018-02-01 08:59:12 -05:00
b88dec06d9 Adds getter for field ID 2018-02-01 08:59:11 -05:00
a0667adace Prevents component from rerendering when Select2 is initialized 2018-02-01 08:59:11 -05:00
fef8017134 Loads select items before render 2018-02-01 08:59:11 -05:00
87de314c18 Adds option to query remote source for data 2018-02-01 08:59:11 -05:00
c8a20ec4ae Merge pull request #1252 from mailpoet/templates
filtering unknown templates categories [MAILPOET-1281]
2018-02-01 14:44:19 +02:00
9739159a6f Merge pull request #1251 from mailpoet/test
Fix acceptance tests flakiness [MAILPOET-1284]
2018-02-01 14:31:41 +02:00
0aa4c37ad3 js-tests: jsdom upgrade 2018-01-31 23:44:12 +01:00
2c8c8b3d0e filtering unknown templates categories 2018-01-31 16:04:28 +00:00
12434b412f Add code comment 2018-01-31 10:30:33 +00:00
789c2a7d4e Wait before login 2018-01-31 09:41:15 +00:00
907356bb0f Wait for login field to be loaded 2018-01-31 09:15:20 +00:00
8800799234 Bump up release version to 3.4.0 2018-01-30 22:21:01 +03:00
9c2aa569ea After login ensure MailPoet present on the page 2018-01-30 15:39:30 +00:00
9ee6920ebb Use our login function 2018-01-30 15:03:03 +00:00
5d8d9567c7 Merge pull request #1234 from mailpoet/tempales-categories
Add template categorization [MAILPOET-1159]
2018-01-30 16:20:01 +02:00
5bddc79576 generating thumb for all newsletter types 2018-01-30 13:51:03 +00:00
e2f23df829 close loading modal 2018-01-30 13:26:51 +00:00
43fbbca050 moving width to css 2018-01-30 12:49:51 +00:00
5109bc3922 Merge pull request #1250 from mailpoet/new-poll
Add a new poll [MAILPOET-1275]
2018-01-30 13:01:58 +02:00
65b4aeffc8 Add a new poll
[MAILPOET-1275]
2018-01-30 10:38:28 +00:00
17a25120d4 Add conflict HTTP code
[PREMIUM-42]
2018-01-30 10:16:12 +00:00
cb055a2b06 Allow extra action buttons in filter rows
[PREMIUM-42]
2018-01-29 15:37:52 +00:00
7361613bba minor fixes 2018-01-29 15:30:17 +00:00
a8f33d9a7e Merge pull request #1248 from mailpoet/update-name
Update plugin name [MAILPOET-1272]
2018-01-26 11:44:52 +03:00
c497a72aab Update plugin name
[MAILPOET-1272]
2018-01-25 15:48:11 +00:00
d0f55a1d1b Merge pull request #1247 from mailpoet/revert-dotdeb
Revert "Use alternative dotdeb mirror" [MAILPOET-1262]
2018-01-25 11:26:50 +03:00
3b92caf677 Merge pull request #1246 from mailpoet/segment-sending-fix
Fix segments sending [MAILPOET-1270]
2018-01-24 22:21:32 -05:00
d3c64810a8 Merge pull request #1243 from mailpoet/subscribers_strict_mode_fix
Fix a fatal error when creating a subscribers table in MySQL strict mode [MAILPOET-1268]
2018-01-24 22:19:55 -05:00
f85a169248 Revert "Use alternative dotdeb mirror"
This reverts commit a4af2b9c65.
2018-01-24 16:22:36 +00:00
2dd08c6820 Fix segments sending
[MAILPOET-1270]
2018-01-24 15:30:52 +00:00
d7609f48d4 Merge pull request #1244 from mailpoet/import
Normalizing emails during the import to avoid integrity constraint violation [MAILPOET-1271]
2018-01-23 19:35:45 +03:00
1d02c688a2 releasing 3.3.6 2018-01-23 15:16:36 +00:00
37c58c6aa4 Add a comment about testing normalization [MAILPOET-1271] 2018-01-23 18:08:13 +03:00
4abd034880 normalizing emails in lowercase 2018-01-23 13:46:10 +00:00
e8c7584b9b Fix a fatal error when creating a subscribers table in MySQL strict mode [MAILPOET-1268] 2018-01-23 15:59:20 +03:00
be3eb0a7ff Add 2 polls for new and old users respectively
[MAILPOET-1266]
2018-01-23 12:26:06 +00:00
eee01ee3f1 Merge pull request #1240 from mailpoet/acceptance-multisite
Execute acceptance tests on multisites [MAILPOET-1193]
2018-01-22 18:35:41 -05:00
56ad9a8976 Merge pull request #1241 from mailpoet/am_display_available_groups
Makes necessary changes for automatic emails feature to work [PREMIUM-55]
2018-01-22 15:41:47 +02:00
20d0ed1aac fixing js tests 2018-01-22 11:36:46 +00:00
f42b61a49e fixing unit test 2018-01-22 11:03:32 +00:00
5e152e920e fix screenshots 2018-01-22 11:03:31 +00:00
0d26b62416 minor fixes 2018-01-22 11:03:31 +00:00
8e60b2b317 renaming and modifying categories 2018-01-22 11:01:20 +00:00
cae46d9acd fixed duplicated templates when scheduling/sending same newsletter twice 2018-01-22 11:01:19 +00:00
bfad5509c1 fixed acceptance test 2018-01-22 11:01:19 +00:00
3ae7b436de returning preview url in meta 2018-01-22 11:01:19 +00:00
30b2eda29f fix eslint errors 2018-01-22 11:01:19 +00:00
a519eff231 saving recently sent templates 2018-01-22 11:01:19 +00:00
fe2ab08a49 adding template to corresponding categories when saved 2018-01-22 11:01:18 +00:00
9b914a471b adding templates categories to the display 2018-01-22 11:01:18 +00:00
74f008517b adding categories to templates 2018-01-22 11:01:18 +00:00
ba45ee7e35 Make acceptance login timeouts longer
[MAILPOET-1193]
2018-01-22 10:14:58 +00:00
a5543d9d78 Add multisite job to workflows
[MAILPOET-1193]
2018-01-22 08:37:34 +00:00
3c2ef4b8ee Merge pull request #1225 from mailpoet/re-captcha
Introduce reCAPTCHA [MAILPOET-1242]
2018-01-21 19:53:31 -05:00
07417391be Allows passing custom data to extra routes 2018-01-20 21:06:28 -05:00
e00d43e506 Displays email type thumbnail image when available 2018-01-20 21:06:22 -05:00
c4f285afca Not use deprecated code 2018-01-18 16:28:30 +00:00
c70097085e Add circle config
[MAILPOET-1193]
2018-01-18 16:02:01 +00:00
ca6bde8a64 Add multisite run for acceptance tests
[MAILPOET-1193]
2018-01-18 12:23:33 +00:00
a1ba783264 reCaptcha works without javascript now 2018-01-18 10:50:07 +00:00
e77d00b179 Add DB variables to compose file
it will be configured automatically and we don't need to run `cli` to configure
2018-01-18 10:00:36 +00:00
b683ae0bc1 Add command to delete docker stuff 2018-01-18 09:59:09 +00:00
f658fd7776 Release 3.3.5 2018-01-16 16:38:06 +02:00
1a08155f54 Merge pull request #1239 from mailpoet/mss_filters
Adds filters to control connection to MSS API [MAILPOET-1267]
2018-01-16 16:04:36 +02:00
a3b3e1f8df Removes filter after use 2018-01-16 08:24:44 -05:00
87aca7c667 Uses a helper to intercept WP functions 2018-01-16 08:21:26 -05:00
a7a8cd2be4 Updates filter name 2018-01-16 08:20:29 -05:00
819d4dc17a Abstracts WP functions 2018-01-15 19:52:51 -05:00
6e94db24a2 minor fixes 2018-01-15 12:43:48 +00:00
5bf532a750 minor UI fix 2018-01-15 10:47:26 +00:00
c63b7d9b91 handling multiple instances of reCaptcha 2018-01-15 10:47:25 +00:00
a8052c118a fixing minor issues and adding unit test 2018-01-15 10:46:07 +00:00
1ad0dce425 applying compact design and updating error messages 2018-01-15 10:46:06 +00:00
2228f60e2a adding recaptcha to form wiget 2018-01-15 10:46:06 +00:00
99a007fb70 fix recaptcha validation 2018-01-15 10:46:06 +00:00
5e5caab4da show error if recaptcha enabled but a key is empty 2018-01-15 10:46:06 +00:00
caa0623112 handling recaptcha on the PHP side 2018-01-15 10:46:06 +00:00
a05f9bf97b showing the recaptcha 2018-01-15 10:46:05 +00:00
7202d9dca1 toggle recaptcha token fields 2018-01-15 10:46:05 +00:00
655dac458a spacing issue 2018-01-15 10:46:05 +00:00
0e487d2c54 added re-captcha settings to UI 2018-01-15 10:46:05 +00:00
d2d1657cb2 added re-captcha settings to database 2018-01-15 10:46:05 +00:00
3bf800b51d Adds filter to set custom batch processing size 2018-01-14 12:39:16 -05:00
9910072e72 Adds filter to set custom request timeout value 2018-01-14 12:36:18 -05:00
8695d147e8 Merge pull request #1237 from mailpoet/eslint5-1
Eslint5 1 [ MAILPOET-1143]
2018-01-11 15:50:23 +01:00
042d47b027 Rename function
[MAILPOET-1143]
2018-01-11 09:55:20 +00:00
a27823ebc5 Merge pull request #1236 from mailpoet/list-report
Add lists and segments to reports [MAILPOET-1256]
2018-01-10 10:16:19 +01:00
1aee4489da Updates changelog and bumps up release version to 3.3.4 2018-01-09 13:30:06 -05:00
e4a37c3c2d Merge pull request #1233 from mailpoet/public-js
fix public.js not included when only shortcode is used [MAILPOET-1258]
2018-01-09 15:06:52 +00:00
ea2a91d15e Fix acceptance tests 2018-01-09 14:36:05 +00:00
72193fefae Loads dependencies only when subscription form (shortcode or widget) is
present
2018-01-09 14:16:04 +00:00
7e60155bdc fixing the acceptance test 2018-01-09 14:16:04 +00:00
7eae7dde11 making sure acceptance tests are executed 2018-01-09 14:16:04 +00:00
d70c6ce453 fix public.js not included when only shortcode is used 2018-01-09 14:16:04 +00:00
3337637a8b Removed redundant order statement
[MAILPOET-1256]
2018-01-09 13:54:11 +00:00
69ca597f24 Add lists and segments to reports
MAILPOET-1256
2018-01-09 13:54:11 +00:00
6f20a402f6 Use alternative dotdeb mirror
The old one is down with no ETA
2018-01-09 12:25:04 +00:00
19c7efc9ef Pauses sending if processed subscribers list can't be updated 2018-01-09 12:25:04 +00:00
6c25fab6d6 Adds option to pause sending after processing sending error 2018-01-09 12:25:04 +00:00
a45a7a7616 Fixes newsletter body being incorrectly saved 2018-01-09 12:25:04 +00:00
3053e21910 Fix acceptance tests
[MAILPOET-1143]
2018-01-08 15:51:12 +00:00
699017532e Fix func-names rule in es5
Please remove those comments if you work on those files
[MAILPOET-1143]
2018-01-08 14:56:00 +00:00
7465398d17 Fix prefer-template rule in es5
[MAILPOET-1143]
2018-01-08 11:49:05 +00:00
ef410fb877 Fix dot-notation rule in es5
[MAILPOET-1143]
2018-01-08 11:38:27 +00:00
f154687c53 Fix eol-last rule in es5
[MAILPOET-1143]
2018-01-08 11:36:17 +00:00
b773263fa4 Fix new-parens rule in es5
[MAILPOET-1143]
2018-01-08 11:35:35 +00:00
9870f62984 Fix object-shorthand rule in es5
[MAILPOET-1143]
2018-01-08 11:34:44 +00:00
1f6430c278 Fix strict rule in es5
[MAILPOET-1143]
2018-01-08 11:29:51 +00:00
4018ca4a65 Merge pull request #1235 from mailpoet/acceptance-fix
Fix acceptance tests on Circle CI
2018-01-03 15:39:47 +01:00
1342389602 Wait for target
MailHog adds target='_blank' to our links.
But we were too quick clicking the links before the target was added

MAILPOET-1260
2018-01-03 11:46:20 +00:00
368f7004c0 Fix acceptance tests on CircleCi
MAILPOET-1260
2018-01-02 14:48:21 +00:00
d33cc9d2b8 Release 3.3.3 2018-01-02 13:53:45 +00:00
e9be62c2d3 Merge pull request #1230 from mailpoet/editor-delete-btn
Improve safety of content deletion in newsletter editor [MAILPOET-1248]
2017-12-27 00:32:30 +03:00
f2733624e4 added transition 2017-12-26 10:09:48 +00:00
46121d74a8 Merge pull request #1232 from mailpoet/sending_queue_rendered_body_encoding
Switches serialize() for json_encode() to store rendered newsletter body [MAILPOET-1216]
2017-12-21 18:17:34 +03:00
cb430673f8 Uses json_encode() instead of serialize() to save rendered newsletter
body
2017-12-20 22:13:00 -05:00
8852f6a3f4 Adds function to test if string is a valid json 2017-12-20 22:13:00 -05:00
56e55c072a Highlight the deletable block in red 2017-12-20 22:11:30 -05:00
77e60d708a swapping cancel and delete links 2017-12-20 22:11:30 -05:00
27fbc25bf9 Fixes Debian missing PHP packages issue 2017-12-20 22:10:25 -05:00
a91929682f Merge pull request #1229 from mailpoet/hs-icon
moving the help icon 20px to the bottom [MAILPOET-1247]
2017-12-20 22:05:48 -05:00
d45c510ab3 Merge pull request #1226 from mailpoet/new_or_updated_user_welcome_email
Schedules welcome notification when adding/editing subscriber [MAILPOET-1249]
2017-12-20 14:26:24 +03:00
57366e972a Updates changelog and bumps up release version to 3.3.2 2017-12-19 11:40:11 -05:00
cbd1ae929e moving the help icon 20px to the bottom 2017-12-19 16:20:36 +00:00
884f476598 Merge pull request #1228 from mailpoet/change-update-header
updated the header string [MAILPOET-1195]
2017-12-19 09:01:13 -05:00
55296d52ec updated the header string 2017-12-19 12:47:57 +00:00
8fb4d2e78f Merge pull request #1227 from mailpoet/status_page_update
Validates ping response when displaying cron URL status [MAILPOET-1253]
2017-12-19 14:29:47 +03:00
840473aae5 Merge pull request #1224 from mailpoet/send_with_language_update
Removes unused string in "send with" tab [MAILPOET-1252]
2017-12-19 09:49:06 +01:00
5d5b61b76f Schedules welcome notification when adding/editing subscriber 2017-12-18 21:19:44 -05:00
0e2a67c203 Validates ping response when displaying cron URL status 2017-12-18 20:28:09 -05:00
aaed5add52 Removes unused string 2017-12-17 10:51:39 -05:00
f616ef4d6c Merge pull request #1218 from mailpoet/widget_update
Prevents loading plugin assets when form widget is not activated [MAILPOET-1241]
2017-12-15 23:15:31 +02:00
083a6fd3a3 Merge pull request #1223 from mailpoet/new-surveys
What's New: 2 new surveys, less call-to-actions [MAILPOET-1243]
2017-12-14 23:28:00 +03:00
9a1ec60750 releasing 3.3.1 2017-12-14 18:09:17 +00:00
bd67f5fd36 New poll
[MAILPOET-1243]
2017-12-14 14:46:18 +00:00
ed2a2a6fa8 Remove additional CTAs
[PREMIUM-1243]
2017-12-14 13:12:53 +00:00
6a28fdcac2 Merge pull request #1222 from mailpoet/number_formatting_fix
Formats number according to user's locale [MAILPOET-1246]
2017-12-14 15:38:37 +03:00
fda1828637 Adds composer.lock security check
[MAILPOET-1226]
2017-12-14 08:47:47 +00:00
ebcc094b4d Formats number according to user's locale 2017-12-13 21:53:03 -05:00
51cde55217 Tests statistics column 2017-12-13 09:39:03 +00:00
23dff7403d Updates variable names to match those in views/newsletters.html 2017-12-13 09:39:03 +00:00
de164f918c releasing 3.3.0 2017-12-12 17:03:21 +00:00
84840c5261 releasing 3.2.5 2017-12-12 16:30:44 +00:00
16b9e0d467 Merge pull request #1219 from mailpoet/new_poll
New poll [MAILPOET-1225]
2017-12-11 18:56:16 +03:00
3c75e7b0bc Merge pull request #1211 from mailpoet/email-segments
Email segments [PREMIUM-44]
2017-12-11 09:29:49 -05:00
c41d5894d0 New poll
[MAILPOET-1225]
2017-12-11 09:39:20 +00:00
1f76f0d98f Allow form fields styling
[PREMIUM-44]
2017-12-11 09:05:29 +00:00
e859c090c8 Allow values for selections to be passed
[PREMIUM-44]
2017-12-11 08:54:43 +00:00
42528ab309 Allow select2 for single selects
[PREMIUM-44]
2017-12-11 08:49:36 +00:00
d761867a7d Enable dynamic segment edits
[PREMIUM-44]
2017-12-11 08:49:36 +00:00
6996615999 Improves tests that would fail due to array_flip and 1 item in array 2017-12-10 19:31:35 -05:00
3450a6fc97 Adds wait condition before assertion; corrects prefix 2017-12-10 18:41:54 -05:00
554dbb8dda Initializes dependencies only when widget is active 2017-12-09 19:53:12 -05:00
d13aa67a07 Centralizes widget logic in one place
Cleans up code
2017-12-09 19:45:19 -05:00
1f9c956637 Removes unused code 2017-12-09 19:27:21 -05:00
59d09866a1 Merge pull request #1217 from mailpoet/eslint-es6-3
Eslint es6 3 [MAILPOET-1139]
2017-12-07 18:49:21 +01:00
f8ade27a6c Improve code
[MAILPOET-1139]
2017-12-07 17:31:15 +00:00
313bcddba1 Split line into multiple lines
[MAILPOET-1139]
2017-12-07 16:39:02 +00:00
fd64702eaa Changes WP DB prefix 2017-12-07 11:08:52 +00:00
e2884ac625 Fix eqeqeq eslint rule in ES6 files
[MAILPOET-1139]
2017-12-07 09:44:58 +00:00
9ce9cb929f Fix camelcase eslint rule in ES6 files
[MAILPOET-1139]
2017-12-07 09:39:05 +00:00
52d33d7fe8 Merge pull request #1215 from mailpoet/fix-template-duplication
Use website language when running populator [MAILPOET-1233]
2017-12-06 20:05:53 -05:00
2ee33b2fc2 Bumps up minimum required WP version 2017-12-06 19:52:12 -05:00
b107be3241 Use website language when running populator
[MAILPOET-1233]
2017-12-06 19:51:09 -05:00
76148d0a85 Fix import/no-extraneous-dependendencies eslint rule in ES6 files
[MAILPOET-1139]
2017-12-06 16:37:45 +00:00
61a7f99e42 Make import/extensions eslint rule an exception in ES6 files
[MAILPOET-1139]
2017-12-06 16:19:48 +00:00
62e3ca8a80 Fix consistent-return eslint rule in ES6 files
[MAILPOET-1139]
2017-12-06 16:05:21 +00:00
d431efb288 Fix array-callback-return eslint rule in ES6 files
[MAILPOET-1139]
2017-12-06 15:55:15 +00:00
adf6485b7d Fix default-case eslint rule in ES6 files
[MAILPOET-1139]
2017-12-06 14:30:54 +00:00
170fd7f051 Fix prefer-template eslint rule in ES6 files
[MAILPOET-1139]
2017-12-06 14:18:24 +00:00
e7ddfc3d29 Fix arrow-body-style eslint rule in ES6 files
[MAILPOET-1139]
2017-12-06 14:16:41 +00:00
b08b53e9c0 Fix no-bitwise eslint rule in ES6 files
[MAILPOET-1139]
2017-12-06 13:58:56 +00:00
570529a8d8 Release 3.2.4 2017-12-05 18:58:18 +02:00
5505ffc783 Merge pull request #1206 from mailpoet/manage_subscription_shortcode_update
Allows using manage_subscription shortcode outside of newsletters [MAILPOET-1122]
2017-12-05 19:38:37 +03:00
6e5fc6ad6b Fix array_key_exists() error if no data is passed to subscription management page [MAILPOET-1122] 2017-12-05 19:22:28 +03:00
e731b261ab Conditionally initializes shortcodes/filters 2017-12-05 10:34:03 -05:00
955f24e71a Load mb_strtoupper() polyfill for MP2 migration
* Load mb_strtoupper() polyfill for MP2 migration
* Add "symfony/polyfill-mbstring" as explicit dependency
* Fixate AspectMock at 2.0.1
* Generate composer.lock with PHP 5.6 to include required dependencies

[MAILPOET-1234]
2017-12-05 11:15:31 +00:00
89ebc6051a Merge pull request #1210 from mailpoet/help_status_tab
Adds system status tab to the Help menu
2017-12-05 10:38:19 +02:00
79fff7b65d Merge pull request #1212 from mailpoet/new-poll
New poll [MAILPOET-1213]
2017-12-04 20:09:15 -05:00
7864e08900 Enables [mailpoet_manage] shortcode
Updates code
2017-12-04 19:58:30 -05:00
878cdf46e6 Update vulnerable Handlebars to newest version [MAILPOET-1235] 2017-12-04 16:12:30 +00:00
131d341744 New poll
[MAILPOET-1213]
2017-12-04 11:13:34 +00:00
513062b15d Cleans up code 2017-12-03 11:38:45 -05:00
4926267e36 Adds system status tab to the Help menu 2017-12-03 11:38:45 -05:00
aa4d78b1c9 Adds method to ping Bridge 2017-12-03 11:38:44 -05:00
8d7289e8ba Merge pull request #1208 from mailpoet/eslint-rules2
Eslint rules2 [MAILPOET-1144]
2017-11-30 19:24:26 -05:00
eb768ff1ee Merge pull request #1209 from mailpoet/mailer_error_code
Make rendering errors during sending more descriptive [MAILPOET-1232]
2017-11-30 12:09:40 -05:00
8afe7f5d97 Make rendering error during sending more descriptive [MAILPOET-1232] 2017-11-30 19:45:53 +03:00
97fb5cf66f Makes string translateable 2017-11-30 09:44:34 +00:00
8ea4a219e2 Fix padded-blocks eslint rule in ES5 files
[MAILPOET-1144]
2017-11-30 09:12:19 +00:00
0e08e58288 Fix camelcase eslint rule in ES5 files
[MAILPOET-1144]
2017-11-30 09:10:08 +00:00
dc52ba0d93 Bump up release version to 3.2.3 2017-11-29 18:35:43 +03:00
dc569672a9 Fix no-use-before-define eslint rule in ES5 files
[MAILPOET-1144]
2017-11-29 15:17:30 +00:00
159e946093 Fix no-else-return eslint rule in ES5 files
[MAILPOET-1144]
2017-11-29 15:04:38 +00:00
3d2a433df1 Moved no-underscore-dangel eslint rule to exceptions
this._appView cannot be renamed

[MAILPOET-1144]
2017-11-29 15:01:16 +00:00
fe0476e1c0 Fix no-shadow eslint rule in ES5 files
[MAILPOET-1144]
2017-11-29 14:49:19 +00:00
ea552508b4 Fix consistent-return eslint rule in ES5 files
[MAILPOET-1144]
2017-11-29 13:43:35 +00:00
dee2ff810c Fixes undefined index error 2017-11-29 10:19:30 +00:00
63ed835d64 Allows using manage_subscription shortcode outside of newsletters 2017-11-28 22:02:29 -05:00
fbf58f23fc Bump up release version to 3.2.2 2017-11-28 20:18:18 +03:00
b6f62bd9bc Catches exceptions during sending 2017-11-28 16:42:22 +00:00
88ef454844 Merge pull request #1203 from mailpoet/nov28_survey
Updates weekly survey [MAILPOET-1224]
2017-11-28 16:07:22 +03:00
3572df6c0c Fixes "other" method test email sending when MSS is enabled
[MAILPOET-1218]
2017-11-28 09:28:56 +00:00
714e6e013f Updates weekly survey 2017-11-27 19:51:40 -05:00
91568cbeb6 Merge pull request #1202 from mailpoet/post_notification_creation_acceptance_test
Tests post notification creation [MAILPOET-1219]
2017-11-27 12:59:48 +02:00
393c89b21f Tests that post notifications can be created 2017-11-23 21:02:42 -05:00
0b491b7943 Adds method to get current URL 2017-11-23 21:02:41 -05:00
e5d7f66561 Adds new id to create standard/notification newsletters 2017-11-23 21:02:36 -05:00
b7a7f40cde Merge pull request #1199 from mailpoet/image_url_space_fix
Encodes URLs in inlined images [MAILPOET-1220]
2017-11-23 16:03:57 +03:00
a267c7524c Close the a tag to make valid HTML [MAILPOET-1220] 2017-11-23 16:02:40 +03:00
20b59d11a7 Merge pull request #1201 from mailpoet/user_profile_language_fix
Changes plugin language based on user's locale [MAILPOET-1211]
2017-11-23 13:40:59 +02:00
94c7e2a5c0 Changes plugin language based on user's locale 2017-11-22 20:13:56 -05:00
d603d99a04 Merge pull request #1190 from mailpoet/multisite_unit_tests
Adds new CI multisite test environment
2017-11-22 15:16:20 +02:00
e7ffe4d694 Replaces spaces in image URLs 2017-11-21 21:02:33 -05:00
018d7bce77 Corrects test to work on multisite environment 2017-11-21 12:26:02 -05:00
64c40d5a1c Adds test for multisite environment 2017-11-21 12:25:54 -05:00
7e49328d5e Corrects test to work on multisite environment 2017-11-21 12:24:19 -05:00
b50b636371 Adds multisite test environment to CI
Adds Robo command to run multisite tests locally and on CI
2017-11-21 12:24:18 -05:00
ec3bb5b95c Release 3.2.1 2017-11-21 15:18:40 +00:00
6b2503fb36 Merge pull request #1196 from mailpoet/minimum_wp_version_notice
Shows notice on WP version < 4.6 and deactivates plugin [MAILPOET-1215]
2017-11-21 16:26:03 +02:00
e71d47f983 Adds link to minimum requirements page for WP version 2017-11-21 08:57:28 -05:00
085d4f566a Merge pull request #1198 from mailpoet/hide-honeypot
Hide honeypot field to prevent Safari autocomplete [MAILPOET-1180]
2017-11-21 16:08:45 +03:00
29b249de6e Remove an attribute we don't need anymore
[MAILPOET-1180]
2017-11-21 12:54:00 +00:00
883ae5b0e4 Hide honeypot field to prevent Safari autocomplete
[MAILPOET-1180]
2017-11-21 11:47:46 +00:00
d78990cda3 Shows notice on WP version < 4.6 and deactivates plugin 2017-11-20 14:26:31 -05:00
e5b5a8df37 Merge pull request #1197 from mailpoet/poll_nov20
Update the poll [MAILPOET-1212]
2017-11-20 11:30:29 -05:00
2ea2db66ec Update the poll [MAILPOET-1212] 2017-11-20 19:03:47 +03:00
7b76ddefd5 Merge pull request #1194 from mailpoet/double_opt-in_test
Add an acceptance test for subscription confirmation [MAILPOET-1205]
2017-11-20 14:36:55 +02:00
6c56ac8509 Clean up the acceptance dump from unused pages [MAILPOET-1206] 2017-11-20 10:42:17 +00:00
dc074bcb14 Add acceptances tests for admin listings [MAILPOET-1206] [MAILPOET-1207] [MAILPOET-1208] [MAILPOET-1209] 2017-11-20 10:42:17 +00:00
0193644b18 Merge pull request #1195 from mailpoet/test_email_send_fix
Fixes "mailer not defined" JS error [MAILPOET-1217]
2017-11-20 13:21:16 +03:00
66de11ecd4 Fixes "mailer not defined" JS error 2017-11-18 19:51:53 -05:00
1238b1711d Add an acceptance test for subscription confirmation [MAILPOET-1205] 2017-11-16 14:57:56 +03:00
0061a9daf9 Move key checks from constructor to init() in Menu class [MAILPOET-1204] 2017-11-15 11:23:39 +00:00
52a55d3bd1 Updates changelog and bumps up release version to 3.2.0 2017-11-14 14:13:49 -05:00
7d686eb1d1 Merge pull request #1191 from mailpoet/post_excerpt_shortcode_fix
Fixes shortcodes not being properly stripped in excerpts [MAILPOET-1210]
2017-11-14 20:51:21 +02:00
962188bdb8 Adds unit test 2017-11-14 13:39:56 -05:00
72c3f763ec Removes shortcodes from full post content 2017-11-14 13:17:47 -05:00
44c5d8490f Fixes shortcodes not being properly stripped on excerpts 2017-11-14 12:35:08 -05:00
fb85623b86 Merge pull request #1185 from mailpoet/mp_api_unsubscribe_from_lists
Adds API method to unsubscribe from lists [MAILPOET-1202]
2017-11-14 17:38:53 +02:00
d7bf6addf1 Fixes error due to throwing exception inside array_map 2017-11-14 09:58:01 -05:00
adea1e9be1 Fixes condition that allowed unsubscribing from WP segments 2017-11-14 09:56:53 -05:00
4f77ca31a3 Rebased master 2017-11-13 12:41:46 -05:00
087f2ebcdd Uses a built-in method to handle plural exception cases
Implements check for empty segments
Implements check for WP segment when unsubscribing
2017-11-13 10:12:50 -05:00
3d2a63f319 Adds methods to unsubscribe from list(s) 2017-11-13 10:12:50 -05:00
54dd3b621a Improves error messages, cleans up code 2017-11-13 10:11:07 -05:00
7fea134109 Merge pull request #1183 from mailpoet/dynamic-segments-listings
Dynamic segments subscribers listings [PREMIUM-38] [PREMIUM-43]
2017-11-13 16:52:48 +03:00
fcf4bd12d9 Merge pull request #1186 from mailpoet/mp_api_get_subscriber
Adds API method to get subscriber [MAILPOET-1203]
2017-11-13 15:38:47 +02:00
6694555592 Adds method to get subscriber 2017-11-10 18:47:53 -05:00
e6eb3d691e Fix quality problems
[PREMIUM-38]
2017-11-09 12:14:01 +00:00
00f2d418cc Load subscribers from dynamic segments
[PREMIUM-38]
2017-11-09 10:11:47 +00:00
c63f218edd Enable to add segments to subscribers listing filter
[PREMIUM-38]
2017-11-09 10:11:47 +00:00
fae849bbfc Merge pull request #1182 from mailpoet/es6_rules_1
Fix ES6 rules 1 [MAILPOET-1137]
2017-11-08 22:32:43 -05:00
2a253ccb8d Move ES6 no-script-url rule to exceptions [MAILPOET-1137] 2017-11-08 21:42:10 -05:00
ff55e55ad2 Fix indentation [MAILPOET-1137] 2017-11-08 21:42:10 -05:00
d798ec446d Fix ES6 no-alert eslint rule (replace confirm() with a custom UI component) [MAILPOET-1137] 2017-11-08 21:41:17 -05:00
56b4038073 Fix padded-blocks after rebasing [MAILPOET-1137] 2017-11-08 21:41:16 -05:00
076a55f1fb Fix ES6 no-underscore-dangle eslint rule [MAILPOET-1137] 2017-11-08 21:41:16 -05:00
10eca98dc3 Fix ES6 padded-blocks eslint rule [MAILPOET-1137] 2017-11-08 21:41:16 -05:00
37aec3ee4f Fix ES6 wrap-iife eslint rule [MAILPOET-1137] 2017-11-08 21:41:16 -05:00
dc7c629e3b Fix ES6 no-shadow eslint rule [MAILPOET-1137] 2017-11-08 21:41:16 -05:00
e4f16eda49 Fix ES6 dot-notation eslint rule [MAILPOET-1137] 2017-11-08 21:41:16 -05:00
bf15bda84f Merge pull request #1181 from mailpoet/norwegian
Update translations in readme [MAILPOET-1196]
2017-11-08 09:19:20 -05:00
8472a837e8 Fix an 'Undefined index: SERVER_NAME' error in ConflictResolverTest [MAILPOET-1187] 2017-11-08 14:18:58 +00:00
fc326131ae Rebased master 2017-11-08 14:04:45 +00:00
a19753205f Increases timeout value when tests are run on slow hosts 2017-11-08 14:04:45 +00:00
ee404e3b84 Uses CLI to truncate table 2017-11-08 14:04:45 +00:00
f1918ac953 Removes timeouts and uses data-automation-id as element selector 2017-11-08 14:04:45 +00:00
d399ddf6b6 Fixed acceptance tests for me 2017-11-08 14:04:45 +00:00
3f06448f37 Uses data-automation-id/iframe id and bypasses throttling for
consecutive signups
2017-11-08 14:04:45 +00:00
83d84e67d6 Adds test for iframe form subscription 2017-11-08 14:04:45 +00:00
46c42c1bb4 Re-adds vendor folder installation (this is needed for Alex's setup) 2017-11-08 14:04:45 +00:00
944bf67190 Updates docker-compose 2017-11-08 14:04:45 +00:00
7cac061a73 Renames test 2017-11-08 14:04:45 +00:00
17764b708f Adds check for JS errors 2017-11-08 14:04:45 +00:00
2e0f4dfb19 Removes the need to reinstall vendor folder 2017-11-08 14:04:45 +00:00
7f5bc8681c Adds acceptance tests for unsubscribe/manage subscription links 2017-11-08 14:04:45 +00:00
bfcb85f744 Updates existing tests format 2017-11-08 14:04:45 +00:00
cb9aaf120e Cleans up DB dump 2017-11-08 14:04:45 +00:00
97a9465db3 Adds MailHog for SMTP testing 2017-11-08 14:04:45 +00:00
8dfaf9ba32 Release 3.1.0 2017-11-07 15:20:00 +02:00
89d0da93d3 Merge pull request #1180 from mailpoet/wp_sync_db_error_fix
Fixes "column cannot be null" error during WP sync [MAILPOET-1191]
2017-11-07 12:23:39 +02:00
c9cbfb4317 Update translations in readme [MAILPOET-1196] 2017-11-07 12:04:56 +03:00
a8ccfec5c6 Merge pull request #1178 from mailpoet/superadmin_access
Enable permissions for superadmin users [MAILPOET-1200]
2017-11-07 11:15:33 +03:00
d8609c9e84 Merge pull request #1179 from mailpoet/survey_nov7
Updates weekly survey [MAILPOET-1199]
2017-11-07 10:41:07 +03:00
5461c975d4 Fixes "column cannot be null" error during WP sync 2017-11-06 22:29:59 -05:00
11298bc101 Updates weekly survey 2017-11-06 22:25:35 -05:00
c42cf2f622 Switch to using current_user_can function to check capabilities 2017-11-06 18:09:38 +02:00
c9f1d38baa Merge pull request #1177 from mailpoet/mpapi_create_list
Add a method to create a new list to public API [MAILPOET-1197]
2017-11-02 18:54:06 -04:00
3d78d6bbe9 Add a method to create a new list to public API [MAILPOET-1197] 2017-11-02 22:13:50 +03:00
2b4288f301 Merge pull request #1176 from mailpoet/throttling_test_fix
Fix an off-by-one error in some timezones [MAILPOET-1186]
2017-11-02 14:34:03 +02:00
09a2dd231a Fix an off-by-one error in some timezones [MAILPOET-1186] 2017-11-02 14:56:44 +03:00
3fd4ef9985 Cleanup after WP sync test [MAILPOET-1185] 2017-11-01 15:43:31 +00:00
05979965ba Merge pull request #1174 from mailpoet/es6
ESLint: ES6 rules 2 [MAILPOET-1138]
2017-11-01 11:32:34 -04:00
e625a7602a Merge pull request #1171 from mailpoet/mixpanel
Report more system environment data via MixPanel [MAILPOET-1189]
2017-11-01 11:21:29 -04:00
a0c41ad7ab Merge pull request #1168 from mailpoet/jquery
plugin scripts should be loaded with a dependency on jquery [MAILPOET-1149]
2017-11-01 15:01:38 +02:00
7163747eb9 no-extra-boolean-cast 2017-11-01 10:20:13 +00:00
c30e2b6cf3 no-sequences 2017-10-31 17:16:24 +00:00
e9eae92ba9 no-useless-concat 2017-10-31 17:15:09 +00:00
0fd6fa8879 max-len 2017-10-31 17:12:59 +00:00
52ca6eac18 no-else-return 2017-10-31 17:10:10 +00:00
28776b8558 no-case-declarations 2017-10-31 16:52:00 +00:00
588ad3eab7 class-methods-use-this 2017-10-31 16:46:19 +00:00
d791538086 no-lonely-if 2017-10-31 16:40:08 +00:00
62173e7996 Bump up release version to 3.0.9 2017-10-31 19:18:42 +03:00
0acdcd1ca7 Merge pull request #1170 from mailpoet/jquery_serialize_object
Rename jQuery Serialize Object function to prevent conflicts [MAILPOET-1190]
2017-10-31 15:05:00 +01:00
f39a2c8dda added env data to weekly report 2017-10-31 11:17:34 +00:00
b648852ef5 Rename jQuery Serialize Object function to prevent conflicts [MAILPOET-1190] 2017-10-30 22:49:00 +03:00
6e45892118 trim values on listing search 2017-10-30 16:24:00 +00:00
cd145c51f7 public.js now depends on jquery 2017-10-30 14:25:05 +00:00
2c12d9ee2d changes on welcome and update pages 2017-10-30 11:36:40 +00:00
5fe28623f1 Merge pull request #1164 from mailpoet/acceptance_js_errors
Add JS error checking to acceptance tests [MAILPOET-1179]
2017-10-29 21:31:45 -04:00
3086b3cfc2 Merge pull request #1165 from mailpoet/esltests
ESLint: Test rules 2 [MAILPOET-1135]
2017-10-29 21:30:27 -04:00
5fd29872ff Merge pull request #1166 from mailpoet/remove-tags
Remove tags from ALC display
2017-10-26 14:28:02 +03:00
732c8a314f Merge pull request #1160 from mailpoet/ci-tables-prefix
changing the tables prefix to "mp_" on CircleCI [MAILPOET-1178]
2017-10-26 13:43:08 +03:00
23c650bfa6 Merge pull request #1163 from mailpoet/new-poll
new poll [MAILPOET-1172]
2017-10-26 13:34:16 +03:00
f5ced785e0 Tests: padded-blocks 2017-10-25 14:54:28 +00:00
4dc9004303 Tests: no-shaddow 2017-10-25 14:52:53 +00:00
893c6bd72b Remove tags from ALC display
[MAILPOET-1182]
2017-10-25 15:49:23 +01:00
2ac32484e1 Tests: max-len 2017-10-25 12:16:32 +00:00
b31e8ce5f2 Tests: no-bitwise 2017-10-25 12:10:29 +00:00
4270e4c315 Check for missing CSS files in acceptance tests [MAILPOET-1177] 2017-10-25 14:04:11 +03:00
4b13395b0c Add JS error checking to acceptance tests [MAILPOET-1179] 2017-10-25 13:34:16 +03:00
2e67029ef5 Merge pull request #1162 from mailpoet/new
Capitalize new [MAILPOET-1174]
2017-10-24 17:48:05 +03:00
257517b9a9 new poll 2017-10-24 14:13:07 +00:00
88ee64e15d Capitalize new 2017-10-24 14:03:27 +00:00
c2030e9a86 Fix readme.txt rendering 2017-10-24 14:55:21 +01:00
16111a99fb Release 3.0.8 2017-10-24 13:17:49 +01:00
543b3e5a91 changing tables prefix for acceptance tests 2017-10-24 09:13:43 +00:00
e33b60065e Merge pull request #1159 from mailpoet/ci_js_compile
Compile JS and CSS assets on CI before running acceptance tests [MAILPOET-1166]
2017-10-24 11:55:24 +03:00
3bcfadd2ab Merge pull request #1161 from mailpoet/translations_update
Translations update [MAILPOET-1161]
2017-10-24 11:30:59 +03:00
4729583d8d Merge pull request #1158 from mailpoet/scroll
enabling body scroll when settings are open [MAILPOET-1148]
2017-10-23 21:52:39 -04:00
aa3f457595 Updates welcome page translations that were not included in pot file 2017-10-23 21:45:48 -04:00
3ad490f840 Loads translations before the rest of the plugin 2017-10-23 21:45:48 -04:00
eb27ed65ae Adds missing translations to migration page 2017-10-23 21:45:40 -04:00
d543f62c5b Merge pull request #1157 from mailpoet/poll
new poll [MAILPOET-1171]
2017-10-23 20:11:19 +03:00
4e6f7a05de changing the tables prefix to "mp_" on CircleCI 2017-10-23 16:49:36 +00:00
5d467115ad Compile JS and CSS assets on CI before running acceptance tests [MAILPOET-1166] 2017-10-23 19:02:28 +03:00
6858b266fe enabling body scroll when settings are open 2017-10-23 16:01:28 +00:00
852b1a4c08 new poll 2017-10-23 14:59:29 +00:00
b2324db7b4 Merge pull request #1156 from mailpoet/number_formatting_update
Formats number as per locale's convention [MAILPOET-1125]
2017-10-23 15:19:47 +02:00
e8c85e2a54 Merge pull request #1155 from mailpoet/wp_user_sync_db_query_fix
Fixes MySQL's "column is ambiguous" error in WP user sync [MAILPOET-1177]
2017-10-23 14:15:14 +03:00
a4ac74c84a Remove more ambiguity in WP sync queries [MAILPOET-1177] 2017-10-23 13:58:23 +03:00
4e378484ea Formats number as per locale's convention 2017-10-22 21:56:33 -04:00
c55be70b2c Merge pull request #1154 from mailpoet/php_version_mixpanel
Report PHP version in weekly MixPanel analytics [MAILPOET-1175]
2017-10-20 17:10:14 +02:00
70898790f5 Cleans up code & fixes possible MySQL's "column is ambiguous" error 2017-10-19 21:14:45 -04:00
bfdb535f5b Fixes method name typo 2017-10-19 21:00:15 -04:00
996e6b16e7 Merge pull request #1142 from mailpoet/links
Enabling links on header and footer on preview [MAILPOET-1121]
2017-10-19 20:07:32 +03:00
0217e21753 Restore a default argument value [MAILPOET-1121] 2017-10-19 19:43:39 +03:00
f6f79d42e1 Report PHP version in weekly MixPanel analytics [MAILPOET-1175] 2017-10-19 19:03:55 +03:00
4bbd26b098 Merge pull request #1152 from mailpoet/form_translation_fix
Adds translated "required field" message to subscription form [MAILPOET-1173]
2017-10-19 18:55:02 +03:00
028179af37 Merge pull request #1153 from mailpoet/form_acceptance_tests
Add an acceptance test for the public subscription form widget [MAILPOET-1166]
2017-10-19 17:46:54 +03:00
87283bf838 Merge pull request #1143 from mailpoet/image-url
Force absolute path for images [MAILPOET-1160]
2017-10-19 12:38:45 +03:00
c680badaa2 Fix WP uploads folder permissions [MAILPOET-1166] 2017-10-19 12:34:16 +03:00
df4a936e43 Fix exit code returned by acceptance tests [MAILPOET-1166] 2017-10-19 12:34:16 +03:00
e27946ebcc Fix artifacts storage [MAILPOET-1166] 2017-10-19 12:34:16 +03:00
13e64c012f Restore PHP 5 support [MAILPOET-1166] 2017-10-19 12:34:16 +03:00
f69302be48 Add an acceptance test for the public subscription form widget [MAILPOET-1166] 2017-10-19 12:34:16 +03:00
16edfc16ea Merge pull request #1144 from mailpoet/dynamic-segments
Dynamic segments [PREMIUM-38]
2017-10-18 18:57:48 +03:00
229a9c8102 Fix QA issue
[PREMIUM-38]
2017-10-18 15:11:57 +01:00
490091a7e2 Move table definition to premium plugin
[PREMIUM-38]
2017-10-18 15:09:16 +01:00
5f58e5ca82 Add tests
[PREMIUM-38]
2017-10-18 15:04:44 +01:00
16beda530a Fix post notifications to work with dynamic segments
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
f1b373924f Remove subscribers filtering for now
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
6a73c463cb QA fixes
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
0271675cd0 Use dynamic segments for sending queue
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
b7555aa640 Show only default segments in listings
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
fa9ef6e5bd Add 500 status code
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
1c97b004ca Add blank template for premium plugin
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
f0ab42adf1 Expose packages for premium
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
165d8358d4 Add action after lists menu item
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
6bd6e74bcb Add dynamic filters table
[PREMIUM-38]
2017-10-18 10:08:04 +01:00
b23df9e0a4 Adds translated "required field" message 2017-10-17 21:43:55 -04:00
7b12affb77 Bumps up release version to 3.0.7 and updates changelog 2017-10-17 14:08:16 -04:00
8c8c01aa75 shows links when previewing sent newsletters 2017-10-17 14:14:08 +00:00
0150e699a2 Merge pull request #1151 from mailpoet/oct17_poll_update
Updates weekly poll [MAILPOET-1170]
2017-10-17 17:06:39 +03:00
e6943e2638 Updates weekly poll 2017-10-17 09:34:04 -04:00
6f80dcb1de adding unit tests 2017-10-17 13:09:37 +00:00
60ed294302 no need to normalize src on the frontend 2017-10-17 12:57:39 +00:00
e8017b58f5 removing tooltip message 2017-10-17 12:48:20 +00:00
c79bf7d337 forcing absolute image source when rendering 2017-10-17 12:35:11 +00:00
ac268c1ec9 Merge pull request #1150 from mailpoet/beacon_cron_url_update
Uses CronHelper's method to return cron ping URL in beacon [MAILPOET-1164]
2017-10-17 09:54:12 +03:00
1ef131fa2d Merge pull request #1149 from mailpoet/capabilities_fix
Fixes "Call to a member function add_cap() on null" error [MAILPOET-1169]
2017-10-17 09:46:48 +03:00
1873007550 Improve a unit test for non-existent roles' capabilities [MAILPOET-1169] 2017-10-17 09:35:50 +03:00
fa2ccb51c9 Uses CronHelper's method to return cron ping URL in beacon 2017-10-16 23:46:17 -04:00
8f87d654af Merge pull request #1148 from mailpoet/stats_cta
Add CTA links for detailed stats [MAILPOET-1152]
2017-10-16 23:33:10 -04:00
dee6e9fbad Fixes "Call to a member function add_cap() on null" error 2017-10-16 22:55:11 -04:00
ef90264316 Add CTA links for detailed stats [MAILPOET-1152] 2017-10-13 01:11:06 +03:00
70bf4be723 ESLint: Test rules 1
[MAILPOET-1134]
2017-10-12 15:36:40 +01:00
07ef727654 Merge pull request #1139 from mailpoet/throttling
Add progressive throttling of subscriptions from the same IP address [MAILPOET-1128]
2017-10-12 15:56:40 +02:00
a346e5be29 normalizing image URL on render 2017-10-12 13:55:04 +00:00
5ce1eadde7 Merge pull request #1147 from mailpoet/honeypot-autofill
Subscription form honeypot gets filled by Autofill [MAILPOET-1163]
2017-10-12 16:52:22 +03:00
8a4d5395b1 Add attribute for Chrome
[MAILPOET-1163]
2017-10-12 14:38:45 +01:00
b5feed0f46 Remove WP subscribers with empty emails when syncing [MAILPOET-1158] 2017-10-12 10:31:11 +01:00
11f9579101 Don't synchronize WP users without emails [MAILPOET-1158] 2017-10-12 10:31:11 +01:00
c6000c959a Force absolute path for images 2017-10-11 14:21:16 +00:00
19e67ea2b0 Enabling links on header and footer on preview 2017-10-11 12:45:07 +00:00
0f6619e25d Merge pull request #1140 from mailpoet/svn_publish
Remove a dependency on WP in svn:publish command [MAILPOET-1156]
2017-10-11 13:21:10 +03:00
daf747d3be Throw an exception if plugin version could not be determined [MAILPOET-1156] 2017-10-11 13:07:53 +03:00
7393b1f2cf Remove a dependency on WP in svn:publish command [MAILPOET-1156] 2017-10-11 10:54:28 +03:00
efe861a9ba Merge pull request #1137 from mailpoet/eslint4
Eslint for tests [MAILPOET-1083]
2017-10-11 10:00:53 +03:00
2c358ab179 Add progressive throttling of subscriptions from the same IP address [MAILPOET-1128] 2017-10-10 19:36:20 +03:00
ca157fc91d Release 3.0.6 2017-10-10 16:46:37 +03:00
1fbe5d7bc6 Merge pull request #1138 from mailpoet/parsley
fixing missing parsley method [MAILPOET-1157]
2017-10-10 16:34:18 +03:00
71c031ccf9 fixing missing parsley method 2017-10-10 13:10:49 +00:00
6449b7ccca fixed minor issue 2017-10-10 09:29:22 +00:00
6a956472fe Release 3.0.5 2017-10-10 12:27:16 +03:00
d6af88d667 Tests object-curly-spacing 2017-10-10 09:09:03 +00:00
b9184a202f Tests func-call-spacing 2017-10-10 09:09:03 +00:00
f898746967 Tests keyword-spacing 2017-10-10 09:09:03 +00:00
68165b7b78 Tests space-before-function-paren 2017-10-10 09:09:03 +00:00
bb8591a67b Tests space-before-blocks 2017-10-10 09:07:29 +00:00
bda71ae78e Tests space-unary-ops 2017-10-10 09:07:29 +00:00
abd4f6cac2 Tests no-spaced-func 2017-10-10 09:07:29 +00:00
87e6cc2a4f Tests no-whitespace-before-property 2017-10-10 09:07:29 +00:00
dde598eb64 rebasing on master 2017-10-10 09:07:29 +00:00
0c4407f43a Merge pull request #1126 from mailpoet/eslint3
Eslint rules [MAILPOET-1084]
2017-10-10 11:46:45 +03:00
b6c864e7a1 Change the JSON API error message
[MAILPOET-1103]
2017-10-10 09:45:50 +01:00
3d9dc6465d Merge pull request #1132 from mailpoet/image_alignment
Add image alignment option to newsletter editor [MAILPOET-1124]
2017-10-10 11:37:11 +03:00
9a6fec094a fixing divider and spacer resize 2017-10-10 08:35:26 +00:00
61af224d7d Fixing image resize 2017-10-09 12:12:47 +00:00
9b41641e97 Tests vars-on-top 2017-10-09 11:17:23 +00:00
4e2e9f6f8f rebasing on master 2017-10-09 11:17:23 +00:00
c29dc8b4c7 fixing tests 2017-10-09 11:15:58 +00:00
98a3c6b156 Tests no-unused-vars 2017-10-09 11:15:58 +00:00
69c540288b Tests one-var 2017-10-09 11:15:58 +00:00
651c9f5692 Tests one-var-declaration-per-line 2017-10-09 11:15:58 +00:00
9ad3778cf7 ES6 rules 2017-10-09 11:15:58 +00:00
c90e0e9f64 ES5 no-unused-vars 2017-10-09 11:15:58 +00:00
cb1730c4e2 ES5 no-var 2017-10-09 11:15:58 +00:00
3dd8a973fd ES5 vars-on-top 2017-10-09 11:15:58 +00:00
c3ea088fca ES5 one-var 2017-10-09 11:15:58 +00:00
a11d6d7868 ES5 one-var-declaration-per-line 2017-10-09 11:15:58 +00:00
a596add838 ES5 block-scoped-var 2017-10-09 11:15:58 +00:00
7e7103ddab ES5 block-scoped-var 2017-10-09 11:15:58 +00:00
0064970ed7 Add a test for an alignment setting of an image block in the editor [MAILPOET-1124] 2017-10-09 13:00:39 +03:00
9d93f3ea95 Add a test for image alignment rendering [MAILPOET-1124] 2017-10-09 09:37:31 +03:00
ff2a3cd19e Release 3.0.4 2017-10-05 12:09:28 +00:00
8419d95ea1 Fix spacer and divider resizing [MAILPOET-1131] 2017-10-05 10:48:52 +01:00
4ad317ac7b Release MP3 3.0.3 2017-10-03 21:37:51 +03:00
7cccebbf2c Merge pull request #1135 from mailpoet/wp_sync_collations_fix
Get rid of WP user IDs updating query in favor of an insert-update due to collation problems [MAILPOET-1132]
2017-10-03 21:01:44 +03:00
e4f76ee9eb Get rid of WP user IDs updating query in favor of an insert-update due to collation problems [MAILPOET-1132] 2017-10-03 20:52:35 +03:00
7f52f72c25 Releasing 3.0.2 2017-10-03 14:27:56 +00:00
44afcbbeaf Merge pull request #1134 from mailpoet/new-poll
Add a new poll to update page [MAILPOET-1129]
2017-10-02 19:55:36 +03:00
e816c59539 Add a new poll to update page 2017-10-02 18:47:39 +03:00
c74421a42a Merge pull request #1133 from mailpoet/permission_update_fix
Remove the check for a plugin update permission [MAILPOET-1130]
2017-10-02 14:58:08 +02:00
23eb4633c4 Remove the check for a plugin update permission [MAILPOET-1130] 2017-10-02 15:44:06 +03:00
26241afb86 Add image alignment option to newsletter editor [MAILPOET-1124] 2017-10-02 15:30:43 +03:00
92dbf966a1 Add a UI hint for managing capabilities using the Members plugin [MAILPOET-1123] 2017-10-02 10:33:20 +01:00
db226b54a8 Include admin-global.css only on admin pages [MAILPOET-493] 2017-10-02 10:22:40 +01:00
3af059f5c4 Fix MailPoet icon displaying in Members tab on production [MAILPOET-493] 2017-10-02 10:22:40 +01:00
8706abcdf0 Change access_plugin_admin permission label [MAILPOET-493] 2017-10-02 10:22:40 +01:00
2129d041ac Fix indentation [MAILPOET-493] 2017-10-02 10:22:40 +01:00
2a4a44ebb5 Make a condition more easy to read [MAILPOET-493] 2017-10-02 10:22:40 +01:00
a4f2d5402c Manage MP3 permissions with WP role capabilities, add Members plugin support [MAILPOET-493] 2017-10-02 10:22:40 +01:00
9f5fc151b4 Move throttling out of the Subscriber model to the API 'subscribe' method [MAILPOET-1115] 2017-09-28 15:45:35 +01:00
8a91eb46e6 Fix the possibility of repeatedly submitting a form with an existing e-mail address [MAILPOET-1115] 2017-09-28 12:59:57 +01:00
e4ab928e82 Merge pull request #1127 from mailpoet/presubscribed_wp_sync_fix
Fix synchronization of presubscribed WP users [MAILPOET-1127]
2017-09-28 11:24:32 +02:00
a1b02cb862 Fix synchronization of presubscribed WP users [MAILPOET-1127] 2017-09-28 10:44:29 +03:00
84b942b9d2 Merge pull request #1121 from mailpoet/template_sort
Applies sorting by date created and name [MAILPOET-1119]
2017-09-27 11:14:00 +02:00
1ca99a6209 Updates Premium tab language 2017-09-27 10:07:36 +01:00
6b61abe8c0 Removes text domain from plugin header 2017-09-27 10:05:10 +01:00
27028ca1ef Merge pull request #1124 from mailpoet/alc_and_post_exclude_search_results
Prevents excluded post types from being displayed in newsletter editor [MAILPOET-701]
2017-09-27 11:40:51 +03:00
eed88926a2 Merge pull request #1120 from mailpoet/editor_horizontal_scroll_fix
Fixes horizontal scrolling inside post/ALC options panel [MAILPOET-1118]
2017-09-27 11:31:34 +03:00
b25877c514 Bump up release version to 3.0.1 2017-09-26 18:18:17 +03:00
119e574495 Prevents excluded post types from being displayed in newsletter editor 2017-09-25 19:45:33 -04:00
7308d253b2 Applies sorting by date created and name 2017-09-25 18:47:43 -04:00
1c19b71697 Fixes horizontal scrolling inside post/ALC options panel 2017-09-25 18:09:58 -04:00
7551fff93f Merge pull request #1116 from mailpoet/fix-tests
Fixing Shortcodes issue [MAILPOET-1104]
2017-09-25 17:14:35 -04:00
b2aa919574 Merge pull request #1118 from mailpoet/fix-query
Add index to improve query performance [MAILPOET-1117]
2017-09-25 17:04:25 -04:00
1102bbe483 Merge pull request #1056 from mailpoet/resize-image
Add image resize feature [MAILPOET-1047]
2017-09-25 13:07:10 +03:00
b78dd22ba9 Merge pull request #1109 from mailpoet/templates-images-src
Adding https prefix the image sources [MAILPOET-1109]
2017-09-25 12:08:02 +03:00
73110ada46 fixing ESLint tests 2017-09-25 09:06:55 +00:00
74dedd06bc changing missing tempaltes 2017-09-25 08:57:18 +00:00
20c936d13b limitting width with CSS 2017-09-21 18:58:17 +00:00
f135b89de9 Fixed image resize bugs 2017-09-21 18:58:16 +00:00
6a83930ae0 Resizing the image fixed 2017-09-21 18:57:35 +00:00
a1d0acfac2 Add image resize feature 2017-09-21 18:56:47 +00:00
04be06c0cb remove additional new line 2017-09-21 18:47:43 +00:00
78d52d6298 Merge pull request #1117 from mailpoet/eslint
Eslint rules [MAILPOET-1081]
2017-09-21 19:42:19 +03:00
5ff7c28c43 Merge pull request #1110 from mailpoet/es6_spacing
Fix ESLint spacing rules for ES6 [MAILPOET-1082]
2017-09-21 17:15:57 +03:00
5526f315d2 Merge pull request #1115 from mailpoet/scheduled_newsletter_status_fix
Sets newsletter status to draft when it's unscheduled [MAILPOET-1060]
2017-09-21 16:32:12 +03:00
d5e25fdeb1 Merge pull request #1114 from mailpoet/long_email_sql_error_fix
Fixes SQL error resulting from subscription with long email [MAILPOET-1113]
2017-09-21 16:17:21 +03:00
90a7bf5179 Adds back rendered subject clearing test
Removes duplicate line
2017-09-21 09:13:13 -04:00
bf1f696870 Add index to improve query performance
[MAILPOET-1117]
2017-09-21 13:17:02 +01:00
95551ad049 ES5 keyword-spacing 2017-09-21 09:13:36 +00:00
1ad90680f4 ES5 object-curly-spacing 2017-09-21 09:12:52 +00:00
d69d3cb421 ES5 array-bracket-spacing 2017-09-21 09:12:37 +00:00
9adca07393 ES5 computed-property-spacing 2017-09-21 09:12:23 +00:00
a9d129fddc ES5 block-spacing 2017-09-21 09:12:09 +00:00
b4ac09bea3 ES5 key-spacing 2017-09-21 09:11:55 +00:00
b1a403d9b5 ES5 space-infix-ops 2017-09-21 09:09:29 +00:00
28504fb5e3 ES5 spaced-comment 2017-09-21 09:08:52 +00:00
8ebb8e3c02 ES5 no-trailing-spaces 2017-09-21 09:04:47 +00:00
c95c2cd1ae ES5 space-in-parens 2017-09-21 09:04:32 +00:00
946bee2194 ES5 space-before-blocks 2017-09-21 09:02:50 +00:00
1f9bd04308 ES5 space-unary-ops 2017-09-21 08:52:30 +00:00
33572b2dc7 ES5 no-multi-spaces 2017-09-21 08:47:23 +00:00
680446b77e ES5 space-before-function-parens 2017-09-21 08:35:12 +00:00
bf1d76a3a7 Fix readme.txt 2017-09-20 16:57:17 +01:00
c915fcfdff Release 3.0.0 2017-09-20 15:21:55 +01:00
02966c3b93 Sets cron daemon timeout to 5s across the plugin
Adds hook to override cron request arguments
2017-09-20 14:59:48 +01:00
84dc48daec Allow passing cron timeouts
[MAILPOET-1114]
2017-09-20 14:59:48 +01:00
12225004f4 Apply hook on cron timeout
[MAILPOET-1114]
2017-09-20 14:59:48 +01:00
320dfa2ec5 Extracts duplicate code into reusable methods
Updates unit test
2017-09-20 14:59:48 +01:00
b5f3016085 Removes URL from user agent
(https://mailpoet.slack.com/archives/C02MTKAJL/p1505488541000029?thread_ts=1505488163.000795&cid=C02MTKAJL)
2017-09-20 14:59:48 +01:00
cd53e369d0 Allows accessing full URL from within custom cron hook 2017-09-20 14:59:48 +01:00
6fc11af774 Returns error message instead of empty body 2017-09-20 14:59:48 +01:00
42e3a97616 Fixing Shortcodes issue 2017-09-20 12:34:27 +00:00
6b16aa1692 Sets newsletter status to draft when it's unscheduled 2017-09-19 21:59:03 -04:00
03d0de74e4 Merge pull request #1108 from mailpoet/send_twice_tooltip
Show a tooltip about sending an email twice only when the Send button is disabled [MAILPOET-1098]
2017-09-19 20:38:10 -04:00
c3b643df84 Prevents leaking SQL errors in API response 2017-09-19 20:32:26 -04:00
697f9ba5bc Adds min/max email length in UI and backend 2017-09-19 20:04:49 -04:00
28c75c5b96 Adds a thousand separator 2017-09-19 09:55:38 -04:00
6f255854f2 Merge pull request #1112 from mailpoet/copy_update
Update free MSS plan size to 2000 subscribers [MAILPOET-1112]
2017-09-19 12:46:36 +03:00
91c5f9c43e Clarify Premium plugin benefits 2017-09-19 12:41:25 +03:00
62acd6404a Update free MSS plan size to 2k subscribers, update plugin description 2017-09-19 12:15:46 +03:00
adc1461771 Don't show send tooltip for paused newsletters [MAILPOET-1098] 2017-09-19 08:51:16 +03:00
66cc0964ce Merge pull request #1106 from mailpoet/fix-tests
Fixing MP API test
2017-09-18 18:23:20 -04:00
10d77720ad Merge pull request #1107 from mailpoet/hooks_unit_test_update
Updates hooks unit test [MAILPOET-1110]
2017-09-18 17:39:50 +02:00
475114c6f9 Fix ES6 no-irregular-whitespace eslint rule [MAILPOET-1082] 2017-09-18 18:31:13 +03:00
a0fec7d103 Fix ES6 space-infix-ops eslint rule [MAILPOET-1082] 2017-09-18 18:27:43 +03:00
4d9d92a026 Fix ES6 array-bracket-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:26:43 +03:00
e51aa8c271 Fix ES6 space-in-parens eslint rule [MAILPOET-1082] 2017-09-18 18:25:37 +03:00
d44adedade Fix ES6 key-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:24:26 +03:00
9fb3c50aa7 Fix ES6 no-multi-spaces eslint rule [MAILPOET-1082] 2017-09-18 18:23:36 +03:00
907053a349 Fix ES6 space-unary-ops eslint rule [MAILPOET-1082] 2017-09-18 18:22:48 +03:00
f0f85cfb59 Fix ES6 template-curly-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:21:44 +03:00
44d0341fb2 Fix ES6 keyword-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:20:55 +03:00
0cdae52c66 Fix ES6 react/jsx-curly-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:18:45 +03:00
0cd9c8e416 Adding https prefix the image sources 2017-09-18 15:11:55 +00:00
9e3010ab52 Fix ES6 react/jsx-tag-spacing eslint rule [MAILPOET-1082] 2017-09-18 18:05:57 +03:00
d831b2df55 Explicitly sets up hooks instead of assuming they are already set up 2017-09-18 10:43:17 -04:00
16ff630e88 Show a tooltip about sending an email twice only when the Send button is dsiabled [MAILPOET-1098] 2017-09-18 17:42:24 +03:00
d35763662e Fixing MP API test 2017-09-18 12:00:43 +00:00
10be411b12 Prepare release v3.0.0 2017-09-18 11:35:59 +01:00
6ecce192f7 Merge pull request #1105 from mailpoet/wp_sync_multisite
Fix WP sync throwing 'Table "users" doesn't exist' errors on multisite subsites [MAILPOET-1107]
2017-09-18 11:48:30 +03:00
ee07e60fe9 Adds new survey 2017-09-18 09:13:06 +01:00
a35d7a1154 Fix WP sync throwing 'Table users doesn't exist' errors on multisite subsites [MAILPOET-1107] 2017-09-18 10:55:49 +03:00
ebba8dbfd6 Merge pull request #1103 from mailpoet/twig_version_conflict_detection_improvement
Updates Twig version conflict detection logic [MAILPOET-1068]
2017-09-18 10:42:51 +03:00
44c637c06b Merge pull request #1101 from mailpoet/premium_key_in_beacon
Add Premium key to Help Scout beacon [MAILPOET-1090]
2017-09-17 12:08:52 -04:00
d54ba734bf Adds a min-max range of supported Twig versions 2017-09-17 11:25:35 -04:00
b45fc22306 Updates coding style and cleans up JS script inclusion part 2017-09-16 11:34:21 -04:00
994935d4ae Adds check for minimum Twig version loaded by external plugins 2017-09-16 11:33:40 -04:00
ceb5ce850c Removes deprecated Twig_ExtensionInterface::getName()
(https://github.com/twigphp/Twig/blob/2.x/CHANGELOG#L207)
Removes deprecated Twig_Extension_GlobalsInterface
(https://github.com/twigphp/Twig/blob/2.x/CHANGELOG#L259)
2017-09-16 11:30:40 -04:00
97b5ed945d Merge pull request #1100 from mailpoet/update-send-copy
Update send copy [MAILPOET-1101]
2017-09-14 20:02:28 +02:00
873b322245 Translate
[MAILPOET-1101]
2017-09-14 18:52:33 +01:00
12ad9e41e7 Translate a string
[MAILPOET-1101]
2017-09-14 18:40:04 +01:00
96b418e455 Our free plan will be for 1,000 subscribers and not 250
[MAILPOET-1101]
2017-09-14 17:35:15 +01:00
8ea7861f77 Merge pull request #1102 from mailpoet/welcome-tab-update
Update welcome tab [MAILPOET-1099]
2017-09-14 19:34:01 +03:00
821976c881 Make text random
[MAILPOET-1099]
2017-09-14 17:19:55 +01:00
6f1443e43d Update welcome tab
[MAILPOET-1099]
2017-09-14 15:35:07 +01:00
09fcaecdfc Add Premium key to Help Scout beacon [MAILPOET-1090] 2017-09-14 16:24:15 +03:00
efd72ca9f6 Merge pull request #1099 from mailpoet/update-readme
Update readme.txt for launch v3
2017-09-14 15:38:36 +03:00
550b5e9aed More readme.txt updates
[MAILPOET-1105]
2017-09-14 13:37:10 +01:00
4b7ae5fcff Fix typo
[MAILPOET-1105]
2017-09-14 13:28:44 +01:00
fa85e12127 Update premium section in readme.txt
[MAILPOET-1105]
2017-09-14 13:27:07 +01:00
1cce50902b Update Send with... other copy
[MAILPOET-1101]
2017-09-14 11:39:20 +01:00
2048fa5cf9 Update Send with... mailpoet copy
[MAILPOET-1101]
2017-09-14 11:31:43 +01:00
f438c8fd31 Update readme.txt for launch v3
[MAILPOET-1105]
2017-09-14 10:15:00 +01:00
0bfa832dad Merge pull request #1098 from mailpoet/subscribers-fix
Subscribers fix [MAILPOET-1102]
2017-09-13 18:17:56 +03:00
483dfbe1ec Fix removal of WP segment subscribers without wp_user_id [MAILPOET-1102] 2017-09-13 16:46:50 +03:00
561fee491d Merge pull request #1097 from mailpoet/makepot_views_fix
Fix makepot adding extra slashes to escaped characters in views [MAILPOET-1093]
2017-09-13 14:54:25 +02:00
97d157192a Remove orphaned links
[MAILPOET-1102]
2017-09-13 13:30:23 +01:00
6b14a8a057 Remove data from usermeta
[MAILPOET-1102]
2017-09-13 13:18:39 +01:00
d27b187f5e Fix QA problems
[MAILPOET-1102]
2017-09-13 13:15:50 +01:00
02d49ba2ca DELETE subscribers in WP list which are not WP users
[MAILPOET-1102]
2017-09-13 13:07:01 +01:00
f3571a5855 Add another testing scenario
[MAILPOET-1102]
2017-09-13 08:54:54 +01:00
3d5f0df213 Don't delete subscribers with wp_user_id = 0 [MAILPOET-1102] 2017-09-13 10:15:09 +03:00
595a201fe7 Stop deleting subscribers
[MAILPOET-1102]
2017-09-12 17:53:12 +01:00
c3db7d8148 Release 3.0.0-rc.2.0.3 2017-09-12 15:41:06 +03:00
4a2187ff32 Merge pull request #1096 from mailpoet/translation_strings_update
Removes escape character in translations [MAILPOET-1093]
2017-09-12 14:24:38 +03:00
279c36a30d Merge pull request #1094 from mailpoet/initializer_update
Updates plugin initialization logic [MAILPOET-1097]
2017-09-12 12:34:27 +03:00
fd65117a5d Fix makepot adding extra slashes to escaped characters in views [MAILPOET-1093] 2017-09-12 11:17:04 +03:00
9305beace3 Removes escape character in translations 2017-09-11 19:27:03 -04:00
ba86cbfb18 Updates unit test 2017-09-11 11:40:14 -04:00
2ac7d1d4ab Breaks plugin initialization into 3 stages: preInit, init and postInit 2017-09-11 11:33:03 -04:00
e9c55260c8 Merge pull request #1092 from mailpoet/db_version_settings_logic_update
Uses plugin's settings to store DB version [MAILPOET-1095]
2017-09-11 18:15:17 +03:00
99b6a287f8 Highlight a container block when hovering over its tools [MAILPOET-1088] 2017-09-11 15:32:45 +01:00
d645f0cad4 Merge pull request #1087 from mailpoet/eslint-un
Eslint un [MAILPOET-1073]
2017-09-11 16:16:51 +02:00
b0343254c0 Renames db version setting value 2017-09-11 10:05:09 -04:00
cc368f015b Remove redundant argument
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
4e508855fc Fix eslint no-unused-expressions in tests
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
72c0a6f165 Fix eslint no-undef in tests
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
f266508654 Fix eslint no-undef in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
1893d82b2d Fix eslint no-unused-expressions in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
bb1dd6a2ec Fix eslint import/no-unresolved in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
7097ea5d9b Fix eslint no-unreachable in ES6
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
b4092e0641 Fix eslint no-unneeded-ternary in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
2c068c7bb6 Fix eslint no-unreachable in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
a1a4fcb978 Fix eslint no-unused-expressions in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
f77620d649 Fix eslint no-undef in ES5
[MAILPOET-1085]
2017-09-11 15:03:30 +01:00
9e932c9078 Merge pull request #1085 from mailpoet/improve-user-sync
Improve user sync [MAILPOET-1073]
2017-09-11 14:56:41 +03:00
de47dbe41b Removes arrow functions that are not supported in IE 2017-09-11 10:25:43 +01:00
6d36d67a60 Delete orphaned subscribers instead of updating their id
[MAILPOET-1073]
2017-09-11 10:09:32 +01:00
607bf51b37 Merge two test cases for one class
[MAILPOET-1073]
2017-09-11 09:28:39 +01:00
f38ed0272c Merge pull request #1093 from mailpoet/cron_helper_improvement
Cron helper improvement [MAILPOET-1096]
2017-09-11 11:23:01 +03:00
eef969439b Code comment
[MAILPOET-1073]
2017-09-11 09:22:40 +01:00
272f552f3c Clean data befre and after test run
[MAILPOET-1073]
2017-09-11 09:22:18 +01:00
dff9c1012b Moves widget initialization back to widgets_init hook
Removes priority from plugin initialization
2017-09-10 19:49:05 -04:00
52470360a1 Returns ping response body instead of boolean 2017-09-10 18:49:15 -04:00
6c62459ed4 Adds filter to override default cron request URL 2017-09-10 18:36:22 -04:00
98482cebf9 Uses plugin's settings to store DB version 2017-09-10 16:31:36 -04:00
509880119e Merge pull request #1090 from mailpoet/eslint-indent
Eslint indent [MAILPOET-1029]
2017-09-07 20:13:20 -04:00
195ccb5eed Fix indent rule in tests
[MAILPOET-1029]
2017-09-07 16:05:45 +01:00
122af1c943 Fix react/jsx-indent rule in ES6
[MAILPOET-1029]
2017-09-07 15:59:38 +01:00
169940058b Fix react/jsx-indent-props rule in ES6
[MAILPOET-1029]
2017-09-07 15:52:46 +01:00
478e60d60e Fix indent rule in ES5
[MAILPOET-1029]
2017-09-07 15:51:25 +01:00
9fc0ac8c4f Merge pull request #1089 from mailpoet/color_picker
Change color on click, add history to color picker [MAILPOET-1087]
2017-09-07 17:08:09 +03:00
e86b780479 Fix build`
[MAILPOET-1073]
2017-09-07 14:44:55 +01:00
42f08bdc65 Fix handling of empty color and transparent color selected from palette [MAILPOET-1087] 2017-09-07 15:48:14 +03:00
c2789cdac3 Don't load all ids to memory, PHP could crash
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
8a362f49f8 Add test for users synchronisation
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
784a80d1a5 Use ->prefix instead of wp_
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
922d2b4b5f Fix migration
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
91e8461cac Clean the code
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
8757598a2d Add index
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
524aabea1d Split users sync into multiple queries
[MAILPOET-1073]
2017-09-07 13:42:18 +01:00
513181ff47 Change color on click, add history to color picker [MAILPOET-1087] 2017-09-07 13:17:57 +03:00
6bc288ed54 Merge pull request #1088 from mailpoet/depreciated_twig_notice_fix
Fixed Twig's deprecated notice [MAILPOET-1092]
2017-09-07 12:48:11 +03:00
77f3a875dd Does not set global is_rtl variable 2017-09-06 20:56:52 -04:00
6584250d1a Adds is_rtl() function to Twig 2017-09-06 20:55:44 -04:00
e42db162aa Merge pull request #1086 from mailpoet/translation_fixes
Fix translations based on translator feedback on TX [MAILPOET-1091]
2017-09-06 16:30:13 +03:00
2762096167 Switch strtoupper to mb_strtoupper based on feedback 2017-09-06 16:14:52 +03:00
b2ec3e5f7b Fix translations based on translator feedback on TX [MAILPOET-1091] 2017-09-06 13:45:42 +03:00
e012bd6cbe Updates changelog & bumps up release version to 3.0.0-rc.2.0.2 2017-09-05 11:17:32 -04:00
a02e64e805 Merge pull request #1084 from mailpoet/editor_get_post_type_optimization
Removes unused properties from the object used to display post types in editor [MAILPOET-1086]
2017-09-05 17:43:27 +03:00
e4bb3e1133 Adds unit test 2017-09-05 10:33:10 -04:00
998795e0e0 Fix tests semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
ec44b84cc9 Fix ES6 no-extra-semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
efece061d0 Fix ES5 semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
e347fc74a2 Fix ES5 no-extra-semi eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
027418a86c Fix ES5 semi-spacing eslint rule [MAILPOET-1030] 2017-09-05 12:31:51 +01:00
864187aa02 Merge pull request #1080 from mailpoet/json_api_method_check_fix
Throws error when JSON API endpoint method is not found [MAILPOET-1074]
2017-09-05 13:08:37 +03:00
59ae6619c0 Browser preview mixed content error fix
Strips protocol from preview URL

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

5
.babelrc Normal file
View File

@ -0,0 +1,5 @@
{
"presets": [
"es2015", "react", "stage-2"
]
}

View File

@ -1,6 +1,4 @@
Listen 8080
<VirtualHost *:8080>
<VirtualHost *:80>
UseCanonicalName Off
ServerName mailpoet.loc
DocumentRoot /home/circleci/mailpoet/wordpress
@ -8,6 +6,9 @@ Listen 8080
LogLevel notice
<Directory /home/circleci/mailpoet/wordpress>
Options Indexes FollowSymLinks
AllowOverride All
RewriteEngine On
Require all granted
</Directory>
</VirtualHost>

View File

@ -1,9 +1,9 @@
version: 2
jobs:
qa_js_php5:
qa_js_security_php5:
working_directory: /home/circleci/mailpoet
docker:
- image: circleci/php:5.6.30-apache-browsers
- image: mailpoet/wordpress:5.6.30_20180417.1
- image: circleci/mysql:5.7
environment:
TZ: /usr/share/zoneinfo/Etc/UTC
@ -38,6 +38,10 @@ jobs:
command: |
mkdir test-results/mocha
./do t:j test-results/mocha/junit.xml
- run:
name: "Composer security check"
command: |
./do s:composer
- run:
name: "PHP Unit tests"
command: |
@ -81,6 +85,7 @@ jobs:
curl -sS https://getcomposer.org/installer | php
php composer.phar install
./do install
./do compile:all --env production
- save_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
paths:
@ -94,13 +99,56 @@ jobs:
command: |
docker-compose run codeception --steps --debug -vvv --html --xml
- store_artifacts:
path: ~/mailpoet/tests/acceptance-tests/_output
path: tests/_output
- store_test_results:
path: ~/mailpoet/tests/acceptance-tests/_output
path: tests/_output
acceptance_tests_multisite:
working_directory: /home/circleci/mailpoet
machine: true
steps:
- checkout
- run:
name: "Set up virtual host"
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
- restore_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
- restore_cache:
key: npm-{{ checksum "package.json" }}
- run:
name: "Set up test environment"
command: |
sudo apt-get update
sudo apt-get install circleci-php-5.6.23
sudo rm /usr/bin/php
sudo ln -s /opt/circleci/php/5.6.23/bin/php /usr/bin/php
# Install NodeJS+NPM
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install nodejs build-essential
# install plugin dependencies
curl -sS https://getcomposer.org/installer | php
php composer.phar install
./do install
./do compile:all --env production
- save_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
paths:
- vendor
- save_cache:
key: npm-{{ checksum "package.json" }}
paths:
- node_modules
- run:
name: Run acceptance tests
command: |
docker-compose run -e MULTISITE=1 codeception --steps --debug -vvv --html --xml
- store_artifacts:
path: tests/_output
- store_test_results:
path: tests/_output
php7:
working_directory: /home/circleci/mailpoet
docker:
- image: circleci/php:7.1-apache-browsers
- image: mailpoet/wordpress:7.1_20180417.1
- image: circleci/mysql:5.7
environment:
TZ: /usr/share/zoneinfo/Etc/UTC
@ -109,6 +157,9 @@ jobs:
- run:
name: "Set up virtual host"
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
- run:
name: "Prepare example.com for testing"
command: echo 127.0.0.1 example.com | sudo tee -a /etc/hosts
- restore_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
- restore_cache:
@ -119,7 +170,41 @@ jobs:
- run:
name: "PHP Unit tests"
command: |
WP_TEST_PATH="/home/circleci/mailpoet/wordpress" ./do t:u --xml
./do t:u --xml
- store_test_results:
path: tests/_output
- store_artifacts:
path: tests/_output
destination: codeception
- store_artifacts:
path: /tmp/fake-mailer/
destination: fake-mailer
php7_multisite:
working_directory: /home/circleci/mailpoet
docker:
- image: mailpoet/wordpress:7.1_20180417.1
- image: circleci/mysql:5.7
environment:
TZ: /usr/share/zoneinfo/Etc/UTC
steps:
- checkout
- run:
name: "Set up virtual host"
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
- run:
name: "Prepare example.com for testing"
command: echo 127.0.0.1 example.com | sudo tee -a /etc/hosts
- restore_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
- restore_cache:
key: npm-{{ checksum "package.json" }}
- run:
name: "Set up test environment"
command: source ./.circleci/setup.bash && setup php7_multisite
- run:
name: "PHP Unit tests"
command: |
./do t:multisite-unit --xml
- store_test_results:
path: tests/_output
- store_artifacts:
@ -132,6 +217,8 @@ workflows:
version: 2
build_and_test:
jobs:
- qa_js_php5
- qa_js_security_php5
- php7
- php7_multisite
- acceptance_tests
- acceptance_tests_multisite

View File

@ -2,47 +2,66 @@
function setup {
local version=$1
# install PHP dependencies for WordPress
if [[ $version == "php7" ]]; then
echo "deb http://packages.dotdeb.org jessie all" | sudo tee -a /etc/apt/sources.list.d/dotdeb.list
echo "deb-src http://packages.dotdeb.org jessie all" | sudo tee -a /etc/apt/sources.list.d/dotdeb.list
wget -qO - http://www.dotdeb.org/dotdeb.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install mysql-client php7.0-mysql zlib1g-dev
sudo docker-php-ext-install mysqli pdo pdo_mysql zip
else
sudo apt-get update
sudo apt-get install mysql-client php5-mysql zlib1g-dev
sudo docker-php-ext-install mysql mysqli pdo pdo_mysql zip
fi
local wp_cli_wordpress_path="--path=wordpress"
local wp_cli_allow_root="--allow-root"
# Add a fake sendmail mailer
sudo cp ./.circleci/fake-sendmail.php /usr/local/bin/
# configure Apache
sudo cp ./.circleci/mailpoet_php.ini /usr/local/etc/php/conf.d/
sudo cp ./.circleci/apache/mailpoet.loc.conf /etc/apache2/sites-available
sudo a2dissite 000-default.conf
sudo a2ensite mailpoet.loc
sudo a2enmod rewrite
sudo service apache2 restart
# Install NodeJS+NPM
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install nodejs build-essential
# install plugin dependencies
curl -sS https://getcomposer.org/installer | php
./composer.phar install
./do install
# Set up Wordpress
until mysql -h 127.0.0.1 -u root -e "select 1"; do
>&2 echo "Mysql is starting up ... will try again momentarily"
sleep 1
done
# Set up WordPress
mysql -h 127.0.0.1 -u root -e "create database wordpress"
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
./wp-cli.phar core download --allow-root --path=wordpress
wp core download $wp_cli_wordpress_path $wp_cli_allow_root
# Generate `wp-config.php` file with debugging enabled
echo "define(\"WP_DEBUG\", true);" | ./wp-cli.phar core config --allow-root --dbname=wordpress --dbuser=root --dbhost=127.0.0.1 --path=wordpress --extra-php
echo "define(\"WP_DEBUG\", true);" | wp core config --dbname=wordpress --dbuser=root --dbhost=127.0.0.1 --extra-php $wp_cli_wordpress_path $wp_cli_allow_root
# Change default table prefix
sed -i "s/\$table_prefix = 'wp_';/\$table_prefix = 'mp_';/" ./wordpress/wp-config.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
if [[ $version == "php7_multisite" ]]; then
# Configure multisite environment
wp core multisite-install --admin_name=admin --admin_password=admin --admin_email=admin@mailpoet.loc --url=http://mailpoet.loc --title="WordPress MultiSite" $wp_cli_wordpress_path $wp_cli_allow_root
cp ./.circleci/wordpress/.htaccess ./wordpress/
# Add a second blog
wp site create --slug=php7_multisite $wp_cli_wordpress_path $wp_cli_allow_root
echo "WP_TEST_MULTISITE_SLUG=php7_multisite" >> .env
echo "WP_TEST_PATH_MULTISITE=/home/circleci/mailpoet/wordpress" >> .env
echo "HTTP_HOST=mailpoet.loc" >> .env
# Add a third dummy blog
wp site create --slug=dummy_multisite $wp_cli_wordpress_path $wp_cli_allow_root
else
wp core install --admin_name=admin --admin_password=admin --admin_email=admin@mailpoet.loc --url=http://mailpoet.loc --title="WordPress Single" $wp_cli_wordpress_path $wp_cli_allow_root
echo "WP_TEST_PATH=/home/circleci/mailpoet/wordpress" >> .env
fi
# Softlink plugin to plugin path
ln -s ../../.. wordpress/wp-content/plugins/mailpoet
./wp-cli.phar plugin activate mailpoet --path=wordpress
# Create .env file with correct path to WP installation
# TODO: Remove this line after PR gets merged and CircleCI env variables change
echo "WP_TEST_PATH=\"/home/circleci/mailpoet/wordpress\"" > .env
# Activate plugin
if [[ $version == "php7_multisite" ]]; then
wp plugin activate mailpoet --url=http://mailpoet.loc/php7_multisite/ $wp_cli_wordpress_path $wp_cli_allow_root
else
wp plugin activate mailpoet $wp_cli_wordpress_path $wp_cli_allow_root
fi
}

View File

@ -0,0 +1,12 @@
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]

View File

@ -1,4 +1,6 @@
WP_TEST_PATH="/var/www/wordpress"
WP_TEST_PATH_MULTISITE="/var/www/wordpress"
WP_TEST_MULTISITE_SLUG=""
WP_TEST_ENABLE_NETWORK_TESTS="true"
WP_TEST_IMPORT_MAILCHIMP_API=""
WP_TEST_IMPORT_MAILCHIMP_LISTS="" // (separated with comma)
@ -16,4 +18,5 @@ WP_TEST_MAILER_SMTP_LOGIN=""
WP_TEST_MAILER_SMTP_PASSWORD=""
WP_SVN_USERNAME=""
WP_SVN_PASSWORD=""
WP_TRANSIFEX_API_TOKEN=""
WP_TRANSIFEX_API_TOKEN=""
HTTP_HOST="" // URL of your site (used for multisite env and equals to DOMAIN_CURRENT_SITE from wp-config.php)

View File

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

View File

@ -10,79 +10,13 @@
"jsx": true
}
},
"settings": {
"import/resolver": "webpack"
},
"rules": {
// Exceptions
"comma-dangle": ["error", "always-multiline"],
"import/no-amd": 0,
"react/no-multi-comp": 0,
"react/sort-comp": 0,
"react/jsx-max-props-per-line": 0,
"react/prop-types": 0,
"react/jsx-first-prop-new-line": 0,
"react/jsx-indent-props": 0,
"react/no-is-mounted": 0,
"react/jsx-no-target-blank": 0,
"react/no-render-return-value": 0,
"react/jsx-boolean-value": 0,
"react/jsx-indent": 0,
"react/jsx-no-bind": 0,
"react/no-array-index-key": 0,
"react/self-closing-comp": 0,
"react/jsx-tag-spacing": 0,
"react/jsx-closing-bracket-location": 0,
"react/no-string-refs": 0,
"react/jsx-curly-spacing": 0,
"react/no-did-mount-set-state": 0,
"react/prefer-stateless-function": 0,
"jsx-a11y/label-has-for": 0,
"jsx-a11y/no-static-element-interactions": 0,
"jsx-a11y/alt-text": 0,
"func-names": 0,
"object-shorthand": 0,
"no-bitwise": 0,
"arrow-body-style": 0,
"prefer-template": 0,
"keyword-spacing": 0,
"default-case": 0,
"array-callback-return": 0,
"consistent-return": 0,
"no-unreachable": 0,
"no-extra-semi": 0,
"import/no-unresolved": 0,
"import/extensions": 0,
"import/no-extraneous-dependencies": 0,
"camelcase": 0,
"template-curly-spacing": 0,
"eqeqeq": 0,
"no-lonely-if": 0,
"space-unary-ops": 0,
"block-scoped-var": 0,
"no-extra-bind": 0,
"no-multi-spaces": 0,
"class-methods-use-this": 0,
"key-spacing": 0,
"no-multiple-empty-lines": 0,
"space-in-parens": 0,
"no-case-declarations": 0,
"array-bracket-spacing": 0,
"newline-per-chained-call": 0,
"no-else-return": 0,
"max-len": 0,
"no-useless-concat": 0,
"no-unused-expressions": 0,
"no-sequences": 0,
"no-extra-boolean-cast": 0,
"dot-notation": 0,
"no-shadow": 0,
"one-var": 0,
"no-alert": 0,
"one-var-declaration-per-line": 0,
"no-script-url": 0,
"wrap-iife": 0,
"vars-on-top": 0,
"space-infix-ops": 0,
"no-irregular-whitespace": 0,
"padded-blocks": 0,
"no-underscore-dangle": 0,
"no-undef": 0
"import/extensions": 0 // we wouldn't be able to import jQuery without this line
}
}

View File

@ -8,32 +8,9 @@
"ecmaVersion": 6
},
"rules": {
"import/no-amd": 0,
"no-undef": 0,
"one-var": 0,
"indent": 0,
"linebreak-style": 0,
"no-whitespace-before-property": 0,
"object-property-newline": 0,
"global-require": 0,
"semi": 0,
"keyword-spacing": 0,
"no-bitwise": 0,
"newline-per-chained-call": 0,
"no-spaced-func": 0,
"func-call-spacing": 0,
"max-len": 0,
"space-unary-ops": 0,
"no-unused-vars": 0,
"no-unused-expressions": 0,
"no-underscore-dangle": 0,
"no-shadow": 0,
"padded-blocks": 0,
"vars-on-top": 0,
"space-before-blocks": 0,
"object-curly-spacing": 0,
"one-var-declaration-per-line": 0,
// Exceptions
"func-names": 0,
"space-before-function-paren": 0
// Temporary
"no-underscore-dangle": 0
}
}

4
.gitignore vendored
View File

@ -2,6 +2,7 @@
TODO
composer.phar
/vendor
/vendor_backup
tests/_output/*
tests/_support/_generated/*
node_modules
@ -20,4 +21,5 @@ assets/js/*.json
.vagrant
lang
.mp_svn
/nbproject/
/nbproject/
tests/_data/acceptanceGenerated.sql

View File

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

View File

@ -90,6 +90,7 @@ class RoboFile extends \Robo\Tasks {
$css_files = array(
'assets/css/src/admin.styl',
'assets/css/src/admin-global.styl',
'assets/css/src/newsletter_editor/newsletter_editor.styl',
'assets/css/src/public.styl',
'assets/css/src/rtl.styl',
@ -152,17 +153,34 @@ class RoboFile extends \Robo\Tasks {
return $this->_exec('./tasks/transifex_init.sh');
}
function testUnit($opts=['file' => null, 'xml' => false]) {
function testUnit(array $opts=['file' => null, 'xml' => false, 'multisite' => false, 'debug' => false]) {
$this->loadEnv();
$command = 'vendor/bin/codecept run unit -c codeception.unit.yml -f '.(($opts['file']) ? $opts['file'] : '');
$command = 'vendor/bin/codecept run unit -c codeception.unit.yml';
if($opts['multisite']) {
$command = 'MULTISITE=true ' . $command;
}
if($opts['file']) {
$command .= ' -f ' . $opts['file'];
}
if($opts['xml']) {
$command .= ' --xml';
}
if($opts['debug']) {
$command .= ' --debug';
}
return $this->_exec($command);
}
function testMultisiteUnit($opts=['file' => null, 'xml' => false, 'multisite' => true]) {
return $this->testUnit($opts);
}
function testCoverage($opts=['file' => null, 'xml' => false]) {
$this->loadEnv();
$command = join(' ', array(
@ -197,6 +215,10 @@ class RoboFile extends \Robo\Tasks {
return $this->_exec($command);
}
function securityComposer() {
return $this->_exec('vendor/bin/security-checker security:check --format=simple');
}
function testDebug($opts=['file' => null, 'xml' => false]) {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
@ -209,8 +231,27 @@ class RoboFile extends \Robo\Tasks {
return $this->_exec($command);
}
function testAcceptance() {
return $this->_exec('COMPOSE_HTTP_TIMEOUT=200 docker-compose run codeception --steps --debug -vvv');
function testAcceptance($opts=['file' => null, 'keep-deps' => false]) {
return $this->_exec(
'COMPOSE_HTTP_TIMEOUT=200 docker-compose run ' .
($opts['keep-deps'] ? '-e KEEP_DEPS=1 ' : '') .
'codeception --steps --debug -vvv ' .
'-f ' . ($opts['file'] ? $opts['file'] : '')
);
}
function testAcceptanceMultisite($opts=['file' => null, 'keep-deps' => false]) {
return $this->_exec(
'COMPOSE_HTTP_TIMEOUT=200 docker-compose run ' .
($opts['keep-deps'] ? '-e KEEP_DEPS=1 ' : '') .
'-e MULTISITE=1 ' .
'codeception --steps --debug -vvv' .
'-f ' . ($opts['file'] ? $opts['file'] : '')
);
}
function deleteDocker() {
return $this->_exec('docker-compose down -v --remove-orphans --rmi all');
}
function testFailed() {
@ -247,7 +288,7 @@ class RoboFile extends \Robo\Tasks {
->taskExec(
'./vendor/bin/phpcs '.
'--standard=./tasks/code_sniffer/MailPoet '.
'--runtime-set testVersion 5.3-7.0 '.
'--runtime-set testVersion 5.4-7.2 '.
'--ignore=./lib/Util/Sudzy/*,./lib/Util/CSS.php,./lib/Util/XLSXWriter.php,'.
'./lib/Util/pQuery/*,./lib/Config/PopulatorData/Templates/* '.
'lib/ '.
@ -256,7 +297,7 @@ class RoboFile extends \Robo\Tasks {
->taskExec(
'./vendor/bin/phpcs '.
'--standard=./tasks/code_sniffer/MailPoet '.
'--runtime-set testVersion 5.4-7.0 '.
'--runtime-set testVersion 5.4-7.2 '.
'--ignore=./tests/unit/_bootstrap.php '.
'tests/unit/ '.
$severityFlag
@ -288,15 +329,16 @@ class RoboFile extends \Robo\Tasks {
}
function svnPublish($opts = ['force' => false]) {
$this->loadWPFunctions();
$this->loadEnv();
$svn_dir = ".mp_svn";
$plugin_data = get_plugin_data('mailpoet.php', false, false);
$plugin_version = $plugin_data['Version'];
$plugin_dist_name = sanitize_title_with_dashes($plugin_data['Name']);
$plugin_dist_name = explode('-', $plugin_dist_name);
$plugin_dist_name = $plugin_dist_name[0];
$plugin_version = $this->getPluginVersion('mailpoet.php');
$plugin_dist_name = 'mailpoet';
$plugin_dist_file = $plugin_dist_name . '.zip';
if(!$plugin_version) {
throw new \Exception('Could not parse plugin version, check the plugin header');
}
$this->say('Publishing version: ' . $plugin_version);
// Sanity checks
@ -415,13 +457,9 @@ class RoboFile extends \Robo\Tasks {
$dotenv->load();
}
protected function loadWPFunctions() {
$this->loadEnv();
define('ABSPATH', getenv('WP_TEST_PATH') . '/');
define('WPINC', 'wp-includes');
require_once(ABSPATH . WPINC . '/functions.php');
require_once(ABSPATH . WPINC . '/formatting.php');
require_once(ABSPATH . WPINC . '/plugin.php');
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
protected function getPluginVersion($file) {
$data = file_get_contents($file);
preg_match('/^[ \t*]*Version:(.*)$/mi', $data, $m);
return !empty($m[1]) ? trim($m[1]) : false;
}
}

View File

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

View File

@ -2,6 +2,7 @@
@require 'select2/dist/css/select2.css'
@require 'datepicker/datepicker'
@require 'badge'
@require 'common'
@require 'modal'
@ -27,3 +28,8 @@
@require 'pages_custom'
@require 'mp2migrator'
@require '../../../node_modules/react-confirm-alert/src/react-confirm-alert.css'
@require 'newsletter_templates'
@require 'welcome_wizard'

View File

@ -0,0 +1,9 @@
badge()
text-transform uppercase
cursor pointer
color white
font-size 0.5625rem
font-weight 500
border-radius 3px
letter-spacing 1px
vertical-align middle

File diff suppressed because one or more lines are too long

View File

@ -28,6 +28,20 @@ a:focus
.select2-container
width: 25em !important
placeholder-color = #999 /* default Select2 placeholder color for single dropdown */
input.select2-search__field::-webkit-input-placeholder
color: placeholder-color
input.select2-search__field:-moz-placeholder
color: placeholder-color
input.select2-search__field::-moz-placeholder
color: placeholder-color
input.select2-search__field:-ms-input-placeholder
color: placeholder-color
.select2-container--default.select2-container--focus .select2-selection--multiple
border: 1px solid #aaa; /* default Select2 border for single dropdown */
// textareas
textarea.regular-text
width: 25em !important
@ -57,3 +71,10 @@ progress::-webkit-progress-value
progress::-moz-progress-bar
background-color: progress-foreground
border-radius: progress-border-radius
span.feedback-tooltip
badge()
display inline-block
padding 0 4px
background-color #ca4a1f

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

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

View File

@ -2,6 +2,7 @@ $excellent-badge-color = #2993ab
$good-badge-color = #f0b849
$bad-badge-color = #d54e21
$green-badge-color = #55bd56
$video-guide-badge-color = #46b450
#newsletters_container
h2.nav-tab-wrapper
@ -31,23 +32,34 @@ $green-badge-color = #55bd56
.mailpoet_badge
padding: 4px 6px 3px 6px
color: #FFFFFF
margin-right: 4px
text-transform: uppercase
font-size: 0.5625rem
font-weight: 500
border-radius: 3px
letter-spacing: 1px
vertical-align: middle
badge()
&_excellent
&_excellent, &_teal
background: $excellent-badge-color
&_good
&_good, &_yellow
background: $good-badge-color
&_bad
&_bad, &_red
background: $bad-badge-color
&_green
background: $green-badge-color
&_video
background: $video-guide-badge-color
line-height: 5em
padding: 7px 6px 7px 6px
text-decoration: none
&:hover, &:active, &:focus
color: #FFFFFF
background: $green-badge-color
&_grey
background: #c3c3c3
.dashicons
font-size: 14px;
line-height: 3.4em;

View File

@ -41,6 +41,8 @@ $master-column-tool-width = 24px
right: initial
&.mailpoet_display_tools
z-index: 21
.mailpoet_tool_slider
left: 0
@ -163,6 +165,7 @@ $master-column-tool-width = 24px
.mailpoet_delete_block_confirm
color: $warning-text-color
float: right
&:hover
color: $warning-text-color
@ -170,6 +173,7 @@ $master-column-tool-width = 24px
.mailpoet_delete_block_cancel
color: $warning-alternate-text-color
float: right
&:hover
color: $warning-alternate-text-color

View File

@ -12,9 +12,11 @@
font-size: 23px
.mailpoet_breadcrumbs
float: right
clear: both
float: left
margin-bottom: 13px
margin-right: 17px
margin-left: 17px
font-size: 0.9em
text-transform: uppercase
p
margin: 0

View File

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

View File

@ -1,15 +1,23 @@
#mailpoet_editor_bottom
margin-top: 39px
margin-left: 29px
margin: 10px 0 70px
.mailpoet_save_wrapper
float: right
position: relative
margin-right: 20px
margin-bottom: 10px
.mailpoet_save_options
border-radius(3px)
float: left
position: absolute
right: 0
z-index: 1000
overflow: hidden
margin: 5px 0 0 0
margin: 5px 0
clear: both
vertical-align: top
white-space: nowrap
background: $white-color
border: 1px solid $content-border-color
@ -33,23 +41,19 @@
.mailpoet_save_show_options
padding: 6px 3px 4px
&.mailpoet_save_show_options_active
.mailpoet_save_show_options_icon::before
content: '\f142'
.mailpoet_save_show_options_icon
vertical-align: middle
&::before
content: '\f140'
.mailpoet_save_as_template_container,
.mailpoet_export_template_container
border-radius(3px)
display: inline-block
position: absolute
right: 0
z-index: 1000
clear: both
margin-top: 5px
margin: 5px 0
padding: 0 10px
background-color: $white-color
border: 1px solid $structure-border-color
@ -61,7 +65,41 @@
.mailpoet_editor_last_saved
color: $primary-inactive-color
font-size: 0.9em
display: inline
position: absolute
right: 0
margin-top: 10px
.mailpoet_save_error
color: $error-text-color
.mailpoet_save_dropdown_down
.mailpoet_save_options,
.mailpoet_save_as_template_container,
.mailpoet_export_template_container
top: 100%
bottom: auto
.mailpoet_save_show_options
&.mailpoet_save_show_options_active
.mailpoet_save_show_options_icon::before
content: '\f142'
.mailpoet_save_show_options_icon
&::before
content: '\f140'
.mailpoet_save_dropdown_up
.mailpoet_save_options,
.mailpoet_save_as_template_container,
.mailpoet_export_template_container
top: auto
bottom: 100%
.mailpoet_save_show_options
&.mailpoet_save_show_options_active
.mailpoet_save_show_options_icon::before
content: '\f140'
.mailpoet_save_show_options_icon
&::before
content: '\f142'

View File

@ -14,7 +14,7 @@
cursor: pointer
.mailpoet_automated_latest_content_block_posts
overflow: auto
overflow: hidden
pointer-events: none
& > .mailpoet_block

View File

@ -21,10 +21,14 @@ $block-text-line-height = $text-line-height
left: 0
pointer-events: none
border: 1px solid $transparent-color
-webkit-transition: 0.3s;
transition: 0.3s;
&:hover > .mailpoet_block_highlight
&.mailpoet_highlight > .mailpoet_block_highlight
border: 1px dashed $block-hover-highlight-color
&.mailpoet_highlight > .mailpoet_block_highlight
border: 1px dashed $block-hover-highlight-color !important
.mailpoet_content
position: relative

View File

@ -52,7 +52,9 @@ $three-column-width = ($newsletter-width / 3) - (2 * $column-margin)
width: $column-margin + $one-column-width + $column-margin
// More than one column
& > .mailpoet_container_block > .mailpoet_container > .mailpoet_container_block > .mailpoet_container_horizontal
& > .mailpoet_container_block > .mailpoet_container > .mailpoet_container_block > .mailpoet_container_horizontal,
& > .mailpoet_container_block > .mailpoet_container > .mailpoet_posts_block > .mailpoet_posts_container > .mailpoet_container_block > .mailpoet_container > .mailpoet_container_block > .mailpoet_container_horizontal,
& > .mailpoet_container_block > .mailpoet_container .mailpoet_automated_latest_content_block_posts .mailpoet_container_horizontal
// Column number detection technique found here:
// http://stackoverflow.com/questions/8720931/can-css-detect-the-number-of-children-an-element-has

View File

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

View File

@ -54,3 +54,6 @@
.mailpoet_post_selection_loading
color: #999
.mailpoet_posts_container > .mailpoet_droppable_block
width: 100%

View File

@ -8,6 +8,8 @@ $content-border-color = $structure-border-color
#mailpoet_editor_heading
padding-left: 15px
margin-left: 2px
margin-bottom: 13px
clear: both
#mailpoet_editor_main_wrapper
border: 1px solid $content-border-color

View File

@ -131,6 +131,7 @@ body
.notice
.update-nag
margin-left: 2px + 15px !important
margin-right: 20px !important
/* Make a button group */
.mailpoet_button_group

View File

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

View File

@ -0,0 +1,12 @@
@require 'newsletter_editor/variables'
.mailpoet_template_iframe
position: absolute
z-index: -9999
top: 0
left: 0
width: $newsletter-width
max-width: $newsletter-width
.newsletter-templates-feedback
margin: 0 10px

View File

@ -1,9 +1,3 @@
.mailpoet_notice
position: relative
.mailpoet_notice_close
position: absolute
right: 0.5em
top: 0.5em
color: #999
text-decoration: none !important
clear: both

View File

@ -46,12 +46,17 @@ Please add custom styles to pages_custom.styl
margin-right: auto
h1
margin: 0.2em 200px 0 0
margin: 1em 0 0.5em 0
padding: 0
color: #32373c
line-height: 1.2em
font-size: 2.8em
font-weight: 400
text-align: center
h1.welcome
margin-right: 200px
text-align: left
h2
margin: 40px 0 .6em

View File

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

View File

@ -28,3 +28,36 @@
.mailpoet_progress_bar
background-color: hsla(191, 78%, 80%, 1)
background-image: linear-gradient(top, hsla(191, 78%, 80%, 1), hsla(191, 76%, 67%, 1))
.mailpoet_stepped_progress_bar
margin: auto
width: 400px
&:before
position: relative
top: 9px
content: ""
display: block
height: 2px
width: 100%
border-radius: 2px
background-color: #d8d8d8
margin: auto
.mailpoet_stepped_progress_bar_step
display: inline-block
&:before
position: relative
content: ""
display: block
height: 14px
width: 14px
border-radius: 14px
background-color: #d8d8d8
margin: auto
&.active
&:before
background-color: #979797
@media screen and (max-width 520px)
.mailpoet_stepped_progress_bar
width: 360px

View File

@ -19,13 +19,15 @@
flex-direction column
flex-basis 0
margin 0 25px 25px 0
border 1px solid #dedede
background-color #fff
border 2px solid #dcdcdc
max-width 500px
.mailpoet_sending_method_description
padding: 25px
flex-grow 1
flex-shrink 0
&:hover:not(.mailpoet_active)
border-color #c5c5c5
> li:last-child
margin-right 0
h3
@ -37,22 +39,36 @@
.mailpoet_status
display flex
flex-direction row
justify-content space-between
justify-content flex-end
align-items center
background-color #2f2f2f
background-color #dcdcdc
color #fff
text-overflow ellipsis
padding 15px
min-height 2em
padding 1em
span
visibility hidden
font-weight bold
div
margin-left 1em
.mailpoet_active
border 2px solid #088b00
&.mailpoet_invalid_key
border 2px solid #dc3232
.mailpoet_status
background-color #088b00
&.mailpoet_invalid_key
background-color #dc3232
.mailpoet_actions
color white
a:not(.button-primary)
color white
span
visibility visible
#mailpoet_mta_activate
visibility hidden
.mailpoet_actions
color initial
.tooltip.dashicons.dashicons-editor-help
line-height: 1.4
@ -62,6 +78,15 @@
margin-bottom: 2em
margin-top: 2em
.sending-free-plan-button
background: #FF5301
border-color: #e64c03
text-shadow: 0 -1px 1px #e64c03
box-shadow: 0 1px 0 #e64c03
margin: 10px 0
strong
text-transform: uppercase
.mailpoet_success_item::before
content ' '

View File

@ -0,0 +1,118 @@
.mailpoet_welcome_wizard_centered_column
display: flex
flex-direction: column
justify-content: center
align-items: center
.mailpoet_welcome_wizard_header img
margin-bottom: 20px
.mailpoet_welcome_wizard_steps
padding-top: 20px
width: 100%
.mailpoet_welcome_wizard_step_content
margin-top: 40px
max-width: 620px
min-height: 35%vh;
h1
font-weight: 400
padding-bottom: 10px
text-align: center
p
font-weight: normal
font-size: 15px
line-height: 22px
color: #595c65
text-align: center
margin: 10px 0;
#mailpoet_sender_form
margin-top: 30px
width: 330px
label
display: inline-block
font-size: 15px
margin-bottom: 20px
input[type="text"]
margin-top: 10px
font-size: 15px
width: 328px
height: 30px
input[type="submit"]
margin: 50px 0 25px 0
a
font-size: 12px
color: #595c65
.mailpoet_sender_form_loading
opacity: .5
.mailpoet_welcome_wizard_help_info_block
padding-left: 180px
position: relative
margin-bottom: 10px
p
text-align: left
.mailpoet_welcome_wizard_support_button
background: #32a8d9 url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAMAAAANIilAAAAA3lBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ymXGKAAAASXRSTlMAAQIFBwoPEBIUFRscHR8jKCkqLC0/Q0RGSEpNUFFXYHFzeXp9gIKFjKCjpamwvL7Aw8bIy8zN0NLT1dja3ODk5ujq7PT19/3+6Nyy9QAAAklJREFUeAGl1/1W4jwQBvAHBapi0erLK7XsKmLxAyp+SBEVAUXluf8b2ibHnqUk0LT7+3+anJlpMoGe1Wh3B9MZOZsOuu2GBWN2q//NhO9+y4YJtzenxrznIs1xyJXCY6xTDfhj3Gl6jm1ZtuM1O2P+CKpY6eST0sh3kOD4I0qfJ9ArXVG6cwtQFNw7SlclaGzdU3ipY4X6C4X7LSh2n2VN/CJWKvqygs+7yroydlLDWrWJjF5auyT3PKwgRWUod17CIpmrhzJSlR9k1hI1kuuWYaAs116oWFXUd1KBkcpE1LuKWCDyXIOhmsh5gB/HjPgw5jMS93koeqMIY0XRLSEkl5E6Mqgz4kLoiX5G7PKLy74usUT0eQ8Rex5/RviPOodIcknObQAtkqNCtuDCiGQLQF+mOtu2ZcL7gCWq5uCvTWvZJhSO6AwLDZJjZDYm2UCbZAeZdUi20SXZRGZNkl0MSHrIzCM5wFTmKzOH5BQzkjbWlkpXMZvkDIxYgNIkKb1iMfJPwXm3vc2ImjC1w3SNdkDyPW+pXJJPeZvklGSQtz2vSV7k/THeSDaUX9LMPiM7usNALY7ijGSYdgwdQqvwSvJcPQCNgo8Y2VOPXqNt35C81R36m2pPaRf28l03eCQ53Mh30ZXkwrmu2Ph3VC9382BlrMgXrA405sHqKGUerA5x5sHq+GgebDy4/v/IBZlG5qMbJpgP6/tnr0z6MHkmbB+4p9dvXPbxO+sDZehZsYxPI956G/keZQzP95BGfQ7y/Sm4+LUDrT+vKBtiP2phEAAAAABJRU5ErkJggg==') center center no-repeat
background-size: 30px
display: inline-block
height: 54px
width: 54px
border-radius: 28px
position: absolute
top: 10px
left: 70px
box-shadow: 2px 2px 8px #666;
transform: scale(0.8)
.mailpoet_welcome_wizard_video_badge
cursor: default
position: absolute
top: 20px
left: 30px
line-height: 1.5em
padding-bottom: 0
.dashicons
line-height: 1em
&:hover
background: $video-guide-badge-color
.mailpoet_welcome_wizard_mail_icon
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAABrCAYAAADw4IlaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABT9JREFUeNrsnTFSGz0YhhWSgpJJkS4z9tBS4JbKOUHwDfAJYp8AcwLDCSBdOpwT4IoWCoo0jJ1JlybcIPmEvw0LwyTG1iftrp5nRjGh+PktHmv16t3YzgEA5Mqrp9/Y297pysMnGftMDwRmIuPk8vZm+qyAIt9AHsbMExjTFwnPHgko8vkV75y5gUj0RMLJRukbrHwQk/HfFVD3fRfMCUSmU6yALeYCErCFgJCUDaYAEBAQEAABAQEBYvImwc+8k3F0eXtzzPRXC61iD2VsNVlA/+TG8mQ/yuNQRLzmV59cvF15OJWxm9MluCvjSp78CAWSibclw1diVynkq8oe8FAmYaZ1IMSTr6viDXLbAz5HS8aFTMqZXpbvUMRu1dPLbSXu91x1BZz6IKGBIiQHMmZ6axjYhIyZgXzeg6F6EecSLKuU37t1VvmhS4SUc5ksvyK20CaIeC0/n25xC1TohOvvcu6seqqx1h5Qfuhcxgf5smewGhJSwsg30lUv9B577hY3lfoxTxpC/J2t8tCWcWawGvqQcqVHBfCCkOHDnVuc64XmWFe9SWVCiAaHvjzpz7rJDXn53NXV0D/xI0LKf0PGoVG6vdaQGGzbFfwYxv/PyWhrSAnNQEUkpDwv375ebkPLV7RXnZDymQgYIaS0NKSc66sd8R5CxrlByJjq5dZkL256EO1rNg0pQ4OQcv9q16OF3I9WrgxCxv2Wyv/+1gkZSQUsiXisIWUS+D9d9MoXuYUU/3x9ODM6WvFhsl38211LolVxPjj4yO4WRzahX1Fdl8mRjXF/638vfsXrxwp60btgje4djfKhaXSvbNzfHulebxrzOSXpgvXVNSwd2YR8JfuQ0qhe2bi/nbqEt8UlvRtGQ0rH0Sv/S74DZ9jfashIdk9mJW7Jp1f+59HKqatYf9s4AVXColfuu8x7ZcP+1s/r2v1tIwUsiXh/BOAy7JW1v/Uhw6q/bYfob2sfQpYMKdn0ynXrbxu9Aj4Rcap7Q8teuZtYPqv+1jmj/jYbAYvV0LhXvkjRK2vI8N2tVX/btupvsxKwJGJjeuVSf2txtGLe32YpYEnEY10NLXvllpF4lv3txEXqb7MWUCWcG/fKs5BHNtrfjpxtf9urY+tT6/eGqUOvXOpvLY5WkvS3IXnjak6pV/6qlzaLXvnFRzbG/e217vVq/7YmjXl3LP2nAFa98sC9oFeO0N92mvKeOo17e7aUvXIu/S0CLhdSrHvlwRP5Ri6T/hYBlxfRH0lY9cpj7ZUPcutvCSEvDymWvfKpUcgY1jndsgI+E1KcXa8cksr3twi4xmpoGFLWZepq0t8i4PoiWvbKq4SMWvW3CBhORKteeVlq2d8SQsJK6Fednh4yj12cz82b66o3zX3++ZyQBxEte+VHIcPVvL9lBTQMKc6uV25Mf8sKaC9iyF65cf0tAsYTceTWO7JpZH/LJTh+SPmgd7gseydzcbQyYQZZAUOJeOaW65Ub39+yAqYNKUWv/Mkt7nzZ0hXPX6ZPSLcIGCWkuOpVeVyCARAQEBAAAQEBARAQEBAAAQEBARAQEBAAAQEBARAQEBAQEAABAQEBEBAQEAABAQEBEBAQEAABAQEBEBAQEAABAQEBEBAQEAABoX6s+g6p3b3tnd9MH7ACAgICICAgIAACQi0FnDMVkFJAPsURUnD3qvhqb3tn5uJ8WjjA/VX38vamXd4DDpkTiEjf//G6+NuPXz+/vX/77rt8uc/cgLV8xaeJvi5/VyS8Fgn9x9Vv6uV4k7mCUPs9GV9k9PhEUagMfwQYAFppkb3J5HUdAAAAAElFTkSuQmCC') center center no-repeat
background-size: 40px 27px
display: inline-block
width: 40px
height: 27px
position: absolute
top: 50px
left: 75px
@media screen and (max-width 520px)
.mailpoet_welcome_wizard_help_info_block
padding-left: 150px
.mailpoet_welcome_wizard_support_button
left: 40px
.mailpoet_welcome_wizard_video_badge
left: 10px
.mailpoet_welcome_wizard_mail_icon
left: 50px
.mailpoet_welcome_wizard_step_controls
margin-top: 50px
.button
margin:0 10px
.mailpoet_welcome_wizard_woo_screenshot
margin-top: 30px
width: 400px
@media screen and (max-width 520px)
.mailpoet_welcome_wizard_woo_screenshot
width: 340px
.welcome_wizard_video
position: absolute
top: -1000px

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

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

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/fonts/mailpoet.ttf Normal file

Binary file not shown.

BIN
assets/fonts/mailpoet.woff Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="47.002px" height="38.003px" viewBox="0 0 47.002 38.003" enable-background="new 0 0 47.002 38.003" xml:space="preserve">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#565656" d="M46.328,36.365c-1.188,1.725-3.553,2.158-5.273,0.962L25.479,26.52
c-1.104-0.763-1.674-2.007-1.631-3.257c-2.006,2.157-4.642,3.606-7.594,4.145c-3.626,0.663-7.288-0.13-10.311-2.227
c-3.024-2.098-5.054-5.253-5.714-8.887c-0.661-3.636,0.127-7.31,2.221-10.344c4.325-6.264,12.927-7.834,19.177-3.5
c5.672,3.938,7.486,11.412,4.537,17.443c1.152-0.486,2.519-0.392,3.627,0.377l15.58,10.808C47.09,32.274,47.52,34.641,46.328,36.365
z M23.235,12.09c-0.459-2.534-1.874-4.734-3.982-6.196C14.897,2.87,8.896,3.963,5.878,8.331c-3.014,4.373-1.922,10.388,2.435,13.408
c4.356,3.025,10.356,1.932,13.374-2.438C23.146,17.187,23.696,14.625,23.235,12.09z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 814 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -6,10 +6,25 @@ window.mixpanelTrackingId = "8cce373b255e5a76fb22d57b85db0c92";
if (mailpoet_analytics_enabled) {
mixpanel.init(window.mixpanelTrackingId);
mixpanel.init(window.mixpanelTrackingId, {
loaded: function(mixpanel) {
// used in lib/Analytics/Analytics.php
document.cookie = "mixpanel_distinct_id=" + mixpanel.get_distinct_id();
}
});
mixpanel.register({'Platform': 'Plugin'});
if(typeof window.mailpoet_analytics_public_id === 'string' && window.mailpoet_analytics_public_id.length > 0) {
if(window.mailpoet_analytics_new_public_id === true) {
mixpanel.alias(window.mailpoet_analytics_public_id);
} else {
mixpanel.identify(window.mailpoet_analytics_public_id);
}
}
if (mailpoet_analytics_data != null) {
mixpanel.track('MailPoet 3', mailpoet_analytics_data);
mixpanel.people.set(mailpoet_analytics_data);
}
}

View File

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

View File

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

View File

@ -17,7 +17,7 @@
*/
var eventsCache = [];
function track(name, data){
function track(name, data) {
if (typeof window.mixpanel.track !== 'function') {
window.mixpanel.init(window.mixpanelTrackingId);
}
@ -31,27 +31,18 @@ function exportMixpanel(mp) {
if (window.mailpoet_analytics_enabled) {
MailPoet.trackEvent = track;
} else {
MailPoet.trackEvent = function () {};
MailPoet.trackEvent = function emptyFunction() {};
}
}
function trackCachedEvents() {
eventsCache.map(function (event) {
eventsCache.forEach(function trackIfEnabled(event) {
if (window.mailpoet_analytics_enabled || event.forced) {
window.mixpanel.track(event.name, event.data)
window.mixpanel.track(event.name, event.data);
}
});
}
function initializeMixpanelWhenLoaded() {
if (typeof window.mixpanel === 'object') {
exportMixpanel(MailPoet);
trackCachedEvents();
} else {
setTimeout(initializeMixpanelWhenLoaded, 100);
}
}
function cacheEvent(forced, name, data) {
eventsCache.push({
name: name,
@ -62,9 +53,18 @@ function cacheEvent(forced, name, data) {
define(
['mailpoet', 'underscore'],
function(mp, _) {
function analyticsEvent(mp, _) {
var MailPoet = mp;
function initializeMixpanelWhenLoaded() {
if (typeof window.mixpanel === 'object') {
exportMixpanel(MailPoet);
trackCachedEvents();
} else {
setTimeout(initializeMixpanelWhenLoaded, 100);
}
}
MailPoet.trackEvent = _.partial(cacheEvent, false);
MailPoet.forceTrackEvent = _.partial(cacheEvent, true);

View File

@ -0,0 +1,31 @@
import React from 'react';
const KeyValueTable = props => (
<table className={'widefat fixed'} style={{ maxWidth: props.max_width }}>
<tbody>
{props.children.map(row => (
<tr key={`row_${row.key}`}>
<td className={'row-title'}>{ row.key }</td><td>{ row.value }</td>
</tr>
))}
</tbody>
</table>
);
KeyValueTable.propTypes = {
max_width: React.PropTypes.string,
children: React.PropTypes.arrayOf(React.PropTypes.shape({
key: React.PropTypes.string.isRequired,
value: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.element,
]).isRequired,
})).isRequired,
};
KeyValueTable.defaultProps = {
max_width: 'auto',
};
module.exports = KeyValueTable;

View File

@ -0,0 +1,16 @@
import React from 'react';
import MailPoet from 'mailpoet';
class Loading extends React.Component {
componentWillMount() {
MailPoet.Modal.loading(true);
}
componentWillUnmount() {
MailPoet.Modal.loading(false);
}
render() {
return null;
}
}
export default Loading;

View File

@ -0,0 +1,26 @@
import React from 'react';
import MailPoet from 'mailpoet';
const PrintBoolean = props => (
<span>
{(props.children === true && props.truthy) ||
(props.children === false && props.falsy) ||
(props.unknown)}
</span>
);
PrintBoolean.propTypes = {
truthy: React.PropTypes.string,
falsy: React.PropTypes.string,
unknown: React.PropTypes.string,
children: React.PropTypes.bool,
};
PrintBoolean.defaultProps = {
truthy: MailPoet.I18n.t('yes'),
falsy: MailPoet.I18n.t('no'),
unknown: MailPoet.I18n.t('unknown'),
children: null,
};
module.exports = PrintBoolean;

View File

@ -0,0 +1,27 @@
import React from 'react';
const SteppedProgressBar = (props) => {
if (props.step > props.steps_count) {
return null;
}
return (
<div className="mailpoet_stepped_progress_bar">
{
[...Array(props.steps_count).keys()].map(step => (
<div
className={`mailpoet_stepped_progress_bar_step ${(step < props.step ? 'active' : '')}`}
key={`step_${step}`}
style={{ width: `${Math.floor(100 / props.steps_count)}%` }}
/>
))
}
</div>
);
};
SteppedProgressBar.propTypes = {
steps_count: React.PropTypes.number.isRequired,
step: React.PropTypes.number.isRequired,
};
module.exports = SteppedProgressBar;

View File

@ -0,0 +1,76 @@
import _ from 'underscore';
import MailPoet from 'mailpoet';
import html2canvas from 'html2canvas';
/**
* Generates a thumbnail from a DOM element.
*
* @param {DOMElement} element
* @return {Promise<String>} DataURL of the generated image.
*/
export const fromDom = element =>
html2canvas(element, {
logging: false,
}).then(canvas => canvas.toDataURL('image/jpeg'));
/**
* Generates a thumbnail from an URL.
*
* @param {String} url
* @return {Promise<String>} DataURL of the generated image.
*/
export const fromUrl = url =>
new Promise((resolve, reject) => {
const iframe = document.createElement('iframe');
const protocol = location.href.startsWith('https://') ? 'https:' : 'http:';
iframe.src = protocol + url.replace(/^https?:/, '');
iframe.style.opacity = 0;
iframe.scrolling = 'no';
iframe.onload = () => {
fromDom(iframe.contentDocument.documentElement)
.then((image) => {
document.body.removeChild(iframe);
resolve(image);
})
.catch(() => {
document.body.removeChild(iframe);
reject(MailPoet.I18n.t('errorWhileTakingScreenshot'));
});
};
const onError = () => {
document.body.removeChild(iframe);
reject(MailPoet.I18n.t('errorWhileTakingScreenshot'));
};
iframe.onerror = onError;
iframe.onError = onError;
iframe.className = 'mailpoet_template_iframe';
try {
document.body.appendChild(iframe);
} catch (err) {
onError();
}
});
/**
* Generates a thumbnail from a newsletter's data.
*
* @param {Object} data
* @return {Promise<String>} DataURL of the generated image.
*/
export const fromNewsletter = data =>
new Promise((resolve, reject) => {
const json = data;
if (!_.isUndefined(json.body)) {
json.body = JSON.stringify(json.body);
}
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'showPreview',
data: json,
}).done(response => fromUrl(response.meta.preview_url)
.then(resolve)
.catch(reject)
).fail(response => reject(response.errors));
});

View File

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

View File

@ -1,49 +1,43 @@
define([
'react',
],
(
React
) => {
const FormFieldCheckbox = React.createClass({
onValueChange: function (e) {
e.target.value = this.refs.checkbox.checked ? '1' : '0';
return this.props.onValueChange(e);
},
render: function () {
if (this.props.field.values === undefined) {
return false;
}
import React from 'react';
// isChecked will be true only if the value is "1"
// it will be false in case value is "0" or empty
const isChecked = !!(~~(this.props.item[this.props.field.name]));
const options = Object.keys(this.props.field.values).map(
(value, index) => {
return (
<p key={ 'checkbox-' + index }>
<label>
<input
ref="checkbox"
type="checkbox"
value="1"
checked={ isChecked }
onChange={ this.onValueChange }
name={ this.props.field.name }
/>
{ this.props.field.values[value] }
</label>
</p>
);
}
);
const FormFieldCheckbox = React.createClass({
onValueChange: function onValueChange(e) {
e.target.value = this.checkbox.checked ? '1' : '0';
return this.props.onValueChange(e);
},
render: function render() {
if (this.props.field.values === undefined) {
return false;
}
return (
<div>
{ options }
</div>
);
},
});
// isChecked will be true only if the value is "1"
// it will be false in case value is "0" or empty
const isChecked = !!(Number(this.props.item[this.props.field.name]));
const options = Object.keys(this.props.field.values).map(
value => (
<p key={`checkbox-${value}`}>
<label htmlFor={this.props.field.name}>
<input
ref={(c) => { this.checkbox = c; }}
type="checkbox"
value="1"
checked={isChecked}
onChange={this.onValueChange}
name={this.props.field.name}
id={this.props.field.name}
/>
{ this.props.field.values[value] }
</label>
</p>
)
);
return FormFieldCheckbox;
return (
<div>
{ options }
</div>
);
},
});
export default FormFieldCheckbox;

View File

@ -1,251 +1,279 @@
define([
'react',
'moment',
], (
React,
Moment
) => {
class FormFieldDateYear extends React.Component {
render() {
const yearsRange = 100;
const years = [];
import React from 'react';
import moment from 'moment';
import PropTypes from 'prop-types';
if (this.props.placeholder !== undefined) {
years.push((
<option value="" key={ 0 }>{ this.props.placeholder }</option>
));
}
function FormFieldDateYear(props) {
const yearsRange = 100;
const years = [];
const currentYear = Moment().year();
for (let i = currentYear; i >= currentYear - yearsRange; i -= 1) {
years.push((
<option
key={ i }
value={ i }
>{ i }</option>
));
}
return (
<select
name={ `${this.props.name}[year]` }
value={ this.props.year }
onChange={ this.props.onValueChange }
>
{ years }
</select>
);
}
if (props.placeholder !== undefined) {
years.push((
<option value="" key={0}>{ props.placeholder }</option>
));
}
class FormFieldDateMonth extends React.Component {
render() {
const months = [];
const currentYear = moment().year();
for (let i = currentYear; i >= currentYear - yearsRange; i -= 1) {
years.push((
<option
key={i}
value={i}
>{ i }</option>
));
}
return (
<select
name={`${props.name}[year]`}
value={props.year}
onChange={props.onValueChange}
>
{ years }
</select>
);
}
if (this.props.placeholder !== undefined) {
months.push((
<option value="" key={ 0 }>{ this.props.placeholder }</option>
));
}
FormFieldDateYear.propTypes = {
name: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
onValueChange: PropTypes.func.isRequired,
year: PropTypes.string.isRequired,
};
for (let i = 1; i <= 12; i += 1) {
months.push((
<option
key={ i }
value={ i }
>{ this.props.monthNames[i - 1] }</option>
));
}
return (
<select
name={ `${this.props.name}[month]` }
value={ this.props.month }
onChange={ this.props.onValueChange }
>
{ months }
</select>
);
}
function FormFieldDateMonth(props) {
const months = [];
if (props.placeholder !== undefined) {
months.push((
<option value="" key={0}>{ props.placeholder }</option>
));
}
class FormFieldDateDay extends React.Component {
render() {
const days = [];
for (let i = 1; i <= 12; i += 1) {
months.push((
<option
key={i}
value={i}
>{ props.monthNames[i - 1] }</option>
));
}
return (
<select
name={`${props.name}[month]`}
value={props.month}
onChange={props.onValueChange}
>
{ months }
</select>
);
}
if (this.props.placeholder !== undefined) {
days.push((
<option value="" key={ 0 }>{ this.props.placeholder }</option>
));
}
FormFieldDateMonth.propTypes = {
name: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
onValueChange: PropTypes.func.isRequired,
month: PropTypes.string.isRequired,
monthNames: PropTypes.arrayOf(PropTypes.string).isRequired,
};
for (let i = 1; i <= 31; i += 1) {
days.push((
<option
key={ i }
value={ i }
>{ i }</option>
));
}
function FormFieldDateDay(props) {
const days = [];
return (
<select
name={ `${this.props.name}[day]` }
value={ this.props.day }
onChange={ this.props.onValueChange }
>
{ days }
</select>
);
}
if (props.placeholder !== undefined) {
days.push((
<option value="" key={0}>{ props.placeholder }</option>
));
}
class FormFieldDate extends React.Component {
constructor(props) {
super(props);
this.state = {
year: '',
month: '',
day: '',
};
}
componentDidMount() {
for (let i = 1; i <= 31; i += 1) {
days.push((
<option
key={i}
value={i}
>{ i }</option>
));
}
return (
<select
name={`${props.name}[day]`}
value={props.day}
onChange={props.onValueChange}
>
{ days }
</select>
);
}
FormFieldDateDay.propTypes = {
name: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
onValueChange: PropTypes.func.isRequired,
day: PropTypes.string.isRequired,
};
class FormFieldDate extends React.Component {
constructor(props) {
super(props);
this.state = {
year: '',
month: '',
day: '',
};
this.onValueChange = this.onValueChange.bind(this);
}
componentDidMount() {
this.extractDateParts();
}
componentDidUpdate(prevProps) {
if (
(this.props.item !== undefined && prevProps.item !== undefined)
&& (this.props.item.id !== prevProps.item.id)
) {
this.extractDateParts();
}
componentDidUpdate(prevProps) {
if (
(this.props.item !== undefined && prevProps.item !== undefined)
&& (this.props.item.id !== prevProps.item.id)
) {
this.extractDateParts();
}
}
extractDateParts() {
const value = (this.props.item[this.props.field.name] !== undefined)
? this.props.item[this.props.field.name].trim()
: '';
}
onValueChange(e) {
// extract property from name
const matches = e.target.name.match(/(.*?)\[(.*?)\]/);
let field = null;
let property = null;
if(value === '') {
return;
}
if (matches !== null && matches.length === 3) {
field = matches[1];
property = matches[2];
const dateTime = Moment(value);
const value = Number(e.target.value);
this.setState({
year: dateTime.format('YYYY'),
month: dateTime.format('M'),
day: dateTime.format('D'),
});
}
formatValue() {
const dateType = this.props.field.params.date_type;
let value;
switch(dateType) {
case 'year_month_day':
value = {
year: this.state.year,
month: this.state.month,
day: this.state.day,
};
break;
case 'year_month':
value = {
year: this.state.year,
month: this.state.month,
};
break;
case 'month':
value = {
month: this.state.month,
};
break;
case 'year':
value = {
year: this.state.year,
};
break;
}
return value;
}
onValueChange(e) {
// extract property from name
const matches = e.target.name.match(/(.*?)\[(.*?)\]/);
let field = null;
let property = null;
if (matches !== null && matches.length === 3) {
field = matches[1];
property = matches[2];
const value = ~~(e.target.value);
this.setState({
[`${property}`]: value,
}, () => {
this.props.onValueChange({
target: {
name: field,
value: this.formatValue(),
},
});
[`${property}`]: value,
}, () => {
this.props.onValueChange({
target: {
name: field,
value: this.formatValue(),
},
});
}
}
render() {
const monthNames = window.mailpoet_month_names || [];
const dateFormats = window.mailpoet_date_formats || {};
const dateType = this.props.field.params.date_type;
const dateSelects = dateFormats[dateType][0].split('/');
const fields = dateSelects.map((type) => {
switch(type) {
case 'YYYY':
return (<FormFieldDateYear
onValueChange={ this.onValueChange.bind(this) }
ref={ 'year' }
key={ 'year' }
name={ this.props.field.name }
year={ this.state.year }
placeholder={ this.props.field.year_placeholder }
/>);
break;
case 'MM':
return (<FormFieldDateMonth
onValueChange={ this.onValueChange.bind(this) }
ref={ 'month' }
key={ 'month' }
name={ this.props.field.name }
month={ this.state.month }
monthNames={ monthNames }
placeholder={ this.props.field.month_placeholder }
/>);
break;
case 'DD':
return (<FormFieldDateDay
onValueChange={ this.onValueChange.bind(this) }
ref={ 'day' }
key={ 'day' }
name={ this.props.field.name }
day={ this.state.day }
placeholder={ this.props.field.day_placeholder }
/>);
break;
}
});
return (
<div>
{fields}
</div>
);
}
};
}
formatValue() {
const dateType = this.props.field.params.date_type;
return FormFieldDate;
});
let value;
switch (dateType) {
case 'year_month_day':
value = {
year: this.state.year,
month: this.state.month,
day: this.state.day,
};
break;
case 'year_month':
value = {
year: this.state.year,
month: this.state.month,
};
break;
case 'month':
value = {
month: this.state.month,
};
break;
case 'year':
value = {
year: this.state.year,
};
break;
default:
value = {
value: 'invalid type',
};
break;
}
return value;
}
extractDateParts() {
const value = (this.props.item[this.props.field.name] !== undefined)
? this.props.item[this.props.field.name].trim()
: '';
if (value === '') {
return;
}
const dateTime = moment(value);
this.setState({
year: dateTime.format('YYYY'),
month: dateTime.format('M'),
day: dateTime.format('D'),
});
}
render() {
const monthNames = window.mailpoet_month_names || [];
const dateFormats = window.mailpoet_date_formats || {};
const dateType = this.props.field.params.date_type;
const dateSelects = dateFormats[dateType][0].split('/');
const fields = dateSelects.map((type) => {
switch (type) {
case 'YYYY':
return (<FormFieldDateYear
onValueChange={this.onValueChange}
key={'year'}
name={this.props.field.name}
year={this.state.year}
placeholder={this.props.field.year_placeholder}
/>);
case 'MM':
return (<FormFieldDateMonth
onValueChange={this.onValueChange}
key={'month'}
name={this.props.field.name}
month={this.state.month}
monthNames={monthNames}
placeholder={this.props.field.month_placeholder}
/>);
case 'DD':
return (<FormFieldDateDay
onValueChange={this.onValueChange}
key={'day'}
name={this.props.field.name}
day={this.state.day}
placeholder={this.props.field.day_placeholder}
/>);
default:
return <div>Invalid date type</div>;
}
});
return (
<div>
{fields}
</div>
);
}
}
FormFieldDate.propTypes = {
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
field: PropTypes.shape({
name: PropTypes.string,
day_placeholder: PropTypes.string,
month_placeholder: PropTypes.string,
year_placeholder: PropTypes.string,
params: PropTypes.object, // eslint-disable-line react/forbid-prop-types
}).isRequired,
onValueChange: PropTypes.func.isRequired,
};
export default FormFieldDate;

View File

@ -1,129 +1,119 @@
define([
'react',
'form/fields/text.jsx',
'form/fields/textarea.jsx',
'form/fields/select.jsx',
'form/fields/radio.jsx',
'form/fields/checkbox.jsx',
'form/fields/selection.jsx',
'form/fields/date.jsx',
],
(
React,
FormFieldText,
FormFieldTextarea,
FormFieldSelect,
FormFieldRadio,
FormFieldCheckbox,
FormFieldSelection,
FormFieldDate
) => {
const FormField = React.createClass({
renderField: function (data, inline = false) {
let description = false;
if(data.field.description) {
description = (
<p className="description">{ data.field.description }</p>
);
}
import React from 'react';
import FormFieldText from 'form/fields/text.jsx';
import FormFieldTextarea from 'form/fields/textarea.jsx';
import FormFieldSelect from 'form/fields/select.jsx';
import FormFieldRadio from 'form/fields/radio.jsx';
import FormFieldCheckbox from 'form/fields/checkbox.jsx';
import FormFieldSelection from 'form/fields/selection.jsx';
import FormFieldDate from 'form/fields/date.jsx';
import jQuery from 'jquery';
let field = false;
let dataField = data.field;
if(data.field['field'] !== undefined) {
dataField = jQuery.merge(dataField, data.field.field);
}
switch(dataField.type) {
case 'text':
field = (<FormFieldText {...data} />);
break;
case 'textarea':
field = (<FormFieldTextarea {...data} />);
break;
case 'select':
field = (<FormFieldSelect {...data} />);
break;
case 'radio':
field = (<FormFieldRadio {...data} />);
break;
case 'checkbox':
field = (<FormFieldCheckbox {...data} />);
break;
case 'selection':
field = (<FormFieldSelection {...data} />);
break;
case 'date':
field = (<FormFieldDate {...data} />);
break;
case 'reactComponent':
field = (<data.field.component {...data} />);
break;
}
if(inline === true) {
return (
<span key={ 'field-' + (data.index || 0) }>
{ field }
{ description }
</span>
);
} else {
return (
<div key={ 'field-' + (data.index || 0) }>
{ field }
{ description }
</div>
);
}
},
render: function () {
let field = false;
if(this.props.field['fields'] !== undefined) {
field = this.props.field.fields.map((subfield, index) => {
return this.renderField({
index: index,
field: subfield,
item: this.props.item,
onValueChange: this.props.onValueChange || false,
});
});
} else {
field = this.renderField(this.props);
}
let tip = false;
if(this.props.field.tip) {
tip = (
<p className="description">{ this.props.field.tip }</p>
);
}
return (
<tr>
<th scope="row">
<label
htmlFor={ 'field_'+this.props.field.name }
>
{ this.props.field.label }
{ tip }
</label>
</th>
<td>
{ field }
</td>
</tr>
const FormField = React.createClass({
renderField: function renderField(data, inline = false) {
let description = false;
if (data.field.description) {
description = (
<p className="description">{ data.field.description }</p>
);
},
});
}
return FormField;
let field = false;
let dataField = data.field;
if (data.field.field !== undefined) {
dataField = jQuery.merge(dataField, data.field.field);
}
switch (dataField.type) {
case 'text':
field = (<FormFieldText {...data} />);
break;
case 'textarea':
field = (<FormFieldTextarea {...data} />);
break;
case 'select':
field = (<FormFieldSelect {...data} />);
break;
case 'radio':
field = (<FormFieldRadio {...data} />);
break;
case 'checkbox':
field = (<FormFieldCheckbox {...data} />);
break;
case 'selection':
field = (<FormFieldSelection {...data} />);
break;
case 'date':
field = (<FormFieldDate {...data} />);
break;
case 'reactComponent':
field = (<data.field.component {...data} />);
break;
default:
field = 'invalid';
break;
}
if (inline === true) {
return (
<span key={`field-${data.index || 0}`}>
{ field }
{ description }
</span>
);
}
return (
<div key={`field-${data.index || 0}`}>
{ field }
{ description }
</div>
);
},
render: function render() {
let field = false;
if (this.props.field.fields !== undefined) {
field = this.props.field.fields.map((subfield, index) => this.renderField({
index,
field: subfield,
item: this.props.item,
onValueChange: this.props.onValueChange || false,
}));
} else {
field = this.renderField(this.props);
}
let tip = false;
if (this.props.field.tip) {
tip = (
<p className="description">{ this.props.field.tip }</p>
);
}
return (
<tr className={`form-field-row-${this.props.field.name}`}>
<th scope="row">
<label
htmlFor={`field_${this.props.field.name}`}
>
{ this.props.field.label }
{ tip }
</label>
</th>
<td>
{ field }
</td>
</tr>
);
},
});
export default FormField;

View File

@ -1,41 +1,36 @@
define([
'react',
],
(
React
) => {
const FormFieldRadio = React.createClass({
render: function () {
if (this.props.field.values === undefined) {
return false;
}
import React from 'react';
const selected_value = this.props.item[this.props.field.name];
const options = Object.keys(this.props.field.values).map(
(value, index) => {
return (
<p key={ 'radio-' + index }>
<label>
<input
type="radio"
checked={ selected_value === value }
value={ value }
onChange={ this.props.onValueChange }
name={ this.props.field.name } />
{ this.props.field.values[value] }
</label>
</p>
);
}
);
const FormFieldRadio = React.createClass({
render: function render() {
if (this.props.field.values === undefined) {
return false;
}
return (
<div>
{ options }
</div>
);
},
});
const selectedValue = this.props.item[this.props.field.name];
const options = Object.keys(this.props.field.values).map(
value => (
<p key={`radio-${value}`}>
<label htmlFor={this.props.field.name}>
<input
type="radio"
checked={selectedValue === value}
value={value}
onChange={this.props.onValueChange}
name={this.props.field.name}
id={this.props.field.name}
/>
{ this.props.field.values[value] }
</label>
</p>
)
);
return FormFieldRadio;
return (
<div>
{ options }
</div>
);
},
});
export default FormFieldRadio;

View File

@ -17,7 +17,7 @@ const FormFieldSelect = React.createClass({
);
}
if (this.props.field['filter'] !== undefined) {
if (this.props.field.filter !== undefined) {
filter = this.props.field.filter;
}
@ -41,29 +41,29 @@ const FormFieldSelect = React.createClass({
keys = Object.keys(this.props.field.values);
}
const options = keys.map(
(value, index) => {
if (filter !== false && filter(this.props.item, value) === false) {
return;
}
return (
const options = keys
.filter((value) => {
if (filter === false) return true;
return filter(this.props.item, value);
})
.map(
value => (
<option
key={ 'option-' + index }
value={ value }>
key={`option-${value}`}
value={value}
>
{ this.props.field.values[value] }
</option>
);
}
);
)
);
return (
<select
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
onChange={ this.props.onValueChange }
name={this.props.field.name}
id={`field_${this.props.field.name}`}
value={this.props.item[this.props.field.name] || ''}
onChange={this.props.onValueChange}
data-automation-id={this.props.automationId}
{...this.props.field.validation}
>
{placeholder}

View File

@ -1,194 +1,261 @@
define([
'react',
'react-dom',
'jquery',
'select2',
],
(
React,
ReactDOM,
jQuery
) => {
const Selection = React.createClass({
getInitialState: function () {
return {
items: [],
select2: false,
};
},
componentWillMount: function () {
this.loadCachedItems();
},
allowMultipleValues: function () {
return (this.props.field.multiple === true);
},
isSelect2Initialized: function () {
return (this.state.select2 === true);
},
componentDidMount: function () {
if(this.allowMultipleValues()) {
this.setupSelect2();
}
},
componentDidUpdate: function (prevProps) {
if(
(this.props.item !== undefined && prevProps.item !== undefined)
&& (this.props.item.id !== prevProps.item.id)
) {
jQuery('#'+this.refs.select.id)
.val(this.getSelectedValues())
.trigger('change');
}
},
componentWillUnmount: function () {
if(this.allowMultipleValues()) {
this.destroySelect2();
}
},
destroySelect2: function () {
if(this.isSelect2Initialized()) {
jQuery('#'+this.refs.select.id).select2('destroy');
}
},
setupSelect2: function () {
if(this.isSelect2Initialized()) {
return;
}
import React from 'react';
import jQuery from 'jquery';
import _ from 'underscore';
import 'react-dom';
import 'select2';
const select2 = jQuery('#'+this.refs.select.id).select2({
width: (this.props.width || ''),
templateResult: function (item) {
if(item.element && item.element.selected) {
return null;
} else {
if(item.title) {
return item.title;
} else {
return item.text;
}
}
},
});
const Selection = React.createClass({
allowMultipleValues: function allowMultipleValues() {
return (this.props.field.multiple === true);
},
isSelect2Initialized: function isSelect2Initialized() {
return (jQuery(`#${this.select.id}`).hasClass('select2-hidden-accessible') === true);
},
isSelect2Component: function isSelect2Component() {
return this.allowMultipleValues() || this.props.field.forceSelect2;
},
componentDidMount: function componentDidMount() {
if (this.isSelect2Component()) {
this.setupSelect2();
}
},
componentDidUpdate: function componentDidUpdate(prevProps) {
if ((this.props.item !== undefined && prevProps.item !== undefined)
&& (this.props.item.id !== prevProps.item.id)
) {
jQuery(`#${this.select.id}`)
.val(this.getSelectedValues())
.trigger('change');
}
let hasRemoved = false;
select2.on('select2:unselecting', () => {
hasRemoved = true;
});
select2.on('select2:opening', (e) => {
if(hasRemoved === true) {
hasRemoved = false;
e.preventDefault();
if (this.isSelect2Initialized() &&
(this.getFieldId(this.props) !== this.getFieldId(prevProps)) &&
this.props.field.resetSelect2OnUpdate !== undefined
) {
this.resetSelect2();
}
},
componentWillUnmount: function componentWillUnmount() {
if (this.isSelect2Component()) {
this.destroySelect2();
}
},
getFieldId: function getFieldId(data) {
const props = data || this.props;
return props.field.id || props.field.name;
},
resetSelect2: function resetSelect2() {
this.destroySelect2();
this.setupSelect2();
},
destroySelect2: function destroySelect2() {
if (this.isSelect2Initialized()) {
jQuery(`#${this.select.id}`).select2('destroy');
this.cleanupAfterSelect2();
}
},
cleanupAfterSelect2: function cleanupAfterSelect2() {
// remove DOM elements created by Select2 that are not tracked by React
jQuery(`#${this.select.id}`)
.find('option:not(.default)')
.remove();
// unbind events (https://select2.org/programmatic-control/methods#event-unbinding)
jQuery(`#${this.select.id}`)
.off('select2:unselecting')
.off('select2:opening');
},
setupSelect2: function setupSelect2() {
if (this.isSelect2Initialized()) {
return;
}
let select2Options = {
disabled: this.props.disabled || false,
width: (this.props.width || ''),
placeholder: {
id: '', // the value of the option
text: this.props.field.placeholder,
},
templateResult: function templateResult(item) {
if (item.element && item.element.selected) {
return null;
} else if (item.title) {
return item.title;
}
});
return item.text;
},
};
select2.on('change', this.handleChange);
this.setState({ select2: true });
},
getSelectedValues: function () {
if(this.props.field['selected'] !== undefined) {
return this.props.field['selected'](this.props.item);
} else if(this.props.item !== undefined && this.props.field.name !== undefined) {
if (this.allowMultipleValues()) {
if (Array.isArray(this.props.item[this.props.field.name])) {
return this.props.item[this.props.field.name].map((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') {
let items = window['mailpoet_'+this.props.field.endpoint];
if(this.props.field['filter'] !== undefined) {
items = items.filter(this.props.field.filter);
}
this.setState({
items: items,
});
}
},
handleChange: function (e) {
if(this.props.onValueChange !== undefined) {
if(this.props.field.multiple) {
value = jQuery('#'+this.refs.select.id).val();
} else {
value = e.target.value;
}
const transformedValue = this.transformChangedValue(value);
this.props.onValueChange({
target: {
value: transformedValue,
name: this.props.field.name,
const remoteQuery = this.props.field.remoteQuery || null;
if (remoteQuery) {
select2Options = Object.assign(select2Options, {
ajax: {
url: window.ajaxurl,
type: 'POST',
dataType: 'json',
data: function data(params) {
return {
action: 'mailpoet',
api_version: window.mailpoet_api_version,
token: window.mailpoet_token,
endpoint: remoteQuery.endpoint,
method: remoteQuery.method,
data: Object.assign(
remoteQuery.data,
{ query: params.term }
),
};
},
});
}
},
getLabel: function (item) {
if(this.props.field['getLabel'] !== undefined) {
return this.props.field.getLabel(item, this.props.item);
}
return item.name;
},
getSearchLabel: function (item) {
if(this.props.field['getSearchLabel'] !== undefined) {
return this.props.field.getSearchLabel(item, this.props.item);
}
return null;
},
getValue: function (item) {
if(this.props.field['getValue'] !== undefined) {
return this.props.field.getValue(item, this.props.item);
}
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) => {
const label = this.getLabel(item);
const searchLabel = this.getSearchLabel(item);
const value = this.getValue(item);
return (
<option
key={ 'option-'+index }
value={ value }
title={ searchLabel }
>
{ label }
</option>
);
processResults: function processResults(response) {
return { results: (!_.has(response, 'data')) ?
[] :
response.data.map(item =>
({ id: item.id || item.value, text: item.name || item.text })
),
};
},
},
minimumInputLength: remoteQuery.minimumInputLength || 2,
});
}
if (this.props.field.extendSelect2Options !== undefined) {
select2Options = Object.assign(select2Options, this.props.field.extendSelect2Options);
}
const select2 = jQuery(`#${this.select.id}`).select2(select2Options);
let hasRemoved = false;
select2.on('select2:unselecting', () => {
hasRemoved = true;
});
select2.on('select2:opening', (e) => {
if (hasRemoved === true) {
hasRemoved = false;
e.preventDefault();
}
});
select2.on('change', this.handleChange);
},
getSelectedValues: function getSelectedValues() {
if (this.props.field.selected !== undefined) {
return this.props.field.selected(this.props.item);
} else if (this.props.item !== undefined && this.props.field.name !== undefined) {
if (this.allowMultipleValues()) {
if (_.isArray(this.props.item[this.props.field.name])) {
return this.props.item[this.props.field.name].map(item => item.id);
}
} else {
return this.props.item[this.props.field.name];
}
}
return null;
},
getItems: function getItems() {
let items;
if (typeof (window[`mailpoet_${this.props.field.endpoint}`]) !== 'undefined') {
items = window[`mailpoet_${this.props.field.endpoint}`];
} else if (this.props.field.values !== undefined) {
items = this.props.field.values;
}
if (_.isArray(items)) {
if (this.props.field.filter !== undefined) {
items = items.filter(this.props.field.filter);
}
}
return items;
},
handleChange: function handleChange(e) {
if (this.props.onValueChange === undefined) return;
const valueTextPair = jQuery(`#${this.select.id}`).children(':selected').map(function element() {
return { id: jQuery(this).val(), text: jQuery(this).text() };
});
const value = (this.props.field.multiple) ? _.pluck(valueTextPair, 'id') : _.pluck(valueTextPair, 'id').toString();
const transformedValue = this.transformChangedValue(value, valueTextPair);
this.props.onValueChange({
target: {
value: transformedValue,
name: this.props.field.name,
id: e.target.id,
},
});
},
getLabel: function getLabel(item) {
if (this.props.field.getLabel !== undefined) {
return this.props.field.getLabel(item, this.props.item);
}
return item.name;
},
getSearchLabel: function getSearchLabel(item) {
if (this.props.field.getSearchLabel !== undefined) {
return this.props.field.getSearchLabel(item, this.props.item);
}
return null;
},
getValue: function getValue(item) {
if (this.props.field.getValue !== undefined) {
return this.props.field.getValue(item, this.props.item);
}
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 transformChangedValue(value, textValuePair) {
if (typeof this.props.field.transformChangedValue === 'function') {
return this.props.field.transformChangedValue.call(this, value, textValuePair);
}
return value;
},
insertEmptyOption: function insertEmptyOption() {
// https://select2.org/placeholders
// For single selects only, in order for the placeholder value to appear,
// we must have a blank <option> as the first option in the <select> control.
if (this.allowMultipleValues()) return undefined;
if (this.props.field.placeholder) return (<option className="default" />);
return undefined;
},
render: function render() {
const items = this.getItems(this.props.field);
const selectedValues = this.getSelectedValues();
const options = items.map((item) => {
const label = this.getLabel(item);
const searchLabel = this.getSearchLabel(item);
const value = this.getValue(item);
return (
<select
id={ this.props.field.id || this.props.field.name }
ref="select"
disabled={this.props.field.disabled}
data-placeholder={ this.props.field.placeholder }
multiple={ this.props.field.multiple }
defaultValue={ this.getSelectedValues() }
{...this.props.field.validation}
>{ options }</select>
<option
key={`option-${item.id}`}
className="default"
value={value}
title={searchLabel}
>
{ label }
</option>
);
},
});
});
return Selection;
return (
<select
id={this.getFieldId()}
ref={(c) => { this.select = c; }}
disabled={this.props.field.disabled}
data-placeholder={this.props.field.placeholder}
multiple={this.props.field.multiple}
defaultValue={selectedValues}
{...this.props.field.validation}
>
{ this.insertEmptyOption() }
{ options }
</select>
);
},
});
export default Selection;

View File

@ -2,30 +2,52 @@ import React from 'react';
const FormFieldText = React.createClass({
render() {
let value = this.props.item[this.props.field.name];
if (value === undefined) {
value = this.props.field.defaultValue || '';
const name = this.props.field.name || null;
const item = this.props.item || {};
let value;
let defaultValue;
// value should only be set when onChangeValue is configured
if (this.props.onValueChange instanceof Function) {
value = item[this.props.field.name];
// set value to defaultValue if available
value = (value === undefined) ?
(this.props.field.defaultValue || '') : value;
}
// defaultValue should only be set only when value is not set
if (!value && this.props.field.defaultValue) {
defaultValue = this.props.field.defaultValue;
}
let id = this.props.field.id || null;
if (!id && this.props.field.name) {
id = `field_${this.props.field.name}`;
}
let className = this.props.field.class || null;
if (!className && !this.props.field.size) {
className = 'regular-text';
}
return (
<input
type="text"
disabled={
(this.props.field['disabled'] !== undefined)
? this.props.field.disabled(this.props.item)
: false
(this.props.field.disabled !== undefined)
? this.props.field.disabled(this.props.item)
: false
}
className={ (this.props.field.size) ? '' : 'regular-text' }
className={className}
size={
(this.props.field.size !== 'auto' && this.props.field.size > 0)
? this.props.field.size
: false
? this.props.field.size
: false
}
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ value }
placeholder={ this.props.field.placeholder }
onChange={ this.props.onValueChange }
name={name}
id={id}
value={value}
defaultValue={defaultValue}
placeholder={this.props.field.placeholder}
onChange={this.props.onValueChange}
{...this.props.field.validation}
/>
);

View File

@ -1,26 +1,29 @@
define([
'react',
],
(
React
) => {
const FormFieldTextarea = React.createClass({
render: function () {
return (
<textarea
type="text"
className="regular-text"
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
placeholder={ this.props.field.placeholder }
defaultValue={ this.props.field.defaultValue }
onChange={ this.props.onValueChange }
{...this.props.field.validation}
/>
);
},
});
import React from 'react';
import PropTypes from 'prop-types';
return FormFieldTextarea;
});
const FormFieldTextarea = props => (
<textarea
type="text"
className="regular-text"
name={props.field.name}
id={`field_${props.field.name}`}
value={props.item[props.field.name]}
placeholder={props.field.placeholder}
defaultValue={props.field.defaultValue}
onChange={props.onValueChange}
{...props.field.validation}
/>
);
FormFieldTextarea.propTypes = {
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
field: PropTypes.shape({
name: PropTypes.string,
placeholder: PropTypes.string,
defaultValue: PropTypes.string,
validation: PropTypes.object, // eslint-disable-line react/forbid-prop-types
}).isRequired,
onValueChange: PropTypes.func.isRequired,
};
export default FormFieldTextarea;

View File

@ -1,246 +1,237 @@
define(
[
'react',
'mailpoet',
'classnames',
'react-router',
'form/fields/field.jsx',
],
(
React,
MailPoet,
classNames,
Router,
FormField
) => {
import React from 'react';
import MailPoet from 'mailpoet';
import classNames from 'classnames';
import FormField from 'form/fields/field.jsx';
import jQuery from 'jquery';
const Form = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired,
},
getDefaultProps: function () {
return {
params: {},
};
},
getInitialState: function () {
return {
const Form = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired,
},
getDefaultProps: function getDefaultProps() {
return {
params: {},
};
},
getInitialState: function getInitialState() {
return {
loading: false,
errors: [],
item: {},
};
},
getValues: function getValues() {
return this.props.item ? this.props.item : this.state.item;
},
getErrors: function getErrors() {
return this.props.errors ? this.props.errors : this.state.errors;
},
componentDidMount: function componentDidMount() {
if (this.props.params.id !== undefined) {
this.loadItem(this.props.params.id);
} else {
setImmediate(() => {
this.setState({
item: jQuery('.mailpoet_form').mailpoetSerializeObject(),
});
});
}
},
componentWillReceiveProps: function componentWillReceiveProps(props) {
if (props.params.id === undefined) {
setImmediate(() => {
this.setState({
loading: false,
errors: [],
item: {},
});
});
if (props.item === undefined) {
this.form.reset();
}
}
},
loadItem: function loadItem(id) {
this.setState({ loading: true });
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'get',
data: {
id,
},
}).done((response) => {
this.setState({
loading: false,
item: response.data,
});
if (typeof this.props.onItemLoad === 'function') {
this.props.onItemLoad(response.data);
}
}).fail(() => {
this.setState({
loading: false,
item: {},
}, function failSetStateCallback() {
this.context.router.push('/new');
});
});
},
handleSubmit: function handleSubmit(e) {
e.preventDefault();
// handle validation
if (this.props.isValid !== undefined) {
if (this.props.isValid() === false) {
return;
}
}
this.setState({ loading: true });
// only get values from displayed fields
const item = {};
this.props.fields.forEach((field) => {
if (field.fields !== undefined) {
field.fields.forEach((subfield) => {
item[subfield.name] = this.state.item[subfield.name];
});
} else {
item[field.name] = this.state.item[field.name];
}
});
// set id if specified
if (this.props.params.id !== undefined) {
item.id = this.props.params.id;
}
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'save',
data: item,
}).always(() => {
this.setState({ loading: false });
}).done(() => {
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();
}
}).fail((response) => {
if (response.errors.length > 0) {
this.setState({ errors: response.errors });
}
});
},
handleValueChange: function handleValueChange(e) {
if (this.props.onChange) {
return this.props.onChange(e);
}
const item = this.state.item;
const field = e.target.name;
item[field] = e.target.value;
this.setState({
item,
});
return true;
},
render: function render() {
let errors;
if (this.getErrors() !== undefined) {
errors = this.getErrors().map(error => (
<div className="mailpoet_notice notice inline error is-dismissible" key={`error-${error.message}`}>
<p>{ error.message }</p>
</div>
));
}
const formClasses = classNames(
'mailpoet_form',
{ mailpoet_form_loading: this.state.loading || this.props.loading }
);
let beforeFormContent = false;
let afterFormContent = false;
if (this.props.beforeFormContent !== undefined) {
beforeFormContent = this.props.beforeFormContent(this.getValues());
}
if (this.props.afterFormContent !== undefined) {
afterFormContent = this.props.afterFormContent(this.getValues());
}
const fields = this.props.fields.map((field) => {
// Compose an onChange handler from the default and custom one
let onValueChange = this.handleValueChange;
if (field.onBeforeChange) {
onValueChange = (e) => {
field.onBeforeChange(e);
return this.handleValueChange(e);
};
},
getValues: function () {
return this.props.item ? this.props.item : this.state.item;
},
getErrors: function () {
return this.props.errors ? this.props.errors : this.state.errors;
},
componentDidMount: function () {
if(this.isMounted()) {
if(this.props.params.id !== undefined) {
this.loadItem(this.props.params.id);
} else {
this.setState({
item: jQuery('.mailpoet_form').serializeObject(),
});
}
}
},
componentWillReceiveProps: function (props) {
if(props.params.id === undefined) {
this.setState({
loading: false,
item: {},
});
if (props.item === undefined) {
this.refs.form.reset();
}
} else {
this.loadItem(props.params.id);
}
},
loadItem: function (id) {
this.setState({ loading: true });
}
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'get',
data: {
id: id,
},
}).done((response) => {
this.setState({
loading: false,
item: response.data,
});
}).fail(() => {
this.setState({
loading: false,
item: {},
}, function () {
this.context.router.push('/new');
});
});
},
handleSubmit: function (e) {
e.preventDefault();
// handle validation
if(this.props.isValid !== undefined) {
if(this.props.isValid() === false) {
return;
}
}
this.setState({ loading: true });
// only get values from displayed fields
const item = {};
this.props.fields.map((field) => {
if(field['fields'] !== undefined) {
field.fields.map((subfield) => {
item[subfield.name] = this.state.item[subfield.name];
});
} else {
item[field.name] = this.state.item[field.name];
}
});
// set id if specified
if(this.props.params.id !== undefined) {
item.id = this.props.params.id;
}
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'save',
data: item,
}).always(() => {
this.setState({ loading: false });
}).done(() => {
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();
}
}).fail((response) => {
if(response.errors.length > 0) {
this.setState({ errors: response.errors });
}
});
},
handleValueChange: function (e) {
if (this.props.onChange) {
return this.props.onChange(e);
} else {
const item = this.state.item;
const field = e.target.name;
item[field] = e.target.value;
this.setState({
item: item,
});
return true;
}
},
render: function () {
let errors;
if(this.getErrors() !== undefined) {
errors = this.getErrors().map((error, index) => {
return (
<p key={ 'error-'+index } className="mailpoet_error">
{ error.message }
</p>
);
});
}
const formClasses = classNames(
'mailpoet_form',
{ mailpoet_form_loading: this.state.loading || this.props.loading }
);
let beforeFormContent = false;
let afterFormContent = false;
if (this.props.beforeFormContent !== undefined) {
beforeFormContent = this.props.beforeFormContent(this.getValues());
}
if (this.props.afterFormContent !== undefined) {
afterFormContent = this.props.afterFormContent(this.getValues());
}
const fields = this.props.fields.map((field, i) => {
// Compose an onChange handler from the default and custom one
let onValueChange = this.handleValueChange;
if (field.onBeforeChange) {
onValueChange = (e) => {
field.onBeforeChange(e);
return this.handleValueChange(e);
};
}
return (
<FormField
field={ field }
item={ this.getValues() }
onValueChange={ onValueChange }
key={ 'field-'+i } />
);
});
let actions = false;
if(this.props.children) {
actions = this.props.children;
} else {
actions = (
<input
className="button button-primary"
type="submit"
value={MailPoet.I18n.t('save')}
disabled={this.state.loading} />
);
}
return (
<div>
{ beforeFormContent }
<form
id={ this.props.id }
ref="form"
className={ formClasses }
onSubmit={
(this.props.onSubmit !== undefined)
? this.props.onSubmit
: this.handleSubmit
}
>
{ errors }
<table className="form-table">
<tbody>
{fields}
</tbody>
</table>
{ actions }
</form>
{ afterFormContent }
</div>
);
},
return (
<FormField
field={field}
item={this.getValues()}
onValueChange={onValueChange}
key={`field-${field.name}`}
/>
);
});
return Form;
}
);
let actions = false;
if (this.props.children) {
actions = this.props.children;
} else {
actions = (
<input
className="button button-primary"
type="submit"
value={MailPoet.I18n.t('save')}
disabled={this.state.loading}
/>
);
}
return (
<div>
{ beforeFormContent }
<form
id={this.props.id}
ref={(c) => { this.form = c; }}
className={formClasses}
onSubmit={
(this.props.onSubmit !== undefined)
? this.props.onSubmit
: this.handleSubmit
}
data-automation-id={this.props.automationId}
>
{ errors }
<table className="form-table">
<tbody>
{fields}
</tbody>
</table>
{ actions }
</form>
{ afterFormContent }
</div>
);
},
});
export default Form;

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, IndexRoute, useRouterHistory } from 'react-router';
import { createHashHistory } from 'history';
import FormList from 'forms/list.jsx';
import FormList from './list.jsx';
const history = useRouterHistory(createHashHistory)({ queryKey: false });
@ -14,12 +14,12 @@ const App = React.createClass({
const container = document.getElementById('forms_container');
if(container) {
if (container) {
ReactDOM.render((
<Router history={ history }>
<Route path="/" component={ App }>
<IndexRoute component={ FormList } />
<Route path="*" component={ FormList } />
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={FormList} />
<Route path="*" component={FormList} />
</Route>
</Router>
), container);

View File

@ -1,7 +1,8 @@
import React from 'react';
import Listing from 'listing/listing.jsx';
import classNames from 'classnames';
import MailPoet from 'mailpoet';
import jQuery from 'jquery';
import Listing from '../listing/listing.jsx';
const columns = [
{
@ -26,7 +27,7 @@ const columns = [
const messages = {
onTrash: (response) => {
const count = ~~response.meta.count;
const count = Number(response.meta.count);
let message = null;
if (count === 1) {
@ -41,7 +42,7 @@ const messages = {
MailPoet.Notice.success(message);
},
onDelete: (response) => {
const count = ~~response.meta.count;
const count = Number(response.meta.count);
let message = null;
if (count === 1) {
@ -56,7 +57,7 @@ const messages = {
MailPoet.Notice.success(message);
},
onRestore: (response) => {
const count = ~~response.meta.count;
const count = Number(response.meta.count);
let message = null;
if (count === 1) {
@ -72,7 +73,7 @@ const messages = {
},
};
const bulk_actions = [
const bulkActions = [
{
name: 'trash',
label: MailPoet.I18n.t('moveToTrash'),
@ -80,20 +81,20 @@ const bulk_actions = [
},
];
const item_actions = [
const itemActions = [
{
name: 'edit',
label: MailPoet.I18n.t('edit'),
link: function (item) {
link: function link(item) {
return (
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>{MailPoet.I18n.t('edit')}</a>
<a href={`admin.php?page=mailpoet-form-editor&id=${item.id}`}>{MailPoet.I18n.t('edit')}</a>
);
},
},
{
name: 'duplicate',
label: MailPoet.I18n.t('duplicate'),
onClick: function (item, refresh) {
onClick: function onClick(item, refresh) {
return MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'forms',
@ -109,7 +110,7 @@ const item_actions = [
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map((error) => { return error.message; }),
response.errors.map(error => error.message),
{ scroll: true }
);
}
@ -128,40 +129,39 @@ const FormList = React.createClass({
endpoint: 'forms',
action: 'create',
}).done((response) => {
window.location = mailpoet_form_edit_url + response.data.id;
window.location = window.mailpoet_form_edit_url + response.data.id;
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map((error) => { return error.message; }),
response.errors.map(error => error.message),
{ scroll: true }
);
}
});
},
renderItem(form, actions) {
const row_classes = classNames(
const rowClasses = classNames(
'manage-column',
'column-primary',
'has-row-actions'
);
let segments = mailpoet_segments.filter((segment) => {
return (jQuery.inArray(segment.id, form.segments) !== -1);
}).map((segment) => {
return segment.name;
}).join(', ');
let segments = window.mailpoet_segments
.filter(segment => (jQuery.inArray(segment.id, form.segments) !== -1))
.map(segment => segment.name)
.join(', ');
if (form.settings.segments_selected_by === 'user') {
segments = MailPoet.I18n.t('userChoice') + ' ' + segments;
segments = `${MailPoet.I18n.t('userChoice')} ${segments}`;
}
return (
<div>
<td className={ row_classes }>
<td className={rowClasses}>
<strong>
<a
className="row-title"
href={ `admin.php?page=mailpoet-form-editor&id=${form.id}` }
href={`admin.php?page=mailpoet-form-editor&id=${form.id}`}
>{ form.name }</a>
</strong>
{ actions }
@ -185,21 +185,22 @@ const FormList = React.createClass({
{MailPoet.I18n.t('pageTitle')} <a
className="page-title-action"
href="javascript:;"
onClick={ this.createForm }
onClick={this.createForm}
data-automation-id="create_new_form"
>{MailPoet.I18n.t('new')}</a>
</h1>
<Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location }
params={ this.props.params }
messages={ messages }
search={ false }
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.params}
messages={messages}
search={false}
endpoint="forms"
onRenderItem={ this.renderItem }
columns={ columns }
bulk_actions={ bulk_actions }
item_actions={ item_actions }
onRenderItem={this.renderItem}
columns={columns}
bulk_actions={bulkActions}
item_actions={itemActions}
/>
</div>
);

View File

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

View File

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

View File

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

View File

@ -0,0 +1,65 @@
import MailPoet from 'mailpoet';
import React from 'react';
import KeyValueTable from 'common/key_value_table.jsx';
import PrintBoolean from 'common/print_boolean.jsx';
const CronStatus = (props) => {
const status = props.status_data;
const activeStatusMapping = {
active: MailPoet.I18n.t('running'),
inactive: MailPoet.I18n.t('cronWaiting'),
};
return (
<div>
<h2>{MailPoet.I18n.t('systemStatusCronStatusTitle')}</h2>
<KeyValueTable max_width={'400px'}>{[
{
key: MailPoet.I18n.t('accessible'),
value: <PrintBoolean>{status.accessible}</PrintBoolean>,
},
{
key: MailPoet.I18n.t('status'),
value: activeStatusMapping[status.status] ? activeStatusMapping[status.status] : MailPoet.I18n.t('unknown'),
},
{
key: MailPoet.I18n.t('lastUpdated'),
value: status.updated_at ? MailPoet.Date.full(status.updated_at * 1000) : MailPoet.I18n.t('unknown'),
},
{
key: MailPoet.I18n.t('lastRunStarted'),
value: status.run_accessed_at ? MailPoet.Date.full(status.run_started_at * 1000) : MailPoet.I18n.t('unknown'),
},
{
key: MailPoet.I18n.t('lastRunCompleted'),
value: status.run_completed_at ? MailPoet.Date.full(status.run_completed_at * 1000) : MailPoet.I18n.t('unknown'),
},
{
key: MailPoet.I18n.t('lastSeenError'),
value: status.last_error || MailPoet.I18n.t('none'),
}]}
</KeyValueTable>
</div>
);
};
CronStatus.propTypes = {
status_data: React.PropTypes.shape({
accessible: React.PropTypes.bool,
status: React.PropTypes.string,
updated_at: React.PropTypes.number,
run_accessed_at: React.PropTypes.number,
run_completed_at: React.PropTypes.number,
}).isRequired,
};
CronStatus.defaultProps = {
status_data: {
accessible: null,
status: null,
updated_at: null,
run_accessed_at: null,
run_completed_at: null,
},
};
module.exports = CronStatus;

View File

@ -3,8 +3,9 @@ import ReactDOM from 'react-dom';
import { Router, Route, IndexRedirect, useRouterHistory } from 'react-router';
import { createHashHistory } from 'history';
import KnowledgeBase from 'help/knowledge_base.jsx';
import SystemStatus from 'help/system_status.jsx';
import SystemInfo from 'help/system_info.jsx';
import KnowledgeBase from 'help/knowledge_base.jsx';
const history = useRouterHistory(createHashHistory)({ queryKey: false });
@ -16,17 +17,16 @@ const App = React.createClass({
const container = document.getElementById('help_container');
if(container) {
if (container) {
ReactDOM.render((
<Router history={ history }>
<Route path="/" component={ App }>
<Router history={history}>
<Route path="/" component={App}>
<IndexRedirect to="knowledgeBase" />
{/* Pages */}
<Route path="knowledgeBase(/)**" params={{ tab: 'knowledgeBase' }} component={ KnowledgeBase } />
<Route path="systemInfo(/)**" params={{ tab: 'systemInfo' }} component={ SystemInfo } />
<Route path="knowledgeBase(/)**" params={{ tab: 'knowledgeBase' }} component={KnowledgeBase} />
<Route path="systemStatus(/)**" params={{ tab: 'systemStatus' }} component={SystemStatus} />
<Route path="systemInfo(/)**" params={{ tab: 'systemInfo' }} component={SystemInfo} />
</Route>
</Router>
), container);
}

View File

@ -4,7 +4,6 @@ import MailPoet from 'mailpoet';
import Tabs from './tabs.jsx';
function KnowledgeBase() {
return (
<div>
@ -12,18 +11,18 @@ function KnowledgeBase() {
<p>{MailPoet.I18n.t('knowledgeBaseIntro')}</p>
<ul>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/116-common-problems">Common Problems</a></li>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/165-newsletters">Newsletters</a></li>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/156-migration-questions">Migration Questions</a></li>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/149-sending-methods">Sending Methods</a></li>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/139-subscription-forms">Subscription Forms</a></li>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/114-getting-started">Getting Started</a></li>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/123-newsletter-designer">Newsletter Designer</a></li>
<li><a target="_blank" href="http://beta.docs.mailpoet.com/category/121-subscribers-and-lists">Subscribers and Lists</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/116-common-problems">Common Problems</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/165-newsletters">Newsletters</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/156-migration-questions">Migration Questions</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/149-sending-methods">Sending Methods</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/139-subscription-forms">Subscription Forms</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/114-getting-started">Getting Started</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/123-newsletter-designer">Newsletter Designer</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/category/121-subscribers-and-lists">Subscribers and Lists</a></li>
</ul>
<a target="_blank" href="http://beta.docs.mailpoet.com/" className="button button-primary">{MailPoet.I18n.t('knowledgeBaseButton')}</a>
<a target="_blank" rel="noreferrer noopener" href="http://beta.docs.mailpoet.com/" className="button button-primary">{MailPoet.I18n.t('knowledgeBaseButton')}</a>
</div>
);
};
}
module.exports = KnowledgeBase;

View File

@ -0,0 +1,85 @@
import MailPoet from 'mailpoet';
import React from 'react';
import KeyValueTable from 'common/key_value_table.jsx';
import TasksList from './tasks_list/tasks_list.jsx';
import TasksListDataRow from './tasks_list/tasks_list_data_row.jsx';
const QueueStatus = (props) => {
const status = props.status_data;
return (
<div>
<h2>{MailPoet.I18n.t('systemStatusQueueTitle')}</h2>
<KeyValueTable max_width={'400px'}>{
[{
key: MailPoet.I18n.t('status'),
value: status.status === 'paused' ? MailPoet.I18n.t('paused') : MailPoet.I18n.t('running'),
}, {
key: MailPoet.I18n.t('startedAt'),
value: status.started ? MailPoet.Date.full(status.started * 1000) : MailPoet.I18n.t('unknown'),
}, {
key: MailPoet.I18n.t('sentEmails'),
value: status.sent || 0,
}, {
key: MailPoet.I18n.t('retryAttempt'),
value: status.retry_attempt || MailPoet.I18n.t('none'),
}, {
key: MailPoet.I18n.t('retryAt'),
value: status.retry_at ? MailPoet.Date.full(status.retry_at * 1000) : MailPoet.I18n.t('none'),
}, {
key: MailPoet.I18n.t('error'),
value: status.error || MailPoet.I18n.t('none'),
}, {
key: MailPoet.I18n.t('totalCompletedTasks'),
value: status.tasksStatusCounts.completed,
}, {
key: MailPoet.I18n.t('totalRunningTasks'),
value: status.tasksStatusCounts.running,
}, {
key: MailPoet.I18n.t('totalPausedTasks'),
value: status.tasksStatusCounts.paused,
}, {
key: MailPoet.I18n.t('totalScheduledTasks'),
value: status.tasksStatusCounts.scheduled,
}]}
</KeyValueTable>
<h4>{MailPoet.I18n.t('scheduledTasks')}</h4>
<TasksList show_scheduled_at tasks={status.latestTasks.filter(task => (task.status === 'scheduled'))} />
<h4>{MailPoet.I18n.t('runningTasks')}</h4>
<TasksList tasks={status.latestTasks.filter(task => (task.status === null))} />
<h4>{MailPoet.I18n.t('completedTasks')}</h4>
<TasksList tasks={status.latestTasks.filter(task => (task.status === 'completed'))} />
</div>
);
};
QueueStatus.propTypes = {
status_data: React.PropTypes.shape({
status: React.PropTypes.string,
started: React.PropTypes.number,
sent: React.PropTypes.number,
retry_attempt: React.PropTypes.number,
retry_at: React.PropTypes.number,
tasksStatusCounts: React.PropTypes.shape({
completed: React.PropTypes.number.isRequired,
running: React.PropTypes.number.isRequired,
paused: React.PropTypes.number.isRequired,
scheduled: React.PropTypes.number.isRequired,
}).isRequired,
latestTasks: React.PropTypes.arrayOf(TasksListDataRow.propTypes.task).isRequired,
}).isRequired,
};
QueueStatus.defaultProps = {
status_data: {
status: null,
started: null,
sent: null,
retry_attempt: null,
retry_at: null,
},
};
module.exports = QueueStatus;

View File

@ -1,7 +1,6 @@
import React from 'react';
import MailPoet from 'mailpoet';
import _ from 'underscore';
import Tabs from './tabs.jsx';
function handleFocus(event) {
@ -10,12 +9,10 @@ function handleFocus(event) {
function printData(data) {
if (_.isObject(data)) {
const printableData = Object.keys(data).map((key) => {
return `${key}: ${data[key]}`;
});
const printableData = Object.keys(data).map(key => `${key}: ${data[key]}`);
return (<textarea
readOnly={true}
readOnly
onFocus={handleFocus}
value={printableData.join('\n')}
style={{
@ -23,25 +20,24 @@ function printData(data) {
height: '400px',
}}
/>);
} else {
return (<p>{MailPoet.I18n.t('systemInfoDataError')}</p>);
}
return (<p>{MailPoet.I18n.t('systemInfoDataError')}</p>);
}
function KnowledgeBase() {
const data = window.help_scout_data;
function SystemInfo() {
const systemInfoData = window.systemInfoData;
return (
<div>
<Tabs tab="systemInfo" />
<div className="mailpoet_notice notice inline notice-success" style={{ marginTop: '1em' }}>
<div className="mailpoet_notice notice inline" style={{ marginTop: '1em' }}>
<p>{MailPoet.I18n.t('systemInfoIntro')}</p>
</div>
{printData(data)}
{printData(systemInfoData)}
</div>
);
};
}
module.exports = KnowledgeBase;
module.exports = SystemInfo;

View File

@ -0,0 +1,75 @@
import MailPoet from 'mailpoet';
import React from 'react';
import ReactStringReplace from 'react-string-replace';
import CronStatus from './cron_status.jsx';
import QueueStatus from './queue_status.jsx';
import Tabs from './tabs.jsx';
function renderStatusMessage(status, error, link) {
const noticeType = (status) ? 'success' : 'error';
let noticeMessage = (status) ?
MailPoet.I18n.t('systemStatusConnectionSuccessful') :
`${MailPoet.I18n.t('systemStatusConnectionUnsuccessful')} ${error}`;
if (link) {
noticeMessage = ReactStringReplace(
noticeMessage,
/\[link\](.*?)\[\/link\]/g,
match => (
<a href={`${link}`} key="kb-link">{ match }</a>
)
);
}
return (
<div className={`mailpoet_notice notice inline notice-${noticeType}`} style={{ marginTop: '1em' }}>
<p>{noticeMessage}</p>
</div>
);
}
function renderCronSection(data) {
const status = data.cron.isReachable;
const url = data.cron.url;
return (
<div>
<h2>{MailPoet.I18n.t('systemStatusCronTitle')}</h2>
<p>
<a href={url} target="_blank">{url}</a>
</p>
{renderStatusMessage(status, MailPoet.I18n.t('systemStatusCronConnectionUnsuccessfulInfo'), '//beta.docs.mailpoet.com/article/231-sending-does-not-work')}
</div>
);
}
function renderMSSSection(data) {
if (!data.mss.enabled) return undefined;
const status = data.mss.enabled.isReachable;
return (
<div>
<h2>{MailPoet.I18n.t('systemStatusMSSTitle')}</h2>
{renderStatusMessage(status, MailPoet.I18n.t('systemStatusMSSConnectionUnsuccessfulInfo'), false)}
</div>
);
}
function SystemStatus() {
const systemStatusData = window.systemStatusData;
return (
<div>
<Tabs tab="systemStatus" />
<div className="mailpoet_notice notice inline" style={{ marginTop: '1em' }}>
<p>{systemStatusData.mss.enabled ? MailPoet.I18n.t('systemStatusIntroCronMSS') : MailPoet.I18n.t('systemStatusIntroCron')}</p>
</div>
{renderCronSection(systemStatusData)}
{renderMSSSection(systemStatusData)}
<CronStatus status_data={systemStatusData.cronStatus} />
<QueueStatus status_data={systemStatusData.queueStatus} />
</div>
);
}
module.exports = SystemStatus;

View File

@ -9,6 +9,11 @@ const tabs = [
label: MailPoet.I18n.t('tabKnowledgeBaseTitle'),
link: '/knowledgeBase',
},
{
name: 'systemStatus',
label: MailPoet.I18n.t('tabSystemStatusTitle'),
link: '/systemStatus',
},
{
name: 'systemInfo',
label: MailPoet.I18n.t('tabSystemInfoTitle'),
@ -17,8 +22,7 @@ const tabs = [
];
function Tabs(props) {
const tabLinks = tabs.map((tab, index) => {
const tabLinks = tabs.map((tab) => {
const tabClasses = classNames(
'nav-tab',
{ 'nav-tab-active': (props.tab === tab.name) }
@ -26,9 +30,9 @@ function Tabs(props) {
return (
<Link
key={ 'tab-'+index }
className={ tabClasses }
to={ tab.link }
key={`tab-${tab.name}`}
className={tabClasses}
to={tab.link}
>{ tab.label }</Link>
);
});
@ -38,7 +42,7 @@ function Tabs(props) {
{ tabLinks }
</h2>
);
};
}
Tabs.propTypes = { tab: React.PropTypes.string };
Tabs.defaultProps = { tab: 'knowledgeBase' };

View File

@ -0,0 +1,41 @@
import React from 'react';
import MailPoet from 'mailpoet';
import TaskListDataRow from './tasks_list_data_row.jsx';
import TaskListLabelsRow from './tasks_list_labels_row.jsx';
const TasksList = (props) => {
const colsCount = props.show_scheduled_at ? 6 : 5;
return (
<table className="widefat fixed striped">
<thead><TaskListLabelsRow show_scheduled_at={props.show_scheduled_at} /></thead>
<tbody>
{
props.tasks.length ? props.tasks.map(task => (
<TaskListDataRow
key={task.id}
task={task}
show_scheduled_at={props.show_scheduled_at}
/>)
) : (
<tr className="no-items">
<td colSpan={colsCount}>{MailPoet.I18n.t('nothingToShow')}</td>
</tr>
)
}
</tbody>
<tfoot><TaskListLabelsRow show_scheduled_at={props.show_scheduled_at} /></tfoot>
</table>
);
};
TasksList.propTypes = {
show_scheduled_at: React.PropTypes.bool,
tasks: React.PropTypes.arrayOf(TaskListDataRow.propTypes.task).isRequired,
};
TasksList.defaultProps = {
show_scheduled_at: false,
};
module.exports = TasksList;

View File

@ -0,0 +1,63 @@
import React from 'react';
import MailPoet from 'mailpoet';
const TasksListDataRow = props => (
<tr>
<td className="column column-primary">
{ props.task.id }
</td>
<td className="column">
{ props.task.type }
</td>
<td className="column">
{ props.task.newsletter ? (
<a
href={props.task.newsletter.preview_url}
data-newsletter-id={props.task.newsletter.newsletter_id}
data-queue-id={props.task.newsletter.queue_id}
target="_blank"
>
{props.task.newsletter.subject || MailPoet.I18n.t('preview')}
</a>) : MailPoet.I18n.t('none')
}
</td>
<td className="column">
{ props.task.priority }
</td>
{ props.show_scheduled_at ? (
<td className="column-date">
<abbr>{ MailPoet.Date.format(props.task.scheduled_at * 1000) }</abbr>
</td>
) : null }
<td className="column-date">
<abbr>{ MailPoet.Date.format(props.task.updated_at * 1000) }</abbr>
</td>
</tr>
);
TasksListDataRow.propTypes = {
show_scheduled_at: React.PropTypes.bool,
task: React.PropTypes.shape({
id: React.PropTypes.number.isRequired,
type: React.PropTypes.string.isRequired,
priority: React.PropTypes.number.isRequired,
updated_at: React.PropTypes.number.isRequired,
scheduled_at: React.PropTypes.number,
status: React.PropTypes.string,
newsletter: React.PropTypes.shape({
newsletter_id: React.PropTypes.number.isRequired,
queue_id: React.PropTypes.number.isRequired,
preview_url: React.PropTypes.string.isRequired,
subject: React.PropTypes.string,
}),
}).isRequired,
};
TasksListDataRow.defaultProps = {
show_scheduled_at: false,
task: {
newsletter: null,
},
};
module.exports = TasksListDataRow;

View File

@ -0,0 +1,23 @@
import React from 'react';
import MailPoet from 'mailpoet';
const TasksListLabelsRow = props => (
<tr>
<th className="row-title">Id</th>
<th className="row-title">{MailPoet.I18n.t('type')}</th>
<th className="row-title">{MailPoet.I18n.t('email')}</th>
<th className="row-title">{MailPoet.I18n.t('priority')}</th>
{ props.show_scheduled_at ? (<th className="row-title">{MailPoet.I18n.t('scheduledAt')}</th>) : null }
<th className="row-title">{MailPoet.I18n.t('updatedAt')}</th>
</tr>
);
TasksListLabelsRow.propTypes = {
show_scheduled_at: React.PropTypes.bool,
};
TasksListLabelsRow.defaultProps = {
show_scheduled_at: false,
};
module.exports = TasksListLabelsRow;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,122 +1,114 @@
define([
'react',
'mailpoet',
],
(
React,
MailPoet
) => {
const ListingBulkActions = React.createClass({
getInitialState: function () {
return {
action: false,
extra: false,
};
},
handleChangeAction: function (e) {
this.setState({
action: e.target.value,
extra: false,
}, () => {
const action = this.getSelectedAction();
// action on select callback
if(action !== null && action['onSelect'] !== undefined) {
this.setState({
extra: action.onSelect(e),
});
}
});
},
handleApplyAction: function (e) {
e.preventDefault();
import React from 'react';
import MailPoet from 'mailpoet';
const ListingBulkActions = React.createClass({
getInitialState: function getInitialState() {
return {
action: false,
extra: false,
};
},
handleChangeAction: function handleChangeAction(e) {
this.setState({
action: e.target.value,
extra: false,
}, () => {
const action = this.getSelectedAction();
if(action === null) {
return;
}
const selected_ids = (this.props.selection !== 'all')
? this.props.selected_ids
: [];
const data = (action['getData'] !== undefined)
? action.getData()
: {};
data.action = this.state.action;
let onSuccess = function () {};
if(action['onSuccess'] !== undefined) {
onSuccess = action.onSuccess;
}
if(data.action) {
const promise = this.props.onBulkAction(selected_ids, data);
if (promise !== false) {
promise.then(onSuccess);
};
}
this.setState({
action: false,
extra: false,
});
},
getSelectedAction: function () {
const selected_action = this.refs.action.value;
if(selected_action.length > 0) {
const action = this.props.bulk_actions.filter((action) => {
return (action.name === selected_action);
// action on select callback
if (action !== null && action.onSelect !== undefined) {
this.setState({
extra: action.onSelect(e),
});
if(action.length > 0) {
return action[0];
}
}
});
},
handleApplyAction: function handleApplyAction(e) {
e.preventDefault();
const action = this.getSelectedAction();
if (action === null) {
return;
}
const selectedIds = (this.props.selection !== 'all')
? this.props.selected_ids
: [];
const data = (action.getData !== undefined)
? action.getData()
: {};
data.action = this.state.action;
let onSuccess = () => {};
if (action.onSuccess !== undefined) {
onSuccess = action.onSuccess;
}
if (data.action) {
const promise = this.props.onBulkAction(selectedIds, data);
if (promise !== false) {
promise.then(onSuccess);
}
}
this.setState({
action: false,
extra: false,
});
},
getSelectedAction: function getSelectedAction() {
const selectedAction = this.action.value;
if (selectedAction.length > 0) {
const action = this.props.bulk_actions.filter(act => (act.name === selectedAction));
if (action.length > 0) {
return action[0];
}
}
return null;
},
render: function render() {
if (this.props.bulk_actions.length === 0) {
return null;
},
render: function () {
if(this.props.bulk_actions.length === 0) {
return null;
}
}
return (
<div className="alignleft actions bulkactions">
<label
className="screen-reader-text"
htmlFor="bulk-action-selector-top">
{MailPoet.I18n.t('selectBulkAction')}
</label>
return (
<div className="alignleft actions bulkactions">
<label
className="screen-reader-text"
htmlFor="bulk-action-selector-top"
>
{MailPoet.I18n.t('selectBulkAction')}
</label>
<select
name="bulk_actions"
ref="action"
value={ this.state.action }
onChange={this.handleChangeAction}
>
<option value="">{MailPoet.I18n.t('bulkActions')}</option>
{ this.props.bulk_actions.map((action, index) => {
return (
<option
value={ action.name }
key={ 'action-' + index }
>{ action.label }</option>
);
}) }
</select>
<input
onClick={ this.handleApplyAction }
type="submit"
defaultValue={MailPoet.I18n.t('apply')}
className="button action" />
<select
name="bulk_actions"
ref={(c) => { this.action = c; }}
value={this.state.action}
onChange={this.handleChangeAction}
>
<option value="">{MailPoet.I18n.t('bulkActions')}</option>
{ this.props.bulk_actions.map(action => (
<option
value={action.name}
key={`action-${action.name}`}
>{ action.label }</option>
)) }
</select>
<input
onClick={this.handleApplyAction}
type="submit"
defaultValue={MailPoet.I18n.t('apply')}
className="button action"
/>
{ this.state.extra }
</div>
);
},
});
return ListingBulkActions;
{ this.state.extra }
</div>
);
},
});
export default ListingBulkActions;

View File

@ -1,107 +1,95 @@
define([
'react',
'jquery',
'mailpoet',
],
(
React,
jQuery,
MailPoet
) => {
const ListingFilters = React.createClass({
handleFilterAction: function () {
const filters = {};
this.getAvailableFilters().map((filter, i) => {
filters[this.refs['filter-'+i].name] = this.refs['filter-'+i].value;
});
if (this.props.onBeforeSelectFilter) {
this.props.onBeforeSelectFilter(filters);
}
return this.props.onSelectFilter(filters);
},
handleEmptyTrash: function () {
return this.props.onEmptyTrash();
},
getAvailableFilters: function () {
const filters = this.props.filters;
return Object.keys(filters).filter((filter) => {
return !(
filters[filter].length === 0
|| (
filters[filter].length === 1
&& !filters[filter][0].value
)
);
});
},
componentDidUpdate: function () {
const selected_filters = this.props.filter;
this.getAvailableFilters().map(
(filter, i) => {
if (selected_filters[filter] !== undefined && selected_filters[filter]) {
jQuery(this.refs['filter-'+i])
.val(selected_filters[filter])
.trigger('change');
}
import React from 'react';
import jQuery from 'jquery';
import MailPoet from 'mailpoet';
const ListingFilters = React.createClass({
handleFilterAction: function handleFilterAction() {
const filters = {};
this.getAvailableFilters().forEach((filter, i) => {
filters[this[`filter-${i}`].name] = this[`filter-${i}`].value;
});
if (this.props.onBeforeSelectFilter) {
this.props.onBeforeSelectFilter(filters);
}
return this.props.onSelectFilter(filters);
},
handleEmptyTrash: function handleEmptyTrash() {
return this.props.onEmptyTrash();
},
getAvailableFilters: function getAvailableFilters() {
const filters = this.props.filters;
return Object.keys(filters).filter(filter => !(
filters[filter].length === 0
|| (
filters[filter].length === 1
&& !filters[filter][0].value
)
));
},
componentDidUpdate: function componentDidUpdate() {
const selectedFilters = this.props.filter;
this.getAvailableFilters().forEach(
(filter, i) => {
if (selectedFilters[filter] !== undefined && selectedFilters[filter]) {
jQuery(this[`filter-${i}`])
.val(selectedFilters[filter])
.trigger('change');
}
);
},
render: function () {
const filters = this.props.filters;
const available_filters = this.getAvailableFilters()
.map((filter, i) => {
return (
<select
ref={ `filter-${i}` }
key={ `filter-${i}` }
name={ filter }
>
{ filters[filter].map((option, j) => {
return (
<option
value={ option.value }
key={ 'filter-option-' + j }
>{ option.label }</option>
);
}) }
</select>
);
});
let button;
if (available_filters.length > 0) {
button = (
<input
id="post-query-submit"
onClick={ this.handleFilterAction }
type="submit"
defaultValue={MailPoet.I18n.t('filter')}
className="button" />
);
}
);
},
render: function render() {
const filters = this.props.filters;
const availableFilters = this.getAvailableFilters()
.map((filter, i) => (
<select
ref={(c) => { this[`filter-${i}`] = c; }}
key={`filter-${filter}`}
name={filter}
>
{ filters[filter].map(option => (
<option
value={option.value}
key={`filter-option-${option.value}`}
>{ option.label }</option>
)) }
</select>
));
let empty_trash;
if (this.props.group === 'trash') {
empty_trash = (
<input
onClick={ this.handleEmptyTrash }
type="submit"
value={MailPoet.I18n.t('emptyTrash')}
className="button"
/>
);
}
let button;
return (
<div className="alignleft actions actions">
{ available_filters }
{ button }
{ empty_trash }
</div>
if (availableFilters.length > 0) {
button = (
<input
id="post-query-submit"
onClick={this.handleFilterAction}
type="submit"
defaultValue={MailPoet.I18n.t('filter')}
className="button"
/>
);
},
});
}
return ListingFilters;
let emptyTrash;
if (this.props.group === 'trash') {
emptyTrash = (
<input
onClick={this.handleEmptyTrash}
type="submit"
value={MailPoet.I18n.t('emptyTrash')}
className="button"
/>
);
}
return (
<div className="alignleft actions actions">
{ availableFilters }
{ button }
{ emptyTrash }
</div>
);
},
});
export default ListingFilters;

View File

@ -1,40 +1,58 @@
define(['react', 'classnames'], (React, classNames) => {
import React from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
const ListingGroups = React.createClass({
handleSelect: function (group) {
return this.props.onSelectGroup(group);
},
render: function () {
const groups = this.props.groups.map((group, index) => {
if(group.name === 'trash' && group.count === 0) {
return false;
}
class ListingGroups extends React.Component {
constructor(props) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
}
const classes = classNames(
{ current : (group.name === this.props.group) }
);
handleSelect(group) {
return this.props.onSelectGroup(group);
}
return (
<li key={index}>
{(index > 0) ? ' |' : ''}
<a
href="javascript:;"
className={classes}
onClick={this.handleSelect.bind(this, group.name)} >
{group.label} <span className="count">({ group.count.toLocaleString() })</span>
</a>
</li>
);
});
render() {
const groups = this.props.groups.map((group, index) => {
if (group.name === 'trash' && group.count === 0) {
return false;
}
const classes = classNames(
{ current: (group.name === this.props.group) }
);
return (
<ul className="subsubsub">
{ groups }
</ul>
<li key={group.name}>
{(index > 0) ? ' |' : ''}
<a
href="javascript:;"
className={classes}
onClick={() => this.handleSelect(group.name)}
data-automation-id={`filters_${group.label.replace(' ', '_').toLowerCase()}`}
>
{group.label}
<span className="count">({ parseInt(group.count, 10).toLocaleString() })</span>
</a>
</li>
);
},
});
});
return ListingGroups;
return (
<ul className="subsubsub">
{ groups }
</ul>
);
}
}
);
ListingGroups.propTypes = {
onSelectGroup: PropTypes.func.isRequired,
groups: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string,
count: PropTypes.number,
})).isRequired,
group: PropTypes.any.isRequired, // eslint-disable-line react/forbid-prop-types
};
export default ListingGroups;

View File

@ -3,12 +3,12 @@ import React from 'react';
import classNames from 'classnames';
const ListingHeader = React.createClass({
handleSelectItems: function () {
handleSelectItems: function handleSelectItems() {
return this.props.onSelectItems(
this.refs.toggle.checked
this.toggle.checked
);
},
render: function () {
render: function render() {
const columns = this.props.columns.map((column, index) => {
const renderColumn = column;
renderColumn.is_primary = (index === 0);
@ -19,26 +19,30 @@ const ListingHeader = React.createClass({
<ListingColumn
onSort={this.props.onSort}
sort_by={this.props.sort_by}
key={ 'column-' + index }
column={renderColumn} />
key={`column-${column.name}`}
column={renderColumn}
/>
);
});
let checkbox;
if(this.props.is_selectable === true) {
if (this.props.is_selectable === true) {
checkbox = (
<th
className="manage-column column-cb check-column">
<label className="screen-reader-text">
className="manage-column column-cb check-column"
>
<label className="screen-reader-text" htmlFor="select_all">
{MailPoet.I18n.t('selectAll')}
</label>
<input
type="checkbox"
name="select_all"
ref="toggle"
checked={ this.props.selection }
onChange={ this.handleSelectItems } />
id="select_all"
ref={(c) => { this.toggle = c; }}
checked={this.props.selection}
onChange={this.handleSelectItems}
/>
</th>
);
}
@ -53,12 +57,12 @@ const ListingHeader = React.createClass({
});
const ListingColumn = React.createClass({
handleSort: function () {
const sort_by = this.props.column.name;
const sort_order = (this.props.column.sorted === 'asc') ? 'desc' : 'asc';
this.props.onSort(sort_by, sort_order);
handleSort: function handleSort() {
const sortBy = this.props.column.name;
const sortOrder = (this.props.column.sorted === 'asc') ? 'desc' : 'asc';
this.props.onSort(sortBy, sortOrder);
},
render: function () {
render: function render() {
const classes = classNames(
'manage-column',
{ 'column-primary': this.props.column.is_primary },
@ -68,11 +72,15 @@ const ListingColumn = React.createClass({
);
let label;
if(this.props.column.sortable === true) {
if (this.props.column.sortable === true) {
label = (
<a onClick={ this.handleSort }>
<a
onClick={this.handleSort}
role="button"
tabIndex={0}
>
<span>{ this.props.column.label }</span>
<span className="sorting-indicator"></span>
<span className="sorting-indicator" />
</a>
);
} else {
@ -80,10 +88,11 @@ const ListingColumn = React.createClass({
}
return (
<th
className={ classes }
id={this.props.column.name }
role="columnheader"
className={classes}
id={this.props.column.name}
scope="col"
width={ this.props.column.width || null }
width={this.props.column.width || null}
>{label}</th>
);
},

File diff suppressed because it is too large Load Diff

View File

@ -1,185 +1,187 @@
define([
'react',
'classnames',
'mailpoet',
], (
React,
classNames,
MailPoet
) => {
import React from 'react';
import classNames from 'classnames';
import MailPoet from 'mailpoet';
const ListingPages = React.createClass({
getInitialState: function () {
return {
page: null,
};
},
setPage: function (page) {
this.setState({
page: null,
}, () => {
this.props.onSetPage(this.constrainPage(page));
});
},
setFirstPage: function () {
this.setPage(1);
},
setLastPage: function () {
this.setPage(this.getLastPage());
},
setPreviousPage: function () {
this.setPage(this.constrainPage(
parseInt(this.props.page, 10) - 1)
);
},
setNextPage: function () {
this.setPage(this.constrainPage(
parseInt(this.props.page, 10) + 1)
);
},
constrainPage: function (page) {
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
},
handleSetManualPage: function (e) {
if(e.which === 13) {
this.setPage(this.state.page);
const ListingPages = React.createClass({
getInitialState: function getInitialState() {
return {
page: null,
};
},
setPage: function setPage(page) {
this.setState({
page: null,
}, () => {
this.props.onSetPage(this.constrainPage(page));
});
},
setFirstPage: function setFirstPage() {
this.setPage(1);
},
setLastPage: function setLastPage() {
this.setPage(this.getLastPage());
},
setPreviousPage: function setPreviousPage() {
this.setPage(this.constrainPage(
parseInt(this.props.page, 10) - 1)
);
},
setNextPage: function setNextPage() {
this.setPage(this.constrainPage(
parseInt(this.props.page, 10) + 1)
);
},
constrainPage: function constrainPage(page) {
return Math.min(Math.max(1, Math.abs(Number(page))), this.getLastPage());
},
handleSetManualPage: function handleSetManualPage(e) {
if (e.which === 13) {
this.setPage(this.state.page);
}
},
handleChangeManualPage: function handleChangeManualPage(e) {
this.setState({
page: e.target.value,
});
},
handleBlurManualPage: function handleBlurManualPage(e) {
this.setPage(e.target.value);
},
getLastPage: function getLastPage() {
return Math.ceil(this.props.count / this.props.limit);
},
render: function render() {
if (this.props.count === 0) {
return false;
}
let pagination = false;
let firstPage = (
<span aria-hidden="true" className="tablenav-pages-navspan">«</span>
);
let previousPage = (
<span aria-hidden="true" className="tablenav-pages-navspan"></span>
);
let nextPage = (
<span aria-hidden="true" className="tablenav-pages-navspan"></span>
);
let lastPage = (
<span aria-hidden="true" className="tablenav-pages-navspan">»</span>
);
if (this.props.limit > 0 && this.props.count > this.props.limit) {
if (this.props.page > 1) {
previousPage = (
<a
href="javascript:;"
onClick={this.setPreviousPage}
className="prev-page"
>
<span className="screen-reader-text">{MailPoet.I18n.t('previousPage')}</span>
<span aria-hidden="true"></span>
</a>
);
}
},
handleChangeManualPage: function (e) {
this.setState({
page: e.target.value,
});
},
handleBlurManualPage: function (e) {
this.setPage(e.target.value);
},
getLastPage: function () {
return Math.ceil(this.props.count / this.props.limit);
},
render: function () {
if(this.props.count === 0) {
return false;
} else {
let pagination = false;
let firstPage = (
<span aria-hidden="true" className="tablenav-pages-navspan">«</span>
if (this.props.page > 2) {
firstPage = (
<a
href="javascript:;"
onClick={this.setFirstPage}
className="first-page"
>
<span className="screen-reader-text">{MailPoet.I18n.t('firstPage')}</span>
<span aria-hidden="true">«</span>
</a>
);
let previousPage = (
<span aria-hidden="true" className="tablenav-pages-navspan"></span>
}
if (this.props.page < this.getLastPage()) {
nextPage = (
<a
href="javascript:;"
onClick={this.setNextPage}
className="next-page"
>
<span className="screen-reader-text">{MailPoet.I18n.t('nextPage')}</span>
<span aria-hidden="true"></span>
</a>
);
let nextPage = (
<span aria-hidden="true" className="tablenav-pages-navspan"></span>
);
let lastPage = (
<span aria-hidden="true" className="tablenav-pages-navspan">»</span>
}
if (this.props.page < this.getLastPage() - 1) {
lastPage = (
<a
href="javascript:;"
onClick={this.setLastPage}
className="last-page"
>
<span className="screen-reader-text">{MailPoet.I18n.t('lastPage')}</span>
<span aria-hidden="true">»</span>
</a>
);
}
if(this.props.limit > 0 && this.props.count > this.props.limit) {
if(this.props.page > 1) {
previousPage = (
<a href="javascript:;"
onClick={ this.setPreviousPage }
className="prev-page">
<span className="screen-reader-text">{MailPoet.I18n.t('previousPage')}</span>
<span aria-hidden="true"></span>
</a>
);
}
let pageValue = this.props.page;
if (this.state.page !== null) {
pageValue = this.state.page;
}
if(this.props.page > 2) {
firstPage = (
<a href="javascript:;"
onClick={ this.setFirstPage }
className="first-page">
<span className="screen-reader-text">{MailPoet.I18n.t('firstPage')}</span>
<span aria-hidden="true">«</span>
</a>
);
}
if(this.props.page < this.getLastPage()) {
nextPage = (
<a href="javascript:;"
onClick={ this.setNextPage }
className="next-page">
<span className="screen-reader-text">{MailPoet.I18n.t('nextPage')}</span>
<span aria-hidden="true"></span>
</a>
);
}
if(this.props.page < this.getLastPage() - 1) {
lastPage = (
<a href="javascript:;"
onClick={ this.setLastPage }
className="last-page">
<span className="screen-reader-text">{MailPoet.I18n.t('lastPage')}</span>
<span aria-hidden="true">»</span>
</a>
);
}
let pageValue = this.props.page;
if(this.state.page !== null) {
pageValue = this.state.page;
}
pagination = (
<span className="pagination-links">
{firstPage}
&nbsp;
{previousPage}
&nbsp;
<span className="paging-input">
<label
className="screen-reader-text"
htmlFor="current-page-selector">{MailPoet.I18n.t('currentPage')}</label>
<input
type="text"
onChange={ this.handleChangeManualPage }
onKeyUp={ this.handleSetManualPage }
onBlur={ this.handleBlurManualPage }
aria-describedby="table-paging"
size="2"
ref="page"
value={ pageValue }
name="paged"
id="current-page-selector"
className="current-page" />
&nbsp;{MailPoet.I18n.t('pageOutOf')}&nbsp;
<span className="total-pages">
{Math.ceil(this.props.count / this.props.limit).toLocaleString()}
</span>
</span>
&nbsp;
{nextPage}
&nbsp;
{lastPage}
pagination = (
<span className="pagination-links">
{firstPage}
&nbsp;
{previousPage}
&nbsp;
<span className="paging-input">
<label
className="screen-reader-text"
htmlFor="current-page-selector"
>{MailPoet.I18n.t('currentPage')}</label>
<input
type="text"
onChange={this.handleChangeManualPage}
onKeyUp={this.handleSetManualPage}
onBlur={this.handleBlurManualPage}
aria-describedby="table-paging"
size="2"
value={pageValue}
name="paged"
id="current-page-selector"
className="current-page"
/>
{MailPoet.I18n.t('pageOutOf')}&nbsp;
<span className="total-pages">
{Math.ceil(this.props.count / this.props.limit).toLocaleString()}
</span>
);
}
</span>
&nbsp;
{nextPage}
&nbsp;
{lastPage}
</span>
);
}
const classes = classNames(
'tablenav-pages',
{ 'one-page': (this.props.count <= this.props.limit) }
);
const classes = classNames(
'tablenav-pages',
{ 'one-page': (this.props.count <= this.props.limit) }
);
let numberOfItemsLabel;
if (this.props.count == 1) {
numberOfItemsLabel = MailPoet.I18n.t('numberOfItemsSingular');
} else {
numberOfItemsLabel = MailPoet.I18n.t('numberOfItemsMultiple')
.replace('%$1d', this.props.count.toLocaleString());
}
return (
<div className={ classes }>
<span className="displaying-num">{ numberOfItemsLabel }</span>
{ pagination }
</div>
);
}
},
});
let numberOfItemsLabel;
if (Number(this.props.count) === 1) {
numberOfItemsLabel = MailPoet.I18n.t('numberOfItemsSingular');
} else {
numberOfItemsLabel = MailPoet.I18n.t('numberOfItemsMultiple')
.replace('%$1d', parseInt(this.props.count, 10).toLocaleString());
}
return ListingPages;
return (
<div className={classes}>
<span className="displaying-num">{ numberOfItemsLabel }</span>
{ pagination }
</div>
);
},
});
module.exports = ListingPages;

View File

@ -1,47 +1,51 @@
define([
'mailpoet',
'react',
], (
MailPoet,
React
) => {
import React from 'react';
import MailPoet from 'mailpoet';
import PropTypes from 'prop-types';
const ListingSearch = React.createClass({
handleSearch: function (e) {
e.preventDefault();
this.props.onSearch(
this.refs.search.value
);
},
componentWillReceiveProps: function (nextProps) {
this.refs.search.value = nextProps.search;
},
render: function () {
if(this.props.search === false) {
return false;
} else {
return (
<form name="search" onSubmit={this.handleSearch}>
<p className="search-box">
<label htmlFor="search_input" className="screen-reader-text">
{MailPoet.I18n.t('searchLabel')}
</label>
<input
type="search"
id="search_input"
ref="search"
name="s"
defaultValue={this.props.search} />
<input
type="submit"
defaultValue={MailPoet.I18n.t('searchLabel')}
className="button" />
</p>
</form>
);
}
},
});
class ListingSearch extends React.Component {
componentWillReceiveProps(nextProps) {
this.search.value = nextProps.search;
this.handleSearch = this.handleSearch.bind(this);
}
return ListingSearch;
});
handleSearch(e) {
e.preventDefault();
this.props.onSearch(
this.search.value.trim()
);
}
render() {
if (this.props.search === false) {
return false;
}
return (
<form name="search" onSubmit={this.handleSearch}>
<p className="search-box">
<label htmlFor="search_input" className="screen-reader-text">
{MailPoet.I18n.t('searchLabel')}
</label>
<input
type="search"
id="search_input"
ref={(c) => { this.search = c; }}
name="s"
defaultValue={this.props.search}
/>
<input
type="submit"
defaultValue={MailPoet.I18n.t('searchLabel')}
className="button"
/>
</p>
</form>
);
}
}
ListingSearch.propTypes = {
search: PropTypes.string.isRequired,
onSearch: PropTypes.func.isRequired,
};
export default ListingSearch;

View File

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

View File

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

View File

@ -1,5 +1,7 @@
define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
/* eslint-disable func-names */
define('mp2migrator', ['mailpoet', 'jquery'], function (mp, jQuery) {
'use strict';
var MailPoet = mp;
MailPoet.MP2Migrator = {
@ -11,7 +13,7 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
clearTimeout(MailPoet.MP2Migrator.displayLogs_timeout);
clearTimeout(MailPoet.MP2Migrator.updateProgressbar_timeout);
clearTimeout(MailPoet.MP2Migrator.update_wordpress_info_timeout);
setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000)
setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000);
},
stopLogger: function () {
@ -25,51 +27,54 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
displayLogs: function () {
jQuery.ajax({
url: mailpoet_mp2_migrator.log_file_url,
url: window.mailpoet_mp2_migrator.log_file_url,
cache: false
}).done(function (result) {
jQuery('#logger').html('');
result.split('\n').forEach(function (resultRow) {
var row = resultRow;
if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
if (row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
}
// Test if the import is complete
else if(row === MailPoet.I18n.t('import_complete')) {
} else if (row === MailPoet.I18n.t('import_complete')) { // Test if the import is complete
jQuery('#import-actions').hide();
jQuery('#upgrade-completed').show();
}
jQuery('#logger').append(row + '<br />\n');
});
jQuery('#logger').append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span>' + '<br />\n');
jQuery('#logger').append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span><br />\n');
}).always(function () {
if(MailPoet.MP2Migrator.is_logging) {
MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000);
if (MailPoet.MP2Migrator.is_logging) {
MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(
MailPoet.MP2Migrator.displayLogs,
1000
);
}
});
},
updateProgressbar: function () {
jQuery.ajax({
url: mailpoet_mp2_migrator.progress_url,
url: window.mailpoet_mp2_migrator.progress_url,
cache: false,
dataType: 'json'
}).always(function (result) {
// Move the progress bar
var progress = 0;
if((result.total !== undefined) && (Number(result.total) !== 0)) {
progress = Math.round(Number(result.current) / Number(result.total) * 100);
if ((result.total !== undefined) && (Number(result.total) !== 0)) {
progress = Math.round((Number(result.current) / Number(result.total)) * 100);
}
jQuery('#progressbar').progressbar('option', 'value', progress);
jQuery('#progresslabel').html(progress + '%');
if(Number(result.current) !== 0) {
if (Number(result.current) !== 0) {
jQuery('#skip-import').hide();
jQuery('#progressbar').show();
jQuery('#logger-container').show();
}
if(MailPoet.MP2Migrator.is_logging) {
MailPoet.MP2Migrator.updateProgressbar_timeout = setTimeout(MailPoet.MP2Migrator.updateProgressbar, 1000);
if (MailPoet.MP2Migrator.is_logging) {
MailPoet.MP2Migrator.updateProgressbar_timeout = setTimeout(
MailPoet.MP2Migrator.updateProgressbar,
1000
);
}
});
},
@ -96,19 +101,20 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
}
}).always(function () {
MailPoet.MP2Migrator.stopLogger();
MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped
// Get the latest information after the import was stopped
MailPoet.MP2Migrator.updateDisplay();
MailPoet.MP2Migrator.reactivateImportButton();
}).done(function (response) {
if(response) {
if (response) {
MailPoet.MP2Migrator.fatal_error = response.data;
}
}).fail(function (response) {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function (error) {
return error.message;
}),
{scroll: true}
{ scroll: true }
);
}
});
@ -132,14 +138,15 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
}).always(function () {
jQuery('#stop-import').removeAttr('disabled'); // Enable the button
MailPoet.MP2Migrator.reactivateImportButton();
MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped
// Get the latest information after the import was stopped
MailPoet.MP2Migrator.updateDisplay();
}).fail(function (response) {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function (error) {
return error.message;
}),
{scroll: true}
{ scroll: true }
);
}
});
@ -157,12 +164,12 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
}).done(function () {
MailPoet.MP2Migrator.gotoWelcomePage();
}).fail(function (response) {
if(response.errors.length > 0) {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(function (error) {
return error.message;
}),
{scroll: true}
{ scroll: true }
);
}
});
@ -175,35 +182,34 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
}
};
/**
* Actions to run when the DOM is ready
*/
jQuery(function () {
jQuery('#progressbar').progressbar({value: 0});
jQuery('#progressbar').progressbar({ value: 0 });
// Import button
jQuery('#import').click(function() {
jQuery('#import').click(function () {
MailPoet.MP2Migrator.startImport();
});
// Stop import button
jQuery('#stop-import').click(function() {
jQuery('#stop-import').click(function () {
MailPoet.MP2Migrator.stopImport();
});
// Skip import link
jQuery('#skip-import').click(function() {
jQuery('#skip-import').click(function () {
MailPoet.MP2Migrator.skipImport();
});
// Go to welcome page
jQuery('#goto-welcome').click(function() {
jQuery('#goto-welcome').click(function () {
MailPoet.MP2Migrator.gotoWelcomePage();
});
// Update the display
MailPoet.MP2Migrator.updateDisplay();
});
});

View File

@ -1,12 +1,8 @@
define([
'backbone',
'backbone.marionette',
'backbone.radio',
'jquery',
'underscore',
'handlebars',
'handlebars_helpers'
], function(Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
'backbone',
'backbone.marionette',
'backbone.radio'
], function (Backbone, Marionette, BackboneRadio) { // eslint-disable-line func-names
var Radio = BackboneRadio;
var AppView = Marionette.View.extend({
@ -16,19 +12,20 @@ define([
contentRegion: '#mailpoet_editor_content',
sidebarRegion: '#mailpoet_editor_sidebar',
bottomRegion: '#mailpoet_editor_bottom',
headingRegion: '#mailpoet_editor_heading'
headingRegion: '#mailpoet_editor_heading',
topRegion: '#mailpoet_editor_top'
}
});
var EditorApplication = Marionette.Application.extend({
region: '#mailpoet_editor',
onStart: function() {
onStart: function () { // eslint-disable-line func-names
this._appView = new AppView();
this.showView(this._appView);
},
getChannel: function(channel) {
getChannel: function (channel) { // eslint-disable-line func-names
if (channel === undefined) {
return Radio.channel('global');
}
@ -40,5 +37,4 @@ define([
window.EditorApplication = app;
return app;
});

View File

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

View File

@ -4,23 +4,43 @@
* Adds a color picker integration with the view
*/
define([
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup',
'mailpoet',
'spectrum'
], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) {
'backbone.marionette',
'newsletter_editor/behaviors/BehaviorsLookup',
'mailpoet',
'spectrum'
], function (Marionette, BehaviorsLookup, MailPoet) { // eslint-disable-line func-names
var BL = BehaviorsLookup;
BL.ColorPickerBehavior = Marionette.Behavior.extend({
onRender: function() {
this.view.$('.mailpoet_color').spectrum({
clickoutFiresChange: true,
showInput: true,
showInitial: true,
preferredFormat: 'hex6',
allowEmpty: true,
chooseText: MailPoet.I18n.t('selectColor'),
cancelText: MailPoet.I18n.t('cancelColorSelection')
onRender: function () { // eslint-disable-line func-names
var that = this;
var preferredFormat = 'hex6';
this.view.$('.mailpoet_color').each(function () { // eslint-disable-line func-names
var $input = that.view.$(this);
var updateColorInput = function (color) { // eslint-disable-line func-names
if (color && color.getAlpha() > 0) {
$input.val(color.toString(preferredFormat));
} else {
$input.val('');
}
$input.trigger('change');
};
$input.spectrum({
clickoutFiresChange: true,
showInput: true,
showInitial: true,
showPalette: true,
showSelectionPalette: true,
palette: [],
localStorageKey: 'newsletter_editor.spectrum.palette',
preferredFormat: preferredFormat,
allowEmpty: true,
chooseText: MailPoet.I18n.t('selectColor'),
cancelText: MailPoet.I18n.t('cancelColorSelection'),
change: updateColorInput,
move: updateColorInput,
hide: updateColorInput
});
});
}
});

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