Compare commits
91 Commits
3.0.0-rc.1
...
3.0.0-rc.1
Author | SHA1 | Date | |
---|---|---|---|
14810a22b5 | |||
c12752403f | |||
d3ff174e9f | |||
03df7e723c | |||
6c8fe8413a | |||
89b0b51980 | |||
fa1ab733f8 | |||
127022645e | |||
b1d26b8cee | |||
f07b90adde | |||
b3884d06a8 | |||
abf1d817f4 | |||
c7b7b0abad | |||
8540e5eea9 | |||
09ed3d4fa6 | |||
b96dc8b3f7 | |||
0a4dc3eb38 | |||
a78af28943 | |||
f035d12aaf | |||
6353075f1e | |||
6c91ca9d31 | |||
6f8634570c | |||
0efcfad3d1 | |||
5d7b54ab22 | |||
ad1f6e2a8e | |||
d844b7e47f | |||
36d4e3eb15 | |||
853f686dde | |||
d17486bac4 | |||
4226684c5a | |||
364dd1b2a3 | |||
eaf10e8a96 | |||
bac494ac0d | |||
acd2b9f51e | |||
27c6fa5ff4 | |||
89b51b6215 | |||
7725391eff | |||
a37117cfa3 | |||
856331caa4 | |||
9117ae1a27 | |||
4aae8d56e5 | |||
033d527db9 | |||
b2b1f7ff71 | |||
de261d6179 | |||
a587b0a966 | |||
441aa14bcb | |||
4b4b5dd556 | |||
df9ba7e6c8 | |||
ca4f1c9387 | |||
8c151d2d11 | |||
78fb9ba46f | |||
3a0669e1a2 | |||
c466e53681 | |||
d02aed870e | |||
fad7ff0018 | |||
84a3f98725 | |||
1c3e968ec4 | |||
c090a8260b | |||
65726de7de | |||
33fe302f0d | |||
2d702dd5d3 | |||
18f208cf47 | |||
f7b1016e63 | |||
223fedba72 | |||
bf7e7e414f | |||
618d0c0c9d | |||
49318791fc | |||
a5abdd28e1 | |||
70860a676c | |||
469e9fd8e1 | |||
715b48df8d | |||
27ae0a9f16 | |||
b92329a6b5 | |||
6fe5b7e0c5 | |||
7e0c500e4f | |||
eec35c8ab6 | |||
4096c4b31b | |||
40cbefd1f4 | |||
fb5d43e975 | |||
f35b66b3cf | |||
7900e7eb8d | |||
849a24ced7 | |||
f7e73b06be | |||
52cbb9fcb2 | |||
966ec0cb7a | |||
2ff0d40d10 | |||
bb249ebe09 | |||
5a57029b38 | |||
84d427cc4c | |||
f044db5745 | |||
9859df98b7 |
@ -55,6 +55,48 @@ jobs:
|
|||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: /tmp/fake-mailer/
|
path: /tmp/fake-mailer/
|
||||||
destination: fake-mailer
|
destination: fake-mailer
|
||||||
|
acceptance_tests:
|
||||||
|
working_directory: /home/circleci/mailpoet
|
||||||
|
machine: true
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: "Set up virtual host"
|
||||||
|
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
|
||||||
|
- restore_cache:
|
||||||
|
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
|
||||||
|
- restore_cache:
|
||||||
|
key: npm-{{ checksum "package.json" }}
|
||||||
|
- run:
|
||||||
|
name: "Set up test environment"
|
||||||
|
command: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install circleci-php-5.6.23
|
||||||
|
sudo rm /usr/bin/php
|
||||||
|
sudo ln -s /opt/circleci/php/5.6.23/bin/php /usr/bin/php
|
||||||
|
# Install NodeJS+NPM
|
||||||
|
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
|
||||||
|
sudo apt-get install nodejs build-essential
|
||||||
|
# install plugin dependencies
|
||||||
|
curl -sS https://getcomposer.org/installer | php
|
||||||
|
php composer.phar install
|
||||||
|
./do install
|
||||||
|
- save_cache:
|
||||||
|
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
|
||||||
|
paths:
|
||||||
|
- vendor
|
||||||
|
- save_cache:
|
||||||
|
key: npm-{{ checksum "package.json" }}
|
||||||
|
paths:
|
||||||
|
- node_modules
|
||||||
|
- run:
|
||||||
|
name: Run acceptance tests
|
||||||
|
command: |
|
||||||
|
docker-compose run codeception --steps --debug -vvv --html --xml
|
||||||
|
- store_artifacts:
|
||||||
|
path: ~/mailpoet/tests/acceptance-tests/_output
|
||||||
|
- store_test_results:
|
||||||
|
path: ~/mailpoet/tests/acceptance-tests/_output
|
||||||
php7:
|
php7:
|
||||||
working_directory: /home/circleci/mailpoet
|
working_directory: /home/circleci/mailpoet
|
||||||
docker:
|
docker:
|
||||||
@ -92,3 +134,4 @@ workflows:
|
|||||||
jobs:
|
jobs:
|
||||||
- qa_js_php5
|
- qa_js_php5
|
||||||
- php7
|
- php7
|
||||||
|
- acceptance_tests
|
||||||
|
@ -33,10 +33,8 @@
|
|||||||
"no-useless-return": 0,
|
"no-useless-return": 0,
|
||||||
"array-callback-return": 0,
|
"array-callback-return": 0,
|
||||||
"new-cap": 0,
|
"new-cap": 0,
|
||||||
"no-return-assign": 0,
|
|
||||||
"no-continue": 0,
|
"no-continue": 0,
|
||||||
"no-new": 0,
|
"no-new": 0,
|
||||||
"no-cond-assign": 0,
|
|
||||||
"space-unary-ops": 0,
|
"space-unary-ops": 0,
|
||||||
"no-redeclare": 0,
|
"no-redeclare": 0,
|
||||||
"no-console": 0,
|
"no-console": 0,
|
||||||
@ -60,7 +58,6 @@
|
|||||||
"space-in-parens": 0,
|
"space-in-parens": 0,
|
||||||
"semi": 0,
|
"semi": 0,
|
||||||
"max-len": 0,
|
"max-len": 0,
|
||||||
"no-multi-assign": 0,
|
|
||||||
"no-trailing-spaces": 0,
|
"no-trailing-spaces": 0,
|
||||||
"global-require": 0,
|
"global-require": 0,
|
||||||
"no-throw-literal": 0,
|
"no-throw-literal": 0,
|
||||||
@ -85,7 +82,6 @@
|
|||||||
"no-unused-vars": 0,
|
"no-unused-vars": 0,
|
||||||
"object-shorthand": 0,
|
"object-shorthand": 0,
|
||||||
"new-parens": 0,
|
"new-parens": 0,
|
||||||
"no-param-reassign": 0,
|
|
||||||
"keyword-spacing": 0,
|
"keyword-spacing": 0,
|
||||||
"eol-last": 0,
|
"eol-last": 0,
|
||||||
"dot-notation": 0,
|
"dot-notation": 0,
|
||||||
|
@ -80,7 +80,6 @@
|
|||||||
"no-sequences": 0,
|
"no-sequences": 0,
|
||||||
"no-extra-boolean-cast": 0,
|
"no-extra-boolean-cast": 0,
|
||||||
"dot-notation": 0,
|
"dot-notation": 0,
|
||||||
"no-param-reassign": 0,
|
|
||||||
"no-shadow": 0,
|
"no-shadow": 0,
|
||||||
"one-var": 0,
|
"one-var": 0,
|
||||||
"no-alert": 0,
|
"no-alert": 0,
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
"semi": 0,
|
"semi": 0,
|
||||||
"keyword-spacing": 0,
|
"keyword-spacing": 0,
|
||||||
"no-bitwise": 0,
|
"no-bitwise": 0,
|
||||||
"no-multi-assign": 0,
|
|
||||||
"newline-per-chained-call": 0,
|
"newline-per-chained-call": 0,
|
||||||
"no-spaced-func": 0,
|
"no-spaced-func": 0,
|
||||||
"func-call-spacing": 0,
|
"func-call-spacing": 0,
|
||||||
@ -38,7 +37,6 @@
|
|||||||
"vars-on-top": 0,
|
"vars-on-top": 0,
|
||||||
"space-before-blocks": 0,
|
"space-before-blocks": 0,
|
||||||
"object-curly-spacing": 0,
|
"object-curly-spacing": 0,
|
||||||
"no-param-reassign": 0,
|
|
||||||
"one-var-declaration-per-line": 0,
|
"one-var-declaration-per-line": 0,
|
||||||
"func-names": 0,
|
"func-names": 0,
|
||||||
"space-before-function-paren": 0
|
"space-before-function-paren": 0
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,7 +3,6 @@ TODO
|
|||||||
composer.phar
|
composer.phar
|
||||||
/vendor
|
/vendor
|
||||||
tests/_output/*
|
tests/_output/*
|
||||||
tests/acceptance.suite.yml
|
|
||||||
tests/_support/_generated/*
|
tests/_support/_generated/*
|
||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
|
39
Dockerfile
Normal file
39
Dockerfile
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
FROM php:5.6-cli
|
||||||
|
|
||||||
|
ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get -y install \
|
||||||
|
git \
|
||||||
|
zlib1g-dev \
|
||||||
|
libssl-dev \
|
||||||
|
mysql-client \
|
||||||
|
sudo less \
|
||||||
|
--no-install-recommends && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
|
||||||
|
docker-php-ext-install bcmath zip mysqli pdo pdo_mysql && \
|
||||||
|
echo "date.timezone = UTC" >> /usr/local/etc/php/php.ini && \
|
||||||
|
curl -sS https://getcomposer.org/installer | php -- \
|
||||||
|
--filename=composer \
|
||||||
|
--install-dir=/usr/local/bin && \
|
||||||
|
composer global require --optimize-autoloader "hirak/prestissimo" && \
|
||||||
|
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
|
||||||
|
chmod +x wp-cli.phar && \
|
||||||
|
mv wp-cli.phar /usr/local/bin/wp
|
||||||
|
|
||||||
|
# Prepare application
|
||||||
|
WORKDIR /repo
|
||||||
|
|
||||||
|
# Install vendor
|
||||||
|
COPY ./composer.json /repo/composer.json
|
||||||
|
|
||||||
|
# Add source-code
|
||||||
|
COPY . /repo
|
||||||
|
|
||||||
|
WORKDIR /wp-core/wp-content/plugins/mailpoet
|
||||||
|
ENV WP_TEST_PATH=/wp-core
|
||||||
|
|
||||||
|
ADD docker-entrypoint.sh /
|
||||||
|
|
||||||
|
RUN ["chmod", "+x", "/docker-entrypoint.sh"]
|
18
README.md
18
README.md
@ -180,3 +180,21 @@ Run 'svn copy ...' to tag the release
|
|||||||
It's quite literal: you can review the changes to be pushed and if you're satisfied, run the suggested command to finish the release publishing process.
|
It's quite literal: you can review the changes to be pushed and if you're satisfied, run the suggested command to finish the release publishing process.
|
||||||
|
|
||||||
If you're confident, execute `./do publish --force` and your release will be published to the remote SVN repository without manual intervention (automatically). For easier authentication you might want to set `WP_SVN_USERNAME` and `WP_SVN_PASSWORD` environment variables.
|
If you're confident, execute `./do publish --force` and your release will be published to the remote SVN repository without manual intervention (automatically). For easier authentication you might want to set `WP_SVN_USERNAME` and `WP_SVN_PASSWORD` environment variables.
|
||||||
|
|
||||||
|
# Acceptance testing
|
||||||
|
|
||||||
|
We are using Gravity Flow plugin's setup as an example for our acceptance test suite: https://www.stevenhenty.com/learn-acceptance-testing-deeply/
|
||||||
|
|
||||||
|
From the article above:
|
||||||
|
|
||||||
|
_Windows users only: enable hard drive sharing in the Docker settings._
|
||||||
|
|
||||||
|
The browser runs in a docker container. You can use a VNC client to watch the test run, follow instructions in official
|
||||||
|
repo: https://github.com/SeleniumHQ/docker-selenium
|
||||||
|
If you’re on a Mac, you can open vnc://localhost:5900 in Safari to watch the tests running in Chrome. If you’re on Windows, you’ll need a VNC client. Password: secret.
|
||||||
|
|
||||||
|
|
||||||
|
To run tests:
|
||||||
|
```sh
|
||||||
|
$ ./do test:acceptance
|
||||||
|
```
|
24
RoboFile.php
24
RoboFile.php
@ -154,9 +154,9 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
|
|
||||||
function testUnit($opts=['file' => null, 'xml' => false]) {
|
function testUnit($opts=['file' => null, 'xml' => false]) {
|
||||||
$this->loadEnv();
|
$this->loadEnv();
|
||||||
$this->_exec('vendor/bin/codecept build');
|
$this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
|
||||||
|
|
||||||
$command = 'vendor/bin/codecept run unit -f '.(($opts['file']) ? $opts['file'] : '');
|
$command = 'vendor/bin/codecept run unit -c codeception.unit.yml -f '.(($opts['file']) ? $opts['file'] : '');
|
||||||
|
|
||||||
if($opts['xml']) {
|
if($opts['xml']) {
|
||||||
$command .= ' --xml';
|
$command .= ' --xml';
|
||||||
@ -166,9 +166,9 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
|
|
||||||
function testCoverage($opts=['file' => null, 'xml' => false]) {
|
function testCoverage($opts=['file' => null, 'xml' => false]) {
|
||||||
$this->loadEnv();
|
$this->loadEnv();
|
||||||
$this->_exec('vendor/bin/codecept build');
|
$this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
|
||||||
$command = join(' ', array(
|
$command = join(' ', array(
|
||||||
'vendor/bin/codecept run',
|
'vendor/bin/codecept run -c codeception.unit.yml ',
|
||||||
(($opts['file']) ? $opts['file'] : ''),
|
(($opts['file']) ? $opts['file'] : ''),
|
||||||
'--coverage',
|
'--coverage',
|
||||||
($opts['xml']) ? '--coverage-xml' : '--coverage-html'
|
($opts['xml']) ? '--coverage-xml' : '--coverage-html'
|
||||||
@ -201,9 +201,9 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
|
|
||||||
function testDebug($opts=['file' => null, 'xml' => false]) {
|
function testDebug($opts=['file' => null, 'xml' => false]) {
|
||||||
$this->loadEnv();
|
$this->loadEnv();
|
||||||
$this->_exec('vendor/bin/codecept build');
|
$this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
|
||||||
|
|
||||||
$command = 'vendor/bin/codecept run unit --debug -f '.(($opts['file']) ? $opts['file'] : '');
|
$command = 'vendor/bin/codecept run unit -c codeception.unit.yml --debug -f '.(($opts['file']) ? $opts['file'] : '');
|
||||||
|
|
||||||
if($opts['xml']) {
|
if($opts['xml']) {
|
||||||
$command .= ' --xml';
|
$command .= ' --xml';
|
||||||
@ -211,10 +211,14 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
return $this->_exec($command);
|
return $this->_exec($command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testAcceptance() {
|
||||||
|
return $this->_exec('COMPOSE_HTTP_TIMEOUT=200 docker-compose run codeception --steps --debug -vvv');
|
||||||
|
}
|
||||||
|
|
||||||
function testFailed() {
|
function testFailed() {
|
||||||
$this->loadEnv();
|
$this->loadEnv();
|
||||||
$this->_exec('vendor/bin/codecept build');
|
$this->_exec('vendor/bin/codecept build -c codeception.unit.yml');
|
||||||
return $this->_exec('vendor/bin/codecept run -g failed');
|
return $this->_exec('vendor/bin/codecept run -c codeception.unit.yml -g failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
function qa() {
|
function qa() {
|
||||||
@ -295,10 +299,6 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
$plugin_dist_name = explode('-', $plugin_dist_name);
|
$plugin_dist_name = explode('-', $plugin_dist_name);
|
||||||
$plugin_dist_name = $plugin_dist_name[0];
|
$plugin_dist_name = $plugin_dist_name[0];
|
||||||
$plugin_dist_file = $plugin_dist_name . '.zip';
|
$plugin_dist_file = $plugin_dist_name . '.zip';
|
||||||
|
|
||||||
$this->say('name: '. $plugin_dist_name);
|
|
||||||
return;
|
|
||||||
|
|
||||||
$this->say('Publishing version: ' . $plugin_version);
|
$this->say('Publishing version: ' . $plugin_version);
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
|
@ -45,7 +45,6 @@ body.mailpoet_modal_opened
|
|||||||
position: absolute
|
position: absolute
|
||||||
z-index: 25
|
z-index: 25
|
||||||
top: 48px
|
top: 48px
|
||||||
padding-bottom: 48px
|
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|
||||||
.mailpoet_popup_wrapper
|
.mailpoet_popup_wrapper
|
||||||
@ -54,6 +53,7 @@ body.mailpoet_modal_opened
|
|||||||
position: relative
|
position: relative
|
||||||
width: 100%
|
width: 100%
|
||||||
z-index: 0
|
z-index: 0
|
||||||
|
height: 96%
|
||||||
|
|
||||||
.mailpoet_overlay_hidden .mailpoet_popup_wrapper
|
.mailpoet_overlay_hidden .mailpoet_popup_wrapper
|
||||||
border: 1px solid #333
|
border: 1px solid #333
|
||||||
@ -75,6 +75,7 @@ body.mailpoet_modal_opened
|
|||||||
|
|
||||||
.mailpoet_popup_body
|
.mailpoet_popup_body
|
||||||
padding: 10px 10px 10px 10px
|
padding: 10px 10px 10px 10px
|
||||||
|
height: 92%
|
||||||
|
|
||||||
// modal panel
|
// modal panel
|
||||||
#mailpoet_modal_overlay.mailpoet_panel_overlay
|
#mailpoet_modal_overlay.mailpoet_panel_overlay
|
||||||
|
@ -179,6 +179,28 @@ select.mailpoet_font-size
|
|||||||
width: 100%
|
width: 100%
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
|
|
||||||
|
.tooltip-help-designer-subject-line div, .tooltip-help-designer-preheader div
|
||||||
|
z-index: 100001
|
||||||
|
|
||||||
|
.tooltip-help-send-preview
|
||||||
|
position: absolute
|
||||||
|
right: 15px
|
||||||
|
|
||||||
|
.tooltip-help-designer-ideal-width
|
||||||
|
color: #656565
|
||||||
|
text-transform: none
|
||||||
|
margin-left: 5px
|
||||||
|
font-weight: normal
|
||||||
|
|
||||||
|
.tooltip-help-designer-styles
|
||||||
|
position: absolute
|
||||||
|
top: 40px
|
||||||
|
|
||||||
|
.tooltip-help-designer-full-width .dashicons
|
||||||
|
line-height 34px
|
||||||
|
.tooltip-help-designer-full-width span
|
||||||
|
line-height 1.4em
|
||||||
|
|
||||||
.mailpoet_button_primary
|
.mailpoet_button_primary
|
||||||
border-color: $button-primary-border-color
|
border-color: $button-primary-border-color
|
||||||
background-color: $button-primary-background-color
|
background-color: $button-primary-background-color
|
||||||
|
@ -127,9 +127,6 @@ body
|
|||||||
background-color: $primary-background-color
|
background-color: $primary-background-color
|
||||||
border: 1px solid $content-border-color
|
border: 1px solid $content-border-color
|
||||||
|
|
||||||
#mailpoet_modal_close
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.wrap > .mailpoet_notice,
|
.wrap > .mailpoet_notice,
|
||||||
.notice
|
.notice
|
||||||
.update-nag
|
.update-nag
|
||||||
|
@ -54,6 +54,9 @@
|
|||||||
#mailpoet_mta_activate
|
#mailpoet_mta_activate
|
||||||
visibility hidden
|
visibility hidden
|
||||||
|
|
||||||
|
.tooltip.dashicons.dashicons-editor-help
|
||||||
|
line-height: 1.4
|
||||||
|
|
||||||
ul.sending-method-benefits
|
ul.sending-method-benefits
|
||||||
list-style-type: none
|
list-style-type: none
|
||||||
margin-bottom: 2em
|
margin-bottom: 2em
|
||||||
|
@ -12,7 +12,8 @@ function requestFailed(errorMessage, xhr) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery, _) {
|
define('ajax', ['mailpoet', 'jquery', 'underscore'], function(mp, jQuery, _) {
|
||||||
|
var MailPoet = mp;
|
||||||
|
|
||||||
MailPoet.Ajax = {
|
MailPoet.Ajax = {
|
||||||
version: 0.5,
|
version: 0.5,
|
||||||
|
@ -24,7 +24,8 @@ function track(name, data){
|
|||||||
window.mixpanel.track(name, data);
|
window.mixpanel.track(name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportMixpanel(MailPoet) {
|
function exportMixpanel(mp) {
|
||||||
|
var MailPoet = mp;
|
||||||
MailPoet.forceTrackEvent = track;
|
MailPoet.forceTrackEvent = track;
|
||||||
|
|
||||||
if (window.mailpoet_analytics_enabled) {
|
if (window.mailpoet_analytics_enabled) {
|
||||||
@ -61,7 +62,8 @@ function cacheEvent(forced, name, data) {
|
|||||||
|
|
||||||
define(
|
define(
|
||||||
['mailpoet', 'underscore'],
|
['mailpoet', 'underscore'],
|
||||||
function(MailPoet, _) {
|
function(mp, _) {
|
||||||
|
var MailPoet = mp;
|
||||||
|
|
||||||
MailPoet.trackEvent = _.partial(cacheEvent, false);
|
MailPoet.trackEvent = _.partial(cacheEvent, false);
|
||||||
MailPoet.forceTrackEvent = _.partial(cacheEvent, true);
|
MailPoet.forceTrackEvent = _.partial(cacheEvent, true);
|
||||||
|
@ -4,12 +4,14 @@ define('date',
|
|||||||
'jquery',
|
'jquery',
|
||||||
'moment'
|
'moment'
|
||||||
], function(
|
], function(
|
||||||
MailPoet,
|
mp,
|
||||||
jQuery,
|
jQuery,
|
||||||
Moment
|
Moment
|
||||||
) {
|
) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var MailPoet = mp;
|
||||||
|
|
||||||
MailPoet.Date = {
|
MailPoet.Date = {
|
||||||
version: 0.1,
|
version: 0.1,
|
||||||
options: {},
|
options: {},
|
||||||
@ -17,8 +19,8 @@ define('date',
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
format: 'F, d Y H:i:s'
|
format: 'F, d Y H:i:s'
|
||||||
},
|
},
|
||||||
init: function(options) {
|
init: function (opts) {
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
|
|
||||||
// set UTC offset
|
// set UTC offset
|
||||||
if (
|
if (
|
||||||
@ -39,16 +41,16 @@ define('date',
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
format: function(date, options) {
|
format: function(date, opts) {
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
this.init(options);
|
this.init(options);
|
||||||
|
|
||||||
var date = Moment(date, this.convertFormat(options.parseFormat));
|
var momentDate = Moment(date, this.convertFormat(options.parseFormat));
|
||||||
if (options.offset === 0) date = date.utc();
|
if (options.offset === 0) momentDate = momentDate.utc();
|
||||||
return date.format(this.convertFormat(this.options.format));
|
return momentDate.format(this.convertFormat(this.options.format));
|
||||||
},
|
},
|
||||||
toDate: function(date, options) {
|
toDate: function(date, opts) {
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
this.init(options);
|
this.init(options);
|
||||||
|
|
||||||
return Moment(date, this.convertFormat(options.parseFormat)).toDate();
|
return Moment(date, this.convertFormat(options.parseFormat)).toDate();
|
||||||
@ -143,7 +145,8 @@ define('date',
|
|||||||
var convertedFormat = [];
|
var convertedFormat = [];
|
||||||
var escapeToken = false;
|
var escapeToken = false;
|
||||||
|
|
||||||
for(var index = 0, token = ''; token = format.charAt(index); index++){
|
for(var index = 0, token = ''; format.charAt(index); index += 1){
|
||||||
|
token = format.charAt(index);
|
||||||
if (escapeToken === true) {
|
if (escapeToken === true) {
|
||||||
convertedFormat.push('['+token+']');
|
convertedFormat.push('['+token+']');
|
||||||
escapeToken = false;
|
escapeToken = false;
|
||||||
|
@ -28,12 +28,13 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
let field = false;
|
let field = false;
|
||||||
|
let dataField = data.field;
|
||||||
|
|
||||||
if(data.field['field'] !== undefined) {
|
if(data.field['field'] !== undefined) {
|
||||||
data.field = jQuery.merge(data.field, data.field.field);
|
dataField = jQuery.merge(dataField, data.field.field);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(data.field.type) {
|
switch(dataField.type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
field = (<FormFieldText {...data} />);
|
field = (<FormFieldText {...data} />);
|
||||||
break;
|
break;
|
||||||
|
@ -180,6 +180,7 @@ define([
|
|||||||
<select
|
<select
|
||||||
id={ this.props.field.id || this.props.field.name }
|
id={ this.props.field.id || this.props.field.name }
|
||||||
ref="select"
|
ref="select"
|
||||||
|
disabled={this.props.field.disabled}
|
||||||
data-placeholder={ this.props.field.placeholder }
|
data-placeholder={ this.props.field.placeholder }
|
||||||
multiple={ this.props.field.multiple }
|
multiple={ this.props.field.multiple }
|
||||||
defaultValue={ this.getSelectedValues() }
|
defaultValue={ this.getSelectedValues() }
|
||||||
|
@ -11,12 +11,14 @@ Object.extend(document, (function() {
|
|||||||
var cache = Event.cacheDelegated;
|
var cache = Event.cacheDelegated;
|
||||||
|
|
||||||
function getCacheForSelector(selector) {
|
function getCacheForSelector(selector) {
|
||||||
return cache[selector] = cache[selector] || {};
|
cache[selector] = cache[selector] || {};
|
||||||
|
return cache[selector];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWrappersForSelector(selector, eventName) {
|
function getWrappersForSelector(selector, eventName) {
|
||||||
var c = getCacheForSelector(selector);
|
var c = getCacheForSelector(selector);
|
||||||
return c[eventName] = c[eventName] || [];
|
c[eventName] = c[eventName] || [];
|
||||||
|
return c[eventName];
|
||||||
}
|
}
|
||||||
|
|
||||||
function findWrapper(selector, eventName, handler) {
|
function findWrapper(selector, eventName, handler) {
|
||||||
@ -79,8 +81,8 @@ Object.extend(document, (function() {
|
|||||||
})());
|
})());
|
||||||
|
|
||||||
var Observable = (function() {
|
var Observable = (function() {
|
||||||
function getEventName(name, namespace) {
|
function getEventName(nameA, namespace) {
|
||||||
name = name.substring(2);
|
var name = nameA.substring(2);
|
||||||
if(namespace) name = namespace + ':' + name;
|
if(namespace) name = namespace + ':' + name;
|
||||||
return name.underscore().split('_').join(':');
|
return name.underscore().split('_').join(':');
|
||||||
}
|
}
|
||||||
@ -574,7 +576,8 @@ var WysijaForm = {
|
|||||||
WysijaForm.locks.showingTools = false;
|
WysijaForm.locks.showingTools = false;
|
||||||
},
|
},
|
||||||
instances: {},
|
instances: {},
|
||||||
get: function(element, type) {
|
get: function(element, typ) {
|
||||||
|
var type = typ;
|
||||||
if(type === undefined) type = 'block';
|
if(type === undefined) type = 'block';
|
||||||
// identify element
|
// identify element
|
||||||
var id = element.identify();
|
var id = element.identify();
|
||||||
@ -893,7 +896,8 @@ WysijaForm.Block = Class.create({
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* Invoked on item dropped */
|
/* Invoked on item dropped */
|
||||||
WysijaForm.Block.create = function(block, target) {
|
WysijaForm.Block.create = function(createBlock, target) {
|
||||||
|
var block = createBlock;
|
||||||
if($('form_template_' + block.type) === null) {
|
if($('form_template_' + block.type) === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1050,7 +1054,8 @@ function info(value) {
|
|||||||
var noop = function() {};
|
var noop = function() {};
|
||||||
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
|
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
|
||||||
var length = methods.length;
|
var length = methods.length;
|
||||||
var console = window.console = {};
|
window.console = {};
|
||||||
|
var console = {};
|
||||||
while(length--) {
|
while(length--) {
|
||||||
console[methods[length]] = noop;
|
console[methods[length]] = noop;
|
||||||
}
|
}
|
||||||
|
@ -125,12 +125,13 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
|||||||
* @return {String} The truncated string.
|
* @return {String} The truncated string.
|
||||||
*/
|
*/
|
||||||
Handlebars.registerHelper('ellipsis', function (str, limit, append) {
|
Handlebars.registerHelper('ellipsis', function (str, limit, append) {
|
||||||
if (append === undefined) {
|
var strAppend = append;
|
||||||
append = '';
|
if (strAppend === undefined) {
|
||||||
|
strAppend = '';
|
||||||
}
|
}
|
||||||
var sanitized = str.replace(/(<([^>]+)>)/g, '');
|
var sanitized = str.replace(/(<([^>]+)>)/g, '');
|
||||||
if (sanitized.length > limit) {
|
if (sanitized.length > limit) {
|
||||||
return sanitized.substr(0, limit - append.length) + append;
|
return sanitized.substr(0, limit - strAppend.length) + strAppend;
|
||||||
} else {
|
} else {
|
||||||
return sanitized;
|
return sanitized;
|
||||||
}
|
}
|
||||||
|
21
assets/js/src/help-tooltip.js
Normal file
21
assets/js/src/help-tooltip.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
define('helpTooltip', ['mailpoet', 'react', 'react-dom', 'help-tooltip.jsx'],
|
||||||
|
function (mp, React, ReactDOM, TooltipComponent) {
|
||||||
|
'use strict';
|
||||||
|
var MailPoet = mp;
|
||||||
|
|
||||||
|
MailPoet.helpTooltip = {
|
||||||
|
show: function (domContainerNode, opts) {
|
||||||
|
|
||||||
|
ReactDOM.render(React.createElement(
|
||||||
|
TooltipComponent, {
|
||||||
|
tooltip: opts.tooltip,
|
||||||
|
tooltipId: opts.tooltipId,
|
||||||
|
place: opts.place
|
||||||
|
}
|
||||||
|
), domContainerNode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
63
assets/js/src/help-tooltip.jsx
Normal file
63
assets/js/src/help-tooltip.jsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactTooltip from 'react-tooltip';
|
||||||
|
import ReactHtmlParser from 'react-html-parser';
|
||||||
|
|
||||||
|
function Tooltip(props) {
|
||||||
|
let tooltipId = props.tooltipId;
|
||||||
|
let tooltip = props.tooltip;
|
||||||
|
// tooltip ID must be unique, defaults to tooltip text
|
||||||
|
if(!props.tooltipId && typeof props.tooltip === "string") {
|
||||||
|
tooltipId = props.tooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof props.tooltip === "string") {
|
||||||
|
tooltip = (<span
|
||||||
|
style={{
|
||||||
|
pointerEvents: "all",
|
||||||
|
maxWidth: "400",
|
||||||
|
display: "inline-block",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ReactHtmlParser(props.tooltip)}
|
||||||
|
</span>);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={props.className}>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
className="tooltip dashicons dashicons-editor-help"
|
||||||
|
data-event="click"
|
||||||
|
data-tip
|
||||||
|
data-for={tooltipId}
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<ReactTooltip
|
||||||
|
globalEventOff="click"
|
||||||
|
multiline={true}
|
||||||
|
id={tooltipId}
|
||||||
|
efect="solid"
|
||||||
|
place={props.place}
|
||||||
|
>
|
||||||
|
{tooltip}
|
||||||
|
</ReactTooltip>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip.propTypes = {
|
||||||
|
tooltipId: React.PropTypes.string,
|
||||||
|
tooltip: React.PropTypes.node.isRequired,
|
||||||
|
place: React.PropTypes.string,
|
||||||
|
className: React.PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
Tooltip.defaultProps = {
|
||||||
|
tooltipId: undefined,
|
||||||
|
place: undefined,
|
||||||
|
className: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Tooltip;
|
@ -2,9 +2,10 @@ define('i18n',
|
|||||||
[
|
[
|
||||||
'mailpoet'
|
'mailpoet'
|
||||||
], function(
|
], function(
|
||||||
MailPoet
|
mp
|
||||||
) {
|
) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var MailPoet = mp;
|
||||||
|
|
||||||
var translations = {};
|
var translations = {};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
define('iframe', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
define('iframe', ['mailpoet'], function(mp) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var MailPoet = mp;
|
||||||
MailPoet.Iframe = {
|
MailPoet.Iframe = {
|
||||||
marginY: 20,
|
marginY: 20,
|
||||||
autoSize: function(iframe) {
|
autoSize: function(iframe) {
|
||||||
@ -10,11 +11,12 @@ define('iframe', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
iframe.contentWindow.document.body.scrollHeight
|
iframe.contentWindow.document.body.scrollHeight
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
setSize: function(iframe, i) {
|
setSize: function(sizeIframe, i) {
|
||||||
|
var iframe = sizeIframe;
|
||||||
if(!iframe) return;
|
if(!iframe) return;
|
||||||
|
|
||||||
iframe.style.height = (
|
iframe.style.height = (
|
||||||
parseInt(i) + this.marginY
|
parseInt(i, 10) + this.marginY
|
||||||
) + "px";
|
) + "px";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3,8 +3,9 @@ define(
|
|||||||
'jquery'
|
'jquery'
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
$
|
jQuery
|
||||||
) {
|
) {
|
||||||
|
var $ = jQuery;
|
||||||
// Combination of jQuery.deparam and jQuery.serializeObject by Ben Alman.
|
// Combination of jQuery.deparam and jQuery.serializeObject by Ben Alman.
|
||||||
/*!
|
/*!
|
||||||
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
|
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
|
||||||
@ -74,9 +75,10 @@ define(
|
|||||||
// * Rinse & repeat.
|
// * Rinse & repeat.
|
||||||
for ( ; i <= keys_last; i++ ) {
|
for ( ; i <= keys_last; i++ ) {
|
||||||
key = keys[i] === '' ? cur.length : keys[i];
|
key = keys[i] === '' ? cur.length : keys[i];
|
||||||
cur = cur[key] = i < keys_last
|
cur[key] = i < keys_last
|
||||||
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
|
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
|
||||||
: val;
|
: val;
|
||||||
|
cur = cur[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -10,8 +10,9 @@ const ListingHeader = React.createClass({
|
|||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
const columns = this.props.columns.map((column, index) => {
|
const columns = this.props.columns.map((column, index) => {
|
||||||
column.is_primary = (index === 0);
|
const renderColumn = column;
|
||||||
column.sorted = (this.props.sort_by === column.name)
|
renderColumn.is_primary = (index === 0);
|
||||||
|
renderColumn.sorted = (this.props.sort_by === column.name)
|
||||||
? this.props.sort_order
|
? this.props.sort_order
|
||||||
: 'desc';
|
: 'desc';
|
||||||
return (
|
return (
|
||||||
@ -19,7 +20,7 @@ const ListingHeader = React.createClass({
|
|||||||
onSort={this.props.onSort}
|
onSort={this.props.onSort}
|
||||||
sort_by={this.props.sort_by}
|
sort_by={this.props.sort_by}
|
||||||
key={ 'column-' + index }
|
key={ 'column-' + index }
|
||||||
column={column} />
|
column={renderColumn} />
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -260,8 +260,9 @@ const ListingItems = React.createClass({
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{this.props.items.map((item, index) => {
|
{this.props.items.map((item, index) => {
|
||||||
item.id = parseInt(item.id, 10);
|
const renderItem = item;
|
||||||
item.selected = (this.props.selected_ids.indexOf(item.id) !== -1);
|
renderItem.id = parseInt(item.id, 10);
|
||||||
|
renderItem.selected = (this.props.selected_ids.indexOf(renderItem.id) !== -1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListingItem
|
<ListingItem
|
||||||
@ -276,8 +277,8 @@ const ListingItems = React.createClass({
|
|||||||
is_selectable={ this.props.is_selectable }
|
is_selectable={ this.props.is_selectable }
|
||||||
item_actions={ this.props.item_actions }
|
item_actions={ this.props.item_actions }
|
||||||
group={ this.props.group }
|
group={ this.props.group }
|
||||||
key={ `item-${item.id}-${index}` }
|
key={ `item-${renderItem.id}-${index}` }
|
||||||
item={ item } />
|
item={ renderItem } />
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -418,16 +419,17 @@ const Listing = React.createClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setBaseUrlParams: function (base_url) {
|
setBaseUrlParams: function (base_url) {
|
||||||
if (base_url.indexOf(':') !== -1) {
|
let ret = base_url;
|
||||||
|
if (ret.indexOf(':') !== -1) {
|
||||||
const params = this.getParams();
|
const params = this.getParams();
|
||||||
Object.keys(params).map((key) => {
|
Object.keys(params).map((key) => {
|
||||||
if (base_url.indexOf(':'+key) !== -1) {
|
if (ret.indexOf(':'+key) !== -1) {
|
||||||
base_url = base_url.replace(':'+key, params[key]);
|
ret = ret.replace(':'+key, params[key]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return base_url;
|
return ret;
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
if (this.isMounted()) {
|
if (this.isMounted()) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
define('modal', ['mailpoet', 'jquery'],
|
define('modal', ['mailpoet', 'jquery'],
|
||||||
function(MailPoet, jQuery) {
|
function(mp, jQuery) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var MailPoet = mp;
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
MailPoet Modal:
|
MailPoet Modal:
|
||||||
|
|
||||||
@ -308,10 +309,11 @@ define('modal', ['mailpoet', 'jquery'],
|
|||||||
setDimensions: function() {
|
setDimensions: function() {
|
||||||
switch(this.options.type) {
|
switch(this.options.type) {
|
||||||
case 'popup':
|
case 'popup':
|
||||||
|
console.log(this.options)
|
||||||
// set popup dimensions
|
// set popup dimensions
|
||||||
jQuery('#mailpoet_popup').css({
|
jQuery('#mailpoet_popup').css({
|
||||||
width: this.options.width,
|
width: this.options.width,
|
||||||
minHeight: this.options.height
|
height: this.options.height
|
||||||
});
|
});
|
||||||
// set popup wrapper height
|
// set popup wrapper height
|
||||||
jQuery('#mailpoet_popup_wrapper').css({
|
jQuery('#mailpoet_popup_wrapper').css({
|
||||||
@ -458,9 +460,9 @@ define('modal', ['mailpoet', 'jquery'],
|
|||||||
jQuery('#mailpoet_modal_overlay').hide();
|
jQuery('#mailpoet_modal_overlay').hide();
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
popup: function(options) {
|
popup: function(opts) {
|
||||||
// get options
|
// get options
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
// set modal type
|
// set modal type
|
||||||
options.type = 'popup';
|
options.type = 'popup';
|
||||||
// set overlay state
|
// set overlay state
|
||||||
@ -472,9 +474,9 @@ define('modal', ['mailpoet', 'jquery'],
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
panel: function(options) {
|
panel: function(opts) {
|
||||||
// get options
|
// get options
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
// reset subpanels
|
// reset subpanels
|
||||||
this.subpanels = [];
|
this.subpanels = [];
|
||||||
// set modal type
|
// set modal type
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
define('mp2migrator', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var MailPoet = mp;
|
||||||
MailPoet.MP2Migrator = {
|
MailPoet.MP2Migrator = {
|
||||||
|
|
||||||
fatal_error: '',
|
fatal_error: '',
|
||||||
@ -28,7 +29,8 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
cache: false
|
cache: false
|
||||||
}).done(function (result) {
|
}).done(function (result) {
|
||||||
jQuery("#logger").html('');
|
jQuery("#logger").html('');
|
||||||
result.split("\n").forEach(function (row) {
|
result.split("\n").forEach(function (resultRow) {
|
||||||
|
var row = resultRow;
|
||||||
if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
|
if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
|
||||||
row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
|
row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@ define([
|
|||||||
'underscore',
|
'underscore',
|
||||||
'handlebars',
|
'handlebars',
|
||||||
'handlebars_helpers'
|
'handlebars_helpers'
|
||||||
], function(Backbone, Marionette, Radio, jQuery, _, Handlebars) {
|
], function(Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
|
||||||
|
var Radio = BackboneRadio;
|
||||||
|
|
||||||
var AppView = Marionette.View.extend({
|
var AppView = Marionette.View.extend({
|
||||||
el: '#mailpoet_editor',
|
el: '#mailpoet_editor',
|
||||||
@ -28,7 +29,9 @@ define([
|
|||||||
},
|
},
|
||||||
|
|
||||||
getChannel: function(channel) {
|
getChannel: function(channel) {
|
||||||
if (channel === undefined) channel = 'global';
|
if (channel === undefined) {
|
||||||
|
return Radio.channel('global');
|
||||||
|
}
|
||||||
return Radio.channel(channel);
|
return Radio.channel(channel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
define([
|
define([
|
||||||
'backbone.marionette'
|
'backbone.marionette'
|
||||||
], function(Marionette) {
|
], function(BackboneMarionette) {
|
||||||
|
var Marionette = BackboneMarionette;
|
||||||
var BehaviorsLookup = {};
|
var BehaviorsLookup = {};
|
||||||
Marionette.Behaviors.behaviorsLookup = function() {
|
Marionette.Behaviors.behaviorsLookup = function() {
|
||||||
return BehaviorsLookup;
|
return BehaviorsLookup;
|
||||||
|
@ -9,8 +9,9 @@ define([
|
|||||||
'mailpoet',
|
'mailpoet',
|
||||||
'spectrum'
|
'spectrum'
|
||||||
], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) {
|
], function(Marionette, BehaviorsLookup, MailPoet, Spectrum) {
|
||||||
|
var BL = BehaviorsLookup;
|
||||||
|
|
||||||
BehaviorsLookup.ColorPickerBehavior = Marionette.Behavior.extend({
|
BL.ColorPickerBehavior = Marionette.Behavior.extend({
|
||||||
onRender: function() {
|
onRender: function() {
|
||||||
this.view.$('.mailpoet_color').spectrum({
|
this.view.$('.mailpoet_color').spectrum({
|
||||||
clickoutFiresChange: true,
|
clickoutFiresChange: true,
|
||||||
|
@ -11,7 +11,8 @@ define([
|
|||||||
'jquery',
|
'jquery',
|
||||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||||
'interact'
|
'interact'
|
||||||
], function(Marionette, _, jQuery, BehaviorsLookup, interact) {
|
], function(Marionette, _, jQuery, BL, interact) {
|
||||||
|
var BehaviorsLookup = BL;
|
||||||
|
|
||||||
BehaviorsLookup.ContainerDropZoneBehavior = Marionette.Behavior.extend({
|
BehaviorsLookup.ContainerDropZoneBehavior = Marionette.Behavior.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
@ -268,7 +269,7 @@ define([
|
|||||||
// 2. Remove visual markings of drop position visualization
|
// 2. Remove visual markings of drop position visualization
|
||||||
this.view.$('.mailpoet_drop_marker').remove();
|
this.view.$('.mailpoet_drop_marker').remove();
|
||||||
},
|
},
|
||||||
getDropPosition: function(eventX, eventY, unsafe) {
|
getDropPosition: function(eventX, eventY, is_unsafe) {
|
||||||
var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3
|
var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3
|
||||||
|
|
||||||
element = this.view.$el,
|
element = this.view.$el,
|
||||||
@ -290,7 +291,7 @@ define([
|
|||||||
|
|
||||||
insertionType, index, position, indexAndPosition;
|
insertionType, index, position, indexAndPosition;
|
||||||
|
|
||||||
unsafe = !!unsafe;
|
unsafe = !!is_unsafe;
|
||||||
|
|
||||||
if (this.getCollection().length === 0) {
|
if (this.getCollection().length === 0) {
|
||||||
return {
|
return {
|
||||||
|
@ -11,8 +11,9 @@ define([
|
|||||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||||
'interact'
|
'interact'
|
||||||
], function(Marionette, _, jQuery, BehaviorsLookup, interact) {
|
], function(Marionette, _, jQuery, BehaviorsLookup, interact) {
|
||||||
|
var BL = BehaviorsLookup;
|
||||||
|
|
||||||
BehaviorsLookup.DraggableBehavior = Marionette.Behavior.extend({
|
BL.DraggableBehavior = Marionette.Behavior.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
cloneOriginal: false,
|
cloneOriginal: false,
|
||||||
hideOriginal: false,
|
hideOriginal: false,
|
||||||
@ -46,7 +47,8 @@ define([
|
|||||||
// Scroll when dragging near edges of a window
|
// Scroll when dragging near edges of a window
|
||||||
autoScroll: true,
|
autoScroll: true,
|
||||||
|
|
||||||
onstart: function(event) {
|
onstart: function(startEvent) {
|
||||||
|
var event = startEvent;
|
||||||
|
|
||||||
if (that.options.cloneOriginal === true) {
|
if (that.options.cloneOriginal === true) {
|
||||||
// Use substitution instead of a clone
|
// Use substitution instead of a clone
|
||||||
@ -89,9 +91,8 @@ define([
|
|||||||
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
|
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
|
||||||
|
|
||||||
// translate the element
|
// translate the element
|
||||||
target.style.webkitTransform =
|
target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
|
||||||
target.style.transform =
|
target.style.webkitTransform = target.style.transform;
|
||||||
'translate(' + x + 'px, ' + y + 'px)';
|
|
||||||
|
|
||||||
// update the posiion attributes
|
// update the posiion attributes
|
||||||
target.setAttribute('data-x', x);
|
target.setAttribute('data-x', x);
|
||||||
@ -99,7 +100,8 @@ define([
|
|||||||
},
|
},
|
||||||
onend: function (event) {
|
onend: function (event) {
|
||||||
var target = event.target;
|
var target = event.target;
|
||||||
target.style.webkitTransform = target.style.transform = '';
|
target.style.transform = '';
|
||||||
|
target.style.webkitTransform = target.style.transform;
|
||||||
target.removeAttribute('data-x');
|
target.removeAttribute('data-x');
|
||||||
target.removeAttribute('data-y');
|
target.removeAttribute('data-y');
|
||||||
jQuery(event.interaction.element).addClass('mailpoet_droppable_active');
|
jQuery(event.interaction.element).addClass('mailpoet_droppable_active');
|
||||||
@ -129,7 +131,8 @@ define([
|
|||||||
} else {
|
} else {
|
||||||
interactable.getDropModel = this.view.getDropFunc();
|
interactable.getDropModel = this.view.getDropFunc();
|
||||||
}
|
}
|
||||||
interactable.onDrop = function(options) {
|
interactable.onDrop = function(opts) {
|
||||||
|
var options = opts;
|
||||||
if (_.isObject(options)) {
|
if (_.isObject(options)) {
|
||||||
// Inject Draggable behavior if possible
|
// Inject Draggable behavior if possible
|
||||||
options.dragBehavior = that;
|
options.dragBehavior = that;
|
||||||
|
@ -7,8 +7,9 @@ define([
|
|||||||
'backbone.marionette',
|
'backbone.marionette',
|
||||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||||
], function(Marionette, BehaviorsLookup) {
|
], function(Marionette, BehaviorsLookup) {
|
||||||
|
var BL = BehaviorsLookup;
|
||||||
|
|
||||||
BehaviorsLookup.HighlightEditingBehavior = Marionette.Behavior.extend({
|
BL.HighlightEditingBehavior = Marionette.Behavior.extend({
|
||||||
modelEvents: {
|
modelEvents: {
|
||||||
'startEditing': 'enableHighlight',
|
'startEditing': 'enableHighlight',
|
||||||
'stopEditing': 'disableHighlight'
|
'stopEditing': 'disableHighlight'
|
||||||
|
@ -8,8 +8,9 @@ define([
|
|||||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||||
'interact'
|
'interact'
|
||||||
], function(Marionette, BehaviorsLookup, interact) {
|
], function(Marionette, BehaviorsLookup, interact) {
|
||||||
|
var BL = BehaviorsLookup;
|
||||||
|
|
||||||
BehaviorsLookup.ResizableBehavior = Marionette.Behavior.extend({
|
BL.ResizableBehavior = Marionette.Behavior.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
elementSelector: null,
|
elementSelector: null,
|
||||||
resizeHandleSelector: true, // true will use edges of the element itself
|
resizeHandleSelector: true, // true will use edges of the element itself
|
||||||
|
@ -8,8 +8,9 @@ define([
|
|||||||
'jquery',
|
'jquery',
|
||||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||||
], function(Marionette, jQuery, BehaviorsLookup) {
|
], function(Marionette, jQuery, BehaviorsLookup) {
|
||||||
|
var BL = BehaviorsLookup;
|
||||||
|
|
||||||
BehaviorsLookup.ShowSettingsBehavior = Marionette.Behavior.extend({
|
BL.ShowSettingsBehavior = Marionette.Behavior.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
ignoreFrom: '' // selector
|
ignoreFrom: '' // selector
|
||||||
},
|
},
|
||||||
|
@ -8,8 +8,9 @@ define([
|
|||||||
'underscore',
|
'underscore',
|
||||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||||
], function(Marionette, _, BehaviorsLookup) {
|
], function(Marionette, _, BehaviorsLookup) {
|
||||||
|
var BL = BehaviorsLookup;
|
||||||
|
|
||||||
BehaviorsLookup.SortableBehavior = Marionette.Behavior.extend({
|
BL.SortableBehavior = Marionette.Behavior.extend({
|
||||||
onRender: function() {
|
onRender: function() {
|
||||||
var collection = this.view.collection;
|
var collection = this.view.collection;
|
||||||
|
|
||||||
|
@ -8,8 +8,9 @@ define([
|
|||||||
'underscore',
|
'underscore',
|
||||||
'newsletter_editor/behaviors/BehaviorsLookup'
|
'newsletter_editor/behaviors/BehaviorsLookup'
|
||||||
], function(Marionette, _, BehaviorsLookup) {
|
], function(Marionette, _, BehaviorsLookup) {
|
||||||
|
var BL = BehaviorsLookup;
|
||||||
|
|
||||||
BehaviorsLookup.TextEditorBehavior = Marionette.Behavior.extend({
|
BL.TextEditorBehavior = Marionette.Behavior.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
selector: '.mailpoet_content',
|
selector: '.mailpoet_content',
|
||||||
toolbar1: "bold italic link unlink forecolor mailpoet_shortcodes",
|
toolbar1: "bold italic link unlink forecolor mailpoet_shortcodes",
|
||||||
|
@ -392,8 +392,9 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
App.on('start', function(App, options) {
|
App.on('start', function(App, options) {
|
||||||
App._ALCSupervisor = new Module.ALCSupervisor();
|
var Application = App;
|
||||||
App._ALCSupervisor.refresh();
|
Application._ALCSupervisor = new Module.ALCSupervisor();
|
||||||
|
Application._ALCSupervisor.refresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
return Module;
|
return Module;
|
||||||
|
@ -194,8 +194,8 @@ define([
|
|||||||
move: true
|
move: true
|
||||||
},
|
},
|
||||||
getSettingsView: function() { return Module.BlockSettingsView; },
|
getSettingsView: function() { return Module.BlockSettingsView; },
|
||||||
initialize: function(options) {
|
initialize: function(opts) {
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
if (!_.isUndefined(options.tools)) {
|
if (!_.isUndefined(options.tools)) {
|
||||||
// Make a new block specific tool config object
|
// Make a new block specific tool config object
|
||||||
this.tools = jQuery.extend({}, this.tools, options.tools || {});
|
this.tools = jQuery.extend({}, this.tools, options.tools || {});
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
define([
|
define([
|
||||||
'newsletter_editor/App',
|
'newsletter_editor/App',
|
||||||
'newsletter_editor/blocks/base',
|
'newsletter_editor/blocks/base',
|
||||||
'underscore'
|
'underscore',
|
||||||
], function(App, BaseBlock, _) {
|
'mailpoet'
|
||||||
|
], function(App, BaseBlock, _, MailPoet) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -61,6 +62,16 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
Module.ImageBlockSettingsView = base.BlockSettingsView.extend({
|
Module.ImageBlockSettingsView = base.BlockSettingsView.extend({
|
||||||
|
onRender: function() {
|
||||||
|
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-full-width'), {
|
||||||
|
tooltipId: 'tooltip-editor-full-width',
|
||||||
|
tooltip: MailPoet.I18n.t('helpTooltipDesignerFullWidth')
|
||||||
|
});
|
||||||
|
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-ideal-width'), {
|
||||||
|
tooltipId: 'tooltip-editor-ideal-width',
|
||||||
|
tooltip: MailPoet.I18n.t('helpTooltipDesignerIdealWidth')
|
||||||
|
});
|
||||||
|
},
|
||||||
getTemplate: function() { return templates.imageBlockSettings; },
|
getTemplate: function() { return templates.imageBlockSettings; },
|
||||||
events: function() {
|
events: function() {
|
||||||
return {
|
return {
|
||||||
@ -266,7 +277,8 @@ define([
|
|||||||
},
|
},
|
||||||
|
|
||||||
mainEmbedToolbar: function(toolbar) {
|
mainEmbedToolbar: function(toolbar) {
|
||||||
toolbar.view = new wp.media.view.Toolbar.Embed({
|
var tbar = toolbar;
|
||||||
|
tbar.view = new wp.media.view.Toolbar.Embed({
|
||||||
controller: this,
|
controller: this,
|
||||||
text: 'Add images'
|
text: 'Add images'
|
||||||
});
|
});
|
||||||
@ -274,7 +286,7 @@ define([
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var theFrame = this._mediaManager = new MediaManager({
|
var theFrame = new MediaManager({
|
||||||
id: 'mailpoet-media-manager',
|
id: 'mailpoet-media-manager',
|
||||||
frame: 'select',
|
frame: 'select',
|
||||||
title: 'Select image',
|
title: 'Select image',
|
||||||
@ -289,6 +301,7 @@ define([
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
that = this;
|
that = this;
|
||||||
|
this._mediaManager = theFrame;
|
||||||
|
|
||||||
this._mediaManager.on('insert', function() {
|
this._mediaManager.on('insert', function() {
|
||||||
// Append media manager image selections to Images tab
|
// Append media manager image selections to Images tab
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
}
|
}
|
||||||
}(this, function(Marionette, Radio, _) {
|
}(this, function(Marionette, Radio, _) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var MarionetteApplication = Marionette.Application;
|
||||||
Marionette.Application.prototype._initChannel = function () {
|
MarionetteApplication.prototype._initChannel = function () {
|
||||||
this.channelName = _.result(this, 'channelName') || 'global';
|
this.channelName = _.result(this, 'channelName') || 'global';
|
||||||
this.channel = _.result(this, 'channel') || Radio.channel(this.channelName);
|
this.channel = _.result(this, 'channel') || Radio.channel(this.channelName);
|
||||||
};
|
};
|
||||||
|
@ -25,11 +25,12 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
App.on('before:start', function(App, options) {
|
App.on('before:start', function(App, options) {
|
||||||
|
var Application = App;
|
||||||
// Expose config methods globally
|
// Expose config methods globally
|
||||||
App.getConfig = Module.getConfig;
|
Application.getConfig = Module.getConfig;
|
||||||
App.setConfig = Module.setConfig;
|
Application.setConfig = Module.setConfig;
|
||||||
|
|
||||||
App.setConfig(options.config);
|
Application.setConfig(options.config);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Module;
|
return Module;
|
||||||
|
@ -67,7 +67,8 @@ define([
|
|||||||
return _.filter(blocks, predicate);
|
return _.filter(blocks, predicate);
|
||||||
};
|
};
|
||||||
|
|
||||||
App.on('before:start', function(App, options) {
|
App.on('before:start', function(Application, options) {
|
||||||
|
var App = Application;
|
||||||
// Expose block methods globally
|
// Expose block methods globally
|
||||||
App.registerBlockType = Module.registerBlockType;
|
App.registerBlockType = Module.registerBlockType;
|
||||||
App.getBlockTypeModel = Module.getBlockTypeModel;
|
App.getBlockTypeModel = Module.getBlockTypeModel;
|
||||||
@ -80,7 +81,8 @@ define([
|
|||||||
Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body']));
|
Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body']));
|
||||||
});
|
});
|
||||||
|
|
||||||
App.on('start', function(App, options) {
|
App.on('start', function(Application, options) {
|
||||||
|
var App = Application;
|
||||||
var body = options.newsletter.body;
|
var body = options.newsletter.body;
|
||||||
var content = (_.has(body, 'content')) ? body.content : {};
|
var content = (_.has(body, 'content')) ? body.content : {};
|
||||||
|
|
||||||
|
@ -30,6 +30,15 @@ define([
|
|||||||
|
|
||||||
App.on('start', function(App, options) {
|
App.on('start', function(App, options) {
|
||||||
App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() }));
|
App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() }));
|
||||||
|
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-subject-line'), {
|
||||||
|
tooltipId: 'tooltip-designer-subject-line-ti',
|
||||||
|
tooltip: MailPoet.I18n.t('helpTooltipDesignerSubjectLine'),
|
||||||
|
place: "right"
|
||||||
|
});
|
||||||
|
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-preheader'), {
|
||||||
|
tooltipId: 'tooltip-designer-preheader-ti',
|
||||||
|
tooltip: MailPoet.I18n.t('helpTooltipDesignerPreheader')
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Module;
|
return Module;
|
||||||
|
@ -67,9 +67,10 @@ define([
|
|||||||
|
|
||||||
// For getting a promise after triggering save event
|
// For getting a promise after triggering save event
|
||||||
Module.saveAndProvidePromise = function(saveResult) {
|
Module.saveAndProvidePromise = function(saveResult) {
|
||||||
|
var result = saveResult;
|
||||||
var promise = Module.save();
|
var promise = Module.save();
|
||||||
if (saveResult !== undefined) {
|
if (saveResult !== undefined) {
|
||||||
saveResult.promise = promise;
|
result.promise = promise;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,6 +141,9 @@ define([
|
|||||||
);
|
);
|
||||||
|
|
||||||
FileSaver.saveAs(blob, 'template.json');
|
FileSaver.saveAs(blob, 'template.json');
|
||||||
|
MailPoet.trackEvent('Editor > Template exported', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -225,6 +229,9 @@ define([
|
|||||||
scroll: true
|
scroll: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
MailPoet.trackEvent('Editor > Template saved', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version
|
||||||
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
MailPoet.I18n.t('templateSaveFailed'),
|
MailPoet.I18n.t('templateSaveFailed'),
|
||||||
@ -331,10 +338,10 @@ define([
|
|||||||
Module.beforeExitWithUnsavedChanges = function(e) {
|
Module.beforeExitWithUnsavedChanges = function(e) {
|
||||||
if (saveTimeout) {
|
if (saveTimeout) {
|
||||||
var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
|
var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
|
||||||
e = e || window.event;
|
var event = e || window.event;
|
||||||
|
|
||||||
if (e) {
|
if (event) {
|
||||||
e.returnValue = message;
|
event.returnValue = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
@ -342,12 +349,13 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
App.on('before:start', function(App, options) {
|
App.on('before:start', function(App, options) {
|
||||||
App.save = Module.saveAndProvidePromise;
|
var Application = App;
|
||||||
App.getChannel().on('autoSave', Module.autoSave);
|
Application.save = Module.saveAndProvidePromise;
|
||||||
|
Application.getChannel().on('autoSave', Module.autoSave);
|
||||||
|
|
||||||
window.onbeforeunload = Module.beforeExitWithUnsavedChanges;
|
window.onbeforeunload = Module.beforeExitWithUnsavedChanges;
|
||||||
|
|
||||||
App.getChannel().on('save', function(saveResult) { App.save(saveResult); });
|
Application.getChannel().on('save', function(saveResult) { Application.save(saveResult); });
|
||||||
});
|
});
|
||||||
|
|
||||||
App.on('start', function(App, options) {
|
App.on('start', function(App, options) {
|
||||||
|
@ -272,16 +272,23 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
var view = this.previewView.render();
|
var view = this.previewView.render();
|
||||||
|
this.previewView.$el.css('height', '100%');
|
||||||
|
|
||||||
MailPoet.Modal.popup({
|
MailPoet.Modal.popup({
|
||||||
template: '',
|
template: '',
|
||||||
element: this.previewView.$el,
|
element: this.previewView.$el,
|
||||||
|
width: '95%',
|
||||||
|
height: '94%',
|
||||||
title: MailPoet.I18n.t('newsletterPreview'),
|
title: MailPoet.I18n.t('newsletterPreview'),
|
||||||
onCancel: function() {
|
onCancel: function() {
|
||||||
this.previewView.destroy();
|
this.previewView.destroy();
|
||||||
this.previewView = null;
|
this.previewView = null;
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MailPoet.trackEvent('Editor > Browser Preview', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version
|
||||||
|
});
|
||||||
}.bind(this)).fail(function(response) {
|
}.bind(this)).fail(function(response) {
|
||||||
if (response.errors.length > 0) {
|
if (response.errors.length > 0) {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
@ -323,7 +330,12 @@ define([
|
|||||||
}).done(function(response) {
|
}).done(function(response) {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
MailPoet.I18n.t('newsletterPreviewSent'),
|
MailPoet.I18n.t('newsletterPreviewSent'),
|
||||||
{ scroll: true });
|
{ scroll: true }
|
||||||
|
);
|
||||||
|
MailPoet.trackEvent('Editor > Preview sent', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
'Domain name': data.subscriber.substring(data.subscriber.indexOf('@') + 1)
|
||||||
|
});
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
if (response.errors.length > 0) {
|
if (response.errors.length > 0) {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
@ -340,8 +352,10 @@ define([
|
|||||||
getTemplate: function() { return templates.newsletterPreview; },
|
getTemplate: function() { return templates.newsletterPreview; },
|
||||||
initialize: function(options) {
|
initialize: function(options) {
|
||||||
this.previewUrl = options.previewUrl;
|
this.previewUrl = options.previewUrl;
|
||||||
this.width = App.getConfig().get('newsletterPreview.width');
|
this.width = '100%';
|
||||||
this.height = App.getConfig().get('newsletterPreview.height')
|
this.height = '100%';
|
||||||
|
// this.width = App.getConfig().get('newsletterPreview.width');
|
||||||
|
// this.height = App.getConfig().get('newsletterPreview.height')
|
||||||
},
|
},
|
||||||
templateContext: function() {
|
templateContext: function() {
|
||||||
return {
|
return {
|
||||||
@ -353,10 +367,11 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
App.on('before:start', function(App, options) {
|
App.on('before:start', function(App, options) {
|
||||||
App.registerWidget = Module.registerWidget;
|
var Application = App;
|
||||||
App.getWidgets = Module.getWidgets;
|
Application.registerWidget = Module.registerWidget;
|
||||||
App.registerLayoutWidget = Module.registerLayoutWidget;
|
Application.getWidgets = Module.getWidgets;
|
||||||
App.getLayoutWidgets = Module.getLayoutWidgets;
|
Application.registerLayoutWidget = Module.registerLayoutWidget;
|
||||||
|
Application.getLayoutWidgets = Module.getLayoutWidgets;
|
||||||
});
|
});
|
||||||
|
|
||||||
App.on('start', function(App, options) {
|
App.on('start', function(App, options) {
|
||||||
@ -364,6 +379,16 @@ define([
|
|||||||
sidebarView = new SidebarView();
|
sidebarView = new SidebarView();
|
||||||
|
|
||||||
App._appView.showChildView('sidebarRegion', sidebarView);
|
App._appView.showChildView('sidebarRegion', sidebarView);
|
||||||
|
|
||||||
|
MailPoet.helpTooltip.show(document.getElementById('tooltip-send-preview'), {
|
||||||
|
tooltipId: 'tooltip-editor-send-preview',
|
||||||
|
tooltip: MailPoet.I18n.t('helpTooltipSendPreview')
|
||||||
|
});
|
||||||
|
|
||||||
|
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-styles'), {
|
||||||
|
tooltipId: 'tooltip-editor-designer-styles',
|
||||||
|
tooltip: MailPoet.I18n.t('helpTooltipDesignerStyles')
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Module;
|
return Module;
|
||||||
|
@ -69,10 +69,11 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
App.on('before:start', function(App, options) {
|
App.on('before:start', function(App, options) {
|
||||||
|
var Application = App;
|
||||||
// Expose style methods to global application
|
// Expose style methods to global application
|
||||||
App.getGlobalStyles = Module.getGlobalStyles;
|
Application.getGlobalStyles = Module.getGlobalStyles;
|
||||||
App.setGlobalStyles = Module.setGlobalStyles;
|
Application.setGlobalStyles = Module.setGlobalStyles;
|
||||||
App.getAvailableStyles = Module.getAvailableStyles;
|
Application.getAvailableStyles = Module.getAvailableStyles;
|
||||||
|
|
||||||
var body = options.newsletter.body;
|
var body = options.newsletter.body;
|
||||||
var globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};
|
var globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};
|
||||||
|
@ -145,13 +145,14 @@ const _QueueMixin = {
|
|||||||
|
|
||||||
const _StatisticsMixin = {
|
const _StatisticsMixin = {
|
||||||
renderStatistics: function (newsletter, is_sent, current_time) {
|
renderStatistics: function (newsletter, is_sent, current_time) {
|
||||||
if (is_sent === undefined) {
|
let sent = is_sent;
|
||||||
|
if (sent === undefined) {
|
||||||
// condition for standard and post notification listings
|
// condition for standard and post notification listings
|
||||||
is_sent = newsletter.statistics
|
sent = newsletter.statistics
|
||||||
&& newsletter.queue
|
&& newsletter.queue
|
||||||
&& newsletter.queue.status !== 'scheduled';
|
&& newsletter.queue.status !== 'scheduled';
|
||||||
}
|
}
|
||||||
if (!is_sent) {
|
if (!sent) {
|
||||||
return (
|
return (
|
||||||
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
||||||
);
|
);
|
||||||
|
@ -97,6 +97,17 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const confirmEdit = (newsletter) => {
|
||||||
|
if(
|
||||||
|
!newsletter.queue
|
||||||
|
|| newsletter.status != 'sending'
|
||||||
|
|| newsletter.queue.status !== null
|
||||||
|
|| window.confirm(MailPoet.I18n.t('confirmEdit'))
|
||||||
|
) {
|
||||||
|
window.location.href = `?page=mailpoet-newsletter-editor&id=${ newsletter.id }`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let newsletter_actions = [
|
let newsletter_actions = [
|
||||||
{
|
{
|
||||||
name: 'view',
|
name: 'view',
|
||||||
@ -110,13 +121,8 @@ let newsletter_actions = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
link: function (newsletter) {
|
label: MailPoet.I18n.t('edit'),
|
||||||
return (
|
onClick: confirmEdit,
|
||||||
<a href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }>
|
|
||||||
{MailPoet.I18n.t('edit')}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'duplicate',
|
name: 'duplicate',
|
||||||
@ -172,7 +178,8 @@ const NewsletterListStandard = React.createClass({
|
|||||||
<strong>
|
<strong>
|
||||||
<a
|
<a
|
||||||
className="row-title"
|
className="row-title"
|
||||||
href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }
|
href="javascript:;"
|
||||||
|
onClick={() => confirmEdit(newsletter)}
|
||||||
>{ newsletter.queue.newsletter_rendered_subject || newsletter.subject }</a>
|
>{ newsletter.queue.newsletter_rendered_subject || newsletter.subject }</a>
|
||||||
</strong>
|
</strong>
|
||||||
{ actions }
|
{ actions }
|
||||||
@ -198,7 +205,14 @@ const NewsletterListStandard = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className="title">
|
<h1 className="title">
|
||||||
{MailPoet.I18n.t('pageTitle')} <Link className="page-title-action" to="/new">{MailPoet.I18n.t('new')}</Link>
|
{MailPoet.I18n.t('pageTitle')}
|
||||||
|
<Link className="page-title-action" to="/new"
|
||||||
|
onClick={() => MailPoet.trackEvent('Emails > Add New',
|
||||||
|
{ 'MailPoet Free version': window.mailpoet_version }
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{MailPoet.I18n.t('new')}
|
||||||
|
</Link>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<ListingTabs tab="standard" />
|
<ListingTabs tab="standard" />
|
||||||
|
@ -38,6 +38,9 @@ const ListingTabs = React.createClass({
|
|||||||
key={ 'tab-'+index }
|
key={ 'tab-'+index }
|
||||||
className={ tabClasses }
|
className={ tabClasses }
|
||||||
to={ tab.link }
|
to={ tab.link }
|
||||||
|
onClick={() => MailPoet.trackEvent(`Tab Emails > ${tab.name} clicked`,
|
||||||
|
{ 'MailPoet Free version': window.mailpoet_version }
|
||||||
|
)}
|
||||||
>{ tab.label }</Link>
|
>{ tab.label }</Link>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -9,6 +9,7 @@ define(
|
|||||||
'newsletters/send/notification.jsx',
|
'newsletters/send/notification.jsx',
|
||||||
'newsletters/send/welcome.jsx',
|
'newsletters/send/welcome.jsx',
|
||||||
'newsletters/breadcrumb.jsx',
|
'newsletters/breadcrumb.jsx',
|
||||||
|
'help-tooltip.jsx',
|
||||||
],
|
],
|
||||||
(
|
(
|
||||||
React,
|
React,
|
||||||
@ -19,7 +20,8 @@ define(
|
|||||||
StandardNewsletterFields,
|
StandardNewsletterFields,
|
||||||
NotificationNewsletterFields,
|
NotificationNewsletterFields,
|
||||||
WelcomeNewsletterFields,
|
WelcomeNewsletterFields,
|
||||||
Breadcrumb
|
Breadcrumb,
|
||||||
|
HelpTooltip
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const NewsletterSend = React.createClass({
|
const NewsletterSend = React.createClass({
|
||||||
@ -108,16 +110,25 @@ define(
|
|||||||
}).done((response) => {
|
}).done((response) => {
|
||||||
// redirect to listing based on newsletter type
|
// redirect to listing based on newsletter type
|
||||||
this.context.router.push(`/${ this.state.item.type || '' }`);
|
this.context.router.push(`/${ this.state.item.type || '' }`);
|
||||||
|
const opts = this.state.item.options;
|
||||||
// display success message depending on newsletter type
|
// display success message depending on newsletter type
|
||||||
if (response.data.type === 'welcome') {
|
if (response.data.type === 'welcome') {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
MailPoet.I18n.t('welcomeEmailActivated')
|
MailPoet.I18n.t('welcomeEmailActivated')
|
||||||
);
|
);
|
||||||
|
MailPoet.trackEvent('Emails > Welcome email activated', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
'List type': opts.event,
|
||||||
|
'Delay': opts.afterTimeNumber + ' ' + opts.afterTimeType,
|
||||||
|
});
|
||||||
} else if (response.data.type === 'notification') {
|
} else if (response.data.type === 'notification') {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
MailPoet.I18n.t('postNotificationActivated')
|
MailPoet.I18n.t('postNotificationActivated')
|
||||||
);
|
);
|
||||||
|
MailPoet.trackEvent('Emails > Post notifications activated', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
'Frequency': opts.intervalType,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}).fail(this._showError);
|
}).fail(this._showError);
|
||||||
default:
|
default:
|
||||||
@ -136,10 +147,18 @@ define(
|
|||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
MailPoet.I18n.t('newsletterHasBeenScheduled')
|
MailPoet.I18n.t('newsletterHasBeenScheduled')
|
||||||
);
|
);
|
||||||
|
MailPoet.trackEvent('Emails > Newsletter sent', {
|
||||||
|
scheduled: true,
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
MailPoet.Notice.success(
|
MailPoet.Notice.success(
|
||||||
MailPoet.I18n.t('newsletterBeingSent')
|
MailPoet.I18n.t('newsletterBeingSent')
|
||||||
);
|
);
|
||||||
|
MailPoet.trackEvent('Emails > Newsletter sent', {
|
||||||
|
scheduled: false,
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}).fail(this._showError);
|
}).fail(this._showError);
|
||||||
}
|
}
|
||||||
@ -149,6 +168,40 @@ define(
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
handleResume: function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!this.isValid()) {
|
||||||
|
jQuery('#mailpoet_newsletter').parsley().validate();
|
||||||
|
} else {
|
||||||
|
this._save(e).done(() => {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
}).done(() => {
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
api_version: window.mailpoet_api_version,
|
||||||
|
endpoint: 'sendingQueue',
|
||||||
|
action: 'resume',
|
||||||
|
data: {
|
||||||
|
newsletter_id: this.state.item.id,
|
||||||
|
},
|
||||||
|
}).done(() => {
|
||||||
|
this.context.router.push(`/${ this.state.item.type || '' }`);
|
||||||
|
MailPoet.Notice.success(
|
||||||
|
MailPoet.I18n.t('newsletterSendingHasBeenResumed')
|
||||||
|
);
|
||||||
|
}).fail((response) => {
|
||||||
|
if (response.errors.length > 0) {
|
||||||
|
MailPoet.Notice.error(
|
||||||
|
response.errors.map((error) => { return error.message; }),
|
||||||
|
{ scroll: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).fail(this._showError).always(() => {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
handleSave: function (e) {
|
handleSave: function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -174,6 +227,7 @@ define(
|
|||||||
},
|
},
|
||||||
_save: function () {
|
_save: function () {
|
||||||
const data = this.state.item;
|
const data = this.state.item;
|
||||||
|
data.queue = undefined;
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
|
|
||||||
// Store only properties that can be changed on this page
|
// Store only properties that can be changed on this page
|
||||||
@ -215,6 +269,16 @@ define(
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
|
const isPaused = this.state.item.status == 'sending'
|
||||||
|
&& this.state.item.queue
|
||||||
|
&& this.state.item.queue.status == 'paused';
|
||||||
|
const fields = this.state.fields.map((field) => {
|
||||||
|
const newField = field;
|
||||||
|
if (field.name == 'segments' || field.name == 'options') {
|
||||||
|
newField.disabled = isPaused;
|
||||||
|
}
|
||||||
|
return newField;
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
|
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
|
||||||
@ -223,13 +287,21 @@ define(
|
|||||||
|
|
||||||
<Form
|
<Form
|
||||||
id="mailpoet_newsletter"
|
id="mailpoet_newsletter"
|
||||||
fields={ this.state.fields }
|
fields={ fields }
|
||||||
item={ this.state.item }
|
item={ this.state.item }
|
||||||
loading={ this.state.loading }
|
loading={ this.state.loading }
|
||||||
onChange={this.handleFormChange}
|
onChange={this.handleFormChange}
|
||||||
onSubmit={this.handleSave}
|
onSubmit={this.handleSave}
|
||||||
>
|
>
|
||||||
<p className="submit">
|
<p className="submit">
|
||||||
|
{
|
||||||
|
isPaused ?
|
||||||
|
<input
|
||||||
|
className="button button-primary"
|
||||||
|
type="button"
|
||||||
|
onClick={ this.handleResume }
|
||||||
|
value={MailPoet.I18n.t('resume')} />
|
||||||
|
:
|
||||||
<input
|
<input
|
||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
type="button"
|
type="button"
|
||||||
@ -237,6 +309,7 @@ define(
|
|||||||
value={MailPoet.I18n.t('send')}
|
value={MailPoet.I18n.t('send')}
|
||||||
{...this.getSendButtonOptions()}
|
{...this.getSendButtonOptions()}
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
<input
|
<input
|
||||||
className="button button-secondary"
|
className="button button-secondary"
|
||||||
@ -251,6 +324,10 @@ define(
|
|||||||
{MailPoet.I18n.t('goBackToDesign')}
|
{MailPoet.I18n.t('goBackToDesign')}
|
||||||
</a>.
|
</a>.
|
||||||
</p>
|
</p>
|
||||||
|
<HelpTooltip
|
||||||
|
tooltip={MailPoet.I18n.t('helpTooltipSendEmail')}
|
||||||
|
tooltipId="helpTooltipSendEmail"
|
||||||
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -8,12 +8,14 @@ define(
|
|||||||
],
|
],
|
||||||
(
|
(
|
||||||
React,
|
React,
|
||||||
jQuery,
|
jq,
|
||||||
_,
|
_,
|
||||||
MailPoet,
|
MailPoet,
|
||||||
Hooks
|
Hooks
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
|
const jQuery = jq;
|
||||||
|
|
||||||
const currentTime = window.mailpoet_current_time || '00:00';
|
const currentTime = window.mailpoet_current_time || '00:00';
|
||||||
const defaultDateTime = window.mailpoet_current_date + ' ' + '00:00:00';
|
const defaultDateTime = window.mailpoet_current_date + ' ' + '00:00:00';
|
||||||
const timeOfDayItems = window.mailpoet_schedule_time_of_day;
|
const timeOfDayItems = window.mailpoet_schedule_time_of_day;
|
||||||
@ -84,12 +86,13 @@ define(
|
|||||||
|
|
||||||
const DateText = React.createClass({
|
const DateText = React.createClass({
|
||||||
onChange: function (event) {
|
onChange: function (event) {
|
||||||
|
const changeEvent = event;
|
||||||
// Swap display format to storage format
|
// Swap display format to storage format
|
||||||
const displayDate = event.target.value;
|
const displayDate = changeEvent.target.value;
|
||||||
const storageDate = this.getStorageDate(displayDate);
|
const storageDate = this.getStorageDate(displayDate);
|
||||||
|
|
||||||
event.target.value = storageDate;
|
changeEvent.target.value = storageDate;
|
||||||
this.props.onChange(event);
|
this.props.onChange(changeEvent);
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
const $element = jQuery(this.refs.dateInput);
|
const $element = jQuery(this.refs.dateInput);
|
||||||
@ -155,6 +158,7 @@ define(
|
|||||||
name={this.getFieldName()}
|
name={this.getFieldName()}
|
||||||
value={this.getDisplayDate(this.props.value)}
|
value={this.getDisplayDate(this.props.value)}
|
||||||
readOnly={ true }
|
readOnly={ true }
|
||||||
|
disabled={this.props.disabled}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
ref="dateInput"
|
ref="dateInput"
|
||||||
{...this.props.validation} />
|
{...this.props.validation} />
|
||||||
@ -180,6 +184,7 @@ define(
|
|||||||
<select
|
<select
|
||||||
name={this.props.name || 'time'}
|
name={this.props.name || 'time'}
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
|
disabled={this.props.disabled}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
{...this.props.validation}
|
{...this.props.validation}
|
||||||
>
|
>
|
||||||
@ -235,11 +240,13 @@ define(
|
|||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
displayFormat={dateDisplayFormat}
|
displayFormat={dateDisplayFormat}
|
||||||
storageFormat={dateStorageFormat}
|
storageFormat={dateStorageFormat}
|
||||||
|
disabled={this.props.disabled}
|
||||||
validation={this.props.dateValidation}/>
|
validation={this.props.dateValidation}/>
|
||||||
<TimeSelect
|
<TimeSelect
|
||||||
name="time"
|
name="time"
|
||||||
value={this.state.time}
|
value={this.state.time}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
disabled={this.props.disabled}
|
||||||
validation={this.props.timeValidation} />
|
validation={this.props.timeValidation} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
@ -269,8 +276,9 @@ define(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleCheckboxChange: function (event) {
|
handleCheckboxChange: function (event) {
|
||||||
event.target.value = this.refs.isScheduled.checked ? '1' : '0';
|
const changeEvent = event;
|
||||||
return this.handleValueChange(event);
|
changeEvent.target.value = this.refs.isScheduled.checked ? '1' : '0';
|
||||||
|
return this.handleValueChange(changeEvent);
|
||||||
},
|
},
|
||||||
isScheduled: function () {
|
isScheduled: function () {
|
||||||
return this._getCurrentValue().isScheduled === '1';
|
return this._getCurrentValue().isScheduled === '1';
|
||||||
@ -292,6 +300,7 @@ define(
|
|||||||
name="scheduledAt"
|
name="scheduledAt"
|
||||||
value={this._getCurrentValue().scheduledAt}
|
value={this._getCurrentValue().scheduledAt}
|
||||||
onChange={this.handleValueChange}
|
onChange={this.handleValueChange}
|
||||||
|
disabled={this.props.field.disabled}
|
||||||
dateValidation={this.getDateValidation()} />
|
dateValidation={this.getDateValidation()} />
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
@ -300,7 +309,6 @@ define(
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
@ -308,6 +316,7 @@ define(
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
value="1"
|
value="1"
|
||||||
checked={this.isScheduled()}
|
checked={this.isScheduled()}
|
||||||
|
disabled={this.props.field.disabled}
|
||||||
name="isScheduled"
|
name="isScheduled"
|
||||||
onChange={this.handleCheckboxChange} />
|
onChange={this.handleCheckboxChange} />
|
||||||
|
|
||||||
@ -414,11 +423,11 @@ define(
|
|||||||
return fields;
|
return fields;
|
||||||
},
|
},
|
||||||
getSendButtonOptions: function (newsletter) {
|
getSendButtonOptions: function (newsletter) {
|
||||||
newsletter = newsletter || {};
|
const newsletterOptions = newsletter || {};
|
||||||
|
|
||||||
const isScheduled = (
|
const isScheduled = (
|
||||||
typeof newsletter.options === 'object'
|
typeof newsletterOptions.options === 'object'
|
||||||
&& newsletter.options.isScheduled === '1'
|
&& newsletterOptions.options.isScheduled === '1'
|
||||||
);
|
);
|
||||||
const options = {
|
const options = {
|
||||||
value: (isScheduled
|
value: (isScheduled
|
||||||
@ -426,8 +435,8 @@ define(
|
|||||||
: MailPoet.I18n.t('send')),
|
: MailPoet.I18n.t('send')),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (newsletter.status === 'sent'
|
if (newsletterOptions.status === 'sent'
|
||||||
|| newsletter.status === 'sending') {
|
|| newsletterOptions.status === 'sending') {
|
||||||
options['disabled'] = 'disabled';
|
options['disabled'] = 'disabled';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ define(
|
|||||||
'react-router',
|
'react-router',
|
||||||
'classnames',
|
'classnames',
|
||||||
'newsletters/breadcrumb.jsx',
|
'newsletters/breadcrumb.jsx',
|
||||||
|
'help-tooltip.jsx',
|
||||||
],
|
],
|
||||||
(
|
(
|
||||||
React,
|
React,
|
||||||
@ -13,11 +14,13 @@ define(
|
|||||||
MailPoet,
|
MailPoet,
|
||||||
Router,
|
Router,
|
||||||
classNames,
|
classNames,
|
||||||
Breadcrumb
|
Breadcrumb,
|
||||||
|
HelpTooltip
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const ImportTemplate = React.createClass({
|
const ImportTemplate = React.createClass({
|
||||||
saveTemplate: function (template) {
|
saveTemplate: function (saveTemplate) {
|
||||||
|
const template = saveTemplate;
|
||||||
|
|
||||||
// Stringify to enable transmission of primitive non-string value types
|
// Stringify to enable transmission of primitive non-string value types
|
||||||
if (!_.isUndefined(template.body)) {
|
if (!_.isUndefined(template.body)) {
|
||||||
@ -49,6 +52,7 @@ define(
|
|||||||
|
|
||||||
if (_.size(this.refs.templateFile.files) <= 0) return false;
|
if (_.size(this.refs.templateFile.files) <= 0) return false;
|
||||||
|
|
||||||
|
|
||||||
const file = _.first(this.refs.templateFile.files);
|
const file = _.first(this.refs.templateFile.files);
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
const saveTemplate = this.saveTemplate;
|
const saveTemplate = this.saveTemplate;
|
||||||
@ -56,6 +60,9 @@ define(
|
|||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
try {
|
try {
|
||||||
saveTemplate(JSON.parse(e.target.result));
|
saveTemplate(JSON.parse(e.target.result));
|
||||||
|
MailPoet.trackEvent('Emails > Template imported', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
MailPoet.Notice.error(MailPoet.I18n.t('templateFileMalformedError'));
|
MailPoet.Notice.error(MailPoet.I18n.t('templateFileMalformedError'));
|
||||||
}
|
}
|
||||||
@ -66,10 +73,13 @@ define(
|
|||||||
render: function () {
|
render: function () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>{MailPoet.I18n.t('importTemplateTitle')}</h2>
|
<h2>{MailPoet.I18n.t('importTemplateTitle')} <HelpTooltip
|
||||||
|
tooltip={MailPoet.I18n.t('helpTooltipTemplateUpload')}
|
||||||
|
place="right"
|
||||||
|
className="tooltip-help-import-template"
|
||||||
|
/></h2>
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
<input type="file" placeholder={MailPoet.I18n.t('selectJsonFileToUpload')} ref="templateFile" />
|
<input type="file" placeholder={MailPoet.I18n.t('selectJsonFileToUpload')} ref="templateFile" />
|
||||||
|
|
||||||
<p className="submit">
|
<p className="submit">
|
||||||
<input
|
<input
|
||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
@ -138,6 +148,11 @@ define(
|
|||||||
body = JSON.stringify(body);
|
body = JSON.stringify(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MailPoet.trackEvent('Emails > Template selected', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
'Email name': template.name,
|
||||||
|
});
|
||||||
|
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
api_version: window.mailpoet_api_version,
|
api_version: window.mailpoet_api_version,
|
||||||
endpoint: 'newsletters',
|
endpoint: 'newsletters',
|
||||||
|
@ -20,9 +20,17 @@ define(
|
|||||||
setupNewsletter: function (type) {
|
setupNewsletter: function (type) {
|
||||||
if(type !== undefined) {
|
if(type !== undefined) {
|
||||||
this.context.router.push(`/new/${type}`);
|
this.context.router.push(`/new/${type}`);
|
||||||
|
MailPoet.trackEvent('Emails > Type selected', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
'Email type': type,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createNewsletter: function (type) {
|
createNewsletter: function (type) {
|
||||||
|
MailPoet.trackEvent('Emails > Type selected', {
|
||||||
|
'MailPoet Free version': window.mailpoet_version,
|
||||||
|
'Email type': type,
|
||||||
|
});
|
||||||
MailPoet.Ajax.post({
|
MailPoet.Ajax.post({
|
||||||
api_version: window.mailpoet_api_version,
|
api_version: window.mailpoet_api_version,
|
||||||
endpoint: 'newsletters',
|
endpoint: 'newsletters',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
|
||||||
"use strict";
|
"use strict";
|
||||||
/*==================================================================================================
|
/*==================================================================================================
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
MailPoet.Notice.system('You need to updated ASAP!');
|
MailPoet.Notice.system('You need to updated ASAP!');
|
||||||
|
|
||||||
==================================================================================================*/
|
==================================================================================================*/
|
||||||
|
var MailPoet = mp;
|
||||||
MailPoet.Notice = {
|
MailPoet.Notice = {
|
||||||
version: 1.0,
|
version: 1.0,
|
||||||
// default options
|
// default options
|
||||||
@ -103,12 +103,12 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
setMessage: function(message) {
|
setMessage: function(message) {
|
||||||
message = this.formatMessage(message);
|
var formattedMessage = this.formatMessage(message);
|
||||||
|
|
||||||
// let's sugar coat the message with a fancy <p>
|
// let's sugar coat the message with a fancy <p>
|
||||||
message = '<p>'+message+'</p>';
|
formattedMessage = '<p>'+formattedMessage+'</p>';
|
||||||
// set message
|
// set message
|
||||||
return this.element.html(message);
|
return this.element.html(formattedMessage);
|
||||||
},
|
},
|
||||||
formatMessage: function(message) {
|
formatMessage: function(message) {
|
||||||
if (Array.isArray(message)) {
|
if (Array.isArray(message)) {
|
||||||
|
@ -2,13 +2,14 @@ define('num',
|
|||||||
[
|
[
|
||||||
'mailpoet'
|
'mailpoet'
|
||||||
], function(
|
], function(
|
||||||
MailPoet
|
mp
|
||||||
) {
|
) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var MailPoet = mp;
|
||||||
MailPoet.Num = {
|
MailPoet.Num = {
|
||||||
toLocaleFixed: function (num, precision) {
|
toLocaleFixed: function (num, precisionOpts) {
|
||||||
precision = precision || 0;
|
var precision = precisionOpts || 0;
|
||||||
var factor = Math.pow(10, precision);
|
var factor = Math.pow(10, precision);
|
||||||
return (Math.round(num * factor) / factor)
|
return (Math.round(num * factor) / factor)
|
||||||
.toLocaleString(
|
.toLocaleString(
|
||||||
|
@ -7,8 +7,9 @@ define(
|
|||||||
function(
|
function(
|
||||||
Backbone,
|
Backbone,
|
||||||
jQuery,
|
jQuery,
|
||||||
MailPoet
|
mp
|
||||||
) {
|
) {
|
||||||
|
var MailPoet = mp;
|
||||||
if(jQuery('#mailpoet_settings').length === 0) {
|
if(jQuery('#mailpoet_settings').length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -50,9 +51,9 @@ define(
|
|||||||
jQuery('#mailpoet_sending_method_setup').fadeIn();
|
jQuery('#mailpoet_sending_method_setup').fadeIn();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tabs: function(tab, section) {
|
tabs: function(tabStr, section) {
|
||||||
// set default tab
|
// set default tab
|
||||||
tab = tab || 'mta';
|
var tab = tabStr || 'mta';
|
||||||
|
|
||||||
// reset all active tabs
|
// reset all active tabs
|
||||||
jQuery('.nav-tab-wrapper a').removeClass('nav-tab-active');
|
jQuery('.nav-tab-wrapper a').removeClass('nav-tab-active');
|
||||||
|
@ -52,8 +52,9 @@ define(
|
|||||||
router.on('route:step1', function () {
|
router.on('route:step1', function () {
|
||||||
// set or reset temporary validation rule on all columns
|
// set or reset temporary validation rule on all columns
|
||||||
mailpoetColumns = jQuery.map(mailpoetColumns, function (column, columnIndex) {
|
mailpoetColumns = jQuery.map(mailpoetColumns, function (column, columnIndex) {
|
||||||
column.validation_rule = false;
|
var col = column;
|
||||||
return column;
|
col.validation_rule = false;
|
||||||
|
return col;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof (importData.step1) !== 'undefined') {
|
if (typeof (importData.step1) !== 'undefined') {
|
||||||
@ -302,10 +303,10 @@ define(
|
|||||||
advancedOptionComments = false,
|
advancedOptionComments = false,
|
||||||
// trim spaces, commas, periods,
|
// trim spaces, commas, periods,
|
||||||
// single/double quotes and convert to lowercase
|
// single/double quotes and convert to lowercase
|
||||||
detectAndCleanupEmail = function (email) {
|
detectAndCleanupEmail = function (emailString) {
|
||||||
var test;
|
var test;
|
||||||
// decode HTML entities
|
// decode HTML entities
|
||||||
email = jQuery('<div />').html(email).text();
|
var email = jQuery('<div />').html(emailString).text();
|
||||||
email = email
|
email = email
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
||||||
@ -315,11 +316,13 @@ define(
|
|||||||
// remove urlencoded characters
|
// remove urlencoded characters
|
||||||
.replace(/\s+|%\d+|,+/g, '');
|
.replace(/\s+|%\d+|,+/g, '');
|
||||||
// detect e-mails that will be otherwise rejected by email regex
|
// detect e-mails that will be otherwise rejected by email regex
|
||||||
if (test = /<(.*?)>/.exec(email)) {
|
test = /<(.*?)>/.exec(email);
|
||||||
|
if (test) {
|
||||||
// is the email inside angle brackets (e.g., 'some@email.com <some@email.com>')?
|
// is the email inside angle brackets (e.g., 'some@email.com <some@email.com>')?
|
||||||
email = test[1].trim();
|
email = test[1].trim();
|
||||||
}
|
}
|
||||||
if (test = /mailto:(?:\s+)?(.*)/.exec(email)) {
|
test = /mailto:(?:\s+)?(.*)/.exec(email);
|
||||||
|
if (test) {
|
||||||
// is the email in 'mailto:email' format?
|
// is the email in 'mailto:email' format?
|
||||||
email = test[1].trim();
|
email = test[1].trim();
|
||||||
}
|
}
|
||||||
@ -534,12 +537,14 @@ define(
|
|||||||
data: segments,
|
data: segments,
|
||||||
width: '20em',
|
width: '20em',
|
||||||
templateResult: function (item) {
|
templateResult: function (item) {
|
||||||
item.subscriberCount = parseInt(item.subscriberCount);
|
var i = item;
|
||||||
return item.name + ' (' + item.subscriberCount.toLocaleString() + ')';
|
i.subscriberCount = parseInt(i.subscriberCount, 10);
|
||||||
|
return i.name + ' (' + i.subscriberCount.toLocaleString() + ')';
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
templateSelection: function (item) {
|
||||||
item.subscriberCount = parseInt(item.subscriberCount);
|
var i = item;
|
||||||
return item.name + ' (' + item.subscriberCount.toLocaleString() + ')';
|
i.subscriberCount = parseInt(i.subscriberCount, 10);
|
||||||
|
return i.name + ' (' + i.subscriberCount.toLocaleString() + ')';
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.change(function () {
|
.change(function () {
|
||||||
@ -894,7 +899,8 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jQuery.map(subscribersClone.subscribers, function (data, index) {
|
jQuery.map(subscribersClone.subscribers, function (dataSubscribers, index) {
|
||||||
|
var data = dataSubscribers;
|
||||||
var rowData = data[matchedColumn.index];
|
var rowData = data[matchedColumn.index];
|
||||||
if (index === fillerPosition || rowData.trim() === '') return;
|
if (index === fillerPosition || rowData.trim() === '') return;
|
||||||
var date = Moment(rowData, testedFormat, true);
|
var date = Moment(rowData, testedFormat, true);
|
||||||
|
9
build.sh
9
build.sh
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh -e
|
||||||
|
|
||||||
# Translations (npm install & composer install need to be run before)
|
# Translations (npm install & composer install need to be run before)
|
||||||
echo '[BUILD] Generating translations'
|
echo '[BUILD] Generating translations'
|
||||||
@ -9,21 +9,22 @@ plugin_name='mailpoet'
|
|||||||
|
|
||||||
# Remove previous build.
|
# Remove previous build.
|
||||||
echo '[BUILD] Removing previous build'
|
echo '[BUILD] Removing previous build'
|
||||||
rm $plugin_name.zip
|
test -e $plugin_name.zip && rm $plugin_name.zip
|
||||||
|
|
||||||
# Create temp dir.
|
# Create temp dir.
|
||||||
echo '[BUILD] Creating temporary directory'
|
echo '[BUILD] Creating temporary directory'
|
||||||
|
test -d $plugin_name && rm -rf $plugin_name
|
||||||
mkdir $plugin_name
|
mkdir $plugin_name
|
||||||
|
|
||||||
# Production assets.
|
# Production assets.
|
||||||
echo '[BUILD] Generating production CSS and JS assets'
|
echo '[BUILD] Generating production CSS and JS assets'
|
||||||
rm -rf node_modules
|
test -d node_modules && rm -rf node_modules
|
||||||
npm install
|
npm install
|
||||||
./do compile:all --env production
|
./do compile:all --env production
|
||||||
|
|
||||||
# Production libraries.
|
# Production libraries.
|
||||||
echo '[BUILD] Fetching production libraries'
|
echo '[BUILD] Fetching production libraries'
|
||||||
rm -rf vendor
|
test -d vendor && rm -rf vendor
|
||||||
./composer.phar install --no-dev --prefer-dist --optimize-autoloader --no-scripts
|
./composer.phar install --no-dev --prefer-dist --optimize-autoloader --no-scripts
|
||||||
|
|
||||||
# Copy release folders.
|
# Copy release folders.
|
||||||
|
50
codeception.acceptance.yml
Normal file
50
codeception.acceptance.yml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
actor: Tester
|
||||||
|
paths:
|
||||||
|
tests: tests
|
||||||
|
log: tests/_output
|
||||||
|
data: tests/_data
|
||||||
|
support: tests/_support
|
||||||
|
envs: tests/_envs
|
||||||
|
settings:
|
||||||
|
colors: true
|
||||||
|
memory_limit: 1024M
|
||||||
|
log: true
|
||||||
|
strict_xml: true
|
||||||
|
extensions:
|
||||||
|
enabled:
|
||||||
|
- Codeception\Extension\RunFailed
|
||||||
|
modules:
|
||||||
|
config:
|
||||||
|
WPWebDriver:
|
||||||
|
host: chrome
|
||||||
|
url: 'http://wordpress'
|
||||||
|
browser: chrome
|
||||||
|
port: 4444
|
||||||
|
window_size: '1024x768'
|
||||||
|
restart: true
|
||||||
|
wait: 0
|
||||||
|
adminUsername: admin
|
||||||
|
adminPassword: password
|
||||||
|
adminPath: /wp-admin
|
||||||
|
WPLoader:
|
||||||
|
wpRootFolder: /wp-core
|
||||||
|
dbName: wordpress
|
||||||
|
dbHost: mysql
|
||||||
|
dbUser: wordpress
|
||||||
|
dbPassword: wordpress
|
||||||
|
wpDebug: false
|
||||||
|
tablePrefix: wp_
|
||||||
|
domain: wordpress
|
||||||
|
plugins: ['mailpoet/mailpoet.php']
|
||||||
|
activatePlugins: ['mailpoet/mailpoet.php']
|
||||||
|
coverage:
|
||||||
|
enabled: true
|
||||||
|
whitelist:
|
||||||
|
include:
|
||||||
|
- lib/*
|
||||||
|
exclude:
|
||||||
|
- lib/Config/PopulatorData/*
|
||||||
|
- lib/Util/Sudzy/*
|
||||||
|
- lib/Util/CSS.php
|
||||||
|
- lib/Util/Helpers.php
|
||||||
|
- lib/Util/XLSXWriter.php
|
@ -21,6 +21,28 @@ modules:
|
|||||||
user: ''
|
user: ''
|
||||||
password: ''
|
password: ''
|
||||||
dump: tests/_data/dump.sql
|
dump: tests/_data/dump.sql
|
||||||
|
WPLoader:
|
||||||
|
wpRootFolder: /wp-core
|
||||||
|
dbName: wordpress
|
||||||
|
dbHost: mysql
|
||||||
|
dbUser: wordpress
|
||||||
|
dbPassword: wordpress
|
||||||
|
wpDebug: false
|
||||||
|
tablePrefix: wp_
|
||||||
|
domain: wordpress
|
||||||
|
plugins: ['mailpoet/mailpoet.php']
|
||||||
|
activatePlugins: ['mailpoet/mailpoet.php']
|
||||||
|
WPWebDriver:
|
||||||
|
host: chrome
|
||||||
|
url: 'http://wordpress'
|
||||||
|
browser: chrome
|
||||||
|
port: 4444
|
||||||
|
window_size: '1024x768'
|
||||||
|
restart: true
|
||||||
|
wait: 0
|
||||||
|
adminUsername: admin
|
||||||
|
adminPassword: password
|
||||||
|
adminPath: /wp-admin
|
||||||
coverage:
|
coverage:
|
||||||
enabled: true
|
enabled: true
|
||||||
whitelist:
|
whitelist:
|
@ -20,10 +20,12 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"codeception/aspect-mock": "^2.0",
|
"codeception/aspect-mock": "^2.0",
|
||||||
"codeception/codeception": "^2.2.9",
|
"codeception/codeception": "2.2.11",
|
||||||
"codeception/verify": "^0.3.3",
|
"codeception/verify": "^0.3.3",
|
||||||
"consolidation/robo": "^1.0.5",
|
"consolidation/robo": "^1.0.5",
|
||||||
"henrikbjorn/lurker": "^1.2",
|
"henrikbjorn/lurker": "^1.2",
|
||||||
|
"lucatume/wp-browser": "1.19.12",
|
||||||
|
"phpunit/phpunit": "4.8.21",
|
||||||
"vlucas/phpdotenv": "^2.4.0",
|
"vlucas/phpdotenv": "^2.4.0",
|
||||||
"umpirsky/twig-gettext-extractor": "1.1.*",
|
"umpirsky/twig-gettext-extractor": "1.1.*",
|
||||||
"raveren/kint": "^1.0",
|
"raveren/kint": "^1.0",
|
||||||
|
2794
composer.lock
generated
2794
composer.lock
generated
File diff suppressed because it is too large
Load Diff
47
docker-compose.yml
Normal file
47
docker-compose.yml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
version: '2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
codeception:
|
||||||
|
build: .
|
||||||
|
depends_on:
|
||||||
|
- wordpress
|
||||||
|
volumes:
|
||||||
|
- ./:/project
|
||||||
|
- wp-core:/wp-core
|
||||||
|
- ./:/wp-core/wp-content/plugins/mailpoet
|
||||||
|
entrypoint: /docker-entrypoint.sh
|
||||||
|
|
||||||
|
wordpress:
|
||||||
|
build: ./tests/wordpressDockerfile
|
||||||
|
image: wordpress:latest
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
- chrome
|
||||||
|
volumes:
|
||||||
|
- wp-core:/var/www/html
|
||||||
|
- ./:/var/www/html/wp-content/plugins/mailpoet
|
||||||
|
- /tmp:/var/www/html/wp-content/uploads/mailpoet/cache
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
environment:
|
||||||
|
WORDPRESS_DB_PASSWORD: wordpress
|
||||||
|
|
||||||
|
mysql:
|
||||||
|
image: mysql:5.6
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: wordpress
|
||||||
|
MYSQL_DATABASE: wordpress
|
||||||
|
MYSQL_USER: wordpress
|
||||||
|
MYSQL_PASSWORD: wordpress
|
||||||
|
|
||||||
|
chrome:
|
||||||
|
environment:
|
||||||
|
- DBUS_SESSION_BUS_ADDRESS=/dev/null
|
||||||
|
volumes:
|
||||||
|
- /dev/shm:/dev/shm
|
||||||
|
image: selenium/standalone-chrome-debug
|
||||||
|
ports:
|
||||||
|
- '4444'
|
||||||
|
- '5900:5900'
|
||||||
|
volumes:
|
||||||
|
wp-core:
|
42
docker-entrypoint.sh
Normal file
42
docker-entrypoint.sh
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Allows WP CLI to run with the right permissions.
|
||||||
|
wp-su() {
|
||||||
|
sudo -E -u www-data wp "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
while ! mysqladmin ping -hmysql --silent; do
|
||||||
|
echo 'Waiting for the database'
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure permissions are correct.
|
||||||
|
cd /wp-core
|
||||||
|
chown www-data:www-data wp-content/plugins
|
||||||
|
chmod 755 wp-content/plugins
|
||||||
|
|
||||||
|
# Make sure WordPress is installed.
|
||||||
|
if ! $(wp-su core is-installed); then
|
||||||
|
|
||||||
|
echo "Installing WordPress"
|
||||||
|
|
||||||
|
wp-su core install --url=wordpress --title=tests --admin_user=admin --admin_email=test@test.com
|
||||||
|
|
||||||
|
echo "Configuring WordPress"
|
||||||
|
# The development version of Gravity Flow requires SCRIPT_DEBUG
|
||||||
|
wp-su core config --dbhost=mysql --dbname=wordpress --dbuser=wordpress --dbpass=wordpress --extra-php="define( 'SCRIPT_DEBUG', true );" --force
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf /project/vendor_backup
|
||||||
|
mv /project/vendor /project/vendor_backup
|
||||||
|
cd /project
|
||||||
|
php composer.phar install
|
||||||
|
|
||||||
|
cd /wp-core/wp-content/plugins/mailpoet
|
||||||
|
|
||||||
|
/project/vendor/bin/codecept run acceptance -c codeception.acceptance.yml $@
|
||||||
|
|
||||||
|
rm -rf /project/vendor
|
||||||
|
mv /project/vendor_backup /project/vendor
|
@ -33,6 +33,7 @@ class Newsletters extends APIEndpoint {
|
|||||||
$newsletter = $newsletter
|
$newsletter = $newsletter
|
||||||
->withSegments()
|
->withSegments()
|
||||||
->withOptions()
|
->withOptions()
|
||||||
|
->withSendingQueue()
|
||||||
->asArray();
|
->asArray();
|
||||||
$newsletter = Hooks::applyFilters('mailpoet_api_newsletters_get_after', $newsletter);
|
$newsletter = Hooks::applyFilters('mailpoet_api_newsletters_get_after', $newsletter);
|
||||||
return $this->successResponse($newsletter);
|
return $this->successResponse($newsletter);
|
||||||
@ -110,6 +111,13 @@ class Newsletters extends APIEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$queue = $newsletter->getQueue();
|
||||||
|
if($queue) {
|
||||||
|
$queue->newsletter_rendered_body = null;
|
||||||
|
$queue->newsletter_rendered_subject = null;
|
||||||
|
$queue->save();
|
||||||
|
}
|
||||||
|
|
||||||
Hooks::doAction('mailpoet_api_newsletters_save_after', $newsletter);
|
Hooks::doAction('mailpoet_api_newsletters_save_after', $newsletter);
|
||||||
|
|
||||||
return $this->successResponse($newsletter->asArray());
|
return $this->successResponse($newsletter->asArray());
|
||||||
|
@ -4,6 +4,7 @@ use MailPoet\API\JSON\Endpoint as APIEndpoint;
|
|||||||
use MailPoet\API\JSON\Error as APIError;
|
use MailPoet\API\JSON\Error as APIError;
|
||||||
use MailPoet\API\JSON\Access as APIAccess;
|
use MailPoet\API\JSON\Access as APIAccess;
|
||||||
|
|
||||||
|
use MailPoet\Form\Util\FieldNameObfuscator;
|
||||||
use MailPoet\Listing;
|
use MailPoet\Listing;
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Models\Form;
|
use MailPoet\Models\Form;
|
||||||
@ -66,6 +67,11 @@ class Subscribers extends APIEndpoint {
|
|||||||
APIError::BAD_REQUEST => __('Please specify a valid form ID.', 'mailpoet')
|
APIError::BAD_REQUEST => __('Please specify a valid form ID.', 'mailpoet')
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if(!empty($data['email'])) {
|
||||||
|
return $this->badRequest(array(
|
||||||
|
APIError::BAD_REQUEST => __('Please leave the first field empty.', 'mailpoet')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$segment_ids = (!empty($data['segments'])
|
$segment_ids = (!empty($data['segments'])
|
||||||
? (array)$data['segments']
|
? (array)$data['segments']
|
||||||
@ -74,6 +80,8 @@ class Subscribers extends APIEndpoint {
|
|||||||
$segment_ids = $form->filterSegments($segment_ids);
|
$segment_ids = $form->filterSegments($segment_ids);
|
||||||
unset($data['segments']);
|
unset($data['segments']);
|
||||||
|
|
||||||
|
$data = $this->deobfuscateFormPayload($data);
|
||||||
|
|
||||||
if(empty($segment_ids)) {
|
if(empty($segment_ids)) {
|
||||||
return $this->badRequest(array(
|
return $this->badRequest(array(
|
||||||
APIError::BAD_REQUEST => __('Please select a list.', 'mailpoet')
|
APIError::BAD_REQUEST => __('Please select a list.', 'mailpoet')
|
||||||
@ -115,6 +123,11 @@ class Subscribers extends APIEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function deobfuscateFormPayload($data) {
|
||||||
|
$obfuscator = new FieldNameObfuscator();
|
||||||
|
return $obfuscator->deobfuscateFormPayload($data);
|
||||||
|
}
|
||||||
|
|
||||||
function save($data = array()) {
|
function save($data = array()) {
|
||||||
if(empty($data['segments'])) {
|
if(empty($data['segments'])) {
|
||||||
$data['segments'] = array();
|
$data['segments'] = array();
|
||||||
|
@ -5,6 +5,7 @@ use MailPoet\API;
|
|||||||
use MailPoet\Cron\CronTrigger;
|
use MailPoet\Cron\CronTrigger;
|
||||||
use MailPoet\Router;
|
use MailPoet\Router;
|
||||||
use MailPoet\Util\ConflictResolver;
|
use MailPoet\Util\ConflictResolver;
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
use MailPoet\WP\Notice as WPNotice;
|
use MailPoet\WP\Notice as WPNotice;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
@ -13,7 +14,8 @@ require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
|||||||
|
|
||||||
class Initializer {
|
class Initializer {
|
||||||
|
|
||||||
const UNABLE_TO_CONNECT = '<strong>Mailpoet:</strong> Unable to connect to the database (the database is unable to open a file or folder), the connection is likely not configured correctly. Please read our <a href="http://beta.docs.mailpoet.com/article/200-solving-database-connection-issues">Knowledge Base article</a> for steps how to resolve it.';
|
const UNABLE_TO_CONNECT = 'Unable to connect to the database (the database is unable to open a file or folder), the connection is likely not configured correctly. Please read our [link] Knowledge Base article [/link] for steps how to resolve it.';
|
||||||
|
const SOLVE_DB_ISSUE_URL = 'http://beta.docs.mailpoet.com/article/200-solving-database-connection-issues';
|
||||||
|
|
||||||
protected $plugin_initialized = false;
|
protected $plugin_initialized = false;
|
||||||
|
|
||||||
@ -36,7 +38,11 @@ class Initializer {
|
|||||||
try {
|
try {
|
||||||
$this->setupDB();
|
$this->setupDB();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
return WPNotice::displayWarning(self::UNABLE_TO_CONNECT);
|
return WPNotice::displayError(Helpers::replaceLinkTags(
|
||||||
|
__(self::UNABLE_TO_CONNECT, 'mailpoet'),
|
||||||
|
self::SOLVE_DB_ISSUE_URL,
|
||||||
|
array('target' => '_blank')
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// activation function
|
// activation function
|
||||||
|
@ -2,21 +2,19 @@
|
|||||||
|
|
||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
use MailPoet\Util\ProgressBar;
|
|
||||||
use MailPoet\Models\Form;
|
|
||||||
use MailPoet\Models\Setting;
|
|
||||||
use MailPoet\Models\Segment;
|
|
||||||
use MailPoet\Models\Subscriber;
|
|
||||||
use MailPoet\Models\CustomField;
|
use MailPoet\Models\CustomField;
|
||||||
use MailPoet\Models\SubscriberSegment;
|
use MailPoet\Models\Form;
|
||||||
use MailPoet\Models\SubscriberCustomField;
|
|
||||||
use MailPoet\Models\MappingToExternalEntities;
|
use MailPoet\Models\MappingToExternalEntities;
|
||||||
use MailPoet\Config\Activator;
|
use MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Models\SubscriberCustomField;
|
||||||
|
use MailPoet\Models\SubscriberSegment;
|
||||||
|
use MailPoet\Util\ProgressBar;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class MP2Migrator {
|
class MP2Migrator {
|
||||||
|
|
||||||
const IMPORT_TIMEOUT_IN_SECONDS = 7200; // Timeout = 2 hours
|
const IMPORT_TIMEOUT_IN_SECONDS = 7200; // Timeout = 2 hours
|
||||||
const CHUNK_SIZE = 10; // To import the data by batch
|
const CHUNK_SIZE = 10; // To import the data by batch
|
||||||
|
|
||||||
@ -145,7 +143,9 @@ class MP2Migrator {
|
|||||||
* @return string Result
|
* @return string Result
|
||||||
*/
|
*/
|
||||||
public function import() {
|
public function import() {
|
||||||
set_time_limit(self::IMPORT_TIMEOUT_IN_SECONDS);
|
if(strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
|
||||||
|
@set_time_limit(3600);
|
||||||
|
}
|
||||||
ob_start();
|
ob_start();
|
||||||
$datetime = new \MailPoet\WP\DateTime();
|
$datetime = new \MailPoet\WP\DateTime();
|
||||||
$this->log(sprintf('=== ' . __('START IMPORT', 'mailpoet') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT)));
|
$this->log(sprintf('=== ' . __('START IMPORT', 'mailpoet') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT)));
|
||||||
@ -1139,5 +1139,4 @@ class MP2Migrator {
|
|||||||
}
|
}
|
||||||
return $emails_number;
|
return $emails_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -337,7 +337,7 @@ class Populator {
|
|||||||
function convertExistingDataToUTF8() {
|
function convertExistingDataToUTF8() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
if(!version_compare(get_option('mailpoet_db_version'), '3.0.0-beta.32', '<=')) {
|
if(!version_compare(get_option('mailpoet_db_version', '3.0.0-beta.33'), '3.0.0-beta.32', '<=')) {
|
||||||
// Data conversion should only be performed only once, when migrating from
|
// Data conversion should only be performed only once, when migrating from
|
||||||
// older version
|
// older version
|
||||||
return false;
|
return false;
|
||||||
@ -402,7 +402,7 @@ class Populator {
|
|||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
// perform once for versions below 3.0.0-beta.36.2.1
|
// perform once for versions below 3.0.0-beta.36.2.1
|
||||||
if(version_compare(get_option('mailpoet_db_version'), '3.0.0-beta.36.2.1', '>=')) {
|
if(version_compare(get_option('mailpoet_db_version', '3.0.0-beta.36.2.3'), '3.0.0-beta.36.2.1', '>=')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,7 +455,7 @@ class Populator {
|
|||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
// perform once for versions below 3.0.0-beta.36.2.1
|
// perform once for versions below 3.0.0-beta.36.2.1
|
||||||
if(version_compare(get_option('mailpoet_db_version'), '3.0.0-beta.36.2.1', '>=')) {
|
if(version_compare(get_option('mailpoet_db_version', '3.0.0-beta.36.2.3'), '3.0.0-beta.36.2.1', '>=')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,15 +15,15 @@ if(!defined('ABSPATH')) exit;
|
|||||||
class Links {
|
class Links {
|
||||||
static function process($rendered_newsletter, $newsletter, $queue) {
|
static function process($rendered_newsletter, $newsletter, $queue) {
|
||||||
list($rendered_newsletter, $links) =
|
list($rendered_newsletter, $links) =
|
||||||
self::hashAndReplaceLinks($rendered_newsletter);
|
self::hashAndReplaceLinks($rendered_newsletter, $newsletter->id, $queue->id);
|
||||||
self::saveLinks($links, $newsletter, $queue);
|
self::saveLinks($links, $newsletter, $queue);
|
||||||
return $rendered_newsletter;
|
return $rendered_newsletter;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function hashAndReplaceLinks($rendered_newsletter) {
|
static function hashAndReplaceLinks($rendered_newsletter, $newsletter_id, $queue_id) {
|
||||||
// join HTML and TEXT rendered body into a text string
|
// join HTML and TEXT rendered body into a text string
|
||||||
$content = Helpers::joinObject($rendered_newsletter);
|
$content = Helpers::joinObject($rendered_newsletter);
|
||||||
list($content, $links) = NewsletterLinks::process($content);
|
list($content, $links) = NewsletterLinks::process($content, $newsletter_id, $queue_id);
|
||||||
// split the processed body with hashed links back to HTML and TEXT
|
// split the processed body with hashed links back to HTML and TEXT
|
||||||
list($rendered_newsletter['html'], $rendered_newsletter['text'])
|
list($rendered_newsletter['html'], $rendered_newsletter['text'])
|
||||||
= Helpers::splitObject($content);
|
= Helpers::splitObject($content);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Form\Block;
|
namespace MailPoet\Form\Block;
|
||||||
|
|
||||||
|
use MailPoet\Form\Util\FieldNameObfuscator;
|
||||||
|
|
||||||
abstract class Base {
|
abstract class Base {
|
||||||
protected static function getInputValidation($block, $extra_rules = array()) {
|
protected static function getInputValidation($block, $extra_rules = array()) {
|
||||||
$rules = array();
|
$rules = array();
|
||||||
@ -104,7 +106,8 @@ abstract class Base {
|
|||||||
if((int)$block['id'] > 0) {
|
if((int)$block['id'] > 0) {
|
||||||
return 'cf_'.$block['id'];
|
return 'cf_'.$block['id'];
|
||||||
} else {
|
} else {
|
||||||
return $block['id'];
|
$obfuscator = new FieldNameObfuscator();
|
||||||
|
return $obfuscator->obfuscate($block['id']);//obfuscate field name for spambots
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class Date extends Base {
|
|||||||
$html .= '</select>';
|
$html .= '</select>';
|
||||||
} else if($date_selector === 'MM') {
|
} else if($date_selector === 'MM') {
|
||||||
$block['selected'] = $month;
|
$block['selected'] = $month;
|
||||||
$html .= '<select class="mailpoet_date_month" ';
|
$html .= '<select class="mailpoet_select mailpoet_date_month" ';
|
||||||
$html .= static::getInputValidation($block, array(
|
$html .= static::getInputValidation($block, array(
|
||||||
'required-message' => __('Please select a month', 'mailpoet')
|
'required-message' => __('Please select a month', 'mailpoet')
|
||||||
));
|
));
|
||||||
|
@ -8,7 +8,7 @@ class Submit extends Base {
|
|||||||
static function render($block) {
|
static function render($block) {
|
||||||
$html = '';
|
$html = '';
|
||||||
|
|
||||||
$html .= '<p class="mailpoet_submit"><input type="submit" ';
|
$html .= '<p class="mailpoet_paragraph"><input type="submit" class="mailpoet_submit" ';
|
||||||
|
|
||||||
$html .= 'value="'.static::getFieldLabel($block).'" ';
|
$html .= 'value="'.static::getFieldLabel($block).'" ';
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ class Renderer {
|
|||||||
$styles = new Util\Styles(static::getStyles($form));
|
$styles = new Util\Styles(static::getStyles($form));
|
||||||
|
|
||||||
$html = '<style type="text/css">';
|
$html = '<style type="text/css">';
|
||||||
|
$html .= '.mailpoet_hp_email_label{position: absolute;left: -999em;}';// move honeypot field out of the sight
|
||||||
$html .= $styles->render($prefix);
|
$html .= $styles->render($prefix);
|
||||||
$html .= '</style>';
|
$html .= '</style>';
|
||||||
|
|
||||||
@ -38,7 +39,8 @@ class Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function renderBlocks($blocks = array()) {
|
static function renderBlocks($blocks = array()) {
|
||||||
$html = '';
|
// this is a honeypot for spambots
|
||||||
|
$html = '<label class="mailpoet_hp_email_label">Please leave this field empty<input type="email" name="data[email]"></label>';
|
||||||
foreach($blocks as $key => $block) {
|
foreach($blocks as $key => $block) {
|
||||||
$html .= static::renderBlock($block)."\n";
|
$html .= static::renderBlock($block)."\n";
|
||||||
}
|
}
|
||||||
|
38
lib/Form/Util/FieldNameObfuscator.php
Normal file
38
lib/Form/Util/FieldNameObfuscator.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Form\Util;
|
||||||
|
|
||||||
|
class FieldNameObfuscator {
|
||||||
|
|
||||||
|
const OBFUSCATED_FIELD_PREFIX = 'form_field_';
|
||||||
|
|
||||||
|
public function obfuscate($name) {
|
||||||
|
return FieldNameObfuscator::OBFUSCATED_FIELD_PREFIX.base64_encode($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deobfuscate($name) {
|
||||||
|
$prefixLength = strlen(FieldNameObfuscator::OBFUSCATED_FIELD_PREFIX);
|
||||||
|
return base64_decode(substr($name, $prefixLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deobfuscateFormPayload($data) {
|
||||||
|
$result = array();
|
||||||
|
foreach($data as $key => $value) {
|
||||||
|
$result[$this->deobfuscateField($key)] = $value;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deobfuscateField($name) {
|
||||||
|
if($this->wasFieldObfuscated($name)) {
|
||||||
|
return $this->deobfuscate($name);
|
||||||
|
} else {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function wasFieldObfuscated($name) {
|
||||||
|
return strpos($name, FieldNameObfuscator::OBFUSCATED_FIELD_PREFIX) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -13,10 +13,11 @@ class Styles {
|
|||||||
|
|
||||||
/* paragraphs (label + input) */
|
/* paragraphs (label + input) */
|
||||||
.mailpoet_paragraph {
|
.mailpoet_paragraph {
|
||||||
|
line-height:20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* labels */
|
/* labels */
|
||||||
|
.mailpoet_segment_label,
|
||||||
.mailpoet_text_label,
|
.mailpoet_text_label,
|
||||||
.mailpoet_textarea_label,
|
.mailpoet_textarea_label,
|
||||||
.mailpoet_select_label,
|
.mailpoet_select_label,
|
||||||
@ -25,18 +26,35 @@ class Styles {
|
|||||||
.mailpoet_list_label,
|
.mailpoet_list_label,
|
||||||
.mailpoet_date_label {
|
.mailpoet_date_label {
|
||||||
display:block;
|
display:block;
|
||||||
|
font-weight:bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* inputs */
|
/* inputs */
|
||||||
.mailpoet_text,
|
.mailpoet_text,
|
||||||
.mailpoet_textarea,
|
.mailpoet_textarea,
|
||||||
.mailpoet_select,
|
.mailpoet_select,
|
||||||
|
.mailpoet_date_month,
|
||||||
|
.mailpoet_date_day,
|
||||||
|
.mailpoet_date_year,
|
||||||
.mailpoet_date {
|
.mailpoet_date {
|
||||||
display:block;
|
display:block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mailpoet_checkbox {
|
.mailpoet_text,
|
||||||
|
.mailpoet_textarea {
|
||||||
|
width:200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailpoet_checkbox {
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailpoet_submit input {
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailpoet_divider {
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailpoet_message {
|
||||||
}
|
}
|
||||||
|
|
||||||
.mailpoet_validate_success {
|
.mailpoet_validate_success {
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace MailPoet\Form;
|
namespace MailPoet\Form;
|
||||||
|
|
||||||
use MailPoet\API\JSON\API;
|
use MailPoet\API\JSON\API;
|
||||||
use MailPoet\Config\Renderer;
|
use MailPoet\Config\Renderer;
|
||||||
use MailPoet\Models\Form;
|
|
||||||
use MailPoet\Form\Renderer as FormRenderer;
|
use MailPoet\Form\Renderer as FormRenderer;
|
||||||
|
use MailPoet\Models\Form;
|
||||||
use MailPoet\Util\Security;
|
use MailPoet\Util\Security;
|
||||||
|
use MailPoet\WP\Hooks;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -37,7 +40,7 @@ class Widget extends \WP_Widget {
|
|||||||
$instance = wp_parse_args(
|
$instance = wp_parse_args(
|
||||||
(array)$instance,
|
(array)$instance,
|
||||||
array(
|
array(
|
||||||
'title' => __("Subscribe to Our Newsletter", 'mailpoet')
|
'title' => __('Subscribe to Our Newsletter', 'mailpoet')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -109,7 +112,7 @@ class Widget extends \WP_Widget {
|
|||||||
$instance = $args;
|
$instance = $args;
|
||||||
}
|
}
|
||||||
|
|
||||||
$title = apply_filters(
|
$title = Hooks::applyFilters(
|
||||||
'widget_title',
|
'widget_title',
|
||||||
!empty($instance['title']) ? $instance['title'] : '',
|
!empty($instance['title']) ? $instance['title'] : '',
|
||||||
$instance,
|
$instance,
|
||||||
@ -119,7 +122,7 @@ class Widget extends \WP_Widget {
|
|||||||
// get form
|
// get form
|
||||||
$form = Form::getPublished()->findOne($instance['form']);
|
$form = Form::getPublished()->findOne($instance['form']);
|
||||||
|
|
||||||
// if the form was not found, return nothing.
|
// if the form was not found, return nothing
|
||||||
if($form === false) {
|
if($form === false) {
|
||||||
return '';
|
return '';
|
||||||
} else {
|
} else {
|
||||||
@ -175,6 +178,7 @@ class Widget extends \WP_Widget {
|
|||||||
try {
|
try {
|
||||||
$output = $renderer->render('form/widget.html', $data);
|
$output = $renderer->render('form/widget.html', $data);
|
||||||
$output = do_shortcode($output);
|
$output = do_shortcode($output);
|
||||||
|
$output = Hooks::applyFilters('mailpoet_form_widget_post_process', $output);
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
$output = $e->getMessage();
|
$output = $e->getMessage();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace MailPoet\Newsletter\Editor;
|
namespace MailPoet\Newsletter\Editor;
|
||||||
|
|
||||||
|
use MailPoet\WP\Hooks;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class PostContentManager {
|
class PostContentManager {
|
||||||
|
|
||||||
const MAX_EXCERPT_LENGTH = 60;
|
|
||||||
const WP_POST_CLASS = 'mailpoet_wp_post';
|
const WP_POST_CLASS = 'mailpoet_wp_post';
|
||||||
|
|
||||||
|
public $max_excerpt_length = 60;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
$this->max_excerpt_length = Hooks::applyFilters('mailpoet_newsletter_post_excerpt_length', $this->max_excerpt_length);
|
||||||
|
}
|
||||||
|
|
||||||
function getContent($post, $displayType) {
|
function getContent($post, $displayType) {
|
||||||
if($displayType === 'titleOnly') {
|
if($displayType === 'titleOnly') {
|
||||||
return '';
|
return '';
|
||||||
@ -57,7 +64,7 @@ class PostContentManager {
|
|||||||
return $excerpts[0];
|
return $excerpts[0];
|
||||||
} else {
|
} else {
|
||||||
// Separator not present, try to shorten long posts
|
// Separator not present, try to shorten long posts
|
||||||
return wp_trim_words($content, self::MAX_EXCERPT_LENGTH, ' …');
|
return wp_trim_words($content, $this->max_excerpt_length, ' …');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,5 +99,4 @@ class PostContentManager {
|
|||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ class PostTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function transform($post) {
|
function transform($post) {
|
||||||
$content_manager = new PostContentManager($post);
|
$content_manager = new PostContentManager();
|
||||||
$meta_manager = new MetaInformationManager();
|
$meta_manager = new MetaInformationManager();
|
||||||
|
|
||||||
$content = $content_manager->getContent($post, $this->args['displayType']);
|
$content = $content_manager->getContent($post, $this->args['displayType']);
|
||||||
|
@ -8,8 +8,8 @@ use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
|||||||
use MailPoet\Router\Endpoints\Track as TrackEndpoint;
|
use MailPoet\Router\Endpoints\Track as TrackEndpoint;
|
||||||
use MailPoet\Router\Router;
|
use MailPoet\Router\Router;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
use MailPoet\Util\pQuery\pQuery as DomParser;
|
|
||||||
use MailPoet\Util\Security;
|
use MailPoet\Util\Security;
|
||||||
|
use MailPoet\Util\pQuery\pQuery as DomParser;
|
||||||
|
|
||||||
class Links {
|
class Links {
|
||||||
const DATA_TAG_CLICK = '[mailpoet_click_data]';
|
const DATA_TAG_CLICK = '[mailpoet_click_data]';
|
||||||
@ -17,9 +17,10 @@ class Links {
|
|||||||
const LINK_TYPE_SHORTCODE = 'shortcode';
|
const LINK_TYPE_SHORTCODE = 'shortcode';
|
||||||
const LINK_TYPE_URL = 'link';
|
const LINK_TYPE_URL = 'link';
|
||||||
|
|
||||||
static function process($content) {
|
static function process($content, $newsletter_id, $queue_id) {
|
||||||
$extracted_links = self::extract($content);
|
$extracted_links = self::extract($content);
|
||||||
$processed_links = self::hash($extracted_links);
|
$saved_links = self::load($newsletter_id, $queue_id);
|
||||||
|
$processed_links = self::hash($extracted_links, $saved_links);
|
||||||
return self::replace($content, $processed_links);
|
return self::replace($content, $processed_links);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,13 +52,31 @@ class Links {
|
|||||||
return array_unique($extracted_links, SORT_REGULAR);
|
return array_unique($extracted_links, SORT_REGULAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function hash($extracted_links) {
|
static function load($newsletter_id, $queue_id) {
|
||||||
$processed_links = array();
|
$links = NewsletterLink::whereEqual('newsletter_id', $newsletter_id)
|
||||||
|
->whereEqual('queue_id', $queue_id)
|
||||||
|
->findMany();
|
||||||
|
$saved_links = array();
|
||||||
|
foreach($links as $link) {
|
||||||
|
$saved_links[$link->url] = $link->asArray();
|
||||||
|
}
|
||||||
|
return $saved_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function hash($extracted_links, $saved_links) {
|
||||||
|
$processed_links = array_map(function(&$link) {
|
||||||
|
$link['type'] = Links::LINK_TYPE_URL;
|
||||||
|
$link['link'] = $link['url'];
|
||||||
|
$link['processed_link'] = self::DATA_TAG_CLICK . '-' . $link['hash'];
|
||||||
|
return $link;
|
||||||
|
}, $saved_links);
|
||||||
foreach($extracted_links as $extracted_link) {
|
foreach($extracted_links as $extracted_link) {
|
||||||
|
$link = $extracted_link['link'];
|
||||||
|
if (array_key_exists($link, $processed_links))
|
||||||
|
continue;
|
||||||
$hash = Security::generateHash();
|
$hash = Security::generateHash();
|
||||||
// Use URL as a key to map between extracted and processed links
|
// Use URL as a key to map between extracted and processed links
|
||||||
// regardless of their sequential position (useful for link skips etc.)
|
// regardless of their sequential position (useful for link skips etc.)
|
||||||
$link = $extracted_link['link'];
|
|
||||||
$processed_links[$link] = array(
|
$processed_links[$link] = array(
|
||||||
'type' => $extracted_link['type'],
|
'type' => $extracted_link['type'],
|
||||||
'hash' => $hash,
|
'hash' => $hash,
|
||||||
@ -137,6 +156,8 @@ class Links {
|
|||||||
|
|
||||||
static function save(array $links, $newsletter_id, $queue_id) {
|
static function save(array $links, $newsletter_id, $queue_id) {
|
||||||
foreach($links as $link) {
|
foreach($links as $link) {
|
||||||
|
if (isset($link['id']))
|
||||||
|
continue;
|
||||||
if(empty($link['hash']) || empty($link['link'])) continue;
|
if(empty($link['hash']) || empty($link['link'])) continue;
|
||||||
$newsletter_link = NewsletterLink::create();
|
$newsletter_link = NewsletterLink::create();
|
||||||
$newsletter_link->newsletter_id = $newsletter_id;
|
$newsletter_link->newsletter_id = $newsletter_id;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||||
|
|
||||||
class Date {
|
class Date {
|
||||||
@ -7,20 +8,19 @@ class Date {
|
|||||||
$action_argument = false,
|
$action_argument = false,
|
||||||
$action_argument_value = false
|
$action_argument_value = false
|
||||||
) {
|
) {
|
||||||
$date = new \DateTime('now');
|
$action_mapping = array(
|
||||||
$action_formats = array(
|
'd' => 'd',
|
||||||
'd' => $date->format('d'),
|
'dordinal' => 'dS',
|
||||||
'dordinal' => $date->format('dS'),
|
'dtext' => 'l',
|
||||||
'dtext' => $date->format('l'),
|
'm' => 'm',
|
||||||
'm' => $date->format('m'),
|
'mtext' => 'F',
|
||||||
'mtext' => $date->format('F'),
|
'y' => 'Y'
|
||||||
'y' => $date->format('Y')
|
|
||||||
);
|
);
|
||||||
if(!empty($action_formats[$action])) {
|
if(!empty($action_mapping[$action])) {
|
||||||
return $action_formats[$action];
|
return date_i18n($action_mapping[$action], current_time('timestamp'));
|
||||||
}
|
}
|
||||||
return ($action === 'custom' && $action_argument === 'format') ?
|
return ($action === 'custom' && $action_argument === 'format') ?
|
||||||
$date->format($action_argument_value) :
|
date_i18n($action_argument_value, current_time('timestamp')) :
|
||||||
false;
|
false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace MailPoet\Newsletter\Shortcodes;
|
namespace MailPoet\Newsletter\Shortcodes;
|
||||||
|
|
||||||
use MailPoet\Models\CustomField;
|
use MailPoet\Models\CustomField;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace MailPoet\Subscribers\ImportExport\Export;
|
namespace MailPoet\Subscribers\ImportExport\Export;
|
||||||
|
|
||||||
use MailPoet\Config\Env;
|
use MailPoet\Config\Env;
|
||||||
@ -26,7 +27,9 @@ class Export {
|
|||||||
public $subscriber_batch_size;
|
public $subscriber_batch_size;
|
||||||
|
|
||||||
public function __construct($data) {
|
public function __construct($data) {
|
||||||
|
if(strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
}
|
||||||
$this->export_confirmed_option = $data['export_confirmed_option'];
|
$this->export_confirmed_option = $data['export_confirmed_option'];
|
||||||
$this->export_format_option = $data['export_format_option'];
|
$this->export_format_option = $data['export_format_option'];
|
||||||
$this->group_by_segment_option = $data['group_by_segment_option'];
|
$this->group_by_segment_option = $data['group_by_segment_option'];
|
||||||
@ -47,7 +50,7 @@ class Export {
|
|||||||
function process() {
|
function process() {
|
||||||
try {
|
try {
|
||||||
if(is_writable($this->export_path) === false) {
|
if(is_writable($this->export_path) === false) {
|
||||||
throw new \Exception(__("The export file could not be saved on the server.", 'mailpoet'));
|
throw new \Exception(__('The export file could not be saved on the server.', 'mailpoet'));
|
||||||
}
|
}
|
||||||
if(!extension_loaded('zip')) {
|
if(!extension_loaded('zip')) {
|
||||||
throw new \Exception(__('Export requires a ZIP extension to be installed on the host.', 'mailpoet'));
|
throw new \Exception(__('Export requires a ZIP extension to be installed on the host.', 'mailpoet'));
|
||||||
|
13
mailpoet.php
13
mailpoet.php
@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Plugin Name: MailPoet 3 (new)
|
* Plugin Name: MailPoet 3 (new)
|
||||||
* Version: 3.0.0-rc.1.0.0
|
* Version: 3.0.0-rc.1.0.4
|
||||||
* Plugin URI: http://www.mailpoet.com
|
* Plugin URI: http://www.mailpoet.com
|
||||||
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
|
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
|
||||||
* Author: MailPoet
|
* Author: MailPoet
|
||||||
@ -21,7 +21,7 @@ if(!defined('ABSPATH')) exit;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$mailpoet_plugin = array(
|
$mailpoet_plugin = array(
|
||||||
'version' => '3.0.0-rc.1.0.0',
|
'version' => '3.0.0-rc.1.0.4',
|
||||||
'filename' => __FILE__,
|
'filename' => __FILE__,
|
||||||
'path' => dirname(__FILE__),
|
'path' => dirname(__FILE__),
|
||||||
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
|
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
|
||||||
@ -54,11 +54,8 @@ function mailpoet_php_version_notice() {
|
|||||||
printf('<div class="error"><p>%1$s</p></div>', $notice);
|
printf('<div class="error"><p>%1$s</p></div>', $notice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(isset($_SERVER['SERVER_SOFTWARE']) && strpos(strtolower($_SERVER['SERVER_SOFTWARE']), 'microsoft-iis') !== false) {
|
||||||
isset($_SERVER["SERVER_SOFTWARE"])
|
add_action('admin_notices', 'mailpoet_microsoft_iis_notice');
|
||||||
&& strpos(strtolower($_SERVER["SERVER_SOFTWARE"]), "microsoft-iis") !== false
|
|
||||||
) {
|
|
||||||
add_action('admin_notices', 'mailpoet_php_version_notice');
|
|
||||||
// deactivate the plugin
|
// deactivate the plugin
|
||||||
add_action('admin_init', 'mailpoet_deactivate_plugin');
|
add_action('admin_init', 'mailpoet_deactivate_plugin');
|
||||||
return;
|
return;
|
||||||
@ -66,7 +63,7 @@ if(
|
|||||||
|
|
||||||
// Display IIS server error notice
|
// Display IIS server error notice
|
||||||
function mailpoet_microsoft_iis_notice() {
|
function mailpoet_microsoft_iis_notice() {
|
||||||
$notice = __('MailPoet plugin cannot run under Microsoft\'s Internet Information Services (IIS) web server. We recommend that you use a web server powered by Apache or NGINX.', 'mailpoet');
|
$notice = __("MailPoet plugin cannot run under Microsoft's Internet Information Services (IIS) web server. We recommend that you use a web server powered by Apache or NGINX.", 'mailpoet');
|
||||||
printf('<div class="error"><p>%1$s</p></div>', $notice);
|
printf('<div class="error"><p>%1$s</p></div>', $notice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "npm run lint6 && npm run lint5 && npm run lint-tests",
|
"lint": "npm run lint6 && npm run lint5 && npm run lint-tests",
|
||||||
"lint6": "eslint -c .eslintrc.es6.json --max-warnings 0 'assets/js/src/**/*.jsx'",
|
"lint6": "eslint -c .eslintrc.es6.json --max-warnings 0 'assets/js/src/**/*.jsx'",
|
||||||
"lint5": "eslint -c .eslintrc.es5.json --max-warnings 0 'assets/js/src/**/*.js'",
|
"lint5": "eslint -c .eslintrc.es5.json --ignore-pattern helpscout.js --max-warnings 0 'assets/js/src/**/*.js'",
|
||||||
"lint-tests": "eslint -c .eslintrc.tests.json --max-warnings 0 'tests/javascript'"
|
"lint-tests": "eslint -c .eslintrc.tests.json --max-warnings 0 'tests/javascript'"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -25,6 +25,7 @@
|
|||||||
"parsleyjs": "^2.1.2",
|
"parsleyjs": "^2.1.2",
|
||||||
"react": "~15.4.2",
|
"react": "~15.4.2",
|
||||||
"react-dom": "~15.4.2",
|
"react-dom": "~15.4.2",
|
||||||
|
"react-html-parser": "^1.0.3",
|
||||||
"react-router": "~3.0.2",
|
"react-router": "~3.0.2",
|
||||||
"react-string-replace": "^0.3.2",
|
"react-string-replace": "^0.3.2",
|
||||||
"react-tooltip": "^3.2.10",
|
"react-tooltip": "^3.2.10",
|
||||||
@ -38,10 +39,10 @@
|
|||||||
"amd-inject-loader": "~0.5.0",
|
"amd-inject-loader": "~0.5.0",
|
||||||
"babel-core": "^5.8.22",
|
"babel-core": "^5.8.22",
|
||||||
"babel-loader": "^5.3.2",
|
"babel-loader": "^5.3.2",
|
||||||
"clean-webpack-plugin": "^0.1.16",
|
|
||||||
"cross-env": "^5.0.1",
|
|
||||||
"chai": "2.2.0",
|
"chai": "2.2.0",
|
||||||
"chai-jq": "0.0.8",
|
"chai-jq": "0.0.8",
|
||||||
|
"clean-webpack-plugin": "^0.1.16",
|
||||||
|
"cross-env": "^5.0.1",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^3.19.0",
|
||||||
"eslint-config-airbnb": "^15.0.1",
|
"eslint-config-airbnb": "^15.0.1",
|
||||||
"eslint-plugin-import": "^2.3.0",
|
"eslint-plugin-import": "^2.3.0",
|
||||||
@ -53,6 +54,7 @@
|
|||||||
"imports-loader": "~0.7.1",
|
"imports-loader": "~0.7.1",
|
||||||
"jquery": "2.1.4",
|
"jquery": "2.1.4",
|
||||||
"jsdom": "3.1.2",
|
"jsdom": "3.1.2",
|
||||||
|
"json-loader": "^0.5.7",
|
||||||
"mocha": "2.2.1",
|
"mocha": "2.2.1",
|
||||||
"nib": "~1.1.2",
|
"nib": "~1.1.2",
|
||||||
"sinon": "1.14.1",
|
"sinon": "1.14.1",
|
||||||
|
21
readme.txt
21
readme.txt
@ -3,7 +3,7 @@ Contributors: mailpoet, wysija
|
|||||||
Tags: newsletter, email, welcome email, post notification, autoresponder, signup, subscription, SMTP
|
Tags: newsletter, email, welcome email, post notification, autoresponder, signup, subscription, SMTP
|
||||||
Requires at least: 4.6
|
Requires at least: 4.6
|
||||||
Tested up to: 4.8
|
Tested up to: 4.8
|
||||||
Stable tag: 3.0.0-rc.1.0.0
|
Stable tag: 3.0.0-rc.1.0.4
|
||||||
Create and send beautiful emails and newsletters from WordPress.
|
Create and send beautiful emails and newsletters from WordPress.
|
||||||
|
|
||||||
== Description ==
|
== Description ==
|
||||||
@ -93,6 +93,25 @@ Our [support site](https://beta.docs.mailpoet.com) has plenty of articles. You c
|
|||||||
|
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 3.0.0-rc.1.0.4 - 2017-08-22 =
|
||||||
|
* Added: newsletters can now be paused and edited while sending;
|
||||||
|
* Added: tooltips across the UI to quickly answer questions we often get on support;
|
||||||
|
* Added: extra measures to help prevent fake subscriptions by bots;
|
||||||
|
* Added: a hook to modify maximum post excerpt length;
|
||||||
|
* Fixed: it is possible again to switch to other sending methods after choosing MailPoet Sending Service. Thx Bastien!
|
||||||
|
|
||||||
|
= 3.0.0-rc.1.0.3 - 2017-08-15 =
|
||||||
|
* Improved: newsletter browser preview window in newsletter editor now fits correctly in any screen height;
|
||||||
|
* Improved: date shortcode displays WP time and is available to be translated into other laguages. Thanks Rik and Yves!
|
||||||
|
* Improved: rendered form body can be modified via a hook. Thanks, Vrodo;
|
||||||
|
* Fixed: subscriber export will not fail on hosts with PHP's set_time_limit() disabled. Thanks, @miguelarroyo;
|
||||||
|
|
||||||
|
= 3.0.0-rc.1.0.2 - 2017-08-08 =
|
||||||
|
* Fixed: correct error notice is displayed when using IIS server. Thanks @flauer!
|
||||||
|
|
||||||
|
= 3.0.0-rc.1.0.1 - 2017-08-02 =
|
||||||
|
* Fixed: we were so excited to come out of Beta, we forgot to include translation files. Woops :)
|
||||||
|
|
||||||
= 3.0.0-rc.1.0.0 - 2017-08-01 =
|
= 3.0.0-rc.1.0.0 - 2017-08-01 =
|
||||||
* Improved: MailPoet 3 is no longer in Beta!
|
* Improved: MailPoet 3 is no longer in Beta!
|
||||||
* Improved: blockquotes in posts are now displayed in emails; Thanks @newslines!
|
* Improved: blockquotes in posts are now displayed in emails; Thanks @newslines!
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash -e
|
||||||
|
|
||||||
echo "Getting translations from Transifex..."
|
echo "Getting translations from Transifex..."
|
||||||
tx pull -a -f
|
tx pull -a -f
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash -e
|
||||||
|
|
||||||
# Write ~/.transifexrc file if not exists
|
# Write ~/.transifexrc file if not exists
|
||||||
if [ ! -f ~/.transifexrc ]; then
|
if [ ! -f ~/.transifexrc ]; then
|
||||||
|
@ -29,4 +29,29 @@ class AcceptanceTester extends \Codeception\Actor {
|
|||||||
$this->click('Log In');
|
$this->click('Log In');
|
||||||
$this->saveSessionSnapshot('login');
|
$this->saveSessionSnapshot('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define custom actions here
|
||||||
|
*/
|
||||||
|
public function logOut() {
|
||||||
|
$I = $this;
|
||||||
|
$I->amOnPage('/wp-login.php?action=logout');
|
||||||
|
$I->click('log out');
|
||||||
|
$I->wait(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the specified Mailpoet page in the admin.
|
||||||
|
*
|
||||||
|
* @param string $page The page to visit e.g. Inbox or Status
|
||||||
|
*/
|
||||||
|
public function amOnMailpoetPage($page) {
|
||||||
|
$I = $this;
|
||||||
|
$I->amOnPage('/wp-admin');
|
||||||
|
$I->click('MailPoet');
|
||||||
|
$I->waitForText($page, 3);
|
||||||
|
$I->click($page);
|
||||||
|
$I->waitForText($page, 3);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
6
tests/acceptance.suite.yml
Normal file
6
tests/acceptance.suite.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
actor: AcceptanceTester
|
||||||
|
modules:
|
||||||
|
enabled:
|
||||||
|
- \Helper\Acceptance
|
||||||
|
- WPLoader
|
||||||
|
- WPWebDriver
|
15
tests/acceptance/NewsletterListingCept.php
Normal file
15
tests/acceptance/NewsletterListingCept.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Test summary: Test Newsletters page works
|
||||||
|
*
|
||||||
|
* Test details:
|
||||||
|
* - Open newsletters from the menu
|
||||||
|
*/
|
||||||
|
$I = new AcceptanceTester($scenario);
|
||||||
|
$I->wantTo('Open newsletters page');
|
||||||
|
|
||||||
|
$I->loginAsAdmin();
|
||||||
|
$I->seeInCurrentUrl('/wp-admin/');
|
||||||
|
// Go to Status
|
||||||
|
$I->amOnMailpoetPage('Emails');
|
||||||
|
$I->waitForElement('#newsletters_container', 3);
|
1
tests/acceptance/_bootstrap.php
Normal file
1
tests/acceptance/_bootstrap.php
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?php
|
@ -1,9 +1,9 @@
|
|||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
loadFileToContainer: function (path, window, containerTagName, options) {
|
loadFileToContainer: function (path, window, containerTagName, opts) {
|
||||||
var contents = fs.readFileSync(path),
|
var contents = fs.readFileSync(path),
|
||||||
container = window.document.createElement(containerTagName);
|
container = window.document.createElement(containerTagName);
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
container.innerHTML = contents;
|
container.innerHTML = contents;
|
||||||
|
|
||||||
if (options.type) {
|
if (options.type) {
|
||||||
@ -17,9 +17,9 @@ module.exports = {
|
|||||||
loadScript: function (scriptPath, window, options) {
|
loadScript: function (scriptPath, window, options) {
|
||||||
this.loadFileToContainer(scriptPath, window, 'script', options);
|
this.loadFileToContainer(scriptPath, window, 'script', options);
|
||||||
},
|
},
|
||||||
loadTemplate: function (path, window, options) {
|
loadTemplate: function (path, window, opts) {
|
||||||
var w = window || global.window;
|
var w = window || global.window;
|
||||||
options = options || {};
|
var options = opts || {};
|
||||||
options.type = "text/x-handlebars-template";
|
options.type = "text/x-handlebars-template";
|
||||||
|
|
||||||
this.loadScript("views/newsletter/templates/" + path, w, options);
|
this.loadScript("views/newsletter/templates/" + path, w, options);
|
||||||
|
@ -28,7 +28,9 @@ if (!global.document || !global.window) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global.testHelpers = require('./loadHelpers.js');
|
global.testHelpers = require('./loadHelpers.js');
|
||||||
global.$ = global.jQuery = global.window.jQuery = require('jquery');
|
global.$ = require('jquery');
|
||||||
|
global.jQuery = require('jquery');
|
||||||
|
global.window.jQuery = require('jquery');
|
||||||
|
|
||||||
testHelpers.loadScript('tests/javascript/testBundles/vendor.js', global.window);
|
testHelpers.loadScript('tests/javascript/testBundles/vendor.js', global.window);
|
||||||
global.Handlebars = global.window.Handlebars;
|
global.Handlebars = global.window.Handlebars;
|
||||||
@ -46,27 +48,28 @@ global.interact = function () {
|
|||||||
styleCursor: global.interact
|
styleCursor: global.interact
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
global.spectrum = function() { return this; };
|
||||||
jQuery.fn.spectrum = global.spectrum = function() { return this; };
|
jQuery.fn.spectrum = global.spectrum;
|
||||||
jQuery.fn.stick_in_parent = function() { return this; };
|
jQuery.fn.stick_in_parent = function() { return this; };
|
||||||
|
|
||||||
// Add global stubs for convenience
|
// Add global stubs for convenience
|
||||||
// TODO: Extract those to a separate file
|
// TODO: Extract those to a separate file
|
||||||
global.stubChannel = function (EditorApplication, returnObject) {
|
global.stubChannel = function (EditorApplication, returnObject) {
|
||||||
EditorApplication.getChannel = sinon.stub().returns(_.defaults(returnObject || {}, {
|
var App = EditorApplication;
|
||||||
|
App.getChannel = sinon.stub().returns(_.defaults(returnObject || {}, {
|
||||||
trigger: function () {
|
trigger: function () {
|
||||||
},
|
},
|
||||||
on: function () {
|
on: function () {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
global.stubConfig = function (EditorApplication, config) {
|
global.stubConfig = function (EditorApplication, opts) {
|
||||||
config = config || {};
|
var App = EditorApplication;
|
||||||
EditorApplication.getConfig = sinon.stub().returns(new Backbone.SuperModel(config));
|
App.getConfig = sinon.stub().returns(new Backbone.SuperModel(opts || {}));
|
||||||
};
|
};
|
||||||
global.stubAvailableStyles = function (EditorApplication, styles) {
|
global.stubAvailableStyles = function (EditorApplication, styles) {
|
||||||
styles = styles || {};
|
var App = EditorApplication;
|
||||||
EditorApplication.getAvailableStyles = sinon.stub().returns(new Backbone.SuperModel(styles));
|
App.getAvailableStyles = sinon.stub().returns(new Backbone.SuperModel(styles || {}));
|
||||||
};
|
};
|
||||||
|
|
||||||
global.stubImage = function(defaultWidth, defaultHeight) {
|
global.stubImage = function(defaultWidth, defaultHeight) {
|
||||||
|
@ -5,12 +5,14 @@ define([
|
|||||||
'amd-inject-loader!newsletter_editor/blocks/automatedLatestContent',
|
'amd-inject-loader!newsletter_editor/blocks/automatedLatestContent',
|
||||||
'newsletter_editor/components/communication'
|
'newsletter_editor/components/communication'
|
||||||
], function(
|
], function(
|
||||||
EditorApplication,
|
App,
|
||||||
AutomatedLatestContentBlock,
|
AutomatedLatestContentBlock,
|
||||||
ContainerBlock,
|
ContainerBlock,
|
||||||
AutomatedLatestContentInjector,
|
AutomatedLatestContentInjector,
|
||||||
CommunicationComponent
|
Communication
|
||||||
) {
|
) {
|
||||||
|
var EditorApplication = App;
|
||||||
|
var CommunicationComponent = Communication;
|
||||||
|
|
||||||
describe('Automated Latest Content Supervisor', function() {
|
describe('Automated Latest Content Supervisor', function() {
|
||||||
var model;
|
var model;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
define([
|
define([
|
||||||
'newsletter_editor/App',
|
'newsletter_editor/App',
|
||||||
'newsletter_editor/blocks/button'
|
'newsletter_editor/blocks/button'
|
||||||
], function(EditorApplication, ButtonBlock) {
|
], function(App, ButtonBlock) {
|
||||||
|
var EditorApplication = App;
|
||||||
|
|
||||||
describe("Button", function () {
|
describe("Button", function () {
|
||||||
describe("model", function () {
|
describe("model", function () {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
define([
|
define([
|
||||||
'newsletter_editor/App',
|
'newsletter_editor/App',
|
||||||
'newsletter_editor/blocks/container'
|
'newsletter_editor/blocks/container'
|
||||||
], function(EditorApplication, ContainerBlock) {
|
], function(App, ContainerBlock) {
|
||||||
|
var EditorApplication = App;
|
||||||
|
|
||||||
describe('Container', function () {
|
describe('Container', function () {
|
||||||
var ModelClass = ContainerBlock.ContainerBlockModel;
|
var ModelClass = ContainerBlock.ContainerBlockModel;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
define([
|
define([
|
||||||
'newsletter_editor/App',
|
'newsletter_editor/App',
|
||||||
'newsletter_editor/blocks/divider'
|
'newsletter_editor/blocks/divider'
|
||||||
], function(EditorApplication, DividerBlock) {
|
], function(App, DividerBlock) {
|
||||||
|
var EditorApplication = App;
|
||||||
|
|
||||||
describe("Divider", function () {
|
describe("Divider", function () {
|
||||||
describe("model", function () {
|
describe("model", function () {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user