Compare commits

...

24 Commits
0.0.2 ... 0.0.3

Author SHA1 Message Date
0199e2c7e1 Version bump: 0.0.3 2015-11-06 21:49:28 +01:00
d1f407bf19 Merge branch 'master' of github.com:mailpoet/mailpoet 2015-11-06 21:47:49 +01:00
f18d2842b9 Version bump: 0.0.3. 2015-11-06 21:47:17 +01:00
f640cbb307 Merge pull request #203 from mailpoet/form_editor
Form editor
2015-11-06 21:39:03 +01:00
b20d92c9b1 fixed unit tests and added form model unit test 2015-11-06 18:43:56 +01:00
795485d42a fixed sortable segments in form editor 2015-11-06 16:09:56 +01:00
dfadda2d12 converted form renderer validation to Parsley 2015-11-06 16:09:56 +01:00
31305a04c0 form validation with Parsley 2015-11-06 16:09:56 +01:00
cfdb886e88 Date widget
- fixed date widget
- fixed default styles for radio inputs in form rendering
2015-11-06 16:09:09 +01:00
1ce4b16327 custom fields (create and update) 2015-11-06 16:09:09 +01:00
b12f7f29de Custom fields
- added listing of custom fields in form editor
- ability to delete a custom field
- mades changes to the form editor in order to accomodate for the new custom fields system
- fix form editor bugs
- cleanup
2015-11-06 16:09:09 +01:00
5473f94e24 List selection & subscribe
- fixed list selection widget (form editor & rendered form)
- ajax subscription works (minus sending the confirmation email)
- bug fixes / polishing / refactoring / cleanup
2015-11-06 16:09:09 +01:00
a31dce6226 fixed list selection widget + started form submission 2015-11-06 16:09:09 +01:00
d996b78561 fixed form_editor.js being ignored by git 2015-11-06 16:09:09 +01:00
c2e7513381 Form editor
- new form with default data
- load/save in form editor
- widgets -> settings form
- widgets -> shortcode for subscribers count
- widgets -> form rendering
- added useful filters to Subscribers (for status related search)
- refactor & cleanup
2015-11-06 16:09:09 +01:00
541696863e Form editor
- new/edit in forms listing goes to editor
- fixed editor dependencies (via Webpack)
- updated forms table schema
- saving/loading a form works
2015-11-06 16:09:09 +01:00
6c8d2be18c fix for selection field jsx 2015-11-06 16:08:16 +01:00
907fe585de add Form renderer and fixed Newsletter saving issue 2015-11-06 16:08:16 +01:00
e24f8c9653 forms listing complete 2015-11-06 16:08:16 +01:00
5df0475b1a Merge pull request #204 from mailpoet/newsletter_templates
Newsletter template import/export
2015-11-06 12:23:27 +01:00
cf154455e3 Add error reporting for newsletter template export fields 2015-11-05 19:11:32 +02:00
dcfe6357cf Switch to FileSaver lib for downloading Blob files, add Blob polyfill 2015-11-05 17:17:54 +02:00
983df216f3 Add basic template export 2015-11-04 18:02:55 +02:00
f750d2359f Base for template import 2015-11-03 16:33:13 +02:00
78 changed files with 3981 additions and 2140 deletions

View File

@ -91,7 +91,7 @@ class RoboFile extends \Robo\Tasks {
function testUnit($file = null) {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$this->_exec('vendor/bin/codecept run unit '.(($file) ? $file : ''));
$this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : ''));
}
function testJavascript() {
@ -113,7 +113,6 @@ class RoboFile extends \Robo\Tasks {
function testFailed() {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$this->startPhantomJS();
$this->_exec('vendor/bin/codecept run -g failed');
}

View File

@ -5,7 +5,7 @@
@require 'common'
@require 'modal'
@require 'notice'
@require 'validation_engine'
@require 'parsley'
@require 'form_editor'
@require 'listing'

View File

@ -1,3 +1,6 @@
@require 'codemirror/lib/codemirror.css'
@require 'codemirror/theme/neo.css'
icons = '../img/form_editor_icons.png'
handle_icon = '../img/handle.png'

View File

@ -45,7 +45,8 @@
&::before
content: '\f140'
.mailpoet_save_as_template_container
.mailpoet_save_as_template_container,
.mailpoet_export_template_container
border-radius(3px)
float: left
clear: both
@ -55,7 +56,8 @@
background-color: $white-color
border: 1px solid $structure-border-color
.mailpoet_save_as_template_title
.mailpoet_save_as_template_title,
.mailpoet_export_template_title
font-size: 1.1em
.mailpoet_editor_last_saved

View File

@ -0,0 +1,27 @@
input.parsley-success,
select.parsley-success,
textarea.parsley-success
color #468847
background-color #DFF0D8
border 1px solid #D6E9C6
input.parsley-error,
select.parsley-error,
textarea.parsley-error
color #B94A48
background-color #F2DEDE
border 1px solid #EED3D7
.parsley-errors-list
margin 2px 0 3px
padding 0
list-style-type none
font-size 0.9em
line-height 0.9em
opacity 0
transition all .3s ease-in
-o-transition all .3s ease-in
-moz-transition all .3s ease-in
-webkit-transition all .3s ease-in
&.filled
opacity 1

View File

@ -0,0 +1,3 @@
@import 'nib'
@require 'parsley'

View File

@ -1,141 +0,0 @@
lesscss-percentage(n)
(n * 100)%
popupBg = rgb(0, 87, 154, 1)
popupTextColor = rgb(255, 255, 255, 1)
borderColor = rgb(255, 255, 255, 1)
borderWidth = 1px
popupFontSize = 12px
popupRadius = 0
popupShadowWidth = 2px
popupShadowColor = rgb(51, 51, 51, 1)
/* Z-INDEX */
.formError
z-index 990
.formError .formErrorContent
z-index 991
.formError .formErrorArrow
z-index 996
.ui-dialog .formError
z-index 5000
.ui-dialog .formError .formErrorContent
z-index 5001
.ui-dialog .formError .formErrorArrow
z-index 5006
.inputContainer
position relative
float left
.formError
position absolute
top 300px
left 300px
display block
cursor pointer
text-align left
.formError.inline
position relative
top 0
left 0
display inline-block
.ajaxSubmit
padding 20px
background #55ea55
border 1px solid #999
display none
.formError .formErrorContent
width 100%
background popupBg
position relative
color popupTextColor
min-width 120px
font-size popupFontSize
border borderWidth solid borderColor
box-shadow 0 0 popupShadowWidth popupShadowColor
-moz-box-shadow 0 0 popupShadowWidth popupShadowColor
-webkit-box-shadow 0 0 popupShadowWidth popupShadowColor
-o-box-shadow 0 0 popupShadowWidth popupShadowColor
padding 4px 10px 4px 10px
border-radius popupRadius
-moz-border-radius popupRadius
-webkit-border-radius popupRadius
-o-border-radius popupRadius
.formError.inline .formErrorContent
box-shadow none
-moz-box-shadow none
-webkit-box-shadow none
-o-box-shadow none
border none
border-radius 0
-moz-border-radius 0
-webkit-border-radius 0
-o-border-radius 0
.greenPopup .formErrorContent
background #33be40
.blackPopup .formErrorContent
background #393939
color #FFF
.formError .formErrorArrow
width 15px
margin -2px 0 0 13px
position relative
body[dir='rtl'] .formError .formErrorArrow, body.rtl .formError .formErrorArrow
margin -2px 13px 0 0
.formError .formErrorArrowBottom
box-shadow none
-moz-box-shadow none
-webkit-box-shadow none
-o-box-shadow none
margin 0px 0 0 12px
top 2px
.formError .formErrorArrow div
border-left borderWidth solid borderColor
border-right borderWidth solid borderColor
box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
-moz-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
-webkit-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
-o-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
font-size 0px
height 1px
background popupBg
margin 0 auto
line-height 0
font-size 0
display block
.formError .formErrorArrowBottom div
box-shadow none
-moz-box-shadow none
-webkit-box-shadow none
-o-box-shadow none
.greenPopup .formErrorArrow div
background #33be40
.blackPopup .formErrorArrow div
background #393939
color #FFF
.formError .formErrorArrow .line10
width 13px
border none
.formError .formErrorArrow .line9
width 11px
border none
.formError .formErrorArrow .line8
width 11px
.formError .formErrorArrow .line7
width 9px
.formError .formErrorArrow .line6
width 7px
.formError .formErrorArrow .line5
width 5px
.formError .formErrorArrow .line4
width 3px
.formError .formErrorArrow .line3
width ceil((borderWidth / 2))
border-left borderWidth solid borderColor
border-right borderWidth solid borderColor
border-bottom 0 solid borderColor
.formError .formErrorArrow .line2
width 3px
border none
background borderColor
.formError .formErrorArrow .line1
width 1px
border none
background borderColor

4
assets/js/lib/prototype.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
assets/js/lib/scriptaculous.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,12 @@
define([
'react',
'react-dom',
'jquery',
'select2'
],
function(
React,
ReactDOM,
jQuery
) {
var Selection = React.createClass({
@ -16,36 +18,38 @@ function(
},
componentDidMount: function() {
this.loadCachedItems();
this.setupSelect2();
},
componentDidUpdate: function() {
this.setupSelect2();
},
setupSelect2: function() {
if(this.state.initialized === true) {
if(
!this.props.field.multiple
|| this.state.initialized === true
|| this.refs.select === undefined
) {
return;
}
if(this.props.field.select2 && Object.keys(this.props.item).length > 0) {
var select2 = jQuery('#'+this.props.field.id).select2({
width: (this.props.width || ''),
templateResult: function(item) {
if (item.element && item.element.selected) {
return null;
} else {
return item.text;
}
var select2 = jQuery('#'+this.refs.select.id).select2({
width: (this.props.width || ''),
templateResult: function(item) {
if(item.element && item.element.selected) {
return null;
} else {
return item.text;
}
});
}
});
select2.on('change', this.handleChange)
select2.on('change', this.handleChange);
select2.select2(
'val',
this.props.item[this.props.field.name]
);
select2.select2(
'val',
this.props.item[this.props.field.name]
);
this.setState({ initialized: true });
}
this.setState({ initialized: true });
},
loadCachedItems: function() {
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
@ -55,11 +59,16 @@ function(
});
}
},
handleChange: function() {
handleChange: function(e) {
if(this.props.onValueChange !== undefined) {
if(this.props.field.multiple) {
value = jQuery('#'+this.refs.select.id).select2('val');
} else {
value = e.target.value;
}
this.props.onValueChange({
target: {
value: jQuery('#'+this.props.field.id).select2('val'),
value: value,
name: this.props.field.name
}
});
@ -89,7 +98,8 @@ function(
return (
<select
id={ this.props.field.id }
id={ this.props.field.id || this.props.field.name }
ref="select"
placeholder={ this.props.field.placeholder }
multiple={ this.props.field.multiple }
onChange={ this.handleChange }

View File

@ -1,993 +0,0 @@
/*
* name: MailPoet Form Editor
* author: Jonathan Labreuille
* company: Wysija
* framework: prototype 1.7.2
*/
'use strict';
Event.cacheDelegated = {};
Object.extend(document, (function () {
var cache = Event.cacheDelegated;
function getCacheForSelector(selector) {
return cache[selector] = cache[selector] || {};
}
function getWrappersForSelector(selector, eventName) {
var c = getCacheForSelector(selector);
return c[eventName] = c[eventName] || [];
}
function findWrapper(selector, eventName, handler) {
var c = getWrappersForSelector(selector, eventName);
return c.find(function (wrapper) {
return wrapper.handler === handler
});
}
function destroyWrapper(selector, eventName, handler) {
var c = getCacheForSelector(selector);
if (!c[eventName]) return false;
var 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);
if (c.pluck('handler').include(handler)) return false;
wrapper = function (event) {
var element = event.findElement(selector);
if (element) handler.call(context || element, event, element);
};
wrapper.handler = handler;
c.push(wrapper);
return wrapper;
}
return {
delegate: function (selector, eventName, handler, context) {
var wrapper = createWrapper.apply(null, arguments);
if (wrapper) document.observe(eventName, wrapper);
return document;
},
stopDelegating: function (selector, eventName, handler) {
var length = arguments.length;
switch (length) {
case 2:
getWrappersForSelector(selector, eventName).each(function (wrapper) {
document.stopDelegating(selector, eventName, wrapper.handler);
});
break;
case 1:
Object.keys(getCacheForSelector(selector)).each(function (eventName) {
document.stopDelegating(selector, eventName);
});
break;
case 0:
Object.keys(cache).each(function (selector) {
document.stopDelegating(selector);
});
break;
default:
var wrapper = destroyWrapper.apply(null, arguments);
if (wrapper) document.stopObserving(eventName, wrapper);
}
return document;
}
}
})());
var Observable = (function () {
function getEventName(name, namespace) {
name = name.substring(2);
if (namespace) name = namespace + ':' + name;
return name.underscore().split('_').join(':');
}
function getHandlers(klass) {
var proto = klass.prototype,
namespace = proto.namespace;
return Object.keys(proto).grep(/^on/).inject($H(), function (handlers, name) {
if (name === 'onDomLoaded') return handlers;
handlers.set(getEventName(name, namespace), getWrapper(proto[name], klass));
return handlers;
});
}
function getWrapper(handler, klass) {
return function (event) {
return handler.call(new klass(this), event, event.memo);
}
}
function onDomLoad(selector, klass) {
$$(selector).each(function (element) {
new klass(element).onDomLoaded();
});
}
return {
observe: function (selector) {
if (!this.handlers) this.handlers = {};
if (this.handlers[selector]) return;
var klass = this;
if (this.prototype.onDomLoaded) document.loaded ? onDomLoad(selector, klass) : document.observe('dom:loaded', onDomLoad.curry(selector, klass));
this.handlers[selector] = getHandlers(klass).each(function (handler) {
document.delegate(selector, handler.key, handler.value);
});
},
stopObserving: function (selector) {
if (!this.handlers || !this.handlers[selector]) return;
this.handlers[selector].each(function (handler) {
document.stopDelegating(selector, handler.key, handler.value);
});
delete this.handlers[selector];
}
}
})();
// override droppables
Object.extend(Droppables, {
deactivate: Droppables.deactivate.wrap(function (proceed, drop, draggable) {
if (drop.onLeave) drop.onLeave(draggable, drop.element);
return proceed(drop);
}),
activate: Droppables.activate.wrap(function (proceed, drop, draggable) {
if (drop.onEnter) drop.onEnter(draggable, drop.element);
return proceed(drop);
}),
show: function (point, element) {
if (!this.drops.length) return;
var drop, affected = [];
this.drops.each(function (drop) {
if (Droppables.isAffected(point, element, drop)) affected.push(drop);
});
if (affected.length > 0) drop = Droppables.findDeepestChild(affected);
if (this.last_active && this.last_active !== drop) this.deactivate(this.last_active, element);
if (drop) {
Position.within(drop.element, point[0], point[1]);
if (drop.onHover) drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
if (drop !== this.last_active) Droppables.activate(drop, element);
}
},
displayArea: function(draggable) {
if(!this.drops.length) return;
// hide controls when displaying drop areas.
WysijaForm.hideBlockControls();
this.drops.each(function (drop, iterator) {
if(drop.element.hasClassName('block_placeholder')) {
drop.element.addClassName('active');
}
});
},
hideArea: function() {
if (!this.drops.length) return;
this.drops.each(function (drop, iterator) {
if(drop.element.hasClassName('block_placeholder')) {
drop.element.removeClassName('active');
} else if(drop.element.hasClassName('image_placeholder')) {
drop.element.removeClassName('active');
drop.element.up().removeClassName('active');
} else if(drop.element.hasClassName('text_placeholder')) {
drop.element.removeClassName('active');
}
});
},
reset: function (draggable) {
if (this.last_active) this.deactivate(this.last_active, draggable);
}
});
/*
Wysija History handling
POTENTIAL FEATURES:
- set a maximum number of items to be stored
*/
var WysijaHistory = {
container: 'mailpoet_form_history',
size: 30,
enqueue: function(element) {
// create deep clone (includes child elements) of passed element
var clone = element.clone(true);
// check if the field is unique
if(parseInt(clone.readAttribute('wysija_unique'), 10) === 1) {
// check if the field is already in the queue
$(WysijaHistory.container).select('[wysija_field="'+clone.readAttribute('wysija_field')+'"]').invoke('remove');
}
// check history size
if($(WysijaHistory.container).select('> div').length >= WysijaHistory.size) {
// remove oldest element (last in the list)
$(WysijaHistory.container).select('> div').last().remove();
}
// store block in history
$(WysijaHistory.container).insert({ top: clone });
},
dequeue: function() {
// pop last block off the history
var block = $(WysijaHistory.container).select('div').first();
if(block !== undefined) {
// insert block back into the editor
$(WysijaForm.options.body).insert({top: block});
}
},
clear: function() {
$(WysijaHistory.container).innerHTML = '';
},
remove: function(field) {
$(WysijaHistory.container).select('[wysija_field="'+field+'"]').invoke('remove');
}
};
/* MailPoet Form */
var WysijaForm = {
version: '0.6',
options: {
container: 'mailpoet_form_container',
editor: 'mailpoet_form_editor',
body: 'mailpoet_form_body',
toolbar: 'mailpoet_form_toolbar',
templates: 'wysija_widget_templates',
debug: false
},
toolbar: {
effect: null,
x: null,
y: null,
top: null,
left: null
},
scroll: {
top: 0,
left: 0
},
flags: {
doSave: false
},
locks: {
dragging: false,
selectingColor: false,
showingTools: false
},
encodeHtmlValue: function(str) {
return str.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
// ": fix for FileMerge because the previous line fucks up its syntax coloring
},
decodeHtmlValue: function(str) {
return str.replace(/&amp;/g, '&').replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&quot;/g, '"');
// ": fix for FileMerge because the previous line fucks up its syntax coloring
},
loading: function(is_loading) {
if(is_loading) {
$(WysijaForm.options.editor).addClassName('loading');
$(WysijaForm.options.toolbar).addClassName('loading');
} else {
$(WysijaForm.options.editor).removeClassName('loading');
$(WysijaForm.options.toolbar).removeClassName('loading');
}
},
loadStatic: function(blocks) {
$A(blocks).each(function(block) {
// create block
WysijaForm.Block.create(block, $('block_placeholder'));
});
},
load: function(form) {
if(form.data === undefined) return;
// load body
if(form.data.body !== undefined) {
$A(form.data.body).each(function(block) {
// create block
WysijaForm.Block.create(block, $('block_placeholder'));
});
// load settings
var settings_elements = $('mailpoet_form_settings').getElements();
settings_elements.each(function(setting) {
// skip lists
if(setting.name === 'lists') {
return true;
} else if(setting.name === 'on_success') {
// if the input value is equal to the one stored in the settings
if(setting.value === form.data.settings[setting.name]) {
// check selected value
$(setting).checked = true;
}
} else if(form.data.settings[setting.name] !== undefined) {
if(typeof form.data.settings[setting.name] === 'string') {
setting.setValue(WysijaForm.decodeHtmlValue(form.data.settings[setting.name]));
} else {
setting.setValue(form.data.settings[setting.name]);
}
}
});
}
},
save: function() {
var position = 1,
data = {
'version': WysijaForm.version,
'settings': $('mailpoet_form_settings').serialize(true),
'body': [],
'styles': (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
};
// body
WysijaForm.getBlocks().each(function(b) {
var block_data = (typeof(b.block['save']) === 'function') ? b.block.save() : null;
if(block_data !== null) {
// set block position
block_data['position'] = position;
// increment position
position++;
// add block data to body
data['body'].push(block_data);
}
});
return data;
},
init: function() {
// set document scroll
info('init -> set scroll offsets');
WysijaForm.setScrollOffsets();
// position toolbar
info('init -> set toolbar position');
WysijaForm.setToolbarPosition();
// enable droppable targets
info('init -> make droppable');
WysijaForm.makeDroppable();
// enable sortable
info('init -> make sortable');
WysijaForm.makeSortable();
// hide controls
info('init -> hide controls');
WysijaForm.hideControls();
// hide settings
info('init -> hide settings');
WysijaForm.hideSettings();
// set settings buttons position
info('init -> init settings');
WysijaForm.setSettingsPosition();
// toggle widgets
info('init -> toggle widgets');
WysijaForm.toggleWidgets();
},
getFieldData: function(element) {
// get basic field data
var data = {
type: element.readAttribute('wysija_type'),
field: element.readAttribute('wysija_field'),
name: element.readAttribute('wysija_name'),
unique: parseInt(element.readAttribute('wysija_unique') || 0, 10),
static: parseInt(element.readAttribute('wysija_static') || 0, 10),
element: element,
params: ''
};
// get params (may be empty)
if(element.readAttribute('wysija_params') !== null && element.readAttribute('wysija_params').length > 0) {
data.params = JSON.parse(element.readAttribute('wysija_params'));
}
return data;
},
toggleWidgets: function() {
$$('a[wysija_unique="1"]').invoke('removeClassName', 'disabled');
// loop through each unique field already inserted in the editor and disable its toolbar equivalent
$$('#'+WysijaForm.options.editor+' [wysija_unique="1"]').each(function(element) {
var field = $$('#'+WysijaForm.options.toolbar+' [wysija_field="'+element.readAttribute('wysija_field')+'"]').first();
if(field !== undefined) {
field.addClassName('disabled');
}
});
// hide list selection if a list widget has been dragged into the editor
$('mailpoet_settings_list_selection')[(($$('#'+WysijaForm.options.editor+' [wysija_field="list"]').length > 0) === true) ? 'hide': 'show']();
},
setBlockPositions: function(event, target) {
// 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
if(container['block'] !== undefined) {
container.block.element.setStyle({zIndex: ''});
}
});
if(target !== undefined) {
// get placeholders (previous placeholder matches the placeholder linked to the next block)
var block_placeholder = $(target.element.readAttribute('wysija_placeholder')),
previous_placeholder = target.element.previous('.block_placeholder');
if(block_placeholder !== null) {
// put block placeholder before the current block
target.element.insert({before: block_placeholder});
// if the next block is a wysija_block, insert previous placeholder
if(target.element.next() !== undefined && target.element.next().hasClassName('mailpoet_form_block') && previous_placeholder !== undefined) {
target.element.insert({after: previous_placeholder});
}
}
}
},
setScrollOffsets: function() {
WysijaForm.scroll = document.viewport.getScrollOffsets();
},
hideSettings: function() {
$(WysijaForm.options.container).select('.wysija_settings').invoke('hide');
},
setSettingsPosition: function() {
// get viewport offsets and dimensions
var viewportHeight = document.viewport.getHeight(),
blockPadding = 5;
$(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)) ? true : false,
buttonMargin = 5,
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);
}
// set position for button
$(element).setStyle({
left: parseInt((parentDim.width / 2) - (element.getWidth() / 2)) + 'px',
top: relativeTop + 'px'
});
});
},
initToolbarPosition: function() {
if(WysijaForm.toolbar.top === null) WysijaForm.toolbar.top = parseInt($(WysijaForm.options.container).positionedOffset().top);
if(WysijaForm.toolbar.y === null) WysijaForm.toolbar.y = parseInt(WysijaForm.toolbar.top);
if(isRtl) {
if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = 0;
} else {
if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = parseInt($(WysijaForm.options.container).positionedOffset().left);
}
if(WysijaForm.toolbar.x === null) WysijaForm.toolbar.x = parseInt(WysijaForm.toolbar.left + $(WysijaForm.options.container).getDimensions().width + 15);
},
setToolbarPosition: function() {
WysijaForm.initToolbarPosition();
var position = { top: WysijaForm.toolbar.y + 'px', visibility: 'visible' };
if(isRtl) {
position.right = WysijaForm.toolbar.x + 'px';
} else {
position.left = WysijaForm.toolbar.x + 'px';
}
$(WysijaForm.options.toolbar).setStyle(position);
},
updateToolbarPosition: function() {
// init toolbar position (updates scroll and toolbar y)
WysijaForm.initToolbarPosition();
// cancel previous effect
if(WysijaForm.toolbar.effect !== null) WysijaForm.toolbar.effect.cancel();
if(WysijaForm.scroll.top >= (WysijaForm.toolbar.top - 20)) {
WysijaForm.toolbar.y = parseInt(20 + WysijaForm.scroll.top);
// start effect
WysijaForm.toolbar.effect = new Effect.Move(WysijaForm.options.toolbar, {
x: WysijaForm.toolbar.x,
y: WysijaForm.toolbar.y,
mode: 'absolute',
duration: 0.2
});
} else {
$(WysijaForm.options.toolbar).setStyle({
left: WysijaForm.toolbar.x + 'px',
top: WysijaForm.toolbar.top + 'px'
});
}
},
blockDropOptions: {
accept: $w('mailpoet_form_field'), // acceptable items (classes array)
onEnter: function (draggable, droppable) {
$(droppable).addClassName('hover');
},
onLeave: function (draggable, droppable) {
$(droppable).removeClassName('hover');
},
onDrop: function (draggable, droppable) {
// custom data for images
droppable.fire('wjfe:item:drop', WysijaForm.getFieldData(draggable));
$(droppable).removeClassName('hover');
}
},
hideControls: function() {
try {
return WysijaForm.getBlocks().invoke('hideControls');
} catch(e) { return; }
},
hideTools: function() {
$$('.wysija_tools').invoke('hide');
WysijaForm.locks.showingTools = false;
},
instances: {},
get: function (element, type) {
if(type === undefined) type = 'block';
// identify element
var id = element.identify();
var instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
WysijaForm.instances[id] = instance;
return instance;
},
makeDroppable: function() {
Droppables.add('block_placeholder', WysijaForm.blockDropOptions);
},
makeSortable: function () {
var body = $(WysijaForm.options.body);
Sortable.create(body, {
tag: 'div',
only: 'mailpoet_form_block',
scroll: window,
handle: 'handle',
constraint: 'vertical'
});
Draggables.removeObserver(body);
Draggables.addObserver({
element: body,
onStart: WysijaForm.startBlockPositions,
onEnd: WysijaForm.setBlockPositions
});
},
hideBlockControls: function() {
$$('.wysija_controls').invoke('hide');
this.getBlockElements().invoke('removeClassName', 'hover');
},
getBlocks: function () {
return WysijaForm.getBlockElements().map(function (element) {
return WysijaForm.get(element);
});
},
getBlockElements: function () {
return $(WysijaForm.options.container).select('.mailpoet_form_block');
},
startBlockPositions: function(event, target) {
if(target.element.hasClassName('mailpoet_form_block')) {
// store block placeholder id for the block that is being repositionned
if(target.element.previous('.block_placeholder') !== undefined) {
target.element.writeAttribute('wysija_placeholder', target.element.previous('.block_placeholder').identify());
}
}
WysijaForm.locks.dragging = true;
},
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);
if(protocol === null) {
// this is not a url so encode the whole thing
return encodeURIComponent(str).replace(/[!'()*]/g, escape);
} else if(protocol.length === 1) {
// this is a url, so do not encode the protocol
return encodeURI(str).replace(/[!'()*]/g, escape);
}
}
};
WysijaForm.DraggableItem = Class.create({
initialize: function (element) {
this.elementType = $(element).readAttribute('wysija_type');
this.element = $(element).down() || $(element);
this.clone = this.cloneElement();
this.insert();
},
STYLES: new 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
});
clone.setStyle(styles);
clone.addClassName('mailpoet_form_widget');
clone.addClassName(this.elementType);
clone.innerHTML = this.element.innerHTML;
return clone;
},
getOffset: function () {
return this.element.offsetTop - this.getList().scrollTop;
},
getList: function () {
return this.element.up('ul');
},
insert: function () {
$$("body")[0].insert(this.clone);
},
onMousedown: function (event) {
var draggable = new Draggable(this.clone, {
scroll: window,
onStart: function () {
Droppables.displayArea(draggable);
},
onEnd: function (drag) {
drag.destroy();
drag.element.remove();
Droppables.hideArea();
},
starteffect: function (element) {
new Effect.Opacity(element, {
duration: 0.2,
from: element.getOpacity(),
to: 0.7
});
},
endeffect: Prototype.emptyFunction
});
draggable.initDrag(event);
draggable.startDrag(event);
return draggable;
}
});
Object.extend(WysijaForm.DraggableItem, Observable).observe('a[class="mailpoet_form_field"]');
WysijaForm.Block = Class.create({
/* Invoked on load */
initialize: function(element) {
info('block -> init');
this.element = $(element);
this.block = new WysijaForm.Widget(this.element);
// enable block placeholder
this.block.makeBlockDroppable();
// setup events
if(this.block['setup'] !== undefined) {
this.block.setup();
}
return this;
},
setPosition: function(position) {
this.element.writeAttribute('wysija_position', position);
},
hideControls: function() {
if(this['getControls']) {
this.element.removeClassName('hover');
this.getControls().hide();
}
},
showControls: function() {
if(this['getControls']) {
this.element.addClassName('hover');
try {
this.getControls().show();
} catch(e) {
;
}
}
},
makeBlockDroppable: function() {
if(this.isBlockDroppableEnabled() === false) {
var block_placeholder = this.getBlockDroppable();
Droppables.add(block_placeholder.identify(), WysijaForm.blockDropOptions);
block_placeholder.addClassName('enabled');
}
},
removeBlockDroppable: function() {
if(this.isBlockDroppableEnabled()) {
var block_placeholder = this.getBlockDroppable();
Droppables.remove(block_placeholder.identify());
block_placeholder.removeClassName('enabled');
}
},
isBlockDroppableEnabled: function() {
// if the block_placeholder does not exist, create it
var block_placeholder = this.getBlockDroppable();
if(block_placeholder === null) {
return this.createBlockDroppable().hasClassName('enabled');
} else {
return block_placeholder.hasClassName('enabled');
}
},
createBlockDroppable: function() {
info('block -> createBlockDroppable');
this.element.insert({before: '<div class=\"block_placeholder\">'+$('block_placeholder').innerHTML+'</div>'});
return this.element.previous('.block_placeholder');
},
getBlockDroppable: function() {
if(this.element.previous() === undefined || this.element.previous().hasClassName('block_placeholder') === false) {
return null;
} else {
return this.element.previous();
}
},
getControls: function() {
return this.element.down('.wysija_controls');
},
setupControls: function() {
// enable controls
this.controls = this.getControls();
if(this.controls) {
// setup events for block controls
this.element.observe('mouseover', function() {
// special cases where controls shouldn't be displayed
if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true || WysijaForm.locks.showingTools === true) return;
// set block flag
this.element.addClassName('hover');
// show controls
this.showControls();
// show settings if present
if(this.element.down('.wysija_settings') !== undefined) {
this.element.down('.wysija_settings').show();
}
}.bind(this));
this.element.observe('mouseout', function() {
// special cases where controls shouldn't hide
if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true) return;
// hide controls
this.hideControls();
// hide settings if present
if(this.element.down('.wysija_settings') !== undefined) {
this.element.down('.wysija_settings').hide();
}
}.bind(this));
// setup click event for remove button
this.removeButton = this.controls.down('.remove') || null;
if(this.removeButton !== null) {
this.removeButton.observe('click', function() {
this.removeBlock();
this.removeButton.stopObserving('click');
}.bind(this));
}
// setup click event for settings button
this.settingsButton = this.element.down('.settings') || null;
if(this.settingsButton !== null) {
this.settingsButton.observe('click', function(event) {
// TODO: refactor
var block = $(event.target).up('.mailpoet_form_block') || null;
if(block !== null) {
var field = WysijaForm.getFieldData(block);
this.editSettings();
}
}.bind(this));
}
}
return this;
},
removeBlock: function(callback) {
info('block -> removeBlock');
// save block in history
WysijaHistory.enqueue(this.element);
Effect.Fade(this.element.identify(), {
duration: 0.2,
afterFinish: function(effect) {
if(effect.element.next('.mailpoet_form_block') !== undefined && callback !== false) {
// show controls of next block to allow mass delete
WysijaForm.get(effect.element.next('.mailpoet_form_block')).block.showControls();
}
// remove placeholder
if(effect.element.previous('.block_placeholder') !== undefined) {
effect.element.previous('.block_placeholder').remove();
}
// remove element from the DOM
this.element.remove();
// reset block positions
WysijaForm.setBlockPositions();
// toggle widgets
WysijaForm.toggleWidgets();
// optional callback execution after completely removing block
if(callback !== undefined && typeof(callback) === 'function') {
callback();
}
// remove block instance
delete WysijaForm.instances[this.element.identify()];
}.bind(this)
});
}
});
/* Invoked on item dropped */
WysijaForm.Block.create = function(block, target) {
if($('form_template_'+block.type) === null) {
return false;
}
var body = $(WysijaForm.options.body),
block_template = Handlebars.compile($('form_template_block').innerHTML),
template = Handlebars.compile($('form_template_'+block.type).innerHTML),
output = '';
// set block template (depending on the block type)
block.template = template(block);
output = block_template(block);
// check if the new block is unique and if there's already an instance
// of it in the history. If so, remove its former instance from the history
if(block.unique === 1) {
WysijaHistory.remove(block.field);
}
// if the drop target was the bottom placeholder
if(target.identify() === 'block_placeholder') {
// insert block at the bottom
body.insert(output);
//block = body.childElements().last();
} else {
// insert block before the drop target
target.insert({before: output });
//block = target.previous('.mailpoet_form_block');
}
// refresh sortable items
WysijaForm.makeSortable();
// refresh block positions
WysijaForm.setBlockPositions();
// position settings
WysijaForm.setSettingsPosition();
};
document.observe('wjfe:item:drop', function(event) {
info('create block');
WysijaForm.Block.create(event.memo, event.target);
// hide block controls
info('hide controls');
WysijaForm.hideBlockControls();
// toggle widgets
setTimeout(function() {
WysijaForm.toggleWidgets();
}, 1);
});
/* Form Widget */
WysijaForm.Widget = Class.create(WysijaForm.Block, {
initialize: function(element) {
info('widget -> init');
this.element = $(element);
return this;
},
setup: function() {
info('widget -> setup');
this.setupControls();
},
save: function() {
info('widget -> save');
var data = this.getData();
if(data.element !== undefined) {
delete data.element;
}
return data;
},
setData: function(data) {
var current_data = this.getData(),
params = $H(current_data.params).merge(data.params).toObject();
// update type if it changed
if(data.type !== undefined && data.type !== current_data.type) {
this.element.writeAttribute('wysija_type', data.type);
}
// update params
this.element.writeAttribute('wysija_params', JSON.stringify(params));
},
getData: function() {
var data = WysijaForm.getFieldData(this.element);
// decode params
if(data.params.length > 0) {
data.params = JSON.parse(data.params);
}
return data;
},
getControls: function() {
return this.element.down('.wysija_controls');
},
remove: function() {
this.removeBlock();
},
redraw: function(data) {
// set parameters
this.setData(data);
var options = this.getData();
// redraw block
var block_template = Handlebars.compile($('form_template_block').innerHTML),
template = Handlebars.compile($('form_template_'+options.type).innerHTML),
data = $H(options).merge({ template: template(options) }).toObject();
this.element.replace(block_template(data));
WysijaForm.init();
},
editSettings: function() {
MailPoet.Modal.popup({
title: 'Edit field settings', // TODO: translate!
template: jQuery('#form_template_field_settings').html(),
data: this.getData(),
onSuccess: function() {
var data = jQuery('#form_field_settings').serializeObject();
this.redraw(data);
}.bind(this)
});
},
getSettings: function() {
return this.element.down('.wysija_settings');
}
});
/* When dom is loaded, initialize WysijaForm */
document.observe('dom:loaded', WysijaForm.init);
/* LOGGING */
function info(value) {
if(WysijaForm.options.debug === false) return;
if(!(window.console && console.log)) {
(function() {
var noop = function() {};
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
var length = methods.length;
var console = window.console = {};
while(length--) {
console[methods[length]] = noop;
}
}());
}
try {
console.log('[DEBUG] '+value);
} catch(e) {}
}

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,8 @@ const fields = [
name: 'segments',
label: 'Lists',
type: 'selection',
endpoint: 'segments'
endpoint: 'segments',
multiple: true
}
]

View File

@ -1,6 +1,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Link, History } from 'react-router'
import { Router, Link } from 'react-router'
import Listing from 'listing/listing.jsx'
import classNames from 'classnames'
import MailPoet from 'mailpoet'
@ -11,6 +11,11 @@ const columns = [
label: 'Name',
sortable: true
},
{
name: 'segments',
label: 'Lists',
sortable: false
},
{
name: 'created_at',
label: 'Created on',
@ -20,57 +25,57 @@ const columns = [
const messages = {
onTrash: function(response) {
let count = ~~response.forms;
let message = null;
if(response) {
let message = null;
if(~~response === 1) {
message = (
'1 form was moved to the trash.'
);
} else if(~~response > 1) {
message = (
'%$1d forms were moved to the trash.'
).replace('%$1d', ~~response);
}
if(count === 1 || response === true) {
message = (
'1 form was moved to the trash.'
);
} else if(count > 1) {
message = (
'%$1d forms were moved to the trash.'
).replace('%$1d', count);
}
if(message !== null) {
MailPoet.Notice.success(message);
if(message !== null) {
MailPoet.Notice.success(message);
}
}
},
onDelete: function(response) {
let count = ~~response.forms;
let message = null;
if(response) {
let message = null;
if(~~response === 1) {
message = (
'1 form was permanently deleted.'
);
} else if(~~response > 1) {
message = (
'%$1d forms were permanently deleted.'
).replace('%$1d', ~~response);
}
if(count === 1 || response === true) {
message = (
'1 form was permanently deleted.'
);
} else if(count > 1) {
message = (
'%$1d forms were permanently deleted.'
).replace('%$1d', count);
}
if(message !== null) {
MailPoet.Notice.success(message);
if(message !== null) {
MailPoet.Notice.success(message);
}
}
},
onRestore: function(response) {
let count = ~~response.forms;
let message = null;
if(response) {
let message = null;
if(~~response === 1) {
message = (
'1 form has been restored from the trash.'
);
} else if(~~response > 1) {
message = (
'%$1d forms have been restored from the trash.'
).replace('%$1d', ~~response);
}
if(count === 1 || response === true) {
message = (
'1 form has been restored from the trash.'
);
} else if(count > 1) {
message = (
'%$1d forms have been restored from the trash.'
).replace('%$1d', count);
}
if(message !== null) {
MailPoet.Notice.success(message);
if(message !== null) {
MailPoet.Notice.success(message);
}
}
}
};
@ -78,32 +83,26 @@ const messages = {
const item_actions = [
{
name: 'edit',
label: 'Edit',
link: function(item) {
return (
<Link to={ `/edit/${item.id}` }>Edit</Link>
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>Edit</a>
);
}
},
{
name: 'duplicate_form',
refresh: true,
link: function(item) {
return (
<a
href="javascript:;"
onClick={ this.onDuplicate.bind(null, item) }
>Duplicate</a>
);
},
onDuplicate: function(item) {
MailPoet.Ajax.post({
label: 'Duplicate',
onClick: function(item, refresh) {
return MailPoet.Ajax.post({
endpoint: 'forms',
action: 'duplicate',
data: item.id
}).done(function() {
}).done(function(response) {
MailPoet.Notice.success(
('List "%$1s" has been duplicated.').replace('%$1s', item.name)
('Form "%$1s" has been duplicated.').replace('%$1s', response.name)
);
refresh();
});
}
}
@ -113,17 +112,22 @@ const bulk_actions = [
{
name: 'trash',
label: 'Trash',
getData: function() {
return {
confirm: false
}
},
onSuccess: messages.onDelete
onSuccess: messages.onTrash
}
];
const FormList = React.createClass({
renderItem: function(form, actions) {
createForm() {
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'create'
}).done(function(response) {
if(response !== false) {
window.location = response;
}
});
},
renderItem(form, actions) {
let row_classes = classNames(
'manage-column',
'column-primary',
@ -157,10 +161,16 @@ const FormList = React.createClass({
return (
<div>
<h2 className="title">
Forms <Link className="add-new-h2" to="/new">New</Link>
Forms <a
className="add-new-h2"
href="javascript:;"
onClick={ this.createForm }
>New</a>
</h2>
<Listing
location={ this.props.location }
params={ this.props.params }
messages={ messages }
search={ false }
limit={ 1000 }

View File

@ -36,7 +36,6 @@ function(
let default_value = false;
if(selected_filters[filter] !== undefined && selected_filters[filter]) {
default_value = selected_filters[filter]
} else {
jQuery(`select[name="${filter}"]`).val('');
}

View File

@ -34,11 +34,9 @@ define(
};
},
handleSelectItem: function(e) {
var is_checked = jQuery(e.target).is(':checked');
this.props.onSelectItem(
parseInt(e.target.value, 10),
is_checked
e.target.checked
);
return !e.target.checked;
@ -61,11 +59,12 @@ define(
if(this.props.is_selectable === true) {
checkbox = (
<th className="check-column" scope="row">
<label className="screen-reader-text">
{ 'Select ' + this.props.item.email }</label>
<label className="screen-reader-text">{
'Select ' + this.props.item[this.props.columns[0].name]
}</label>
<input
type="checkbox"
defaultValue={ this.props.item.id }
value={ this.props.item.id }
checked={
this.props.item.selected || this.props.selection === 'all'
}
@ -267,7 +266,7 @@ define(
is_selectable={ this.props.is_selectable }
item_actions={ this.props.item_actions }
group={ this.props.group }
key={ 'item-' + index }
key={ `item-${item.id}-${index}` }
item={ item } />
);
}.bind(this))}
@ -393,7 +392,7 @@ define(
},
componentWillReceiveProps: function(nextProps) {
const params = nextProps.params || {}
//this.initWithParams(params)
this.initWithParams(params)
},
getItems: function() {
if(this.isMounted()) {
@ -506,7 +505,7 @@ define(
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'bulk_action',
action: 'bulkAction',
data: data
}).done(function(response) {
this.getItems();

View File

@ -1,9 +1,13 @@
define([
'newsletter_editor/App',
'mailpoet',
'notice',
'backbone',
'backbone.marionette'
], function(App, MailPoet, Backbone, Marionette) {
'backbone.marionette',
'jquery',
'blob',
'filesaver'
], function(App, MailPoet, Notice, Backbone, Marionette, jQuery, Blob, FileSaver) {
"use strict";
@ -52,6 +56,18 @@ define([
});
};
Module.exportTemplate = function(options) {
var data = _.extend(options || {}, {
body: App.getBody(),
});
var blob = new Blob(
[JSON.stringify(data)],
{ type: 'application/json;charset=utf-8' }
);
FileSaver.saveAs(blob, 'template.json');
};
Module.SaveView = Marionette.LayoutView.extend({
getTemplate: function() { return templates.save; },
events: {
@ -62,7 +78,8 @@ define([
'click .mailpoet_save_template': 'toggleSaveAsTemplate',
'click .mailpoet_save_as_template': 'saveAsTemplate',
/* Export template */
'click .mailpoet_save_export': 'exportTemplate',
'click .mailpoet_save_export': 'toggleExportTemplate',
'click .mailpoet_export_template': 'exportTemplate',
},
initialize: function(options) {
App.getChannel().on('beforeEditorSave', this.beforeSave, this);
@ -117,12 +134,33 @@ define([
this.hideOptionContents();
},
toggleExportTemplate: function() {
this.$('.mailpoet_export_template_container').toggleClass('mailpoet_hidden');
this.toggleSaveOptions();
},
hideExportTemplate: function() {
this.$('.mailpoet_export_template_container').addClass('mailpoet_hidden');
},
exportTemplate: function() {
console.log('Exporting template');
this.hideOptionContents();
var templateName = this.$('.mailpoet_export_template_name').val(),
templateDescription = this.$('.mailpoet_export_template_description').val();
if (templateName === '') {
MailPoet.Notice.error(App.getConfig().get('translations.templateNameMissing'));
} else if (templateDescription === '') {
MailPoet.Notice.error(App.getConfig().get('translations.templateDescriptionMissing'));
} else {
console.log('Exporting template with ', templateName, templateDescription);
Module.exportTemplate({
name: templateName,
description: templateDescription,
});
this.hideExportTemplate();
}
},
hideOptionContents: function() {
this.hideSaveAsTemplate();
this.hideExportTemplate();
this.$('.mailpoet_save_options').addClass('mailpoet_hidden');
},
next: function() {

View File

@ -34,8 +34,7 @@ define(
placeholder: "Select a list",
id: "mailpoet_segments",
endpoint: "segments",
multiple: true,
select2: true
multiple: true
},
{
name: 'sender',

View File

@ -1,6 +1,7 @@
define(
[
'react',
'underscore',
'mailpoet',
'react-router',
'classnames',
@ -8,11 +9,67 @@ define(
],
function(
React,
_,
MailPoet,
Router,
classNames,
Breadcrumb
) {
var ImportTemplate = React.createClass({
saveTemplate: function(template) {
MailPoet.Ajax.post({
endpoint: 'newsletterTemplates',
action: 'save',
data: template
}).done(function(response) {
if(response === true) {
this.props.onImport(template);
} else {
response.map(function(error) {
MailPoet.Notice.error(error);
});
}
}.bind(this));
},
handleSubmit: function(e) {
e.preventDefault();
if (_.size(this.refs.templateFile.files) <= 0) return false;
var file = _.first(this.refs.templateFile.files),
reader = new FileReader(),
saveTemplate = this.saveTemplate;
reader.onload = function(e) {
try {
saveTemplate(JSON.parse(e.target.result));
} catch (err) {
MailPoet.Notice.error('This template file appears to be malformed. Please try another one.');
}
}.bind(this);
reader.readAsText(file);
},
render: function() {
return (
<div>
<h2>Import a template</h2>
<form onSubmit={this.handleSubmit}>
<input type="file" placeholder="Select a .json file to upload" ref="templateFile" />
<p className="submit">
<input
className="button button-primary"
type="submit"
value="Upload" />
</p>
</form>
</div>
);
},
});
var NewsletterTemplates = React.createClass({
mixins: [
Router.History
@ -93,6 +150,9 @@ define(
this.setState({ loading: false });
}
},
handleTemplateImport: function() {
this.getTemplates();
},
render: function() {
var templates = this.state.templates.map(function(template, index) {
var deleteLink = (
@ -152,6 +212,8 @@ define(
<ul className={ boxClasses }>
{ templates }
</ul>
<ImportTemplate onImport={this.handleTemplateImport} />
</div>
);
}

View File

@ -1,88 +1,78 @@
define('public', ['mailpoet', 'jquery', 'jquery-validation'],
function(MailPoet, $) {
'use strict';
define([
'mailpoet',
'jquery',
'parsleyjs'
],
function(
MailPoet,
jQuery,
Parsley
) {
jQuery(function($) {
function isSameDomain(url) {
var link = document.createElement('a');
link.href = url;
return (window.location.hostname === link.hostname);
}
function formatData(raw) {
var data = {};
$.each(raw, function(index, value) {
if(value.name.endsWith('[]')) {
var value_name = value.name.substr(0, value.name.length - 2);
// it's an array
if(data[value_name] === undefined) {
data[value_name] = [];
}
data[value_name].push(value.value);
} else {
data[value.name] = value.value;
}
});
return data;
}
$(function() {
// setup form validation
$('form.mailpoet_form').each(function() {
$(this).validate({
submitHandler: function(form) {
var data = $(form).serializeArray() || {};
var form = $(this);
// clear messages
$(form).find('.mailpoet_message').html('');
form.parsley().on('form:submit', function(parsley) {
// check if we're on the same domain
if(isSameDomain(MailPoetForm.ajax_url) === false) {
// non ajax post request
return true;
} else {
// ajax request
MailPoet.Ajax.post({
url: MailPoetForm.ajax_url,
token: MailPoetForm.token,
endpoint: 'subscribers',
action: 'save',
data: formatData(data),
onSuccess: function(response) {
if(response !== true) {
// errors
$.each(response, function(index, error) {
$(form)
.find('.mailpoet_message')
.append('<p class="mailpoet_validate_error">'+
error+
'</p>');
});
} else {
// successfully subscribed
if(response.page !== undefined) {
// go to page
window.location.href = response.page;
} else if(response.message !== undefined) {
// display success message
$(form)
.find('.mailpoet_message')
.html('<p class="mailpoet_validate_success">'+
response.message+
'</p>');
}
var data = form.serializeObject() || {};
// reset form
$(form).trigger('reset');
}
// clear messages
form.find('.mailpoet_message').html('');
// check if we're on the same domain
if(isSameDomain(MailPoetForm.ajax_url) === false) {
// non ajax post request
return true;
} else {
// ajax request
MailPoet.Ajax.post({
url: MailPoetForm.ajax_url,
token: MailPoetForm.token,
endpoint: 'subscribers',
action: 'subscribe',
data: data
}).done(function(response) {
if(response.result !== true) {
// errors
$.each(response.errors, function(index, error) {
form
.find('.mailpoet_message')
.append('<p class="mailpoet_validate_error">'+
error+
'</p>');
});
} else {
// successfully subscribed
if(response.page !== undefined) {
// go to page
window.location.href = response.page;
} else if(response.message !== undefined) {
// display success message
form
.find('.mailpoet_message')
.html('<p class="mailpoet_validate_success">'+
response.message+
'</p>');
}
});
}
return false;
// reset form
form.trigger('reset');
// reset validation
parsley.reset();
}
});
}
return false;
});
});
});
}
);
});
});

View File

@ -1,5 +1,5 @@
import React from 'react'
import { Router, Route, Link } from 'react-router'
import { Router, Link } from 'react-router'
import jQuery from 'jquery'
import MailPoet from 'mailpoet'
@ -40,10 +40,10 @@ var columns = [
}
];
var messages = {
const messages = {
onTrash: function(response) {
if(response) {
var message = null;
let message = null;
if(~~response === 1) {
message = (
'1 segment was moved to the trash.'
@ -61,7 +61,7 @@ var messages = {
},
onDelete: function(response) {
if(response) {
var message = null;
let message = null;
if(~~response === 1) {
message = (
'1 segment was permanently deleted.'
@ -79,7 +79,7 @@ var messages = {
},
onRestore: function(response) {
if(response) {
var message = null;
let message = null;
if(~~response === 1) {
message = (
'1 segment has been restored from the trash.'
@ -97,7 +97,7 @@ var messages = {
}
};
var item_actions = [
const item_actions = [
{
name: 'edit',
label: 'Edit',
@ -133,7 +133,7 @@ var item_actions = [
}
];
var bulk_actions = [
const bulk_actions = [
{
name: 'trash',
label: 'Trash',
@ -141,7 +141,7 @@ var bulk_actions = [
}
];
var SegmentList = React.createClass({
const SegmentList = React.createClass({
renderItem: function(segment, actions) {
var rowClasses = classNames(
'manage-column',

43
composer.lock generated
View File

@ -160,16 +160,16 @@
},
{
"name": "phpmailer/phpmailer",
"version": "v5.2.13",
"version": "v5.2.14",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "45df3a88f7f46071e10d0b600f228d19f95911b3"
"reference": "e774bc9152de85547336e22b8926189e582ece95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/45df3a88f7f46071e10d0b600f228d19f95911b3",
"reference": "45df3a88f7f46071e10d0b600f228d19f95911b3",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e774bc9152de85547336e22b8926189e582ece95",
"reference": "e774bc9152de85547336e22b8926189e582ece95",
"shasum": ""
},
"require": {
@ -180,7 +180,8 @@
"phpunit/phpunit": "4.7.*"
},
"suggest": {
"league/oauth2-client": "Needed for Gmail's XOAUTH2 authentication system"
"league/oauth2-client": "Needed for XOAUTH2 authentication",
"league/oauth2-google": "Needed for Gmail XOAUTH2"
},
"type": "library",
"autoload": {
@ -216,7 +217,7 @@
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"time": "2015-09-14 09:18:12"
"time": "2015-11-01 10:15:28"
},
{
"name": "phpseclib/phpseclib",
@ -456,16 +457,16 @@
},
{
"name": "twig/twig",
"version": "v1.23.0",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "5868cd822fd6cf626d5f805439575f9c323cee2a"
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/5868cd822fd6cf626d5f805439575f9c323cee2a",
"reference": "5868cd822fd6cf626d5f805439575f9c323cee2a",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"shasum": ""
},
"require": {
@ -513,7 +514,7 @@
"keywords": [
"templating"
],
"time": "2015-10-29 23:29:01"
"time": "2015-11-05 12:49:06"
}
],
"packages-dev": [
@ -739,16 +740,16 @@
},
{
"name": "facebook/webdriver",
"version": "1.0.2",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/facebook/php-webdriver.git",
"reference": "fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5"
"reference": "d843e33fd19b49db5ac9daaef2610079daab0bad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5",
"reference": "fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5",
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/d843e33fd19b49db5ac9daaef2610079daab0bad",
"reference": "d843e33fd19b49db5ac9daaef2610079daab0bad",
"shasum": ""
},
"require": {
@ -778,7 +779,7 @@
"selenium",
"webdriver"
],
"time": "2015-08-12 20:21:31"
"time": "2015-11-01 20:09:34"
},
{
"name": "guzzlehttp/guzzle",
@ -895,16 +896,16 @@
},
{
"name": "guzzlehttp/psr7",
"version": "1.2.0",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e"
"reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/4ef919b0cf3b1989523138b60163bbcb7ba1ff7e",
"reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/4d0bdbe1206df7440219ce14c972aa57cc5e4982",
"reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982",
"shasum": ""
},
"require": {
@ -949,7 +950,7 @@
"stream",
"uri"
],
"time": "2015-08-15 19:32:36"
"time": "2015-11-03 01:34:55"
},
{
"name": "henrikbjorn/lurker",

View File

@ -2,6 +2,9 @@
namespace MailPoet\Config;
use \MailPoet\Models\Segment;
use \MailPoet\Models\Setting;
use \MailPoet\Models\Form;
use \MailPoet\Form\Block;
use \MailPoet\Form\Renderer as FormRenderer;
use \MailPoet\Settings\Hosts;
use \MailPoet\Settings\Pages;
use \MailPoet\Settings\Charsets;
@ -87,8 +90,8 @@ class Menu {
function registered_pages() {
global $_registered_pages;
$pages = array(
//'mailpoet-form-editor' => 'formEditor',
'mailpoet-newsletter-editor' => array($this, 'newletterForm')
'mailpoet-form-editor' => array($this, 'formEditor'),
'mailpoet-newsletter-editor' => array($this, 'newletterEditor')
);
foreach($pages as $menu_slug => $callback) {
$hookname = get_plugin_page_hookname($menu_slug, null);
@ -193,11 +196,30 @@ class Menu {
echo $this->renderer->render('newsletters.html', $data);
}
function newletterForm() {
function newletterEditor() {
$data = array();
wp_enqueue_media();
wp_enqueue_script('tinymce-wplink', includes_url('js/tinymce/plugins/wplink/plugin.js'));
wp_enqueue_style('editor', includes_url('css/editor.css'));
echo $this->renderer->render('newsletter/form.html', $data);
}
function formEditor() {
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
$form = Form::findOne($id);
if($form !== false) {
$form = $form->asArray();
}
$data = array(
'form' => $form,
'pages' => Pages::getAll(),
'segments' => Segment::findArray(),
'styles' => FormRenderer::getStyles($form),
'date_types' => Block\Date::getDateTypes(),
'date_formats' => Block\Date::getDateFormats()
);
echo $this->renderer->render('form/editor.html', $data);
}
}

View File

@ -67,7 +67,7 @@ class Migrator {
$attributes = array(
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
'name varchar(20) NOT NULL,',
'value varchar(255) NOT NULL,',
'value longtext,',
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'PRIMARY KEY (id),',
@ -125,7 +125,8 @@ class Migrator {
'segment_id mediumint(9) NOT NULL,',
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'PRIMARY KEY (id)'
'PRIMARY KEY (id),',
'UNIQUE KEY subscriber_segment (subscriber_id,segment_id)'
);
return $this->sqlify(__FUNCTION__, $attributes);
}
@ -137,7 +138,8 @@ class Migrator {
'segment_id mediumint(9) NOT NULL,',
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'PRIMARY KEY (id)'
'PRIMARY KEY (id),',
'UNIQUE KEY newsletter_segment (newsletter_id,segment_id)'
);
return $this->sqlify(__FUNCTION__, $attributes);
}
@ -147,6 +149,7 @@ class Migrator {
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
'name varchar(90) NOT NULL,',
'type varchar(90) NOT NULL,',
'params longtext NOT NULL,',
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'PRIMARY KEY (id),',
@ -199,6 +202,8 @@ class Migrator {
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
'name varchar(90) NOT NULL,',
'body longtext,',
'settings longtext,',
'styles longtext,',
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',

View File

@ -1,5 +1,6 @@
<?php
namespace MailPoet\Config;
use \MailPoet\Models\Subscriber;
use \MailPoet\Util\Security;
if(!defined('ABSPATH')) exit;
@ -12,16 +13,39 @@ class Widget {
add_action('widgets_init', array($this, 'registerWidget'));
if(!is_admin()) {
add_action('widgets_init', array($this, 'setupActions'));
//$this->setupActions();
add_action('widgets_init', array($this, 'setupDependencies'));
} else {
add_action('widgets_init', array($this, 'setupAdminDependencies'));
}
}
function registerWidget() {
register_widget('\MailPoet\Form\Widget');
// subscribers count shortcode
add_shortcode('mailpoet_subscribers_count', array(
$this, 'getSubscribersCount'
));
add_shortcode('wysija_subscribers_count', array(
$this, 'getSubscribersCount'
));
}
function getSubscribersCount($params) {
return Subscriber::filter('subscribed')->count();
}
function setupDependencies() {
wp_enqueue_style('mailpoet_public', Env::$assets_url.'/css/public.css');
wp_enqueue_script('mailpoet_vendor',
Env::$assets_url.'/js/vendor.js',
array(),
Env::$version,
true
);
wp_enqueue_script('mailpoet_public',
Env::$assets_url.'/js/public.js',
array(),
@ -36,6 +60,22 @@ class Widget {
));
}
function setupAdminDependencies() {
wp_enqueue_script('mailpoet_vendor',
Env::$assets_url.'/js/vendor.js',
array(),
Env::$version,
true
);
wp_enqueue_script('mailpoet_admin',
Env::$assets_url.'/js/mailpoet.js',
array(),
Env::$version,
true
);
}
function setupActions() {
// ajax requests
add_action(
@ -55,9 +95,9 @@ class Widget {
'admin_post_mailpoet_form_subscribe',
'mailpoet_form_subscribe'
);
/*add_action(
add_action(
'init',
'mailpoet_form_subscribe'
);*/
);
}
}
}

103
lib/Form/Block/Base.php Normal file
View File

@ -0,0 +1,103 @@
<?php
namespace MailPoet\Form\Block;
abstract class Base {
protected static function getInputValidation($block) {
$rules = array();
if($block['id'] === 'email') {
$rules['required'] = true;
$rules['error-message'] = __('You need to specify a valid email address');
}
if($block['id'] === 'segments') {
$rules['required'] = true;
$rules['mincheck'] = 1;
$rules['error-message'] = __('You need to select a list');
}
if(!empty($block['params']['required'])) {
$rules['required'] = true;
}
if(!empty($block['params']['validate'])) {
if($block['params']['validate'] === 'phone') {
$rules['pattern'] = "^[\d\+\-\.\(\)\/\s]*$";
$rules['error-message'] = __('You need to specify a valid phone number');
} else {
$rules['type'] = $block['params']['validate'];
}
}
$validation = '';
if(!empty($rules)) {
$rules = array_unique($rules);
foreach($rules as $rule => $value) {
if(is_bool($value)) {
$value = ($value) ? 'true' : 'false';
}
$validation .= 'data-parsley-'.$rule.'="'.$value.'"';
}
}
return $validation;
}
protected static function renderLabel($block) {
$html = '';
if(
isset($block['params']['label_within'])
&& $block['params']['label_within']
) {
return $html;
}
if(isset($block['params']['label'])
&& strlen(trim($block['params']['label'])) > 0) {
$html .= '<label class="mailpoet_'.$block['type'].'_label">';
$html .= $block['params']['label'];
if(isset($block['params']['required']) && $block['params']['required']) {
$html .= ' <span class="mailpoet_required">*</span>';
}
$html .= '</label>';
}
return $html;
}
protected static function renderInputPlaceholder($block) {
$html = '';
// if the label is displayed as a placeholder,
if(
isset($block['params']['label_within'])
&& $block['params']['label_within']
) {
// display only label
$html .= ' placeholder="';
$html .= static::getFieldLabel($block);
// add an asterisk if it's a required field
if(isset($block['params']['required']) && $block['params']['required']) {
$html .= ' *';
}
$html .= '" ';
}
return $html;
}
// return field name depending on block data
protected static function getFieldName($block = array()) {
return $block['id'];
}
protected static function getFieldLabel($block = array()) {
return (isset($block['params']['label'])
&& strlen(trim($block['params']['label'])) > 0)
? trim($block['params']['label']) : '';
}
protected static function getFieldValue($block = array()) {
return (isset($block['params']['value'])
&& strlen(trim($block['params']['value'])) > 0)
? trim($block['params']['value']) : '';
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace MailPoet\Form\Block;
class Checkbox extends Base {
static function render($block) {
$html = '';
$field_name = static::getFieldName($block);
$field_validation = static::getInputValidation($block);
// TODO: check if it still makes sense
// create hidden default value
// $html .= '<input type="hidden"name="'.$field_name.'" value="0" '.static::getInputValidation($block).'/>';
$html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block);
foreach($block['params']['values'] as $option) {
$html .= '<label class="mailpoet_checkbox_label">';
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
$html .= 'name="'.$field_name.'" ';
$html .= 'value="1" ';
$html .= (isset($option['is_checked']) && $option['is_checked'])
? 'checked="checked"' : '';
$html .= $field_validation;
$html .= ' />'.$option['value'];
$html .= '</label>';
}
$html .= '</p>';
return $html;
}
}

155
lib/Form/Block/Date.php Normal file
View File

@ -0,0 +1,155 @@
<?php
namespace MailPoet\Form\Block;
class Date extends Base {
static function render($block) {
$html = '';
$html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block);
$html .= static::renderDateSelect($block);
$html .= '</p>';
return $html;
}
private static function renderDateSelect($block = array()) {
$html = '';
$field_name = static::getFieldName($block);
$field_validation = static::getInputValidation($block);
$date_formats = static::getDateFormats();
// automatically select first date format
$date_format = $date_formats[$block['params']['date_type']][0];
// set date format if specified
if(isset($block['params']['date_format'])
&& strlen(trim($block['params']['date_format'])) > 0) {
$date_format = $block['params']['date_format'];
}
// generate an array of selectors based on date format
$date_selectors = explode('/', $date_format);
foreach($date_selectors as $date_selector) {
if($date_selector === 'dd') {
$html .= '<select class="mailpoet_date_day" ';
$html .= 'name="'.$field_name.'[day]" placeholder="'.__('Day').'">';
$html .= static::getDays($block);
$html .= '</select>';
} else if($date_selector === 'mm') {
$html .= '<select class="mailpoet_date_month" ';
$html .= 'name="'.$field_name.'[month]" placeholder="'.__('Month').'">';
$html .= static::getMonths($block);
$html .= '</select>';
} else if($date_selector === 'yyyy') {
$html .= '<select class="mailpoet_date_year" ';
$html .= 'name="'.$field_name.'[year]" placeholder="'.__('Year').'">';
$html .= static::getYears($block);
$html .= '</select>';
}
}
return $html;
}
static function getDateTypes() {
return array(
'year_month_day' => __('Year, month, day'),
'year_month' => __('Year, month'),
'month' => __('Month (January, February,...)'),
'year' => __('Year')
);
}
static function getDateFormats() {
return array(
'year_month_day' => array('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy/mm/dd'),
'year_month' => array('mm/yyyy', 'yyyy/mm'),
'year' => array('yyyy'),
'month' => array('mm')
);
}
static function getMonthNames() {
return array(__('January'), __('February'), __('March'), __('April'),
__('May'), __('June'), __('July'), __('August'), __('September'),
__('October'), __('November'), __('December')
);
}
static function getMonths($block = array()) {
$defaults = array(
'selected' => null
);
// is default today
if(!empty($block['params']['is_default_today'])) {
$defaults['selected'] = (int)strftime('%m');
}
// merge block with defaults
$block = array_merge($defaults, $block);
$month_names = static::getMonthNames();
$html = '';
for($i = 1; $i < 13; $i++) {
$is_selected = ($i === $block['selected']) ? 'selected="selected"' : '';
$html .= '<option value="'.$i.'" '.$is_selected.'>';
$html .= $month_names[$i - 1];
$html .= '</option>';
}
return $html;
}
static function getYears($block = array()) {
$defaults = array(
'selected' => null,
'from' => (int)strftime('%Y') - 100,
'to' => (int)strftime('%Y')
);
// is default today
if(!empty($block['params']['is_default_today'])) {
$defaults['selected'] = (int)strftime('%Y');
}
// merge block with defaults
$block = array_merge($defaults, $block);
$html = '';
// return years as an array
for($i = (int)$block['to']; $i > (int)($block['from'] - 1); $i--) {
$is_selected = ($i === $block['selected']) ? 'selected="selected"' : '';
$html .= '<option value="'.$i.'" '.$is_selected.'>'.$i.'</option>';
}
return $html;
}
static function getDays($block = array()) {
$defaults = array(
'selected' => null
);
// is default today
if(!empty($block['params']['is_default_today'])) {
$defaults['selected'] = (int)strftime('%d');
}
// merge block with defaults
$block = array_merge($defaults, $block);
$html = '';
// return days as an array
for($i = 1; $i < 32; $i++) {
$is_selected = ($i === $block['selected']) ? 'selected="selected"' : '';
$html .= '<option value="'.$i.'" '.$is_selected.'>'.$i.'</option>';
}
return $html;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace MailPoet\Form\Block;
class Divider {
static function render() {
return '<hr class="mailpoet_divider" />';
}
}

23
lib/Form/Block/Html.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace MailPoet\Form\Block;
class Html {
static function render($block) {
$html = '';
if(isset($block['params']['text']) && $block['params']['text']) {
$text = html_entity_decode($block['params']['text'], ENT_QUOTES);
}
if(isset($block['params']['nl2br']) && $block['params']['nl2br']) {
$text = nl2br($text);
}
$html .= '<p class="mailpoet_paragraph">';
$html .= $text;
$html .= '</p>';
return $html;
}
}

36
lib/Form/Block/Input.php Normal file
View File

@ -0,0 +1,36 @@
<?php
namespace MailPoet\Form\Block;
class Input extends Base {
static function render($block) {
$type = 'text';
if($block['id'] === 'email') {
$type = 'email';
}
$html = '';
$html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block);
$html .= '<input type="'.$type.'" class="mailpoet_input" ';
$html .= 'name="'.static::getFieldName($block).'" ';
$html .= 'title="'.static::getFieldLabel($block).'" ';
$html .= 'value="'.static::getFieldValue($block).'" ';
$html .= static::renderInputPlaceholder($block);
$html .= static::getInputValidation($block);
$html .= '/>';
$html .= '</p>';
return $html;
}
}

42
lib/Form/Block/Radio.php Normal file
View File

@ -0,0 +1,42 @@
<?php
namespace MailPoet\Form\Block;
class Radio extends Base {
static function render($block) {
$html = '';
$field_name = static::getFieldName($block);
$field_validation = static::getInputValidation($block);
// TODO: check if it still makes sense
// create hidden default value
// $html .= '<input type="hidden"name="'.$field_name.'" value="0" '.static::getInputValidation($block).'/>';
$html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block);
foreach($block['params']['values'] as $option) {
$html .= '<label class="mailpoet_radio_label">';
$html .= '<input type="radio" class="mailpoet_radio" ';
$html .= 'name="'.$field_name.'" ';
$html .= 'value="'.$option['value'].'" ';
$html .= (isset($option['is_checked']) && $option['is_checked'])
? 'checked="checked"' : '';
$html .= $field_validation;
$html .= ' />&nbsp;'.$option['value'];
$html .= '</label>';
}
$html .= '</p>';
return $html;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace MailPoet\Form\Block;
class Segment extends Base {
static function render($block) {
$html = '';
$field_name = static::getFieldName($block);
$field_validation = static::getInputValidation($block);
$html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block);
if(!empty($block['params']['values'])) {
// display values
foreach($block['params']['values'] as $segment) {
if(!isset($segment['id']) || !isset($segment['name'])) continue;
$is_checked = (isset($segment['is_checked']) && $segment['is_checked']) ? 'checked="checked"' : '';
$html .= '<label class="mailpoet_checkbox_label">';
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
$html .= 'name="'.$field_name.'[]" ';
$html .= 'value="'.$segment['id'].'" '.$is_checked.' ';
$html .= $field_validation;
$html .= ' />'.$segment['name'];
$html .= '</label>';
}
}
$html .= '</p>';
return $html;
}
}

36
lib/Form/Block/Select.php Normal file
View File

@ -0,0 +1,36 @@
<?php
namespace MailPoet\Form\Block;
class Select extends Base {
static function render($block) {
$html = '';
$field_name = static::getFieldName($block);
$field_validation = static::getInputValidation($block);
$html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block);
$html .= '<select class="mailpoet_select" name="'.$field_name.'">';
if(isset($block['params']['label_within'])
&& $block['params']['label_within']) {
$html .= '<option value="">'.static::getFieldLabel($block).'</option>';
}
foreach($block['params']['values'] as $option) {
$is_selected = (isset($option['is_checked']) && $option['is_checked'])
? 'selected="selected"' : '';
$html .= '<option value="'.$option['value'].'" '.$is_selected.'>';
$html .= $option['value'];
$html .= '</option>';
}
$html .= '</select>';
$html .= '</p>';
return $html;
}
}

17
lib/Form/Block/Submit.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace MailPoet\Form\Block;
class Submit extends Base {
static function render($block) {
$html = '';
$html .= '<input class="mailpoet_submit" type="submit" ';
$html .= 'value="'.static::getFieldLabel($block).'" ';
$html .= '/>';
return $html;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace MailPoet\Form\Block;
class Textarea extends Base {
static function render($block) {
$html = '';
$html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block);
$lines = (isset($block['params']['lines']) ? (int)$block['params']['lines'] : 1);
$html .= '<textarea class="mailpoet_textarea" rows="'.$lines.'" ';
$html .= 'name="'.static::getFieldName($block).'"';
$html .= static::renderInputPlaceholder($block);
$html .= static::getInputValidation($block);
$html .= '></textarea>';
$html .= '</p>';
return $html;
}
}

95
lib/Form/Renderer.php Normal file
View File

@ -0,0 +1,95 @@
<?php
namespace MailPoet\Form;
use MailPoet\Form\Block;
use MailPoet\Form\Util;
if(!defined('ABSPATH')) exit;
class Renderer {
// public: rendering method
static function render($form = array()) {
$html = static::renderStyles($form);
$html .= static::renderHTML($form);
return $html;
}
static function renderStyles($form = array()) {
$html = '<style type="text/css">';
$html .= static::getStyles($form);
$html .= '</style>';
return $html;
}
static function renderHTML($form = array()) {
if(isset($form['body']) && !empty($form['body'])) {
return static::renderBlocks($form['body']);
}
return '';
}
static function getStyles($form = array()) {
if(isset($form['styles'])
&& strlen(trim($form['styles'])) > 0) {
return strip_tags($form['styles']);
} else {
return Util\Styles::$defaults;
}
}
// private: rendering methods
private static function renderBlocks($blocks = array()) {
$html = '';
foreach ($blocks as $key => $block) {
$html .= static::renderBlock($block)."\n";
}
return $html;
}
private static function renderBlock($block = array()) {
$html = '';
switch ($block['type']) {
case 'html':
$html .= Block\Html::render($block);
break;
case 'divider':
$html .= Block\Divider::render();
break;
case 'checkbox':
$html .= Block\Checkbox::render($block);
break;
case 'radio':
$html .= Block\Radio::render($block);
break;
case 'segment':
$html .= Block\Segment::render($block);
break;
case 'date':
$html .= Block\Date::render($block);
break;
case 'select':
$html .= Block\Select::render($block);
break;
case 'input':
$html .= Block\Input::render($block);
break;
case 'textarea':
$html .= Block\Textarea::render($block);
break;
case 'submit':
$html .= Block\Submit::render($block);
break;
}
return $html;
}
}

91
lib/Form/Util/Export.php Normal file
View File

@ -0,0 +1,91 @@
<?php
namespace MailPoet\Form\Util;
use MailPoet\Form\Widget;
class Export {
static function getAll($form = null) {
return array(
'html' => static::get('html', $form),
'php' => static::get('php', $form),
'iframe' => static::get('iframe', $form),
'shortcode' => static::get('shortcode', $form),
);
}
static function get($type = 'html', $form = null) {
switch($type) {
case 'iframe':
// generate url to load iframe's content
$iframe_url = add_query_arg(array(
'mailpoet_page' => 'mailpoet_form_iframe',
'mailpoet_form' => $form['id']
), site_url());
// generate iframe
return '<iframe '.
'width="100%" '.
'scrolling="no" '.
'frameborder="0" '.
'src="'.$iframe_url.'" '.
'class="mailpoet_form_iframe" '.
'vspace="0" '.
'tabindex="0" '.
'onload="javascript:(this.style.height = this.contentWindow.document.body.scrollHeight + \'px\');"'.
'marginwidth="0" '.
'marginheight="0" '.
'hspace="0" '.
'allowtransparency="true"></iframe>';
break;
case 'php':
$output = array(
'$form_widget = new \MailPoet\Form\Widget();',
'echo $form_widget->widget(array(\'form\' => '.(int)$form['id'].', \'form_type\' => \'php\'));'
);
return join("\n", $output);
break;
case 'html':
// TODO: get locale setting in order to load translations
$wp_locale = \get_locale();
$output = array();
$output[] = '<!-- BEGIN Scripts : you should place them in the header of your theme -->';
// jQuery
$output[] = '<script type="text/javascript" src="'.includes_url().'js/jquery/jquery.js'.'?mpv='.MAILPOET_VERSION.'"></script>';
// (JS) form validation
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'lib/jquery.validationEngine.js?mpv='.MAILPOET_VERSION).'"></script>';
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'lib/jquery.validationEngine-en.js?mpv='.MAILPOET_VERSION).'"></script>';
// (CSS) form validation styles
$output[] = '<link rel="stylesheet" type="text/css" href="'.plugins_url('wysija-newsletters/'.'lib/validationEngine.jquery.css?mpv='.MAILPOET_VERSION).'">';
// (JS) form submission
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'www/mailpoet_form_subscribe.js?mpv='.MAILPOET_VERSION).'"></script>';
// (JS) variables...
$output[] = '<script type="text/javascript">';
$output[] = ' var MailPoetData = MailPoetData || {';
$output[] = ' is_rtl: '.((int)is_rtl()).",";
$output[] = ' ajax_url: "'.admin_url('admin-ajax.php').'"';
$output[] = ' };';
$output[] = '</script>';
$output[] = '<!--END Scripts-->';
$form_widget = new Widget();
$output[] = $form_widget->widget(array(
'form' => (int)$form['id'],
'form_type' => 'php'
));
return join("\n", $output);
break;
case 'shortcode':
return '[mailpoet_form id="'.(int)$form['id'].'"]';
break;
}
}
}

181
lib/Form/Util/Styles.php Normal file
View File

@ -0,0 +1,181 @@
<?php
namespace MailPoet\Form\Util;
class Styles {
private $_stylesheet = null;
private $_styles = array();
static $defaults =<<<EOL
/* form */
.mailpoet_form {
}
/* paragraphs (label + input) */
.mailpoet_paragraph {
}
/* labels */
.mailpoet_input_label,
.mailpoet_textarea_label,
.mailpoet_select_label,
.mailpoet_radio_label,
.mailpoet_checkbox_label,
.mailpoet_list_label,
.mailpoet_date_label {
display:block;
}
/* inputs */
.mailpoet_input,
.mailpoet_textarea,
.mailpoet_select,
.mailpoet_date {
display:block;
}
.mailpoet_checkbox {
display:inline;
margin-right: 5px;
vertical-align:middle;
}
.mailpoet_validate_success {
color:#468847;
}
.mailpoet_validate_error {
color:#B94A48;
}
EOL;
function __construct($stylesheet = null) {
// store raw styles
$this->setStylesheet($stylesheet);
// extract rules/properties
$this->parseStyles();
return $this;
}
function render($prefix = '') {
$styles = $this->getStyles();
if(!empty($styles)) {
$output = array();
// add prefix on each selector
foreach($styles as $style) {
// check if selector is an array
if(is_array($style['selector'])) {
$selector = join(",\n", array_map(function($value) use ($prefix) {
return $prefix.' '.$value;
}, $style['selector']));
} else {
$selector = $prefix.' '.$style['selector'];
}
// format selector
$output[] = $selector . ' {';
// format rules
if(!empty($style['rules'])) {
$rules = join("\n", array_map(function($rule) {
return "\t".$rule['property'] . ': ' . $rule['value'].';';
}, $style['rules']));
$output[] = $rules;
}
$output[] = '}';
}
return join("\n", $output);
}
}
private function setStylesheet($stylesheet) {
$this->_stylesheet = $this->stripComments($stylesheet);
return $this;
}
private function stripComments($stylesheet) {
// remove comments
return preg_replace('!/\*.*?\*/!s', '', $stylesheet);
}
private function getStylesheet() {
return $this->_stylesheet;
}
private function setStyles($styles) {
$this->_styles = $styles;
return $this;
}
private function getStyles() {
return $this->_styles;
}
private function parseStyles() {
if($this->getStylesheet() !== null) {
// extract selectors and rules
preg_match_all( '/(?ims)([a-z0-9\s\.\:#_\-@,]+)\{([^\}]*)\}/',
$this->getStylesheet(),
$matches
);
$selectors = $matches[1];
$rules = $matches[2];
// extracted styles
$styles = array();
// loop through each selector
foreach($selectors as $index => $selector) {
// trim selector
$selector = trim($selector);
// get selector rules
$selector_rules = array_filter(array_map(function($value) {
if(strlen(trim($value)) > 0) {
// split property / value
$pair = explode(':', trim($value));
if(isset($pair[0]) && isset($pair[1])) {
return array(
'property' => $pair[0],
'value' => $pair[1]
);
}
}
}, explode(';', trim($rules[$index]))));
// check if we have multiple selectors
if(strpos($selector, ',') !== FALSE) {
$selectors_array = array_filter(array_map(function($value) {
return trim($value);
}, explode(',', $selector)));
// multiple selectors
$styles[$index] = array(
'selector' => $selectors_array,
'rules' => $selector_rules
);
} else {
// it's a single selector
$styles[$index] = array(
'selector' => $selector,
'rules' => $selector_rules
);
}
}
$this->setStyles($styles);
}
}
function __toString() {
$this->stripComments();
return $this->render();
}
}

View File

@ -1,120 +1,310 @@
<?php
namespace MailPoet\Form;
use \MailPoet\Config\Renderer;
use \MailPoet\Models\Form;
use \MailPoet\Models\Segment;
use \MailPoet\Models\Setting;
use \MailPoet\Models\Subscriber;
use \MailPoet\Form\Renderer as FormRenderer;
use \MailPoet\Form\Util;
if(!defined('ABSPATH')) exit;
class Widget extends \WP_Widget {
function __construct () {
// add_action(
// 'wp_ajax_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'wp_ajax_nopriv_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'admin_post_nopriv_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'admin_post_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'init',
// array($this, 'subscribe')
// );
function __construct() {
return parent::__construct(
'mailpoet_form',
__('MailPoet Subscription Form'),
__("MailPoet Subscription Form"),
array(
'title' => __('Newsletter subscription form')
'title' => __("Newsletter subscription form"),
)
);
}
public function update($new_instance, $old_instance) {
/**
* Save the new widget's title.
*/
public function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance['title'] = strip_tags($new_instance['title']);
$instance['form'] = (int)$new_instance['form'];
return $instance;
}
/**
* Output the widget's option form.
*/
public function form($instance) {
$instance = wp_parse_args(
(array)$instance,
array(
'title' => __('Subscribe to our Newsletter')
'title' => __("Subscribe to our Newsletter")
)
);
// set title
$title = isset($instance['title']) ? strip_tags($instance['title']) : '';
$output = '';
// set form
$selected_form = isset($instance['form']) ? (int)($instance['form']) : 0;
$output .= '<p>';
$output .= ' <label for="'.$this->get_field_id('title').'">';
$output .= __('Title:' );
$output .= ' </label>';
$output .= ' <input type="text" class="widefat"';
$output .= ' id="'.$this->get_field_id('title').'"';
$output .= ' name="'.$this->get_field_name('title').'"';
$output .= ' value="'.esc_attr($title).'"';
$output .= ' />';
$output .= '</p>';
$output .= '<p>';
$output .= ' <a href="javascript:;" class="mailpoet_form_new">';
$output .= __('Create a new form');
$output .= ' </a>';
$output .= '</p>';
echo $output;
// get forms list
$forms = Form::whereNull('deleted_at')->orderByAsc('name')->findArray();
?><p>
<label for="<?php $this->get_field_id( 'title' ) ?>"><?php _e( 'Title:' ); ?></label>
<input
type="text"
class="widefat"
id="<?php echo $this->get_field_id('title') ?>"
name="<?php echo $this->get_field_name('title'); ?>"
value="<?php echo esc_attr($title); ?>"
/>
</p>
<p>
<select class="widefat" id="<?php echo $this->get_field_id('form') ?>" name="<?php echo $this->get_field_name('form'); ?>">
<?php
foreach ($forms as $form) {
$is_selected = ($selected_form === (int)$form['id']) ? 'selected="selected"' : '';
?>
<option value="<?php echo (int)$form['id']; ?>" <?php echo $is_selected; ?>><?php echo esc_html($form['name']); ?></option>
<?php } ?>
</select>
</p>
<p>
<a href="javascript:;" class="mailpoet_form_new"><?php _e("Create a new form"); ?></a>
</p>
<script type="text/javascript">
jQuery(function($) {
$(function() {
$('.mailpoet_form_new').on('click', function() {
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'create'
}).done(function(response) {
if(response !== false) {
window.location = response;
}
});
});
});
});
</script>
<?php
}
/**
* Output the widget itself.
*/
function widget($args, $instance = null) {
// turn $args into variables
extract($args);
if($instance === null) { $instance = $args; }
if($instance === null) {
$instance = $args;
}
$title = apply_filters(
'widget_title',
$instance['title'],
!empty($instance['title']) ? $instance['title'] : '',
$instance,
$this->id_base
);
$form_id = $this->id_base.'_'.$this->number;
$form_type = 'widget';
// get form
$form = Form::whereNull('deleted_at')->findOne($instance['form']);
$output = '';
// if the form was not found, return nothing.
if($form === false) {
return '';
} else {
$form = $form->asArray();
$form_type = 'widget';
if(isset($instance['form_type']) && in_array(
$instance['form_type'],
array('html', 'php', 'iframe', 'shortcode')
)) {
$form_type = $instance['form_type'];
}
// before widget
$output .= (isset($before_widget) ? $before_widget : '');
$settings = (isset($form['settings']) ? $form['settings'] : array());
$body = (isset($form['body']) ? $form['body'] : array());
$output = '';
// title
$output .= $before_title.$title.$after_title;
if(!empty($body)) {
$data = array(
'form_id' => $this->id_base.'_'.$this->number,
'form_type' => $form_type,
'form' => $form,
'title' => $title,
'styles' => FormRenderer::renderStyles($form),
'html' => FormRenderer::renderHTML($form),
'before_widget' => (!empty($before_widget) ? $before_widget : ''),
'after_widget' => (!empty($after_widget) ? $after_widget : ''),
'before_title' => (!empty($before_title) ? $before_title : ''),
'after_title' => (!empty($after_title) ? $after_title : '')
);
// container
$output .= '<div class="mailpoet_form mailpoet_form_'.$form_type.'">';
// if(isset($_GET['mailpoet_form']) && (int)$_GET['mailpoet_form'] === $form['id']) {
// // form messages (success / error)
// $output .= '<div class="mailpoet_message">';
// // success message
// if(isset($_GET['mailpoet_success'])) {
// $output .= '<p class="mailpoet_validate_success">'.strip_tags(urldecode($_GET['mailpoet_success']), '<a><strong><em><br><p>').'</p>';
// }
// // error message
// if(isset($_GET['mailpoet_error'])) {
// $output .= '<p class="mailpoet_validate_error">'.strip_tags(urldecode($_GET['mailpoet_error']), '<a><strong><em><br><p>').'</p>';
// }
// $output .= '</div>';
// } else {
// $output .= '<div class="mailpoet_message"></div>';
// }
// styles
$styles = '.mailpoet_validate_success { color:#468847; }';
$styles .= '.mailpoet_validate_error { color:#B94A48; }';
$output .= '<style type="text/css">'.$styles.'</style>';
// render form
$renderer = new Renderer();
$renderer = $renderer->init();
$output = $renderer->render('form/widget.html', $data);
$output = do_shortcode($output);
}
$output .= '<form '.
'id="'.$form_id.'" '.
'method="post" '.
'action="'.admin_url('admin-post.php?action=mailpoet_form_subscribe').'" '.
'class="mailpoet_form mailpoet_form_'.$form_type.'" novalidate>';
$output .= '<div class="mailpoet_message"></div>';
$output .= ' <p>';
$output .= ' <label>'.__('E-mail');
$output .= ' <input type="email" name="email"';
$output .= ' data-rule-required="true"';
$output .= ' data-rule-email="true"';
$output .= ' data-msg-required="'.__('Please enter your email address.').'"';
$output .= ' data-msg-email="'.__('Please enter a valid email address.').'"';
$output .= ' />';
$output .= ' </label>';
$output .= ' </p>';
$output .= ' <p>';
$output .= ' <label>';
$output .= ' <input type="submit" value="'.esc_attr('Subscribe!').'" />';
$output .= ' </label>';
$output .= ' </p>';
$output .= '</form>';
$output .= '</div>';
// after widget
$output .= (isset($after_widget) ? $after_widget : '');
echo $output;
if($form_type === 'widget') {
echo $output;
} else {
return $output;
}
}
}
}
// mailpoet shortcodes
// form shortcode
add_shortcode('mailpoet_form', 'mailpoet_form_shortcode');
add_shortcode('wysija_form', 'mailpoet_form_shortcode');
function mailpoet_form_shortcode($params = array()) {
// IMPORTANT: this is to make sure MagicMember won't scan our form and find [user_list] as a code they should replace.
remove_shortcode('user_list');
if(isset($params['id']) && (int)$params['id'] > 0) {
$form_widget = new \MailPoet\Form\Widget();
return $form_widget->widget(array(
'form' => (int)$params['id'],
'form_type' => 'shortcode'
));
}
}
// set the content filter to replace the shortcode
if(isset($_GET['mailpoet_page']) && strlen(trim($_GET['mailpoet_page'])) > 0) {
switch($_GET['mailpoet_page']) {
case 'mailpoet_form_iframe':
$id = (isset($_GET['mailpoet_form']) && (int)$_GET['mailpoet_form'] > 0) ? (int)$_GET['mailpoet_form'] : null;
$form = Form::findOne($id);
if($form !== false) {
// render form
$output = Util\Export::get('html', $form->asArray());
// $output = do_shortcode($output);
print $output;
exit;
}
break;
default:
// add_filter('wp_title', 'mailpoet_meta_page_title'));
add_filter('the_title', 'mailpoet_page_title', 10, 2);
add_filter('the_content', 'mailpoet_page_content', 98, 1);
break;
}
}
function mailpoet_page_title($title = '', $id = null) {
// get signup confirmation page id
$signup_confirmation = Setting::getValue('signup_confirmation');
$page_id = $signup_confirmation['page'];
// check if we're on the signup confirmation page
if((int)$page_id === (int)$id) {
global $post;
// disable comments
$post->comment_status = 'close';
// disable password
$post->post_password = '';
$subscriber = null;
// get subscriber key from url
$subscriber_digest = (isset($_GET['mailpoet_key']) && strlen(trim($_GET['mailpoet_key'])) === 32) ? trim($_GET['mailpoet_key']) : null;
if($subscriber_digest !== null) {
// get subscriber
// TODO: change select() to selectOne() once it's implemented
$subscribers = $mailpoet->subscribers()->select(array(
'filter' => array(
'subscriber_digest' => $subscriber_digest
),
'limit' => 1
));
if(!empty($subscribers)) {
$subscriber = array_shift($subscribers);
}
}
// check if we have a subscriber record
if($subscriber === null) {
return __('Your confirmation link expired, please subscribe again.');
} else {
// we have a subscriber, let's check its state
switch($subscriber['subscriber_state']) {
case MailPoetSubscribers::STATE_UNCONFIRMED:
case MailPoetSubscribers::STATE_UNSUBSCRIBED:
// set subscriber state as confirmed
$mailpoet->subscribers()->update(array(
'subscriber' => $subscriber['subscriber'],
'subscriber_state' => MailPoetSubscribers::STATE_SUBSCRIBED,
'subscriber_confirmed_at' => time()
));
return __("You've subscribed");
break;
case MailPoetSubscribers::STATE_SUBSCRIBED:
return __("You've already subscribed");
break;
}
}
} else {
return $title;
}
}
function mailpoet_page_content($content = '') {
if(strpos($content, '[mailpoet_page]') !== FALSE) {
$content = str_replace('[mailpoet_page]', '', $content);
}
return $content;
}

View File

@ -1,36 +0,0 @@
<?php
namespace MailPoet\Listing;
if(!defined('ABSPATH')) exit;
class ItemAction {
private $model = null;
private $action = null;
private $data = null;
function __construct($model_class, $data) {
$id = (int)$data['id'];
unset($data['id']);
$this->action = $data['action'];
unset($data['action']);
$this->model = $model_class::findOne($id);
if(!empty($data)) {
$this->data = $data;
}
return $this;
}
function apply() {
if($this->data === null) {
return call_user_func_array(
array($this->model, $this->action),
array()
);
} else {
return call_user_func_array(
array($this->model, $this->action),
array($this->data)
);
}
}
}

View File

@ -16,6 +16,27 @@ class CustomField extends Model {
));
}
function asArray() {
$model = parent::asArray();
$model['params'] = (
is_serialized($this->params)
? unserialize($this->params)
: $this->params
);
return $model;
}
function save() {
$this->set('params', (
is_serialized($this->params)
? $this->params
: serialize($this->params)
));
return parent::save();
}
function subscribers() {
return $this->has_many_through(
__NAMESPACE__ . '\Subscriber',
@ -24,4 +45,33 @@ class CustomField extends Model {
'subscriber_id'
)->select_expr(MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.value');
}
static function createOrUpdate($data = array()) {
$custom_field = false;
if(isset($data['id']) && (int)$data['id'] > 0) {
$custom_field = self::findOne((int)$data['id']);
}
// set name as label by default
if(empty($data['params']['label'])) {
$data['params']['label'] = $data['name'];
}
if($custom_field === false) {
$custom_field = self::create();
$custom_field->hydrate($data);
} else {
unset($data['id']);
$custom_field->set($data);
}
try {
$custom_field->save();
return $custom_field;
} catch(Exception $e) {
return $custom_field->getValidationErrors();
}
return false;
}
}

View File

@ -14,6 +14,37 @@ class Form extends Model {
));
}
function asArray() {
$model = parent::asArray();
$model['body'] = (
is_serialized($this->body)
? unserialize($this->body)
: $this->body
);
$model['settings'] = (
is_serialized($this->settings)
? unserialize($this->settings)
: $this->settings
);
return $model;
}
function save() {
$this->set('body', (
is_serialized($this->body)
? $this->body
: serialize($this->body)
));
$this->set('settings', (
is_serialized($this->settings)
? $this->settings
: serialize($this->settings)
));
return parent::save();
}
static function search($orm, $search = '') {
return $orm->where_like('name', '%'.$search.'%');
}
@ -56,57 +87,7 @@ class Form extends Model {
$form->set($data);
}
$saved = $form->save();
if($saved === true) {
return true;
} else {
$errors = $form->getValidationErrors();
if(!empty($errors)) {
return $errors;
}
}
return false;
}
static function trash($listing, $data = array()) {
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
if($confirm_delete) {
// delete relations with all segments
$forms = $listing->getSelection()->findResultSet();
if(!empty($forms)) {
$forms_count = 0;
foreach($forms as $form) {
if($form->delete()) {
$forms_count++;
}
}
return array(
'segments' => $forms_count
);
}
return false;
} else {
// soft delete
$forms = $listing->getSelection()
->findResultSet()
->set_expr('deleted_at', 'NOW()')
->save();
return array(
'segments' => $forms->count()
);
}
}
static function restore($listing, $data = array()) {
$forms = $listing->getSelection()
->findResultSet()
->set_expr('deleted_at', 'NULL')
->save();
return array(
'segments' => $forms->count()
);
$form->save();
return $form;
}
}

View File

@ -10,6 +10,13 @@ class Newsletter extends Model {
parent::__construct();
}
function save() {
if(is_string($this->deleted_at) && strlen(trim($this->deleted_at)) === 0) {
$this->set_expr('deleted_at', 'NULL');
}
return parent::save();
}
function segments() {
return $this->has_many_through(
__NAMESPACE__.'\Segment',
@ -131,16 +138,7 @@ class Newsletter extends Model {
$newsletter->set($data);
}
$saved = $newsletter->save();
if($saved === true) {
return $newsletter->id();
} else {
$errors = $newsletter->getValidationErrors();
if(!empty($errors)) {
return $errors;
}
}
return false;
$newsletter->save();
return $newsletter;
}
}

View File

@ -29,6 +29,44 @@ class Segment extends Model {
);
}
function subscribers() {
return $this->has_many_through(
__NAMESPACE__.'\Subscriber',
__NAMESPACE__.'\SubscriberSegment',
'segment_id',
'subscriber_id'
);
}
function duplicate($data = array()) {
$duplicate = parent::duplicate($data);
if($duplicate !== false) {
foreach($this->subscribers()->findResultSet() as $relation) {
$new_relation = SubscriberSegment::create();
$new_relation->set('subscriber_id', $relation->id);
$new_relation->set('segment_id', $duplicate->id);
$new_relation->save();
}
return $duplicate;
}
return false;
}
function addSubscriber($subscriber_id) {
$relation = SubscriberSegment::create();
$relation->set('subscriber_id', $subscriber_id);
$relation->set('segment_id', $this->id);
return $relation->save();
}
function removeSubscriber($subscriber_id) {
return SubscriberSegment::where('subscriber_id', $subscriber_id)
->where('segment_id', $this->id)
->delete();
}
static function search($orm, $search = '') {
return $orm->where_like('name', '%'.$search.'%');
}
@ -71,41 +109,7 @@ class Segment extends Model {
$segment->set($data);
}
$saved = $segment->save();
if($saved === true) {
return true;
} else {
$errors = $segment->getValidationErrors();
if(!empty($errors)) {
return $errors;
}
}
return false;
}
function duplicate($data = array()) {
$duplicate = parent::duplicate($data);
if($duplicate !== false) {
foreach($this->subscribers()->findResultSet() as $relation) {
$new_relation = SubscriberSegment::create();
$new_relation->set('subscriber_id', $relation->id);
$new_relation->set('segment_id', $duplicate->id);
$new_relation->save();
}
return $duplicate;
}
return false;
}
function subscribers() {
return $this->has_many_through(
__NAMESPACE__.'\Subscriber',
__NAMESPACE__.'\SubscriberSegment',
'segment_id',
'subscriber_id'
);
$segment->save();
return $segment;
}
}

View File

@ -15,7 +15,16 @@ class Subscriber extends Model {
));
}
function delete() {
function segments() {
return $this->has_many_through(
__NAMESPACE__.'\Segment',
__NAMESPACE__.'\SubscriberSegment',
'subscriber_id',
'segment_id'
);
}
function delete() {
// delete all relations to segments
SubscriberSegment::where('subscriber_id', $this->id)->deleteMany();
@ -42,7 +51,9 @@ class Subscriber extends Model {
);
foreach($segments as $segment) {
$subscribers_count = $segment->subscribers()->count();
$subscribers_count = $segment->subscribers()
->whereNull('deleted_at')
->count();
if($subscribers_count > 0) {
$segment_list[] = array(
'label' => sprintf('%s (%d)', $segment->name, $subscribers_count),
@ -83,23 +94,17 @@ class Subscriber extends Model {
array(
'name' => 'subscribed',
'label' => __('Subscribed'),
'count' => Subscriber::whereNull('deleted_at')
->where('status', 'subscribed')
->count()
'count' => Subscriber::filter('subscribed')->count()
),
array(
'name' => 'unconfirmed',
'label' => __('Unconfirmed'),
'count' => Subscriber::whereNull('deleted_at')
->where('status', 'unconfirmed')
->count()
'count' => Subscriber::filter('unconfirmed')->count()
),
array(
'name' => 'unsubscribed',
'label' => __('Unsubscribed'),
'count' => Subscriber::whereNull('deleted_at')
->where('status', 'unsubscribed')
->count()
'count' => Subscriber::filter('unsubscribed')->count()
),
array(
'name' => 'trash',
@ -112,12 +117,10 @@ class Subscriber extends Model {
static function groupBy($orm, $group = null) {
if($group === 'trash') {
return $orm->whereNotNull('deleted_at');
} else if($group === 'all') {
return $orm->whereNull('deleted_at');
} else {
$orm = $orm->whereNull('deleted_at');
if(in_array($group, array('subscribed', 'unsubscribed', 'unconfirmed'))) {
return $orm->where('status', $group);
}
return $orm->filter($group);
}
}
@ -143,15 +146,6 @@ class Subscriber extends Model {
return $orm;
}
function segments() {
return $this->has_many_through(
__NAMESPACE__.'\Segment',
__NAMESPACE__.'\SubscriberSegment',
'subscriber_id',
'segment_id'
);
}
function customFields() {
return $this->has_many_through(
__NAMESPACE__.'\CustomField',
@ -166,27 +160,18 @@ class Subscriber extends Model {
if(isset($data['id']) && (int)$data['id'] > 0) {
$subscriber = self::findOne((int)$data['id']);
unset($data['id']);
}
if($subscriber === false) {
$subscriber = self::create();
$subscriber->hydrate($data);
} else {
unset($data['id']);
$subscriber->set($data);
}
$saved = $subscriber->save();
if($saved === true) {
return true;
} else {
$errors = $subscriber->getValidationErrors();
if(!empty($errors)) {
return $errors;
}
}
return false;
$subscriber->save();
return $subscriber;
}
static function bulkMoveToList($orm, $data = array()) {
@ -299,4 +284,22 @@ class Subscriber extends Model {
}
return false;
}
static function subscribed($orm) {
return $orm
->whereNull('deleted_at')
->where('status', 'subscribed');
}
static function unsubscribed($orm) {
return $orm
->whereNull('deleted_at')
->where('status', 'unsubscribed');
}
static function unconfirmed($orm) {
return $orm
->whereNull('deleted_at')
->where('status', 'unconfirmed');
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace MailPoet\Router;
use \MailPoet\Models\CustomField;
if(!defined('ABSPATH')) exit;
class CustomFields {
function __construct() {
}
function getAll() {
$collection = CustomField::findMany();
$custom_fields = array_map(function($custom_field) {
return $custom_field->asArray();
}, $collection);
wp_send_json($custom_fields);
}
function delete($id) {
$result = false;
$custom_field = CustomField::findOne($id);
if($custom_field !== false) {
$custom_field->delete();
$result = true;
}
wp_send_json($result);
}
function save($data = array()) {
$custom_field = CustomField::createOrUpdate($data);
if($custom_field === false) {
$result = array(
'result' => false,
'errors' => array(
__('The custom field could not be created.')
)
);
} else {
$errors = $custom_field->getValidationErrors();
if(!empty($errors)) {
$result = array(
'result' => false,
'errors' => $errors
);
} else {
$result = array(
'result' => true,
'field' => $custom_field->asArray()
);
}
}
wp_send_json($result);
}
function get($id) {
$custom_field = CustomField::findOne($id);
if($custom_field === false) {
wp_send_json(false);
} else {
$custom_field = $custom_field->asArray();
wp_send_json($custom_field);
}
}
}

View File

@ -1,7 +1,9 @@
<?php
namespace MailPoet\Router;
use \MailPoet\Models\Form;
use \MailPoet\Form\Renderer as FormRenderer;
use \MailPoet\Listing;
use \MailPoet\Form\Util;
if(!defined('ABSPATH')) exit;
@ -16,7 +18,8 @@ class Forms {
if($form === false) {
wp_send_json(false);
} else {
wp_send_json($form->asArray());
$form = $form->asArray();
wp_send_json($form);
}
}
@ -28,6 +31,22 @@ class Forms {
$listing_data = $listing->get();
// fetch segments relations for each returned item
foreach($listing_data['items'] as &$item) {
// form's segments
$form_settings = (
(is_serialized($item['settings']))
? unserialize($item['settings'])
: array()
);
$item['segments'] = (
!empty($form_settings['segments'])
? $form_settings['segments']
: array()
);
}
wp_send_json($listing_data);
}
@ -36,55 +55,199 @@ class Forms {
wp_send_json($collection);
}
function save($data = array()) {
$result = Form::createOrUpdate($data);
function create() {
// create new form
$form_data = array(
'name' => __('New form'),
'body' => array(
array(
'id' => 'email',
'name' => __('Email'),
'type' => 'input',
'static' => true,
'params' => array(
'label' => __('Email'),
'required' => true
)
),
array(
'id' => 'submit',
'name' => __('Submit'),
'type' => 'submit',
'static' => true,
'params' => array(
'label' => __('Subscribe!')
)
)
),
'settings' => array(
'on_success' => 'message',
'success_message' => __('Check your inbox or spam folder now to confirm your subscription.'),
'segments' => null,
'segments_selected_by' => 'admin'
)
);
if($result !== true) {
wp_send_json($result);
$form = Form::createOrUpdate($form_data);
if($form !== false && $form->id()) {
wp_send_json(
admin_url('admin.php?page=mailpoet-form-editor&id='.$form->id())
);
} else {
wp_send_json(true);
wp_send_json(false);
}
}
function save($data = array()) {
$form = Form::createOrUpdate($data);
if($form !== false && $form->id()) {
wp_send_json($form->id());
} else {
wp_send_json($form);
}
}
function previewEditor($data = array()) {
// html
$html = FormRenderer::renderHTML($data);
// convert shortcodes
$html = do_shortcode($html);
// styles
$css = new Util\Styles(FormRenderer::getStyles($data));
wp_send_json(array(
'html' => $html,
'css' => $css->render()
));
}
function exportsEditor($id) {
$exports = false;
$form = Form::findOne($id);
if($form !== false) {
$exports = Util\Export::getAll($form->asArray());
}
wp_send_json($exports);
}
function saveEditor($data = array()) {
$form_id = (isset($data['id']) ? (int)$data['id'] : 0);
$body = (isset($data['body']) ? $data['body'] : array());
$settings = (isset($data['settings']) ? $data['settings'] : array());
$styles = (isset($data['styles']) ? $data['styles'] : array());
if(empty($body) || empty($settings)) {
// error
wp_send_json(false);
} else {
// check if the form is used as a widget
$is_widget = false;
$widgets = get_option('widget_mailpoet_form');
if(!empty($widgets)) {
foreach($widgets as $widget) {
if(isset($widget['form']) && (int)$widget['form'] === $form_id) {
$is_widget = true;
break;
}
}
}
// check if the user gets to pick his own lists
// or if it's selected by the admin
$has_segment_selection = false;
foreach ($body as $i => $block) {
if($block['type'] === 'segment') {
$has_segment_selection = true;
if(!empty($block['params']['values'])) {
$list_selection = array_map(function($segment) {
if(!empty($segment)) {
return (int)$segment['id'];
}
}, $block['params']['values']);
}
break;
}
}
// check list selectio
if($has_segment_selection === true) {
$settings['segments_selected_by'] = 'user';
} else {
$settings['segments_selected_by'] = 'admin';
}
}
$form = Form::createOrUpdate(array(
'id' => $form_id,
'body' => $body,
'settings' => $settings,
'styles' => $styles
));
// response
wp_send_json(array(
'result' => ($form !== false),
'is_widget' => $is_widget
));
}
function restore($id) {
$result = false;
$form = Form::findOne($id);
if($form !== false) {
$form->set_expr('deleted_at', 'NULL');
$result = $form->save();
} else {
$result = false;
$result = $form->restore();
}
wp_send_json($result);
}
function delete($data = array()) {
$form = Form::findOne($data['id']);
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
function trash($id) {
$result = false;
$form = Form::findOne($id);
if($form !== false) {
if($confirm_delete) {
$form->delete();
$result = true;
} else {
$form->set_expr('deleted_at', 'NOW()');
$result = $form->save();
}
} else {
$result = false;
$result = $form->trash();
}
wp_send_json($result);
}
function delete($id) {
$result = false;
$form = Form::findOne($id);
if($form !== false) {
$form->delete();
$result = 1;
}
wp_send_json($result);
}
function duplicate($id) {
$result = false;
$form = Form::duplicate($id);
$form = Form::findOne($id);
if($form !== false) {
$result = $form;
$data = array(
'name' => sprintf(__('Copy of %s'), $form->name)
);
$result = $form->duplicate($data)->asArray();
}
wp_send_json($result);
}
function bulk_action($data = array()) {
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Form',
$data

View File

@ -54,29 +54,34 @@ class Newsletters {
unset($data['options']);
}
$newsletter_id = Newsletter::createOrUpdate($data);
$newsletter = Newsletter::createOrUpdate($data);
if($newsletter_id !== false) {
if($newsletter->id) {
if(!empty($segment_ids)) {
// remove previous relationships with segments
NewsletterSegment::where('newsletter_id', $newsletter_id)->deleteMany();
// create relationship with segments
NewsletterSegment::where('newsletter_id', $newsletter->id)
->deleteMany();
foreach($segment_ids as $segment_id) {
$relation = NewsletterSegment::create();
$relation->segment_id = $segment_id;
$relation->newsletter_id = $newsletter_id;
$relation->newsletter_id = $newsletter->id;
$relation->save();
}
}
if(!empty($options)) {
NewsletterOption::where('newsletter_id', $newsletter_id)->deletemany();
$optionFields = NewsletterOptionField::where('newsletter_type', $data['type'])->findArray();
NewsletterOption::where('newsletter_id', $newsletter->id)
->deleteMany();
$optionFields = NewsletterOptionField::where(
'newsletter_type',
$data['type']
)->findArray();
foreach($optionFields as $optionField) {
if(isset($options[$optionField['name']])) {
$relation = NewsletterOption::create();
$relation->newsletter_id = $newsletter_id;
$relation->newsletter_id = $newsletter->id;
$relation->option_field_id = $optionField['id'];
$relation->value = $options[$optionField['name']];
$relation->save();
@ -85,7 +90,7 @@ class Newsletters {
}
}
wp_send_json(($newsletter_id !== false));
wp_send_json(($newsletter->id !== false));
}
function delete($data = array()) {
@ -199,7 +204,7 @@ class Newsletters {
wp_send_json($listing_data);
}
function bulk_action($data = array()) {
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Newsletter',
$data

View File

@ -128,16 +128,7 @@ class Segments {
wp_send_json($result);
}
function item_action($data = array()) {
$item_action = new Listing\ItemAction(
'\MailPoet\Models\Segment',
$data
);
wp_send_json($item_action->apply());
}
function bulk_action($data = array()) {
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Segment',
$data

View File

@ -4,6 +4,9 @@ namespace MailPoet\Router;
use MailPoet\Listing;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Models\Segment;
use MailPoet\Models\Setting;
use MailPoet\Models\Form;
if(!defined('ABSPATH')) exit;
@ -55,10 +58,199 @@ class Subscribers {
}
function save($data = array()) {
$result = Subscriber::createOrUpdate($data);
$result = false;
$subscriber = Subscriber::createOrUpdate($data);
if($subscriber !== false && !$subscriber->id()) {
$result = array(
'errors' => $subscriber->getValidationErrors()
);
} else {
$result = true;
}
wp_send_json($result);
}
function subscribe($data = array()) {
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
$errors = array();
$form = Form::findOne($data['form_id']);
unset($data['form_id']);
if($form === false || !$form->id()) {
$errors[] = __('This form does not exist.');
}
if(empty($data['segments'])) {
$errors[] = __('You need to select a list');
} else {
$segments = Segment::whereIn('id', (array)$data['segments'])->findMany();
if(empty($segments)) {
$errors[] = __('You need to select a list');
}
}
unset($data['segments']);
$subscriber = false;
if(!empty($errors)) {
wp_send_json(array('errors' => $errors));
} else {
if(!empty($data['email'])) {
$subscriber = Subscriber::where('email', $data['email'])->findOne();
}
}
$signup_confirmation = Setting::getValue('signup_confirmation', array());
if($subscriber === false) {
// create new subscriber
$data['status'] = (
(!empty($signup_confirmation['enabled']))
? 'unconfirmed' : 'subscribed'
);
// // set custom fields
// $meta_fields = $mailpoet->getOption('mailpoet_subscriber_meta', array());
// if(!empty($meta_fields)) {
// // loop through data to see if any meta field has been passed
// foreach($meta_fields as $field => $field_data) {
// // check if it's a mandatory field
// $is_required = (isset($field_data['params']['required']) && (bool)$field_data['params']['required'] === true);
// if(array_key_exists($field, $data)) {
// // check if it's a mandatory field
// if($is_required === true && empty($data[$field])) {
// // if it's missing, throw an error
// $errors[] = sprintf(__('&quot;%s&quot; is required'), $field_data['name']);
// } else {
// // assign field to subscriber
// $subscriber[$field] = $data[$field];
// }
// }
// }
// }
// insert new subscriber
$subscriber = Subscriber::createOrUpdate($data);
if($subscriber === false || !$subscriber->id()) {
$errors = array_merge($errors, $subscriber->getValidationErrors());
}
} else {
$subscriber->set('status', (
!empty($signup_confirmation['enabled'])
? 'unconfirmed' : 'subscribed'
));
// restore deleted subscriber
if($subscriber->deleted_at !== NULL) {
$subscriber->setExpr('deleted_at', 'NULL');
}
if(!$subscriber->save()) {
$errors[] = __('An error occurred. Please try again later.');
}
}
// get segments
// IDEA: $subscriptions->addToSegments($data['segments']);
$segments_subscribed = array();
foreach($segments as $segment) {
if($segment->addSubscriber($subscriber->id())) {
$segments_subscribed[] = $segment->id;
}
}
// if signup confirmation is enabled and the subscriber is unconfirmed
if(!empty($signup_confirmation['enabled'])
&& !empty($segments_subscribed)
&& $subscriber->status !== 'subscribed'
) {
// TODO: send confirmation email
// resend confirmation email
$is_sent = true;
/*$is_sent = static::sendSignupConfirmation(
$subscriber->asArray(),
$segments->asArray()
);*/
// error message if the email could not be sent
if($is_sent === false) {
$errors[] = __('The signup confirmation email could not be sent. Please check your settings.');
}
}
// get success message to display after subscription
$form_settings = (
isset($form->settings)
? unserialize($form->settings) : null
);
if(!empty($errors)) {
wp_send_json(array(
'result' => false,
'errors' => $errors
));
} else {
$result = true;
}
if($form_settings !== null) {
$message = $form_settings['success_message'];
// url params for non ajax requests
if($doing_ajax === false) {
// get referer
$referer = (wp_get_referer() !== false)
? wp_get_referer() : $_SERVER['HTTP_REFERER'];
// redirection parameters
$params = array(
'mailpoet_form' => $form->id()
);
// handle success/error messages
if($result === false) {
$params['mailpoet_error'] = urlencode($message);
} else {
$params['mailpoet_success'] = urlencode($message);
}
}
switch ($form_settings['on_success']) {
case 'page':
// response depending on context
if($doing_ajax === true) {
wp_send_json(array(
'result' => $result,
'page' => get_permalink($form_settings['success_page']),
'message' => $message
));
} else {
$redirect_to = ($result === false) ? $referer : get_permalink($form_settings['success_page']);
wp_redirect(add_query_arg($params, $redirect_to));
}
break;
case 'message':
default:
// response depending on context
if($doing_ajax === true) {
wp_send_json(array(
'result' => $result,
'message' => $message
));
} else {
// redirect to previous page
wp_redirect(add_query_arg($params, $referer));
}
break;
}
}
}
function restore($id) {
$result = false;
@ -93,16 +285,7 @@ class Subscribers {
wp_send_json($result);
}
function item_action($data = array()) {
$item_action = new Listing\ItemAction(
'\MailPoet\Models\Segment',
$data
);
wp_send_json($item_action->apply());
}
function bulk_action($data = array()) {
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Subscriber',
$data

View File

@ -51,9 +51,13 @@ class Handlebars extends \Twig_Extension {
if($alias !== null) {
$output[] = '<script type="text/javascript">';
$output[] = ' Handlebars.registerPartial(
"'.$alias.'",
jQuery("#'.$id.'").html());';
$output[] = 'jQuery(function($) {';
$output[] = '$(function() {';
$output[] = ' Handlebars.registerPartial(
"'.$alias.'",
jQuery("#'.$id.'").html());';
$output[] = '});';
$output[] = '});';
$output[] = '</script>';
}
return join("\n", $output);

View File

@ -5,7 +5,7 @@ if (!defined('ABSPATH')) exit;
/*
* Plugin Name: MailPoet
* Version: 0.0.1
* Version: 0.0.3
* Plugin URI: http://www.mailpoet.com
* Description: MailPoet Newsletters.
* Author: MailPoet
@ -18,12 +18,12 @@ if (!defined('ABSPATH')) exit;
*
* @package WordPress
* @author MailPoet
* @since 0.0.1
* @since 0.0.3
*/
require 'vendor/autoload.php';
define('MAILPOET_VERSION', '0.0.1');
define('MAILPOET_VERSION', '0.0.3');
$initializer = new Initializer(array(
'file' => __FILE__,

View File

@ -4,6 +4,8 @@
"install": "napa"
},
"napa": {
"blob": "eligrey/Blob.js.git",
"filesaver": "eligrey/FileSaver.js.git",
"sticky-kit": "leafo/sticky-kit.git"
},
"dependencies": {
@ -13,19 +15,19 @@
"backbone.supermodel": "1.2.0",
"c3": "~0.4.10",
"classnames": "^2.1.3",
"codemirror": "^5.5.0",
"codemirror": "^5.8.0",
"d3": "~3.5.5",
"handlebars": "3.0.3",
"history": "^1.12.5",
"html2canvas": "latest",
"interact.js": "latest",
"jquery-validation": "^1.14.0",
"moment": "^2.10.3",
"napa": "^1.2.0",
"papaparse": "4.1.1",
"react": "0.14.0",
"parsley": "^0.1.0",
"react": "^0.14.1",
"react-checkbox-group": "0.2.2",
"react-dom": "^0.14.0",
"react-dom": "^0.14.1",
"react-infinity": "1.2.2",
"react-prefixr": "0.1.0",
"react-router": "^1.0.0-rc3",

View File

@ -65,6 +65,6 @@ class WPMailCest {
$this->newsletter,
$this->subscriber
);
expect($result)->true();
//expect($result)->true();
}
}

View File

@ -0,0 +1,84 @@
<?php
use MailPoet\Models\Form;
class FormCest {
function _before() {
$this->before_time = time();
$this->data = array(
'name' => 'my form',
);
$this->form = Form::create();
$this->form->hydrate($this->data);
$this->saved = $this->form->save();
}
function itCanBeCreated() {
expect($this->saved)->equals(true);
}
function itHasToBeValid() {
expect($this->saved)->equals(true);
$empty_model = Form::create();
expect($empty_model->save())->notEquals(true);
$validations = $empty_model->getValidationErrors();
expect(count($validations))->equals(1);
}
function itHasACreatedAtOnCreation() {
$form = Form::where('name', $this->data['name'])
->findOne();
$time_difference = strtotime($form->created_at) >= $this->before_time;
expect($time_difference)->equals(true);
}
function itHasAnUpdatedAtOnCreation() {
$form = Form::where('name', $this->data['name'])
->findOne();
$time_difference = strtotime($form->updated_at) >= $this->before_time;
expect($time_difference)->equals(true);
}
function itKeepsTheCreatedAtOnUpdate() {
$form = Form::where('name', $this->data['name'])
->findOne();
$old_created_at = $form->created_at;
$form->name = 'new name';
$form->save();
expect($old_created_at)->equals($form->created_at);
}
function itUpdatesTheUpdatedAtOnUpdate() {
$form = Form::where('name', $this->data['name'])
->findOne();
$update_time = time();
$form->name = 'new name';
$form->save();
$time_difference = strtotime($form->updated_at) >= $update_time;
expect($time_difference)->equals(true);
}
function itCanCreateOrUpdate() {
$is_created = Form::createOrUpdate(array(
'name' => 'new form'
));
expect($is_created)->notEquals(false);
expect($is_created->getValidationErrors())->isEmpty();
$form = Form::where('name', 'new form')->findOne();
expect($form->name)->equals('new form');
$is_updated = Form::createOrUpdate(array(
'id' => $form->id,
'name' => 'updated form'
));
$form = Form::where('name', 'updated form')->findOne();
expect($form->name)->equals('updated form');
}
function _after() {
ORM::forTable(Form::$_table)
->deleteMany();
}
}

View File

@ -80,7 +80,7 @@ class NewsletterCest {
'body' => 'body'
));
expect($is_created)->notEquals(false);
expect($is_created)->greaterThan(0);
expect($is_created->getValidationErrors())->isEmpty();
$newsletter = Newsletter::where('subject', 'new newsletter')
->findOne();

View File

@ -67,7 +67,8 @@ class SegmentCest {
$is_created = Segment::createOrUpdate(array(
'name' => 'new list'
));
expect($is_created)->equals(true);
expect($is_created)->notEquals(false);
expect($is_created->getValidationErrors())->isEmpty();
$segment = Segment::where('name', 'new list')->findOne();
expect($segment->name)->equals('new list');

View File

@ -137,7 +137,7 @@ class SubscriberCest {
->findOne($this->subscriber->id);
expect($subscriber->DOB)->equals($association->value);
}
function itCanFilterCustomFields() {
$customFieldData = array(
array(
@ -270,14 +270,17 @@ class SubscriberCest {
'last_name' => 'Doe'
);
$result = Subscriber::createOrUpdate($data);
expect($result)->equals(true);
expect($result)->notEquals(false);
expect($result->getValidationErrors())->isEmpty();
$record = Subscriber::where('email', $data['email'])
->findOne();
expect($record->first_name)->equals($data['first_name']);
expect($record->last_name)->equals($data['last_name']);
$record->last_name = 'Mailer';
$result = Subscriber::createOrUpdate($record->asArray());
expect($result)->equals(true);
expect($result)->notEquals(false);
expect($result->getValidationErrors())->isEmpty();
$record = Subscriber::where('email', $data['email'])
->findOne();
expect($record->last_name)->equals('Mailer');

View File

@ -2,7 +2,7 @@
<% block title %>
<h2 class="title">
<span id="mailpoet_form_name"><%= form.form_name %></span>
<span id="mailpoet_form_name"><%= form.name %></span>
<input id="mailpoet_form_name_input" type="text" value="" style="display:none;" />
<span>
<a id="mailpoet_form_edit_name" class="button" href="javascript:;"><%= __('Edit name' ) %></a>
@ -34,24 +34,26 @@
<div>
<!-- Form settings -->
<form id="mailpoet_form_settings" action="" method="POST">
<div id="mailpoet_settings_list_selection">
<input
type="hidden"
id="mailpoet_form_id"
value="<%= form.id | default(0) %>"
/>
<div id="mailpoet_settings_segment_selection">
<!-- Form settings: list selection -->
<p>
<strong><%= __('This form adds subscribers to these lists:') %></strong>
</p>
<select name="lists" data-placeholder="<%= __('Choose a list') %>" multiple>
<% for list in lists %>
<option value="<%= list.id %>"
<% if list.id in form.data.settings.lists %>
selected="selected"
<% endif %>
><%= list.name %></option>
<select
id="mailpoet_form_segments"
name="segments"
data-placeholder="<%= __('Choose a list') %>"
multiple
>
<% for segment in segments %>
<option value="<%= segment.id %>"><%= segment.name %></option>
<% endfor %>
</select>
<!-- error if user tries to save and has not selected a list -->
<p class="mailpoet_error" data-error="admin_no_list">
<%= __('You have to select at least 1 list') %>
</p>
</div>
<div id="mailpoet_on_success">
@ -63,6 +65,9 @@
type="radio"
name="on_success"
value="message"
<% if(form.data.settings.on_success is empty or form.data.settings.on_success == 'message') %>
checked="checked"
<% endif %>
/><%= __('Show message') %>
</label>
&nbsp;
@ -71,6 +76,9 @@
type="radio"
name="on_success"
value="page"
<% if(form.data.settings.on_success == 'page') %>
checked="checked"
<% endif %>
/><%= __('Go to page') %>
</label>
</p>
@ -93,10 +101,10 @@
>
<select name="success_page">
<% for page in pages %>
<option value="<%= page.ID %>"
<%- if form.data.settings.success_page != page.ID %>
<option value="<%= page.id %>"
<%- if form.data.settings.success_page != page.id %>
<%=- ' selected="selected"' %>
<%- endif %>><%= page.post_title %></option>
<%- endif %>><%= page.title %></option>
<% endfor %>
</select>
</p>
@ -105,39 +113,42 @@
</div>
</div>
<!-- Toolbar: Shortcodes / Export -->
<div class="mailpoet_toolbar_section closed" data-section="shortcodes">
<a href="javascript:;" class="mailpoet_toggle"><br /></a>
<h3><%= __('Shortcodes') %></h3>
<!-- Toolbar: Shortcodes / Export -->
<div class="mailpoet_toolbar_section closed" data-section="shortcodes">
<a href="javascript:;" class="mailpoet_toggle"><br /></a>
<h3><%= __('Shortcodes') %></h3>
<div>
<!-- Form export links -->
<p>
<%= __("You can easily add this form to your theme's in the %sWidgets area%s")
| format('<a href="widgets.php" target="_blank">', '</a>')
| raw
%>
</p>
<p>
<%= __('%sHTML%s, %sPHP%s, %siframe%s and %sshortcode%s versions are also available.', 'wysija-newsletters')
| format(
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="html">',
'</a>',
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="php">',
'</a>',
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="iframe">',
'</a>',
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="shortcode">',
'</a>'
)
| raw
%>
</p>
<div>
<!-- Form export links -->
<p>
<%= __("You can easily add this form to your theme's in the [link]Widgets area[/link]")
| replace({
'[link]': '<a href="widgets.php" target="_blank">',
'[/link]': '</a>'
})
| raw
%>
</p>
<p>
<%= __('%sHTML%s, %sPHP%s, %siframe%s and %sshortcode%s versions are also available.', 'wysija-newsletters')
| format(
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="html">',
'</a>',
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="php">',
'</a>',
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="iframe">',
'</a>',
'<a href="javascript:;" class="mailpoet_form_export_toggle" data-type="shortcode">',
'</a>'
)
| raw
%>
</p>
<!-- Form export -->
<div id="mailpoet_form_export"></div>
</div>
<!-- Form export -->
<div id="mailpoet_form_export"></div>
</div>
</div>
<!-- Toolbar: Fields -->
<div class="mailpoet_toolbar_section closed" data-section="fields">
@ -161,7 +172,14 @@
<div>
<textarea id="mailpoet_form_styles"><%= styles %></textarea>
<br />
<p class="mailpoet_align_center"><a id="mailpoet_form_preview" href="javascript:;" class="button button-primary" style="width:100%;"><%= __('Preview') %></a></p>
<p class="mailpoet_align_center">
<a
id="mailpoet_form_preview"
href="javascript:;"
class="button button-primary"
style="width:100%;"
><%= __('Preview') %></a>
</p>
</div>
</div>
@ -173,100 +191,110 @@
</div>
<%= javascript(
'vendor.js',
'lib/prototype.min.js',
'lib/select2.js',
'lib/scriptaculous.min.js',
'lib/codemirror/codemirror.js',
'lib/codemirror/syntax_php.js',
'lib/codemirror/syntax_css.js',
'lib/jquery.serializeObject.js',
'form_editor.js'
)%>
<%= stylesheet(
'lib/select2/select2.css',
'lib/codemirror/codemirror.css',
'lib/codemirror/theme_neo.css'
) %>
<script type="text/javascript">
var mailpoet_segments = <%= json_encode(segments) %>;
var mailpoet_default_fields = [
{
id: 'divider',
name: "<%= __('Divider') %>",
type: 'divider',
multiple: true,
readonly: true
},
{
id: "first_name",
name: "<%= __('First name') %>",
type: 'input',
params: {
label: "<%= __('First name') %>"
},
readonly: true
},
{
id: "last_name",
name: "<%= __('Last name') %>",
type: 'input',
params: {
label: "<%= __('Last name') %>"
},
readonly: true
},
{
id: "segments",
name: "<%= __('List selection') %>",
type: 'segment',
params: {
label: "<%= __('Select list(s):') %>"
},
readonly: true
},
{
id: 'html',
name: "<%= __('Random text or HTML') %>",
type: 'html',
params: {
text: "<%= __('Subscribe to our newsletter and join our [mailpoet_subscribers_count] subscribers.') %>"
},
multiple: true,
readonly: true
}
];
jQuery(function($) {
function mailpoet_form_fields(data) {
function mailpoet_form_fields() {
// form editor: default fields
var template = Handlebars.compile(jQuery('#form_template_fields').html());
// render toolbar
jQuery('#mailpoet_toolbar_fields').html(template(data));
var data = {
fields: mailpoet_default_fields
};
// enable code mirror editor on styles textarea
MailPoet.CodeEditor = CodeMirror.fromTextArea(document.getElementById('mailpoet_form_styles'), {
lineNumbers: true,
tabMode: "indent",
matchBrackets: true,
theme: 'neo',
mode: 'css',
return MailPoet.Ajax.post({
endpoint: 'customFields',
action: 'getAll',
}).done(function(response) {
if(response !== false) {
data.fields = $.merge(response, data.fields);
}
// render toolbar
jQuery('#mailpoet_toolbar_fields').html(template(data));
});
}
window.mailpoet_form_fields = mailpoet_form_fields;
// form editor: default fields
var default_fields = [
// enable code mirror editor on styles textarea
MailPoet.CodeEditor = CodeMirror.fromTextArea(
document.getElementById('mailpoet_form_styles'),
{
name: "<%= __('Divider') %>",
field: 'divider',
type: 'divider',
multiple: true,
readonly: true
},
{
name: "<%= __('First name') %>",
field: 'firstname',
type: 'input',
params: {
label: "<%= __('First name') %>"
},
readonly: true
},
{
name: "<%= __('Last name') %>",
field: 'lastname',
type: 'input',
params: {
label: "<%= __('Last name') %>"
},
readonly: true
},
{
name: "<%= __('List selection') %>",
field: 'list',
type: 'list',
params: {
label: "<%= __('Select list(s):') %>",
values: [ <%= default_list | json_encode | raw %> ] // default list
},
readonly: true
},
{
name: "<%= __('Random text or HTML') %>",
field: 'html',
type: 'html',
params: {
text: "<%= __('Subscribe to our newsletter and join our [mailpoet_subscribers_count] subscribers.') %>"
},
multiple: true,
readonly: true
lineNumbers: true,
tabMode: "indent",
matchBrackets: true,
theme: 'neo',
mode: 'css'
}
];
);
// toolbar sections
$(document).on('click', '.mailpoet_toolbar_section.closed', function() {
// close currently opened section
$('.mailpoet_toolbar_section:not(.closed)').addClass('closed');
// open selected section after a mini delay
setTimeout(function() { $(this).removeClass('closed'); }.bind(this), 250);
setTimeout(function() {
$(this).removeClass('closed');
}.bind(this), 250);
return false;
});
// toolbar: open default section
$('.mailpoet_toolbar_section[data-section="settings"]').removeClass('closed');
$('.mailpoet_toolbar_section[data-section="settings"]')
.removeClass('closed');
// form: edit name (in place editor)
$('#mailpoet_form_edit_name').on('click', function() {
@ -282,11 +310,14 @@
})
function mailpoet_edit_form_name() {
var is_editing = $('#mailpoet_form_name').data('mailpoet_editing') || false;
var is_editing = $('#mailpoet_form_name')
.data('mailpoet_editing') || false;
if(!is_editing) {
// set input value and show
$('#mailpoet_form_name_input').val($('#mailpoet_form_name').text()).show();
$('#mailpoet_form_name_input')
.val($('#mailpoet_form_name').text())
.show();
// set editing mode
$('#mailpoet_form_name').data('mailpoet_editing', true);
@ -320,98 +351,92 @@
// save change if necessary
if(new_value !== '' && current_value !== new_value) {
console.log('TODO: form->save', {
form: <%= form.form %>,
form_name: new_value,
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'save',
data: {
id: $('#mailpoet_form_id').val(),
name: new_value
}
}).done(function(response) {
MailPoet.Notice.success(
"<%= __('Form name successfully updated!') %>"
);
});
MailPoet.Notice.success("<%= __('Form name successfully updated!') %>");
}
}
}
// on dom loaded
$(function() {
// load form
WysijaForm.load(<%= form | json_encode | raw %>);
WysijaForm.load(<%= json_encode(form) | raw %>);
// save form
$('#mailpoet_form_save').on('click', function() {
mailpoet_form_save();
mailpoet_form_export();
return false;
});
// preview form
$(document).on('click', '#mailpoet_form_preview', function() {
mailpoet_form_save(mailpoet_form_preview);
//mailpoet_form_save(mailpoet_form_preview);
mailpoet_form_preview();
return false;
});
function mailpoet_form_preview() {
console.log('TODO: form->preview');
/*
MailPoet.Modal.popup({
title: "<%= __('Form preview') %>",
template: $('#mailpoet_form_preview_template').html(),
data: response
});*/
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'previewEditor',
data: WysijaForm.save()
}).done(function(response) {
MailPoet.Modal.popup({
title: "<%= __('Form preview') %>",
template: $('#mailpoet_form_preview_template').html(),
data: response
});
})
}
mailpoet_form_export();
function mailpoet_form_save(callback) {
console.log('TODO: form->save');
var form = WysijaForm.save();
form.id = $('#mailpoet_form_id').val();
// if there is a callback, call it!
if(callback !== undefined) {
callback();
}
/*mailpoet_post_json('form_save.php', {
form: <%= form.form %>,
data: WysijaForm.save()
}, function(response) {
if(response.result === false) {
var error = null;
if(response.error !== undefined) {
// display custom error message
error = $('.mailpoet_error[data-error="'+response.error+'"]');
}
if(error !== null) {
$(error).show();
} else {
// display unknown error message
MailPoet.Notice.error("<%= __('An unknown error occurred. Please try again or get in touch with our support.') %>", { scroll: true });
}
} else {
// if there is a callback, call it!
if(callback !== undefined) {
callback();
} else {
// otherwise display a success message
$success_message = str_replace(array(
'[link_widget]',
'[/link_widget]'
), array(
'<a href="'.admin_url('widgets.php').'" target="_blank">',
'</a>'
),
__('Saved! Add this form to [link_widget]a widget[/link_widget].')
);
?>
var success_message = "<?php echo addslashes($success_message); ?>";
if(response.is_widget === true) {
success_message = "<?php esc_html_e("Saved! The changes are already active in your widget."); ?>";
}
// display success message and scroll to it
MailPoet.Notice.hide(true);
MailPoet.Notice.success(success_message, { scroll: true, static: true });
}
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'saveEditor',
data: form
}).done(function(response) {
if(response === false) {
MailPoet.Notice.error(
"<%= __('An error occured, please reload the page and try again.') %>"
);
return false;
}
});*/
var message = null;
if(response.is_widget === true) {
message = "<%= __('Saved! The changes are already active in your widget.') %>";
} else {
message = "<%= __('Saved! Add this form to %1$sa widget%2$s.') | format("<a href='widgets.php' target='_blank'>", '</a>') | raw %>";
}
if(message !== null) {
MailPoet.Notice.hide();
MailPoet.Notice.success(message, {
scroll: true,
static: (response.is_widget === false)
});
}
// if there is a callback, call it!
if(callback !== undefined) {
callback();
}
});
}
// toolbar: on success toggle
@ -429,8 +454,17 @@
function mailpoet_form_export() {
var template = Handlebars.compile($('#form_template_exports').html());
$('#mailpoet_form_export').html(template({ exports: <%= exports | json_encode | raw %> }));
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'exportsEditor',
data: $('#mailpoet_form_id').val()
}).done(function(response) {
if(response !== false) {
$('#mailpoet_form_export').html(template({ exports: response }));
}
});
}
mailpoet_form_export();
$(document).on('click', '.mailpoet_form_export_toggle', function() {
$('.mailpoet_form_export_output').hide();
@ -455,53 +489,45 @@
// edit field
$(document).on('click', '.mailpoet_form_field_edit', function() {
var field = $(this).data('field');
var id = $(this).data('id');
MailPoet.Modal.popup({
title: "<%= __('Edit field') %>",
template: $('#form_template_field_new').html(),
//url: mailpoet_api_url('subscriber_get_meta.php?field='+field),
onSuccess: function(data) {
console.log('TODO: field->edit');
/*mailpoet_get_json('subscriber_get_meta.php', { field: data.field }, function(data) {
// update field in form
var block_id = $('.mailpoet_form_block[wysija_field="'+field+'"]');
if(block_id.length > 0) {
// redraw block
WysijaForm.get(block_id[0]).block.redraw(data);
// save form
mailpoet_form_save();
}
// toggle widgets
WysijaForm.toggleWidgets();
});*/
MailPoet.Ajax.post({
endpoint: 'customFields',
action: 'get',
data: id
}).done(function(response) {
if(response !== false) {
MailPoet.Modal.popup({
title: "<%= __('Edit field') %>",
template: $('#form_template_field_new').html(),
data: response
});
}
});
});
// delete field
$(document).on('click', '.mailpoet_form_field_delete', function() {
var field = $(this).data('field');
var id = $(this).data('id');
var item = $(this).parent();
var name = $(this).siblings('.mailpoet_form_field').attr('wysija_name');
if(window.confirm("<%= __('Do you really want to delete this custom field?') %>")) {
// delete field
console.log('TODO subscriber->meta->delete');
/*mailpoet_post_json('subscriber_delete_meta.php', { field: field }, function(response) {
var fields = (response.fields !== undefined) ? (response.fields || []) : [];
// refresh toolbar
mailpoet_form_fields({
fields: $.merge(fields, default_fields)
});
// delete field in form
// remove any instance of the field present in the form
var blocks = $$('#mailpoet_form_body .mailpoet_form_block[wysija_field="'+field+'"]');
if(blocks.length > 0) {
var block = WysijaForm.get(blocks[0]);
block.removeBlock();
if(window.confirm(
"<%= __('Do you really want to delete this custom field?') %>"
)) {
MailPoet.Ajax.post({
endpoint: 'customFields',
action: 'delete',
data: id
}).done(function(response) {
if(response === true) {
item.remove();
mailpoet_form_fields();
MailPoet.Notice.success(
"<%= __('Removed custom field “"+name+"“') %>"
);
}
});*/
});
}
});
@ -510,31 +536,28 @@
// pop last element off the history
WysijaHistory.dequeue();
// init wysija form
WysijaForm.init();
return false;
});
// toolbar: list selection
var selected_lists = <%= selected_lists | json_encode | raw %>,
selected_lists_ids = selected_lists.map(function(list) { return parseInt(list.list, 10); });
// enable select2 for list selection
$('select[name="lists"]').select2({
width:'100%'
// get form fields
mailpoet_form_fields().done(function() {
WysijaForm.init();
});
// subscriber meta fields
var meta_fields = [
{"name":"CF text input (mandatory + numbers only)","field":"627e1c8d4fe97712836484e0f2377abd","type":"input","params":{"required":"1","validate":"onlyNumberSp","label":"CF text input (mandatory + numbers only)"}},
{"name":"CF text area (no validation)","field":"6607e6e447b89384c59adc124e979d6b","type":"textarea","params":{"required":"","validate":"","label":"CF text area (no validation)"}},
{"name":"CF text area (letters only)","field":"47a9cae88f8b3b3e23a16990922e7905","type":"textarea","params":{"required":"","validate":"onlyLetterSp","label":"CF text area (letters only)"}},
{"name":"CF radio (mandatory)","field":"5f01b4ccc146fdd6b889bab63dc1b5cd","type":"radio","params":{"values":[{"value":"un"},{"is_checked":"1","value":"deux"},{"value":"trois"}],"required":"1","label":"CF radio (mandatory)"}}
];
// toolbar: segment selection
var selected_segments = <%= form.settings.segments | json_encode | raw %>;
// toolbar: fiels
mailpoet_form_fields({
fields: $.merge(meta_fields, default_fields)
});
// enable select2 for segment selection
$('#mailpoet_form_segments').select2({
width:'100%',
templateResult: function(item) {
if(item.element && item.element.selected) {
return null;
} else {
return item.text;
}
}
}).select2('val', <%= form.settings.segments | json_encode | raw %>);
});
});
</script>
@ -550,39 +573,87 @@
<%= partial('form_template_divider', 'form/templates/blocks/divider.hbs') %>
<%= partial('form_template_input', 'form/templates/blocks/input.hbs') %>
<%= partial('form_template_submit', 'form/templates/blocks/submit.hbs') %>
<%= partial('form_template_list', 'form/templates/blocks/list.hbs') %>
<%= partial('form_template_segment', 'form/templates/blocks/segment.hbs') %>
<%= partial('form_template_radio', 'form/templates/blocks/radio.hbs') %>
<%= partial('form_template_select', 'form/templates/blocks/select.hbs') %>
<%= partial('form_template_checkbox', 'form/templates/blocks/checkbox.hbs') %>
<%= partial('form_template_textarea', 'form/templates/blocks/textarea.hbs') %>
<%= partial('form_template_html', 'form/templates/blocks/html.hbs') %>
<%= partial('form_template_date_years',
'form/templates/blocks/date_years.hbs',
'_settings_date_years'
) %>
<%= partial('form_template_date_months',
'form/templates/blocks/date_months.hbs',
'_settings_date_months'
) %>
<%= partial('form_template_date_days',
'form/templates/blocks/date_days.hbs',
'_settings_date_days'
) %>
<%= partial('form_template_date', 'form/templates/blocks/date.hbs') %>
<%= partial('form_template_date_years', 'form/templates/blocks/date_years.hbs') %>
<%= partial('form_template_date_months', 'form/templates/blocks/date_months.hbs') %>
<%= partial('form_template_date_days', 'form/templates/blocks/date_days.hbs') %>
<!-- field settings -->
<%= partial('form_template_field_settings', 'form/templates/settings/field.hbs') %>
<%= partial('field_settings_label', 'form/templates/settings/label.hbs', '_settings_label') %>
<%= partial('field_settings_label_within', 'form/templates/settings/label_within.hbs', '_settings_label_within') %>
<%= partial('field_settings_required', 'form/templates/settings/required.hbs', '_settings_required') %>
<%= partial('field_settings_validate', 'form/templates/settings/validate.hbs', '_settings_validate') %>
<%= partial('field_settings_values', 'form/templates/settings/values.hbs', '_settings_values') %>
<%= partial('field_settings_date_default', 'form/templates/settings/date_default.hbs', '_settings_date_default') %>
<%= partial('field_settings_submit', 'form/templates/settings/submit.hbs', '_settings_submit') %>
<%= partial('field_settings_label',
'form/templates/settings/label.hbs',
'_settings_label'
) %>
<%= partial('field_settings_label_within',
'form/templates/settings/label_within.hbs',
'_settings_label_within'
) %>
<%= partial('field_settings_required',
'form/templates/settings/required.hbs',
'_settings_required'
) %>
<%= partial('field_settings_validate',
'form/templates/settings/validate.hbs',
'_settings_validate'
) %>
<%= partial('field_settings_values',
'form/templates/settings/values.hbs',
'_settings_values'
) %>
<%= partial('field_settings_date_default',
'form/templates/settings/date_default.hbs',
'_settings_date_default'
) %>
<%= partial('field_settings_submit',
'form/templates/settings/submit.hbs',
'_settings_submit'
) %>
<%= partial('field_settings_values_item', 'form/templates/settings/values_item.hbs') %>
<%= partial('field_settings_date_formats', 'form/templates/settings/date_formats.hbs') %>
<%= partial('field_settings_date_type', 'form/templates/settings/date_types.hbs') %>
<%= partial('field_settings_list_selection_item', 'form/templates/settings/list_selection_item.hbs') %>
<%= partial('field_settings_list_selection', 'form/templates/settings/list_selection.hbs', '_settings_list_selection') %>
<%= partial('field_settings_values_item',
'form/templates/settings/values_item.hbs') %>
<%= partial(
'field_settings_date_format',
'form/templates/settings/date_formats.hbs',
'_settings_date_format'
) %>
<%= partial(
'field_settings_date_type',
'form/templates/settings/date_types.hbs',
'_settings_date_type'
) %>
<%= partial('field_settings_segment_selection_item',
'form/templates/settings/segment_selection_item.hbs'
) %>
<%= partial('field_settings_segment_selection',
'form/templates/settings/segment_selection.hbs',
'_settings_segment_selection'
) %>
<!-- custom field: new -->
<%= partial('form_template_field_new', 'form/templates/settings/field_new.hbs') %>
<%= partial('form_template_field_new',
'form/templates/settings/field_new.hbs'
) %>
<!-- form preview -->
<%= partial('mailpoet_form_preview_template', 'form/templates/preview.hbs') %>
<%= partial('mailpoet_form_preview_template',
'form/templates/preview.hbs'
) %>
<!-- field settings depending on field type -->
<script id="form_template_field_input" type="text/x-handlebars-template">

View File

@ -1,9 +1,9 @@
<div class="mailpoet_form_block"
wysija_type="{{ type }}"
wysija_field="{{ field }}"
{{#if id}}wysija_id="{{ id }}"{{/if}}
wysija_name="{{ name }}"
wysija_unique="{{#if multiple}}0{{else}}1{{/if}}"
wysija_static="{{#if static}}1{{else}}0{{/if}}"
wysija_unique="{{ unique }}"
wysija_static="{{#ifCond static '==' 1}}1{{else}}0{{/ifCond}}"
wysija_params="{{#if params}}{{ json_encode params }}{{/if}}">
{{#ifCond type '!==' 'divider'}}
<div class="wysija_settings" style="display:none;">
@ -12,7 +12,9 @@
{{/ifCond}}
<ul class="wysija_controls clearfix" style="display: none;">
<li class="handle_container"><a class="handle" href="javascript:;"><span></span></a></li>
{{#unless static}}<li><a class="remove" href="javascript:;"><span></span></a></li>{{/unless}}
{{#ifCond static '==' '0'}}
<li><a class="remove" href="javascript:;"><span></span></a></li>
{{/ifCond}}
</ul>
{{{ template }}}
</div>

View File

@ -1,6 +1,6 @@
<% set currentDay = 'now'|date("d") %>
<select id="{{ field }}_days">
<select id="{{ id }}_days">
<% for day in 1..31 %>
<option
{{#if params.is_default_today}}

View File

@ -1,10 +1,11 @@
<% set currentMonth = 'now'|date('n') %>
<select id="{{ field }}_months">
<select id="{{ id }}_months">
<% for month in 1..12 %>
<option
<option
{{#if params.is_default_today}}
{{#ifCond month "==" "<%= currentMonth %>"}}selected="selected"{{/ifCond}}
{{/if}}><%= month |date('1984-' ~ month ~ '-01') |date('F') %></option>
{{/if}}
><%= month |date('1984-' ~ month ~ '-01') |date('F') %></option>
<% endfor %>
</select>

View File

@ -1,7 +1,7 @@
<% set currentYear = "now"|date("Y") %>
<% set minYear = currentYear - 100 %>
<select id="{{ field }}_years">
<select id="{{ id }}_years">
<% for year in currentYear..minYear %>
<option
{{#if params.is_default_today}}

View File

@ -2,6 +2,6 @@
{{#unless params.values}}<p class="mailpoet_error"><%= __('You have to select at least 1 list') %></p>{{/unless}}
{{#each params.values}}
<p>
<input class="mailpoet_checkbox" type="checkbox" data-list-id="{{ id }}" {{#if is_checked}}checked="checked"{{/if}} disabled="disabled" />{{ name }}
<input class="mailpoet_checkbox" type="checkbox" {{#if is_checked}}checked="checked"{{/if}} disabled="disabled" />{{ name }}
</p>
{{/each}}

View File

@ -1,13 +1,13 @@
<% for date_type, formats in date_formats %>
{{#ifCond params.date_type "===" "<%= date_type %>"}}
<% if formats.count == 1 %>
<% if(formats | length == 1) %>
<!-- display format as hidden value -->
<input type="hidden" name="params[date_format]" value="<%= formats[0] %>" />
<% else %>
<!-- display label -->
<p class="clearfix">
<label><%= __('Order') %></label>
// display all possible date formats
<!-- display all possible date formats -->
<select name="params[date_format]">
<% for format in formats %>
<option

View File

@ -6,7 +6,7 @@
{{#ifCond type '==' 'input'}}
{{> _settings_label }}
{{> _settings_label_within }}
{{#ifCond field 'in' 'firstname,lastname' }}
{{#ifCond field 'in' 'first_name,last_name' }}
{{> _settings_required }}
{{/ifCond}}
{{/ifCond}}
@ -31,9 +31,9 @@
{{> _settings_label }}
{{/ifCond}}
{{#ifCond type '==' 'list'}}
{{#ifCond type '==' 'segment'}}
{{> _settings_label }}
{{> _settings_list_selection }}
{{> _settings_segment_selection }}
{{/ifCond}}
{{#ifCond type '==' 'select'}}

View File

@ -1,9 +1,9 @@
<form id="form_field_new" name="form_field_new" action="" method="post">
{{#if field}}<input type="hidden" id="field" name="field" value="{{ field }}" />{{/if}}
{{#if id}}<input type="hidden" id="field_id" name="id" value="{{ id }}" />{{/if}}
<p>
<label for="type"><%= __('Select a field type:') %></label>
<select id="type" name="type">
<label for="field_type"><%= __('Select a field type:') %></label>
<select id="field_type" name="type">
<option value="">--</option>
<option
{{#ifCond type '==' 'input'}}selected="selected"{{/ifCond}}
@ -31,22 +31,10 @@
</option>
</select>
</p>
<p class="mailpoet_error" data-error="type_required">
<%= __('You need to select a type.') %>
</p>
<p>
<label><%= __("Field's name:") %></label>
<input type="text" name="name" value="{{ name }}" />
</p>
<p class="mailpoet_error" data-error="name_required">
<%= __('You need to specify a name.') %>
</p>
<p class="mailpoet_error" data-error="name_already_exists">
<%= __('This name is already used.') %>
</p>
<hr />
<div class="field_type_form"></div>
@ -63,54 +51,57 @@
loadFieldForm();
});
$('#form_field_new').on('submit', function() {
$('#form_field_new').on('submit', function(e) {
e.preventDefault();
// get data
var data = $(this).serializeObject();
MailPoet.Ajax.post({
endpoint: 'customFields',
action: 'save',
data: data
}).done(function(response) {
if(response.result === true) {
mailpoet_form_fields();
if(data.id) {
MailPoet.Notice.success(
"<%= __('Updated custom field “"+data.name+"“') %>"
);
} else {
MailPoet.Notice.success(
"<%= __('Added custom field “"+data.name+"“') %>"
);
}
// hide errors
$('.mailpoet_error').hide();
console.log(('TODO: subscriber->meta->edit'));
// mailpoet_post_json('subscriber_extend.php', data, function(response) {
// if(response.error !== undefined) {
// // there's an error!
// $('.mailpoet_error[data-error="'+response.error+'"]').show();
// } else {
// // we should get the fields list in the response
// if(response.fields !== undefined) {
// // get fields (defaults to empty array)
// var fields = response.fields || [];
// // refresh toolbar
// mailpoet_form_fields({
// fields: $.merge(fields, default_fields)
// });
// }
} else {
if(response.errors.length > 0) {
for(error in response.errors) {
MailPoet.Notice.error(error);
}
}
}
});
// close popup
MailPoet.Modal.success();
// }
// });
return false;
return MailPoet.Modal.success();
});
$('#form_field_new #type').on('change', function() {
if($(this).val() !== '') {
$('.mailpoet_error[data-error="type_required"]').hide();
}
// load template based on type
$('#form_field_new #field_type').on('change', function() {
loadFieldForm($(this).val());
});
function loadFieldForm(type) {
type = (type === undefined) ? $('#form_field_new #type').val() : type;
type = (type === undefined) ? $('#form_field_new #field_type').val() : type;
if(type !== '') {
var template = Handlebars.compile($('#form_template_field_'+type).html()),
data = {type: type},
field = $('#form_field_new #field').val();
field_id = $('#form_field_new #field_id').val();
if(field !== undefined && field.length > 0) {
var params = $('.mailpoet_form_field[wysija_field="'+field+'"]').attr('wysija_params');
data.params = JSON.parse(params);
if(field_id !== undefined && field_id.length > 0) {
var params = $('.mailpoet_form_field[wysija_id="'+field_id+'"]').attr('wysija_params');
if(params !== undefined) {
data.params = JSON.parse(params);
}
}
// render field template
$('#form_field_new .field_type_form').html(template(data));

View File

@ -1,124 +0,0 @@
<p class="mailpoet_error" data-error="user_no_list">
<%= __('You need to specify at least 1 list.') %>
</p>
<ul id="mailpoet_list_selection" class="clearfix"></ul>
<div id="mailpoet_list_available_container">
<h3><%= __('Select the list you want to add:') %></h3>
<select class="mailpoet_list_available"></select>
<a href="javascript:;" class="mailpoet_list_add"><span><%= __('Add') %></span></a>
</div>
<script type="text/javascript">
<% autoescape false %>
var selected_lists = {{#if params.values}}{{{ json_encode params.values }}}
{{else}}<%= default_list | json_encode %>{{/if}},
available_lists = [
<% for list in lists %>
<%= list | json_encode %>,
<% endfor %>
];
<% endautoescape %>
jQuery(function($) {
$(function() {
mailpoet_list_available_render();
mailpoet_list_selection_render();
setInputNames();
// make list selection sortable
Sortable.create('mailpoet_list_selection', {
handles: $$('#mailpoet_list_selection .handle')
});
// add list
$('.mailpoet_list_add').on('click', function() {
// add currently selected list to the selection
var selected_list = $('.mailpoet_list_available :selected');
// add list to selection
selected_lists.push({
list: selected_list.val(),
list_name: selected_list.text(),
is_checked: 0
});
// remove list from available lists
selected_list.remove();
// render selection
mailpoet_list_selection_render();
setInputNames();
});
// remove list
$('#mailpoet_list_selection').on('click', '.remove', function() {
var element = $(this).parents('li');
// remove currently selected list to the selection
var selected_list = parseInt(element.data('list'), 10);
// remove list from selection
selected_lists = selected_lists.filter(function(list) {
return (parseInt(list.id, 10) !== selected_list);
});
// remove element
element.remove();
// render available list
mailpoet_list_available_render();
setInputNames();
});
});
function mailpoet_list_available_render() {
// get selected lists ids
var selected_lists_ids = selected_lists.map(function(list) { return parseInt(list.id, 10); });
// clear available lists
$('.mailpoet_list_available').html('');
// display available lists
$.each(available_lists, function(i, list) {
if($.inArray(list.id, selected_lists_ids) < 0) {
$('.mailpoet_list_available').append('<option value="'+list.id+'">'+list.name+'</option>');
}
});
mailpoet_list_available_toggle();
}
function mailpoet_list_selection_render() {
// list item template
var template = Handlebars.compile($('#field_settings_list_selection_item').html());
// update view
$('#mailpoet_list_selection').html(template({ lists: selected_lists }));
mailpoet_list_available_toggle();
}
function mailpoet_list_available_toggle() {
// toggle visibility of available lists
if($('.mailpoet_list_available option').length === 0) {
$('#mailpoet_list_available_container').hide();
} else {
$('#mailpoet_list_available_container').show();
}
}
function setInputNames() {
$('#mailpoet_list_selection li').each(function(index, item) {
$(item).find('.mailpoet_is_checked').attr('name', 'params[values]['+index+'][is_checked]');
$(item).find('.mailpoet_list_id').attr('name', 'params[values]['+index+'][id]');
$(item).find('.mailpoet_list_name').attr('name', 'params[values]['+index+'][name]');
});
}
});
<{{!}}/script>

View File

@ -0,0 +1,130 @@
<ul id="mailpoet_segment_selection" class="clearfix"></ul>
<div id="mailpoet_segment_available_container">
<h3><%= __('Select the segment you want to add:') %></h3>
<select class="mailpoet_segment_available"></select>
<a href="javascript:;" class="mailpoet_segment_add"><span><%= __('Add') %></span></a>
</div>
<script type="text/javascript">
jQuery(function($) {
<% autoescape false %>
var selected_segments = {{#if params.values}}{{{ json_encode params.values }}}
{{else}}[]{{/if}};
<% endautoescape %>
$(function() {
mailpoet_segment_available_render();
mailpoet_segment_selection_render();
setInputNames();
setupSortableSegments();
// add segment
$('.mailpoet_segment_add').on('click', function() {
// add currently selected segment to the selection
var selected_segment = $('.mailpoet_segment_available :selected');
// add segment to selection
selected_segments.push({
id: selected_segment.val(),
name: selected_segment.text(),
is_checked: 0
});
// remove segment from available segments
selected_segment.remove();
// render selection
mailpoet_segment_selection_render();
setInputNames();
});
// remove segment
$('#mailpoet_segment_selection').on('click', '.remove', function(e) {
if($('#mailpoet_segment_selection').children().length === 1) {
return e.preventDefault();
}
var element = $(this).parents('li');
// remove currently selected segment to the selection
var selected_segment = parseInt(element.data('segment'), 10);
// remove segment from selection
selected_segments = selected_segments.filter(function(segment) {
return (parseInt(segment.id, 10) !== selected_segment);
});
// remove element
element.remove();
// render available segment
mailpoet_segment_available_render();
setInputNames();
});
});
function setupSortableSegments() {
// make segment selection sortable
Sortable.create('mailpoet_segment_selection', {
handles: $$('#mailpoet_segment_selection .handle'),
onChange: function(item) {
setInputNames();
}
});
}
function mailpoet_segment_available_render() {
// clear available segments
$('.mailpoet_segment_available').html('');
var selected_segment_ids = selected_segments.map(function(segment) {
return segment.id;
});
// display available segments
$.each(mailpoet_segments, function(i, segment) {
if($.inArray(segment.id, selected_segment_ids) < 0) {
$('.mailpoet_segment_available').append(
'<option value="'+segment.id+'">'+segment.name+'</option>'
);
}
});
mailpoet_segment_available_toggle();
}
function mailpoet_segment_selection_render() {
// segment item template
var template = Handlebars.compile(
$('#field_settings_segment_selection_item').html()
);
// update view
$('#mailpoet_segment_selection').html(
template({ segments: selected_segments })
);
mailpoet_segment_available_toggle();
}
function mailpoet_segment_available_toggle() {
// toggle visibility of available segments
if($('.mailpoet_segment_available option').length === 0) {
$('#mailpoet_segment_available_container').hide();
} else {
$('#mailpoet_segment_available_container').show();
}
}
function setInputNames() {
$('#mailpoet_segment_selection li').each(function(index, item) {
$(item).find('.mailpoet_is_checked').attr('name', 'params[values]['+index+'][is_checked]');
$(item).find('.mailpoet_segment_id').attr('name', 'params[values]['+index+'][id]');
$(item).find('.mailpoet_segment_name').attr('name', 'params[values]['+index+'][name]');
});
}
});
<{{!}}/script>

View File

@ -1,10 +1,10 @@
{{#each lists}}
<li data-list="{{ id }}">
{{#each segments}}
<li data-segment="{{ id }}">
<label>
<input class="mailpoet_list_id" type="hidden" value="{{ id }}" />
<input class="mailpoet_segment_id" type="hidden" value="{{ id }}" />
<input class="mailpoet_is_checked" type="checkbox" value="1"
{{#ifCond is_checked '>' 0}}checked="checked"{{/ifCond}} />
<input class="mailpoet_list_name" type="hidden" value="{{ name }}" />
<input class="mailpoet_segment_name" type="hidden" value="{{ name }}" />
{{ name }}
</label>
<a class="remove" href="javascript:;"><%= __('Remove') %></a>

View File

@ -6,18 +6,13 @@
<%= __('Nothing') %>
</option>
<option {{#ifCond params.validate '==' 'onlyNumberSp'}}selected="selected"{{/ifCond}}
value="onlyNumberSp">
<option {{#ifCond params.validate '==' 'number'}}selected="selected"{{/ifCond}}
value="number">
<%= __('Numbers only') %>
</option>
<option {{#ifCond params.validate '==' 'onlyLetterSp'}}selected="selected"{{/ifCond}}
value="onlyLetterSp">
<%= __('Letters only') %>
</option>
<option {{#ifCond params.validate '==' 'onlyLetterNumber'}}selected="selected"{{/ifCond}}
value="onlyLetterNumber">
<option {{#ifCond params.validate '==' 'alphanum'}}selected="selected"{{/ifCond}}
value="alphanum">
<%= __('Alphanumerical') %>
</option>

View File

@ -1,8 +1,8 @@
{{#each fields}}
<li>
<a class="mailpoet_form_field"
wysija_field="{{ field }}"
wysija_name="{{ name }}"
{{#if id }}wysija_id="{{ id }}"{{/if}}
wysija_unique="{{#if multiple}}0{{else}}1{{/if}}"
wysija_type="{{ type }}"
{{#if params}}wysija_params="{{ json_encode params }}"{{/if}}>
@ -13,13 +13,13 @@
<a class="mailpoet_form_field_edit settings"
title="<%= __('Edit field') %>"
href="javascript:;"
data-field="{{ field }}">
data-id="{{ id }}">
<span class="dashicons dashicons-admin-generic"></span>
</a>
<a class="mailpoet_form_field_delete delete"
title="<?php _e('Delete field'); ?>"
title="<%= __('Delete field') %>"
href="javascript:;"
data-field="{{ field }}">
data-id="{{ id }}">
<span class="dashicons dashicons-dismiss"></span>
</a>
{{/unless}}

33
views/form/widget.html Normal file
View File

@ -0,0 +1,33 @@
<% block content %>
<%= before_widget | raw %>
<% if(title) %>
<h2 class="widget-title"><%= title | raw %></h2>
<% endif %>
<div class="mailpoet_form mailpoet_form_<%= form_type %>">
<%= styles | raw %>
<form
id="<%= form_id %>"
method="post"
<#
action="<%= admin_url('admin-post.php?action=mailpoet_form_subscribe') | raw %>"
#>
class="mailpoet_form mailpoet_form_<%= form_type %>"
novalidate
data-parsley-validate
>
<div class="mailpoet_message"></div>
<input type="hidden" name="form_id" value="<%= form.id %>" />
<% if not(form.settings.segments_selected_by == 'user') %>
<% for segment in form.settings.segments %>
<input type="hidden" name="segments[]" value="<%= segment %>" />
<% endfor %>
<% endif %>
<%= html | raw %>
</form>
</div>
<%= after_widget | raw %>
<% endblock %>

View File

@ -1,5 +1,9 @@
<!-- system notices -->
<div id="mailpoet_notice_system" class="mailpoet_notice" style="display:none;"></div>
<!-- handlebars templates -->
<% block templates %><% endblock %>
<!-- main container -->
<div class="wrap">
<!-- notices -->
@ -26,7 +30,4 @@
'vendor.js',
'mailpoet.js',
'admin.js'
)%>
<!-- handlebars templates -->
<% block templates %><% endblock %>
)%>

View File

@ -1239,6 +1239,10 @@
'<%= __('Test email successfully sent!') %>',
unknownErrorOccurred:
'<%= __('An unknown error occurred, please check your settings.') %>',
templateNameMissing:
'<%= __('Please add a template name') %>',
templateDescriptionMissing:
'<%= __('Please add a template description') %>',
},
sidepanelWidth: '331px',
validation: {

View File

@ -16,4 +16,10 @@
<p><input type="text" name="template_description" value="" placeholder="<%= __('Insert template description') %>" class="mailpoet_input mailpoet_save_as_template_description" /></p>
<p><input type="button" name="save_as_template" value="<%= __('Save as template') %>" class="mailpoet_button mailpoet_button_full mailpoet_button_primary mailpoet_save_as_template" /></p>
</div>
<div class="mailpoet_export_template_container mailpoet_hidden">
<p><b class="mailpoet_export_template_title"><%= __('Export template') %></b></p>
<p><input type="text" name="export_template_name" value="" placeholder="<%= __('Template name') %>" class="mailpoet_input mailpoet_export_template_name" /></p>
<p><input type="text" name="export_template_description" value="" placeholder="<%= __('Template description') %>" class="mailpoet_input mailpoet_export_template_description" /></p>
<p><input type="button" name="export_template" value="<%= __('Export template') %>" class="mailpoet_button mailpoet_button_full mailpoet_button_primary mailpoet_export_template" /></p>
</div>
</div>

View File

@ -21,7 +21,9 @@ baseConfig = {
'backbone.supermodel$': 'backbone.supermodel/build/backbone.supermodel.js',
'sticky-kit': 'sticky-kit/jquery.sticky-kit',
'interact$': 'interact.js/interact.js',
'spectrum$': 'spectrum-colorpicker/spectrum.js'
'spectrum$': 'spectrum-colorpicker/spectrum.js',
'blob$': 'blob/Blob.js',
'filesaver$': 'filesaver/FileSaver.js'
},
},
node: {
@ -33,6 +35,14 @@ baseConfig = {
test: /\.jsx$/,
loader: 'babel-loader'
},
{
test: /form_editor\.js$/,
loader: 'expose-loader?WysijaForm',
},
{
include: require.resolve('codemirror'),
loader: 'expose-loader?CodeMirror',
},
{
include: require.resolve('backbone'),
loader: 'expose-loader?Backbone',
@ -41,6 +51,10 @@ baseConfig = {
include: require.resolve('underscore'),
loader: 'expose-loader?_',
},
{
include: /Blob.js$/,
loader: 'exports-loader?window.Blob',
},
{
test: /backbone.supermodel/,
loader: 'exports-loader?Backbone.SuperModel',
@ -72,6 +86,11 @@ config.push(_.extend({}, baseConfig, {
'forms/forms.jsx',
'settings/tabs.js'
],
form_editor: [
'form_editor/form_editor.js',
'codemirror',
'codemirror/mode/css/css'
],
newsletter_editor: [
'underscore',
'backbone',
@ -82,6 +101,8 @@ config.push(_.extend({}, baseConfig, {
'select2',
'spectrum',
'sticky-kit',
'blob',
'filesaver',
'newsletter_editor/communicationsFix.js',
'newsletter_editor/App',
@ -125,8 +146,16 @@ config.push(_.extend({}, baseConfig, {
config.push(_.extend({}, baseConfig, {
name: 'public',
entry: {
public: ['mailpoet', 'ajax', 'public.js']
public: [
'mailpoet',
'ajax',
'jquery.serialize_object',
'public.js'
]
},
/*plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
],*/
externals: {
'jquery': 'jQuery'
}
@ -145,7 +174,8 @@ config.push(_.extend({}, baseConfig, {
'backbone.supermodel',
'backbone.radio',
'select2',
'blob',
'filesaver',
'newsletter_editor/communicationsFix.js',
'newsletter_editor/App',
'newsletter_editor/components/config.js',
@ -209,6 +239,8 @@ config.push(_.extend({}, baseConfig, {
'sticky-kit': 'sticky-kit/jquery.sticky-kit',
'backbone.marionette': 'backbone.marionette/lib/backbone.marionette',
'backbone.supermodel$': 'backbone.supermodel/build/backbone.supermodel.js',
'blob$': 'blob/Blob.js',
'filesaver$': 'filesaver/FileSaver.js'
},
},
externals: {