Compare commits

...

34 Commits
3.0.5 ... 3.0.7

Author SHA1 Message Date
7b12affb77 Bumps up release version to 3.0.7 and updates changelog 2017-10-17 14:08:16 -04:00
0150e699a2 Merge pull request #1151 from mailpoet/oct17_poll_update
Updates weekly poll [MAILPOET-1170]
2017-10-17 17:06:39 +03:00
e6943e2638 Updates weekly poll 2017-10-17 09:34:04 -04:00
ac268c1ec9 Merge pull request #1150 from mailpoet/beacon_cron_url_update
Uses CronHelper's method to return cron ping URL in beacon [MAILPOET-1164]
2017-10-17 09:54:12 +03:00
1ef131fa2d Merge pull request #1149 from mailpoet/capabilities_fix
Fixes "Call to a member function add_cap() on null" error [MAILPOET-1169]
2017-10-17 09:46:48 +03:00
1873007550 Improve a unit test for non-existent roles' capabilities [MAILPOET-1169] 2017-10-17 09:35:50 +03:00
fa2ccb51c9 Uses CronHelper's method to return cron ping URL in beacon 2017-10-16 23:46:17 -04:00
8f87d654af Merge pull request #1148 from mailpoet/stats_cta
Add CTA links for detailed stats [MAILPOET-1152]
2017-10-16 23:33:10 -04:00
dee6e9fbad Fixes "Call to a member function add_cap() on null" error 2017-10-16 22:55:11 -04:00
ef90264316 Add CTA links for detailed stats [MAILPOET-1152] 2017-10-13 01:11:06 +03:00
70bf4be723 ESLint: Test rules 1
[MAILPOET-1134]
2017-10-12 15:36:40 +01:00
07ef727654 Merge pull request #1139 from mailpoet/throttling
Add progressive throttling of subscriptions from the same IP address [MAILPOET-1128]
2017-10-12 15:56:40 +02:00
5ce1eadde7 Merge pull request #1147 from mailpoet/honeypot-autofill
Subscription form honeypot gets filled by Autofill [MAILPOET-1163]
2017-10-12 16:52:22 +03:00
8a4d5395b1 Add attribute for Chrome
[MAILPOET-1163]
2017-10-12 14:38:45 +01:00
b5feed0f46 Remove WP subscribers with empty emails when syncing [MAILPOET-1158] 2017-10-12 10:31:11 +01:00
11f9579101 Don't synchronize WP users without emails [MAILPOET-1158] 2017-10-12 10:31:11 +01:00
0f6619e25d Merge pull request #1140 from mailpoet/svn_publish
Remove a dependency on WP in svn:publish command [MAILPOET-1156]
2017-10-11 13:21:10 +03:00
daf747d3be Throw an exception if plugin version could not be determined [MAILPOET-1156] 2017-10-11 13:07:53 +03:00
7393b1f2cf Remove a dependency on WP in svn:publish command [MAILPOET-1156] 2017-10-11 10:54:28 +03:00
efe861a9ba Merge pull request #1137 from mailpoet/eslint4
Eslint for tests [MAILPOET-1083]
2017-10-11 10:00:53 +03:00
2c358ab179 Add progressive throttling of subscriptions from the same IP address [MAILPOET-1128] 2017-10-10 19:36:20 +03:00
ca157fc91d Release 3.0.6 2017-10-10 16:46:37 +03:00
1fbe5d7bc6 Merge pull request #1138 from mailpoet/parsley
fixing missing parsley method [MAILPOET-1157]
2017-10-10 16:34:18 +03:00
71c031ccf9 fixing missing parsley method 2017-10-10 13:10:49 +00:00
6449b7ccca fixed minor issue 2017-10-10 09:29:22 +00:00
d6af88d667 Tests object-curly-spacing 2017-10-10 09:09:03 +00:00
b9184a202f Tests func-call-spacing 2017-10-10 09:09:03 +00:00
f898746967 Tests keyword-spacing 2017-10-10 09:09:03 +00:00
68165b7b78 Tests space-before-function-paren 2017-10-10 09:09:03 +00:00
bb8591a67b Tests space-before-blocks 2017-10-10 09:07:29 +00:00
bda71ae78e Tests space-unary-ops 2017-10-10 09:07:29 +00:00
abd4f6cac2 Tests no-spaced-func 2017-10-10 09:07:29 +00:00
87e6cc2a4f Tests no-whitespace-before-property 2017-10-10 09:07:29 +00:00
dde598eb64 rebasing on master 2017-10-10 09:07:29 +00:00
49 changed files with 701 additions and 392 deletions

View File

@ -8,21 +8,13 @@
"ecmaVersion": 6
},
"rules": {
"import/no-amd": 0,
"no-whitespace-before-property": 0,
"global-require": 0,
"keyword-spacing": 0,
// Exceptions
"func-names": 0,
// To add
"no-bitwise": 0,
"no-spaced-func": 0,
"func-call-spacing": 0,
"max-len": 0,
"space-unary-ops": 0,
"no-underscore-dangle": 0,
"no-shadow": 0,
"padded-blocks": 0,
"space-before-blocks": 0,
"object-curly-spacing": 0,
"func-names": 0,
"space-before-function-paren": 0
"padded-blocks": 0
}
}

View File

@ -289,15 +289,16 @@ class RoboFile extends \Robo\Tasks {
}
function svnPublish($opts = ['force' => false]) {
$this->loadWPFunctions();
$this->loadEnv();
$svn_dir = ".mp_svn";
$plugin_data = get_plugin_data('mailpoet.php', false, false);
$plugin_version = $plugin_data['Version'];
$plugin_dist_name = sanitize_title_with_dashes($plugin_data['Name']);
$plugin_dist_name = explode('-', $plugin_dist_name);
$plugin_dist_name = $plugin_dist_name[0];
$plugin_version = $this->getPluginVersion('mailpoet.php');
$plugin_dist_name = 'mailpoet';
$plugin_dist_file = $plugin_dist_name . '.zip';
if(!$plugin_version) {
throw new \Exception('Could not parse plugin version, check the plugin header');
}
$this->say('Publishing version: ' . $plugin_version);
// Sanity checks
@ -416,13 +417,9 @@ class RoboFile extends \Robo\Tasks {
$dotenv->load();
}
protected function loadWPFunctions() {
$this->loadEnv();
define('ABSPATH', getenv('WP_TEST_PATH') . '/');
define('WPINC', 'wp-includes');
require_once(ABSPATH . WPINC . '/functions.php');
require_once(ABSPATH . WPINC . '/formatting.php');
require_once(ABSPATH . WPINC . '/plugin.php');
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
protected function getPluginVersion($file) {
$data = file_get_contents($file);
preg_match('/^[ \t*]*Version:(.*)$/mi', $data, $m);
return !empty($m[1]) ? trim($m[1]) : false;
}
}

View File

@ -51,8 +51,7 @@ define([
.on('resizestart', function () {
that.isBeingResized = true;
that.$el.addClass('mailpoet_resize_active');
})
.on('resizemove', function (event) {
}).on('resizemove', function (event) {
var onResize = that.options.onResize.bind(that);
return onResize(event);
})

View File

@ -143,6 +143,13 @@ const _QueueMixin = {
},
};
const trackStatsCTAClicked = function () {
MailPoet.trackEvent(
'User has clicked a CTA to view detailed stats',
{ 'MailPoet Free version': window.mailpoet_version }
);
};
const _StatisticsMixin = {
renderStatistics: function (newsletter, is_sent, current_time) {
let sent = is_sent;
@ -159,6 +166,7 @@ const _StatisticsMixin = {
}
let params = {};
Hooks.addFilter('mailpoet_newsletters_listing_stats_before', this.addStatsCTALink);
params = Hooks.applyFilters('mailpoet_newsletters_listing_stats_before', params, newsletter);
// welcome emails provide explicit total_sent value
@ -282,18 +290,33 @@ const _StatisticsMixin = {
if (total_sent > 0 && params.link) {
// wrap content in a link
return (
<div>
<Link
key={`stats-${newsletter.id}`}
to={params.link}
onClick={params.onClick || null}
>
{content}
</Link>
{after_content}
</div>
);
if (params.externalLink) {
return (
<div>
<a
key={`stats-${newsletter.id}`}
href={params.link}
onClick={params.onClick || null}
>
{content}
</a>
{after_content}
</div>
);
} else {
return (
<div>
<Link
key={`stats-${newsletter.id}`}
to={params.link}
onClick={params.onClick || null}
>
{content}
</Link>
{after_content}
</div>
);
}
}
return (
@ -303,6 +326,37 @@ const _StatisticsMixin = {
</div>
);
},
addStatsCTAAction: function (actions) {
if (window.mailpoet_premium_active) {
return actions;
}
actions.unshift({
name: 'stats',
link: function () {
return (
<a href={'admin.php?page=mailpoet-premium'} onClick={trackStatsCTAClicked}>
{MailPoet.I18n.t('statsListingActionTitle')}
</a>
);
},
display: function (newsletter) {
// welcome emails provide explicit total_sent value
const count_processed = newsletter.queue && newsletter.queue.count_processed;
return ~~(newsletter.total_sent || count_processed) > 0;
},
});
return actions;
},
addStatsCTALink: function (params) {
if (window.mailpoet_premium_active) {
return params;
}
const newParams = params;
newParams.link = 'admin.php?page=mailpoet-premium';
newParams.externalLink = true;
newParams.onClick = trackStatsCTAClicked;
return newParams;
},
};
const _MailerMixin = {

View File

@ -52,6 +52,7 @@ let newsletter_actions = [
},
];
Hooks.addFilter('mailpoet_newsletters_listings_notification_history_actions', StatisticsMixin.addStatsCTAAction);
newsletter_actions = Hooks.applyFilters('mailpoet_newsletters_listings_notification_history_actions', newsletter_actions);
const NewsletterListNotificationHistory = React.createClass({

View File

@ -157,6 +157,7 @@ let newsletter_actions = [
},
];
Hooks.addFilter('mailpoet_newsletters_listings_standard_actions', StatisticsMixin.addStatsCTAAction);
newsletter_actions = Hooks.applyFilters('mailpoet_newsletters_listings_standard_actions', newsletter_actions);
const NewsletterListStandard = React.createClass({

View File

@ -124,6 +124,7 @@ let newsletter_actions = [
},
];
Hooks.addFilter('mailpoet_newsletters_listings_welcome_notification_actions', StatisticsMixin.addStatsCTAAction);
newsletter_actions = Hooks.applyFilters('mailpoet_newsletters_listings_welcome_notification_actions', newsletter_actions);
const NewsletterListWelcome = React.createClass({

View File

@ -1,6 +1,7 @@
define([
'mailpoet',
'jquery'
'jquery',
'parsleyjs'
],
function (
MailPoet,

View File

@ -10,7 +10,7 @@ use MailPoet\Form\Util\FieldNameObfuscator;
use MailPoet\Models\Form;
use MailPoet\Models\StatisticsForms;
use MailPoet\Models\Subscriber;
use MailPoet\Util\Helpers;
use MailPoet\Subscription\Throttling as SubscriptionThrottling;
if(!defined('ABSPATH')) exit;
@ -98,16 +98,10 @@ class Subscribers extends APIEndpoint {
$data = array_intersect_key($data, array_flip($form_fields));
// make sure we don't allow too many subscriptions with the same ip address
$subscription_count = Subscriber::where(
'subscribed_ip',
Helpers::getIP()
)->whereRaw(
'(TIME_TO_SEC(TIMEDIFF(NOW(), created_at)) < ? OR TIME_TO_SEC(TIMEDIFF(NOW(), updated_at)) < ?)',
array(self::SUBSCRIPTION_LIMIT_COOLDOWN, self::SUBSCRIPTION_LIMIT_COOLDOWN)
)->count();
$timeout = SubscriptionThrottling::throttle();
if($subscription_count > 0) {
throw new \Exception(__('You need to wait before subscribing again.', 'mailpoet'));
if($timeout > 0) {
throw new \Exception(sprintf(__('You need to wait %d seconds before subscribing again.', 'mailpoet'), $timeout));
}
$subscriber = Subscriber::subscribe($data, $segment_ids);

View File

@ -27,6 +27,7 @@ class Capabilities {
if(!isset($role_objects[$role])) {
$role_objects[$role] = get_role($role);
}
if(!is_object($role_objects[$role])) continue;
$role_objects[$role]->add_cap($name);
}
}
@ -40,6 +41,7 @@ class Capabilities {
if(!isset($role_objects[$role])) {
$role_objects[$role] = get_role($role);
}
if(!is_object($role_objects[$role])) continue;
$role_objects[$role]->remove_cap($name);
}
}

View File

@ -68,6 +68,7 @@ class Database {
$subscribers = Env::$db_prefix . 'subscribers';
$subscriber_segment = Env::$db_prefix . 'subscriber_segment';
$subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field';
$subscriber_ips = Env::$db_prefix . 'subscriber_ips';
$newsletter_segment = Env::$db_prefix . 'newsletter_segment';
$scheduled_tasks = Env::$db_prefix . 'scheduled_tasks';
$scheduled_task_subscribers = Env::$db_prefix . 'scheduled_task_subscribers';
@ -92,6 +93,7 @@ class Database {
define('MP_SUBSCRIBERS_TABLE', $subscribers);
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field);
define('MP_SUBSCRIBER_IPS_TABLE', $subscriber_ips);
define('MP_SCHEDULED_TASKS_TABLE', $scheduled_tasks);
define('MP_SCHEDULED_TASK_SUBSCRIBERS_TABLE', $scheduled_task_subscribers);
define('MP_SENDING_QUEUES_TABLE', $sending_queues);

View File

@ -529,6 +529,7 @@ class Menu {
);
$data['tracking_enabled'] = Setting::getValue('tracking.enabled');
$data['premium_plugin_active'] = License::getLicense();
wp_enqueue_script('jquery-ui');
wp_enqueue_script('jquery-ui-datepicker');

View File

@ -23,6 +23,7 @@ class Migrator {
'subscribers',
'subscriber_segment',
'subscriber_custom_field',
'subscriber_ips',
'newsletters',
'newsletter_templates',
'newsletter_option_fields',
@ -207,6 +208,16 @@ class Migrator {
return $this->sqlify(__FUNCTION__, $attributes);
}
function subscriberIps() {
$attributes = array(
'ip varchar(45) NOT NULL,',
'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,',
'PRIMARY KEY (created_at, ip),',
'KEY ip (ip)'
);
return $this->sqlify(__FUNCTION__, $attributes);
}
function newsletters() {
$attributes = array(
'id int(11) unsigned NOT NULL AUTO_INCREMENT,',

View File

@ -41,7 +41,7 @@ class Renderer {
static function renderBlocks($blocks = array(), $honeypot_enabled = true) {
// add honeypot for spambots
$html = ($honeypot_enabled) ?
'<label class="mailpoet_hp_email_label">' . __('Please leave this field empty', 'mailpoet') . '<input type="email" name="data[email]"></label>' :
'<label class="mailpoet_hp_email_label">' . __('Please leave this field empty', 'mailpoet') . '<input autocomplete="not-really-email" type="email" name="data[email]"></label>' :
'';
foreach($blocks as $key => $block) {
$html .= static::renderBlock($block) . PHP_EOL;

View File

@ -1,10 +1,11 @@
<?php
namespace MailPoet\Helpscout;
use MailPoet\Cron\CronHelper;
use MailPoet\Models\Subscriber;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber;
use MailPoet\Router\Endpoints\CronDaemon;
use MailPoet\Router\Router;
use MailPoet\Services\Bridge;
if(!defined('ABSPATH')) exit;
@ -16,11 +17,6 @@ class Beacon {
$mta = Setting::getValue('mta');
$current_theme = wp_get_theme();
$current_user = wp_get_current_user();
$cron_ping_url = Router::buildRequest(
CronDaemon::ENDPOINT,
CronDaemon::ACTION_PING
);
$cron_ping_url = str_replace(home_url(), CronHelper::getSiteUrl(), $cron_ping_url);
$premium_key = Setting::getValue(Bridge::PREMIUM_KEY_SETTING_NAME) ?: Setting::getValue(Bridge::API_KEY_SETTING_NAME);
return array(
'name' => $current_user->display_name,
@ -51,7 +47,9 @@ class Beacon {
$mta['frequency']['interval']
),
'Task Scheduler method' => Setting::getValue('cron_trigger.method'),
'Cron ping URL' => $cron_ping_url,
'Cron ping URL' => CronHelper::getCronUrl(
CronDaemon::ACTION_PING
),
'Default FROM address' => Setting::getValue('sender.address'),
'Default Reply-To address' => Setting::getValue('reply_to.address'),
'Bounce Email Address' => Setting::getValue('bounce.address'),

View File

@ -0,0 +1,8 @@
<?php
namespace MailPoet\Models;
if(!defined('ABSPATH')) exit;
class SubscriberIP extends Model {
public static $_table = MP_SUBSCRIBER_IPS_TABLE;
}

View File

@ -99,7 +99,7 @@ class WP {
UPDATE IGNORE %s
JOIN %s as wu ON %s.wp_user_id = wu.id
SET email = user_email
WHERE %s.wp_user_id IS NOT NULL
WHERE %s.wp_user_id IS NOT NULL AND wu.user_email != ""
', $subscribers_table, $wpdb->users, $subscribers_table, $subscribers_table));
}
@ -110,7 +110,7 @@ class WP {
INSERT IGNORE INTO %s(wp_user_id, email, status, created_at)
SELECT wu.id, wu.user_email, "subscribed", CURRENT_TIMESTAMP() FROM %s wu
LEFT JOIN %s mps ON wu.id = mps.wp_user_id
WHERE mps.wp_user_id IS NULL
WHERE mps.wp_user_id IS NULL AND wu.user_email != ""
ON DUPLICATE KEY UPDATE wp_user_id = wu.id
', $subscribers_table, $wpdb->users, $subscribers_table));
}
@ -180,7 +180,7 @@ class WP {
$wp_segment->subscribers()
->leftOuterJoin($wpdb->users, array(MP_SUBSCRIBERS_TABLE . '.wp_user_id', '=', 'wu.id'), 'wu')
->whereNull('wu.id')
->whereRaw('(wu.id IS NULL OR ' . MP_SUBSCRIBERS_TABLE . '.email = "")')
->findResultSet()
->set('wp_user_id', null)
->delete();

View File

@ -0,0 +1,55 @@
<?php
namespace MailPoet\Subscription;
use MailPoet\Models\SubscriberIP;
use MailPoet\Util\Helpers;
use MailPoet\WP\Hooks;
class Throttling {
static function throttle() {
$subscription_limit_enabled = Hooks::applyFilters('mailpoet_subscription_limit_enabled', true);
$subscription_limit_window = Hooks::applyFilters('mailpoet_subscription_limit_window', DAY_IN_SECONDS);
$subscription_limit_base = Hooks::applyFilters('mailpoet_subscription_limit_base', MINUTE_IN_SECONDS);
$subscriber_ip = Helpers::getIP();
if($subscription_limit_enabled && !is_user_logged_in()) {
if(!empty($subscriber_ip)) {
$subscription_count = SubscriberIP::where('ip', $subscriber_ip)
->whereRaw(
'(`created_at` >= NOW() - INTERVAL ? SECOND)',
array((int)$subscription_limit_window)
)->count();
if($subscription_count > 0) {
$timeout = $subscription_limit_base * pow(2, $subscription_count - 1);
$existing_user = SubscriberIP::where('ip', $subscriber_ip)
->whereRaw(
'(`created_at` >= NOW() - INTERVAL ? SECOND)',
array((int)$timeout)
)->findOne();
if(!empty($existing_user)) {
return $timeout;
}
}
}
}
$ip = SubscriberIP::create();
$ip->ip = $subscriber_ip;
$ip->save();
self::purge($subscription_limit_window);
return false;
}
static function purge($interval) {
return SubscriberIP::whereRaw(
'(`created_at` < NOW() - INTERVAL ? SECOND)',
array($interval)
)->deleteMany();
}
}

View File

@ -10,6 +10,10 @@ class Hooks {
return self::callWithFallback('apply_filters', func_get_args());
}
static function removeFilter() {
return self::callWithFallback('remove_filter', func_get_args());
}
static function addAction() {
return self::callWithFallback('add_action', func_get_args());
}
@ -18,6 +22,10 @@ class Hooks {
return self::callWithFallback('do_action', func_get_args());
}
static function removeAction() {
return self::callWithFallback('remove_action', func_get_args());
}
private static function callWithFallback($func, $args) {
$local_func = __NAMESPACE__ . '\\' . $func;
if(function_exists($local_func)) {

View File

@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
/*
* Plugin Name: MailPoet 3 (new)
* Version: 3.0.5
* Version: 3.0.7
* Plugin URI: http://www.mailpoet.com
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
* Author: MailPoet
@ -20,7 +20,7 @@ if(!defined('ABSPATH')) exit;
*/
$mailpoet_plugin = array(
'version' => '3.0.5',
'version' => '3.0.7',
'filename' => __FILE__,
'path' => dirname(__FILE__),
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',

View File

@ -4,7 +4,7 @@ Tags: newsletter, email, welcome email, post notification, autoresponder, signup
Requires at least: 4.6
Tested up to: 4.8
Requires PHP: 5.3
Stable tag: 3.0.5
Stable tag: 3.0.7
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@ -114,6 +114,15 @@ Stop by our [support site](https://www.mailpoet.com/support).
== Changelog ==
= 3.0.7 - 2017-10-17 =
* Improved: subscribing from the same IP address is progressively throttled. Thanks Suyog Palav, Piyush Kumar and Bits of Freedom!
* Fixed: WordPress users without an email address will not be added as subscribers;
* Fixed: bug asking subscribers to leave the first field empty in MailPoet subscription forms;
* Fixed: plugin no longer fails to activate on sites when certain user roles do not exist. Thanks to all who reported this!
= 3.0.6 - 2017-10-10 =
* Fixed: subscription forms to not throw form validation engine errors;
= 3.0.5 - 2017-10-10 =
* Added: images can now be aligned left, center or right in email designer;

View File

@ -25,6 +25,7 @@ $models = array(
'Subscriber',
'SubscriberCustomField',
'SubscriberSegment',
'SubscriberIP',
'StatisticsOpens',
'StatisticsClicks',
'StatisticsNewsletters',

View File

@ -52,9 +52,9 @@ global.interact = function () {
styleCursor: global.interact
};
};
global.spectrum = function() { return this; };
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
// TODO: Extract those to a separate file
@ -78,18 +78,18 @@ global.stubAvailableStyles = function (EditorApplication, styles) {
App.getAvailableStyles = sinon.stub().returns(new global.Backbone.SuperModel(styles || {}));
};
global.stubImage = function(defaultWidth, defaultHeight) {
global.Image = function() {
this.onload = function() {};
global.stubImage = function (defaultWidth, defaultHeight) {
global.Image = function () {
this.onload = function () {};
this.naturalWidth = defaultWidth;
this.naturalHeight = defaultHeight;
this.address = '';
Object.defineProperty(this, 'src', {
get: function() {
get: function () {
return this.address;
},
set: function(src) {
set: function (src) {
this.address = src;
this.onload();
}
@ -98,73 +98,73 @@ global.stubImage = function(defaultWidth, defaultHeight) {
};
testHelpers.loadTemplate('blocks/base/toolsGeneric.hbs', window, {id: 'newsletter_editor_template_tools_generic'});
testHelpers.loadTemplate('blocks/base/toolsGeneric.hbs', window, { id: 'newsletter_editor_template_tools_generic' });
testHelpers.loadTemplate('blocks/automatedLatestContent/block.hbs', window, {id: 'newsletter_editor_template_automated_latest_content_block'});
testHelpers.loadTemplate('blocks/automatedLatestContent/widget.hbs', window, {id: 'newsletter_editor_template_automated_latest_content_widget'});
testHelpers.loadTemplate('blocks/automatedLatestContent/settings.hbs', window, {id: 'newsletter_editor_template_automated_latest_content_settings'});
testHelpers.loadTemplate('blocks/automatedLatestContent/block.hbs', window, { id: 'newsletter_editor_template_automated_latest_content_block' });
testHelpers.loadTemplate('blocks/automatedLatestContent/widget.hbs', window, { id: 'newsletter_editor_template_automated_latest_content_widget' });
testHelpers.loadTemplate('blocks/automatedLatestContent/settings.hbs', window, { id: 'newsletter_editor_template_automated_latest_content_settings' });
testHelpers.loadTemplate('blocks/button/block.hbs', window, {id: 'newsletter_editor_template_button_block'});
testHelpers.loadTemplate('blocks/button/widget.hbs', window, {id: 'newsletter_editor_template_button_widget'});
testHelpers.loadTemplate('blocks/button/settings.hbs', window, {id: 'newsletter_editor_template_button_settings'});
testHelpers.loadTemplate('blocks/button/block.hbs', window, { id: 'newsletter_editor_template_button_block' });
testHelpers.loadTemplate('blocks/button/widget.hbs', window, { id: 'newsletter_editor_template_button_widget' });
testHelpers.loadTemplate('blocks/button/settings.hbs', window, { id: 'newsletter_editor_template_button_settings' });
testHelpers.loadTemplate('blocks/container/block.hbs', window, {id: 'newsletter_editor_template_container_block'});
testHelpers.loadTemplate('blocks/container/emptyBlock.hbs', window, {id: 'newsletter_editor_template_container_block_empty'});
testHelpers.loadTemplate('blocks/container/oneColumnLayoutWidget.hbs', window, {id: 'newsletter_editor_template_container_one_column_widget'});
testHelpers.loadTemplate('blocks/container/twoColumnLayoutWidget.hbs', window, {id: 'newsletter_editor_template_container_two_column_widget'});
testHelpers.loadTemplate('blocks/container/threeColumnLayoutWidget.hbs', window, {id: 'newsletter_editor_template_container_three_column_widget'});
testHelpers.loadTemplate('blocks/container/settings.hbs', window, {id: 'newsletter_editor_template_container_settings'});
testHelpers.loadTemplate('blocks/container/columnSettings.hbs', window, {id: 'newsletter_editor_template_container_column_settings'});
testHelpers.loadTemplate('blocks/container/block.hbs', window, { id: 'newsletter_editor_template_container_block' });
testHelpers.loadTemplate('blocks/container/emptyBlock.hbs', window, { id: 'newsletter_editor_template_container_block_empty' });
testHelpers.loadTemplate('blocks/container/oneColumnLayoutWidget.hbs', window, { id: 'newsletter_editor_template_container_one_column_widget' });
testHelpers.loadTemplate('blocks/container/twoColumnLayoutWidget.hbs', window, { id: 'newsletter_editor_template_container_two_column_widget' });
testHelpers.loadTemplate('blocks/container/threeColumnLayoutWidget.hbs', window, { id: 'newsletter_editor_template_container_three_column_widget' });
testHelpers.loadTemplate('blocks/container/settings.hbs', window, { id: 'newsletter_editor_template_container_settings' });
testHelpers.loadTemplate('blocks/container/columnSettings.hbs', window, { id: 'newsletter_editor_template_container_column_settings' });
testHelpers.loadTemplate('blocks/divider/block.hbs', window, {id: 'newsletter_editor_template_divider_block'});
testHelpers.loadTemplate('blocks/divider/widget.hbs', window, {id: 'newsletter_editor_template_divider_widget'});
testHelpers.loadTemplate('blocks/divider/settings.hbs', window, {id: 'newsletter_editor_template_divider_settings'});
testHelpers.loadTemplate('blocks/divider/block.hbs', window, { id: 'newsletter_editor_template_divider_block' });
testHelpers.loadTemplate('blocks/divider/widget.hbs', window, { id: 'newsletter_editor_template_divider_widget' });
testHelpers.loadTemplate('blocks/divider/settings.hbs', window, { id: 'newsletter_editor_template_divider_settings' });
testHelpers.loadTemplate('blocks/footer/block.hbs', window, {id: 'newsletter_editor_template_footer_block'});
testHelpers.loadTemplate('blocks/footer/widget.hbs', window, {id: 'newsletter_editor_template_footer_widget'});
testHelpers.loadTemplate('blocks/footer/settings.hbs', window, {id: 'newsletter_editor_template_footer_settings'});
testHelpers.loadTemplate('blocks/footer/block.hbs', window, { id: 'newsletter_editor_template_footer_block' });
testHelpers.loadTemplate('blocks/footer/widget.hbs', window, { id: 'newsletter_editor_template_footer_widget' });
testHelpers.loadTemplate('blocks/footer/settings.hbs', window, { id: 'newsletter_editor_template_footer_settings' });
testHelpers.loadTemplate('blocks/header/block.hbs', window, {id: 'newsletter_editor_template_header_block'});
testHelpers.loadTemplate('blocks/header/widget.hbs', window, {id: 'newsletter_editor_template_header_widget'});
testHelpers.loadTemplate('blocks/header/settings.hbs', window, {id: 'newsletter_editor_template_header_settings'});
testHelpers.loadTemplate('blocks/header/block.hbs', window, { id: 'newsletter_editor_template_header_block' });
testHelpers.loadTemplate('blocks/header/widget.hbs', window, { id: 'newsletter_editor_template_header_widget' });
testHelpers.loadTemplate('blocks/header/settings.hbs', window, { id: 'newsletter_editor_template_header_settings' });
testHelpers.loadTemplate('blocks/image/block.hbs', window, {id: 'newsletter_editor_template_image_block'});
testHelpers.loadTemplate('blocks/image/widget.hbs', window, {id: 'newsletter_editor_template_image_widget'});
testHelpers.loadTemplate('blocks/image/settings.hbs', window, {id: 'newsletter_editor_template_image_settings'});
testHelpers.loadTemplate('blocks/image/block.hbs', window, { id: 'newsletter_editor_template_image_block' });
testHelpers.loadTemplate('blocks/image/widget.hbs', window, { id: 'newsletter_editor_template_image_widget' });
testHelpers.loadTemplate('blocks/image/settings.hbs', window, { id: 'newsletter_editor_template_image_settings' });
testHelpers.loadTemplate('blocks/posts/block.hbs', window, {id: 'newsletter_editor_template_posts_block'});
testHelpers.loadTemplate('blocks/posts/widget.hbs', window, {id: 'newsletter_editor_template_posts_widget'});
testHelpers.loadTemplate('blocks/posts/settings.hbs', window, {id: 'newsletter_editor_template_posts_settings'});
testHelpers.loadTemplate('blocks/posts/settingsDisplayOptions.hbs', window, {id: 'newsletter_editor_template_posts_settings_display_options'});
testHelpers.loadTemplate('blocks/posts/settingsSelection.hbs', window, {id: 'newsletter_editor_template_posts_settings_selection'});
testHelpers.loadTemplate('blocks/posts/settingsSelectionEmpty.hbs', window, {id: 'newsletter_editor_template_posts_settings_selection_empty'});
testHelpers.loadTemplate('blocks/posts/settingsSinglePost.hbs', window, {id: 'newsletter_editor_template_posts_settings_single_post'});
testHelpers.loadTemplate('blocks/posts/block.hbs', window, { id: 'newsletter_editor_template_posts_block' });
testHelpers.loadTemplate('blocks/posts/widget.hbs', window, { id: 'newsletter_editor_template_posts_widget' });
testHelpers.loadTemplate('blocks/posts/settings.hbs', window, { id: 'newsletter_editor_template_posts_settings' });
testHelpers.loadTemplate('blocks/posts/settingsDisplayOptions.hbs', window, { id: 'newsletter_editor_template_posts_settings_display_options' });
testHelpers.loadTemplate('blocks/posts/settingsSelection.hbs', window, { id: 'newsletter_editor_template_posts_settings_selection' });
testHelpers.loadTemplate('blocks/posts/settingsSelectionEmpty.hbs', window, { id: 'newsletter_editor_template_posts_settings_selection_empty' });
testHelpers.loadTemplate('blocks/posts/settingsSinglePost.hbs', window, { id: 'newsletter_editor_template_posts_settings_single_post' });
testHelpers.loadTemplate('blocks/social/block.hbs', window, {id: 'newsletter_editor_template_social_block'});
testHelpers.loadTemplate('blocks/social/blockIcon.hbs', window, {id: 'newsletter_editor_template_social_block_icon'});
testHelpers.loadTemplate('blocks/social/widget.hbs', window, {id: 'newsletter_editor_template_social_widget'});
testHelpers.loadTemplate('blocks/social/settings.hbs', window, {id: 'newsletter_editor_template_social_settings'});
testHelpers.loadTemplate('blocks/social/settingsIcon.hbs', window, {id: 'newsletter_editor_template_social_settings_icon'});
testHelpers.loadTemplate('blocks/social/settingsIconSelector.hbs', window, {id: 'newsletter_editor_template_social_settings_icon_selector'});
testHelpers.loadTemplate('blocks/social/settingsStyles.hbs', window, {id: 'newsletter_editor_template_social_settings_styles'});
testHelpers.loadTemplate('blocks/social/block.hbs', window, { id: 'newsletter_editor_template_social_block' });
testHelpers.loadTemplate('blocks/social/blockIcon.hbs', window, { id: 'newsletter_editor_template_social_block_icon' });
testHelpers.loadTemplate('blocks/social/widget.hbs', window, { id: 'newsletter_editor_template_social_widget' });
testHelpers.loadTemplate('blocks/social/settings.hbs', window, { id: 'newsletter_editor_template_social_settings' });
testHelpers.loadTemplate('blocks/social/settingsIcon.hbs', window, { id: 'newsletter_editor_template_social_settings_icon' });
testHelpers.loadTemplate('blocks/social/settingsIconSelector.hbs', window, { id: 'newsletter_editor_template_social_settings_icon_selector' });
testHelpers.loadTemplate('blocks/social/settingsStyles.hbs', window, { id: 'newsletter_editor_template_social_settings_styles' });
testHelpers.loadTemplate('blocks/spacer/block.hbs', window, {id: 'newsletter_editor_template_spacer_block'});
testHelpers.loadTemplate('blocks/spacer/widget.hbs', window, {id: 'newsletter_editor_template_spacer_widget'});
testHelpers.loadTemplate('blocks/spacer/settings.hbs', window, {id: 'newsletter_editor_template_spacer_settings'});
testHelpers.loadTemplate('blocks/spacer/block.hbs', window, { id: 'newsletter_editor_template_spacer_block' });
testHelpers.loadTemplate('blocks/spacer/widget.hbs', window, { id: 'newsletter_editor_template_spacer_widget' });
testHelpers.loadTemplate('blocks/spacer/settings.hbs', window, { id: 'newsletter_editor_template_spacer_settings' });
testHelpers.loadTemplate('blocks/text/block.hbs', window, {id: 'newsletter_editor_template_text_block'});
testHelpers.loadTemplate('blocks/text/widget.hbs', window, {id: 'newsletter_editor_template_text_widget'});
testHelpers.loadTemplate('blocks/text/settings.hbs', window, {id: 'newsletter_editor_template_text_settings'});
testHelpers.loadTemplate('blocks/text/block.hbs', window, { id: 'newsletter_editor_template_text_block' });
testHelpers.loadTemplate('blocks/text/widget.hbs', window, { id: 'newsletter_editor_template_text_widget' });
testHelpers.loadTemplate('blocks/text/settings.hbs', window, { id: 'newsletter_editor_template_text_settings' });
testHelpers.loadTemplate('components/heading.hbs', window, {id: 'newsletter_editor_template_heading'});
testHelpers.loadTemplate('components/save.hbs', window, {id: 'newsletter_editor_template_save'});
testHelpers.loadTemplate('components/styles.hbs', window, {id: 'newsletter_editor_template_styles'});
testHelpers.loadTemplate('components/heading.hbs', window, { id: 'newsletter_editor_template_heading' });
testHelpers.loadTemplate('components/save.hbs', window, { id: 'newsletter_editor_template_save' });
testHelpers.loadTemplate('components/styles.hbs', window, { id: 'newsletter_editor_template_styles' });
testHelpers.loadTemplate('components/sidebar/sidebar.hbs', window, {id: 'newsletter_editor_template_sidebar'});
testHelpers.loadTemplate('components/sidebar/content.hbs', window, {id: 'newsletter_editor_template_sidebar_content'});
testHelpers.loadTemplate('components/sidebar/layout.hbs', window, {id: 'newsletter_editor_template_sidebar_layout'});
testHelpers.loadTemplate('components/sidebar/preview.hbs', window, {id: 'newsletter_editor_template_sidebar_preview'});
testHelpers.loadTemplate('components/sidebar/styles.hbs', window, {id: 'newsletter_editor_template_sidebar_styles'});
testHelpers.loadTemplate('components/sidebar/sidebar.hbs', window, { id: 'newsletter_editor_template_sidebar' });
testHelpers.loadTemplate('components/sidebar/content.hbs', window, { id: 'newsletter_editor_template_sidebar_content' });
testHelpers.loadTemplate('components/sidebar/layout.hbs', window, { id: 'newsletter_editor_template_sidebar_layout' });
testHelpers.loadTemplate('components/sidebar/preview.hbs', window, { id: 'newsletter_editor_template_sidebar_preview' });
testHelpers.loadTemplate('components/sidebar/styles.hbs', window, { id: 'newsletter_editor_template_sidebar_styles' });
global.templates = {

View File

@ -9,7 +9,7 @@ define([
'newsletter_editor/blocks/container',
'amd-inject-loader!newsletter_editor/blocks/automatedLatestContent',
'newsletter_editor/components/communication'
], function(
], function (
App,
AutomatedLatestContentBlock,
ContainerBlock,
@ -19,19 +19,19 @@ define([
var EditorApplication = App;
var CommunicationComponent = Communication;
describe('Automated Latest Content Supervisor', function() {
describe('Automated Latest Content Supervisor', function () {
var model;
var mock;
var module;
beforeEach(function() {
beforeEach(function () {
model = new AutomatedLatestContentBlock.ALCSupervisor();
});
it('fetches posts in bulk from the server', function() {
it('fetches posts in bulk from the server', function () {
global.stubChannel(EditorApplication);
EditorApplication.findModels = sinon.stub().returns([new Backbone.SuperModel()]);
mock = sinon.mock({ getBulkTransformedPosts: function() {} })
mock = sinon.mock({ getBulkTransformedPosts: function () {} })
.expects('getBulkTransformedPosts').once().returns(jQuery.Deferred());
module = AutomatedLatestContentInjector({
@ -46,7 +46,7 @@ define([
mock.verify();
});
it('refreshes posts for given blocks', function() {
it('refreshes posts for given blocks', function () {
var block1 = new Backbone.SuperModel();
var block2 = new Backbone.SuperModel();
var postsSet1 = [
@ -74,7 +74,7 @@ define([
var model;
var module;
before(function() {
before(function () {
module = AutomatedLatestContentBlock;
});
@ -254,7 +254,7 @@ define([
expect(model.get('divider.styles.block.padding')).to.equal('38px');
});
it('accepts displayable posts', function() {
it('accepts displayable posts', function () {
var model;
EditorApplication.getBlockTypeModel = sinon.stub().returns(ContainerBlock.ContainerBlockModel);
model = new (module.AutomatedLatestContentBlockModel)();
@ -273,7 +273,7 @@ define([
var view;
var module;
before(function() {
before(function () {
module = AutomatedLatestContentBlock;
});
@ -283,7 +283,7 @@ define([
EditorApplication.getBlockTypeModel = sinon.stub().returns(Backbone.Model);
EditorApplication.getBlockTypeView = sinon.stub().returns(Backbone.View);
model = new (module.AutomatedLatestContentBlockModel)();
view = new (module.AutomatedLatestContentBlockView)({model: model});
view = new (module.AutomatedLatestContentBlockView)({ model: model });
});
afterEach(function () {
@ -302,11 +302,11 @@ define([
beforeEach(function () {
onStub = sinon.stub();
global.stubChannel(EditorApplication, {on: onStub});
global.stubChannel(EditorApplication, { on: onStub });
global.stubConfig(EditorApplication);
EditorApplication.getBlockTypeModel = sinon.stub().returns(Backbone.Model);
EditorApplication.getBlockTypeView = sinon.stub().returns(Backbone.View);
view = new (AutomatedLatestContentBlock.AutomatedLatestContentBlockView)({model: {set: sinon.stub()}});
view = new (AutomatedLatestContentBlock.AutomatedLatestContentBlockView)({ model: { set: sinon.stub() } });
});
it('listens to the event', function () {
@ -334,10 +334,10 @@ define([
var view;
var module;
before(function() {
before(function () {
module = AutomatedLatestContentInjector({
'newsletter_editor/components/communication': {
getPostTypes: function() {
getPostTypes: function () {
return jQuery.Deferred();
}
}
@ -345,7 +345,7 @@ define([
});
before(function () {
CommunicationComponent.getPostTypes = function() {
CommunicationComponent.getPostTypes = function () {
var deferred = jQuery.Deferred();
deferred.resolve([
{
@ -378,9 +378,9 @@ define([
EditorApplication.getBlockTypeView = sinon.stub().returns(Backbone.View);
});
beforeEach(function() {
beforeEach(function () {
model = new (module.AutomatedLatestContentBlockModel)();
view = new (module.AutomatedLatestContentBlockSettingsView)({model: model});
view = new (module.AutomatedLatestContentBlockSettingsView)({ model: model });
});
after(function () {
@ -392,9 +392,9 @@ define([
});
describe('once rendered', function () {
beforeEach(function() {
beforeEach(function () {
model = new (module.AutomatedLatestContentBlockModel)();
view = new (module.AutomatedLatestContentBlockSettingsView)({model: model});
view = new (module.AutomatedLatestContentBlockSettingsView)({ model: model });
view.render();
});
@ -500,12 +500,12 @@ define([
expect(model.get('showDivider')).to.equal(newValue);
});
describe('when "title only" display type is selected', function() {
describe('when "title only" display type is selected', function () {
var model;
var view;
beforeEach(function() {
beforeEach(function () {
model = new (module.AutomatedLatestContentBlockModel)();
view = new (module.AutomatedLatestContentBlockSettingsView)({model: model});
view = new (module.AutomatedLatestContentBlockSettingsView)({ model: model });
view.render();
view.$('.mailpoet_automated_latest_content_display_type').val('titleOnly').change();
});
@ -514,12 +514,12 @@ define([
expect(view.$('.mailpoet_automated_latest_content_title_as_list')).to.not.have.$class('mailpoet_hidden');
});
describe('when "title as list" is selected', function() {
describe('when "title as list" is selected', function () {
var model;
var view;
beforeEach(function() {
beforeEach(function () {
model = new (module.AutomatedLatestContentBlockModel)();
view = new (module.AutomatedLatestContentBlockSettingsView)({model: model});
view = new (module.AutomatedLatestContentBlockSettingsView)({ model: model });
view.render();
view.$('.mailpoet_automated_latest_content_display_type').val('titleOnly').change();
view.$('.mailpoet_automated_latest_content_title_format').val('ul').change();
@ -530,14 +530,14 @@ define([
expect(view.$('.mailpoet_automated_latest_content_title_as_link')).to.have.$class('mailpoet_hidden');
});
it('is set to "yes"', function() {
it('is set to "yes"', function () {
expect(model.get('titleIsLink')).to.equal(true);
});
});
});
describe('when "title as list" is deselected', function() {
before(function() {
describe('when "title as list" is deselected', function () {
before(function () {
view.$('.mailpoet_automated_latest_content_title_format').val('ul').change();
view.$('.mailpoet_automated_latest_content_title_format').val('h3').change();
});
@ -555,7 +555,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -4,7 +4,7 @@ const sinon = global.sinon;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/button'
], function(App, ButtonBlock) {
], function (App, ButtonBlock) {
var EditorApplication = App;
describe('Button', function () {
@ -20,7 +20,7 @@ define([
});
afterEach(function () {
if(EditorApplication.getChannel) {
if (EditorApplication.getChannel) {
delete EditorApplication.getChannel;
}
});
@ -159,13 +159,13 @@ define([
});
it('renders', function () {
var view = new (ButtonBlock.ButtonBlockView)({model: model});
var view = new (ButtonBlock.ButtonBlockView)({ model: model });
expect(view.render).to.not.throw();
expect(view.$('.mailpoet_editor_button')).to.have.length(1);
});
it('rerenders when attributes change', function () {
var view = new (ButtonBlock.ButtonBlockView)({model: model});
var view = new (ButtonBlock.ButtonBlockView)({ model: model });
view.render();
model.set('text', 'Some new text');
@ -198,7 +198,7 @@ define([
}
}
});
view = new (ButtonBlock.ButtonBlockView)({model: model});
view = new (ButtonBlock.ButtonBlockView)({ model: model });
view.render();
});
@ -272,9 +272,9 @@ define([
beforeEach(function () {
onStub = sinon.stub();
global.stubChannel(EditorApplication, {on: onStub});
model = {set: sinon.stub(), toJSON: sinon.stub()};
view = new (ButtonBlock.ButtonBlockView)({model: model});
global.stubChannel(EditorApplication, { on: onStub });
model = { set: sinon.stub(), toJSON: sinon.stub() };
view = new (ButtonBlock.ButtonBlockView)({ model: model });
view.render();
});
@ -315,14 +315,14 @@ define([
});
it('renders', function () {
var view = new (ButtonBlock.ButtonBlockSettingsView)({model: model});
var view = new (ButtonBlock.ButtonBlockSettingsView)({ model: model });
expect(view.render).to.not.throw();
});
describe('once rendered', function () {
var model;
var view;
before(function() {
before(function () {
global.stubChannel(EditorApplication);
global.stubConfig(EditorApplication);
global.stubAvailableStyles(EditorApplication, {
@ -331,12 +331,12 @@ define([
});
});
beforeEach(function() {
beforeEach(function () {
model = new (ButtonBlock.ButtonBlockModel)({
type: 'button',
text: 'Some random text'
});
view = new (ButtonBlock.ButtonBlockSettingsView)({model: model});
view = new (ButtonBlock.ButtonBlockSettingsView)({ model: model });
view.render();
});
@ -453,7 +453,7 @@ define([
expect(view.$('.mailpoet_field_button_line_height_input').val()).to.equal('37');
});
it('does not display link option when `hideLink` option is active', function() {
it('does not display link option when `hideLink` option is active', function () {
view = new (ButtonBlock.ButtonBlockSettingsView)({
model: model,
renderOptions: {
@ -464,7 +464,7 @@ define([
expect(view.$('.mailpoet_field_button_url').length).to.equal(0);
});
it('does not display "Apply to all" option when `hideApplyToAll` option is active', function() {
it('does not display "Apply to all" option when `hideApplyToAll` option is active', function () {
view = new (ButtonBlock.ButtonBlockSettingsView)({
model: model,
renderOptions: {
@ -480,7 +480,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -5,7 +5,7 @@ const Backbone = global.Backbone;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/container'
], function(App, ContainerBlock) {
], function (App, ContainerBlock) {
var EditorApplication = App;
describe('Container', function () {
@ -65,7 +65,7 @@ define([
model = new (ContainerBlock.ContainerBlockModel)({
type: 'container',
blocks: [testModel]
}, {parse: true});
}, { parse: true });
expect(model.get('blocks')).to.have.length(1);
expect(model.get('blocks').at(0).get('type')).to.equal(testModel.type);
@ -95,7 +95,7 @@ define([
]
}
]
}, {parse: true});
}, { parse: true });
expect(model.get('blocks')).to.have.length(1);
expect(model.get('blocks').at(0).get('blocks')).to.have.length(2);
@ -114,7 +114,7 @@ define([
global.stubChannel(EditorApplication);
global.stubAvailableStyles(EditorApplication);
model = new (ContainerBlock.ContainerBlockModel)();
view = new (ContainerBlock.ContainerBlockView)({model: model});
view = new (ContainerBlock.ContainerBlockView)({ model: model });
it('renders', function () {
expect(view.render).to.not.throw();
@ -196,7 +196,7 @@ define([
global.stubChannel(EditorApplication);
global.stubAvailableStyles(EditorApplication);
model = new (ContainerBlock.ContainerBlockModel)();
view = new (ContainerBlock.ContainerBlockSettingsView)({model: model});
view = new (ContainerBlock.ContainerBlockSettingsView)({ model: model });
it('renders', function () {
expect(view.render).to.not.throw();
@ -205,11 +205,11 @@ define([
describe('once rendered', function () {
var model;
var view;
beforeEach(function() {
beforeEach(function () {
global.stubChannel(EditorApplication);
global.stubAvailableStyles(EditorApplication);
model = new (ContainerBlock.ContainerBlockModel)();
view = new (ContainerBlock.ContainerBlockSettingsView)({model: model});
view = new (ContainerBlock.ContainerBlockSettingsView)({ model: model });
});
it('updates the model when background color changes', function () {
@ -222,7 +222,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -4,7 +4,7 @@ const sinon = global.sinon;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/divider'
], function(App, DividerBlock) {
], function (App, DividerBlock) {
var EditorApplication = App;
describe('Divider', function () {
@ -104,7 +104,7 @@ define([
global.stubChannel(EditorApplication);
global.stubConfig(EditorApplication);
model = new (DividerBlock.DividerBlockModel)();
view = new (DividerBlock.DividerBlockView)({model: model});
view = new (DividerBlock.DividerBlockView)({ model: model });
});
it('renders', function () {
@ -146,7 +146,7 @@ define([
dividers: ['solid', 'inset']
});
model = new (DividerBlock.DividerBlockModel)();
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
view = new (DividerBlock.DividerBlockSettingsView)({ model: model });
it('renders', function () {
expect(view.render).to.not.throw();
@ -157,7 +157,7 @@ define([
var model;
var view;
before(function() {
before(function () {
global.stubChannel(EditorApplication);
global.stubAvailableStyles(EditorApplication, {
dividers: ['solid', 'inset']
@ -166,7 +166,7 @@ define([
beforeEach(function () {
model = new (DividerBlock.DividerBlockModel)();
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
view = new (DividerBlock.DividerBlockSettingsView)({ model: model });
view.render();
});
@ -200,13 +200,13 @@ define([
expect(model.get('styles.block.backgroundColor')).to.equal('#cccccc');
});
it ('changes color of available divider styles when actual divider color changes', function() {
it('changes color of available divider styles when actual divider color changes', function () {
var newColor = '#889912';
view.$('.mailpoet_field_divider_border_color').val(newColor).change();
expect(view.$('.mailpoet_field_divider_style div')).to.have.$css('border-top-color', newColor);
});
it('does not display "Apply to all" option when `hideApplyToAll` option is active', function() {
it('does not display "Apply to all" option when `hideApplyToAll` option is active', function () {
view = new (DividerBlock.DividerBlockSettingsView)({
model: model,
renderOptions: {
@ -222,7 +222,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -4,7 +4,7 @@ const sinon = global.sinon;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/footer'
], function(App, FooterBlock) {
], function (App, FooterBlock) {
var EditorApplication = App;
describe('Footer', function () {
@ -126,7 +126,7 @@ define([
beforeEach(function () {
global.stubChannel(EditorApplication);
view = new (FooterBlock.FooterBlockView)({model: model});
view = new (FooterBlock.FooterBlockView)({ model: model });
});
it('renders', function () {
@ -144,7 +144,7 @@ define([
textSizes: ['16px', '20px']
});
model = new (FooterBlock.FooterBlockModel)();
view = new (FooterBlock.FooterBlockSettingsView)({model: model});
view = new (FooterBlock.FooterBlockSettingsView)({ model: model });
it('renders', function () {
expect(view.render).to.not.throw();
@ -155,14 +155,14 @@ define([
var model;
var view;
beforeEach(function() {
beforeEach(function () {
global.stubChannel(EditorApplication);
global.stubAvailableStyles(EditorApplication, {
fonts: ['Arial', 'Tahoma'],
textSizes: ['16px', '20px']
});
model = new (FooterBlock.FooterBlockModel)({});
view = new (FooterBlock.FooterBlockSettingsView)({model: model});
view = new (FooterBlock.FooterBlockSettingsView)({ model: model });
view.render();
});
@ -203,7 +203,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -4,7 +4,7 @@ const sinon = global.sinon;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/header'
], function(App, HeaderBlock) {
], function (App, HeaderBlock) {
var EditorApplication = App;
describe('Header', function () {
@ -12,7 +12,7 @@ define([
var model;
beforeEach(function () {
global.stubChannel(EditorApplication);
global. stubConfig(EditorApplication, {
global.stubConfig(EditorApplication, {
blockDefaults: {}
});
model = new (HeaderBlock.HeaderBlockModel)();
@ -125,7 +125,7 @@ define([
beforeEach(function () {
global.stubChannel(EditorApplication);
view = new (HeaderBlock.HeaderBlockView)({model: model});
view = new (HeaderBlock.HeaderBlockView)({ model: model });
});
it('renders', function () {
@ -144,7 +144,7 @@ define([
textSizes: ['16px', '20px']
});
model = new (HeaderBlock.HeaderBlockModel)();
view = new (HeaderBlock.HeaderBlockSettingsView)({model: model});
view = new (HeaderBlock.HeaderBlockSettingsView)({ model: model });
it('renders', function () {
expect(view.render).to.not.throw();
@ -155,14 +155,14 @@ define([
var model;
var view;
beforeEach(function() {
beforeEach(function () {
global.stubChannel(EditorApplication);
global.stubAvailableStyles(EditorApplication, {
fonts: ['Arial', 'Tahoma'],
textSizes: ['16px', '20px']
});
model = new (HeaderBlock.HeaderBlockModel)({});
view = new (HeaderBlock.HeaderBlockSettingsView)({model: model});
view = new (HeaderBlock.HeaderBlockSettingsView)({ model: model });
view.render();
});
@ -203,7 +203,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -4,7 +4,7 @@ const sinon = global.sinon;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/image'
], function(App, ImageBlock) {
], function (App, ImageBlock) {
var EditorApplication = App;
describe('Image', function () {
@ -113,7 +113,7 @@ define([
model = new (ImageBlock.ImageBlockModel)();
beforeEach(function () {
view = new (ImageBlock.ImageBlockView)({model: model});
view = new (ImageBlock.ImageBlockView)({ model: model });
});
it('renders', function () {
@ -133,7 +133,7 @@ define([
src: 'http://example.org/someimage.png',
alt: 'some alt'
});
view = new (ImageBlock.ImageBlockView)({model: model});
view = new (ImageBlock.ImageBlockView)({ model: model });
view.render();
});
@ -174,7 +174,7 @@ define([
});
global.stubImage(newWidth, newHeight);
model = new (ImageBlock.ImageBlockModel)();
view = new (ImageBlock.ImageBlockSettingsView)({model: model});
view = new (ImageBlock.ImageBlockSettingsView)({ model: model });
});
it('renders', function () {
@ -218,12 +218,12 @@ define([
expect(model.get('styles.block.textAlign')).to.equal('left');
});
it.skip('closes the sidepanel after "Done" is clicked', function() {
it.skip('closes the sidepanel after "Done" is clicked', function () {
var mock = sinon.mock().once();
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -8,7 +8,7 @@ define([
'newsletter_editor/components/communication',
'newsletter_editor/blocks/posts',
'newsletter_editor/blocks/container'
], function(App, Communication, PostsBlock, ContainerBlock) {
], function (App, Communication, PostsBlock, ContainerBlock) {
var EditorApplication = App;
var CommunicationComponent = Communication;
@ -24,8 +24,8 @@ define([
describe('model', function () {
var model;
before(function() {
CommunicationComponent.getPosts = function() {
before(function () {
CommunicationComponent.getPosts = function () {
var deferred = jQuery.Deferred();
return deferred;
};
@ -238,7 +238,7 @@ define([
});
it('triggers loading and loaded events for more posts', function () {
var stub = sinon.stub(CommunicationComponent, 'getPosts', function() {
var stub = sinon.stub(CommunicationComponent, 'getPosts', function () {
var deferred = jQuery.Deferred();
deferred.resolve([{}]); // 1 post
return deferred;
@ -270,7 +270,7 @@ define([
global.stubConfig(EditorApplication);
EditorApplication.getBlockTypeModel = sinon.stub().returns(Backbone.Model);
model = new (PostsBlock.PostsBlockModel)();
view = new (PostsBlock.PostsBlockView)({model: model});
view = new (PostsBlock.PostsBlockView)({ model: model });
// Disable auto-opening of settings view
view.off('showSettings');
@ -291,7 +291,7 @@ define([
var view;
before(function () {
CommunicationComponent.getPostTypes = function() {
CommunicationComponent.getPostTypes = function () {
var deferred = jQuery.Deferred();
deferred.resolve([
{
@ -322,12 +322,12 @@ define([
});
EditorApplication.getBlockTypeModel = sinon.stub().returns(ContainerBlock.ContainerBlockModel);
model = new (PostsBlock.PostsBlockModel)();
view = new (PostsBlock.PostsBlockSettingsView)({model: model});
view = new (PostsBlock.PostsBlockSettingsView)({ model: model });
});
it('renders', function () {
// Stub out block view requests
model.request = sinon.stub().returns({$el: {}});
model.request = sinon.stub().returns({ $el: {} });
expect(view.render).to.not.throw();
});
@ -423,13 +423,13 @@ define([
expect(model.get('readMoreText')).to.equal(newValue);
});
describe('when "title only" display type is selected', function() {
describe('when "title only" display type is selected', function () {
var model;
var view;
beforeEach(function() {
beforeEach(function () {
model = new (PostsBlock.PostsBlockModel)();
model.request = sinon.stub().returns({$el: {}});
view = new (PostsBlock.PostsBlockSettingsView)({model: model});
model.request = sinon.stub().returns({ $el: {} });
view = new (PostsBlock.PostsBlockSettingsView)({ model: model });
view.render();
view.$('.mailpoet_posts_display_type').val('titleOnly').change();
});
@ -438,8 +438,8 @@ define([
expect(view.$('.mailpoet_posts_title_as_list')).to.not.have.$class('mailpoet_hidden');
});
describe('when "title as list" is selected', function() {
beforeEach(function() {
describe('when "title as list" is selected', function () {
beforeEach(function () {
view.$('.mailpoet_posts_display_type').val('titleOnly').change();
view.$('.mailpoet_posts_title_format').val('ul').change();
});
@ -449,14 +449,14 @@ define([
expect(view.$('.mailpoet_posts_title_as_link')).to.have.$class('mailpoet_hidden');
});
it('is set to "yes"', function() {
it('is set to "yes"', function () {
expect(model.get('titleIsLink')).to.equal(true);
});
});
});
describe('when "title as list" is deselected', function() {
before(function() {
describe('when "title as list" is deselected', function () {
before(function () {
view.$('.mailpoet_posts_title_format').val('ul').change();
view.$('.mailpoet_posts_title_format').val('h3').change();
});

View File

@ -5,7 +5,7 @@ define([
'newsletter_editor/App',
'newsletter_editor/blocks/social',
'backbone'
], function(EditorApplication, SocialBlock, Backbone) {
], function (EditorApplication, SocialBlock, Backbone) {
describe('Social', function () {
describe('block model', function () {
@ -125,7 +125,7 @@ define([
});
it('renders', function () {
var view = new (SocialBlock.SocialBlockView)({model: model});
var view = new (SocialBlock.SocialBlockView)({ model: model });
expect(view.render).to.not.throw();
expect(view.$('.mailpoet_social')).to.have.length(1);
});
@ -156,7 +156,7 @@ define([
}
]
});
view = new (SocialBlock.SocialBlockView)({model: model});
view = new (SocialBlock.SocialBlockView)({ model: model });
view.render();
});
@ -212,7 +212,7 @@ define([
});
it('renders', function () {
var view = new (SocialBlock.SocialBlockSettingsView)({model: model});
var view = new (SocialBlock.SocialBlockSettingsView)({ model: model });
expect(view.render).to.not.throw();
});
@ -253,22 +253,22 @@ define([
}
]
});
view = new (SocialBlock.SocialBlockSettingsView)({model: model});
view = new (SocialBlock.SocialBlockSettingsView)({ model: model });
view.render();
});
it('updates icons in settings if iconset changes', function() {
it('updates icons in settings if iconset changes', function () {
view.$('.mailpoet_social_icon_set').last().click();
expect(view.$('.mailpoet_social_icon_field_image').val()).to.equal(EditorApplication.getAvailableStyles().get('socialIconSets.light.custom'));
});
it('removes the icon when "remove" is clicked', function() {
it('removes the icon when "remove" is clicked', function () {
view.$('.mailpoet_delete_block').click();
expect(model.get('icons').length).to.equal(0);
expect(view.$('.mailpoet_social_icon_settings').length).to.equal(0);
});
it('adds another icon when "Add another social network" is pressed', function() {
it('adds another icon when "Add another social network" is pressed', function () {
view.$('.mailpoet_add_social_icon').click();
expect(model.get('icons').length).to.equal(2);
});
@ -278,7 +278,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -4,7 +4,7 @@ const sinon = global.sinon;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/spacer'
], function(App, SpacerBlock) {
], function (App, SpacerBlock) {
var EditorApplication = App;
describe('Spacer', function () {
@ -84,7 +84,7 @@ define([
global.stubConfig(EditorApplication);
global.stubAvailableStyles(EditorApplication);
model = new (SpacerBlock.SpacerBlockModel)();
view = new (SpacerBlock.SpacerBlockView)({model: model});
view = new (SpacerBlock.SpacerBlockView)({ model: model });
});
it('renders', function () {
@ -129,7 +129,7 @@ define([
beforeEach(function () {
global.stubChannel(EditorApplication);
view = new (SpacerBlock.SpacerBlockSettingsView)({model: model});
view = new (SpacerBlock.SpacerBlockSettingsView)({ model: model });
});
it('renders', function () {
@ -139,11 +139,11 @@ define([
describe('once rendered', function () {
var view;
var model;
beforeEach(function() {
beforeEach(function () {
global.stubChannel(EditorApplication);
global.stubConfig(EditorApplication);
model = new (SpacerBlock.SpacerBlockModel)();
view = new (SpacerBlock.SpacerBlockSettingsView)({model: model});
view = new (SpacerBlock.SpacerBlockSettingsView)({ model: model });
view.render();
});
@ -157,7 +157,7 @@ define([
global.MailPoet.Modal.cancel = mock;
view.$('.mailpoet_done_editing').click();
mock.verify();
delete(global.MailPoet.Modal.cancel);
delete (global.MailPoet.Modal.cancel);
});
});
});

View File

@ -3,7 +3,7 @@ const expect = global.expect;
define([
'newsletter_editor/App',
'newsletter_editor/blocks/text'
], function(EditorApplication, TextBlock) {
], function (EditorApplication, TextBlock) {
describe('Text', function () {
describe('model', function () {
@ -42,7 +42,7 @@ define([
var view;
global.stubConfig(EditorApplication);
model = new (TextBlock.TextBlockModel)();
view = new (TextBlock.TextBlockView)({model: model});
view = new (TextBlock.TextBlockView)({ model: model });
it('renders', function () {
expect(view.render).to.not.throw();
@ -55,7 +55,7 @@ define([
beforeEach(function () {
global.stubConfig(EditorApplication);
view = new (TextBlock.TextBlockView)({model: model});
view = new (TextBlock.TextBlockView)({ model: model });
view.render();
});

View File

@ -6,14 +6,14 @@ define([
'newsletter_editor/App',
'newsletter_editor/components/communication',
'amd-inject-loader!newsletter_editor/components/communication'
], function(EditorApplication, Communication, CommunicationInjector) {
], function (EditorApplication, Communication, CommunicationInjector) {
describe('getPostTypes', function() {
it('fetches post types from the server', function() {
describe('getPostTypes', function () {
it('fetches post types from the server', function () {
var module = CommunicationInjector({
mailpoet: {
Ajax: {
post: function() {
post: function () {
var deferred = jQuery.Deferred();
deferred.resolve({
data: {
@ -26,14 +26,14 @@ define([
}
}
});
module.getPostTypes().done(function(types) {
module.getPostTypes().done(function (types) {
expect(types).to.eql(['val1', 'val2']);
});
});
it('caches results', function() {
it('caches results', function () {
var deferred = jQuery.Deferred();
var mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred);
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
var module = CommunicationInjector({
mailpoet: {
Ajax: {
@ -52,10 +52,10 @@ define([
});
});
describe('getTaxonomies', function() {
it('sends post type to endpoint', function() {
describe('getTaxonomies', function () {
it('sends post type to endpoint', function () {
var spy;
var post = function() {
var post = function () {
var deferred = jQuery.Deferred();
deferred.resolve({
category: 'val1',
@ -77,11 +77,11 @@ define([
expect(spy.args[0][0].data.postType).to.equal('post');
});
it('fetches taxonomies from the server', function() {
it('fetches taxonomies from the server', function () {
var module = CommunicationInjector({
mailpoet: {
Ajax: {
post: function() {
post: function () {
var deferred = jQuery.Deferred();
deferred.resolve({
data: {
@ -93,14 +93,14 @@ define([
}
}
});
module.getTaxonomies('page').done(function(types) {
module.getTaxonomies('page').done(function (types) {
expect(types).to.eql({ category: 'val1' });
});
});
it('caches results', function() {
it('caches results', function () {
var deferred = jQuery.Deferred();
var mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred);
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
var module = CommunicationInjector({
mailpoet: {
Ajax: {
@ -116,10 +116,10 @@ define([
});
});
describe('getTerms', function() {
it('sends terms to endpoint', function() {
describe('getTerms', function () {
it('sends terms to endpoint', function () {
var spy;
var post = function() {
var post = function () {
var deferred = jQuery.Deferred();
deferred.resolve({});
return deferred;
@ -140,11 +140,11 @@ define([
expect(spy.args[0][0].data.taxonomies).to.eql(['category', 'post_tag']);
});
it('fetches terms from the server', function() {
it('fetches terms from the server', function () {
var module = CommunicationInjector({
mailpoet: {
Ajax: {
post: function() {
post: function () {
var deferred = jQuery.Deferred();
deferred.resolve({
data: {
@ -157,14 +157,14 @@ define([
}
}
});
module.getTerms({ taxonomies: ['category'] }).done(function(types) {
module.getTerms({ taxonomies: ['category'] }).done(function (types) {
expect(types).to.eql({ term1: 'term1val1', term2: 'term2val2' });
});
});
it('caches results', function() {
it('caches results', function () {
var deferred = jQuery.Deferred();
var mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred);
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
var module = CommunicationInjector({
mailpoet: {
Ajax: {
@ -180,10 +180,10 @@ define([
});
});
describe('getPosts', function() {
it('sends options to endpoint', function() {
describe('getPosts', function () {
it('sends options to endpoint', function () {
var spy;
var post = function() {
var post = function () {
var deferred = jQuery.Deferred();
deferred.resolve({});
return deferred;
@ -208,16 +208,16 @@ define([
});
});
it('fetches posts from the server', function() {
it('fetches posts from the server', function () {
var module = CommunicationInjector({
mailpoet: {
Ajax: {
post: function() {
post: function () {
var deferred = jQuery.Deferred();
deferred.resolve({
data: [
{post_title: 'title 1'},
{post_title: 'post title 2'}
{ post_title: 'title 1' },
{ post_title: 'post title 2' }
]
});
return deferred;
@ -225,14 +225,14 @@ define([
}
}
});
module.getPosts().done(function(posts) {
expect(posts).to.eql([{post_title: 'title 1'}, {post_title: 'post title 2'}]);
module.getPosts().done(function (posts) {
expect(posts).to.eql([{ post_title: 'title 1' }, { post_title: 'post title 2' }]);
});
});
it('caches results', function() {
it('caches results', function () {
var deferred = jQuery.Deferred();
var mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred);
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
var module = CommunicationInjector({
mailpoet: {
Ajax: {
@ -251,10 +251,10 @@ define([
});
});
describe('getTransformedPosts', function() {
it('sends options to endpoint', function() {
describe('getTransformedPosts', function () {
it('sends options to endpoint', function () {
var spy;
var post = function() {
var post = function () {
var deferred = jQuery.Deferred();
deferred.resolve({});
return deferred;
@ -279,16 +279,16 @@ define([
});
});
it('fetches transformed posts from the server', function() {
it('fetches transformed posts from the server', function () {
var module = CommunicationInjector({
mailpoet: {
Ajax: {
post: function() {
post: function () {
var deferred = jQuery.Deferred();
deferred.resolve({
data: [
{type: 'text', text: 'something'},
{type: 'text', text: 'something else'}
{ type: 'text', text: 'something' },
{ type: 'text', text: 'something else' }
]
});
return deferred;
@ -296,14 +296,14 @@ define([
}
}
});
module.getTransformedPosts().done(function(posts) {
expect(posts).to.eql([{type: 'text', text: 'something'}, {type: 'text', text: 'something else'}]);
module.getTransformedPosts().done(function (posts) {
expect(posts).to.eql([{ type: 'text', text: 'something' }, { type: 'text', text: 'something else' }]);
});
});
it('caches results', function() {
it('caches results', function () {
var deferred = jQuery.Deferred();
var mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred);
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
var module = CommunicationInjector({
mailpoet: {
Ajax: {

View File

@ -3,10 +3,10 @@ const expect = global.expect;
define([
'newsletter_editor/App',
'newsletter_editor/components/config'
], function(EditorApplication, ConfigComponent) {
], function (EditorApplication, ConfigComponent) {
describe('Config', function () {
it('loads and stores configuration', function() {
it('loads and stores configuration', function () {
var model;
ConfigComponent.setConfig({
testConfig: 'testValue'

View File

@ -6,14 +6,14 @@ const _ = global._;
define([
'newsletter_editor/App',
'newsletter_editor/components/content'
], function(App, ContentComponent) {
], function (App, ContentComponent) {
var EditorApplication = App;
describe('Content', function() {
describe('newsletter model', function() {
describe('Content', function () {
describe('newsletter model', function () {
var model;
beforeEach(function() {
beforeEach(function () {
model = new (ContentComponent.NewsletterModel)({
body: {
globalStyles: {
@ -29,8 +29,8 @@ define([
});
});
it('triggers autosave on change', function() {
var mock = sinon.mock({ trigger: function() {} }).expects('trigger').once().withArgs('autoSave');
it('triggers autosave on change', function () {
var mock = sinon.mock({ trigger: function () {} }).expects('trigger').once().withArgs('autoSave');
global.stubChannel(EditorApplication, {
trigger: mock
});
@ -38,13 +38,13 @@ define([
mock.verify();
});
it('does not include styles and content properties in its JSON', function() {
it('does not include styles and content properties in its JSON', function () {
var json = model.toJSON();
expect(json).to.deep.equal({subject: 'my test subject'});
expect(json).to.deep.equal({ subject: 'my test subject' });
});
describe('toJSON()', function() {
it('will only contain properties modifiable by the editor', function() {
describe('toJSON()', function () {
it('will only contain properties modifiable by the editor', function () {
var model = new (ContentComponent.NewsletterModel)({
id: 19,
subject: 'some subject',
@ -63,8 +63,8 @@ define([
});
});
describe('block types', function() {
it('registers a block type view and model', function() {
describe('block types', function () {
it('registers a block type view and model', function () {
var blockModel = new Backbone.SuperModel();
var blockView = new Backbone.View();
ContentComponent.registerBlockType('testType', {
@ -76,8 +76,8 @@ define([
});
});
describe('transformation to json', function() {
it('includes content, globalStyles and initial newsletter fields', function() {
describe('transformation to json', function () {
it('includes content, globalStyles and initial newsletter fields', function () {
var json;
var dataField = {
containerModelField: 'containerModelValue'
@ -89,20 +89,20 @@ define([
subject: 'test newsletter subject'
};
EditorApplication._contentContainer = {
toJSON: function() {
toJSON: function () {
return dataField;
}
};
EditorApplication.getGlobalStyles = function() {
EditorApplication.getGlobalStyles = function () {
return {
toJSON: function() {
toJSON: function () {
return stylesField;
}
};
};
EditorApplication.getNewsletter = function() {
EditorApplication.getNewsletter = function () {
return {
toJSON: function() {
toJSON: function () {
return newsletterFields;
}
};

View File

@ -4,12 +4,12 @@ const Backbone = global.Backbone;
define([
'newsletter_editor/App',
'newsletter_editor/components/heading'
], function(EditorApplication, HeadingComponent) {
], function (EditorApplication, HeadingComponent) {
describe('Heading', function() {
describe('view', function() {
describe('Heading', function () {
describe('view', function () {
var view;
beforeEach(function() {
beforeEach(function () {
var model = new Backbone.SuperModel({
subject: 'a test subject'
});
@ -18,14 +18,14 @@ define([
});
});
it('renders', function() {
it('renders', function () {
expect(view.render).to.not.throw();
});
describe('once rendered', function() {
describe('once rendered', function () {
var view;
var model;
beforeEach(function() {
beforeEach(function () {
model = new Backbone.SuperModel({
subject: 'a test subject',
preheader: 'a test preheader'
@ -36,12 +36,12 @@ define([
view.render();
});
it('changes the model when subject field is changed', function() {
it('changes the model when subject field is changed', function () {
view.$('.mailpoet_input_title').val('a new testing subject').keyup();
expect(model.get('subject')).to.equal('a new testing subject');
});
it('changes the model when preheader field is changed', function() {
it('changes the model when preheader field is changed', function () {
view.$('.mailpoet_input_preheader').val('a new testing preheader').keyup();
expect(model.get('preheader')).to.equal('a new testing preheader');
});

View File

@ -6,23 +6,23 @@ define([
'newsletter_editor/components/save',
'amd-inject-loader!newsletter_editor/components/save',
'jquery'
], function(App, SaveComponent, SaveInjector, jQuery) {
], function (App, SaveComponent, SaveInjector, jQuery) {
var EditorApplication = App;
describe('Save', function() {
describe('save method', function() {
describe('Save', function () {
describe('save method', function () {
var module;
before(function() {
before(function () {
module = SaveInjector({
'newsletter_editor/components/communication': {
saveNewsletter: function() {
saveNewsletter: function () {
return jQuery.Deferred();
}
}
});
});
it('triggers beforeEditorSave event', function() {
it('triggers beforeEditorSave event', function () {
var spy = sinon.spy();
global.stubChannel(EditorApplication, {
trigger: spy
@ -37,7 +37,7 @@ define([
expect(spy).to.have.been.calledWith('beforeEditorSave');
});
it('triggers afterEditorSave event', function() {
it('triggers afterEditorSave event', function () {
var module;
var spy = sinon.spy();
var promise = jQuery.Deferred();
@ -59,7 +59,7 @@ define([
expect(spy.withArgs('afterEditorSave').calledOnce).to.be.true;// eslint-disable-line no-unused-expressions
});
it('sends newsletter json to server for saving', function() {
it('sends newsletter json to server for saving', function () {
var mock = sinon.mock().once().returns(jQuery.Deferred());
var module = SaveInjector({
'newsletter_editor/components/communication': {
@ -74,9 +74,9 @@ define([
mock.verify();
});
it('encodes newsletter body in JSON format', function() {
it('encodes newsletter body in JSON format', function () {
var module;
var body = {type: 'testType'};
var body = { type: 'testType' };
var mock = sinon.mock()
.once()
.withArgs({
@ -100,28 +100,28 @@ define([
});
describe('view', function() {
describe('view', function () {
var view;
before(function() {
before(function () {
EditorApplication._contentContainer = { isValid: sinon.stub().returns(true) };
global.stubConfig(EditorApplication);
view = new (SaveComponent.SaveView)();
});
it('renders', function() {
it('renders', function () {
expect(view.render).to.not.throw();
});
describe('once rendered', function() {
describe('once rendered', function () {
var view;
beforeEach(function() {
beforeEach(function () {
EditorApplication._contentContainer = { isValid: sinon.stub().returns(true) };
view = new (SaveComponent.SaveView)();
view.render();
});
it('triggers newsletter saving when clicked on save button', function() {
var mock = sinon.mock({ request: function() {} }).expects('request').once().withArgs('save');
it('triggers newsletter saving when clicked on save button', function () {
var mock = sinon.mock({ request: function () {} }).expects('request').once().withArgs('save');
global.stubChannel(EditorApplication, {
request: mock
});
@ -130,19 +130,19 @@ define([
mock.verify();
});
it('displays saving options when clicked on save options button', function() {
it('displays saving options when clicked on save options button', function () {
view.$('.mailpoet_save_show_options').click();
expect(view.$('.mailpoet_save_options')).to.not.have.$class('mailpoet_hidden');
});
it('triggers template saving when clicked on "save as template" button', function() {
var mock = sinon.mock({ post: function() {} }).expects('post').once().returns(jQuery.Deferred());
it('triggers template saving when clicked on "save as template" button', function () {
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(jQuery.Deferred());
var html2canvasMock = jQuery.Deferred();
var module;
var view;
html2canvasMock.resolve({
toDataURL: function() { return 'somedataurl'; }
toDataURL: function () { return 'somedataurl'; }
});
EditorApplication.getBody = sinon.stub();
@ -152,18 +152,18 @@ define([
post: mock
},
I18n: {
t: function() { return ''; }
t: function () { return ''; }
},
Notice: {
success: function() {},
error: function() {}
success: function () {},
error: function () {}
},
trackEvent: function() {}
trackEvent: function () {}
},
'newsletter_editor/App': EditorApplication,
html2canvas: function() {
html2canvas: function () {
return {
then: function() { return html2canvasMock; }
then: function () { return html2canvasMock; }
};
}
});
@ -177,12 +177,12 @@ define([
mock.verify();
});
it('saves newsletter when clicked on "next" button', function() {
it('saves newsletter when clicked on "next" button', function () {
var spy = sinon.spy();
var view;
var module = SaveInjector({
'newsletter_editor/components/communication': {
saveNewsletter: function() {
saveNewsletter: function () {
return jQuery.Deferred();
}
}

View File

@ -4,53 +4,53 @@ const Backbone = global.Backbone;
define([
'newsletter_editor/App',
'newsletter_editor/components/sidebar'
], function(EditorApplication, SidebarComponent) {
], function (EditorApplication, SidebarComponent) {
describe('Sidebar', function() {
describe('content view', function() {
describe('Sidebar', function () {
describe('content view', function () {
var view;
beforeEach(function() {
beforeEach(function () {
view = new (SidebarComponent.SidebarWidgetsView)({
collection: new Backbone.Collection([])
});
});
it('renders', function() {
it('renders', function () {
expect(view.render).to.not.throw();
});
});
describe('layout view', function() {
describe('layout view', function () {
var view;
beforeEach(function() {
beforeEach(function () {
view = new (SidebarComponent.SidebarLayoutWidgetsView)({
collection: new Backbone.Collection([])
});
});
it('renders', function() {
it('renders', function () {
expect(view.render).to.not.throw();
});
});
describe('styles view', function() {
describe('styles view', function () {
var view;
beforeEach(function() {
beforeEach(function () {
view = new (SidebarComponent.SidebarStylesView)({
model: new Backbone.SuperModel({}),
availableStyles: new Backbone.SuperModel({})
});
});
it('renders', function() {
it('renders', function () {
expect(view.render).to.not.throw();
});
describe('once rendered', function() {
describe('once rendered', function () {
var model;
var availableStyles;
var view;
before(function() {
before(function () {
model = new Backbone.SuperModel({
text: {
fontColor: '#000000',
@ -96,95 +96,95 @@ define([
view.render();
});
it('changes model if text font color field changes', function() {
it('changes model if text font color field changes', function () {
view.$('#mailpoet_text_font_color').val('#123456').change();
expect(model.get('text.fontColor')).to.equal('#123456');
});
it('changes model if h1 font color field changes', function() {
it('changes model if h1 font color field changes', function () {
view.$('#mailpoet_h1_font_color').val('#123457').change();
expect(model.get('h1.fontColor')).to.equal('#123457');
});
it('changes model if h2 font color field changes', function() {
it('changes model if h2 font color field changes', function () {
view.$('#mailpoet_h2_font_color').val('#123458').change();
expect(model.get('h2.fontColor')).to.equal('#123458');
});
it('changes model if h3 font color field changes', function() {
it('changes model if h3 font color field changes', function () {
view.$('#mailpoet_h3_font_color').val('#123426').change();
expect(model.get('h3.fontColor')).to.equal('#123426');
});
it('changes model if link font color field changes', function() {
it('changes model if link font color field changes', function () {
view.$('#mailpoet_a_font_color').val('#323232').change();
expect(model.get('link.fontColor')).to.equal('#323232');
});
it('changes model if newsletter background color field changes', function() {
it('changes model if newsletter background color field changes', function () {
view.$('#mailpoet_newsletter_background_color').val('#636237').change();
expect(model.get('wrapper.backgroundColor')).to.equal('#636237');
});
it('changes model if background color field changes', function() {
it('changes model if background color field changes', function () {
view.$('#mailpoet_background_color').val('#878587').change();
expect(model.get('body.backgroundColor')).to.equal('#878587');
});
it('changes model if text font family field changes', function() {
it('changes model if text font family field changes', function () {
view.$('#mailpoet_text_font_family').val('Times New Roman').change();
expect(model.get('text.fontFamily')).to.equal('Times New Roman');
});
it('changes model if h1 font family field changes', function() {
it('changes model if h1 font family field changes', function () {
view.$('#mailpoet_h1_font_family').val('Comic Sans').change();
expect(model.get('h1.fontFamily')).to.equal('Comic Sans');
});
it('changes model if h2 font family field changes', function() {
it('changes model if h2 font family field changes', function () {
view.$('#mailpoet_h2_font_family').val('Tahoma').change();
expect(model.get('h2.fontFamily')).to.equal('Tahoma');
});
it('changes model if h3 font family field changes', function() {
it('changes model if h3 font family field changes', function () {
view.$('#mailpoet_h3_font_family').val('Lucida').change();
expect(model.get('h3.fontFamily')).to.equal('Lucida');
});
it('changes model if text font size field changes', function() {
it('changes model if text font size field changes', function () {
view.$('#mailpoet_text_font_size').val('9px').change();
expect(model.get('text.fontSize')).to.equal('9px');
});
it('changes model if h1 font size field changes', function() {
it('changes model if h1 font size field changes', function () {
view.$('#mailpoet_h1_font_size').val('12px').change();
expect(model.get('h1.fontSize')).to.equal('12px');
});
it('changes model if h2 font size field changes', function() {
it('changes model if h2 font size field changes', function () {
view.$('#mailpoet_h2_font_size').val('14px').change();
expect(model.get('h2.fontSize')).to.equal('14px');
});
it('changes model if h3 font size field changes', function() {
it('changes model if h3 font size field changes', function () {
view.$('#mailpoet_h3_font_size').val('16px').change();
expect(model.get('h3.fontSize')).to.equal('16px');
});
it('changes model if link underline field changes', function() {
it('changes model if link underline field changes', function () {
view.$('#mailpoet_a_font_underline').prop('checked', true).change();
expect(model.get('link.textDecoration')).to.equal('underline');
});
});
});
describe('preview view', function() {
describe('preview view', function () {
var view;
beforeEach(function() {
beforeEach(function () {
view = new (SidebarComponent.SidebarPreviewView)();
});
it('renders', function() {
it('renders', function () {
expect(view.render).to.not.throw();
});
});

View File

@ -4,11 +4,11 @@ const sinon = global.sinon;
define([
'newsletter_editor/App',
'newsletter_editor/components/styles'
], function(App, StylesComponent) {
], function (App, StylesComponent) {
var EditorApplication = App;
describe('Styles', function () {
it('loads and stores globally available styles', function() {
it('loads and stores globally available styles', function () {
var model;
StylesComponent.setGlobalStyles({
testStyle: 'testValue'
@ -17,15 +17,15 @@ define([
expect(model.get('testStyle')).to.equal('testValue');
});
describe('model', function() {
describe('model', function () {
var model;
beforeEach(function() {
beforeEach(function () {
model = new (StylesComponent.StylesModel)();
});
it('triggers autoSave when changed', function() {
var mock = sinon.mock({ trigger: function(){}}).expects('trigger').once().withExactArgs('autoSave');
EditorApplication.getChannel = function() {
it('triggers autoSave when changed', function () {
var mock = sinon.mock({ trigger: function () {} }).expects('trigger').once().withExactArgs('autoSave');
EditorApplication.getChannel = function () {
return {
trigger: mock
};
@ -35,15 +35,15 @@ define([
});
});
describe('view', function() {
describe('view', function () {
var model;
var view;
beforeEach(function() {
beforeEach(function () {
model = new (StylesComponent.StylesModel)();
view = new (StylesComponent.StylesView)({ model: model });
});
it('renders', function() {
it('renders', function () {
expect(view.render).to.not.throw();
});
});

View File

@ -8,6 +8,7 @@ use MailPoet\API\JSON\Response as APIResponse;
use MailPoet\Form\Util\FieldNameObfuscator;
use MailPoet\Models\Form;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberIP;
use MailPoet\Models\Segment;
use MailPoet\Models\Setting;
@ -516,7 +517,7 @@ class SubscribersTest extends \MailPoetTest {
));
$this->fail('It should not be possible to subscribe a second time so soon');
} catch(\Exception $e) {
expect($e->getMessage())->equals('You need to wait before subscribing again.');
expect($e->getMessage())->equals('You need to wait 60 seconds before subscribing again.');
}
}
@ -544,12 +545,13 @@ class SubscribersTest extends \MailPoetTest {
));
$this->fail('It should not be possible to resubscribe a second time so soon');
} catch(\Exception $e) {
expect($e->getMessage())->equals('You need to wait before subscribing again.');
expect($e->getMessage())->equals('You need to wait 60 seconds before subscribing again.');
}
}
function _after() {
Segment::deleteMany();
Subscriber::deleteMany();
SubscriberIP::deleteMany();
}
}

View File

@ -7,6 +7,7 @@ use Helper\WordPressHooks as WPHooksHelper;
use MailPoet\Config\AccessControl;
use MailPoet\Config\Capabilities;
use MailPoet\Config\Renderer;
use MailPoet\WP\Hooks;
class CapabilitiesTest extends \MailPoetTest {
function _before() {
@ -52,6 +53,32 @@ class CapabilitiesTest extends \MailPoetTest {
$this->caps->setupWPCapabilities();
}
function testItDoesNotSetupCapabilitiesForNonexistentRoles() {
$this->caps->removeWPCapabilities();
$filter = function() {
return array('nonexistent_role');
};
Hooks::addFilter('mailpoet_permission_access_plugin_admin', $filter);
$this->caps->setupWPCapabilities();
// role does not exist
expect(get_role('nonexistent_role'))->null();
// other MailPoet capabilities were successfully configured
$editor_role = get_role('editor');
expect($editor_role->has_cap(AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN))->false();
expect($editor_role->has_cap(AccessControl::PERMISSION_MANAGE_EMAILS))->true();
// Restore capabilities
Hooks::removeFilter('mailpoet_permission_access_plugin_admin', $filter);
$this->caps->setupWPCapabilities();
$editor_role = get_role('editor');
expect($editor_role->has_cap(AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN))->true();
expect($editor_role->has_cap(AccessControl::PERMISSION_MANAGE_EMAILS))->true();
}
function testItSetsUpMembersCapabilities() {
WPHooksHelper::interceptAddAction();

View File

@ -5,6 +5,7 @@ use MailPoet\Helpscout\Beacon;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber;
use MailPoet\Services\Bridge;
use MailPoet\WP\Hooks;
class BeaconTest extends \MailPoetTest {
function _before() {
@ -122,8 +123,16 @@ class BeaconTest extends \MailPoetTest {
expect($this->beacon_data['Server OS'])->equals(utf8_encode(php_uname()));
}
function testItReturnsCronPingResponse() {
function testItReturnsCronPingUrl() {
expect($this->beacon_data['Cron ping URL'])->contains('&action=ping');
// cron ping URL should react to custom filters
$filter = function($url) {
return str_replace(home_url(), 'http://custom_url/', $url);
};
Hooks::addFilter('mailpoet_cron_request_url', $filter);
$beacon_data = Beacon::getData();
expect($beacon_data['Cron ping URL'])->regExp('!^http:\/\/custom_url\/!');
Hooks::removeFilter('mailpoet_cron_request_url', $filter);
}
function testItReturnsPremiumVersion() {

View File

@ -54,6 +54,25 @@ class WPTest extends \MailPoetTest {
expect($subscriber->email)->equals('user-sync-test-xx@email.com');
}
function testItDoesNotSynchronizeEmptyEmailsForExistingUsers() {
$id = $this->insertUser();
WP::synchronizeUsers();
$this->updateWPUserEmail($id, '');
WP::synchronizeUsers();
$subscriber = Subscriber::where('wp_user_id', $id)->findOne();
expect($subscriber->email)->notEmpty();
$this->deleteWPUser($id);
}
function testItDoesNotSynchronizeEmptyEmailsForNewUsers() {
$id = $this->insertUser();
$this->updateWPUserEmail($id, '');
WP::synchronizeUsers();
$subscriber = Subscriber::where('wp_user_id', $id)->findOne();
expect($subscriber)->isEmpty();
$this->deleteWPUser($id);
}
function testItSynchronizeFirstNames() {
$id = $this->insertUser();
WP::synchronizeUsers();
@ -152,9 +171,22 @@ class WPTest extends \MailPoetTest {
));
$subscriber2->status = Subscriber::STATUS_SUBSCRIBED;
$subscriber2->save();
// email is empty
$subscriber3 = Subscriber::create();
$subscriber3->hydrate(array(
'first_name' => 'Dave',
'last_name' => 'Dave',
'email' => 'user-sync-test3' . rand() . '@example.com', // need to pass validation
));
$subscriber3->status = Subscriber::STATUS_SUBSCRIBED;
$subscriber3->save();
$this->clearEmail($subscriber3);
WP::synchronizeUsers();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(3);
$db_subscriber = Subscriber::findOne($subscriber3->id);
expect($db_subscriber)->notEmpty();
$subscriber3->delete();
}
function testItRemovesSubscribersInWPSegmentWithoutWPId() {
@ -179,6 +211,31 @@ class WPTest extends \MailPoetTest {
expect($subscribersCount)->equals(0);
}
function testItRemovesSubscribersInWPSegmentWithoutEmail() {
$id = $this->insertUser();
$this->updateWPUserEmail($id, '');
$subscriber = Subscriber::create();
$subscriber->hydrate(array(
'first_name' => 'Mike',
'last_name' => 'Mike',
'email' => 'user-sync-test' . rand() . '@example.com', // need to pass validation
'wp_user_id' => $id,
));
$subscriber->status = Subscriber::STATUS_SUBSCRIBED;
$subscriber->save();
$this->clearEmail($subscriber);
$wp_segment = Segment::getWPSegment();
$association = SubscriberSegment::create();
$association->subscriber_id = $subscriber->id;
$association->segment_id = $wp_segment->id;
$association->save();
$db_subscriber = Subscriber::findOne($subscriber->id);
expect($db_subscriber)->notEmpty();
WP::synchronizeUsers();
$db_subscriber = Subscriber::findOne($subscriber->id);
expect($db_subscriber)->isEmpty();
}
function _before() {
$this->cleanData();
}
@ -282,4 +339,11 @@ class WPTest extends \MailPoetTest {
', $wpdb->users, $id));
}
private function clearEmail($subscriber) {
\ORM::raw_execute('
UPDATE ' . MP_SUBSCRIBERS_TABLE . '
SET `email` = "" WHERE `id` = ' . $subscriber->id
);
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace MailPoet\Test\Subscription;
use Carbon\Carbon;
use MailPoet\Models\SubscriberIP;
use MailPoet\Subscription\Throttling;
use MailPoet\WP\Hooks;
class ThrottlingTest extends \MailPoetTest {
function testItProgressivelyThrottlesSubscriptions() {
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
expect(Throttling::throttle())->equals(false);
expect(Throttling::throttle())->equals(60);
for($i = 0; $i < 11; $i++) {
$ip = SubscriberIP::create();
$ip->ip = '127.0.0.1';
$ip->created_at = Carbon::now()->subMinutes($i);
$ip->save();
}
expect(Throttling::throttle())->equals(MINUTE_IN_SECONDS * pow(2, 10));
}
function testItDoesNotThrottleIfDisabledByAHook() {
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
Hooks::addFilter('mailpoet_subscription_limit_enabled', '__return_false');
expect(Throttling::throttle())->equals(false);
expect(Throttling::throttle())->equals(false);
Hooks::removeFilter('mailpoet_subscription_limit_enabled', '__return_false');
expect(Throttling::throttle())->greaterThan(0);
}
function testItDoesNotThrottleForLoggedInUsers() {
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$wp_users = get_users();
wp_set_current_user($wp_users[0]->ID);
expect(Throttling::throttle())->equals(false);
expect(Throttling::throttle())->equals(false);
wp_set_current_user(0);
expect(Throttling::throttle())->greaterThan(0);
}
function testItPurgesOldSubscriberIps() {
$ip = SubscriberIP::create();
$ip->ip = '127.0.0.1';
$ip->save();
$ip2 = SubscriberIP::create();
$ip2->ip = '127.0.0.1';
$ip2->created_at = Carbon::now()->subDays(1)->subSeconds(1);
$ip2->save();
expect(SubscriberIP::count())->equals(2);
Throttling::throttle();
expect(SubscriberIP::count())->equals(1);
}
function _after() {
SubscriberIP::deleteMany();
}
}

View File

@ -24,6 +24,11 @@ class HooksTest extends \MailPoetTest {
Hooks::doAction($this->action, $test_value, $test_value2);
expect($called)->true();
$called = false;
Hooks::removeAction($this->action, $callback);
Hooks::doAction($this->action);
expect($called)->false();
}
function testItCanProcessFilters() {
@ -41,5 +46,10 @@ class HooksTest extends \MailPoetTest {
expect($called)->true();
expect($result)->equals($test_value);
$called = false;
Hooks::removeFilter($this->filter, $callback);
Hooks::applyFilters($this->filter, $test_value);
expect($called)->false();
}
}

View File

@ -15,6 +15,7 @@
var mailpoet_date_display_format = "<%= wp_date_format() %>";
var mailpoet_date_storage_format = "Y-m-d";
var mailpoet_tracking_enabled = <%= json_encode(tracking_enabled) %>;
var mailpoet_premium_active = <%= json_encode(premium_plugin_active) %>;
</script>
<% endblock %>
@ -60,6 +61,7 @@
'subject': __('Subject'),
'status': __('Status'),
'statsListingActionTitle': __('Statistics'),
'statistics': __('Opened, Clicked'),
'lists': __('Lists'),
'settings': __('Settings'),

View File

@ -60,8 +60,8 @@
<div class="feature-section one-col mailpoet_centered">
<h2><%= __('Care to Give Your Opinion?') %></h2>
<script type="text/javascript" charset="utf-8" src="https://static.polldaddy.com/p/9840615.js"></script>
<noscript><a href="https://polldaddy.com/poll/9840615/">How did you find out about our plugin?</a></noscript>
<script type="text/javascript" charset="utf-8" src="https://secure.polldaddy.com/p/9853743.js"></script>
<noscript><a href="https://polldaddy.com/poll/9853743/">How many people do you know that have their own WordPress website and also write a newsletter?</a></noscript>
</div>
<hr>