Compare commits
59 Commits
Author | SHA1 | Date | |
---|---|---|---|
7b12affb77 | |||
0150e699a2 | |||
e6943e2638 | |||
ac268c1ec9 | |||
1ef131fa2d | |||
1873007550 | |||
fa2ccb51c9 | |||
8f87d654af | |||
dee6e9fbad | |||
ef90264316 | |||
70bf4be723 | |||
07ef727654 | |||
5ce1eadde7 | |||
8a4d5395b1 | |||
b5feed0f46 | |||
11f9579101 | |||
0f6619e25d | |||
daf747d3be | |||
7393b1f2cf | |||
efe861a9ba | |||
2c358ab179 | |||
ca157fc91d | |||
1fbe5d7bc6 | |||
71c031ccf9 | |||
6449b7ccca | |||
6a956472fe | |||
d6af88d667 | |||
b9184a202f | |||
f898746967 | |||
68165b7b78 | |||
bb8591a67b | |||
bda71ae78e | |||
abd4f6cac2 | |||
87e6cc2a4f | |||
dde598eb64 | |||
0c4407f43a | |||
b6c864e7a1 | |||
3d9dc6465d | |||
9a6fec094a | |||
61af224d7d | |||
9b41641e97 | |||
4e2e9f6f8f | |||
c29dc8b4c7 | |||
98a3c6b156 | |||
69c540288b | |||
651c9f5692 | |||
9ad3778cf7 | |||
c90e0e9f64 | |||
cb1730c4e2 | |||
3dd8a973fd | |||
c3ea088fca | |||
a11d6d7868 | |||
a596add838 | |||
7e7103ddab | |||
0064970ed7 | |||
9d93f3ea95 | |||
ff2a3cd19e | |||
8419d95ea1 | |||
26241afb86 |
@ -12,7 +12,6 @@
|
||||
"prefer-arrow-callback": 0,
|
||||
"radix": 0,
|
||||
"no-alert": 0,
|
||||
"block-scoped-var": 0,
|
||||
"guard-for-in": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"no-restricted-syntax": 0,
|
||||
@ -38,20 +37,16 @@
|
||||
"global-require": 0,
|
||||
"no-throw-literal": 0,
|
||||
"no-extra-bind": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"consistent-return": 0,
|
||||
"no-shadow": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"brace-style": 0,
|
||||
"no-else-return": 0,
|
||||
"no-use-before-define": 0,
|
||||
"one-var": 0,
|
||||
"camelcase": 0,
|
||||
"padded-blocks": 0,
|
||||
"strict": 0,
|
||||
"vars-on-top": 0,
|
||||
"no-var": 0,
|
||||
"no-unused-vars": 0,
|
||||
"space-infix-ops": 0,
|
||||
"object-shorthand": 0,
|
||||
"new-parens": 0,
|
||||
"eol-last": 0,
|
||||
|
@ -48,7 +48,7 @@
|
||||
"camelcase": 0,
|
||||
"eqeqeq": 0,
|
||||
"no-lonely-if": 0,
|
||||
"block-scoped-var": 0,
|
||||
"space-unary-ops": 0,
|
||||
"no-extra-bind": 0,
|
||||
"class-methods-use-this": 0,
|
||||
"no-case-declarations": 0,
|
||||
@ -59,12 +59,11 @@
|
||||
"no-extra-boolean-cast": 0,
|
||||
"dot-notation": 0,
|
||||
"no-shadow": 0,
|
||||
"one-var": 0,
|
||||
"no-alert": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"no-script-url": 0,
|
||||
"wrap-iife": 0,
|
||||
"vars-on-top": 0,
|
||||
"space-infix-ops": 0,
|
||||
"no-irregular-whitespace": 0,
|
||||
"padded-blocks": 0,
|
||||
"no-underscore-dangle": 0
|
||||
}
|
||||
|
@ -8,25 +8,13 @@
|
||||
"ecmaVersion": 6
|
||||
},
|
||||
"rules": {
|
||||
"import/no-amd": 0,
|
||||
"one-var": 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-unused-vars": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-shadow": 0,
|
||||
"padded-blocks": 0,
|
||||
"vars-on-top": 0,
|
||||
"space-before-blocks": 0,
|
||||
"object-curly-spacing": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"func-names": 0,
|
||||
"space-before-function-paren": 0
|
||||
"padded-blocks": 0
|
||||
}
|
||||
}
|
||||
|
25
RoboFile.php
25
RoboFile.php
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,10 @@ function requestFailed(errorMessage, xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
return xhr.responseJSON;
|
||||
}
|
||||
var message = errorMessage.replace('%d', xhr.status);
|
||||
return {
|
||||
errors: [
|
||||
{
|
||||
message: message
|
||||
message: errorMessage.replace('%d', xhr.status)
|
||||
}
|
||||
]
|
||||
};
|
||||
@ -54,21 +53,23 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function (mp, jQuery, _) {
|
||||
};
|
||||
},
|
||||
request: function (method, options) {
|
||||
// set options
|
||||
var params;
|
||||
var deferred;
|
||||
// set options
|
||||
this.init(options);
|
||||
|
||||
// set request params
|
||||
var params = this.getParams();
|
||||
// set request params
|
||||
params = this.getParams();
|
||||
|
||||
// remove null values from the data object
|
||||
// remove null values from the data object
|
||||
if (_.isObject(params.data)) {
|
||||
params.data = _.pick(params.data, function (value) {
|
||||
return (value !== null);
|
||||
});
|
||||
}
|
||||
|
||||
// ajax request
|
||||
var deferred = jQuery.post(
|
||||
// ajax request
|
||||
deferred = jQuery.post(
|
||||
this.options.url,
|
||||
params,
|
||||
null,
|
||||
|
@ -43,9 +43,10 @@ define('date',
|
||||
},
|
||||
format: function (date, opts) {
|
||||
var options = opts || {};
|
||||
var momentDate;
|
||||
this.init(options);
|
||||
|
||||
var momentDate = Moment(date, this.convertFormat(options.parseFormat));
|
||||
momentDate = Moment(date, this.convertFormat(options.parseFormat));
|
||||
if (options.offset === 0) momentDate = momentDate.utc();
|
||||
return momentDate.format(this.convertFormat(this.options.format));
|
||||
},
|
||||
@ -71,6 +72,11 @@ define('date',
|
||||
});
|
||||
},
|
||||
convertFormat: function (format) {
|
||||
var replacements;
|
||||
var convertedFormat;
|
||||
var escapeToken;
|
||||
var index;
|
||||
var token;
|
||||
var format_mappings = {
|
||||
date: {
|
||||
d: 'DD',
|
||||
@ -140,12 +146,11 @@ define('date',
|
||||
|
||||
if (!format || format.length <= 0) return format;
|
||||
|
||||
var replacements = format_mappings['date'];
|
||||
replacements = format_mappings['date'];
|
||||
convertedFormat = [];
|
||||
escapeToken = false;
|
||||
|
||||
var convertedFormat = [];
|
||||
var escapeToken = false;
|
||||
|
||||
for (var index = 0, token = ''; format.charAt(index); index += 1) {
|
||||
for (index = 0, token = ''; format.charAt(index); index += 1) {
|
||||
token = format.charAt(index);
|
||||
if (escapeToken === true) {
|
||||
convertedFormat.push('[' + token + ']');
|
||||
|
@ -7,6 +7,10 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var Observable;
|
||||
var WysijaHistory;
|
||||
var WysijaForm;
|
||||
|
||||
Event.cacheDelegated = {};
|
||||
Object.extend(document, (function () {
|
||||
var cache = Event.cacheDelegated;
|
||||
@ -30,18 +34,21 @@ Object.extend(document, (function () {
|
||||
}
|
||||
|
||||
function destroyWrapper(selector, eventName, handler) {
|
||||
var wrapper;
|
||||
var c = getCacheForSelector(selector);
|
||||
if (!c[eventName]) return false;
|
||||
var wrapper = findWrapper(selector, eventName, handler);
|
||||
wrapper = findWrapper(selector, eventName, handler);
|
||||
c[eventName] = c[eventName].without(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function createWrapper(selector, eventName, handler, context) {
|
||||
var wrapper, c = getWrappersForSelector(selector, eventName);
|
||||
var wrapper;
|
||||
var element;
|
||||
var c = getWrappersForSelector(selector, eventName);
|
||||
if (c.pluck('handler').include(handler)) return false;
|
||||
wrapper = function (event) {
|
||||
var element = event.findElement(selector);
|
||||
element = event.findElement(selector);
|
||||
if (element) handler.call(context || element, event, element);
|
||||
};
|
||||
wrapper.handler = handler;
|
||||
@ -49,13 +56,14 @@ Object.extend(document, (function () {
|
||||
return wrapper;
|
||||
}
|
||||
return {
|
||||
delegate: function (selector, eventName, handler, context) {
|
||||
delegate: function (selector, eventName) {
|
||||
var wrapper = createWrapper.apply(null, arguments);
|
||||
if (wrapper) document.observe(eventName, wrapper);
|
||||
return document;
|
||||
},
|
||||
stopDelegating: function (selector, eventName, handler) {
|
||||
stopDelegating: function (selector, eventName) {
|
||||
var length = arguments.length;
|
||||
var wrapper;
|
||||
switch (length) {
|
||||
case 2:
|
||||
getWrappersForSelector(selector, eventName).each(function (wrapper) {
|
||||
@ -73,7 +81,7 @@ Object.extend(document, (function () {
|
||||
});
|
||||
break;
|
||||
default:
|
||||
var wrapper = destroyWrapper.apply(null, arguments);
|
||||
wrapper = destroyWrapper.apply(null, arguments);
|
||||
if (wrapper) document.stopObserving(eventName, wrapper);
|
||||
}
|
||||
return document;
|
||||
@ -81,7 +89,7 @@ Object.extend(document, (function () {
|
||||
};
|
||||
})());
|
||||
|
||||
var Observable = (function () {
|
||||
Observable = (function () {
|
||||
function getEventName(nameA, namespace) {
|
||||
var name = nameA.substring(2);
|
||||
if (namespace) name = namespace + ':' + name;
|
||||
@ -89,8 +97,8 @@ var Observable = (function () {
|
||||
}
|
||||
|
||||
function getHandlers(klass) {
|
||||
var proto = klass.prototype,
|
||||
namespace = proto.namespace;
|
||||
var proto = klass.prototype;
|
||||
var namespace = proto.namespace;
|
||||
return Object.keys(proto).grep(/^on/).inject(window.$H(), function (handlers, name) {
|
||||
if (name === 'onDomLoaded') return handlers;
|
||||
handlers.set(getEventName(name, namespace), getWrapper(proto[name], klass));
|
||||
@ -111,9 +119,9 @@ var Observable = (function () {
|
||||
}
|
||||
return {
|
||||
observe: function (selector) {
|
||||
var klass = this;
|
||||
if (!this.handlers) this.handlers = {};
|
||||
if (this.handlers[selector]) return;
|
||||
var klass = this;
|
||||
if (this.prototype.onDomLoaded) {
|
||||
if (document.loaded) {
|
||||
onDomLoad(selector, klass);
|
||||
@ -146,8 +154,9 @@ Object.extend(window.Droppables, {
|
||||
return proceed(drop);
|
||||
}),
|
||||
show: function (point, element) {
|
||||
var drop;
|
||||
var affected = [];
|
||||
if (!this.drops.length) return;
|
||||
var drop, affected = [];
|
||||
this.drops.each(function (drop) {
|
||||
if (window.Droppables.isAffected(point, element, drop)) affected.push(drop);
|
||||
});
|
||||
@ -159,13 +168,13 @@ Object.extend(window.Droppables, {
|
||||
if (drop !== this.last_active) window.Droppables.activate(drop, element);
|
||||
}
|
||||
},
|
||||
displayArea: function (draggable) {
|
||||
displayArea: function () {
|
||||
if (!this.drops.length) return;
|
||||
|
||||
// hide controls when displaying drop areas.
|
||||
WysijaForm.hideBlockControls();
|
||||
|
||||
this.drops.each(function (drop, iterator) {
|
||||
this.drops.each(function (drop) {
|
||||
if (drop.element.hasClassName('block_placeholder')) {
|
||||
drop.element.addClassName('active');
|
||||
}
|
||||
@ -173,7 +182,7 @@ Object.extend(window.Droppables, {
|
||||
},
|
||||
hideArea: function () {
|
||||
if (!this.drops.length) return;
|
||||
this.drops.each(function (drop, iterator) {
|
||||
this.drops.each(function (drop) {
|
||||
if (drop.element.hasClassName('block_placeholder')) {
|
||||
drop.element.removeClassName('active');
|
||||
} else if (drop.element.hasClassName('image_placeholder')) {
|
||||
@ -195,7 +204,7 @@ Object.extend(window.Droppables, {
|
||||
- set a maximum number of items to be stored
|
||||
|
||||
*/
|
||||
var WysijaHistory = {
|
||||
WysijaHistory = {
|
||||
container: 'mailpoet_form_history',
|
||||
size: 30,
|
||||
enqueue: function (element) {
|
||||
@ -239,7 +248,7 @@ var WysijaHistory = {
|
||||
};
|
||||
|
||||
/* MailPoet Form */
|
||||
var WysijaForm = {
|
||||
WysijaForm = {
|
||||
version: '0.7',
|
||||
options: {
|
||||
container: 'mailpoet_form_container',
|
||||
@ -292,6 +301,7 @@ var WysijaForm = {
|
||||
});
|
||||
},
|
||||
load: function (data) {
|
||||
var settings_elements;
|
||||
if (data === undefined) return;
|
||||
|
||||
// load body
|
||||
@ -302,7 +312,7 @@ var WysijaForm = {
|
||||
});
|
||||
|
||||
// load settings
|
||||
var settings_elements = window.$('mailpoet_form_settings').getElements();
|
||||
settings_elements = window.$('mailpoet_form_settings').getElements();
|
||||
settings_elements.each(function (setting) {
|
||||
// skip lists
|
||||
if (setting.name === 'segments') {
|
||||
@ -324,13 +334,13 @@ var WysijaForm = {
|
||||
}
|
||||
},
|
||||
save: function () {
|
||||
var position = 1,
|
||||
data = {
|
||||
name: window.$F('mailpoet_form_name'),
|
||||
settings: window.$('mailpoet_form_settings').serialize(true),
|
||||
body: [],
|
||||
styles: (window.MailPoet.CodeEditor !== undefined) ? window.MailPoet.CodeEditor.getValue() : null
|
||||
};
|
||||
var position = 1;
|
||||
var data = {
|
||||
name: window.$F('mailpoet_form_name'),
|
||||
settings: window.$('mailpoet_form_settings').serialize(true),
|
||||
body: [],
|
||||
styles: (window.MailPoet.CodeEditor !== undefined) ? window.MailPoet.CodeEditor.getValue() : null
|
||||
};
|
||||
// body
|
||||
WysijaForm.getBlocks().each(function (b) {
|
||||
var block_data = (typeof (b.block['save']) === 'function') ? b.block.save() : null;
|
||||
@ -401,6 +411,7 @@ var WysijaForm = {
|
||||
return data;
|
||||
},
|
||||
toggleWidgets: function () {
|
||||
var hasSegmentSelection;
|
||||
window.$$('a[wysija_unique="1"]').invoke('removeClassName', 'disabled');
|
||||
|
||||
// loop through each unique field already inserted in the editor and disable its toolbar equivalent
|
||||
@ -411,7 +422,7 @@ var WysijaForm = {
|
||||
}
|
||||
});
|
||||
|
||||
var hasSegmentSelection = WysijaForm.hasSegmentSelection();
|
||||
hasSegmentSelection = WysijaForm.hasSegmentSelection();
|
||||
|
||||
if (hasSegmentSelection) {
|
||||
window.$('mailpoet_form_segments').writeAttribute('required', false).disable();
|
||||
@ -426,8 +437,9 @@ var WysijaForm = {
|
||||
},
|
||||
isSegmentSelectionValid: function () {
|
||||
var segment_selection = window.$$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]')[0];
|
||||
var block;
|
||||
if (segment_selection !== undefined) {
|
||||
var block = WysijaForm.get(segment_selection).block.getData();
|
||||
block = WysijaForm.get(segment_selection).block.getData();
|
||||
return (
|
||||
(block.params.values !== undefined)
|
||||
&&
|
||||
@ -437,10 +449,12 @@ var WysijaForm = {
|
||||
return false;
|
||||
},
|
||||
setBlockPositions: function (event, target) {
|
||||
var index = 1;
|
||||
var block_placeholder;
|
||||
var previous_placeholder;
|
||||
// release dragging lock
|
||||
WysijaForm.locks.dragging = false;
|
||||
|
||||
var index = 1;
|
||||
WysijaForm.getBlocks().each(function (container) {
|
||||
container.setPosition(index++);
|
||||
// remove z-index value to avoid issues when resizing images
|
||||
@ -453,8 +467,8 @@ var WysijaForm = {
|
||||
|
||||
if (target !== undefined) {
|
||||
// get placeholders (previous placeholder matches the placeholder linked to the next block)
|
||||
var block_placeholder = window.$(target.element.readAttribute('wysija_placeholder')),
|
||||
previous_placeholder = target.element.previous('.block_placeholder');
|
||||
block_placeholder = window.$(target.element.readAttribute('wysija_placeholder'));
|
||||
previous_placeholder = target.element.previous('.block_placeholder');
|
||||
|
||||
if (block_placeholder !== null) {
|
||||
// put block placeholder before the current block
|
||||
@ -479,23 +493,17 @@ var WysijaForm = {
|
||||
},
|
||||
setSettingsPosition: function () {
|
||||
// get viewport offsets and dimensions
|
||||
var viewportHeight = document.viewport.getHeight(),
|
||||
blockPadding = 5;
|
||||
var viewportHeight = document.viewport.getHeight();
|
||||
|
||||
window.$(WysijaForm.options.container).select('.wysija_settings').each(function (element) {
|
||||
// get parent dimensions and position
|
||||
var parentDim = element.up('.mailpoet_form_block').getDimensions(),
|
||||
parentPos = element.up('.mailpoet_form_block').cumulativeOffset(),
|
||||
is_visible = (parentPos.top <= (WysijaForm.scroll.top + viewportHeight)),
|
||||
buttonMargin = 5,
|
||||
relativeTop = buttonMargin;
|
||||
var parentDim = element.up('.mailpoet_form_block').getDimensions();
|
||||
var parentPos = element.up('.mailpoet_form_block').cumulativeOffset();
|
||||
var is_visible = (parentPos.top <= (WysijaForm.scroll.top + viewportHeight));
|
||||
var buttonMargin = 5;
|
||||
var relativeTop = buttonMargin;
|
||||
|
||||
if (is_visible) {
|
||||
// desired position is set to center of viewport
|
||||
var absoluteTop = parseInt(WysijaForm.scroll.top + ((viewportHeight / 2) - (element.getHeight() / 2)), 10),
|
||||
parentTop = parseInt(parentPos.top - blockPadding, 10),
|
||||
parentBottom = parseInt(parentPos.top + parentDim.height - blockPadding, 10);
|
||||
|
||||
// always center
|
||||
relativeTop = parseInt((parentDim.height / 2) - (element.getHeight() / 2), 10);
|
||||
}
|
||||
@ -519,9 +527,10 @@ var WysijaForm = {
|
||||
|
||||
},
|
||||
setToolbarPosition: function () {
|
||||
var position;
|
||||
WysijaForm.initToolbarPosition();
|
||||
|
||||
var position = {
|
||||
position = {
|
||||
top: WysijaForm.toolbar.y + 'px',
|
||||
visibility: 'visible'
|
||||
};
|
||||
@ -585,10 +594,12 @@ var WysijaForm = {
|
||||
instances: {},
|
||||
get: function (element, typ) {
|
||||
var type = typ;
|
||||
var id;
|
||||
var instance;
|
||||
if (type === undefined) type = 'block';
|
||||
// identify element
|
||||
var id = element.identify();
|
||||
var instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
|
||||
id = element.identify();
|
||||
instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
|
||||
|
||||
WysijaForm.instances[id] = instance;
|
||||
return instance;
|
||||
@ -636,8 +647,8 @@ var WysijaForm = {
|
||||
},
|
||||
encodeURIComponent: function (str) {
|
||||
// check if it's a url and if so, prevent encoding of protocol
|
||||
var regexp = new RegExp(/^http[s]?:\/\//),
|
||||
protocol = regexp.exec(str);
|
||||
var regexp = new RegExp(/^http[s]?:\/\//);
|
||||
var protocol = regexp.exec(str);
|
||||
|
||||
if (protocol === null) {
|
||||
// this is not a url so encode the whole thing
|
||||
@ -680,13 +691,13 @@ WysijaForm.DraggableItem = window.Class.create({
|
||||
},
|
||||
STYLES: new window.Template('position: absolute; top: #{top}px; left: #{left}px;'),
|
||||
cloneElement: function () {
|
||||
var clone = this.element.clone(),
|
||||
offset = this.element.cumulativeOffset(),
|
||||
list = this.getList(),
|
||||
styles = this.STYLES.evaluate({
|
||||
top: offset.top - list.scrollTop,
|
||||
left: offset.left - list.scrollLeft
|
||||
});
|
||||
var clone = this.element.clone();
|
||||
var offset = this.element.cumulativeOffset();
|
||||
var list = this.getList();
|
||||
var styles = this.STYLES.evaluate({
|
||||
top: offset.top - list.scrollTop,
|
||||
left: offset.left - list.scrollLeft
|
||||
});
|
||||
clone.setStyle(styles);
|
||||
|
||||
clone.addClassName('mailpoet_form_widget');
|
||||
@ -767,15 +778,17 @@ WysijaForm.Block = window.Class.create({
|
||||
}
|
||||
},
|
||||
makeBlockDroppable: function () {
|
||||
var block_placeholder;
|
||||
if (this.isBlockDroppableEnabled() === false) {
|
||||
var block_placeholder = this.getBlockDroppable();
|
||||
block_placeholder = this.getBlockDroppable();
|
||||
window.Droppables.add(block_placeholder.identify(), WysijaForm.blockDropOptions);
|
||||
block_placeholder.addClassName('enabled');
|
||||
}
|
||||
},
|
||||
removeBlockDroppable: function () {
|
||||
var block_placeholder;
|
||||
if (this.isBlockDroppableEnabled()) {
|
||||
var block_placeholder = this.getBlockDroppable();
|
||||
block_placeholder = this.getBlockDroppable();
|
||||
window.Droppables.remove(block_placeholder.identify());
|
||||
block_placeholder.removeClassName('enabled');
|
||||
}
|
||||
@ -807,6 +820,7 @@ WysijaForm.Block = window.Class.create({
|
||||
return this.element.down('.wysija_controls');
|
||||
},
|
||||
setupControls: function () {
|
||||
var block;
|
||||
// enable controls
|
||||
this.controls = this.getControls();
|
||||
|
||||
@ -857,9 +871,8 @@ WysijaForm.Block = window.Class.create({
|
||||
if (this.settingsButton !== null) {
|
||||
this.settingsButton.observe('click', function (event) {
|
||||
// TODO: refactor
|
||||
var block = window.$(event.target).up('.mailpoet_form_block') || null;
|
||||
block = window.$(event.target).up('.mailpoet_form_block') || null;
|
||||
if (block !== null) {
|
||||
var field = WysijaForm.getFieldData(block);
|
||||
this.editSettings();
|
||||
}
|
||||
}.bind(this));
|
||||
@ -905,18 +918,23 @@ WysijaForm.Block = window.Class.create({
|
||||
/* Invoked on item dropped */
|
||||
WysijaForm.Block.create = function (createBlock, target) {
|
||||
var block = createBlock;
|
||||
var body;
|
||||
var block_template;
|
||||
var template;
|
||||
var output;
|
||||
var settings_segments;
|
||||
if (window.$('form_template_' + block.type) === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var body = window.$(WysijaForm.options.body),
|
||||
block_template = window.Handlebars.compile(window.$('form_template_block').innerHTML),
|
||||
template = window.Handlebars.compile(window.$('form_template_' + block.type).innerHTML),
|
||||
output = '';
|
||||
body = window.$(WysijaForm.options.body);
|
||||
block_template = window.Handlebars.compile(window.$('form_template_block').innerHTML);
|
||||
template = window.Handlebars.compile(window.$('form_template_' + block.type).innerHTML);
|
||||
output = '';
|
||||
|
||||
if (block.type === 'segment') {
|
||||
if (block.params.values === undefined) {
|
||||
var settings_segments = window.jQuery('#mailpoet_form_segments').val();
|
||||
settings_segments = window.jQuery('#mailpoet_form_segments').val();
|
||||
if (settings_segments !== null && settings_segments.length > 0) {
|
||||
block.params.values = window.mailpoet_segments.filter(function (segment) {
|
||||
return (settings_segments.indexOf(segment.id) !== -1);
|
||||
@ -936,14 +954,13 @@ WysijaForm.Block.create = function (createBlock, target) {
|
||||
}
|
||||
|
||||
// if the drop target was the bottom placeholder
|
||||
var element = null;
|
||||
if (target.identify() === 'block_placeholder') {
|
||||
// insert block at the bottom
|
||||
element = body.insert(output);
|
||||
body.insert(output);
|
||||
// block = body.childElements().last();
|
||||
} else {
|
||||
// insert block before the drop target
|
||||
element = target.insert({
|
||||
target.insert({
|
||||
before: output
|
||||
});
|
||||
// block = target.previous('.mailpoet_form_block');
|
||||
@ -984,8 +1001,8 @@ WysijaForm.Widget = window.Class.create(WysijaForm.Block, {
|
||||
this.setupControls();
|
||||
},
|
||||
save: function () {
|
||||
info('widget -> save');
|
||||
var data = this.getData();
|
||||
info('widget -> save');
|
||||
|
||||
if (data.element !== undefined) {
|
||||
delete data.element;
|
||||
@ -994,8 +1011,8 @@ WysijaForm.Widget = window.Class.create(WysijaForm.Block, {
|
||||
return data;
|
||||
},
|
||||
setData: function (data) {
|
||||
var current_data = this.getData(),
|
||||
params = window.$H(current_data.params).merge(data.params).toObject();
|
||||
var current_data = this.getData();
|
||||
var params = window.$H(current_data.params).merge(data.params).toObject();
|
||||
|
||||
// update type if it changed
|
||||
if (data.type !== undefined && data.type !== current_data.type) {
|
||||
@ -1020,16 +1037,20 @@ WysijaForm.Widget = window.Class.create(WysijaForm.Block, {
|
||||
this.removeBlock();
|
||||
},
|
||||
redraw: function (data) {
|
||||
var options;
|
||||
var block_template;
|
||||
var template;
|
||||
var params;
|
||||
// set parameters
|
||||
this.setData(data);
|
||||
var options = this.getData();
|
||||
options = this.getData();
|
||||
// redraw block
|
||||
var block_template = window.Handlebars.compile(window.$('form_template_block').innerHTML),
|
||||
template = window.Handlebars.compile(window.$('form_template_' + options.type).innerHTML),
|
||||
data = window.$H(options).merge({
|
||||
template: template(options)
|
||||
}).toObject();
|
||||
this.element.replace(block_template(data));
|
||||
block_template = window.Handlebars.compile(window.$('form_template_block').innerHTML);
|
||||
template = window.Handlebars.compile(window.$('form_template_' + options.type).innerHTML);
|
||||
params = window.$H(options).merge({
|
||||
template: template(options)
|
||||
}).toObject();
|
||||
this.element.replace(block_template(params));
|
||||
|
||||
WysijaForm.init();
|
||||
},
|
||||
@ -1061,8 +1082,8 @@ function info(value) {
|
||||
var noop = function () {};
|
||||
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
|
||||
var length = methods.length;
|
||||
window.console = {};
|
||||
var console = {};
|
||||
window.console = {};
|
||||
while (length--) {
|
||||
console[methods[length]] = noop;
|
||||
}
|
||||
|
@ -1,26 +1,28 @@
|
||||
define('handlebars_helpers', ['handlebars'], function (Handlebars) {
|
||||
// Handlebars helpers
|
||||
Handlebars.registerHelper('concat', function () {
|
||||
var size = (arguments.length - 1),
|
||||
output = '';
|
||||
for (var i = 0; i < size; i++) {
|
||||
var size = (arguments.length - 1);
|
||||
var output = '';
|
||||
var i;
|
||||
for (i = 0; i < size; i++) {
|
||||
output += arguments[i];
|
||||
}
|
||||
return output;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('number_format', function (value, block) {
|
||||
Handlebars.registerHelper('number_format', function (value) {
|
||||
return Number(value).toLocaleString();
|
||||
});
|
||||
Handlebars.registerHelper('date_format', function (timestamp, block) {
|
||||
var f;
|
||||
if (window.moment) {
|
||||
if (timestamp === undefined || isNaN(timestamp) || timestamp <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set date format
|
||||
var f = block.hash.format || 'MMM Do, YYYY';
|
||||
// check if we passed a timestamp
|
||||
// set date format
|
||||
f = block.hash.format || 'MMM Do, YYYY';
|
||||
// check if we passed a timestamp
|
||||
if (parseInt(timestamp, 10) == timestamp) {
|
||||
return window.moment.unix(timestamp).format(f);
|
||||
} else {
|
||||
@ -59,25 +61,24 @@ define('handlebars_helpers', ['handlebars'], function (Handlebars) {
|
||||
case '||':
|
||||
return (v1 || v2) ? options.fn(this) : options.inverse(this);
|
||||
case 'in':
|
||||
var values = v2.split(',');
|
||||
return (v2.indexOf(v1) !== -1) ? options.fn(this) : options.inverse(this);
|
||||
default:
|
||||
return options.inverse(this);
|
||||
}
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('nl2br', function (value, block) {
|
||||
Handlebars.registerHelper('nl2br', function (value) {
|
||||
return value.gsub('\n', '<br />');
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('json_encode', function (value, block) {
|
||||
Handlebars.registerHelper('json_encode', function (value) {
|
||||
return JSON.stringify(value);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('json_decode', function (value, block) {
|
||||
Handlebars.registerHelper('json_decode', function (value) {
|
||||
return JSON.parse(value);
|
||||
});
|
||||
Handlebars.registerHelper('url', function (value, block) {
|
||||
Handlebars.registerHelper('url', function (value) {
|
||||
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
||||
|
||||
return url + value;
|
||||
@ -90,16 +91,17 @@ define('handlebars_helpers', ['handlebars'], function (Handlebars) {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
Handlebars.registerHelper('lookup', function (obj, field, options) {
|
||||
Handlebars.registerHelper('lookup', function (obj, field) {
|
||||
return obj && obj[field];
|
||||
});
|
||||
|
||||
|
||||
Handlebars.registerHelper('rsa_key', function (value, block) {
|
||||
// extract all lines into an array
|
||||
Handlebars.registerHelper('rsa_key', function (value) {
|
||||
var lines;
|
||||
// extract all lines into an array
|
||||
if (value === undefined) return '';
|
||||
|
||||
var lines = value.trim().split('\n');
|
||||
lines = value.trim().split('\n');
|
||||
|
||||
// remove header & footer
|
||||
lines.shift();
|
||||
@ -109,7 +111,7 @@ define('handlebars_helpers', ['handlebars'], function (Handlebars) {
|
||||
return lines.join('');
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('trim', function (value, block) {
|
||||
Handlebars.registerHelper('trim', function (value) {
|
||||
if (value === null || value === undefined) return '';
|
||||
return value.trim();
|
||||
});
|
||||
@ -126,10 +128,10 @@ define('handlebars_helpers', ['handlebars'], function (Handlebars) {
|
||||
*/
|
||||
Handlebars.registerHelper('ellipsis', function (str, limit, append) {
|
||||
var strAppend = append;
|
||||
var sanitized = str.replace(/(<([^>]+)>)/g, '');
|
||||
if (strAppend === undefined) {
|
||||
strAppend = '';
|
||||
}
|
||||
var sanitized = str.replace(/(<([^>]+)>)/g, '');
|
||||
if (sanitized.length > limit) {
|
||||
return sanitized.substr(0, limit - strAppend.length) + strAppend;
|
||||
} else {
|
||||
|
@ -24,20 +24,20 @@ define(
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
$.fn.serializeObject = function (coerce) {
|
||||
var obj = {},
|
||||
coerce_types = { true: !0, false: !1, null: null };
|
||||
var obj = {};
|
||||
var coerce_types = { true: !0, false: !1, null: null };
|
||||
|
||||
// Iterate over all name=value pairs.
|
||||
$.each(this.serializeArray(), function (j, v) {
|
||||
var key = v.name,
|
||||
val = v.value,
|
||||
cur = obj,
|
||||
i = 0,
|
||||
var key = v.name;
|
||||
var val = v.value;
|
||||
var cur = obj;
|
||||
var i = 0;
|
||||
|
||||
// If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
|
||||
// into its component parts.
|
||||
keys = key.split(']['),
|
||||
keys_last = keys.length - 1;
|
||||
// If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
|
||||
// into its component parts.
|
||||
var keys = key.split('][');
|
||||
var keys_last = keys.length - 1;
|
||||
|
||||
// If the first keys part contains [ and the last ends with ], then []
|
||||
// are correctly balanced.
|
||||
@ -106,4 +106,4 @@ define(
|
||||
|
||||
return $;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -658,8 +658,8 @@ const Listing = React.createClass({
|
||||
});
|
||||
},
|
||||
handleSelectItem: function (id, is_checked) {
|
||||
let selected_ids = this.state.selected_ids,
|
||||
selection = false;
|
||||
let selected_ids = this.state.selected_ids;
|
||||
let selection = false;
|
||||
|
||||
if (is_checked) {
|
||||
selected_ids = jQuery.merge(selected_ids, [id]);
|
||||
|
@ -116,6 +116,7 @@ define('modal', ['mailpoet', 'jquery'],
|
||||
}
|
||||
},
|
||||
init: function (options) {
|
||||
var modal;
|
||||
if (this.initialized === true) {
|
||||
this.close();
|
||||
}
|
||||
@ -134,7 +135,7 @@ define('modal', ['mailpoet', 'jquery'],
|
||||
if (this.options.type !== null) {
|
||||
// insert modal depending on its type
|
||||
if (this.options.type === 'popup') {
|
||||
var modal = this.compileTemplate(
|
||||
modal = this.compileTemplate(
|
||||
this.templates[this.options.type]
|
||||
);
|
||||
// create modal
|
||||
@ -178,7 +179,7 @@ define('modal', ['mailpoet', 'jquery'],
|
||||
|
||||
return this;
|
||||
},
|
||||
initOverlay: function (toggle) {
|
||||
initOverlay: function () {
|
||||
if (jQuery('#mailpoet_modal_overlay').length === 0) {
|
||||
// insert overlay into the DOM
|
||||
jQuery('body').append(this.templates.overlay);
|
||||
@ -343,20 +344,21 @@ define('modal', ['mailpoet', 'jquery'],
|
||||
return this;
|
||||
},
|
||||
setPosition: function () {
|
||||
var screenWidth;
|
||||
var screenHeight;
|
||||
var modalWidth;
|
||||
var modalHeight;
|
||||
switch (this.options.type) {
|
||||
case 'popup':
|
||||
var screenWidth = jQuery(window).width(),
|
||||
screenHeight = jQuery(window).height(),
|
||||
modalWidth = jQuery('.mailpoet_' + this.options.type + '_wrapper').width(),
|
||||
modalHeight = jQuery('.mailpoet_' + this.options.type + '_wrapper').height();
|
||||
screenWidth = jQuery(window).width();
|
||||
screenHeight = jQuery(window).height();
|
||||
modalWidth = jQuery('.mailpoet_'+ this.options.type +'_wrapper').width();
|
||||
modalHeight = jQuery('.mailpoet_'+ this.options.type +'_wrapper').height();
|
||||
|
||||
var top = Math.max(48, parseInt((screenHeight / 2) - (modalHeight / 2))),
|
||||
left = Math.max(0, parseInt((screenWidth / 2) - (modalWidth / 2)));
|
||||
|
||||
// set position of popup depending on screen dimensions.
|
||||
// set position of popup depending on screen dimensions.
|
||||
jQuery('#mailpoet_popup').css({
|
||||
top: top,
|
||||
left: left
|
||||
top: Math.max(48, parseInt((screenHeight / 2) - (modalHeight / 2))),
|
||||
left: Math.max(0, parseInt((screenWidth / 2) - (modalWidth / 2)))
|
||||
});
|
||||
break;
|
||||
case 'panel':
|
||||
@ -436,7 +438,7 @@ define('modal', ['mailpoet', 'jquery'],
|
||||
.removeClass('mailpoet_modal_highlight');
|
||||
return this;
|
||||
},
|
||||
hideModal: function (callback) {
|
||||
hideModal: function () {
|
||||
// set modal as closed
|
||||
this.opened = false;
|
||||
|
||||
@ -451,7 +453,7 @@ define('modal', ['mailpoet', 'jquery'],
|
||||
|
||||
return this;
|
||||
},
|
||||
showOverlay: function (force) {
|
||||
showOverlay: function () {
|
||||
jQuery('#mailpoet_modal_overlay').show();
|
||||
return this;
|
||||
},
|
||||
|
@ -1,12 +1,8 @@
|
||||
define([
|
||||
'backbone',
|
||||
'backbone.marionette',
|
||||
'backbone.radio',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'handlebars',
|
||||
'handlebars_helpers'
|
||||
], function (Backbone, Marionette, BackboneRadio, jQuery, _, Handlebars) {
|
||||
'backbone.radio'
|
||||
], function (Backbone, Marionette, BackboneRadio) {
|
||||
var Radio = BackboneRadio;
|
||||
|
||||
var AppView = Marionette.View.extend({
|
||||
|
@ -8,13 +8,13 @@ define([
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'mailpoet',
|
||||
'spectrum'
|
||||
], function (Marionette, BehaviorsLookup, MailPoet, Spectrum) {
|
||||
], function (Marionette, BehaviorsLookup, MailPoet) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BL.ColorPickerBehavior = Marionette.Behavior.extend({
|
||||
onRender: function () {
|
||||
var that = this,
|
||||
preferredFormat = 'hex6';
|
||||
var that = this;
|
||||
var preferredFormat = 'hex6';
|
||||
this.view.$('.mailpoet_color').each(function () {
|
||||
var $input = that.view.$(this);
|
||||
var updateColorInput = function (color) {
|
||||
|
@ -25,11 +25,11 @@ define([
|
||||
this.addDropZone();
|
||||
}
|
||||
},
|
||||
addDropZone: function (_event) {
|
||||
var that = this,
|
||||
view = this.view,
|
||||
domElement = that.$el.get(0),
|
||||
acceptableElementSelector;
|
||||
addDropZone: function () {
|
||||
var that = this;
|
||||
var view = this.view;
|
||||
var domElement = that.$el.get(0);
|
||||
var acceptableElementSelector;
|
||||
|
||||
// TODO: Extract this limitation code to be controlled from containers
|
||||
if (this.view.renderOptions.depth === 0) {
|
||||
@ -47,11 +47,11 @@ define([
|
||||
interact(domElement).dropzone({
|
||||
accept: acceptableElementSelector,
|
||||
overlap: 'pointer', // Mouse pointer denotes location of a droppable
|
||||
ondragenter: function (event) {
|
||||
ondragenter: function () {
|
||||
// 1. Visually mark block as active for dropping
|
||||
view.$el.addClass('mailpoet_drop_active');
|
||||
},
|
||||
ondragleave: function (event) {
|
||||
ondragleave: function () {
|
||||
// 1. Remove visual markings of active dropping container
|
||||
// 2. Remove visual markings of drop position visualization
|
||||
that.cleanup();
|
||||
@ -63,20 +63,26 @@ define([
|
||||
// 3b. If insertion is special, compute position (which side) and which cell the insertion belongs to
|
||||
// 4. If insertion at that position is not visualized, display position visualization there, remove other visualizations from this container
|
||||
var dropPosition = that.getDropPosition(
|
||||
event.dragmove.pageX,
|
||||
event.dragmove.pageY,
|
||||
view.$el,
|
||||
view.model.get('orientation'),
|
||||
view.model.get('blocks').length
|
||||
),
|
||||
element = view.$el,
|
||||
markerWidth = '',
|
||||
markerHeight = '',
|
||||
containerOffset = element.offset(),
|
||||
viewCollection = that.getCollection(),
|
||||
marker, targetModel, targetView, targetElement,
|
||||
topOffset, leftOffset, isLastBlockInsertion,
|
||||
$targetBlock, margin;
|
||||
event.dragmove.pageX,
|
||||
event.dragmove.pageY,
|
||||
view.$el,
|
||||
view.model.get('orientation'),
|
||||
view.model.get('blocks').length
|
||||
);
|
||||
var element = view.$el;
|
||||
var markerWidth = '';
|
||||
var markerHeight = '';
|
||||
var containerOffset = element.offset();
|
||||
var viewCollection = that.getCollection();
|
||||
var marker;
|
||||
var targetModel;
|
||||
var targetView;
|
||||
var targetElement;
|
||||
var topOffset;
|
||||
var leftOffset;
|
||||
var isLastBlockInsertion;
|
||||
var $targetBlock;
|
||||
var margin;
|
||||
|
||||
if (dropPosition === undefined) return;
|
||||
|
||||
@ -178,15 +184,19 @@ define([
|
||||
// 4. Perform cleanup actions
|
||||
|
||||
var dropPosition = that.getDropPosition(
|
||||
event.dragEvent.pageX,
|
||||
event.dragEvent.pageY,
|
||||
view.$el,
|
||||
view.model.get('orientation'),
|
||||
view.model.get('blocks').length
|
||||
),
|
||||
droppableModel = event.draggable.getDropModel(),
|
||||
viewCollection = that.getCollection(),
|
||||
droppedView, droppedModel, index, tempCollection, tempCollection2;
|
||||
event.dragEvent.pageX,
|
||||
event.dragEvent.pageY,
|
||||
view.$el,
|
||||
view.model.get('orientation'),
|
||||
view.model.get('blocks').length
|
||||
);
|
||||
var droppableModel = event.draggable.getDropModel();
|
||||
var viewCollection = that.getCollection();
|
||||
var droppedView;
|
||||
var index;
|
||||
var tempCollection;
|
||||
var tempCollection2;
|
||||
var tempModel;
|
||||
|
||||
if (dropPosition === undefined) return;
|
||||
|
||||
@ -210,7 +220,7 @@ define([
|
||||
} else {
|
||||
// Special insertion by replacing target block with collection
|
||||
// and inserting dropModel into that
|
||||
var tempModel = viewCollection.at(dropPosition.index);
|
||||
tempModel = viewCollection.at(dropPosition.index);
|
||||
|
||||
tempCollection = new (window.EditorApplication.getBlockTypeModel('container'))({
|
||||
orientation: (view.model.get('orientation') === 'vertical') ? 'horizontal' : 'vertical'
|
||||
@ -272,26 +282,30 @@ define([
|
||||
this.view.$('.mailpoet_drop_marker').remove();
|
||||
},
|
||||
getDropPosition: function (eventX, eventY, is_unsafe) {
|
||||
var SPECIAL_AREA_INSERTION_WIDTH = 0.00, // Disable special insertion. Default: 0.3
|
||||
var SPECIAL_AREA_INSERTION_WIDTH = 0.00; // Disable special insertion. Default: 0.3
|
||||
|
||||
element = this.view.$el,
|
||||
orientation = this.view.model.get('orientation'),
|
||||
var element = this.view.$el;
|
||||
var orientation = this.view.model.get('orientation');
|
||||
|
||||
elementOffset = element.offset(),
|
||||
elementPageX = elementOffset.left,
|
||||
elementPageY = elementOffset.top,
|
||||
elementWidth = element.outerWidth(true),
|
||||
elementHeight = element.outerHeight(true),
|
||||
var elementOffset = element.offset();
|
||||
var elementPageX = elementOffset.left;
|
||||
var elementPageY = elementOffset.top;
|
||||
var elementWidth = element.outerWidth(true);
|
||||
var elementHeight = element.outerHeight(true);
|
||||
|
||||
relativeX = eventX - elementPageX,
|
||||
relativeY = eventY - elementPageY,
|
||||
var relativeX = eventX - elementPageX;
|
||||
var relativeY = eventY - elementPageY;
|
||||
|
||||
relativeOffset, elementLength,
|
||||
var relativeOffset;
|
||||
var elementLength;
|
||||
|
||||
canAcceptNormalInsertion = this._canAcceptNormalInsertion(),
|
||||
canAcceptSpecialInsertion = this._canAcceptSpecialInsertion(),
|
||||
var canAcceptNormalInsertion = this._canAcceptNormalInsertion();
|
||||
var canAcceptSpecialInsertion = this._canAcceptSpecialInsertion();
|
||||
|
||||
insertionType, index, position, indexAndPosition;
|
||||
var insertionType;
|
||||
var index;
|
||||
var position;
|
||||
var indexAndPosition;
|
||||
|
||||
var unsafe = !!is_unsafe;
|
||||
|
||||
@ -359,12 +373,14 @@ define([
|
||||
// target element if event happens on the second half of the element.
|
||||
// Halves depend on orientation.
|
||||
|
||||
var index = this._computeCellIndex(eventX, eventY),
|
||||
// TODO: Handle case when there are no children, container is empty
|
||||
targetView = this.getChildren().findByModel(this.getCollection().at(index)),
|
||||
orientation = this.view.model.get('orientation'),
|
||||
element = targetView.$el,
|
||||
eventOffset, closeOffset, elementDimension;
|
||||
var index = this._computeCellIndex(eventX, eventY);
|
||||
// TODO: Handle case when there are no children, container is empty
|
||||
var targetView = this.getChildren().findByModel(this.getCollection().at(index));
|
||||
var orientation = this.view.model.get('orientation');
|
||||
var element = targetView.$el;
|
||||
var eventOffset;
|
||||
var closeOffset;
|
||||
var elementDimension;
|
||||
|
||||
if (orientation === 'vertical') {
|
||||
eventOffset = eventY;
|
||||
@ -394,39 +410,40 @@ define([
|
||||
return this._computeCellIndex(eventX, eventY);
|
||||
},
|
||||
_computeCellIndex: function (eventX, eventY) {
|
||||
var orientation = this.view.model.get('orientation'),
|
||||
eventOffset = (orientation === 'vertical') ? eventY : eventX,
|
||||
resultView = this.getChildren().find(function (view) {
|
||||
var element = view.$el,
|
||||
closeOffset, farOffset;
|
||||
var orientation = this.view.model.get('orientation');
|
||||
var eventOffset = (orientation === 'vertical') ? eventY : eventX;
|
||||
var resultView = this.getChildren().find(function (view) {
|
||||
var element = view.$el;
|
||||
var closeOffset;
|
||||
var farOffset;
|
||||
|
||||
if (orientation === 'vertical') {
|
||||
closeOffset = element.offset().top;
|
||||
farOffset = element.outerHeight(true);
|
||||
} else {
|
||||
closeOffset = element.offset().left;
|
||||
farOffset = element.outerWidth(true);
|
||||
}
|
||||
farOffset += closeOffset;
|
||||
if (orientation === 'vertical') {
|
||||
closeOffset = element.offset().top;
|
||||
farOffset = element.outerHeight(true);
|
||||
} else {
|
||||
closeOffset = element.offset().left;
|
||||
farOffset = element.outerWidth(true);
|
||||
}
|
||||
farOffset += closeOffset;
|
||||
|
||||
return closeOffset <= eventOffset && eventOffset <= farOffset;
|
||||
});
|
||||
return closeOffset <= eventOffset && eventOffset <= farOffset;
|
||||
});
|
||||
|
||||
var index = (typeof resultView === 'object') ? resultView._index : 0;
|
||||
|
||||
return index;
|
||||
},
|
||||
_canAcceptNormalInsertion: function () {
|
||||
var orientation = this.view.model.get('orientation'),
|
||||
depth = this.view.renderOptions.depth,
|
||||
childCount = this.getChildren().length;
|
||||
var orientation = this.view.model.get('orientation');
|
||||
var depth = this.view.renderOptions.depth;
|
||||
var childCount = this.getChildren().length;
|
||||
// Note that depth is zero indexed. Root container has depth=0
|
||||
return orientation === 'vertical' || (orientation === 'horizontal' && depth === 1 && childCount < this.options.columnLimit);
|
||||
},
|
||||
_canAcceptSpecialInsertion: function () {
|
||||
var orientation = this.view.model.get('orientation'),
|
||||
depth = this.view.renderOptions.depth,
|
||||
childCount = this.getChildren().length;
|
||||
var orientation = this.view.model.get('orientation');
|
||||
var depth = this.view.renderOptions.depth;
|
||||
var childCount = this.getChildren().length;
|
||||
return depth === 0 || (depth === 1 && orientation === 'horizontal' && childCount <= this.options.columnLimit);
|
||||
},
|
||||
getCollectionView: function () {
|
||||
|
@ -28,12 +28,12 @@ define([
|
||||
throw "Missing 'drop' function for DraggableBehavior";
|
||||
},
|
||||
|
||||
onDrop: function (model, view) {},
|
||||
testAttachToInstance: function (model, view) { return true; }
|
||||
onDrop: function () {},
|
||||
testAttachToInstance: function () { return true; }
|
||||
},
|
||||
onRender: function () {
|
||||
var that = this,
|
||||
interactable;
|
||||
var that = this;
|
||||
var interactable;
|
||||
|
||||
// Give instances more control over whether Draggable should be applied
|
||||
if (!this.options.testAttachToInstance(this.view.model, this.view)) return;
|
||||
@ -49,16 +49,19 @@ define([
|
||||
|
||||
onstart: function (startEvent) {
|
||||
var event = startEvent;
|
||||
var centerXOffset;
|
||||
var centerYOffset;
|
||||
var tempClone;
|
||||
var clone;
|
||||
var $clone;
|
||||
|
||||
if (that.options.cloneOriginal === true) {
|
||||
// Use substitution instead of a clone
|
||||
var tempClone = (_.isFunction(that.options.onDragSubstituteBy)) ? that.options.onDragSubstituteBy(that) : undefined,
|
||||
// Or use a clone
|
||||
clone = tempClone || event.target.cloneNode(true),
|
||||
|
||||
$original = jQuery(event.target),
|
||||
$clone = jQuery(clone),
|
||||
centerXOffset, centerYOffset, parentOffset;
|
||||
tempClone = (_.isFunction(that.options.onDragSubstituteBy)) ? that.options.onDragSubstituteBy(that) : undefined;
|
||||
// Or use a clone
|
||||
clone = tempClone || event.target.cloneNode(true);
|
||||
jQuery(event.target);
|
||||
$clone = jQuery(clone);
|
||||
|
||||
$clone.addClass('mailpoet_droppable_active');
|
||||
$clone.css('position', 'absolute');
|
||||
@ -85,10 +88,10 @@ define([
|
||||
},
|
||||
// call this function on every dragmove event
|
||||
onmove: function (event) {
|
||||
var target = event.target,
|
||||
// keep the dragged position in the data-x/data-y attributes
|
||||
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
|
||||
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
|
||||
var target = event.target;
|
||||
// keep the dragged position in the data-x/data-y attributes
|
||||
var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
|
||||
var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
|
||||
|
||||
// translate the element
|
||||
target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
|
||||
|
@ -14,12 +14,13 @@ define([
|
||||
defaults: {
|
||||
elementSelector: null,
|
||||
resizeHandleSelector: true, // true will use edges of the element itself
|
||||
transformationFunction: function (y) { return y; }, // for blocks that use the default onResize function
|
||||
minLength: 0,
|
||||
maxLength: Infinity,
|
||||
modelField: 'styles.block.height',
|
||||
onResize: function (event) {
|
||||
var currentLength = parseFloat(this.view.model.get(this.options.modelField)),
|
||||
newLength = currentLength + event.y;
|
||||
var currentLength = parseFloat(this.view.model.get(this.options.modelField));
|
||||
var newLength = currentLength + this.options.transformationFunction(event.dy);
|
||||
newLength = Math.min(this.options.maxLength, Math.max(this.options.minLength, newLength));
|
||||
this.view.model.set(this.options.modelField, newLength + 'px');
|
||||
}
|
||||
@ -36,8 +37,8 @@ define([
|
||||
}
|
||||
},
|
||||
attachResize: function () {
|
||||
var domElement = (this.options.elementSelector === null) ? this.view.$el.get(0) : this.view.$(this.options.elementSelector).get(0),
|
||||
that = this;
|
||||
var domElement = (this.options.elementSelector === null) ? this.view.$el.get(0) : this.view.$(this.options.elementSelector).get(0);
|
||||
var that = this;
|
||||
interact(domElement).resizable({
|
||||
// axis: 'y',
|
||||
edges: {
|
||||
@ -47,15 +48,14 @@ define([
|
||||
bottom: (typeof this.options.resizeHandleSelector === 'string') ? this.view.$(this.options.resizeHandleSelector).get(0) : this.options.resizeHandleSelector
|
||||
}
|
||||
})
|
||||
.on('resizestart', function (event) {
|
||||
.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);
|
||||
})
|
||||
.on('resizeend', function (event) {
|
||||
.on('resizeend', function () {
|
||||
that.isBeingResized = null;
|
||||
that.$el.removeClass('mailpoet_resize_active');
|
||||
});
|
||||
|
@ -24,9 +24,9 @@ define([
|
||||
ui.item.removeData('previousIndex');
|
||||
},
|
||||
update: function (event, ui) {
|
||||
var previousIndex = ui.item.data('previousIndex'),
|
||||
newIndex = ui.item.index(),
|
||||
model = collection.at(previousIndex);
|
||||
var previousIndex = ui.item.data('previousIndex');
|
||||
var newIndex = ui.item.index();
|
||||
var model = collection.at(previousIndex);
|
||||
|
||||
// Replicate DOM changes. Move target model to a new position
|
||||
// within the collection
|
||||
|
@ -42,7 +42,7 @@ define([
|
||||
relative_urls: false,
|
||||
remove_script_host: false,
|
||||
convert_urls: true,
|
||||
urlconverter_callback: function (url, node, on_save, name) {
|
||||
urlconverter_callback: function (url) {
|
||||
if (url.match(/\[.+\]/g)) {
|
||||
// Do not convert URLs with shortcodes
|
||||
return url;
|
||||
@ -57,7 +57,7 @@ define([
|
||||
plugins: this.options.plugins,
|
||||
|
||||
setup: function (editor) {
|
||||
editor.on('change', function (e) {
|
||||
editor.on('change', function () {
|
||||
that.view.triggerMethod('text:editor:change', editor.getContent());
|
||||
});
|
||||
|
||||
@ -71,12 +71,12 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('focus', function (e) {
|
||||
editor.on('focus', function () {
|
||||
that.view.triggerMethod('text:editor:focus');
|
||||
that._isActivationClick = true;
|
||||
});
|
||||
|
||||
editor.on('blur', function (e) {
|
||||
editor.on('blur', function () {
|
||||
that.view.triggerMethod('text:editor:blur');
|
||||
});
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
|
||||
Module.ALCSupervisor = SuperModel.extend({
|
||||
initialize: function () {
|
||||
@ -43,12 +43,13 @@ define([
|
||||
);
|
||||
},
|
||||
refresh: function () {
|
||||
var blocks;
|
||||
var models = App.findModels(function (model) {
|
||||
return model.get('type') === 'automatedLatestContent';
|
||||
}) || [];
|
||||
|
||||
if (models.length === 0) return;
|
||||
var blocks = _.map(models, function (model) {
|
||||
blocks = _.map(models, function (model) {
|
||||
return model.toJSON();
|
||||
});
|
||||
|
||||
@ -60,8 +61,8 @@ define([
|
||||
_.each(
|
||||
_.zip(models, renderedBlocks),
|
||||
function (args) {
|
||||
var model = args[0],
|
||||
contents = args[1];
|
||||
var model = args[0];
|
||||
var contents = args[1];
|
||||
model.trigger('refreshPosts', contents);
|
||||
}
|
||||
);
|
||||
@ -150,12 +151,12 @@ define([
|
||||
}),
|
||||
onDragSubstituteBy: function () { return Module.AutomatedLatestContentWidgetView; },
|
||||
onRender: function () {
|
||||
var ContainerView = App.getBlockTypeView('container'),
|
||||
renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay')
|
||||
};
|
||||
var ContainerView = App.getBlockTypeView('container');
|
||||
var renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay')
|
||||
};
|
||||
this.toolsView = new Module.AutomatedLatestContentBlockToolsView({ model: this.model });
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
this.showChildView('postsRegion', new ContainerView({ model: this.model.get('_container'), renderOptions: renderOptions }));
|
||||
@ -213,12 +214,13 @@ define([
|
||||
},
|
||||
transport: function (options, success, failure) {
|
||||
var taxonomies;
|
||||
var termsPromise;
|
||||
var promise = CommunicationComponent.getTaxonomies(
|
||||
that.model.get('contentType')
|
||||
).then(function (tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = CommunicationComponent.getTerms({
|
||||
termsPromise = CommunicationComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function (terms) {
|
||||
@ -227,7 +229,7 @@ define([
|
||||
terms: terms
|
||||
};
|
||||
});
|
||||
return promise;
|
||||
return termsPromise;
|
||||
});
|
||||
|
||||
promise.then(success);
|
||||
@ -264,9 +266,9 @@ define([
|
||||
}
|
||||
}).trigger('change');
|
||||
},
|
||||
toggleDisplayOptions: function (event) {
|
||||
var el = this.$('.mailpoet_automated_latest_content_display_options'),
|
||||
showControl = this.$('.mailpoet_automated_latest_content_show_display_options');
|
||||
toggleDisplayOptions: function () {
|
||||
var el = this.$('.mailpoet_automated_latest_content_display_options');
|
||||
var showControl = this.$('.mailpoet_automated_latest_content_show_display_options');
|
||||
if (el.hasClass('mailpoet_closed')) {
|
||||
el.removeClass('mailpoet_closed');
|
||||
showControl.addClass('mailpoet_hidden');
|
||||
@ -275,7 +277,7 @@ define([
|
||||
showControl.removeClass('mailpoet_hidden');
|
||||
}
|
||||
},
|
||||
showButtonSettings: function (event) {
|
||||
showButtonSettings: function () {
|
||||
var buttonModule = ButtonBlock;
|
||||
(new buttonModule.ButtonBlockSettingsView({
|
||||
model: this.model.get('readMoreButton'),
|
||||
@ -286,7 +288,7 @@ define([
|
||||
}
|
||||
})).render();
|
||||
},
|
||||
showDividerSettings: function (event) {
|
||||
showDividerSettings: function () {
|
||||
var dividerModule = DividerBlock;
|
||||
(new dividerModule.DividerBlockSettingsView({
|
||||
model: this.model.get('divider'),
|
||||
@ -349,8 +351,8 @@ define([
|
||||
this.changeField('titleFormat', event);
|
||||
},
|
||||
_updateContentTypes: function (postTypes) {
|
||||
var select = this.$('.mailpoet_automated_latest_content_content_type'),
|
||||
selectedValue = this.model.get('contentType');
|
||||
var select = this.$('.mailpoet_automated_latest_content_content_type');
|
||||
var selectedValue = this.model.get('contentType');
|
||||
|
||||
select.find('option').remove();
|
||||
_.each(postTypes, function (type) {
|
||||
@ -378,7 +380,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('automatedLatestContent', {
|
||||
blockModel: Module.AutomatedLatestContentBlockModel,
|
||||
blockView: Module.AutomatedLatestContentBlockView
|
||||
@ -391,7 +393,7 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
App.on('start', function (App, options) {
|
||||
App.on('start', function (App) {
|
||||
var Application = App;
|
||||
Application._ALCSupervisor = new Module.ALCSupervisor();
|
||||
Application._ALCSupervisor.refresh();
|
||||
|
@ -12,17 +12,16 @@ define([
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'modal'
|
||||
], function (App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
|
||||
], function (App, Marionette, SuperModel, _, jQuery, MailPoet) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
AugmentedView = Marionette.View.extend({});
|
||||
var Module = {};
|
||||
var AugmentedView = Marionette.View.extend({});
|
||||
|
||||
Module.BlockModel = SuperModel.extend({
|
||||
stale: [], // Attributes to be removed upon saving
|
||||
initialize: function () {
|
||||
var that = this;
|
||||
this.on('change', function () {
|
||||
App.getChannel().trigger('autoSave');
|
||||
});
|
||||
@ -68,7 +67,8 @@ define([
|
||||
options.dragBehavior.view.model.destroy();
|
||||
},
|
||||
onDragSubstituteBy: function (behavior) {
|
||||
var WidgetView, node;
|
||||
var WidgetView;
|
||||
var node;
|
||||
// When block is being dragged, display the widget icon instead.
|
||||
// This will create an instance of block's widget view and
|
||||
// use it's rendered DOM element instead of the content block
|
||||
@ -98,13 +98,13 @@ define([
|
||||
this.on('dom:refresh', this.showBlock, this);
|
||||
this._isFirstRender = true;
|
||||
},
|
||||
showTools: function (_event) {
|
||||
showTools: function () {
|
||||
if (!this.showingToolsDisabled) {
|
||||
this.$('> .mailpoet_tools').addClass('mailpoet_display_tools');
|
||||
this.toolsView.triggerMethod('showTools');
|
||||
}
|
||||
},
|
||||
hideTools: function (e) {
|
||||
hideTools: function () {
|
||||
this.$('> .mailpoet_tools').removeClass('mailpoet_display_tools');
|
||||
this.toolsView.triggerMethod('hideTools');
|
||||
},
|
||||
@ -240,8 +240,9 @@ define([
|
||||
ColorPickerBehavior: {}
|
||||
},
|
||||
initialize: function (params) {
|
||||
var panelParams;
|
||||
this.model.trigger('startEditing');
|
||||
var panelParams = {
|
||||
panelParams = {
|
||||
element: this.$el,
|
||||
template: '',
|
||||
position: 'right',
|
||||
@ -262,7 +263,7 @@ define([
|
||||
model: this.model.toJSON()
|
||||
};
|
||||
},
|
||||
close: function (event) {
|
||||
close: function () {
|
||||
this.destroy();
|
||||
},
|
||||
changeField: function (field, event) {
|
||||
|
@ -11,8 +11,8 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
|
||||
Module.ButtonBlockModel = base.BlockModel.extend({
|
||||
defaults: function () {
|
||||
@ -132,7 +132,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('button', {
|
||||
blockModel: Module.ButtonBlockModel,
|
||||
blockView: Module.ButtonBlockView
|
||||
|
@ -14,9 +14,9 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock,
|
||||
BlockCollection;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
var BlockCollection;
|
||||
|
||||
BlockCollection = Backbone.Collection.extend({
|
||||
model: base.BlockModel,
|
||||
@ -24,7 +24,6 @@ define([
|
||||
this.on('add change remove', function () { App.getChannel().trigger('autoSave'); });
|
||||
},
|
||||
parse: function (response) {
|
||||
var self = this;
|
||||
return _.map(response, function (block) {
|
||||
var Type = App.getBlockTypeModel(block.type);
|
||||
// TODO: If type has no registered model, use a backup one
|
||||
@ -66,7 +65,7 @@ define([
|
||||
return response;
|
||||
},
|
||||
getChildren: function () {
|
||||
var models = this.get('blocks').map(function (model, index, list) {
|
||||
var models = this.get('blocks').map(function (model) {
|
||||
return [model, model.getChildren()];
|
||||
});
|
||||
|
||||
@ -121,7 +120,8 @@ define([
|
||||
options.dragBehavior.view.model.destroy();
|
||||
},
|
||||
onDragSubstituteBy: function (behavior) {
|
||||
var WidgetView, node;
|
||||
var WidgetView;
|
||||
var node;
|
||||
// When block is being dragged, display the widget icon instead.
|
||||
// This will create an instance of block's widget view and
|
||||
// use it's rendered DOM element instead of the content block
|
||||
@ -190,24 +190,24 @@ define([
|
||||
}
|
||||
},
|
||||
toggleEditingLayer: function (event) {
|
||||
var that = this,
|
||||
$toggleButton = this.$('> .mailpoet_tools .mailpoet_newsletter_layer_selector'),
|
||||
$overlay = jQuery('.mailpoet_layer_overlay'),
|
||||
$container = this.$('> .mailpoet_container'),
|
||||
enableContainerLayer = function () {
|
||||
that.$el.addClass('mailpoet_container_layer_active');
|
||||
$toggleButton.addClass('mailpoet_container_layer_active');
|
||||
$container.addClass('mailpoet_layer_highlight');
|
||||
$overlay.click(disableContainerLayer);
|
||||
$overlay.show();
|
||||
},
|
||||
disableContainerLayer = function () {
|
||||
that.$el.removeClass('mailpoet_container_layer_active');
|
||||
$toggleButton.removeClass('mailpoet_container_layer_active');
|
||||
$container.removeClass('mailpoet_layer_highlight');
|
||||
$overlay.hide();
|
||||
$overlay.off('click');
|
||||
};
|
||||
var that = this;
|
||||
var $toggleButton = this.$('> .mailpoet_tools .mailpoet_newsletter_layer_selector');
|
||||
var $overlay = jQuery('.mailpoet_layer_overlay');
|
||||
var $container = this.$('> .mailpoet_container');
|
||||
var enableContainerLayer = function () {
|
||||
that.$el.addClass('mailpoet_container_layer_active');
|
||||
$toggleButton.addClass('mailpoet_container_layer_active');
|
||||
$container.addClass('mailpoet_layer_highlight');
|
||||
$overlay.click(disableContainerLayer);
|
||||
$overlay.show();
|
||||
};
|
||||
var disableContainerLayer = function () {
|
||||
that.$el.removeClass('mailpoet_container_layer_active');
|
||||
$toggleButton.removeClass('mailpoet_container_layer_active');
|
||||
$container.removeClass('mailpoet_layer_highlight');
|
||||
$overlay.hide();
|
||||
$overlay.off('click');
|
||||
};
|
||||
if ($toggleButton.hasClass('mailpoet_container_layer_active')) {
|
||||
disableContainerLayer();
|
||||
} else {
|
||||
@ -336,7 +336,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('container', {
|
||||
blockModel: Module.ContainerBlockModel,
|
||||
blockView: Module.ContainerBlockView
|
||||
|
@ -5,14 +5,13 @@ define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/blocks/base',
|
||||
'underscore',
|
||||
'jquery',
|
||||
'mailpoet'
|
||||
], function (App, BaseBlock, _, jQuery, MailPoet) {
|
||||
'jquery'
|
||||
], function (App, BaseBlock, _, jQuery) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
|
||||
Module.DividerBlockModel = base.BlockModel.extend({
|
||||
defaults: function () {
|
||||
@ -49,8 +48,8 @@ define([
|
||||
}, base.BlockView.prototype.behaviors),
|
||||
onDragSubstituteBy: function () { return Module.DividerWidgetView; },
|
||||
initialize: function () {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
var that = this;
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
// Listen for attempts to change all dividers in one go
|
||||
this._replaceDividerHandler = function (data) { that.model.set(data); that.model.trigger('applyToAll'); };
|
||||
@ -119,7 +118,7 @@ define([
|
||||
repaintDividerStyleOptions: function () {
|
||||
this.$('.mailpoet_field_divider_style > div').css('border-top-color', this.model.get('styles.block.borderColor'));
|
||||
},
|
||||
applyToAll: function (event) {
|
||||
applyToAll: function () {
|
||||
App.getChannel().trigger('replaceAllDividers', this.model.toJSON());
|
||||
},
|
||||
updateValueAndCall: function (fieldToUpdate, callable, event) {
|
||||
@ -139,7 +138,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('divider', {
|
||||
blockModel: Module.DividerBlockModel,
|
||||
blockView: Module.DividerBlockView
|
||||
|
@ -10,8 +10,8 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
|
||||
Module.FooterBlockModel = base.BlockModel.extend({
|
||||
defaults: function () {
|
||||
@ -110,7 +110,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('footer', {
|
||||
blockModel: Module.FooterBlockModel,
|
||||
blockView: Module.FooterBlockView
|
||||
|
@ -10,8 +10,8 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
|
||||
Module.HeaderBlockModel = base.BlockModel.extend({
|
||||
defaults: function () {
|
||||
@ -110,7 +110,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('header', {
|
||||
blockModel: Module.HeaderBlockModel,
|
||||
blockView: Module.HeaderBlockView
|
||||
|
@ -11,9 +11,9 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock,
|
||||
ImageWidgetView;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
var ImageWidgetView;
|
||||
|
||||
Module.ImageBlockModel = base.BlockModel.extend({
|
||||
defaults: function () {
|
||||
@ -48,8 +48,8 @@ define([
|
||||
elementSelector: '.mailpoet_image',
|
||||
resizeHandleSelector: '.mailpoet_image_resize_handle',
|
||||
onResize: function (event) {
|
||||
var corner = this.$('.mailpoet_image').offset(),
|
||||
width = event.pageX - corner.left;
|
||||
var corner = this.$('.mailpoet_image').offset();
|
||||
var width = event.pageX - corner.left;
|
||||
this.view.model.set('width', width + 'px');
|
||||
}
|
||||
},
|
||||
@ -127,13 +127,16 @@ define([
|
||||
}
|
||||
},
|
||||
showMediaManager: function () {
|
||||
var that = this;
|
||||
var MediaManager;
|
||||
var theFrame;
|
||||
if (this._mediaManager) {
|
||||
this._mediaManager.resetSelections();
|
||||
this._mediaManager.open();
|
||||
return;
|
||||
}
|
||||
|
||||
var MediaManager = window.wp.media.view.MediaFrame.Select.extend({
|
||||
MediaManager = window.wp.media.view.MediaFrame.Select.extend({
|
||||
|
||||
initialize: function () {
|
||||
window.wp.media.view.MediaFrame.prototype.initialize.apply(this, arguments);
|
||||
@ -196,6 +199,7 @@ define([
|
||||
},
|
||||
|
||||
bindHandlers: function () {
|
||||
var handlers;
|
||||
// from Select
|
||||
this.on('router:create:browse', this.createRouter, this);
|
||||
this.on('router:render:browse', this.browseRouter, this);
|
||||
@ -210,7 +214,7 @@ define([
|
||||
|
||||
this.on('updateExcluded', this.browseContent, this);
|
||||
|
||||
var handlers = {
|
||||
handlers = {
|
||||
content: {
|
||||
embed: 'embedContent',
|
||||
'edit-selection': 'editSelectionContent'
|
||||
@ -244,9 +248,9 @@ define([
|
||||
},
|
||||
|
||||
editSelectionContent: function () {
|
||||
var state = this.state(),
|
||||
selection = state.get('selection'),
|
||||
view;
|
||||
var state = this.state();
|
||||
var selection = state.get('selection');
|
||||
var view;
|
||||
|
||||
view = new window.wp.media.view.AttachmentsBrowser({
|
||||
controller: this,
|
||||
@ -302,8 +306,8 @@ define([
|
||||
requires: { selection: true },
|
||||
|
||||
click: function () {
|
||||
var state = controller.state(),
|
||||
selection = state.get('selection');
|
||||
var state = controller.state();
|
||||
var selection = state.get('selection');
|
||||
|
||||
controller.close();
|
||||
state.trigger('insert', selection).reset();
|
||||
@ -321,46 +325,42 @@ define([
|
||||
|
||||
});
|
||||
|
||||
var theFrame = new MediaManager({
|
||||
id: 'mailpoet-media-manager',
|
||||
frame: 'select',
|
||||
title: 'Select image',
|
||||
editing: false,
|
||||
multiple: false,
|
||||
library: {
|
||||
type: 'image'
|
||||
},
|
||||
displaySettings: false,
|
||||
button: {
|
||||
text: 'Select'
|
||||
}
|
||||
}),
|
||||
that = this;
|
||||
theFrame = new MediaManager({
|
||||
id: 'mailpoet-media-manager',
|
||||
frame: 'select',
|
||||
title: 'Select image',
|
||||
editing: false,
|
||||
multiple: false,
|
||||
library: {
|
||||
type: 'image'
|
||||
},
|
||||
displaySettings: false,
|
||||
button: {
|
||||
text: 'Select'
|
||||
}
|
||||
});
|
||||
this._mediaManager = theFrame;
|
||||
|
||||
this._mediaManager.on('insert', function () {
|
||||
// Append media manager image selections to Images tab
|
||||
var selection = theFrame.state().get('selection');
|
||||
selection.each(function (attachment) {
|
||||
var sizes = attachment.get('sizes'),
|
||||
// Following advice from Becs, the target width should
|
||||
// be a double of one column width to render well on
|
||||
// retina screen devices
|
||||
targetImageWidth = 1320,
|
||||
var sizes = attachment.get('sizes');
|
||||
// Following advice from Becs, the target width should
|
||||
// be a double of one column width to render well on
|
||||
// retina screen devices
|
||||
var targetImageWidth = 1320;
|
||||
|
||||
// For main image use the size, that's closest to being 660px in width
|
||||
sizeKeys = _.keys(sizes),
|
||||
// Pick the width that is closest to target width
|
||||
var increasingByWidthDifference = _.sortBy(
|
||||
_.keys(sizes),
|
||||
function (size) { return Math.abs(targetImageWidth - sizes[size].width); }
|
||||
);
|
||||
var bestWidth = sizes[_.first(increasingByWidthDifference)].width;
|
||||
var imagesOfBestWidth = _.filter(_.values(sizes), function (size) { return size.width === bestWidth; });
|
||||
|
||||
// Pick the width that is closest to target width
|
||||
increasingByWidthDifference = _.sortBy(
|
||||
_.keys(sizes),
|
||||
function (size) { return Math.abs(targetImageWidth - sizes[size].width); }
|
||||
),
|
||||
bestWidth = sizes[_.first(increasingByWidthDifference)].width,
|
||||
imagesOfBestWidth = _.filter(_.values(sizes), function (size) { return size.width === bestWidth; }),
|
||||
|
||||
// Maximize the height if there are multiple images with same width
|
||||
mainSize = _.max(imagesOfBestWidth, function (size) { return size.height; });
|
||||
// Maximize the height if there are multiple images with same width
|
||||
var mainSize = _.max(imagesOfBestWidth, function (size) { return size.height; });
|
||||
|
||||
that.model.set({
|
||||
height: mainSize.height + 'px',
|
||||
@ -413,7 +413,7 @@ define([
|
||||
});
|
||||
Module.ImageWidgetView = ImageWidgetView;
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('image', {
|
||||
blockModel: Module.ImageBlockModel,
|
||||
blockView: Module.ImageBlockView
|
||||
|
@ -39,8 +39,13 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
var PostsDisplayOptionsSettingsView;
|
||||
var SinglePostSelectionSettingsView;
|
||||
var EmptyPostSelectionSettingsView;
|
||||
var PostSelectionSettingsView;
|
||||
var PostsSelectionCollectionView;
|
||||
|
||||
Module.PostsBlockModel = base.BlockModel.extend({
|
||||
stale: ['_selectedPosts', '_availablePosts', '_transformedPosts'],
|
||||
@ -89,10 +94,9 @@ define([
|
||||
};
|
||||
},
|
||||
initialize: function () {
|
||||
var that = this,
|
||||
POST_REFRESH_DELAY_MS = 500,
|
||||
refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS),
|
||||
refreshTransformedPosts = _.debounce(this._refreshTransformedPosts.bind(this), POST_REFRESH_DELAY_MS);
|
||||
var POST_REFRESH_DELAY_MS = 500;
|
||||
var refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS);
|
||||
var refreshTransformedPosts = _.debounce(this._refreshTransformedPosts.bind(this), POST_REFRESH_DELAY_MS);
|
||||
|
||||
// Attach Radio.Requests API primarily for highlighting
|
||||
_.extend(this, Radio.Requests);
|
||||
@ -120,9 +124,9 @@ define([
|
||||
});
|
||||
},
|
||||
_loadMorePosts: function () {
|
||||
var that = this,
|
||||
postCount = this.get('_availablePosts').length,
|
||||
nextOffset = this.get('offset') + Number(this.get('amount'));
|
||||
var that = this;
|
||||
var postCount = this.get('_availablePosts').length;
|
||||
var nextOffset = this.get('offset') + Number(this.get('amount'));
|
||||
|
||||
if (postCount === 0 || postCount < nextOffset) {
|
||||
// No more posts to load
|
||||
@ -141,8 +145,8 @@ define([
|
||||
});
|
||||
},
|
||||
_refreshTransformedPosts: function () {
|
||||
var that = this,
|
||||
data = this.toJSON();
|
||||
var that = this;
|
||||
var data = this.toJSON();
|
||||
|
||||
data.posts = this.get('_selectedPosts').pluck('ID');
|
||||
|
||||
@ -158,10 +162,9 @@ define([
|
||||
});
|
||||
},
|
||||
_insertSelectedPosts: function () {
|
||||
var that = this,
|
||||
data = this.toJSON(),
|
||||
index = this.collection.indexOf(this),
|
||||
collection = this.collection;
|
||||
var data = this.toJSON();
|
||||
var index = this.collection.indexOf(this);
|
||||
var collection = this.collection;
|
||||
|
||||
data.posts = this.get('_selectedPosts').pluck('ID');
|
||||
|
||||
@ -190,17 +193,19 @@ define([
|
||||
this.model.reply('blockView', this.notifyAboutSelf, this);
|
||||
},
|
||||
onRender: function () {
|
||||
var ContainerView;
|
||||
var renderOptions;
|
||||
if (!this.getRegion('toolsRegion').hasView()) {
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
}
|
||||
this.trigger('showSettings');
|
||||
|
||||
var ContainerView = App.getBlockTypeView('container'),
|
||||
renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay')
|
||||
};
|
||||
ContainerView = App.getBlockTypeView('container');
|
||||
renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay')
|
||||
};
|
||||
this.showChildView('postsRegion', new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions }));
|
||||
},
|
||||
notifyAboutSelf: function () {
|
||||
@ -237,8 +242,8 @@ define([
|
||||
this.displayOptionsView = new PostsDisplayOptionsSettingsView({ model: this.model });
|
||||
},
|
||||
onRender: function () {
|
||||
var that = this,
|
||||
blockView = this.model.request('blockView');
|
||||
var that = this;
|
||||
this.model.request('blockView');
|
||||
|
||||
this.showChildView('selectionRegion', this.selectionView);
|
||||
this.showChildView('displayOptionsRegion', this.displayOptionsView);
|
||||
@ -283,7 +288,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
var PostsSelectionCollectionView = Marionette.CollectionView.extend({
|
||||
PostsSelectionCollectionView = Marionette.CollectionView.extend({
|
||||
className: 'mailpoet_post_scroll_container',
|
||||
childView: function () { return SinglePostSelectionSettingsView; },
|
||||
emptyView: function () { return EmptyPostSelectionSettingsView; },
|
||||
@ -307,7 +312,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
var PostSelectionSettingsView = Marionette.View.extend({
|
||||
PostSelectionSettingsView = Marionette.View.extend({
|
||||
getTemplate: function () { return window.templates.postSelectionPostsBlockSettings; },
|
||||
regions: {
|
||||
posts: '.mailpoet_post_selection_container'
|
||||
@ -334,9 +339,10 @@ define([
|
||||
}
|
||||
},
|
||||
onRender: function () {
|
||||
var postsView;
|
||||
// Dynamically update available post types
|
||||
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
var postsView = new PostsSelectionCollectionView({
|
||||
postsView = new PostsSelectionCollectionView({
|
||||
collection: this.model.get('_availablePosts'),
|
||||
blockModel: this.model
|
||||
});
|
||||
@ -358,12 +364,13 @@ define([
|
||||
},
|
||||
transport: function (options, success, failure) {
|
||||
var taxonomies;
|
||||
var termsPromise;
|
||||
var promise = CommunicationComponent.getTaxonomies(
|
||||
that.model.get('contentType')
|
||||
).then(function (tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = CommunicationComponent.getTerms({
|
||||
termsPromise = CommunicationComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function (terms) {
|
||||
@ -372,7 +379,7 @@ define([
|
||||
terms: terms
|
||||
};
|
||||
});
|
||||
return promise;
|
||||
return termsPromise;
|
||||
});
|
||||
|
||||
promise.then(success);
|
||||
@ -413,8 +420,8 @@ define([
|
||||
this.model.set(field, jQuery(event.target).val());
|
||||
},
|
||||
_updateContentTypes: function (postTypes) {
|
||||
var select = this.$('.mailpoet_settings_posts_content_type'),
|
||||
selectedValue = this.model.get('contentType');
|
||||
var select = this.$('.mailpoet_settings_posts_content_type');
|
||||
var selectedValue = this.model.get('contentType');
|
||||
|
||||
select.find('option').remove();
|
||||
_.each(postTypes, function (type) {
|
||||
@ -427,11 +434,11 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
var EmptyPostSelectionSettingsView = Marionette.View.extend({
|
||||
EmptyPostSelectionSettingsView = Marionette.View.extend({
|
||||
getTemplate: function () { return window.templates.emptyPostPostsBlockSettings; }
|
||||
});
|
||||
|
||||
var SinglePostSelectionSettingsView = Marionette.View.extend({
|
||||
SinglePostSelectionSettingsView = Marionette.View.extend({
|
||||
getTemplate: function () { return window.templates.singlePostPostsBlockSettings; },
|
||||
events: function () {
|
||||
return {
|
||||
@ -448,8 +455,8 @@ define([
|
||||
this.blockModel = options.blockModel;
|
||||
},
|
||||
postSelectionChange: function (event) {
|
||||
var checkBox = jQuery(event.target),
|
||||
selectedPostsCollection = this.blockModel.get('_selectedPosts');
|
||||
var checkBox = jQuery(event.target);
|
||||
var selectedPostsCollection = this.blockModel.get('_selectedPosts');
|
||||
if (checkBox.prop('checked')) {
|
||||
selectedPostsCollection.add(this.model);
|
||||
} else {
|
||||
@ -458,7 +465,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
var PostsDisplayOptionsSettingsView = base.BlockSettingsView.extend({
|
||||
PostsDisplayOptionsSettingsView = base.BlockSettingsView.extend({
|
||||
getTemplate: function () { return window.templates.displayOptionsPostsBlockSettings; },
|
||||
events: function () {
|
||||
return {
|
||||
@ -488,7 +495,7 @@ define([
|
||||
model: this.model.toJSON()
|
||||
};
|
||||
},
|
||||
showButtonSettings: function (event) {
|
||||
showButtonSettings: function () {
|
||||
var buttonModule = ButtonBlock;
|
||||
(new buttonModule.ButtonBlockSettingsView({
|
||||
model: this.model.get('readMoreButton'),
|
||||
@ -499,7 +506,7 @@ define([
|
||||
}
|
||||
})).render();
|
||||
},
|
||||
showDividerSettings: function (event) {
|
||||
showDividerSettings: function () {
|
||||
var dividerModule = DividerBlock;
|
||||
(new dividerModule.DividerBlockSettingsView({
|
||||
model: this.model.get('divider'),
|
||||
@ -575,7 +582,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('posts', {
|
||||
blockModel: Module.PostsBlockModel,
|
||||
blockView: Module.PostsBlockView
|
||||
|
@ -13,12 +13,13 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock,
|
||||
SocialBlockSettingsIconSelectorView,
|
||||
SocialBlockSettingsIconView,
|
||||
SocialBlockSettingsIconCollectionView,
|
||||
SocialBlockSettingsStylesView;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
var SocialBlockSettingsIconSelectorView;
|
||||
var SocialBlockSettingsIconView;
|
||||
var SocialBlockSettingsIconCollectionView;
|
||||
var SocialBlockSettingsStylesView;
|
||||
var SocialIconView;
|
||||
|
||||
Module.SocialIconModel = SuperModel.extend({
|
||||
defaults: function () {
|
||||
@ -33,12 +34,12 @@ define([
|
||||
text: defaultValues.get('title')
|
||||
};
|
||||
},
|
||||
initialize: function (options) {
|
||||
initialize: function () {
|
||||
var that = this;
|
||||
// Make model swap to default values for that type when iconType changes
|
||||
this.on('change:iconType', function () {
|
||||
var defaultValues = App.getConfig().get('socialIcons').get(that.get('iconType')),
|
||||
iconSet = that.collection.iconBlockModel.getIconSet();
|
||||
var defaultValues = App.getConfig().get('socialIcons').get(that.get('iconType'));
|
||||
var iconSet = that.collection.iconBlockModel.getIconSet();
|
||||
this.set({
|
||||
link: defaultValues.get('defaultLink'),
|
||||
image: iconSet.get(that.get('iconType')),
|
||||
@ -83,7 +84,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
var SocialIconView = Marionette.View.extend({
|
||||
SocialIconView = Marionette.View.extend({
|
||||
tagName: 'span',
|
||||
getTemplate: function () { return window.templates.socialIconBlock; },
|
||||
modelEvents: {
|
||||
@ -175,10 +176,10 @@ define([
|
||||
}
|
||||
},
|
||||
templateContext: function () {
|
||||
var icons = App.getConfig().get('socialIcons'),
|
||||
// Construct icon type list of format [{iconType: 'type', title: 'Title'}, ...]
|
||||
availableIconTypes = _.map(_.keys(icons.attributes), function (key) { return { iconType: key, title: icons.get(key).get('title') }; }),
|
||||
allIconSets = App.getAvailableStyles().get('socialIconSets');
|
||||
var icons = App.getConfig().get('socialIcons');
|
||||
// Construct icon type list of format [{iconType: 'type', title: 'Title'}, ...]
|
||||
var availableIconTypes = _.map(_.keys(icons.attributes), function (key) { return { iconType: key, title: icons.get(key).get('title') }; });
|
||||
var allIconSets = App.getAvailableStyles().get('socialIconSets');
|
||||
return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), {
|
||||
iconTypes: availableIconTypes,
|
||||
currentType: icons.get(this.model.get('iconType')).toJSON(),
|
||||
@ -297,7 +298,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('social', {
|
||||
blockModel: Module.SocialBlockModel,
|
||||
blockView: Module.SocialBlockView
|
||||
|
@ -9,8 +9,8 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
|
||||
Module.SpacerBlockModel = base.BlockModel.extend({
|
||||
defaults: function () {
|
||||
@ -87,7 +87,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('spacer', {
|
||||
blockModel: Module.SpacerBlockModel,
|
||||
blockView: Module.SpacerBlockView
|
||||
|
@ -10,8 +10,8 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
base = BaseBlock;
|
||||
var Module = {};
|
||||
var base = BaseBlock;
|
||||
|
||||
Module.TextBlockModel = base.BlockModel.extend({
|
||||
defaults: function () {
|
||||
@ -94,7 +94,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
App.registerBlockType('text', {
|
||||
blockModel: Module.TextBlockModel,
|
||||
blockView: Module.TextBlockView
|
||||
|
@ -7,15 +7,15 @@
|
||||
*/
|
||||
|
||||
(function (root, factory) {
|
||||
var Marionette = require('backbone.marionette');
|
||||
var Radio = require('backbone.radio');
|
||||
var _ = require('underscore');
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['backbone.marionette', 'backbone.radio', 'underscore'], function (Marionette, Radio, _) {
|
||||
return factory(Marionette, Radio, _);
|
||||
});
|
||||
}
|
||||
else if (typeof exports !== 'undefined') {
|
||||
var Marionette = require('backbone.marionette');
|
||||
var Radio = require('backbone.radio');
|
||||
var _ = require('underscore');
|
||||
module.exports = factory(Marionette, Radio, _);
|
||||
}
|
||||
else {
|
||||
|
@ -98,7 +98,7 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
App.on('start', function (App, options) {
|
||||
App.on('start', function () {
|
||||
// Prefetch post types
|
||||
Module.getPostTypes();
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ define([
|
||||
// handled by other components.
|
||||
Module.NewsletterModel = SuperModel.extend({
|
||||
whitelisted: ['id', 'subject', 'preheader'],
|
||||
initialize: function (options) {
|
||||
initialize: function () {
|
||||
this.on('change', function () {
|
||||
App.getChannel().trigger('autoSave');
|
||||
});
|
||||
|
@ -29,7 +29,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('start', function (App, options) {
|
||||
App.on('start', function (App) {
|
||||
App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() }));
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-subject-line'), {
|
||||
tooltipId: 'tooltip-designer-subject-line-ti',
|
||||
|
@ -28,8 +28,8 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {},
|
||||
saveTimeout;
|
||||
var Module = {};
|
||||
var saveTimeout;
|
||||
|
||||
// Save editor contents to server
|
||||
Module.save = function () {
|
||||
@ -76,10 +76,9 @@ define([
|
||||
// Temporary workaround for html2canvas-alpha2.
|
||||
// Removes 1px left transparent border from resulting canvas.
|
||||
|
||||
var oldContext = oldCanvas.getContext('2d'),
|
||||
newCanvas = document.createElement('canvas'),
|
||||
newContext = newCanvas.getContext('2d'),
|
||||
leftBorderWidth = 1;
|
||||
var newCanvas = document.createElement('canvas');
|
||||
var newContext = newCanvas.getContext('2d');
|
||||
var leftBorderWidth = 1;
|
||||
|
||||
newCanvas.width = oldCanvas.width;
|
||||
newCanvas.height = oldCanvas.height;
|
||||
@ -95,8 +94,7 @@ define([
|
||||
};
|
||||
|
||||
Module.saveTemplate = function (options) {
|
||||
var that = this,
|
||||
promise = jQuery.Deferred();
|
||||
var promise = jQuery.Deferred();
|
||||
|
||||
promise.then(function (thumbnail) {
|
||||
var data = _.extend(options || {}, {
|
||||
@ -122,7 +120,6 @@ define([
|
||||
};
|
||||
|
||||
Module.exportTemplate = function (options) {
|
||||
var that = this;
|
||||
return Module.getThumbnail(
|
||||
jQuery('#mailpoet_editor_content > .mailpoet_block').get(0)
|
||||
).then(function (thumbnail) {
|
||||
@ -155,7 +152,7 @@ define([
|
||||
'click .mailpoet_save_export': 'toggleExportTemplate',
|
||||
'click .mailpoet_export_template': 'exportTemplate'
|
||||
},
|
||||
initialize: function (options) {
|
||||
initialize: function () {
|
||||
App.getChannel().on('beforeEditorSave', this.beforeSave, this);
|
||||
App.getChannel().on('afterEditorSave', this.afterSave, this);
|
||||
},
|
||||
@ -170,7 +167,7 @@ define([
|
||||
// TODO: Add a loading animation instead
|
||||
this.$('.mailpoet_autosaved_at').text(MailPoet.I18n.t('saving'));
|
||||
},
|
||||
afterSave: function (json, response) {
|
||||
afterSave: function (json) {
|
||||
this.validateNewsletter(json);
|
||||
// Update 'Last saved timer'
|
||||
this.$('.mailpoet_editor_last_saved').removeClass('mailpoet_hidden');
|
||||
@ -192,9 +189,9 @@ define([
|
||||
this.$('.mailpoet_save_as_template_container').addClass('mailpoet_hidden');
|
||||
},
|
||||
saveAsTemplate: function () {
|
||||
var templateName = this.$('.mailpoet_save_as_template_name').val(),
|
||||
templateDescription = this.$('.mailpoet_save_as_template_description').val(),
|
||||
that = this;
|
||||
var templateName = this.$('.mailpoet_save_as_template_name').val();
|
||||
var templateDescription = this.$('.mailpoet_save_as_template_description').val();
|
||||
var that = this;
|
||||
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(
|
||||
@ -248,9 +245,9 @@ define([
|
||||
this.$('.mailpoet_export_template_container').addClass('mailpoet_hidden');
|
||||
},
|
||||
exportTemplate: function () {
|
||||
var templateName = this.$('.mailpoet_export_template_name').val(),
|
||||
templateDescription = this.$('.mailpoet_export_template_description').val(),
|
||||
that = this;
|
||||
var templateName = this.$('.mailpoet_export_template_name').val();
|
||||
var templateDescription = this.$('.mailpoet_export_template_description').val();
|
||||
var that = this;
|
||||
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(
|
||||
@ -285,18 +282,19 @@ define([
|
||||
this.hideOptionContents();
|
||||
if (!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
|
||||
Module._cancelAutosave();
|
||||
Module.save().done(function (response) {
|
||||
Module.save().done(function () {
|
||||
window.location.href = App.getConfig().get('urls.send');
|
||||
});
|
||||
}
|
||||
},
|
||||
validateNewsletter: function (jsonObject) {
|
||||
var contents;
|
||||
if (!App._contentContainer.isValid()) {
|
||||
this.showValidationError(App._contentContainer.validationError);
|
||||
return;
|
||||
}
|
||||
|
||||
var contents = JSON.stringify(jsonObject);
|
||||
contents = JSON.stringify(jsonObject);
|
||||
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
|
||||
contents.indexOf('[link:subscription_unsubscribe_url]') < 0 &&
|
||||
contents.indexOf('[link:subscription_unsubscribe]') < 0) {
|
||||
@ -340,9 +338,11 @@ define([
|
||||
};
|
||||
|
||||
Module.beforeExitWithUnsavedChanges = function (e) {
|
||||
var message;
|
||||
var event;
|
||||
if (saveTimeout) {
|
||||
var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
|
||||
var event = e || window.event;
|
||||
message = MailPoet.I18n.t('unsavedChangesWillBeLost');
|
||||
event = e || window.event;
|
||||
|
||||
if (event) {
|
||||
event.returnValue = message;
|
||||
@ -352,7 +352,7 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
var Application = App;
|
||||
Application.save = Module.save;
|
||||
Application.getChannel().on('autoSave', Module.autoSave);
|
||||
@ -362,7 +362,7 @@ define([
|
||||
Application.getChannel().reply('save', Application.save);
|
||||
});
|
||||
|
||||
App.on('start', function (App, options) {
|
||||
App.on('start', function (App) {
|
||||
var saveView = new Module.SaveView();
|
||||
App._appView.showChildView('bottomRegion', saveView);
|
||||
});
|
||||
|
@ -6,8 +6,7 @@ define([
|
||||
'backbone.marionette',
|
||||
'backbone.supermodel',
|
||||
'underscore',
|
||||
'jquery',
|
||||
'sticky-kit'
|
||||
'jquery'
|
||||
], function (
|
||||
App,
|
||||
CommunicationComponent,
|
||||
@ -16,14 +15,13 @@ define([
|
||||
Marionette,
|
||||
SuperModel,
|
||||
_,
|
||||
jQuery,
|
||||
StickyKit
|
||||
jQuery
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {};
|
||||
|
||||
var SidebarView;
|
||||
// Widget handlers for use to create new content blocks via drag&drop
|
||||
Module._contentWidgets = new (Backbone.Collection.extend({
|
||||
model: SuperModel.extend({
|
||||
@ -52,7 +50,7 @@ define([
|
||||
Module.registerLayoutWidget = function (widget) { return Module._layoutWidgets.add(widget); };
|
||||
Module.getLayoutWidgets = function () { return Module._layoutWidgets; };
|
||||
|
||||
var SidebarView = Marionette.View.extend({
|
||||
SidebarView = Marionette.View.extend({
|
||||
getTemplate: function () { return window.templates.sidebar; },
|
||||
regions: {
|
||||
contentRegion: '.mailpoet_content_region',
|
||||
@ -62,8 +60,8 @@ define([
|
||||
},
|
||||
events: {
|
||||
'click .mailpoet_sidebar_region h3, .mailpoet_sidebar_region .handlediv': function (event) {
|
||||
var $openRegion = this.$el.find('.mailpoet_sidebar_region:not(.closed)'),
|
||||
$targetRegion = this.$el.find(event.target).closest('.mailpoet_sidebar_region');
|
||||
var $openRegion = this.$el.find('.mailpoet_sidebar_region:not(.closed)');
|
||||
var $targetRegion = this.$el.find(event.target).closest('.mailpoet_sidebar_region');
|
||||
|
||||
$openRegion.find('.mailpoet_region_content').velocity(
|
||||
'slideUp',
|
||||
@ -90,7 +88,7 @@ define([
|
||||
}
|
||||
}
|
||||
},
|
||||
initialize: function (options) {
|
||||
initialize: function () {
|
||||
jQuery(window)
|
||||
.on('resize', this.updateHorizontalScroll.bind(this))
|
||||
.on('scroll', this.updateHorizontalScroll.bind(this));
|
||||
@ -113,9 +111,8 @@ define([
|
||||
// position of the sidebar would be scrollable and not fixed
|
||||
// partially out of visible screen
|
||||
this.$el.parent().each(function () {
|
||||
var calculated_left, self;
|
||||
|
||||
self = jQuery(this);
|
||||
var calculated_left;
|
||||
var self = jQuery(this);
|
||||
|
||||
if (self.css('position') === 'fixed') {
|
||||
calculated_left = self.parent().offset().left - jQuery(window).scrollLeft();
|
||||
@ -271,7 +268,7 @@ define([
|
||||
previewUrl: response.meta.preview_url
|
||||
});
|
||||
|
||||
var view = this.previewView.render();
|
||||
this.previewView.render();
|
||||
this.previewView.$el.css('height', '100%');
|
||||
|
||||
MailPoet.Modal.popup({
|
||||
@ -324,7 +321,7 @@ define([
|
||||
App.getChannel().request('save').always(function () {
|
||||
CommunicationComponent.previewNewsletter(data).always(function () {
|
||||
MailPoet.Modal.loading(false);
|
||||
}).done(function (response) {
|
||||
}).done(function () {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('newsletterPreviewSent'),
|
||||
{ scroll: true }
|
||||
@ -363,7 +360,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
App.on('before:start', function (App) {
|
||||
var Application = App;
|
||||
Application.registerWidget = Module.registerWidget;
|
||||
Application.getWidgets = Module.getWidgets;
|
||||
@ -371,9 +368,8 @@ define([
|
||||
Application.getLayoutWidgets = Module.getLayoutWidgets;
|
||||
});
|
||||
|
||||
App.on('start', function (App, options) {
|
||||
var stylesModel = App.getGlobalStyles(),
|
||||
sidebarView = new SidebarView();
|
||||
App.on('start', function (App) {
|
||||
var sidebarView = new SidebarView();
|
||||
|
||||
App._appView.showChildView('sidebarRegion', sidebarView);
|
||||
|
||||
|
@ -71,17 +71,19 @@ define([
|
||||
|
||||
App.on('before:start', function (App, options) {
|
||||
var Application = App;
|
||||
var body;
|
||||
var globalStyles;
|
||||
// Expose style methods to global application
|
||||
Application.getGlobalStyles = Module.getGlobalStyles;
|
||||
Application.setGlobalStyles = Module.setGlobalStyles;
|
||||
Application.getAvailableStyles = Module.getAvailableStyles;
|
||||
|
||||
var body = options.newsletter.body;
|
||||
var globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};
|
||||
body = options.newsletter.body;
|
||||
globalStyles = (_.has(body, 'globalStyles')) ? body.globalStyles : {};
|
||||
this.setGlobalStyles(globalStyles);
|
||||
});
|
||||
|
||||
App.on('start', function (App, options) {
|
||||
App.on('start', function (App) {
|
||||
var stylesView = new Module.StylesView({ model: App.getGlobalStyles() });
|
||||
App._appView.showChildView('stylesRegion', stylesView);
|
||||
});
|
||||
|
@ -10,31 +10,33 @@
|
||||
|
||||
/* jshint unused:false */
|
||||
/* global tinymce:true */
|
||||
tinymce.PluginManager.add('mailpoet_shortcodes', function (editor, url) {
|
||||
tinymce.PluginManager.add('mailpoet_shortcodes', function (editor) {
|
||||
var appendLabelAndClose = function (shortcode) {
|
||||
editor.insertContent(shortcode);
|
||||
editor.windowManager.close();
|
||||
},
|
||||
generateOnClickFunc = function (shortcode) {
|
||||
return function () {
|
||||
appendLabelAndClose(shortcode);
|
||||
};
|
||||
editor.insertContent(shortcode);
|
||||
editor.windowManager.close();
|
||||
};
|
||||
var generateOnClickFunc = function (shortcode) {
|
||||
return function () {
|
||||
appendLabelAndClose(shortcode);
|
||||
};
|
||||
};
|
||||
|
||||
editor.addButton('mailpoet_shortcodes', {
|
||||
icon: 'mailpoet_shortcodes',
|
||||
onclick: function () {
|
||||
var shortcodes = [],
|
||||
configShortcodes = editor.settings.mailpoet_shortcodes;
|
||||
var shortcodes = [];
|
||||
var configShortcodes = editor.settings.mailpoet_shortcodes;
|
||||
var segment;
|
||||
var i;
|
||||
|
||||
for (var segment in configShortcodes) {
|
||||
for (segment in configShortcodes) {
|
||||
if (configShortcodes.hasOwnProperty(segment)) {
|
||||
shortcodes.push({
|
||||
type: 'label',
|
||||
text: segment
|
||||
});
|
||||
|
||||
for (var i = 0; i < configShortcodes[segment].length; i += 1) {
|
||||
for (i = 0; i < configShortcodes[segment].length; i += 1) {
|
||||
shortcodes.push({
|
||||
type: 'button',
|
||||
text: configShortcodes[segment][i].text,
|
||||
|
@ -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
|
||||
@ -179,11 +187,11 @@ const _StatisticsMixin = {
|
||||
const percentage_opened_display = MailPoet.Num.toLocaleFixed(percentage_opened, 1);
|
||||
const percentage_unsubscribed_display = MailPoet.Num.toLocaleFixed(percentage_unsubscribed, 1);
|
||||
|
||||
let show_stats_timeout,
|
||||
newsletter_date,
|
||||
sent_hours_ago,
|
||||
too_early_for_stats,
|
||||
show_kb_link;
|
||||
let show_stats_timeout;
|
||||
let newsletter_date;
|
||||
let sent_hours_ago;
|
||||
let too_early_for_stats;
|
||||
let show_kb_link;
|
||||
if (current_time !== undefined) {
|
||||
// standard emails and post notifications:
|
||||
// display green box for newsletters that were just sent
|
||||
@ -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 = {
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -47,6 +47,8 @@ define('notice', ['mailpoet', 'jquery'], function (mp, jQuery) {
|
||||
return this;
|
||||
},
|
||||
createNotice: function () {
|
||||
var onClose;
|
||||
var positionAfter;
|
||||
// clone element
|
||||
this.element = jQuery('#mailpoet_notice_' + this.options.type).clone();
|
||||
|
||||
@ -62,7 +64,6 @@ define('notice', ['mailpoet', 'jquery'], function (mp, jQuery) {
|
||||
this.element.removeAttr('id');
|
||||
|
||||
// insert notice after its parent
|
||||
var positionAfter;
|
||||
if (typeof this.options.positionAfter === 'object') {
|
||||
positionAfter = this.options.positionAfter;
|
||||
} else if (typeof this.options.positionAfter === 'string') {
|
||||
@ -73,7 +74,7 @@ define('notice', ['mailpoet', 'jquery'], function (mp, jQuery) {
|
||||
positionAfter.after(this.element);
|
||||
|
||||
// setup onClose callback
|
||||
var onClose = null;
|
||||
onClose = null;
|
||||
if (this.options.onClose !== null) {
|
||||
onClose = this.options.onClose;
|
||||
}
|
||||
@ -177,12 +178,13 @@ define('notice', ['mailpoet', 'jquery'], function (mp, jQuery) {
|
||||
}
|
||||
},
|
||||
hide: function (all) {
|
||||
var id;
|
||||
if (all !== undefined && all === true) {
|
||||
// all notices
|
||||
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
||||
} else if (all !== undefined && jQuery.isArray(all)) {
|
||||
// array of ids
|
||||
for (var id in all) {
|
||||
for (id in all) {
|
||||
jQuery('[data-id="' + all[id] + '"]').trigger('close');
|
||||
}
|
||||
} if (all !== undefined) {
|
||||
|
@ -5,8 +5,7 @@ define([
|
||||
],
|
||||
function (
|
||||
MailPoet,
|
||||
jQuery,
|
||||
Parsley
|
||||
jQuery
|
||||
) {
|
||||
jQuery(function ($) {
|
||||
function isSameDomain(url) {
|
||||
@ -20,7 +19,7 @@ function (
|
||||
$('form.mailpoet_form').each(function () {
|
||||
var form = $(this);
|
||||
|
||||
form.parsley().on('form:validated', function (parsley) {
|
||||
form.parsley().on('form:validated', function () {
|
||||
// clear messages
|
||||
form.find('.mailpoet_message > p').hide();
|
||||
|
||||
@ -84,4 +83,4 @@ function (
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -5,7 +5,7 @@ define(
|
||||
function (
|
||||
MailPoet
|
||||
) {
|
||||
|
||||
var element;
|
||||
function eventHandler() {
|
||||
if (confirm(MailPoet.I18n.t('reinstallConfirmation'))) {
|
||||
MailPoet.trackEvent(
|
||||
@ -36,8 +36,8 @@ define(
|
||||
return false;
|
||||
}
|
||||
|
||||
var element = document.getElementById('mailpoet_reinstall');
|
||||
element = document.getElementById('mailpoet_reinstall');
|
||||
if (element) {
|
||||
element.addEventListener('click', eventHandler, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -51,7 +51,7 @@ define(
|
||||
jQuery('#mailpoet_sending_method_setup').fadeIn();
|
||||
}
|
||||
},
|
||||
tabs: function (tabStr, section) {
|
||||
tabs: function (tabStr) {
|
||||
// set default tab
|
||||
var tab = tabStr || 'mta';
|
||||
|
||||
@ -86,4 +86,4 @@ define(
|
||||
if (!Backbone.History.started) Backbone.history.start();
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -3,98 +3,104 @@ define(
|
||||
'underscore',
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'handlebars',
|
||||
'select2'
|
||||
'handlebars'
|
||||
],
|
||||
function (
|
||||
_,
|
||||
jQuery,
|
||||
MailPoet,
|
||||
Handlebars,
|
||||
select2
|
||||
Handlebars
|
||||
) {
|
||||
if (!jQuery('#mailpoet_subscribers_export').length) {
|
||||
return;
|
||||
}
|
||||
jQuery(document).ready(function () {
|
||||
var segmentsContainerElement;
|
||||
var subscriberFieldsContainerElement;
|
||||
var exportConfirmedOptionElement;
|
||||
var groupBySegmentOptionElement;
|
||||
var nextStepButton;
|
||||
var renderSegmentsAndFields;
|
||||
var subscribers_export_template;
|
||||
if (!window.exportData.segments) {
|
||||
return;
|
||||
}
|
||||
var subscribers_export_template =
|
||||
subscribers_export_template =
|
||||
Handlebars.compile(jQuery('#mailpoet_subscribers_export_template').html());
|
||||
|
||||
// render template
|
||||
jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(window.exportData));
|
||||
|
||||
// define reusable variables
|
||||
var segmentsContainerElement = jQuery('#export_lists'),
|
||||
subscriberFieldsContainerElement = jQuery('#export_columns'),
|
||||
exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]'),
|
||||
groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]'),
|
||||
nextStepButton = jQuery('a.mailpoet_export_process'),
|
||||
renderSegmentsAndFields = function (container, data) {
|
||||
if (container.data('select2')) {
|
||||
container
|
||||
.html('')
|
||||
.select2('destroy');
|
||||
}
|
||||
segmentsContainerElement = jQuery('#export_lists');
|
||||
subscriberFieldsContainerElement = jQuery('#export_columns');
|
||||
exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]');
|
||||
groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]');
|
||||
nextStepButton = jQuery('a.mailpoet_export_process');
|
||||
renderSegmentsAndFields = function (container, data) {
|
||||
if (container.data('select2')) {
|
||||
container
|
||||
.select2({
|
||||
data: data,
|
||||
width: '20em',
|
||||
templateResult: function (item) {
|
||||
return (item.subscriberCount > 0)
|
||||
? item.name + ' (' + parseInt(item.subscriberCount).toLocaleString() + ')'
|
||||
: item.name;
|
||||
},
|
||||
templateSelection: function (item) {
|
||||
return (item.subscriberCount > 0)
|
||||
? item.name + ' (' + parseInt(item.subscriberCount).toLocaleString() + ')'
|
||||
: item.name;
|
||||
}
|
||||
})
|
||||
.on('select2:selecting', function (selectEvent) {
|
||||
var selectElement = this,
|
||||
selectedOptionId = selectEvent.params.args.data.id,
|
||||
fieldsToExclude = [
|
||||
'select',
|
||||
'deselect'
|
||||
];
|
||||
if (_.contains(fieldsToExclude, selectedOptionId)) {
|
||||
selectEvent.preventDefault();
|
||||
if (selectedOptionId === 'deselect') {
|
||||
jQuery(selectElement).val('').trigger('change');
|
||||
} else {
|
||||
var allOptions = [];
|
||||
_.each(container.find('option'), function (field) {
|
||||
if (!_.contains(fieldsToExclude, field.value)) {
|
||||
allOptions.push(field.value);
|
||||
}
|
||||
});
|
||||
jQuery(selectElement).val(allOptions).trigger('change');
|
||||
}
|
||||
jQuery(selectElement).select2('close');
|
||||
}
|
||||
})
|
||||
.on('change', function () {
|
||||
if ((window.exportData.segments && segmentsContainerElement.select2('data').length && subscriberFieldsContainerElement.select2('data').length)
|
||||
||
|
||||
(!window.exportData.segments && subscriberFieldsContainerElement.select2('data').length)
|
||||
) {
|
||||
toggleNextStepButton('on');
|
||||
}
|
||||
else {
|
||||
toggleNextStepButton('off');
|
||||
.html('')
|
||||
.select2('destroy');
|
||||
}
|
||||
container
|
||||
.select2({
|
||||
data: data,
|
||||
width: '20em',
|
||||
templateResult: function (item) {
|
||||
return (item.subscriberCount > 0)
|
||||
? item.name + ' (' + parseInt(item.subscriberCount).toLocaleString() + ')'
|
||||
: item.name;
|
||||
},
|
||||
templateSelection: function (item) {
|
||||
return (item.subscriberCount > 0)
|
||||
? item.name + ' (' + parseInt(item.subscriberCount).toLocaleString() + ')'
|
||||
: item.name;
|
||||
}
|
||||
})
|
||||
.on('select2:selecting', function (selectEvent) {
|
||||
var selectElement = this;
|
||||
var selectedOptionId = selectEvent.params.args.data.id;
|
||||
var fieldsToExclude = [
|
||||
'select',
|
||||
'deselect'
|
||||
];
|
||||
var allOptions;
|
||||
if (_.contains(fieldsToExclude, selectedOptionId)) {
|
||||
selectEvent.preventDefault();
|
||||
if (selectedOptionId === 'deselect') {
|
||||
jQuery(selectElement).val('').trigger('change');
|
||||
} else {
|
||||
allOptions = [];
|
||||
_.each(container.find('option'), function (field) {
|
||||
if (!_.contains(fieldsToExclude, field.value)) {
|
||||
allOptions.push(field.value);
|
||||
}
|
||||
});
|
||||
jQuery(selectElement).val(allOptions).trigger('change');
|
||||
}
|
||||
jQuery(selectElement).select2('close');
|
||||
}
|
||||
})
|
||||
.on('change', function () {
|
||||
if ((window.exportData.segments && segmentsContainerElement.select2('data').length && subscriberFieldsContainerElement.select2('data').length)
|
||||
||
|
||||
(!window.exportData.segments && subscriberFieldsContainerElement.select2('data').length)
|
||||
) {
|
||||
toggleNextStepButton('on');
|
||||
}
|
||||
else {
|
||||
toggleNextStepButton('off');
|
||||
}
|
||||
|
||||
if (segmentsContainerElement.select2('data').length > 1 && window.exportData.groupBySegmentOption) {
|
||||
jQuery('.mailpoet_group_by_list').show();
|
||||
}
|
||||
else if (window.exportData.groupBySegmentOption) {
|
||||
jQuery('.mailpoet_group_by_list').hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
if (segmentsContainerElement.select2('data').length > 1 && window.exportData.groupBySegmentOption) {
|
||||
jQuery('.mailpoet_group_by_list').show();
|
||||
}
|
||||
else if (window.exportData.groupBySegmentOption) {
|
||||
jQuery('.mailpoet_group_by_list').hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// set confirmed subscribers export option to false
|
||||
window.exportData.exportConfirmedOption = false;
|
||||
@ -133,11 +139,12 @@ define(
|
||||
}
|
||||
|
||||
nextStepButton.click(function () {
|
||||
var exportFormat;
|
||||
if (jQuery(this).hasClass('button-disabled')) {
|
||||
return;
|
||||
}
|
||||
MailPoet.Modal.loading(true);
|
||||
var exportFormat = jQuery(':radio[name="option_format"]:checked').val();
|
||||
exportFormat = jQuery(':radio[name="option_format"]:checked').val();
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'ImportExport',
|
||||
@ -149,7 +156,7 @@ define(
|
||||
segments: (window.exportData.segments) ? segmentsContainerElement.val() : false,
|
||||
subscriber_fields: subscriberFieldsContainerElement.val()
|
||||
})
|
||||
}).always(function (response) {
|
||||
}).always(function () {
|
||||
MailPoet.Modal.loading(false);
|
||||
}).done(function (response) {
|
||||
var resultMessage = MailPoet.I18n.t('exportMessage')
|
||||
|
@ -7,8 +7,7 @@ define(
|
||||
'handlebars',
|
||||
'papaparse',
|
||||
'asyncqueue',
|
||||
'moment',
|
||||
'select2'
|
||||
'moment'
|
||||
],
|
||||
function (
|
||||
Backbone,
|
||||
@ -18,16 +17,16 @@ define(
|
||||
Handlebars,
|
||||
Papa,
|
||||
AsyncQueue,
|
||||
Moment,
|
||||
select2
|
||||
Moment
|
||||
) {
|
||||
if (!jQuery('#mailpoet_subscribers_import').length) {
|
||||
return;
|
||||
}
|
||||
jQuery(document).ready(function () {
|
||||
var router;
|
||||
jQuery('input[name="select_method"]').attr('checked', false);
|
||||
// configure router
|
||||
var router = new (Backbone.Router.extend({
|
||||
router = new (Backbone.Router.extend({
|
||||
routes: {
|
||||
'': 'home',
|
||||
step1: 'step1',
|
||||
@ -50,8 +49,20 @@ define(
|
||||
* STEP 1 (upload or copy/paste)
|
||||
*/
|
||||
router.on('route:step1', function () {
|
||||
var methodProcessContainerTemplate;
|
||||
var currentStepE;
|
||||
var methodSelectionElement;
|
||||
var pasteInputElement;
|
||||
var pasteInputPlaceholderElement;
|
||||
var pasteProcessButtonElement;
|
||||
var mailChimpKeyInputElement;
|
||||
var mailChimpKeyVerifyButtonElement;
|
||||
var mailChimpListsContainerElement;
|
||||
var mailChimpProcessButtonElement;
|
||||
var uploadElement;
|
||||
var uploadProcessButtonElement;
|
||||
// set or reset temporary validation rule on all columns
|
||||
window.mailpoetColumns = jQuery.map(window.mailpoetColumns, function (column, columnIndex) {
|
||||
window.mailpoetColumns = jQuery.map(window.mailpoetColumns, function (column) {
|
||||
var col = column;
|
||||
col.validation_rule = false;
|
||||
return col;
|
||||
@ -63,36 +74,34 @@ define(
|
||||
}
|
||||
|
||||
// render process button for each method
|
||||
var methodProcessContainerTemplate =
|
||||
methodProcessContainerTemplate =
|
||||
Handlebars.compile(jQuery('#method_process_template').html());
|
||||
jQuery('.mailpoet_method_process').html(methodProcessContainerTemplate());
|
||||
|
||||
// define reusable variables
|
||||
var currentStepE = jQuery(location.hash),
|
||||
methodSelectionElement = jQuery('#select_method'),
|
||||
pasteInputElement = jQuery('#paste_input'),
|
||||
pasteInputPlaceholderElement =
|
||||
pasteInputElement.data('placeholder').replace(/\\n/g, '\n'),
|
||||
pasteProcessButtonElement =
|
||||
jQuery('#method_paste > div.mailpoet_method_process')
|
||||
.find('a.mailpoet_process'),
|
||||
mailChimpKeyInputElement = jQuery('#mailchimp_key'),
|
||||
mailChimpKeyVerifyButtonElement = jQuery('#mailchimp_key_verify'),
|
||||
mailChimpListsContainerElement = jQuery('#mailchimp_lists'),
|
||||
mailChimpProcessButtonElement =
|
||||
jQuery('#method_mailchimp > div.mailpoet_method_process')
|
||||
.find('a.mailpoet_process'),
|
||||
uploadElement = jQuery('#file_local'),
|
||||
uploadProcessButtonElement =
|
||||
jQuery('#method_file > div.mailpoet_method_process')
|
||||
.find('a.mailpoet_process');
|
||||
currentStepE = jQuery(location.hash);
|
||||
methodSelectionElement = jQuery('#select_method');
|
||||
pasteInputElement = jQuery('#paste_input');
|
||||
pasteInputPlaceholderElement =
|
||||
pasteInputElement.data('placeholder').replace(/\\n/g, '\n');
|
||||
pasteProcessButtonElement =
|
||||
jQuery('#method_paste > div.mailpoet_method_process')
|
||||
.find('a.mailpoet_process');
|
||||
mailChimpKeyInputElement = jQuery('#mailchimp_key');
|
||||
mailChimpKeyVerifyButtonElement = jQuery('#mailchimp_key_verify');
|
||||
mailChimpListsContainerElement = jQuery('#mailchimp_lists');
|
||||
mailChimpProcessButtonElement = jQuery('#method_mailchimp > div.mailpoet_method_process')
|
||||
.find('a.mailpoet_process');
|
||||
uploadElement = jQuery('#file_local');
|
||||
uploadProcessButtonElement =
|
||||
jQuery('#method_file > div.mailpoet_method_process')
|
||||
.find('a.mailpoet_process');
|
||||
|
||||
// define method change behavior
|
||||
methodSelectionElement.change(function () {
|
||||
var available_methods = jQuery(':radio[name="select_method"]');
|
||||
var selected_method = available_methods.index(available_methods.filter(':checked'));
|
||||
MailPoet.Notice.hide();
|
||||
var available_methods = jQuery(':radio[name="select_method"]'),
|
||||
selected_method =
|
||||
available_methods.index(available_methods.filter(':checked'));
|
||||
// hide all methods
|
||||
currentStepE.find('.inside')
|
||||
.children('div[id^="method_"]')
|
||||
@ -131,9 +140,9 @@ define(
|
||||
});
|
||||
|
||||
pasteProcessButtonElement.click(function () {
|
||||
var pasteSize = encodeURI(pasteInputElement.val()).split(/%..|./).length - 1;
|
||||
MailPoet.Notice.hide();
|
||||
// get an approximate size of textarea paste in bytes
|
||||
var pasteSize = encodeURI(pasteInputElement.val()).split(/%..|./).length - 1;
|
||||
if (pasteSize > window.maxPostSizeBytes) {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('maxPostSizeNotice'));
|
||||
return;
|
||||
@ -149,8 +158,8 @@ define(
|
||||
* CSV file
|
||||
*/
|
||||
uploadElement.change(function () {
|
||||
MailPoet.Notice.hide();
|
||||
var ext = this.value.match(/\.(.+)$/);
|
||||
MailPoet.Notice.hide();
|
||||
if (ext === null || ext[1].toLowerCase() !== 'csv') {
|
||||
this.value = '';
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('wrongFileFormat'));
|
||||
@ -234,7 +243,7 @@ define(
|
||||
api_key: mailChimpKeyInputElement.val(),
|
||||
lists: mailChimpListsContainerElement.find('select').val()
|
||||
}
|
||||
}).always(function (response) {
|
||||
}).always(function () {
|
||||
MailPoet.Modal.loading(false);
|
||||
}).done(function (response) {
|
||||
window.importData.step1 = response.data;
|
||||
@ -294,48 +303,48 @@ define(
|
||||
}
|
||||
|
||||
function parseCSV(isFile) {
|
||||
var processedSubscribers = [],
|
||||
parsedEmails = [],
|
||||
duplicateEmails = [],
|
||||
invalidEmails = [],
|
||||
emailColumnPosition = null,
|
||||
columnCount = null,
|
||||
isHeaderFound = false,
|
||||
advancedOptionHeader = true,
|
||||
advancedOptionDelimiter = '',
|
||||
advancedOptionNewline = '',
|
||||
advancedOptionComments = false,
|
||||
// trim spaces, commas, periods,
|
||||
// single/double quotes and convert to lowercase
|
||||
detectAndCleanupEmail = function (emailString) {
|
||||
var test;
|
||||
// decode HTML entities
|
||||
var email = jQuery('<div />').html(emailString).text();
|
||||
email = email
|
||||
.toLowerCase()
|
||||
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
||||
// right trim non-printable characters (e.g., "email@email.com<6F>")
|
||||
.replace(/^["';.,\s]+|[^\x20-\x7E]+$|["';.,_\s]+$/g, '')
|
||||
// remove spaces (e.g., "email @ email . com")
|
||||
// remove urlencoded characters
|
||||
.replace(/\s+|%\d+|,+/g, '');
|
||||
// detect e-mails that will be otherwise rejected by email regex
|
||||
test = /<(.*?)>/.exec(email);
|
||||
if (test) {
|
||||
// is the email inside angle brackets (e.g., 'some@email.com <some@email.com>')?
|
||||
email = test[1].trim();
|
||||
}
|
||||
test = /mailto:(?:\s+)?(.*)/.exec(email);
|
||||
if (test) {
|
||||
// is the email in 'mailto:email' format?
|
||||
email = test[1].trim();
|
||||
}
|
||||
// test for valid characters using WP's rule (https://core.trac.wordpress.org/browser/tags/4.7.3/src/wp-includes/formatting.php#L2902)
|
||||
if (!/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.\-@]+$/.test(email)) {
|
||||
return false;
|
||||
}
|
||||
return email;
|
||||
};
|
||||
var processedSubscribers = [];
|
||||
var parsedEmails = [];
|
||||
var duplicateEmails = [];
|
||||
var invalidEmails = [];
|
||||
var emailColumnPosition = null;
|
||||
var columnCount = null;
|
||||
var isHeaderFound = false;
|
||||
var advancedOptionHeader = true;
|
||||
var advancedOptionDelimiter = '';
|
||||
var advancedOptionNewline = '';
|
||||
var advancedOptionComments = false;
|
||||
// trim spaces, commas, periods,
|
||||
// single/double quotes and convert to lowercase
|
||||
var detectAndCleanupEmail = function (emailString) {
|
||||
var test;
|
||||
// decode HTML entities
|
||||
var email = jQuery('<div />').html(emailString).text();
|
||||
email = email
|
||||
.toLowerCase()
|
||||
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
||||
// right trim non-printable characters (e.g., "email@email.com<6F>")
|
||||
.replace(/^["';.,\s]+|[^\x20-\x7E]+$|["';.,_\s]+$/g, '')
|
||||
// remove spaces (e.g., "email @ email . com")
|
||||
// remove urlencoded characters
|
||||
.replace(/\s+|%\d+|,+/g, '');
|
||||
// detect e-mails that will be otherwise rejected by email regex
|
||||
test = /<(.*?)>/.exec(email);
|
||||
if (test) {
|
||||
// is the email inside angle brackets (e.g., 'some@email.com <some@email.com>')?
|
||||
email = test[1].trim();
|
||||
}
|
||||
test = /mailto:(?:\s+)?(.*)/.exec(email);
|
||||
if (test) {
|
||||
// is the email in 'mailto:email' format?
|
||||
email = test[1].trim();
|
||||
}
|
||||
// test for valid characters using WP's rule (https://core.trac.wordpress.org/browser/tags/4.7.3/src/wp-includes/formatting.php#L2902)
|
||||
if (!/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.\-@]+$/.test(email)) {
|
||||
return false;
|
||||
}
|
||||
return email;
|
||||
};
|
||||
|
||||
return {
|
||||
skipEmptyLines: true,
|
||||
@ -347,11 +356,18 @@ define(
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('dataProcessingError'));
|
||||
},
|
||||
complete: function (CSV) {
|
||||
for (var rowCount in CSV.data) {
|
||||
var rowData = CSV.data[rowCount].map(function (el) {
|
||||
var email;
|
||||
var emailAddress;
|
||||
var column;
|
||||
var rowCount;
|
||||
var rowData;
|
||||
var rowColumnCount;
|
||||
var errorNotice;
|
||||
for (rowCount in CSV.data) {
|
||||
rowData = CSV.data[rowCount].map(function (el) {
|
||||
return el.trim();
|
||||
});
|
||||
var rowColumnCount = rowData.length;
|
||||
rowColumnCount = rowData.length;
|
||||
// set the number of row elements based on the first non-empty row
|
||||
if (columnCount === null) {
|
||||
columnCount = rowColumnCount;
|
||||
@ -365,14 +381,14 @@ define(
|
||||
// determine position of email address inside an array; this is
|
||||
// done once and then email regex is run just on that element for each row
|
||||
if (emailColumnPosition === null) {
|
||||
for (var column in rowData) {
|
||||
var email = detectAndCleanupEmail(rowData[column]);
|
||||
for (column in rowData) {
|
||||
emailAddress = detectAndCleanupEmail(rowData[column]);
|
||||
if (emailColumnPosition === null
|
||||
&& window.emailRegex.test(email)) {
|
||||
&& window.emailRegex.test(emailAddress)) {
|
||||
emailColumnPosition = column;
|
||||
parsedEmails[email] = true; // add current e-mail to an object index
|
||||
rowData[column] = email;
|
||||
processedSubscribers[email] = rowData;
|
||||
parsedEmails[emailAddress] = true; // add current e-mail to an object index
|
||||
rowData[column] = emailAddress;
|
||||
processedSubscribers[emailAddress] = rowData;
|
||||
}
|
||||
}
|
||||
if (emailColumnPosition === null
|
||||
@ -383,7 +399,7 @@ define(
|
||||
}
|
||||
}
|
||||
else if (rowData[emailColumnPosition] !== '') {
|
||||
var email = detectAndCleanupEmail(rowData[emailColumnPosition]);
|
||||
email = detectAndCleanupEmail(rowData[emailColumnPosition]);
|
||||
if (_.has(parsedEmails, email)) {
|
||||
duplicateEmails.push(email);
|
||||
}
|
||||
@ -427,7 +443,7 @@ define(
|
||||
}
|
||||
else {
|
||||
MailPoet.Modal.loading(false);
|
||||
var errorNotice = MailPoet.I18n.t('noValidRecords');
|
||||
errorNotice = MailPoet.I18n.t('noValidRecords');
|
||||
errorNotice = errorNotice.replace('[link]', MailPoet.I18n.t('csvKBLink'));
|
||||
errorNotice = errorNotice.replace('[/link]', '</a>');
|
||||
MailPoet.Notice.error(errorNotice);
|
||||
@ -438,37 +454,41 @@ define(
|
||||
});
|
||||
|
||||
router.on('route:step2', function () {
|
||||
var nextStepButton;
|
||||
var previousStepButton;
|
||||
var subscribers;
|
||||
var subscribersDataTemplate;
|
||||
var subscribersDataTemplatePartial;
|
||||
var subscribersDataParseResultsTemplate;
|
||||
var segmentSelectElement;
|
||||
var maxRowsToShow;
|
||||
var filler;
|
||||
var fillerArray;
|
||||
var fillerPosition;
|
||||
var import_results;
|
||||
var duplicates;
|
||||
var email;
|
||||
if (typeof (window.importData.step1) === 'undefined') {
|
||||
router.navigate('step1', { trigger: true });
|
||||
return;
|
||||
}
|
||||
// define reusable variables
|
||||
var nextStepButton = jQuery('#step2_process'),
|
||||
previousStepButton = jQuery('#return_to_step1'),
|
||||
nextStepButton = jQuery('#step2_process');
|
||||
previousStepButton = jQuery('#return_to_step1');
|
||||
// create a copy of subscribers object for further manipulation
|
||||
subscribers = jQuery.extend(true, {}, window.importData.step1),
|
||||
subscribersDataTemplate =
|
||||
Handlebars
|
||||
.compile(jQuery('#subscribers_data_template')
|
||||
.html()),
|
||||
subscribersDataTemplatePartial =
|
||||
Handlebars
|
||||
.compile(jQuery('#subscribers_data_template_partial')
|
||||
.html()),
|
||||
subscribersDataParseResultsTemplate =
|
||||
Handlebars
|
||||
.compile(jQuery('#subscribers_data_parse_results_template')
|
||||
.html()),
|
||||
segmentSelectElement = jQuery('#mailpoet_segments_select'),
|
||||
maxRowsToShow = 10,
|
||||
filler = '. . .',
|
||||
subscribers = jQuery.extend(true, {}, window.importData.step1);
|
||||
subscribersDataTemplate = Handlebars.compile(jQuery('#subscribers_data_template').html());
|
||||
subscribersDataTemplatePartial = Handlebars.compile(jQuery('#subscribers_data_template_partial').html());
|
||||
subscribersDataParseResultsTemplate = Handlebars.compile(jQuery('#subscribers_data_parse_results_template').html());
|
||||
segmentSelectElement = jQuery('#mailpoet_segments_select');
|
||||
maxRowsToShow = 10;
|
||||
filler = '. . .';
|
||||
// create an array of filler data with the same number of
|
||||
// elements as in the subscribers' data row
|
||||
fillerArray = Array.apply(
|
||||
null,
|
||||
new Array(subscribers.subscribers[0].length)
|
||||
).map(String.prototype.valueOf, filler),
|
||||
fillerPosition;
|
||||
fillerArray = Array.apply(
|
||||
null,
|
||||
new Array(subscribers.subscribers[0].length)
|
||||
).map(String.prototype.valueOf, filler);
|
||||
|
||||
showCurrentStep();
|
||||
|
||||
@ -480,12 +500,12 @@ define(
|
||||
if (subscribers.invalid.length || subscribers.duplicate.length) {
|
||||
// count repeating e-mails inside duplicate array and present them in
|
||||
// 'email (xN)' format
|
||||
var duplicates = {};
|
||||
duplicates = {};
|
||||
subscribers.duplicate.forEach(function (email) {
|
||||
duplicates[email] = (duplicates[email] || 0) + 1;
|
||||
});
|
||||
subscribers.duplicate = [];
|
||||
for (var email in duplicates) {
|
||||
for (email in duplicates) {
|
||||
if (duplicates[email] > 1) {
|
||||
subscribers.duplicate.push(email + ' (x' + duplicates[email] + ')');
|
||||
}
|
||||
@ -494,7 +514,7 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
var import_results = {
|
||||
import_results = {
|
||||
notice: MailPoet.I18n.t('importNoticeSkipped').replace(
|
||||
'%1$s',
|
||||
'<strong>' + (subscribers.invalid.length + subscribers.duplicate.length) + '</strong>'
|
||||
@ -599,13 +619,14 @@ define(
|
||||
description: segmentDescription
|
||||
}
|
||||
}).done(function (response) {
|
||||
var selected_values;
|
||||
window.mailpoetSegments.push({
|
||||
id: response.data.id,
|
||||
name: response.data.name,
|
||||
subscriberCount: 0
|
||||
});
|
||||
|
||||
var selected_values = segmentSelectElement.val();
|
||||
selected_values = segmentSelectElement.val();
|
||||
if (selected_values === null) {
|
||||
selected_values = [response.data.id];
|
||||
} else {
|
||||
@ -642,20 +663,25 @@ define(
|
||||
Handlebars.registerHelper(
|
||||
'show_and_match_columns',
|
||||
function (subscribers, options) {
|
||||
var displayedColumns = [],
|
||||
displayedColumnsIds = [];
|
||||
var displayedColumns = [];
|
||||
var displayedColumnsIds = [];
|
||||
var i;
|
||||
var columnData;
|
||||
var columnId;
|
||||
var headerName;
|
||||
var headerNameMatch;
|
||||
// go through all elements of the first row in subscribers data
|
||||
for (var i in subscribers.subscribers[0]) {
|
||||
var columnData = subscribers.subscribers[0][i],
|
||||
columnId = 'ignore'; // set default column type
|
||||
for (i in subscribers.subscribers[0]) {
|
||||
columnData = subscribers.subscribers[0][i];
|
||||
columnId = 'ignore'; // set default column type
|
||||
// if the column is not undefined and has a valid e-mail, set type as email
|
||||
if (columnData % 1 !== 0 && window.emailRegex.test(columnData)) {
|
||||
columnId = 'email';
|
||||
} else if (subscribers.header) {
|
||||
var headerName = subscribers.header[i],
|
||||
headerNameMatch = window.mailpoetColumns.map(function (el) {
|
||||
return el.name;
|
||||
}).indexOf(headerName);
|
||||
headerName = subscribers.header[i];
|
||||
headerNameMatch = window.mailpoetColumns.map(function (el) {
|
||||
return el.name;
|
||||
}).indexOf(headerName);
|
||||
// set column type using header
|
||||
if (headerNameMatch !== -1) {
|
||||
columnId = window.mailpoetColumns[headerNameMatch].id;
|
||||
@ -733,8 +759,8 @@ define(
|
||||
}
|
||||
})
|
||||
.on('select2:selecting', function (selectEvent) {
|
||||
var selectElement = this,
|
||||
selectedOptionId = selectEvent.params.args.data.id;
|
||||
var selectElement = this;
|
||||
var selectedOptionId = selectEvent.params.args.data.id;
|
||||
// CREATE CUSTOM FIELD
|
||||
if (selectedOptionId === 'create') {
|
||||
selectEvent.preventDefault();
|
||||
@ -743,7 +769,7 @@ define(
|
||||
title: MailPoet.I18n.t('addNewField'),
|
||||
template: jQuery('#form_template_field_form').html()
|
||||
});
|
||||
jQuery('#form_field_new').parsley().on('form:submit', function (parsley) {
|
||||
jQuery('#form_field_new').parsley().on('form:submit', function () {
|
||||
// get data
|
||||
var data = jQuery(this.$element).serializeObject();
|
||||
|
||||
@ -807,8 +833,8 @@ define(
|
||||
// check for duplicate values in all select options
|
||||
jQuery('select.mailpoet_subscribers_column_data_match')
|
||||
.each(function () {
|
||||
var element = this,
|
||||
elementId = jQuery(element).val();
|
||||
var element = this;
|
||||
var elementId = jQuery(element).val();
|
||||
// if another column has the same value and it's not an 'ignore', prompt user
|
||||
if (elementId === selectedOptionId
|
||||
&& elementId !== 'ignore') {
|
||||
@ -824,28 +850,34 @@ define(
|
||||
}
|
||||
})
|
||||
.on('select2:select', function (selectEvent) {
|
||||
var selectElement = this,
|
||||
selectedOptionId = selectEvent.params.data.id;
|
||||
var selectElement = this;
|
||||
var selectedOptionId = selectEvent.params.data.id;
|
||||
jQuery(selectElement).data('column-id', selectedOptionId);
|
||||
filterSubscribers();
|
||||
});
|
||||
|
||||
// filter subscribers' data to detect dates, emails, etc.
|
||||
function filterSubscribers() {
|
||||
var subscribersClone = jQuery.extend(true, {}, subscribers);
|
||||
var preventNextStep = false;
|
||||
var displayedColumns;
|
||||
jQuery(
|
||||
'[data-id="notice_invalidEmail"], [data-id="notice_invalidDate"]')
|
||||
.remove();
|
||||
var subscribersClone = jQuery.extend(true, {}, subscribers),
|
||||
preventNextStep = false,
|
||||
displayedColumns = jQuery.map(
|
||||
jQuery('.mailpoet_subscribers_column_data_match'), function (element, elementIndex) {
|
||||
var columnId = jQuery(element).data('column-id');
|
||||
var validationRule = jQuery(element).data('validation-rule');
|
||||
jQuery(element).val(columnId).trigger('change');
|
||||
return { id: columnId, index: elementIndex, validationRule: validationRule, element: element };
|
||||
});
|
||||
displayedColumns = jQuery.map(
|
||||
jQuery('.mailpoet_subscribers_column_data_match'), function (element, elementIndex) {
|
||||
var columnId = jQuery(element).data('column-id');
|
||||
var validationRule = jQuery(element).data('validation-rule');
|
||||
jQuery(element).val(columnId).trigger('change');
|
||||
return { id: columnId, index: elementIndex, validationRule: validationRule, element: element };
|
||||
});
|
||||
// iterate through the object of mailpoet columns
|
||||
jQuery.map(window.mailpoetColumns, function (column, columnIndex) {
|
||||
jQuery.map(window.mailpoetColumns, function (column) {
|
||||
var firstRowData;
|
||||
var validationRule;
|
||||
var testedFormat;
|
||||
var format;
|
||||
var allowedDateFormats;
|
||||
// check if the column id matches the selected id of one of the
|
||||
// subscriber's data columns
|
||||
var matchedColumn = _.find(displayedColumns, function (data) { return data.id === column.id; });
|
||||
@ -869,7 +901,7 @@ define(
|
||||
}
|
||||
// DATE filter: if column type is date, check if we can recognize it
|
||||
if (column.type === 'date' && matchedColumn) {
|
||||
var allowedDateFormats = [
|
||||
allowedDateFormats = [
|
||||
Moment.ISO_8601,
|
||||
'YYYY/MM/DD',
|
||||
'MM/DD/YYYY',
|
||||
@ -880,8 +912,8 @@ define(
|
||||
'YYYY/MM',
|
||||
'YYYY'
|
||||
];
|
||||
var firstRowData = subscribersClone.subscribers[0][matchedColumn.index];
|
||||
var validationRule = false;
|
||||
firstRowData = subscribersClone.subscribers[0][matchedColumn.index];
|
||||
validationRule = false;
|
||||
// check if date exists
|
||||
if (firstRowData.trim() === '') {
|
||||
subscribersClone.subscribers[0][matchedColumn.index] =
|
||||
@ -892,10 +924,10 @@ define(
|
||||
preventNextStep = true;
|
||||
}
|
||||
else {
|
||||
for (var format in allowedDateFormats) {
|
||||
var testedFormat = allowedDateFormats[format];
|
||||
for (format in allowedDateFormats) {
|
||||
testedFormat = allowedDateFormats[format];
|
||||
if (Moment(firstRowData, testedFormat, true).isValid()) {
|
||||
var validationRule = (typeof (testedFormat) === 'function') ?
|
||||
validationRule = (typeof (testedFormat) === 'function') ?
|
||||
'datetime' :
|
||||
testedFormat;
|
||||
// set validation on the column element
|
||||
@ -910,8 +942,8 @@ define(
|
||||
jQuery.map(subscribersClone.subscribers, function (dataSubscribers, index) {
|
||||
var data = dataSubscribers;
|
||||
var rowData = data[matchedColumn.index];
|
||||
if (index === fillerPosition || rowData.trim() === '') return;
|
||||
var date = Moment(rowData, testedFormat, true);
|
||||
if (index === fillerPosition || rowData.trim() === '') return;
|
||||
// validate date
|
||||
if (date.isValid()) {
|
||||
data[matchedColumn.index] = new Handlebars.SafeString(
|
||||
@ -970,33 +1002,35 @@ define(
|
||||
});
|
||||
|
||||
nextStepButton.off().on('click', function () {
|
||||
var columns = {};
|
||||
var queue = new jQuery.AsyncQueue();
|
||||
var batchNumber = 0;
|
||||
var batchSize = 2000;
|
||||
var timestamp = Date.now() / 1000;
|
||||
var subscribers = [];
|
||||
var importResults = {
|
||||
created: 0,
|
||||
updated: 0,
|
||||
errors: [],
|
||||
segments: []
|
||||
};
|
||||
var subscribers;
|
||||
var splitSubscribers;
|
||||
|
||||
if (jQuery(this).hasClass('button-disabled')) {
|
||||
return;
|
||||
}
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
var columns = {},
|
||||
queue = new jQuery.AsyncQueue(),
|
||||
batchNumber = 0,
|
||||
batchSize = 2000,
|
||||
timestamp = Date.now() / 1000,
|
||||
subscribers = [],
|
||||
importResults = {
|
||||
created: 0,
|
||||
updated: 0,
|
||||
errors: [],
|
||||
segments: []
|
||||
},
|
||||
splitSubscribers = function (subscribers, size) {
|
||||
return subscribers.reduce(function (res, item, index) {
|
||||
if (index % size === 0) {
|
||||
res.push([]);
|
||||
}
|
||||
res[res.length - 1].push(item);
|
||||
return res;
|
||||
}, []);
|
||||
},
|
||||
subscribers = splitSubscribers(window.importData.step1.subscribers, batchSize);
|
||||
splitSubscribers = function (subscribers, size) {
|
||||
return subscribers.reduce(function (res, item, index) {
|
||||
if (index % size === 0) {
|
||||
res.push([]);
|
||||
}
|
||||
res[res.length - 1].push(item);
|
||||
return res;
|
||||
}, []);
|
||||
};
|
||||
subscribers = splitSubscribers(window.importData.step1.subscribers, batchSize);
|
||||
|
||||
_.each(jQuery('select.mailpoet_subscribers_column_data_match'),
|
||||
function (column, columnIndex) {
|
||||
@ -1067,6 +1101,9 @@ define(
|
||||
});
|
||||
|
||||
router.on('route:step3', function () {
|
||||
var subscribersDataImportResultsTemplate;
|
||||
var exportMenuElement;
|
||||
var importResults;
|
||||
if (typeof (window.importData.step2) === 'undefined') {
|
||||
router.navigate('step2', { trigger: true });
|
||||
return;
|
||||
@ -1085,25 +1122,23 @@ define(
|
||||
});
|
||||
|
||||
// display statistics
|
||||
var subscribersDataImportResultsTemplate =
|
||||
Handlebars
|
||||
.compile(jQuery('#subscribers_data_import_results_template')
|
||||
.html()),
|
||||
exportMenuElement = jQuery('span.mailpoet_export'),
|
||||
importResults = {
|
||||
created: (window.importData.step2.created)
|
||||
? MailPoet.I18n.t('subscribersCreated')
|
||||
.replace('%1$s', '<strong>' + window.importData.step2.created.toLocaleString() + '</strong>')
|
||||
.replace('%2$s', '"' + window.importData.step2.segments.join('", "') + '"')
|
||||
: false,
|
||||
updated: (window.importData.step2.updated)
|
||||
? MailPoet.I18n.t('subscribersUpdated')
|
||||
.replace('%1$s', '<strong>' + window.importData.step2.updated.toLocaleString() + '</strong>')
|
||||
.replace('%2$s', '"' + window.importData.step2.segments.join('", "') + '"')
|
||||
: false,
|
||||
no_action: (!window.importData.step2.created && !window.importData.step2.updated),
|
||||
added_to_segment_with_welcome_notification: window.importData.step2.added_to_segment_with_welcome_notification
|
||||
};
|
||||
subscribersDataImportResultsTemplate =
|
||||
Handlebars.compile(jQuery('#subscribers_data_import_results_template').html());
|
||||
exportMenuElement = jQuery('span.mailpoet_export');
|
||||
importResults = {
|
||||
created: (window.importData.step2.created)
|
||||
? MailPoet.I18n.t('subscribersCreated')
|
||||
.replace('%1$s', '<strong>' + window.importData.step2.created.toLocaleString() + '</strong>')
|
||||
.replace('%2$s', '"' + window.importData.step2.segments.join('", "') + '"')
|
||||
: false,
|
||||
updated: (window.importData.step2.updated)
|
||||
? MailPoet.I18n.t('subscribersUpdated')
|
||||
.replace('%1$s', '<strong>' + window.importData.step2.updated.toLocaleString() + '</strong>')
|
||||
.replace('%2$s', '"' + window.importData.step2.segments.join('", "') + '"')
|
||||
: false,
|
||||
no_action: (!window.importData.step2.created && !window.importData.step2.updated),
|
||||
added_to_segment_with_welcome_notification: window.importData.step2.added_to_segment_with_welcome_notification
|
||||
};
|
||||
|
||||
jQuery('#subscribers_data_import_results')
|
||||
.html(subscribersDataImportResultsTemplate(importResults))
|
||||
|
@ -57,7 +57,7 @@ class API {
|
||||
$this->setRequestData($_POST);
|
||||
|
||||
if($this->checkToken() === false) {
|
||||
$error_message = __('Invalid API request.', 'mailpoet');
|
||||
$error_message = __('Sorry, but we couldn\'t connect to the MailPoet server. Please refresh the web page and try again.', 'mailpoet');
|
||||
$error_response = $this->createErrorResponse(Error::UNAUTHORIZED, $error_message, Response::STATUS_UNAUTHORIZED);
|
||||
return $error_response->send();
|
||||
}
|
||||
@ -200,4 +200,4 @@ class API {
|
||||
);
|
||||
return $error_response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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');
|
||||
|
@ -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,',
|
||||
|
@ -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;
|
||||
|
@ -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'),
|
||||
|
8
lib/Models/SubscriberIP.php
Normal file
8
lib/Models/SubscriberIP.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Models;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SubscriberIP extends Model {
|
||||
public static $_table = MP_SUBSCRIBER_IPS_TABLE;
|
||||
}
|
@ -20,9 +20,13 @@ class Image {
|
||||
if(!empty($element['link'])) {
|
||||
$image_template = '<a href="' . $element['link'] . '">' . $image_template . '</a>';
|
||||
}
|
||||
$align = 'center';
|
||||
if(!empty($element['styles']['block']['textAlign']) && in_array($element['styles']['block']['textAlign'], array('left', 'right'))) {
|
||||
$align = $element['styles']['block']['textAlign'];
|
||||
}
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_image ' . (($element['fullWidth'] === false) ? 'mailpoet_padded_bottom mailpoet_padded_side' : '') . '" align="center" valign="top">
|
||||
<td class="mailpoet_image ' . (($element['fullWidth'] === false) ? 'mailpoet_padded_bottom mailpoet_padded_side' : '') . '" align="' . $align . '" valign="top">
|
||||
' . $image_template . '
|
||||
</td>
|
||||
</tr>';
|
||||
|
@ -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();
|
||||
|
55
lib/Subscription/Throttling.php
Normal file
55
lib/Subscription/Throttling.php
Normal 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();
|
||||
}
|
||||
}
|
@ -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)) {
|
||||
|
@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
|
||||
|
||||
/*
|
||||
* Plugin Name: MailPoet 3 (new)
|
||||
* Version: 3.0.3
|
||||
* 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.3',
|
||||
'version' => '3.0.7',
|
||||
'filename' => __FILE__,
|
||||
'path' => dirname(__FILE__),
|
||||
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
|
||||
|
17
readme.txt
17
readme.txt
@ -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.3
|
||||
Stable tag: 3.0.7
|
||||
License: GPLv3
|
||||
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
@ -114,6 +114,21 @@ 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;
|
||||
|
||||
= 3.0.4 - 2017-10-05 =
|
||||
* Fixed: dividers and spacers' height can be changed on mouse drag again;
|
||||
|
||||
= 3.0.3 - 2017-10-03 =
|
||||
* Fixed: mixed collation error in WordPress user synchronization. Thanks Chris, Till, Robin, Robero, @Seph, @kaiwen and others for the reports!
|
||||
|
||||
|
@ -25,6 +25,7 @@ $models = array(
|
||||
'Subscriber',
|
||||
'SubscriberCustomField',
|
||||
'SubscriberSegment',
|
||||
'SubscriberIP',
|
||||
'StatisticsOpens',
|
||||
'StatisticsClicks',
|
||||
'StatisticsNewsletters',
|
||||
|
@ -1,8 +1,8 @@
|
||||
var fs = require('fs');
|
||||
module.exports = {
|
||||
loadFileToContainer: function (path, window, containerTagName, opts) {
|
||||
var contents = fs.readFileSync(path),
|
||||
container = window.document.createElement(containerTagName);
|
||||
var contents = fs.readFileSync(path);
|
||||
var container = window.document.createElement(containerTagName);
|
||||
var options = opts || {};
|
||||
container.innerHTML = contents;
|
||||
|
||||
|
@ -3,6 +3,7 @@ var sinon = require('sinon');
|
||||
var sinonChai = require('sinon-chai');
|
||||
var chaiJq = require('chai-jq');
|
||||
var _ = require('underscore');
|
||||
var jsdom = require('jsdom').jsdom;
|
||||
|
||||
chai.use(sinonChai);
|
||||
chai.use(chaiJq);
|
||||
@ -11,7 +12,6 @@ global.expect = chai.expect;
|
||||
global.sinon = sinon;
|
||||
|
||||
if (!global.document || !global.window) {
|
||||
var jsdom = require('jsdom').jsdom;
|
||||
|
||||
global.document = jsdom('<html><head><script></script></head><body></body></html>', {}, {
|
||||
FetchExternalResources: ['script'],
|
||||
@ -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 = {
|
||||
|
@ -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,43 +19,45 @@ define([
|
||||
var EditorApplication = App;
|
||||
var CommunicationComponent = Communication;
|
||||
|
||||
describe('Automated Latest Content Supervisor', function() {
|
||||
describe('Automated Latest Content Supervisor', function () {
|
||||
var model;
|
||||
beforeEach(function() {
|
||||
var mock;
|
||||
var module;
|
||||
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()]);
|
||||
|
||||
var mock = sinon.mock({ getBulkTransformedPosts: function() {} })
|
||||
mock = sinon.mock({ getBulkTransformedPosts: function () {} })
|
||||
.expects('getBulkTransformedPosts').once().returns(jQuery.Deferred());
|
||||
|
||||
var module = AutomatedLatestContentInjector({
|
||||
module = AutomatedLatestContentInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
getBulkTransformedPosts: mock
|
||||
}
|
||||
});
|
||||
|
||||
var model = new module.ALCSupervisor();
|
||||
model = new module.ALCSupervisor();
|
||||
model.refresh();
|
||||
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('refreshes posts for given blocks', function() {
|
||||
var block1 = new Backbone.SuperModel(),
|
||||
block2 = new Backbone.SuperModel(),
|
||||
postsSet1 = [
|
||||
{ type: 'customTypeOne' }
|
||||
],
|
||||
postsSet2 = [
|
||||
{ type: 'customTypeTwo' },
|
||||
{ type: 'customTypeTwo' }
|
||||
],
|
||||
mock1 = sinon.mock(block1),
|
||||
mock2 = sinon.mock(block2);
|
||||
it('refreshes posts for given blocks', function () {
|
||||
var block1 = new Backbone.SuperModel();
|
||||
var block2 = new Backbone.SuperModel();
|
||||
var postsSet1 = [
|
||||
{ type: 'customTypeOne' }
|
||||
];
|
||||
var postsSet2 = [
|
||||
{ type: 'customTypeTwo' },
|
||||
{ type: 'customTypeTwo' }
|
||||
];
|
||||
var mock1 = sinon.mock(block1);
|
||||
var mock2 = sinon.mock(block2);
|
||||
|
||||
mock1.expects('trigger').once().withArgs('refreshPosts', postsSet1);
|
||||
mock2.expects('trigger').once().withArgs('refreshPosts', postsSet2);
|
||||
@ -69,9 +71,10 @@ define([
|
||||
|
||||
describe('Automated latest content', function () {
|
||||
describe('model', function () {
|
||||
var model, module;
|
||||
var model;
|
||||
var module;
|
||||
|
||||
before(function() {
|
||||
before(function () {
|
||||
module = AutomatedLatestContentBlock;
|
||||
});
|
||||
|
||||
@ -172,6 +175,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
automatedLatestContent: {
|
||||
@ -219,7 +223,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (module.AutomatedLatestContentBlockModel)();
|
||||
model = new (module.AutomatedLatestContentBlockModel)();
|
||||
|
||||
expect(model.get('amount')).to.equal('17');
|
||||
expect(model.get('contentType')).to.equal('mailpoet_page');
|
||||
@ -250,9 +254,10 @@ 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);
|
||||
var model = new (module.AutomatedLatestContentBlockModel)();
|
||||
model = new (module.AutomatedLatestContentBlockModel)();
|
||||
|
||||
model.updatePosts([{
|
||||
type: 'someCustomType'
|
||||
@ -264,9 +269,11 @@ define([
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model, view, module;
|
||||
var model;
|
||||
var view;
|
||||
var module;
|
||||
|
||||
before(function() {
|
||||
before(function () {
|
||||
module = AutomatedLatestContentBlock;
|
||||
});
|
||||
|
||||
@ -276,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 () {
|
||||
@ -290,20 +297,16 @@ define([
|
||||
});
|
||||
|
||||
describe('replaceAllButtonStyles', function () {
|
||||
var model, view, module, onStub;
|
||||
|
||||
before(function() {
|
||||
module = AutomatedLatestContentBlock;
|
||||
});
|
||||
var onStub;
|
||||
var view;
|
||||
|
||||
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);
|
||||
model = {set: sinon.stub()};
|
||||
view = new (module.AutomatedLatestContentBlockView)({model: model});
|
||||
view = new (AutomatedLatestContentBlock.AutomatedLatestContentBlockView)({ model: { set: sinon.stub() } });
|
||||
});
|
||||
|
||||
it('listens to the event', function () {
|
||||
@ -321,18 +324,20 @@ define([
|
||||
}
|
||||
};
|
||||
callback(data);
|
||||
expect(model.set).to.have.been.callCount(1);
|
||||
expect(model.set).to.have.been.calledWithMatch(sinon.match.has('readMoreButton', data));
|
||||
expect(view.model.set).to.have.been.callCount(1);
|
||||
expect(view.model.set).to.have.been.calledWithMatch(sinon.match.has('readMoreButton', data));
|
||||
});
|
||||
});
|
||||
|
||||
describe('block settings view', function () {
|
||||
var model, view, module;
|
||||
var model;
|
||||
var view;
|
||||
var module;
|
||||
|
||||
before(function() {
|
||||
before(function () {
|
||||
module = AutomatedLatestContentInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
getPostTypes: function() {
|
||||
getPostTypes: function () {
|
||||
return jQuery.Deferred();
|
||||
}
|
||||
}
|
||||
@ -340,7 +345,7 @@ define([
|
||||
});
|
||||
|
||||
before(function () {
|
||||
CommunicationComponent.getPostTypes = function() {
|
||||
CommunicationComponent.getPostTypes = function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve([
|
||||
{
|
||||
@ -373,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 () {
|
||||
@ -387,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();
|
||||
});
|
||||
|
||||
@ -495,11 +500,12 @@ define([
|
||||
expect(model.get('showDivider')).to.equal(newValue);
|
||||
});
|
||||
|
||||
describe('when "title only" display type is selected', function() {
|
||||
var model, view;
|
||||
beforeEach(function() {
|
||||
describe('when "title only" display type is selected', function () {
|
||||
var model;
|
||||
var view;
|
||||
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();
|
||||
});
|
||||
@ -508,11 +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() {
|
||||
var model, view;
|
||||
beforeEach(function() {
|
||||
describe('when "title as list" is selected', function () {
|
||||
var model;
|
||||
var view;
|
||||
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();
|
||||
@ -523,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();
|
||||
});
|
||||
@ -548,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
});
|
||||
@ -108,6 +108,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
button: {
|
||||
@ -131,7 +132,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (ButtonBlock.ButtonBlockModel)();
|
||||
model = new (ButtonBlock.ButtonBlockModel)();
|
||||
|
||||
expect(model.get('text')).to.equal('Some new text');
|
||||
expect(model.get('url')).to.equal('http://somenewurl.com');
|
||||
@ -158,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');
|
||||
@ -173,7 +174,8 @@ define([
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
var model;
|
||||
var view;
|
||||
|
||||
before(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
@ -196,7 +198,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
view = new (ButtonBlock.ButtonBlockView)({model: model});
|
||||
view = new (ButtonBlock.ButtonBlockView)({ model: model });
|
||||
view.render();
|
||||
});
|
||||
|
||||
@ -264,14 +266,15 @@ define([
|
||||
});
|
||||
|
||||
describe('replaceAllButtonStyles', function () {
|
||||
var model, view, onStub;
|
||||
|
||||
var model;
|
||||
var view;
|
||||
var onStub;
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
@ -312,13 +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, view;
|
||||
before(function() {
|
||||
var model;
|
||||
var view;
|
||||
before(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
@ -327,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();
|
||||
});
|
||||
@ -449,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: {
|
||||
@ -460,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: {
|
||||
@ -476,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () {
|
||||
@ -13,8 +13,9 @@ define([
|
||||
|
||||
describe('model', function () {
|
||||
describe('by default', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication);
|
||||
var model = new ModelClass();
|
||||
model = new ModelClass();
|
||||
|
||||
it('has container type', function () {
|
||||
expect(model.get('type')).to.equal('container');
|
||||
@ -33,6 +34,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
container: {
|
||||
@ -44,7 +46,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (ContainerBlock.ContainerBlockModel)();
|
||||
model = new (ContainerBlock.ContainerBlockModel)();
|
||||
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#123456');
|
||||
});
|
||||
@ -52,10 +54,10 @@ define([
|
||||
|
||||
describe('when creating with children', function () {
|
||||
var testModel = {
|
||||
type: 'sampleType',
|
||||
someField: 'Some Content'
|
||||
},
|
||||
model;
|
||||
type: 'sampleType',
|
||||
someField: 'Some Content'
|
||||
};
|
||||
var model;
|
||||
|
||||
it('will recursively create children', function () {
|
||||
EditorApplication.getBlockTypeModel = sinon.stub().returns(Backbone.Model);
|
||||
@ -63,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);
|
||||
@ -93,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);
|
||||
@ -107,10 +109,12 @@ define([
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication);
|
||||
var model = new (ContainerBlock.ContainerBlockModel)(),
|
||||
view = new (ContainerBlock.ContainerBlockView)({model: model});
|
||||
model = new (ContainerBlock.ContainerBlockModel)();
|
||||
view = new (ContainerBlock.ContainerBlockView)({ model: model });
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
@ -119,8 +123,8 @@ define([
|
||||
describe('once rendered', function () {
|
||||
|
||||
describe('on root level', function () {
|
||||
var model = new (ContainerBlock.ContainerBlockModel)(),
|
||||
view;
|
||||
var model = new (ContainerBlock.ContainerBlockModel)();
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
@ -151,8 +155,8 @@ define([
|
||||
});
|
||||
|
||||
describe.skip('on non-root levels', function () {
|
||||
var model = new (ContainerBlock.ContainerBlockModel)(),
|
||||
view;
|
||||
var model = new (ContainerBlock.ContainerBlockModel)();
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
@ -187,22 +191,25 @@ define([
|
||||
});
|
||||
|
||||
describe('settings view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication);
|
||||
var model = new (ContainerBlock.ContainerBlockModel)(),
|
||||
view = new (ContainerBlock.ContainerBlockSettingsView)({model: model});
|
||||
model = new (ContainerBlock.ContainerBlockModel)();
|
||||
view = new (ContainerBlock.ContainerBlockSettingsView)({ model: model });
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
beforeEach(function() {
|
||||
var model;
|
||||
var view;
|
||||
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 () {
|
||||
@ -215,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () {
|
||||
@ -70,6 +70,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
divider: {
|
||||
@ -85,7 +86,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (DividerBlock.DividerBlockModel)();
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#123456');
|
||||
expect(model.get('styles.block.padding')).to.equal('37px');
|
||||
@ -103,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 () {
|
||||
@ -137,13 +138,15 @@ define([
|
||||
});
|
||||
|
||||
describe('settings view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
dividers: ['solid', 'inset']
|
||||
});
|
||||
var model = new (DividerBlock.DividerBlockModel)(),
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({ model: model });
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
@ -151,9 +154,10 @@ define([
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
var model;
|
||||
var view;
|
||||
|
||||
before(function() {
|
||||
before(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
dividers: ['solid', 'inset']
|
||||
@ -162,7 +166,7 @@ define([
|
||||
|
||||
beforeEach(function () {
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({ model: model });
|
||||
view.render();
|
||||
});
|
||||
|
||||
@ -196,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: {
|
||||
@ -218,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () {
|
||||
@ -79,6 +79,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
footer: {
|
||||
@ -101,7 +102,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (FooterBlock.FooterBlockModel)();
|
||||
model = new (FooterBlock.FooterBlockModel)();
|
||||
|
||||
expect(model.get('text')).to.equal('some custom config text');
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#123456');
|
||||
@ -116,15 +117,16 @@ define([
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication);
|
||||
var model = new (FooterBlock.FooterBlockModel)(),
|
||||
view;
|
||||
model = new (FooterBlock.FooterBlockModel)();
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
view = new (FooterBlock.FooterBlockView)({model: model});
|
||||
view = new (FooterBlock.FooterBlockView)({ model: model });
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
@ -134,13 +136,15 @@ define([
|
||||
});
|
||||
|
||||
describe('settings view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
fonts: ['Arial', 'Tahoma'],
|
||||
textSizes: ['16px', '20px']
|
||||
});
|
||||
var model = new (FooterBlock.FooterBlockModel)(),
|
||||
view = new (FooterBlock.FooterBlockSettingsView)({model: model});
|
||||
model = new (FooterBlock.FooterBlockModel)();
|
||||
view = new (FooterBlock.FooterBlockSettingsView)({ model: model });
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
@ -148,16 +152,17 @@ define([
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
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();
|
||||
});
|
||||
|
||||
@ -188,7 +193,7 @@ define([
|
||||
expect(model.get('styles.link.textDecoration')).to.equal('underline');
|
||||
});
|
||||
|
||||
it('updates the model when background color changes', function () {
|
||||
it('updates the model when text alignment changes', function () {
|
||||
view.$('.mailpoet_field_footer_alignment').last().prop('checked', true).change();
|
||||
expect(model.get('styles.text.textAlign')).to.equal('right');
|
||||
});
|
||||
@ -198,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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)();
|
||||
@ -79,6 +79,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
header: {
|
||||
@ -101,7 +102,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (HeaderBlock.HeaderBlockModel)();
|
||||
model = new (HeaderBlock.HeaderBlockModel)();
|
||||
|
||||
expect(model.get('text')).to.equal('some custom config text');
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#123456');
|
||||
@ -115,15 +116,16 @@ define([
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication);
|
||||
var model = new (HeaderBlock.HeaderBlockModel)(),
|
||||
view;
|
||||
model = new (HeaderBlock.HeaderBlockModel)();
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
view = new (HeaderBlock.HeaderBlockView)({model: model});
|
||||
view = new (HeaderBlock.HeaderBlockView)({ model: model });
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
@ -133,14 +135,16 @@ define([
|
||||
});
|
||||
|
||||
describe('settings view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
fonts: ['Arial', 'Tahoma'],
|
||||
textSizes: ['16px', '20px']
|
||||
});
|
||||
var model = new (HeaderBlock.HeaderBlockModel)(),
|
||||
view = new (HeaderBlock.HeaderBlockSettingsView)({model: model});
|
||||
model = new (HeaderBlock.HeaderBlockModel)();
|
||||
view = new (HeaderBlock.HeaderBlockSettingsView)({ model: model });
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
@ -148,16 +152,17 @@ define([
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
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();
|
||||
});
|
||||
|
||||
@ -198,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () {
|
||||
@ -74,6 +74,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
image: {
|
||||
@ -91,7 +92,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (ImageBlock.ImageBlockModel)();
|
||||
model = new (ImageBlock.ImageBlockModel)();
|
||||
|
||||
expect(model.get('link')).to.equal('http://example.org/customConfigPage');
|
||||
expect(model.get('src')).to.equal('http://example.org/someCustomConfigImage.png');
|
||||
@ -104,14 +105,15 @@ define([
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication);
|
||||
var model = new (ImageBlock.ImageBlockModel)(),
|
||||
view;
|
||||
model = new (ImageBlock.ImageBlockModel)();
|
||||
|
||||
beforeEach(function () {
|
||||
view = new (ImageBlock.ImageBlockView)({model: model});
|
||||
view = new (ImageBlock.ImageBlockView)({ model: model });
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
@ -131,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();
|
||||
});
|
||||
|
||||
@ -158,7 +160,8 @@ define([
|
||||
});
|
||||
|
||||
describe('block settings view', function () {
|
||||
var model, view;
|
||||
var model;
|
||||
var view;
|
||||
var newWidth = 123;
|
||||
var newHeight = 456;
|
||||
var newLink = 'http://example.org/someNewLink';
|
||||
@ -171,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 () {
|
||||
@ -206,17 +209,21 @@ define([
|
||||
});
|
||||
|
||||
it('updates the model when padding changes', function () {
|
||||
var newValue = 'false';
|
||||
view.$('.mailpoet_field_image_full_width').prop('checked', false).change();
|
||||
expect(model.get('fullWidth')).to.equal(false);
|
||||
});
|
||||
|
||||
it.skip('closes the sidepanel after "Done" is clicked', function() {
|
||||
it('updates the model when alignment changes', function () {
|
||||
view.$('.mailpoet_field_image_alignment').first().prop('checked', true).change();
|
||||
expect(model.get('styles.block.textAlign')).to.equal('left');
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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;
|
||||
};
|
||||
@ -132,6 +132,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
posts: {
|
||||
@ -179,7 +180,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (PostsBlock.PostsBlockModel)();
|
||||
model = new (PostsBlock.PostsBlockModel)();
|
||||
|
||||
expect(model.get('amount')).to.equal('17');
|
||||
expect(model.get('contentType')).to.equal('mailpoet_page');
|
||||
@ -237,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;
|
||||
@ -261,14 +262,15 @@ define([
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model, view;
|
||||
var model;
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
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');
|
||||
@ -285,10 +287,11 @@ define([
|
||||
});
|
||||
|
||||
describe('block settings view', function () {
|
||||
var model, view;
|
||||
var model;
|
||||
var view;
|
||||
|
||||
before(function () {
|
||||
CommunicationComponent.getPostTypes = function() {
|
||||
CommunicationComponent.getPostTypes = function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve([
|
||||
{
|
||||
@ -319,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();
|
||||
});
|
||||
@ -420,12 +423,13 @@ define([
|
||||
expect(model.get('readMoreText')).to.equal(newValue);
|
||||
});
|
||||
|
||||
describe('when "title only" display type is selected', function() {
|
||||
var model, view;
|
||||
beforeEach(function() {
|
||||
describe('when "title only" display type is selected', function () {
|
||||
var model;
|
||||
var view;
|
||||
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();
|
||||
});
|
||||
@ -434,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();
|
||||
});
|
||||
@ -445,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();
|
||||
});
|
||||
|
@ -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 () {
|
||||
@ -29,6 +29,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
social: {
|
||||
@ -36,7 +37,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (SocialBlock.SocialBlockModel)();
|
||||
model = new (SocialBlock.SocialBlockModel)();
|
||||
|
||||
expect(model.get('iconSet')).to.equal('customConfigIconSet');
|
||||
});
|
||||
@ -124,13 +125,14 @@ 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);
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
var model;
|
||||
var view;
|
||||
|
||||
before(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
@ -154,7 +156,7 @@ define([
|
||||
}
|
||||
]
|
||||
});
|
||||
view = new (SocialBlock.SocialBlockView)({model: model});
|
||||
view = new (SocialBlock.SocialBlockView)({ model: model });
|
||||
view.render();
|
||||
});
|
||||
|
||||
@ -210,12 +212,13 @@ define([
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
var view = new (SocialBlock.SocialBlockSettingsView)({model: model});
|
||||
var view = new (SocialBlock.SocialBlockSettingsView)({ model: model });
|
||||
expect(view.render).to.not.throw();
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
var model;
|
||||
var view;
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
@ -250,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);
|
||||
});
|
||||
@ -275,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () {
|
||||
@ -55,6 +55,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
spacer: {
|
||||
@ -67,7 +68,7 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (SpacerBlock.SpacerBlockModel)();
|
||||
model = new (SpacerBlock.SpacerBlockModel)();
|
||||
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#567890');
|
||||
expect(model.get('styles.block.height')).to.equal('19px');
|
||||
@ -83,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 () {
|
||||
@ -119,15 +120,16 @@ define([
|
||||
});
|
||||
|
||||
describe('settings view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
|
||||
var model = new (SpacerBlock.SpacerBlockModel)(),
|
||||
view;
|
||||
model = new (SpacerBlock.SpacerBlockModel)();
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
view = new (SpacerBlock.SpacerBlockSettingsView)({model: model});
|
||||
view = new (SpacerBlock.SpacerBlockSettingsView)({ model: model });
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
@ -135,12 +137,13 @@ define([
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var view, model;
|
||||
beforeEach(function() {
|
||||
var view;
|
||||
var model;
|
||||
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();
|
||||
});
|
||||
|
||||
@ -154,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () {
|
||||
@ -23,6 +23,7 @@ define([
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
var model;
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
text: {
|
||||
@ -30,16 +31,18 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (TextBlock.TextBlockModel)();
|
||||
model = new (TextBlock.TextBlockModel)();
|
||||
|
||||
expect(model.get('text')).to.equal('some custom config text');
|
||||
});
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model;
|
||||
var view;
|
||||
global.stubConfig(EditorApplication);
|
||||
var model = new (TextBlock.TextBlockModel)(),
|
||||
view = new (TextBlock.TextBlockView)({model: model});
|
||||
model = new (TextBlock.TextBlockModel)();
|
||||
view = new (TextBlock.TextBlockView)({ model: model });
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
@ -47,12 +50,12 @@ define([
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model = new (TextBlock.TextBlockModel)(),
|
||||
view;
|
||||
var model = new (TextBlock.TextBlockModel)();
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubConfig(EditorApplication);
|
||||
view = new (TextBlock.TextBlockView)({model: model});
|
||||
view = new (TextBlock.TextBlockView)({ model: model });
|
||||
view.render();
|
||||
});
|
||||
|
||||
|
@ -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,21 +26,21 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
module.getPostTypes().done(function(types) {
|
||||
module.getPostTypes().done(function (types) {
|
||||
expect(types).to.eql(['val1', 'val2']);
|
||||
});
|
||||
});
|
||||
|
||||
it('caches results', function() {
|
||||
var deferred = jQuery.Deferred(),
|
||||
mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred),
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
it('caches results', function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
|
||||
var module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
deferred.resolve({
|
||||
post: 'val1',
|
||||
page: 'val2'
|
||||
@ -52,18 +52,18 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTaxonomies', function() {
|
||||
it('sends post type to endpoint', function() {
|
||||
var spy,
|
||||
post = function(params) {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve({
|
||||
category: 'val1',
|
||||
post_tag: 'val2'
|
||||
});
|
||||
return deferred;
|
||||
},
|
||||
module;
|
||||
describe('getTaxonomies', function () {
|
||||
it('sends post type to endpoint', function () {
|
||||
var spy;
|
||||
var post = function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve({
|
||||
category: 'val1',
|
||||
post_tag: 'val2'
|
||||
});
|
||||
return deferred;
|
||||
};
|
||||
var module;
|
||||
spy = sinon.spy(post);
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
@ -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,21 +93,21 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
module.getTaxonomies('page').done(function(types) {
|
||||
module.getTaxonomies('page').done(function (types) {
|
||||
expect(types).to.eql({ category: 'val1' });
|
||||
});
|
||||
});
|
||||
|
||||
it('caches results', function() {
|
||||
var deferred = jQuery.Deferred(),
|
||||
mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred),
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
it('caches results', function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
|
||||
var module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
deferred.resolve({ category: 'val1' });
|
||||
module.getTaxonomies('page');
|
||||
module.getTaxonomies('page');
|
||||
@ -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(params) {
|
||||
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,21 +157,21 @@ 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() {
|
||||
var deferred = jQuery.Deferred(),
|
||||
mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred),
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
it('caches results', function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
|
||||
var module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
deferred.resolve({ term1: 'term1val1', term2: 'term2val2' });
|
||||
module.getTerms({ taxonomies: ['category'] });
|
||||
module.getTerms({ taxonomies: ['category'] });
|
||||
@ -180,15 +180,15 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPosts', function() {
|
||||
it('sends options to endpoint', function() {
|
||||
var spy,
|
||||
post = function(params) {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve({});
|
||||
return deferred;
|
||||
},
|
||||
module;
|
||||
describe('getPosts', function () {
|
||||
it('sends options to endpoint', function () {
|
||||
var spy;
|
||||
var post = function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve({});
|
||||
return deferred;
|
||||
};
|
||||
var module;
|
||||
spy = sinon.spy(post);
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
@ -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,21 +225,21 @@ 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() {
|
||||
var deferred = jQuery.Deferred(),
|
||||
mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred),
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
it('caches results', function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
|
||||
var module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
deferred.resolve({
|
||||
type: 'posts',
|
||||
search: 'some search term'
|
||||
@ -251,15 +251,15 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTransformedPosts', function() {
|
||||
it('sends options to endpoint', function() {
|
||||
var spy,
|
||||
post = function(params) {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve({});
|
||||
return deferred;
|
||||
},
|
||||
module;
|
||||
describe('getTransformedPosts', function () {
|
||||
it('sends options to endpoint', function () {
|
||||
var spy;
|
||||
var post = function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve({});
|
||||
return deferred;
|
||||
};
|
||||
var module;
|
||||
spy = sinon.spy(post);
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
@ -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,21 +296,21 @@ 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() {
|
||||
var deferred = jQuery.Deferred(),
|
||||
mock = sinon.mock({ post: function() {} }).expects('post').once().returns(deferred),
|
||||
module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
it('caches results', function () {
|
||||
var deferred = jQuery.Deferred();
|
||||
var mock = sinon.mock({ post: function () {} }).expects('post').once().returns(deferred);
|
||||
var module = CommunicationInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
post: mock
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
deferred.resolve({
|
||||
type: 'posts',
|
||||
posts: [1, 3]
|
||||
|
@ -3,14 +3,15 @@ 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'
|
||||
});
|
||||
var model = ConfigComponent.getConfig();
|
||||
model = ConfigComponent.getConfig();
|
||||
expect(model.get('testConfig')).to.equal('testValue');
|
||||
});
|
||||
});
|
||||
|
@ -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,10 +63,10 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('block types', function() {
|
||||
it('registers a block type view and model', function() {
|
||||
var blockModel = new Backbone.SuperModel(),
|
||||
blockView = new Backbone.View();
|
||||
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', {
|
||||
blockModel: blockModel,
|
||||
blockView: blockView
|
||||
@ -76,35 +76,38 @@ 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'
|
||||
}, stylesField = {
|
||||
globalStylesField: 'globalStylesValue'
|
||||
}, newsletterFields = {
|
||||
subject: 'test newsletter subject'
|
||||
};
|
||||
containerModelField: 'containerModelValue'
|
||||
};
|
||||
var stylesField = {
|
||||
globalStylesField: 'globalStylesValue'
|
||||
};
|
||||
var newsletterFields = {
|
||||
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;
|
||||
}
|
||||
};
|
||||
};
|
||||
var json = ContentComponent.toJSON();
|
||||
json = ContentComponent.toJSON();
|
||||
expect(json).to.deep.equal(_.extend({
|
||||
body: {
|
||||
content: dataField,
|
||||
|
@ -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,13 +18,14 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
it('renders', function() {
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
});
|
||||
|
||||
describe('once rendered', function() {
|
||||
var view, model;
|
||||
beforeEach(function() {
|
||||
describe('once rendered', function () {
|
||||
var view;
|
||||
var model;
|
||||
beforeEach(function () {
|
||||
model = new Backbone.SuperModel({
|
||||
subject: 'a test subject',
|
||||
preheader: 'a test preheader'
|
||||
@ -35,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');
|
||||
});
|
||||
|
@ -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,9 +37,10 @@ define([
|
||||
expect(spy).to.have.been.calledWith('beforeEditorSave');
|
||||
});
|
||||
|
||||
it('triggers afterEditorSave event', function() {
|
||||
var spy = sinon.spy(),
|
||||
promise = jQuery.Deferred();
|
||||
it('triggers afterEditorSave event', function () {
|
||||
var module;
|
||||
var spy = sinon.spy();
|
||||
var promise = jQuery.Deferred();
|
||||
global.stubChannel(EditorApplication, {
|
||||
trigger: spy
|
||||
});
|
||||
@ -48,7 +49,7 @@ define([
|
||||
type: 'container'
|
||||
}
|
||||
});
|
||||
var module = SaveInjector({
|
||||
module = SaveInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
saveNewsletter: sinon.stub().returns(promise)
|
||||
}
|
||||
@ -58,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': {
|
||||
@ -73,20 +74,21 @@ define([
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('encodes newsletter body in JSON format', function() {
|
||||
var body = {type: 'testType'},
|
||||
mock = sinon.mock()
|
||||
.once()
|
||||
.withArgs({
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
.returns(jQuery.Deferred());
|
||||
it('encodes newsletter body in JSON format', function () {
|
||||
var module;
|
||||
var body = { type: 'testType' };
|
||||
var mock = sinon.mock()
|
||||
.once()
|
||||
.withArgs({
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
.returns(jQuery.Deferred());
|
||||
global.stubChannel(EditorApplication);
|
||||
|
||||
EditorApplication.toJSON = sinon.stub().returns({
|
||||
body: body
|
||||
});
|
||||
var module = SaveInjector({
|
||||
module = SaveInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
saveNewsletter: mock
|
||||
}
|
||||
@ -98,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
|
||||
});
|
||||
@ -128,42 +130,44 @@ 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()),
|
||||
html2canvasMock = 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();
|
||||
var module = SaveInjector({
|
||||
module = SaveInjector({
|
||||
mailpoet: {
|
||||
Ajax: {
|
||||
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; }
|
||||
};
|
||||
}
|
||||
});
|
||||
var view = new (module.SaveView)();
|
||||
view = new (module.SaveView)();
|
||||
view.render();
|
||||
|
||||
view.$('.mailpoet_save_as_template_name').val('A sample template');
|
||||
@ -173,19 +177,20 @@ define([
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('saves newsletter when clicked on "next" button', function() {
|
||||
var spy = sinon.spy(),
|
||||
module = SaveInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
saveNewsletter: function() {
|
||||
return jQuery.Deferred();
|
||||
}
|
||||
it('saves newsletter when clicked on "next" button', function () {
|
||||
var spy = sinon.spy();
|
||||
var view;
|
||||
var module = SaveInjector({
|
||||
'newsletter_editor/components/communication': {
|
||||
saveNewsletter: function () {
|
||||
return jQuery.Deferred();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
global.stubChannel(EditorApplication, {
|
||||
trigger: spy
|
||||
});
|
||||
var view = new (module.SaveView)();
|
||||
view = new (module.SaveView)();
|
||||
view.render();
|
||||
|
||||
view.$('.mailpoet_save_next').click();
|
||||
|
@ -4,51 +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() {
|
||||
var model, availableStyles, view;
|
||||
before(function() {
|
||||
describe('once rendered', function () {
|
||||
var model;
|
||||
var availableStyles;
|
||||
var view;
|
||||
before(function () {
|
||||
model = new Backbone.SuperModel({
|
||||
text: {
|
||||
fontColor: '#000000',
|
||||
@ -94,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();
|
||||
});
|
||||
});
|
||||
|
@ -4,27 +4,28 @@ 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'
|
||||
});
|
||||
var model = StylesComponent.getGlobalStyles();
|
||||
model = StylesComponent.getGlobalStyles();
|
||||
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
|
||||
};
|
||||
@ -34,14 +35,15 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('view', function() {
|
||||
var model, view;
|
||||
beforeEach(function() {
|
||||
describe('view', function () {
|
||||
var model;
|
||||
var view;
|
||||
beforeEach(function () {
|
||||
model = new (StylesComponent.StylesModel)();
|
||||
view = new (StylesComponent.StylesView)({ model: model });
|
||||
});
|
||||
|
||||
it('renders', function() {
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
});
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -133,6 +133,29 @@ class RendererTest extends \MailPoetTest {
|
||||
expect($DOM('tr > td > img', 0)->attr('style'))->notEmpty();
|
||||
}
|
||||
|
||||
function testItRendersAlignedImage() {
|
||||
$newsletter = $this->newsletter['body'];
|
||||
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][1];
|
||||
// default alignment (center)
|
||||
unset($template['styles']['block']['textAlign']);
|
||||
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 1));
|
||||
expect($DOM('tr > td', 0)->attr('align'))->equals('center');
|
||||
$template['styles']['block']['textAlign'] = 'center';
|
||||
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 1));
|
||||
expect($DOM('tr > td', 0)->attr('align'))->equals('center');
|
||||
$template['styles']['block']['textAlign'] = 'something odd';
|
||||
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 1));
|
||||
expect($DOM('tr > td', 0)->attr('align'))->equals('center');
|
||||
// left alignment
|
||||
$template['styles']['block']['textAlign'] = 'left';
|
||||
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 1));
|
||||
expect($DOM('tr > td', 0)->attr('align'))->equals('left');
|
||||
// right alignment
|
||||
$template['styles']['block']['textAlign'] = 'right';
|
||||
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 1));
|
||||
expect($DOM('tr > td', 0)->attr('align'))->equals('right');
|
||||
}
|
||||
|
||||
function testItDoesNotRenderImageWithoutSrc() {
|
||||
$image = array(
|
||||
'src' => '',
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
60
tests/unit/Subscription/ThrottlingTest.php
Normal file
60
tests/unit/Subscription/ThrottlingTest.php
Normal 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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="mailpoet_tools"></div>
|
||||
<div class="mailpoet_content" style="text-align: {{ model.styles.block.textAlign }}; width: {{model.width}}">
|
||||
<div class="mailpoet_content" style="{{#ifCond model.styles.block.textAlign '==' 'left'}}margin: 0 auto 0 0; {{/ifCond}}{{#ifCond model.styles.block.textAlign '==' 'center'}}margin: auto; {{/ifCond}}{{#ifCond model.styles.block.textAlign '==' 'right'}}margin: 0 0 0 auto; {{/ifCond}}width: {{model.width}}">
|
||||
<div class="mailpoet_image">
|
||||
<a href="{{ model.link }}" onClick="return false;">
|
||||
<img src="{{#ifCond model.src '!=' ''}}{{ model.src }}{{ else }}{{ imageMissingSrc }}{{/ifCond}}" alt="{{ model.alt }}" onerror="if(this.src != '{{ imageMissingSrc }}') {this.src = '{{ imageMissingSrc }}'; this.style.width='auto';}" width="{{model.width}}" />
|
||||
|
@ -27,23 +27,23 @@
|
||||
<label>
|
||||
<div class="mailpoet_form_field_title"><%= __('Width') %></div>
|
||||
<div class="mailpoet_form_field_input_option">
|
||||
<input
|
||||
<input
|
||||
class="mailpoet_input mailpoet_input_small mailpoet_field_image_width_input"
|
||||
name="image-width-input"
|
||||
type="number"
|
||||
value="{{getNumber model.width}}"
|
||||
name="image-width-input"
|
||||
type="number"
|
||||
value="{{getNumber model.width}}"
|
||||
min="36"
|
||||
max="660"
|
||||
step="2"
|
||||
step="2"
|
||||
/> px
|
||||
<input
|
||||
class="mailpoet_range mailpoet_range_small mailpoet_field_image_width"
|
||||
name="image-width"
|
||||
type="range"
|
||||
value="{{getNumber model.width}}"
|
||||
<input
|
||||
class="mailpoet_range mailpoet_range_small mailpoet_field_image_width"
|
||||
name="image-width"
|
||||
type="range"
|
||||
value="{{getNumber model.width}}"
|
||||
min="36"
|
||||
max="660"
|
||||
step="2"
|
||||
step="2"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
@ -57,6 +57,27 @@
|
||||
<span id="tooltip-designer-full-width" class="tooltip-help-designer-full-width"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mailpoet_form_field">
|
||||
<div class="mailpoet_form_field_title"><%= __('Alignment') %></div>
|
||||
<div class="mailpoet_form_field_radio_option">
|
||||
<label>
|
||||
<input type="radio" name="alignment" class="mailpoet_field_image_alignment" value="left" {{#ifCond model.styles.block.textAlign '===' 'left'}}CHECKED{{/ifCond}}/>
|
||||
<%= __('Left') %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="mailpoet_form_field_radio_option">
|
||||
<label>
|
||||
<input type="radio" name="alignment" class="mailpoet_field_image_alignment" value="center" {{#ifCond model.styles.block.textAlign '===' 'center'}}CHECKED{{/ifCond}}/>
|
||||
<%= __('Center') %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="mailpoet_form_field_radio_option">
|
||||
<label>
|
||||
<input type="radio" name="alignment" class="mailpoet_field_image_alignment" value="right" {{#ifCond model.styles.block.textAlign '===' 'right'}}CHECKED{{/ifCond}}/>
|
||||
<%= __('Right') %>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="mailpoet_form_field">
|
||||
<input type="button" name="select-another-image" class="button button-secondary mailpoet_button_full mailpoet_field_image_select_another_image" value="<%= __('Select another image') | escape('html_attr') %>" />
|
||||
|
@ -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'),
|
||||
|
@ -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>
|
||||
|
Reference in New Issue
Block a user