Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
0199e2c7e1 | |||
d1f407bf19 | |||
f18d2842b9 | |||
f640cbb307 | |||
b20d92c9b1 | |||
795485d42a | |||
dfadda2d12 | |||
31305a04c0 | |||
cfdb886e88 | |||
1ce4b16327 | |||
b12f7f29de | |||
5473f94e24 | |||
a31dce6226 | |||
d996b78561 | |||
c2e7513381 | |||
541696863e | |||
6c8d2be18c | |||
907fe585de | |||
e24f8c9653 | |||
5df0475b1a | |||
cf154455e3 | |||
dcfe6357cf | |||
983df216f3 | |||
f750d2359f | |||
d85f51e9fc | |||
40a62687cf | |||
136e09e9fb | |||
f509dc0d7e | |||
c100130f39 | |||
9922ecd93c | |||
a4cf2f9c76 | |||
576fbf2085 | |||
5c63971314 | |||
7418923bbc | |||
a8f8134f67 | |||
103da61d45 | |||
01e6a5e6b2 | |||
f5ccf3b38a | |||
c8929351ba | |||
6ca536e9ca | |||
89b04e8691 | |||
588b441fb1 | |||
13dc3577f1 | |||
505b979ac5 | |||
3b4c5c83e1 | |||
056e79eeac | |||
4bde705f04 |
@ -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');
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
@require 'common'
|
||||
@require 'modal'
|
||||
@require 'notice'
|
||||
@require 'validation_engine'
|
||||
@require 'parsley'
|
||||
|
||||
@require 'form_editor'
|
||||
@require 'listing'
|
||||
|
@ -19,8 +19,10 @@ a:focus
|
||||
|
||||
// select 2
|
||||
.select2-container
|
||||
// textareas
|
||||
textarea.regular-text
|
||||
width: 25em !important
|
||||
|
||||
@media screen and (max-width: 782px)
|
||||
.select2-container
|
||||
width: 100% !important
|
||||
width: 100% !important
|
||||
|
@ -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'
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.mailpoet_listing_loading tbody tr,
|
||||
.mailpoet_listing_loading tbody tr
|
||||
.mailpoet_form_loading tbody tr
|
||||
opacity: 0.2
|
||||
|
||||
@ -8,6 +8,20 @@
|
||||
.mailpoet_select_all td
|
||||
text-align: center
|
||||
|
||||
table.widefat thead .check-column,
|
||||
table.widefat tfoot .check-column
|
||||
padding: 10px 0 0 3px
|
||||
.mailpoet_listing_table
|
||||
th span
|
||||
white-space: nowrap
|
||||
|
||||
thead .check-column
|
||||
tfoot .check-column
|
||||
padding: 10px 0 0 3px
|
||||
|
||||
thead th.column-primary
|
||||
tfoot th.column-primary
|
||||
width: 25em
|
||||
|
||||
// responsive
|
||||
@media screen and (max-width: 782px)
|
||||
thead th.column-primary
|
||||
tfoot th.column-primary
|
||||
width: 100%
|
@ -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
|
||||
|
@ -1,3 +1,8 @@
|
||||
$column-margin = 20px
|
||||
$one-column-width = $newsletter-width - (2 * $column-margin)
|
||||
$two-column-width = ($newsletter-width / 2) - (2 * $column-margin)
|
||||
$three-column-width = ($newsletter-width / 3) - (2 * $column-margin)
|
||||
|
||||
.mailpoet_container
|
||||
width: 100%
|
||||
min-height: 15px
|
||||
@ -44,7 +49,7 @@
|
||||
|
||||
.mailpoet_container_horizontal > .mailpoet_container_block
|
||||
margin-bottom: 0
|
||||
width: 20px + 560px + 20px
|
||||
width: $column-margin + $one-column-width + $column-margin
|
||||
|
||||
// More than one column
|
||||
& > .mailpoet_container_block > .mailpoet_container > .mailpoet_container_block > .mailpoet_container_horizontal
|
||||
@ -57,14 +62,14 @@
|
||||
& > .mailpoet_block:first-child:nth-last-child(2) ~ .mailpoet_block
|
||||
//padding-left: 20px
|
||||
//padding-right: 20px
|
||||
width: 260px + 20px + 20px
|
||||
width: $column-margin + $two-column-width + $column-margin
|
||||
|
||||
// Three columns
|
||||
& > .mailpoet_block:first-child:nth-last-child(3)
|
||||
& > .mailpoet_block:first-child:nth-last-child(3) ~ .mailpoet_block
|
||||
//padding-left: 20px
|
||||
//padding-right: 20px
|
||||
width: 160px + 20px + 20px
|
||||
width: $column-margin + $three-column-width + $column-margin
|
||||
|
||||
.mailpoet_container_empty
|
||||
text-align: center
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Fix select2 z-index to work with MailPoet.Modal */
|
||||
.select2-drop
|
||||
.select2-dropdown
|
||||
z-index: 101000
|
||||
|
||||
/* Remove input field styles from select2 type input */
|
||||
@ -7,6 +7,19 @@
|
||||
border: none
|
||||
padding: 0
|
||||
|
||||
/* Fix select2 input glow and margins that wordpress may insert */
|
||||
.select2 input,
|
||||
.select2 input:focus
|
||||
border-color: none
|
||||
box-shadow: none
|
||||
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
/* Fix width overrides for select2 */
|
||||
.mailpoet_editor_settings .select2-container
|
||||
width: 100% !important
|
||||
|
||||
/* Fix inline TinyMCE toolbar to have minimal width instead of being close to 100% of the screen */
|
||||
div.mce-toolbar-grp.mce-container
|
||||
position: absolute
|
||||
|
@ -23,4 +23,4 @@ $warning-alternate-text-color = #f4c6c8
|
||||
$error-text-color = #d54e21
|
||||
|
||||
// Dimensions
|
||||
$newsletter-width = 600px
|
||||
$newsletter-width = 660px
|
||||
|
27
assets/css/src/parsley.styl
Normal file
27
assets/css/src/parsley.styl
Normal 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
|
@ -0,0 +1,3 @@
|
||||
@import 'nib'
|
||||
|
||||
@require 'parsley'
|
||||
|
@ -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
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
2
assets/js/lib/scriptaculous.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -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 }
|
||||
|
@ -70,15 +70,31 @@ define(
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
||||
// only get values from displayed fields
|
||||
item = {};
|
||||
this.props.fields.map(function(field) {
|
||||
item[field.name] = this.state.item[field.name];
|
||||
}.bind(this));
|
||||
|
||||
// set id if specified
|
||||
if(this.props.params.id !== undefined) {
|
||||
item.id = this.props.params.id;
|
||||
}
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'save',
|
||||
data: this.state.item
|
||||
data: item
|
||||
}).done(function(response) {
|
||||
this.setState({ loading: false });
|
||||
|
||||
if(response === true) {
|
||||
this.history.pushState(null, '/');
|
||||
if(this.props.onSuccess !== undefined) {
|
||||
this.props.onSuccess()
|
||||
} else {
|
||||
this.history.pushState(null, '/')
|
||||
}
|
||||
|
||||
if(this.props.params.id !== undefined) {
|
||||
this.props.messages['updated']();
|
||||
} else {
|
||||
|
@ -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, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"');
|
||||
// ": fix for FileMerge because the previous line fucks up its syntax coloring
|
||||
},
|
||||
decodeHtmlValue: function(str) {
|
||||
return str.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/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) {}
|
||||
}
|
1026
assets/js/src/form_editor/form_editor.js
Normal file
1026
assets/js/src/form_editor/form_editor.js
Normal file
File diff suppressed because it is too large
Load Diff
57
assets/js/src/forms/form.jsx
Normal file
57
assets/js/src/forms/form.jsx
Normal file
@ -0,0 +1,57 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, History } from 'react-router'
|
||||
import MailPoet from 'mailpoet'
|
||||
import Form from 'form/form.jsx'
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
type: 'selection',
|
||||
endpoint: 'segments',
|
||||
multiple: true
|
||||
}
|
||||
]
|
||||
|
||||
const messages = {
|
||||
updated: function() {
|
||||
MailPoet.Notice.success('Form successfully updated!');
|
||||
},
|
||||
created: function() {
|
||||
MailPoet.Notice.success('Form successfully added!');
|
||||
}
|
||||
}
|
||||
|
||||
const FormForm = React.createClass({
|
||||
mixins: [
|
||||
History
|
||||
],
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Form <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
endpoint="forms"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
onSuccess={ this.history.goBack } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = FormForm
|
29
assets/js/src/forms/forms.jsx
Normal file
29
assets/js/src/forms/forms.jsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, Route, IndexRoute } from 'react-router'
|
||||
import FormList from 'forms/list.jsx'
|
||||
import FormForm from 'forms/form.jsx'
|
||||
import createHashHistory from 'history/lib/createHashHistory'
|
||||
|
||||
let history = createHashHistory({ queryKey: false })
|
||||
|
||||
const App = React.createClass({
|
||||
render() {
|
||||
return this.props.children
|
||||
}
|
||||
});
|
||||
|
||||
let container = document.getElementById('forms_container');
|
||||
|
||||
if(container) {
|
||||
ReactDOM.render((
|
||||
<Router history={ history }>
|
||||
<Route path="/" component={ App }>
|
||||
<IndexRoute component={ FormList } />
|
||||
<Route path="new" component={ FormForm } />
|
||||
<Route path="edit/:id" component={ FormForm } />
|
||||
<Route path="*" component={ FormList } />
|
||||
</Route>
|
||||
</Router>
|
||||
), container);
|
||||
}
|
188
assets/js/src/forms/list.jsx
Normal file
188
assets/js/src/forms/list.jsx
Normal file
@ -0,0 +1,188 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, Link } from 'react-router'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import classNames from 'classnames'
|
||||
import MailPoet from 'mailpoet'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
sortable: true
|
||||
}
|
||||
];
|
||||
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
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(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDelete: function(response) {
|
||||
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(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onRestore: function(response) {
|
||||
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(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
link: function(item) {
|
||||
return (
|
||||
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>Edit</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'duplicate_form',
|
||||
label: 'Duplicate',
|
||||
onClick: function(item, refresh) {
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'forms',
|
||||
action: 'duplicate',
|
||||
data: item.id
|
||||
}).done(function(response) {
|
||||
MailPoet.Notice.success(
|
||||
('Form "%$1s" has been duplicated.').replace('%$1s', response.name)
|
||||
);
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
|
||||
const FormList = React.createClass({
|
||||
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',
|
||||
'has-row-actions'
|
||||
);
|
||||
|
||||
let segments = mailpoet_segments.filter(function(segment) {
|
||||
return (jQuery.inArray(segment.id, form.segments) !== -1);
|
||||
}).map(function(segment) {
|
||||
return segment.name;
|
||||
}).join(', ');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<td className={ row_classes }>
|
||||
<strong>
|
||||
<a>{ form.name }</a>
|
||||
</strong>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column-format" data-colname="Lists">
|
||||
{ segments }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Created on">
|
||||
<abbr>{ form.created_at }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
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 }
|
||||
endpoint="forms"
|
||||
onRenderItem={ this.renderItem }
|
||||
columns={ columns }
|
||||
bulk_actions={ bulk_actions }
|
||||
item_actions={ item_actions }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = FormList;
|
@ -45,12 +45,13 @@ function(
|
||||
|
||||
data.action = this.state.action;
|
||||
|
||||
var callback = function() {};
|
||||
if(action['onSuccess'] !== undefined) {
|
||||
data.onSuccess = action.onSuccess;
|
||||
callback = action.onSuccess;
|
||||
}
|
||||
|
||||
if(data.action) {
|
||||
this.props.onBulkAction(selected_ids, data);
|
||||
this.props.onBulkAction(selected_ids, data, callback);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
|
@ -1,57 +1,66 @@
|
||||
define([
|
||||
'react'
|
||||
'react',
|
||||
'jquery'
|
||||
],
|
||||
function(
|
||||
React
|
||||
React,
|
||||
jQuery
|
||||
) {
|
||||
var ListingFilters = React.createClass({
|
||||
handleFilterAction: function() {
|
||||
var filters = this.props.filters.map(function(filter, index) {
|
||||
var value = this.refs['filter-'+index].value;
|
||||
if(value) {
|
||||
return {
|
||||
'name': filter.name,
|
||||
'value': value
|
||||
};
|
||||
}
|
||||
}.bind(this));
|
||||
let filters = {}
|
||||
this.getAvailableFilters().map((filter, i) => {
|
||||
filters[this.refs['filter-'+i].name] = this.refs['filter-'+i].value
|
||||
})
|
||||
return this.props.onSelectFilter(filters);
|
||||
},
|
||||
handleChangeAction: function() {
|
||||
return true;
|
||||
getAvailableFilters: function() {
|
||||
let filters = this.props.filters;
|
||||
|
||||
return Object.keys(filters).filter(function(filter) {
|
||||
return !(
|
||||
filters[filter].length === 0
|
||||
|| (
|
||||
filters[filter].length === 1
|
||||
&& !filters[filter][0].value
|
||||
)
|
||||
);
|
||||
})
|
||||
},
|
||||
render: function() {
|
||||
var filters = this.props.filters
|
||||
.filter(function(filter) {
|
||||
return !(
|
||||
filter.options.length === 0
|
||||
|| (
|
||||
filter.options.length === 1
|
||||
&& !filter.options[0].value
|
||||
)
|
||||
);
|
||||
})
|
||||
const filters = this.props.filters;
|
||||
const selected_filters = this.props.filter;
|
||||
|
||||
const available_filters = this.getAvailableFilters()
|
||||
.map(function(filter, i) {
|
||||
let default_value = false;
|
||||
if(selected_filters[filter] !== undefined && selected_filters[filter]) {
|
||||
default_value = selected_filters[filter]
|
||||
} else {
|
||||
jQuery(`select[name="${filter}"]`).val('');
|
||||
}
|
||||
return (
|
||||
<select
|
||||
ref={ 'filter-'+i }
|
||||
key={ 'filter-'+i }
|
||||
onChange={ this.handleChangeAction }>
|
||||
{ filter.options.map(function(option, j) {
|
||||
return (
|
||||
<option
|
||||
value={ option.value }
|
||||
key={ 'filter-option-' + j }
|
||||
>{ option.label }</option>
|
||||
);
|
||||
}.bind(this)) }
|
||||
ref={ `filter-${i}` }
|
||||
key={ `filter-${i}` }
|
||||
name={ filter }
|
||||
defaultValue={ default_value }
|
||||
>
|
||||
{ filters[filter].map(function(option, j) {
|
||||
return (
|
||||
<option
|
||||
value={ option.value }
|
||||
key={ 'filter-option-' + j }
|
||||
>{ option.label }</option>
|
||||
);
|
||||
}.bind(this)) }
|
||||
</select>
|
||||
);
|
||||
}.bind(this));
|
||||
|
||||
var button = false;
|
||||
let button = false;
|
||||
|
||||
if(filters.length > 0) {
|
||||
if(available_filters.length > 0) {
|
||||
button = (
|
||||
<input
|
||||
onClick={ this.handleFilterAction }
|
||||
@ -63,7 +72,7 @@ function(
|
||||
|
||||
return (
|
||||
<div className="alignleft actions actions">
|
||||
{ filters }
|
||||
{ available_filters }
|
||||
{ button }
|
||||
</div>
|
||||
);
|
||||
|
@ -9,6 +9,9 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
render: function() {
|
||||
var columns = this.props.columns.map(function(column, index) {
|
||||
column.is_primary = (index === 0);
|
||||
column.sorted = (this.props.sort_by === column.name)
|
||||
? this.props.sort_order
|
||||
: 'asc';
|
||||
return (
|
||||
<ListingColumn
|
||||
onSort={this.props.onSort}
|
||||
|
@ -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;
|
||||
@ -46,8 +44,11 @@ define(
|
||||
handleRestoreItem: function(id) {
|
||||
this.props.onRestoreItem(id);
|
||||
},
|
||||
handleDeleteItem: function(id, confirm = false) {
|
||||
this.props.onDeleteItem(id, confirm);
|
||||
handleTrashItem: function(id) {
|
||||
this.props.onTrashItem(id);
|
||||
},
|
||||
handleDeleteItem: function(id) {
|
||||
this.props.onDeleteItem(id);
|
||||
},
|
||||
handleToggleItem: function(id) {
|
||||
this.setState({ toggled: !this.state.toggled });
|
||||
@ -58,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'
|
||||
}
|
||||
@ -77,12 +79,39 @@ define(
|
||||
|
||||
if(custom_actions.length > 0) {
|
||||
item_actions = custom_actions.map(function(action, index) {
|
||||
return (
|
||||
<span key={ 'action-'+index } className={ action.name }>
|
||||
{ action.link(this.props.item.id) }
|
||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
||||
</span>
|
||||
);
|
||||
if(action.refresh) {
|
||||
return (
|
||||
<span
|
||||
onClick={ this.props.onRefreshItems }
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{ action.link(this.props.item) }
|
||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
||||
</span>
|
||||
);
|
||||
} else if(action.link) {
|
||||
return (
|
||||
<span
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{ action.link(this.props.item) }
|
||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
<a href="javascript:;" onClick={
|
||||
(action.onClick !== undefined)
|
||||
? action.onClick.bind(null,
|
||||
this.props.item,
|
||||
this.props.onRefreshItems
|
||||
)
|
||||
: false
|
||||
}>{ action.label }</a>
|
||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}.bind(this));
|
||||
} else {
|
||||
item_actions = (
|
||||
@ -112,8 +141,7 @@ define(
|
||||
href="javascript:;"
|
||||
onClick={ this.handleDeleteItem.bind(
|
||||
null,
|
||||
this.props.item.id,
|
||||
true
|
||||
this.props.item.id
|
||||
)}
|
||||
>Delete permanently</a>
|
||||
</span>
|
||||
@ -134,10 +162,9 @@ define(
|
||||
<span className="trash">
|
||||
<a
|
||||
href="javascript:;"
|
||||
onClick={ this.handleDeleteItem.bind(
|
||||
onClick={ this.handleTrashItem.bind(
|
||||
null,
|
||||
this.props.item.id,
|
||||
false
|
||||
this.props.item.id
|
||||
) }>
|
||||
Trash
|
||||
</a>
|
||||
@ -222,7 +249,7 @@ define(
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{this.props.items.map(function(item) {
|
||||
{this.props.items.map(function(item, index) {
|
||||
item.id = parseInt(item.id, 10);
|
||||
item.selected = (this.props.selected_ids.indexOf(item.id) !== -1);
|
||||
|
||||
@ -233,11 +260,13 @@ define(
|
||||
onRenderItem={ this.props.onRenderItem }
|
||||
onDeleteItem={ this.props.onDeleteItem }
|
||||
onRestoreItem={ this.props.onRestoreItem }
|
||||
onTrashItem={ this.props.onTrashItem }
|
||||
onRefreshItems={ this.props.onRefreshItems }
|
||||
selection={ this.props.selection }
|
||||
is_selectable={ this.props.is_selectable }
|
||||
item_actions={ this.props.item_actions }
|
||||
group={ this.props.group }
|
||||
key={ 'item-' + item.id }
|
||||
key={ `item-${item.id}-${index}` }
|
||||
item={ item } />
|
||||
);
|
||||
}.bind(this))}
|
||||
@ -248,6 +277,9 @@ define(
|
||||
});
|
||||
|
||||
var Listing = React.createClass({
|
||||
mixins: [
|
||||
Router.History
|
||||
],
|
||||
getInitialState: function() {
|
||||
return {
|
||||
loading: false,
|
||||
@ -260,43 +292,136 @@ define(
|
||||
items: [],
|
||||
groups: [],
|
||||
group: 'all',
|
||||
filters: [],
|
||||
filter: [],
|
||||
filters: {},
|
||||
filter: {},
|
||||
selected_ids: [],
|
||||
selection: false
|
||||
};
|
||||
},
|
||||
componentDidUpdate: function(prevProps, prevState) {
|
||||
// reset group to "all" if trash gets emptied
|
||||
if(
|
||||
// we were viewing the trash
|
||||
(prevState.group === 'trash' && prevState.count > 0)
|
||||
&&
|
||||
// we are still viewing the trash but there are no items left
|
||||
(this.state.group === 'trash' && this.state.count === 0)
|
||||
&&
|
||||
// only do this when no filter is set
|
||||
(Object.keys(this.state.filter).length === 0)
|
||||
) {
|
||||
this.handleGroup('all');
|
||||
}
|
||||
},
|
||||
getParam: function(param) {
|
||||
var regex = /(.*)\[(.*)\]/
|
||||
var matches = regex.exec(param)
|
||||
return [matches[1], matches[2]]
|
||||
},
|
||||
initWithParams: function(params) {
|
||||
let state = this.state || {}
|
||||
let original_state = state
|
||||
// check for url params
|
||||
if(params.splat !== undefined) {
|
||||
params.splat.split('/').map(param => {
|
||||
let [key, value] = this.getParam(param);
|
||||
switch(key) {
|
||||
case 'filter':
|
||||
let filters = {}
|
||||
value.split('&').map(function(pair) {
|
||||
let [k, v] = pair.split('=')
|
||||
filters[k] = v
|
||||
}
|
||||
)
|
||||
|
||||
state.filter = filters
|
||||
break;
|
||||
default:
|
||||
state[key] = value
|
||||
}
|
||||
})
|
||||
}
|
||||
if(this.props.limit !== undefined) {
|
||||
state.limit = Math.abs(~~this.props.limit);
|
||||
}
|
||||
this.setState(state, function() {
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
setParams: function() {
|
||||
var params = Object.keys(this.state)
|
||||
.filter(key => {
|
||||
return (
|
||||
[
|
||||
'group',
|
||||
'filter',
|
||||
'search',
|
||||
'page',
|
||||
'sort_by',
|
||||
'sort_order'
|
||||
].indexOf(key) !== -1
|
||||
)
|
||||
})
|
||||
.map(key => {
|
||||
let value = this.state[key]
|
||||
if(value === Object(value)) {
|
||||
value = jQuery.param(value)
|
||||
} else if(value === Boolean(value)) {
|
||||
value = value.toString()
|
||||
}
|
||||
|
||||
if(value !== '') {
|
||||
return `${key}[${value}]`
|
||||
}
|
||||
})
|
||||
.filter(key => { return (key !== undefined) })
|
||||
.join('/');
|
||||
params = '/'+params
|
||||
|
||||
if(this.props.location) {
|
||||
if(this.props.location.pathname !== params) {
|
||||
this.history.pushState(null, `${params}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
componentDidMount: function() {
|
||||
this.getItems();
|
||||
if(this.isMounted()) {
|
||||
const params = this.props.params || {}
|
||||
this.initWithParams(params)
|
||||
}
|
||||
},
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
const params = nextProps.params || {}
|
||||
this.initWithParams(params)
|
||||
},
|
||||
getItems: function() {
|
||||
this.setState({ loading: true });
|
||||
if(this.isMounted()) {
|
||||
this.setState({ loading: true });
|
||||
|
||||
this.clearSelection();
|
||||
this.clearSelection();
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'listing',
|
||||
data: {
|
||||
offset: (this.state.page - 1) * this.state.limit,
|
||||
limit: this.state.limit,
|
||||
group: this.state.group,
|
||||
filter: this.state.filter,
|
||||
search: this.state.search,
|
||||
sort_by: this.state.sort_by,
|
||||
sort_order: this.state.sort_order
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(this.isMounted()) {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'listing',
|
||||
data: {
|
||||
offset: (this.state.page - 1) * this.state.limit,
|
||||
limit: this.state.limit,
|
||||
group: this.state.group,
|
||||
filter: this.state.filter,
|
||||
search: this.state.search,
|
||||
sort_by: this.state.sort_by,
|
||||
sort_order: this.state.sort_order
|
||||
}
|
||||
}).done(function(response) {
|
||||
this.setState({
|
||||
items: response.items || [],
|
||||
filters: response.filters || [],
|
||||
filters: response.filters || {},
|
||||
groups: response.groups || [],
|
||||
count: response.count || 0,
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
handleRestoreItem: function(id) {
|
||||
this.setState({
|
||||
@ -318,7 +443,27 @@ define(
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
handleDeleteItem: function(id, confirm = false) {
|
||||
handleTrashItem: function(id) {
|
||||
this.setState({
|
||||
loading: true,
|
||||
page: 1
|
||||
});
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'trash',
|
||||
data: id
|
||||
}).done(function(response) {
|
||||
if(
|
||||
this.props.messages !== undefined
|
||||
&& this.props.messages['onTrash'] !== undefined
|
||||
) {
|
||||
this.props.messages.onTrash(response);
|
||||
}
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
handleDeleteItem: function(id) {
|
||||
this.setState({
|
||||
loading: true,
|
||||
page: 1
|
||||
@ -327,31 +472,18 @@ define(
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'delete',
|
||||
data: {
|
||||
id: id,
|
||||
confirm: confirm
|
||||
}
|
||||
data: id
|
||||
}).done(function(response) {
|
||||
if(confirm === true) {
|
||||
if(
|
||||
this.props.messages !== undefined
|
||||
&& this.props.messages['onConfirmDelete'] !== undefined
|
||||
) {
|
||||
this.props.messages.onConfirmDelete(response);
|
||||
}
|
||||
} else {
|
||||
if(
|
||||
this.props.messages !== undefined
|
||||
&& this.props.messages['onDelete'] !== undefined
|
||||
) {
|
||||
this.props.messages.onDelete(response);
|
||||
}
|
||||
if(
|
||||
this.props.messages !== undefined
|
||||
&& this.props.messages['onDelete'] !== undefined
|
||||
) {
|
||||
this.props.messages.onDelete(response);
|
||||
}
|
||||
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
handleBulkAction: function(selected_ids, params) {
|
||||
handleBulkAction: function(selected_ids, params, callback) {
|
||||
if(
|
||||
this.state.selection === false
|
||||
&& this.state.selected_ids.length === 0
|
||||
@ -362,12 +494,6 @@ define(
|
||||
this.setState({ loading: true });
|
||||
|
||||
var data = params || {};
|
||||
var callback = ((data['onSuccess'] !== undefined)
|
||||
? data['onSuccess']
|
||||
: function() {}
|
||||
);
|
||||
delete data.onSuccess;
|
||||
|
||||
data.listing = {
|
||||
offset: 0,
|
||||
limit: 0,
|
||||
@ -379,7 +505,7 @@ define(
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'bulk_action',
|
||||
action: 'bulkAction',
|
||||
data: data
|
||||
}).done(function(response) {
|
||||
this.getItems();
|
||||
@ -393,6 +519,7 @@ define(
|
||||
selection: false,
|
||||
selected_ids: []
|
||||
}, function() {
|
||||
this.setParams();
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
@ -401,6 +528,7 @@ define(
|
||||
sort_by: sort_by,
|
||||
sort_order: sort_order,
|
||||
}, function() {
|
||||
this.setParams();
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
@ -460,6 +588,7 @@ define(
|
||||
filter: filters,
|
||||
page: 1
|
||||
}, function() {
|
||||
this.setParams();
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
@ -469,10 +598,11 @@ define(
|
||||
|
||||
this.setState({
|
||||
group: group,
|
||||
filter: [],
|
||||
filter: {},
|
||||
search: '',
|
||||
page: 1
|
||||
}, function() {
|
||||
this.setParams();
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
@ -482,6 +612,7 @@ define(
|
||||
selection: false,
|
||||
selected_ids: []
|
||||
}, function() {
|
||||
this.setParams();
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
},
|
||||
@ -489,17 +620,14 @@ define(
|
||||
var render = this.props.onRenderItem(item, actions);
|
||||
return render.props.children;
|
||||
},
|
||||
handleRefreshItems: function() {
|
||||
this.getItems();
|
||||
},
|
||||
render: function() {
|
||||
var items = this.state.items,
|
||||
sort_by = this.state.sort_by,
|
||||
sort_order = this.state.sort_order;
|
||||
|
||||
// set sortable columns
|
||||
columns = this.props.columns.map(function(column) {
|
||||
column.sorted = (column.name === sort_by) ? sort_order : false;
|
||||
return column;
|
||||
});
|
||||
|
||||
// bulk actions
|
||||
var bulk_actions = this.props.bulk_actions || [];
|
||||
|
||||
@ -511,12 +639,9 @@ define(
|
||||
onSuccess: this.props.messages.onRestore
|
||||
},
|
||||
{
|
||||
name: 'trash',
|
||||
name: 'delete',
|
||||
label: 'Delete permanently',
|
||||
onSuccess: this.props.messages.onConfirmDelete,
|
||||
getData: function() {
|
||||
return { confirm: true };
|
||||
}
|
||||
onSuccess: this.props.messages.onDelete
|
||||
}
|
||||
];
|
||||
}
|
||||
@ -524,22 +649,42 @@ define(
|
||||
// item actions
|
||||
var item_actions = this.props.item_actions || [];
|
||||
|
||||
var tableClasses = classNames(
|
||||
var table_classes = classNames(
|
||||
'mailpoet_listing_table',
|
||||
'wp-list-table',
|
||||
'widefat',
|
||||
'fixed',
|
||||
'striped',
|
||||
{ 'mailpoet_listing_loading': this.state.loading }
|
||||
);
|
||||
|
||||
// search
|
||||
var search = (
|
||||
<ListingSearch
|
||||
onSearch={ this.handleSearch }
|
||||
search={ this.state.search }
|
||||
/>
|
||||
);
|
||||
if(this.props.search === false) {
|
||||
search = false;
|
||||
}
|
||||
|
||||
// groups
|
||||
var groups = (
|
||||
<ListingGroups
|
||||
groups={ this.state.groups }
|
||||
group={ this.state.group }
|
||||
onSelectGroup={ this.handleGroup }
|
||||
/>
|
||||
);
|
||||
if(this.props.groups === false) {
|
||||
groups = false;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ListingGroups
|
||||
groups={ this.state.groups }
|
||||
group={ this.state.group }
|
||||
onSelectGroup={ this.handleGroup } />
|
||||
<ListingSearch
|
||||
onSearch={ this.handleSearch }
|
||||
search={ this.state.search } />
|
||||
{ groups }
|
||||
{ search }
|
||||
<div className="tablenav top clearfix">
|
||||
<ListingBulkActions
|
||||
bulk_actions={ bulk_actions }
|
||||
@ -548,7 +693,7 @@ define(
|
||||
onBulkAction={ this.handleBulkAction } />
|
||||
<ListingFilters
|
||||
filters={ this.state.filters }
|
||||
filter={ this.state.filter }
|
||||
filter={ this.state.filter }
|
||||
onSelectFilter={ this.handleFilter } />
|
||||
<ListingPages
|
||||
count={ this.state.count }
|
||||
@ -556,7 +701,7 @@ define(
|
||||
limit={ this.state.limit }
|
||||
onSetPage={ this.handleSetPage } />
|
||||
</div>
|
||||
<table className={ tableClasses }>
|
||||
<table className={ table_classes }>
|
||||
<thead>
|
||||
<ListingHeader
|
||||
onSort={ this.handleSort }
|
||||
@ -572,6 +717,8 @@ define(
|
||||
onRenderItem={ this.handleRenderItem }
|
||||
onDeleteItem={ this.handleDeleteItem }
|
||||
onRestoreItem={ this.handleRestoreItem }
|
||||
onTrashItem={ this.handleTrashItem }
|
||||
onRefreshItems={ this.handleRefreshItems }
|
||||
columns={ this.props.columns }
|
||||
is_selectable={ bulk_actions.length > 0 }
|
||||
onSelectItem={ this.handleSelectItem }
|
||||
|
@ -40,23 +40,23 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
},
|
||||
render: function() {
|
||||
if(this.props.count === 0) {
|
||||
return (<div></div>);
|
||||
return false;
|
||||
} else {
|
||||
var pagination,
|
||||
firstPage = (
|
||||
var pagination = false;
|
||||
var firstPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">«</span>
|
||||
),
|
||||
previousPage = (
|
||||
);
|
||||
var previousPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">‹</span>
|
||||
),
|
||||
nextPage = (
|
||||
);
|
||||
var nextPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">›</span>
|
||||
),
|
||||
lastPage = (
|
||||
);
|
||||
var lastPage = (
|
||||
<span aria-hidden="true" className="tablenav-pages-navspan">»</span>
|
||||
);
|
||||
|
||||
if(this.props.count > this.props.limit) {
|
||||
if(this.props.limit > 0 && this.props.count > this.props.limit) {
|
||||
if(this.props.page > 1) {
|
||||
previousPage = (
|
||||
<a href="javascript:;"
|
||||
@ -104,6 +104,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
pagination = (
|
||||
<span className="pagination-links">
|
||||
{firstPage}
|
||||
|
||||
{previousPage}
|
||||
|
||||
<span className="paging-input">
|
||||
@ -128,6 +129,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
</span>
|
||||
|
||||
{nextPage}
|
||||
|
||||
{lastPage}
|
||||
</span>
|
||||
);
|
||||
@ -140,7 +142,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
|
||||
return (
|
||||
<div className={ classes }>
|
||||
<span className="displaying-num">{ this.props.count } item(s)</span>
|
||||
<span className="displaying-num">{ this.props.count } items</span>
|
||||
{ pagination }
|
||||
</div>
|
||||
);
|
||||
|
@ -7,26 +7,33 @@ define(['react'], function(React) {
|
||||
this.refs.search.value
|
||||
);
|
||||
},
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
this.refs.search.value = nextProps.search
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<form name="search" onSubmit={this.handleSearch}>
|
||||
<p className="search-box">
|
||||
<label htmlFor="search_input" className="screen-reader-text">
|
||||
Search
|
||||
</label>
|
||||
<input
|
||||
type="search"
|
||||
id="search_input"
|
||||
ref="search"
|
||||
name="s"
|
||||
defaultValue={this.props.search} />
|
||||
<input
|
||||
type="submit"
|
||||
defaultValue={MailPoetI18n.searchLabel}
|
||||
className="button" />
|
||||
</p>
|
||||
</form>
|
||||
);
|
||||
if(this.props.search === false) {
|
||||
return false;
|
||||
} else {
|
||||
return (
|
||||
<form name="search" onSubmit={this.handleSearch}>
|
||||
<p className="search-box">
|
||||
<label htmlFor="search_input" className="screen-reader-text">
|
||||
Search
|
||||
</label>
|
||||
<input
|
||||
type="search"
|
||||
id="search_input"
|
||||
ref="search"
|
||||
name="s"
|
||||
defaultValue={this.props.search} />
|
||||
<input
|
||||
type="submit"
|
||||
defaultValue={MailPoetI18n.searchLabel}
|
||||
className="button" />
|
||||
</p>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -166,81 +166,62 @@ define([
|
||||
this.$('.mailpoet_automated_latest_content_categories_and_tags').select2({
|
||||
multiple: true,
|
||||
allowClear: true,
|
||||
query: function(options) {
|
||||
var taxonomies = [];
|
||||
// Delegate data loading to our own endpoints
|
||||
WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
search: options.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
return {
|
||||
taxonomies: taxonomies,
|
||||
terms: terms,
|
||||
};
|
||||
ajax: {
|
||||
data: function (params) {
|
||||
return {
|
||||
term: params.term
|
||||
};
|
||||
},
|
||||
transport: function(options, success, failure) {
|
||||
var taxonomies,
|
||||
promise = WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
return {
|
||||
taxonomies: taxonomies,
|
||||
terms: terms,
|
||||
};
|
||||
});
|
||||
return promise;
|
||||
});
|
||||
|
||||
promise.then(success);
|
||||
promise.fail(failure);
|
||||
return promise;
|
||||
}).done(function(args) {
|
||||
},
|
||||
processResults: function(data) {
|
||||
// Transform taxonomies and terms into select2 compatible format
|
||||
options.callback({
|
||||
return {
|
||||
results: _.map(
|
||||
args.terms,
|
||||
data.terms,
|
||||
function(item) {
|
||||
return _.defaults({
|
||||
text: args.taxonomies[item.taxonomy].labels.singular_name + ': ' + item.name,
|
||||
text: data.taxonomies[item.taxonomy].labels.singular_name + ': ' + item.name,
|
||||
id: item.term_id
|
||||
}, item);
|
||||
}
|
||||
)
|
||||
});
|
||||
});
|
||||
};
|
||||
},
|
||||
},
|
||||
initSelection: function(element, callback) {
|
||||
// On external data load tell select2 which terms to preselect
|
||||
|
||||
callback(_.map(
|
||||
that.model.get('terms').toJSON(),
|
||||
function(item) {
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.text,
|
||||
};
|
||||
}
|
||||
));
|
||||
}).on({
|
||||
'select2:select': function(event) {
|
||||
var terms = that.model.get('terms');
|
||||
terms.add(event.params.data);
|
||||
// Reset whole model in order for change events to propagate properly
|
||||
that.model.set('terms', terms.toJSON());
|
||||
},
|
||||
}).trigger( 'change' ).on({
|
||||
'change': function(e){
|
||||
var data = jQuery(this).data('selected');
|
||||
|
||||
if (typeof data === 'string') {
|
||||
if (data === '') {
|
||||
data = [];
|
||||
} else {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
if ( e.added ){
|
||||
data.push(e.added);
|
||||
} else {
|
||||
data = _.filter(data, function(item) {
|
||||
return item.id !== e.removed.id;
|
||||
});
|
||||
}
|
||||
|
||||
// Update ALC model
|
||||
that.model.set('terms', data);
|
||||
|
||||
jQuery(this).data('selected', JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
|
||||
// Force close select2 if it hasn't closed yet
|
||||
this.$('.mailpoet_automated_latest_content_categories_and_tags').select2('close');
|
||||
'select2:unselect': function(event) {
|
||||
var terms = that.model.get('terms');
|
||||
terms.remove(event.params.data);
|
||||
// Reset whole model in order for change events to propagate properly
|
||||
that.model.set('terms', terms.toJSON());
|
||||
},
|
||||
}).trigger( 'change' );
|
||||
},
|
||||
toggleDisplayOptions: function(event) {
|
||||
var el = this.$('.mailpoet_automated_latest_content_display_options'),
|
||||
|
@ -297,9 +297,9 @@ define([
|
||||
// Following advice from Becs, the target width should
|
||||
// be a double of one column width to render well on
|
||||
// retina screen devices
|
||||
targetImageWidth = 1200,
|
||||
targetImageWidth = 1320,
|
||||
|
||||
// For main image use the size, that's closest to being 600px in width
|
||||
// For main image use the size, that's closest to being 660px in width
|
||||
sizeKeys = _.keys(sizes),
|
||||
|
||||
// Pick the width that is closest to target width
|
||||
|
@ -21,7 +21,8 @@ define([
|
||||
'newsletter_editor/components/wordpress',
|
||||
'newsletter_editor/blocks/base',
|
||||
'newsletter_editor/blocks/button',
|
||||
'newsletter_editor/blocks/divider'
|
||||
'newsletter_editor/blocks/divider',
|
||||
'select2'
|
||||
], function(Backbone, Marionette, Radio, _, jQuery, MailPoet, App, WordpressComponent, BaseBlock, ButtonBlock, DividerBlock) {
|
||||
|
||||
"use strict";
|
||||
@ -249,59 +250,62 @@ define([
|
||||
this.$('.mailpoet_posts_categories_and_tags').select2({
|
||||
multiple: true,
|
||||
allowClear: true,
|
||||
query: function(options) {
|
||||
var taxonomies = [];
|
||||
// Delegate data loading to our own endpoints
|
||||
WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
search: options.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
return {
|
||||
taxonomies: taxonomies,
|
||||
terms: terms,
|
||||
};
|
||||
ajax: {
|
||||
data: function (params) {
|
||||
return {
|
||||
term: params.term
|
||||
};
|
||||
},
|
||||
transport: function(options, success, failure) {
|
||||
var taxonomies,
|
||||
promise = WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
return {
|
||||
taxonomies: taxonomies,
|
||||
terms: terms,
|
||||
};
|
||||
});
|
||||
return promise;
|
||||
});
|
||||
|
||||
promise.then(success);
|
||||
promise.fail(failure);
|
||||
return promise;
|
||||
}).done(function(args) {
|
||||
},
|
||||
processResults: function(data) {
|
||||
// Transform taxonomies and terms into select2 compatible format
|
||||
options.callback({
|
||||
return {
|
||||
results: _.map(
|
||||
args.terms,
|
||||
data.terms,
|
||||
function(item) {
|
||||
return _.defaults({
|
||||
text: args.taxonomies[item.taxonomy].labels.singular_name + ': ' + item.name,
|
||||
text: data.taxonomies[item.taxonomy].labels.singular_name + ': ' + item.name,
|
||||
id: item.term_id
|
||||
}, item);
|
||||
}
|
||||
)
|
||||
});
|
||||
});
|
||||
};
|
||||
},
|
||||
},
|
||||
}).trigger( 'change' ).on({
|
||||
'change': function(e){
|
||||
var data = [];
|
||||
|
||||
if (typeof data === 'string') {
|
||||
if (data === '') {
|
||||
data = [];
|
||||
} else {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
if ( e.added ){
|
||||
data.push(e.added);
|
||||
}
|
||||
|
||||
// Update ALC model
|
||||
that.model.set('terms', data);
|
||||
|
||||
jQuery(this).data('selected', JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
}).on({
|
||||
'select2:select': function(event) {
|
||||
var terms = that.model.get('terms');
|
||||
terms.add(event.params.data);
|
||||
// Reset whole model in order for change events to propagate properly
|
||||
that.model.set('terms', terms.toJSON());
|
||||
},
|
||||
'select2:unselect': function(event) {
|
||||
var terms = that.model.get('terms');
|
||||
terms.remove(event.params.data);
|
||||
// Reset whole model in order for change events to propagate properly
|
||||
that.model.set('terms', terms.toJSON());
|
||||
},
|
||||
}).trigger( 'change' );
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
|
||||
|
@ -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() {
|
||||
|
@ -37,19 +37,77 @@ define(
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
onTrash: function(response) {
|
||||
var count = ~~response.newsletters;
|
||||
var message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
message = (
|
||||
'1 newsletter was moved to the trash.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d newsletters were moved to the trash.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
},
|
||||
onDelete: function(response) {
|
||||
var count = ~~response.newsletters;
|
||||
var message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
message = (
|
||||
'1 newsletter was permanently deleted.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d newsletters were permanently deleted.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
},
|
||||
onRestore: function(response) {
|
||||
var count = ~~response.newsletters;
|
||||
var message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
message = (
|
||||
'1 newsletter has been restored from the trash.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d newsletters have been restored from the trash.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash'
|
||||
label: 'Trash',
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
|
||||
var item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
link: function(id) {
|
||||
link: function(item) {
|
||||
return (
|
||||
<a href={ '?page=mailpoet-newsletter-editor&id=' + id }>
|
||||
<a href={ `?page=mailpoet-newsletter-editor&id=${ item.id }` }>
|
||||
Edit
|
||||
</a>
|
||||
);
|
||||
@ -100,11 +158,13 @@ define(
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
params={ this.props.params }
|
||||
endpoint="newsletters"
|
||||
onRenderItem={this.renderItem}
|
||||
columns={columns}
|
||||
bulk_actions={ bulk_actions }
|
||||
item_actions={ item_actions } />
|
||||
item_actions={ item_actions }
|
||||
messages={ messages } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import NewsletterTemplates from 'newsletters/templates.jsx'
|
||||
import NewsletterSend from 'newsletters/send.jsx'
|
||||
import NewsletterStandard from 'newsletters/types/standard.jsx'
|
||||
import NewsletterWelcome from 'newsletters/types/welcome.jsx'
|
||||
import NewsletterNotification from 'newsletters/types/notification.jsx'
|
||||
import createHashHistory from 'history/lib/createHashHistory'
|
||||
|
||||
let history = createHashHistory({ queryKey: false })
|
||||
@ -27,8 +28,10 @@ if(container) {
|
||||
<Route path="new" component={ NewsletterTypes } />
|
||||
<Route name="standard" path="new/standard" component={ NewsletterStandard } />
|
||||
<Route name="welcome" path="new/welcome" component={ NewsletterWelcome } />
|
||||
<Route name="notification" path="new/notification" component={ NewsletterNotification } />
|
||||
<Route name="template" path="template/:id" component={ NewsletterTemplates } />
|
||||
<Route path="send/:id" component={ NewsletterSend } />
|
||||
<Route path="filter[:filter]" component={ NewsletterList } />
|
||||
<Route path="*" component={ NewsletterList } />
|
||||
</Route>
|
||||
</Router>
|
||||
|
@ -34,8 +34,7 @@ define(
|
||||
placeholder: "Select a list",
|
||||
id: "mailpoet_segments",
|
||||
endpoint: "segments",
|
||||
multiple: true,
|
||||
select2: true
|
||||
multiple: true
|
||||
},
|
||||
{
|
||||
name: 'sender',
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -85,6 +85,26 @@ define(
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li data-type="notification">
|
||||
<div className="mailpoet_thumbnail"></div>
|
||||
|
||||
<div className="mailpoet_description">
|
||||
<h3>Post notifications</h3>
|
||||
<p>
|
||||
Automatically send posts immediately, daily, weekly or monthly. Filter by categories, if you like.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mailpoet_actions">
|
||||
<a
|
||||
className="button button-primary"
|
||||
onClick={ this.setupNewsletter.bind(null, 'notification') }
|
||||
>
|
||||
Set up
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
225
assets/js/src/newsletters/types/notification.jsx
Normal file
225
assets/js/src/newsletters/types/notification.jsx
Normal file
@ -0,0 +1,225 @@
|
||||
define(
|
||||
[
|
||||
'underscore',
|
||||
'react',
|
||||
'react-router',
|
||||
'mailpoet',
|
||||
'form/form.jsx',
|
||||
'form/fields/select.jsx',
|
||||
'form/fields/selection.jsx',
|
||||
'form/fields/text.jsx',
|
||||
'newsletters/breadcrumb.jsx'
|
||||
],
|
||||
function(
|
||||
_,
|
||||
React,
|
||||
Router,
|
||||
MailPoet,
|
||||
Form,
|
||||
Select,
|
||||
Selection,
|
||||
Text,
|
||||
Breadcrumb
|
||||
) {
|
||||
|
||||
var intervalField = {
|
||||
name: 'interval',
|
||||
values: {
|
||||
'daily': 'Once a day at...',
|
||||
'weekly': 'Weekly on...',
|
||||
'monthly': 'Monthly on the...',
|
||||
'nthWeekDay': 'Monthly every...',
|
||||
'immediately': 'Immediately.',
|
||||
},
|
||||
};
|
||||
|
||||
var SECONDS_IN_DAY = 86400;
|
||||
var TIME_STEP_SECONDS = 3600; // Default: 3600
|
||||
var numberOfTimeSteps = SECONDS_IN_DAY / TIME_STEP_SECONDS;
|
||||
var timeOfDayValues = _.object(_.map(
|
||||
_.times(numberOfTimeSteps, function(step) { return step * TIME_STEP_SECONDS; }),
|
||||
function(seconds) {
|
||||
var date = new Date(null);
|
||||
date.setSeconds(seconds);
|
||||
var timeLabel = date.toISOString().substr(11, 5);
|
||||
return [seconds, timeLabel];
|
||||
}
|
||||
));
|
||||
var timeOfDayField = {
|
||||
name: 'timeOfDay',
|
||||
values: timeOfDayValues,
|
||||
};
|
||||
|
||||
var weekDayField = {
|
||||
name: 'weekDay',
|
||||
values: {
|
||||
0: 'Monday',
|
||||
1: 'Tuesday',
|
||||
2: 'Wednesday',
|
||||
3: 'Thursday',
|
||||
4: 'Friday',
|
||||
5: 'Saturday',
|
||||
6: 'Sunday',
|
||||
},
|
||||
};
|
||||
|
||||
var NUMBER_OF_DAYS_IN_MONTH = 28; // 28 for compatibility with MP2
|
||||
var monthDayField = {
|
||||
name: 'monthDay',
|
||||
values: _.object(_.map(
|
||||
_.times(NUMBER_OF_DAYS_IN_MONTH, function(day) { return day; }),
|
||||
function(day) {
|
||||
var suffixes = {
|
||||
0: 'st',
|
||||
1: 'nd',
|
||||
2: 'rd'
|
||||
};
|
||||
var suffix = suffixes[day] || 'th';
|
||||
|
||||
return [day, (day + 1).toString() + suffix];
|
||||
},
|
||||
)),
|
||||
};
|
||||
|
||||
var nthWeekDayField = {
|
||||
name: 'nthWeekDay',
|
||||
values: {
|
||||
'0': '1st',
|
||||
'1': '2nd',
|
||||
'2': '3rd',
|
||||
'3': 'last',
|
||||
},
|
||||
};
|
||||
|
||||
var NewsletterWelcome = React.createClass({
|
||||
mixins: [
|
||||
Router.History
|
||||
],
|
||||
getInitialState: function() {
|
||||
return {
|
||||
intervalType: 'immediate', // 'immediate'|'daily'|'weekly'|'monthly'
|
||||
timeOfDay: 0,
|
||||
weekDay: 0,
|
||||
monthDay: 0,
|
||||
nthWeekDay: 0,
|
||||
};
|
||||
},
|
||||
handleIntervalChange: function(event) {
|
||||
this.setState({
|
||||
intervalType: event.target.value,
|
||||
});
|
||||
},
|
||||
handleTimeOfDayChange: function(event) {
|
||||
this.setState({
|
||||
timeOfDay: event.target.value,
|
||||
});
|
||||
},
|
||||
handleWeekDayChange: function(event) {
|
||||
this.setState({
|
||||
weekDay: event.target.value,
|
||||
});
|
||||
},
|
||||
handleMonthDayChange: function(event) {
|
||||
this.setState({
|
||||
monthDay: event.target.value,
|
||||
});
|
||||
},
|
||||
handleNthWeekDayChange: function(event) {
|
||||
this.setState({
|
||||
nthWeekDay: event.target.value,
|
||||
});
|
||||
},
|
||||
handleNext: function() {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'create',
|
||||
data: {
|
||||
type: 'notification',
|
||||
options: this.state,
|
||||
},
|
||||
}).done(function(response) {
|
||||
if(response.id !== undefined) {
|
||||
this.showTemplateSelection(response.id);
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
showTemplateSelection: function(newsletterId) {
|
||||
this.history.pushState(null, `/template/${newsletterId}`);
|
||||
},
|
||||
render: function() {
|
||||
var timeOfDaySelection,
|
||||
weekDaySelection,
|
||||
monthDaySelection,
|
||||
nthWeekDaySelection;
|
||||
|
||||
if (this.state.intervalType !== 'immediately') {
|
||||
timeOfDaySelection = (
|
||||
<Select
|
||||
field={timeOfDayField}
|
||||
item={this.state}
|
||||
onValueChange={this.handleTimeOfDayChange} />
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.intervalType === 'weekly'
|
||||
|| this.state.intervalType === 'nthWeekDay') {
|
||||
weekDaySelection = (
|
||||
<Select
|
||||
field={weekDayField}
|
||||
item={this.state}
|
||||
onValueChange={this.handleWeekDayChange} />
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.intervalType === 'monthly') {
|
||||
monthDaySelection = (
|
||||
<Select
|
||||
field={monthDayField}
|
||||
item={this.state}
|
||||
onValueChange={this.handleMonthDayChange} />
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.intervalType === 'nthWeekDay') {
|
||||
nthWeekDaySelection = (
|
||||
<Select
|
||||
field={nthWeekDayField}
|
||||
item={this.state}
|
||||
onValueChange={this.handleNthWeekDayChange} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Post notifications</h1>
|
||||
<Breadcrumb step="type" />
|
||||
|
||||
<Select
|
||||
field={intervalField}
|
||||
item={this.state}
|
||||
onValueChange={this.handleIntervalChange} />
|
||||
|
||||
{nthWeekDaySelection}
|
||||
{monthDaySelection}
|
||||
{weekDaySelection}
|
||||
{timeOfDaySelection}
|
||||
|
||||
<p className="submit">
|
||||
<input
|
||||
className="button button-primary"
|
||||
type="button"
|
||||
onClick={ this.handleNext }
|
||||
value="Next" />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return NewsletterWelcome;
|
||||
}
|
||||
);
|
@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
@ -17,6 +17,11 @@ define(
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
label: 'Description',
|
||||
type: 'textarea'
|
||||
}
|
||||
];
|
||||
|
||||
@ -29,21 +34,27 @@ define(
|
||||
}
|
||||
};
|
||||
|
||||
var Link = Router.Link;
|
||||
|
||||
var SegmentForm = React.createClass({
|
||||
mixins: [
|
||||
Router.History
|
||||
],
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Segment <Link className="add-new-h2" to="/">Back to list</Link>
|
||||
Segment <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
endpoint="segments"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages } />
|
||||
messages={ messages }
|
||||
onSuccess={ this.history.goBack } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,85 +1,202 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'listing/listing.jsx',
|
||||
'classnames'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
Listing,
|
||||
classNames
|
||||
) {
|
||||
var columns = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'updated_at',
|
||||
label: 'Last modified on',
|
||||
sortable: true
|
||||
}
|
||||
];
|
||||
import React from 'react'
|
||||
import { Router, Link } from 'react-router'
|
||||
|
||||
var bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash'
|
||||
}
|
||||
];
|
||||
import jQuery from 'jquery'
|
||||
import MailPoet from 'mailpoet'
|
||||
import classNames from 'classnames'
|
||||
|
||||
var Link = Router.Link;
|
||||
import Listing from 'listing/listing.jsx'
|
||||
|
||||
var SegmentList = React.createClass({
|
||||
renderItem: function(segment, actions) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
'has-row-actions'
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<td className={ rowClasses }>
|
||||
<strong>
|
||||
<a>{ segment.name }</a>
|
||||
</strong>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed on">
|
||||
<abbr>{ segment.created_at }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Last modified on">
|
||||
<abbr>{ segment.updated_at }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Segments <Link className="add-new-h2" to="/new">New</Link>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
endpoint="segments"
|
||||
onRenderItem={this.renderItem}
|
||||
columns={columns}
|
||||
bulk_actions={ bulk_actions } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return SegmentList;
|
||||
var columns = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
label: 'Description',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'subscribed',
|
||||
label: 'Subscribed',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'unconfirmed',
|
||||
label: 'Unconfirmed',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'unsubscribed',
|
||||
label: 'Unsubscribed',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
sortable: true
|
||||
}
|
||||
);
|
||||
];
|
||||
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was moved to the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d segments were moved to the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDelete: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was permanently deleted.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d segments were permanently deleted.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onRestore: function(response) {
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment has been restored from the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d segments have been restored from the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
link: function(item) {
|
||||
return (
|
||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'duplicate_segment',
|
||||
label: 'Duplicate',
|
||||
onClick: function(item, refresh) {
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'segments',
|
||||
action: 'duplicate',
|
||||
data: item.id
|
||||
}).done(function(response) {
|
||||
MailPoet.Notice.success(
|
||||
('List "%$1s" has been duplicated.').replace('%$1s', response.name)
|
||||
);
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'view_subscribers',
|
||||
link: function(item) {
|
||||
return (
|
||||
<a href={ item.subscribers_url }>View subscribers</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
|
||||
const SegmentList = React.createClass({
|
||||
renderItem: function(segment, actions) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
'has-row-actions'
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<td className={ rowClasses }>
|
||||
<strong>
|
||||
<a>{ segment.name }</a>
|
||||
</strong>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Description">
|
||||
<abbr>{ segment.description }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed">
|
||||
<abbr>{ segment.subscribed || 0 }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Unconfirmed">
|
||||
<abbr>{ segment.unconfirmed || 0 }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Unsubscribed">
|
||||
<abbr>{ segment.unsubscribed || 0 }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Created on">
|
||||
<abbr>{ segment.created_at }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Segments <Link className="add-new-h2" to="/new">New</Link>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
location={ this.props.location }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
search={ false }
|
||||
limit={ 1000 }
|
||||
endpoint="segments"
|
||||
onRenderItem={ this.renderItem }
|
||||
columns={ columns }
|
||||
bulk_actions={ bulk_actions }
|
||||
item_actions={ item_actions }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SegmentList;
|
@ -52,18 +52,26 @@ define(
|
||||
var Link = Router.Link;
|
||||
|
||||
var SubscriberForm = React.createClass({
|
||||
mixins: [
|
||||
Router.History
|
||||
],
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscriber <Link className="add-new-h2" to="/">Back to list</Link>
|
||||
Subscriber <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
endpoint="subscribers"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages } />
|
||||
messages={ messages }
|
||||
onSuccess={ this.history.goBack } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,313 +1,294 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'listing/listing.jsx',
|
||||
'form/fields/selection.jsx',
|
||||
'classnames',
|
||||
'mailpoet',
|
||||
'jquery',
|
||||
'select2'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
Listing,
|
||||
Selection,
|
||||
classNames,
|
||||
MailPoet,
|
||||
jQuery
|
||||
) {
|
||||
var Link = Router.Link;
|
||||
import React from 'react'
|
||||
import { Router, Route, Link } from 'react-router'
|
||||
|
||||
var columns = [
|
||||
{
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'first_name',
|
||||
label: 'Firstname',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'last_name',
|
||||
label: 'Lastname',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
sortable: false
|
||||
},
|
||||
import jQuery from 'jquery'
|
||||
import MailPoet from 'mailpoet'
|
||||
import classNames from 'classnames'
|
||||
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Subscribed on',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'updated_at',
|
||||
label: 'Last modified on',
|
||||
sortable: true
|
||||
},
|
||||
];
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import Selection from 'form/fields/selection.jsx'
|
||||
|
||||
var messages = {
|
||||
onDelete: function(response) {
|
||||
var count = ~~response.subscribers;
|
||||
var message = null;
|
||||
const columns = [
|
||||
{
|
||||
name: 'email',
|
||||
label: 'Subscriber',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
sortable: false
|
||||
},
|
||||
|
||||
if(count === 1) {
|
||||
message = (
|
||||
'1 subscriber was moved to the trash.'
|
||||
).replace('%$1d', count);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d subscribers were moved to the trash.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Subscribed on',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'updated_at',
|
||||
label: 'Last modified on',
|
||||
sortable: true
|
||||
},
|
||||
];
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
},
|
||||
onConfirmDelete: function(response) {
|
||||
var count = ~~response.subscribers;
|
||||
var message = null;
|
||||
|
||||
if(count === 1) {
|
||||
message = (
|
||||
'1 subscriber was permanently deleted.'
|
||||
).replace('%$1d', count);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d subscribers were permanently deleted.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
},
|
||||
onRestore: function(response) {
|
||||
var count = ~~response.subscribers;
|
||||
var message = null;
|
||||
|
||||
if(count === 1) {
|
||||
message = (
|
||||
'1 subscriber has been restored from the trash.'
|
||||
).replace('%$1d', count);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d subscribers have been restored from the trash.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var bulk_actions = [
|
||||
{
|
||||
name: 'moveToList',
|
||||
label: 'Move to list...',
|
||||
onSelect: function() {
|
||||
var field = {
|
||||
id: 'move_to_segment',
|
||||
endpoint: 'segments'
|
||||
};
|
||||
|
||||
return (
|
||||
<Selection field={ field }/>
|
||||
);
|
||||
},
|
||||
getData: function() {
|
||||
return {
|
||||
segment_id: ~~(jQuery('#move_to_segment').val())
|
||||
}
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were moved to list <strong>%$2s</strong>.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'addToList',
|
||||
label: 'Add to list...',
|
||||
onSelect: function() {
|
||||
var field = {
|
||||
id: 'add_to_segment',
|
||||
endpoint: 'segments'
|
||||
};
|
||||
|
||||
return (
|
||||
<Selection field={ field }/>
|
||||
);
|
||||
},
|
||||
getData: function() {
|
||||
return {
|
||||
segment_id: ~~(jQuery('#add_to_segment').val())
|
||||
}
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were added to list <strong>%$2s</strong>.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'removeFromList',
|
||||
label: 'Remove from list...',
|
||||
onSelect: function() {
|
||||
var field = {
|
||||
id: 'remove_from_segment',
|
||||
endpoint: 'segments'
|
||||
};
|
||||
|
||||
return (
|
||||
<Selection field={ field }/>
|
||||
);
|
||||
},
|
||||
getData: function() {
|
||||
return {
|
||||
segment_id: ~~(jQuery('#remove_from_segment').val())
|
||||
}
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were removed from list <strong>%$2s</strong>.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'removeFromAllLists',
|
||||
label: 'Remove from all lists',
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were removed from all lists.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'confirmUnconfirmed',
|
||||
label: 'Confirm unconfirmed',
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers have been confirmed.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
getData: function() {
|
||||
return {
|
||||
confirm: false
|
||||
}
|
||||
},
|
||||
onSuccess: messages.onDelete
|
||||
}
|
||||
];
|
||||
|
||||
var SubscriberList = React.createClass({
|
||||
renderItem: function(subscriber, actions) {
|
||||
var row_classes = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
'has-row-actions'
|
||||
);
|
||||
|
||||
var status = '';
|
||||
|
||||
switch(subscriber.status) {
|
||||
case 'subscribed':
|
||||
status = 'Subscribed';
|
||||
break;
|
||||
|
||||
case 'unconfirmed':
|
||||
status = 'Unconfirmed';
|
||||
break;
|
||||
|
||||
case 'unsubscribed':
|
||||
status = 'Unsubscribed';
|
||||
break;
|
||||
}
|
||||
|
||||
var segments = mailpoet_segments.filter(function(segment) {
|
||||
return (jQuery.inArray(segment.id, subscriber.segments) !== -1);
|
||||
}).map(function(segment) {
|
||||
return segment.name;
|
||||
}).join(', ');
|
||||
|
||||
var row_actions = false;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<td className={ row_classes }>
|
||||
<strong><Link to={ `/edit/${ subscriber.id }` }>
|
||||
{ subscriber.email }
|
||||
</Link></strong>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column" data-colname="First name">
|
||||
{ subscriber.first_name }
|
||||
</td>
|
||||
<td className="column" data-colname="Last name">
|
||||
{ subscriber.last_name }
|
||||
</td>
|
||||
<td className="column" data-colname="Status">
|
||||
{ status }
|
||||
</td>
|
||||
<td className="column" data-colname="Lists">
|
||||
{ segments }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed on">
|
||||
<abbr>{ subscriber.created_at }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Last modified on">
|
||||
<abbr>{ subscriber.updated_at }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscribers <Link className="add-new-h2" to="/new">New</Link>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
endpoint="subscribers"
|
||||
onRenderItem={ this.renderItem }
|
||||
columns={ columns }
|
||||
bulk_actions={ bulk_actions }
|
||||
messages={ messages }
|
||||
/>
|
||||
</div>
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 subscriber was moved to the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d subscribers were moved to the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
});
|
||||
|
||||
return SubscriberList;
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDelete: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 subscriber was permanently deleted.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d subscribers were permanently deleted.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onRestore: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 subscriber has been restored from the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d subscribers have been restored from the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'moveToList',
|
||||
label: 'Move to list...',
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'move_to_segment',
|
||||
endpoint: 'segments'
|
||||
};
|
||||
|
||||
return (
|
||||
<Selection field={ field }/>
|
||||
);
|
||||
},
|
||||
getData: function() {
|
||||
return {
|
||||
segment_id: ~~(jQuery('#move_to_segment').val())
|
||||
}
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were moved to list <strong>%$2s</strong>.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'addToList',
|
||||
label: 'Add to list...',
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'add_to_segment',
|
||||
endpoint: 'segments'
|
||||
};
|
||||
|
||||
return (
|
||||
<Selection field={ field }/>
|
||||
);
|
||||
},
|
||||
getData: function() {
|
||||
return {
|
||||
segment_id: ~~(jQuery('#add_to_segment').val())
|
||||
}
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were added to list <strong>%$2s</strong>.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'removeFromList',
|
||||
label: 'Remove from list...',
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'remove_from_segment',
|
||||
endpoint: 'segments'
|
||||
};
|
||||
|
||||
return (
|
||||
<Selection field={ field }/>
|
||||
);
|
||||
},
|
||||
getData: function() {
|
||||
return {
|
||||
segment_id: ~~(jQuery('#remove_from_segment').val())
|
||||
}
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were removed from list <strong>%$2s</strong>.'
|
||||
.replace('%$1d', ~~response.subscribers)
|
||||
.replace('%$2s', response.segment)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'removeFromAllLists',
|
||||
label: 'Remove from all lists',
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers were removed from all lists.'
|
||||
.replace('%$1d', ~~response)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'confirmUnconfirmed',
|
||||
label: 'Confirm unconfirmed',
|
||||
onSuccess: function(response) {
|
||||
MailPoet.Notice.success(
|
||||
'%$1d subscribers have been confirmed.'
|
||||
.replace('%$1d', ~~response)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
|
||||
const SubscriberList = React.createClass({
|
||||
renderItem: function(subscriber, actions) {
|
||||
let row_classes = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
'has-row-actions',
|
||||
'column-username'
|
||||
);
|
||||
|
||||
let status = '';
|
||||
|
||||
switch(subscriber.status) {
|
||||
case 'subscribed':
|
||||
status = 'Subscribed';
|
||||
break;
|
||||
|
||||
case 'unconfirmed':
|
||||
status = 'Unconfirmed';
|
||||
break;
|
||||
|
||||
case 'unsubscribed':
|
||||
status = 'Unsubscribed';
|
||||
break;
|
||||
}
|
||||
|
||||
let segments = mailpoet_segments.filter(function(segment) {
|
||||
return (jQuery.inArray(segment.id, subscriber.segments) !== -1);
|
||||
}).map(function(segment) {
|
||||
return segment.name;
|
||||
}).join(', ');
|
||||
|
||||
let avatar = false;
|
||||
if(subscriber.avatar_url) {
|
||||
avatar = (
|
||||
<img
|
||||
className="avatar"
|
||||
src={ subscriber.avatar_url }
|
||||
title=""
|
||||
width="32"
|
||||
height="32"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<td className={ row_classes }>
|
||||
<strong><Link to={ `/edit/${ subscriber.id }` }>
|
||||
{ subscriber.email }
|
||||
</Link></strong>
|
||||
<p style={{margin: 0}}>
|
||||
{ subscriber.first_name } { subscriber.last_name }
|
||||
</p>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column" data-colname="Status">
|
||||
{ status }
|
||||
</td>
|
||||
<td className="column" data-colname="Lists">
|
||||
{ segments }
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed on">
|
||||
<abbr>{ subscriber.created_at }</abbr>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Last modified on">
|
||||
<abbr>{ subscriber.updated_at }</abbr>
|
||||
</td>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscribers <Link className="add-new-h2" to="/new">New</Link>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
location={ this.props.location }
|
||||
params={ this.props.params }
|
||||
endpoint="subscribers"
|
||||
onRenderItem={ this.renderItem }
|
||||
columns={ columns }
|
||||
bulk_actions={ bulk_actions }
|
||||
messages={ messages }
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SubscriberList;
|
@ -5,15 +5,15 @@ import SubscriberList from 'subscribers/list.jsx'
|
||||
import SubscriberForm from 'subscribers/form.jsx'
|
||||
import createHashHistory from 'history/lib/createHashHistory'
|
||||
|
||||
let history = createHashHistory({ queryKey: false })
|
||||
const history = createHashHistory({ queryKey: false })
|
||||
|
||||
const App = React.createClass({
|
||||
render() {
|
||||
return this.props.children
|
||||
return this.props.children;
|
||||
}
|
||||
});
|
||||
|
||||
let container = document.getElementById('subscribers_container');
|
||||
const container = document.getElementById('subscribers_container')
|
||||
|
||||
if(container) {
|
||||
ReactDOM.render((
|
||||
|
@ -7,7 +7,8 @@
|
||||
"sunra/php-simple-html-dom-parser": "*",
|
||||
"tburry/pquery": "*",
|
||||
"j4mie/paris": "1.5.4",
|
||||
"swiftmailer/swiftmailer": "^5.4"
|
||||
"swiftmailer/swiftmailer": "^5.4",
|
||||
"phpseclib/phpseclib": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/codeception": "*",
|
||||
|
392
composer.lock
generated
392
composer.lock
generated
@ -4,8 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "92704d2679fce692438b9e6f1dc6e02f",
|
||||
"content-hash": "3297411fcec47a02bc4f456fbf3751d1",
|
||||
"hash": "7d7ef94b6e40ac2b2d594e5832d7e16d",
|
||||
"content-hash": "2e70c335edf7429df0794ebf49e2f210",
|
||||
"packages": [
|
||||
{
|
||||
"name": "cerdic/css-tidy",
|
||||
@ -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,95 @@
|
||||
}
|
||||
],
|
||||
"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",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a74aa9efbe61430fcb60157c8e025a48ec8ff604",
|
||||
"reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "~2.7",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"sami/sami": "~2.0",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
||||
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
||||
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
||||
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.",
|
||||
"pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 5.0.0."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpseclib\\": "phpseclib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
"phpseclib/"
|
||||
],
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jim Wigginton",
|
||||
"email": "terrafrost@php.net",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Patrick Monnerat",
|
||||
"email": "pm@datasphere.ch",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Fischer",
|
||||
"email": "bantu@phpbb.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Hans-Jürgen Petrich",
|
||||
"email": "petrich@tronic-media.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
|
||||
"homepage": "http://phpseclib.sourceforge.net",
|
||||
"keywords": [
|
||||
"BigInteger",
|
||||
"aes",
|
||||
"asn.1",
|
||||
"asn1",
|
||||
"blowfish",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"encryption",
|
||||
"rsa",
|
||||
"security",
|
||||
"sftp",
|
||||
"signature",
|
||||
"signing",
|
||||
"ssh",
|
||||
"twofish",
|
||||
"x.509",
|
||||
"x509"
|
||||
],
|
||||
"time": "2015-08-04 04:48:03"
|
||||
},
|
||||
{
|
||||
"name": "sunra/php-simple-html-dom-parser",
|
||||
@ -368,16 +457,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.22.3",
|
||||
"version": "v1.23.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "ebfc36b7e77b0c1175afe30459cf943010245540"
|
||||
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ebfc36b7e77b0c1175afe30459cf943010245540",
|
||||
"reference": "ebfc36b7e77b0c1175afe30459cf943010245540",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
|
||||
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -390,7 +479,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.22-dev"
|
||||
"dev-master": "1.23-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -425,7 +514,7 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2015-10-13 07:07:02"
|
||||
"time": "2015-11-05 12:49:06"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@ -545,16 +634,16 @@
|
||||
},
|
||||
{
|
||||
"name": "codegyre/robo",
|
||||
"version": "0.5.4",
|
||||
"version": "0.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codegyre/Robo.git",
|
||||
"reference": "10aa223f6d1db182dc81d723bf1545dfc6ff380d"
|
||||
"reference": "d18185f0494c854d36aa5ee0ad931ee23bbef552"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codegyre/Robo/zipball/10aa223f6d1db182dc81d723bf1545dfc6ff380d",
|
||||
"reference": "10aa223f6d1db182dc81d723bf1545dfc6ff380d",
|
||||
"url": "https://api.github.com/repos/Codegyre/Robo/zipball/d18185f0494c854d36aa5ee0ad931ee23bbef552",
|
||||
"reference": "d18185f0494c854d36aa5ee0ad931ee23bbef552",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -568,6 +657,7 @@
|
||||
"require-dev": {
|
||||
"codeception/aspect-mock": "0.5.*",
|
||||
"codeception/base": "~2.1",
|
||||
"codeception/codeception": "2.1",
|
||||
"codeception/verify": "0.2.*",
|
||||
"natxet/cssmin": "~3.0",
|
||||
"patchwork/jsqueeze": "~1.0"
|
||||
@ -592,7 +682,7 @@
|
||||
}
|
||||
],
|
||||
"description": "Modern task runner",
|
||||
"time": "2015-08-31 17:35:30"
|
||||
"time": "2015-10-30 11:29:52"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
@ -650,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": {
|
||||
@ -689,7 +779,7 @@
|
||||
"selenium",
|
||||
"webdriver"
|
||||
],
|
||||
"time": "2015-08-12 20:21:31"
|
||||
"time": "2015-11-01 20:09:34"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
@ -806,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": {
|
||||
@ -860,19 +950,19 @@
|
||||
"stream",
|
||||
"uri"
|
||||
],
|
||||
"time": "2015-08-15 19:32:36"
|
||||
"time": "2015-11-03 01:34:55"
|
||||
},
|
||||
{
|
||||
"name": "henrikbjorn/lurker",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/henrikbjorn/Lurker.git",
|
||||
"url": "https://github.com/flint/Lurker.git",
|
||||
"reference": "a020d45b3bc37810aeafe27343c51af8a74c9419"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/henrikbjorn/Lurker/zipball/a020d45b3bc37810aeafe27343c51af8a74c9419",
|
||||
"url": "https://api.github.com/repos/flint/Lurker/zipball/a020d45b3bc37810aeafe27343c51af8a74c9419",
|
||||
"reference": "a020d45b3bc37810aeafe27343c51af8a74c9419",
|
||||
"shasum": ""
|
||||
},
|
||||
@ -901,18 +991,16 @@
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Henrik Bjornskov",
|
||||
"email": "henrik@bjrnskov.dk",
|
||||
"homepage": "http://henrik.bjrnskov.dk"
|
||||
"name": "Yaroslav Kiliba",
|
||||
"email": "om.dattaya@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Konstantin Kudryashov",
|
||||
"email": "ever.zet@gmail.com",
|
||||
"homepage": "http://everzet.com"
|
||||
"email": "ever.zet@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Yaroslav Kiliba",
|
||||
"email": "om.dattaya@gmail.com"
|
||||
"name": "Henrik Bjrnskov",
|
||||
"email": "henrik@bjrnskov.dk"
|
||||
}
|
||||
],
|
||||
"description": "Resource Watcher.",
|
||||
@ -1873,16 +1961,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "277a2457776d4cc25706fbdd9d1e4ab2dac884e4"
|
||||
"reference": "07d664a052572ccc28eb2ab7dbbe82155b1ad367"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/277a2457776d4cc25706fbdd9d1e4ab2dac884e4",
|
||||
"reference": "277a2457776d4cc25706fbdd9d1e4ab2dac884e4",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/07d664a052572ccc28eb2ab7dbbe82155b1ad367",
|
||||
"reference": "07d664a052572ccc28eb2ab7dbbe82155b1ad367",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1891,8 +1979,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/css-selector": "~2.0,>=2.0.5",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/process": "~2.0,>=2.0.5"
|
||||
"symfony/process": "~2.3.34|~2.7,>=2.7.6"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/process": ""
|
||||
@ -1924,29 +2011,26 @@
|
||||
],
|
||||
"description": "Symfony BrowserKit Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-06 08:36:38"
|
||||
"time": "2015-10-23 14:47:27"
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "9698fdf0a750d6887d5e7729d5cf099765b20e61"
|
||||
"reference": "831f88908b51b9ce945f5e6f402931d1ac544423"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/9698fdf0a750d6887d5e7729d5cf099765b20e61",
|
||||
"reference": "9698fdf0a750d6887d5e7729d5cf099765b20e61",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/831f88908b51b9ce945f5e6f402931d1ac544423",
|
||||
"reference": "831f88908b51b9ce945f5e6f402931d1ac544423",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"symfony/filesystem": "~2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -1974,20 +2058,20 @@
|
||||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-21 15:02:29"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "06cb17c013a82f94a3d840682b49425cd00a2161"
|
||||
"reference": "5efd632294c8320ea52492db22292ff853a43766"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/06cb17c013a82f94a3d840682b49425cd00a2161",
|
||||
"reference": "06cb17c013a82f94a3d840682b49425cd00a2161",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/5efd632294c8320ea52492db22292ff853a43766",
|
||||
"reference": "5efd632294c8320ea52492db22292ff853a43766",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1996,7 +2080,6 @@
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/event-dispatcher": "~2.1",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/process": "~2.1"
|
||||
},
|
||||
"suggest": {
|
||||
@ -2031,28 +2114,25 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-25 08:32:23"
|
||||
"time": "2015-10-20 14:38:46"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "abe19cc0429a06be0c133056d1f9859854860970"
|
||||
"reference": "e1b865b26be4a56d22a8dee398375044a80c865b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/abe19cc0429a06be0c133056d1f9859854860970",
|
||||
"reference": "abe19cc0429a06be0c133056d1f9859854860970",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/e1b865b26be4a56d22a8dee398375044a80c865b",
|
||||
"reference": "e1b865b26be4a56d22a8dee398375044a80c865b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2084,28 +2164,27 @@
|
||||
],
|
||||
"description": "Symfony CssSelector Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-22 13:49:29"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "2e185ca136399f902b948694987e62c80099c052"
|
||||
"reference": "5fef7d8b80d8f9992df99d8ee283f420484c9612"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2e185ca136399f902b948694987e62c80099c052",
|
||||
"reference": "2e185ca136399f902b948694987e62c80099c052",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5fef7d8b80d8f9992df99d8ee283f420484c9612",
|
||||
"reference": "5fef7d8b80d8f9992df99d8ee283f420484c9612",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/css-selector": "~2.3",
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
"symfony/css-selector": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/css-selector": ""
|
||||
@ -2137,20 +2216,20 @@
|
||||
],
|
||||
"description": "Symfony DomCrawler Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-20 21:13:58"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9"
|
||||
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae4dcc2a8d3de98bd794167a3ccda1311597c5d9",
|
||||
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87a5db5ea887763fa3a31a5471b512ff1596d9b8",
|
||||
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2161,7 +2240,6 @@
|
||||
"symfony/config": "~2.0,>=2.0.5",
|
||||
"symfony/dependency-injection": "~2.6",
|
||||
"symfony/expression-language": "~2.6",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/stopwatch": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
@ -2195,28 +2273,25 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-22 13:49:29"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "a17f8a17c20e8614c15b8e116e2f4bcde102cfab"
|
||||
"reference": "56fd6df73be859323ff97418d97edc1d756df6df"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/a17f8a17c20e8614c15b8e116e2f4bcde102cfab",
|
||||
"reference": "a17f8a17c20e8614c15b8e116e2f4bcde102cfab",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/56fd6df73be859323ff97418d97edc1d756df6df",
|
||||
"reference": "56fd6df73be859323ff97418d97edc1d756df6df",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2244,28 +2319,25 @@
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-09 17:42:36"
|
||||
"time": "2015-10-18 20:23:18"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "8262ab605973afbb3ef74b945daabf086f58366f"
|
||||
"reference": "2ffb4e9598db3c48eb6d0ae73b04bbf09280c59d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/8262ab605973afbb3ef74b945daabf086f58366f",
|
||||
"reference": "8262ab605973afbb3ef74b945daabf086f58366f",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/2ffb4e9598db3c48eb6d0ae73b04bbf09280c59d",
|
||||
"reference": "2ffb4e9598db3c48eb6d0ae73b04bbf09280c59d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2293,20 +2365,20 @@
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-19 19:59:23"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/form",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/form.git",
|
||||
"reference": "d4a990d2ebe4dd39cac52c5a40a5aac84b12b237"
|
||||
"reference": "b93fcb816bec2b8470ea9d54e4b6658b2461b83c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/form/zipball/d4a990d2ebe4dd39cac52c5a40a5aac84b12b237",
|
||||
"reference": "d4a990d2ebe4dd39cac52c5a40a5aac84b12b237",
|
||||
"url": "https://api.github.com/repos/symfony/form/zipball/b93fcb816bec2b8470ea9d54e4b6658b2461b83c",
|
||||
"reference": "b93fcb816bec2b8470ea9d54e4b6658b2461b83c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2325,7 +2397,6 @@
|
||||
"doctrine/collections": "~1.0",
|
||||
"symfony/http-foundation": "~2.2",
|
||||
"symfony/http-kernel": "~2.4",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/security-csrf": "~2.4",
|
||||
"symfony/translation": "~2.0,>=2.0.5",
|
||||
"symfony/validator": "~2.6,>=2.6.8"
|
||||
@ -2363,28 +2434,27 @@
|
||||
],
|
||||
"description": "Symfony Form Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-22 13:49:29"
|
||||
"time": "2015-10-27 15:38:06"
|
||||
},
|
||||
{
|
||||
"name": "symfony/intl",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/intl.git",
|
||||
"reference": "35f902b232c10056e17d94a842160d44bb540838"
|
||||
"reference": "330f52a996749eb6a2fdc1506c7a4868e070d678"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/intl/zipball/35f902b232c10056e17d94a842160d44bb540838",
|
||||
"reference": "35f902b232c10056e17d94a842160d44bb540838",
|
||||
"url": "https://api.github.com/repos/symfony/intl/zipball/330f52a996749eb6a2fdc1506c7a4868e070d678",
|
||||
"reference": "330f52a996749eb6a2fdc1506c7a4868e070d678",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/filesystem": "~2.1",
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
"symfony/filesystem": "~2.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "to use the component with locales other than \"en\""
|
||||
@ -2438,28 +2508,25 @@
|
||||
"l10n",
|
||||
"localization"
|
||||
],
|
||||
"time": "2015-09-09 17:53:06"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/options-resolver.git",
|
||||
"reference": "75389f6f948edfdf0c0ebdbe00c4f84ab5d1a03e"
|
||||
"reference": "85fd10e551677d3c9a4632def78b8ec4670b247d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/75389f6f948edfdf0c0ebdbe00c4f84ab5d1a03e",
|
||||
"reference": "75389f6f948edfdf0c0ebdbe00c4f84ab5d1a03e",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/85fd10e551677d3c9a4632def78b8ec4670b247d",
|
||||
"reference": "85fd10e551677d3c9a4632def78b8ec4670b247d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2492,28 +2559,25 @@
|
||||
"configuration",
|
||||
"options"
|
||||
],
|
||||
"time": "2015-09-25 06:59:16"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "b27c8e317922cd3cdd3600850273cf6b82b2e8e9"
|
||||
"reference": "4a959dd4e19c2c5d7512689413921e0a74386ec7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/b27c8e317922cd3cdd3600850273cf6b82b2e8e9",
|
||||
"reference": "b27c8e317922cd3cdd3600850273cf6b82b2e8e9",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/4a959dd4e19c2c5d7512689413921e0a74386ec7",
|
||||
"reference": "4a959dd4e19c2c5d7512689413921e0a74386ec7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2541,28 +2605,25 @@
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-19 19:59:23"
|
||||
"time": "2015-10-23 14:47:27"
|
||||
},
|
||||
{
|
||||
"name": "symfony/property-access",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/property-access.git",
|
||||
"reference": "f8ea7aa472f0e3f8cdf43287caa72a70ff5c088c"
|
||||
"reference": "368b784738fa932e6d86866038312b03e073a824"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/property-access/zipball/f8ea7aa472f0e3f8cdf43287caa72a70ff5c088c",
|
||||
"reference": "f8ea7aa472f0e3f8cdf43287caa72a70ff5c088c",
|
||||
"url": "https://api.github.com/repos/symfony/property-access/zipball/368b784738fa932e6d86866038312b03e073a824",
|
||||
"reference": "368b784738fa932e6d86866038312b03e073a824",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2601,20 +2662,20 @@
|
||||
"property path",
|
||||
"reflection"
|
||||
],
|
||||
"time": "2015-08-24 07:13:45"
|
||||
"time": "2015-10-23 14:47:27"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/routing.git",
|
||||
"reference": "6c5fae83efa20baf166fcf4582f57094e9f60f16"
|
||||
"reference": "f353e1f588679c3ec987624e6c617646bd01ba38"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/6c5fae83efa20baf166fcf4582f57094e9f60f16",
|
||||
"reference": "6c5fae83efa20baf166fcf4582f57094e9f60f16",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/f353e1f588679c3ec987624e6c617646bd01ba38",
|
||||
"reference": "f353e1f588679c3ec987624e6c617646bd01ba38",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2630,7 +2691,6 @@
|
||||
"symfony/config": "~2.7",
|
||||
"symfony/expression-language": "~2.4",
|
||||
"symfony/http-foundation": "~2.3",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/yaml": "~2.0,>=2.0.5"
|
||||
},
|
||||
"suggest": {
|
||||
@ -2672,20 +2732,20 @@
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2015-09-14 14:14:09"
|
||||
"time": "2015-10-27 15:38:06"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "485877661835e188cd78345c6d4eef1290d17571"
|
||||
"reference": "6ccd9289ec1c71d01a49d83480de3b5293ce30c8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/485877661835e188cd78345c6d4eef1290d17571",
|
||||
"reference": "485877661835e188cd78345c6d4eef1290d17571",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/6ccd9289ec1c71d01a49d83480de3b5293ce30c8",
|
||||
"reference": "6ccd9289ec1c71d01a49d83480de3b5293ce30c8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2698,7 +2758,6 @@
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.7",
|
||||
"symfony/intl": "~2.4",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/yaml": "~2.2"
|
||||
},
|
||||
"suggest": {
|
||||
@ -2733,20 +2792,20 @@
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-06 08:36:38"
|
||||
"time": "2015-10-27 15:38:06"
|
||||
},
|
||||
{
|
||||
"name": "symfony/twig-bridge",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/twig-bridge.git",
|
||||
"reference": "bce37975610a46bde48dbf2f67f724401251d199"
|
||||
"reference": "3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/bce37975610a46bde48dbf2f67f724401251d199",
|
||||
"reference": "bce37975610a46bde48dbf2f67f724401251d199",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f",
|
||||
"reference": "3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2758,10 +2817,9 @@
|
||||
"symfony/console": "~2.7",
|
||||
"symfony/expression-language": "~2.4",
|
||||
"symfony/finder": "~2.3",
|
||||
"symfony/form": "~2.7,>=2.7.2",
|
||||
"symfony/form": "~2.7,>=2.7.6",
|
||||
"symfony/http-kernel": "~2.3",
|
||||
"symfony/intl": "~2.3",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/routing": "~2.2",
|
||||
"symfony/security": "~2.6",
|
||||
"symfony/security-acl": "~2.6",
|
||||
@ -2812,28 +2870,25 @@
|
||||
],
|
||||
"description": "Symfony Twig Bridge",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-23 09:17:11"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.7.5",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770"
|
||||
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/31cb2ad0155c95b88ee55fe12bc7ff92232c1770",
|
||||
"reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/eca9019c88fbe250164affd107bc8057771f3f4d",
|
||||
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -2861,7 +2916,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-14 14:14:09"
|
||||
"time": "2015-10-11 09:39:48"
|
||||
},
|
||||
{
|
||||
"name": "twig/extensions",
|
||||
@ -2966,25 +3021,30 @@
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v2.0.1",
|
||||
"version": "v2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||
"reference": "91064290f5b53a09bdff1b939d7f69fb0e7531b5"
|
||||
"reference": "c10040e0df17d2ee88e9212b50cbe9319e878f59"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/91064290f5b53a09bdff1b939d7f69fb0e7531b5",
|
||||
"reference": "91064290f5b53a09bdff1b939d7f69fb0e7531b5",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/c10040e0df17d2ee88e9212b50cbe9319e878f59",
|
||||
"reference": "c10040e0df17d2ee88e9212b50cbe9319e878f59",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dotenv\\": "src/"
|
||||
@ -3008,7 +3068,7 @@
|
||||
"env",
|
||||
"environment"
|
||||
],
|
||||
"time": "2015-05-30 16:15:01"
|
||||
"time": "2015-10-28 18:53:35"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -39,6 +39,7 @@ class Initializer {
|
||||
$newsletters = Env::$db_prefix . 'newsletters';
|
||||
$newsletter_templates = Env::$db_prefix . 'newsletter_templates';
|
||||
$segments = Env::$db_prefix . 'segments';
|
||||
$forms = Env::$db_prefix . 'forms';
|
||||
$subscriber_segment = Env::$db_prefix . 'subscriber_segment';
|
||||
$newsletter_segment = Env::$db_prefix . 'newsletter_segment';
|
||||
$custom_fields = Env::$db_prefix . 'custom_fields';
|
||||
@ -50,6 +51,7 @@ class Initializer {
|
||||
define('MP_SETTINGS_TABLE', $settings);
|
||||
define('MP_NEWSLETTERS_TABLE', $newsletters);
|
||||
define('MP_SEGMENTS_TABLE', $segments);
|
||||
define('MP_FORMS_TABLE', $forms);
|
||||
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
|
||||
define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates);
|
||||
define('MP_NEWSLETTER_SEGMENT_TABLE', $newsletter_segment);
|
||||
|
@ -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;
|
||||
@ -41,6 +44,14 @@ class Menu {
|
||||
'mailpoet-newsletters',
|
||||
array($this, 'newsletters')
|
||||
);
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
__('Forms'),
|
||||
__('Forms'),
|
||||
'manage_options',
|
||||
'mailpoet-forms',
|
||||
array($this, 'forms')
|
||||
);
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
__('Subscribers'),
|
||||
@ -79,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);
|
||||
@ -163,6 +174,13 @@ class Menu {
|
||||
echo $this->renderer->render('segments.html', $data);
|
||||
}
|
||||
|
||||
function forms() {
|
||||
$data = array();
|
||||
$data['segments'] = Segment::findArray();
|
||||
|
||||
echo $this->renderer->render('forms.html', $data);
|
||||
}
|
||||
|
||||
function newsletters() {
|
||||
global $wp_roles;
|
||||
|
||||
@ -178,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);
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class Migrator {
|
||||
'subscriber_custom_field',
|
||||
'newsletter_option_fields',
|
||||
'newsletter_option',
|
||||
'forms'
|
||||
);
|
||||
}
|
||||
|
||||
@ -66,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),',
|
||||
@ -107,6 +108,7 @@ class Migrator {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'name varchar(90) NOT NULL,',
|
||||
'description varchar(250) NOT NULL,',
|
||||
'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,',
|
||||
@ -123,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);
|
||||
}
|
||||
@ -135,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);
|
||||
}
|
||||
@ -145,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),',
|
||||
@ -192,6 +197,21 @@ class Migrator {
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
function forms() {
|
||||
$attributes = array(
|
||||
'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,',
|
||||
'PRIMARY KEY (id)'
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
private function sqlify($model, $attributes) {
|
||||
$table = $this->prefix . $model;
|
||||
|
||||
|
@ -60,6 +60,27 @@ class Populator {
|
||||
'name' => 'afterTimeType',
|
||||
'newsletter_type' => 'welcome',
|
||||
),
|
||||
|
||||
array(
|
||||
'name' => 'intervalType',
|
||||
'newsletter_type' => 'notification',
|
||||
),
|
||||
array(
|
||||
'name' => 'timeOfDay',
|
||||
'newsletter_type' => 'notification',
|
||||
),
|
||||
array(
|
||||
'name' => 'weekDay',
|
||||
'newsletter_type' => 'notification',
|
||||
),
|
||||
array(
|
||||
'name' => 'monthDay',
|
||||
'newsletter_type' => 'notification',
|
||||
),
|
||||
array(
|
||||
'name' => 'nthWeekDay',
|
||||
'newsletter_type' => 'notification',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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
103
lib/Form/Block/Base.php
Normal 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']) : '';
|
||||
}
|
||||
}
|
43
lib/Form/Block/Checkbox.php
Normal file
43
lib/Form/Block/Checkbox.php
Normal 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
155
lib/Form/Block/Date.php
Normal 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;
|
||||
}
|
||||
}
|
9
lib/Form/Block/Divider.php
Normal file
9
lib/Form/Block/Divider.php
Normal 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
23
lib/Form/Block/Html.php
Normal 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
36
lib/Form/Block/Input.php
Normal 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
42
lib/Form/Block/Radio.php
Normal 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 .= ' /> '.$option['value'];
|
||||
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
37
lib/Form/Block/Segment.php
Normal file
37
lib/Form/Block/Segment.php
Normal 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
36
lib/Form/Block/Select.php
Normal 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
17
lib/Form/Block/Submit.php
Normal 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;
|
||||
}
|
||||
}
|
28
lib/Form/Block/Textarea.php
Normal file
28
lib/Form/Block/Textarea.php
Normal 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
95
lib/Form/Renderer.php
Normal 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
91
lib/Form/Util/Export.php
Normal 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
181
lib/Form/Util/Styles.php
Normal 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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -5,15 +5,17 @@ if(!defined('ABSPATH')) exit;
|
||||
|
||||
class BulkAction {
|
||||
private $listing = null;
|
||||
private $action = null;
|
||||
private $data = null;
|
||||
private $model_class = null;
|
||||
|
||||
function __construct($model_class, $data) {
|
||||
$this->model_class = $model_class;
|
||||
$this->action = $data['action'];
|
||||
unset($data['action']);
|
||||
$this->data = $data;
|
||||
|
||||
$this->model_class = $model_class;
|
||||
$this->listing = new Handler(
|
||||
$this->model_class,
|
||||
$model_class,
|
||||
$this->data['listing']
|
||||
);
|
||||
return $this;
|
||||
@ -21,8 +23,9 @@ class BulkAction {
|
||||
|
||||
function apply() {
|
||||
return call_user_func_array(
|
||||
array($this->model_class, $this->data['action']),
|
||||
array($this->listing, $this->data)
|
||||
array($this->model_class, 'bulk'.ucfirst($this->action)),
|
||||
array($this->listing->getSelection(), $this->data)
|
||||
);
|
||||
return $models->count();
|
||||
}
|
||||
}
|
@ -4,16 +4,13 @@ namespace MailPoet\Listing;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Handler {
|
||||
|
||||
private $data = array();
|
||||
private $model = null;
|
||||
|
||||
function __construct($model_class, $data = array()) {
|
||||
$class = new \ReflectionClass($model_class);
|
||||
$this->table_name = $class->getStaticPropertyValue('_table');
|
||||
|
||||
$this->model = \Model::factory($model_class);
|
||||
|
||||
$this->model = $model_class::select('*');
|
||||
$this->data = array(
|
||||
// pagination
|
||||
'offset' => (isset($data['offset']) ? (int)$data['offset'] : 0),
|
||||
@ -31,7 +28,7 @@ class Handler {
|
||||
'selection' => (isset($data['selection']) ? $data['selection'] : null)
|
||||
);
|
||||
|
||||
$this->model = $this->setFilter();
|
||||
$this->setFilter();
|
||||
$this->setSearch();
|
||||
$this->setGroup();
|
||||
$this->setOrder();
|
||||
@ -59,22 +56,18 @@ class Handler {
|
||||
|
||||
private function setFilter() {
|
||||
if($this->data['filter'] === null) {
|
||||
return $this->model;
|
||||
return;
|
||||
}
|
||||
return $this->model->filter('filterBy', $this->data['filter']);
|
||||
$this->model = $this->model->filter('filterBy', $this->data['filter']);
|
||||
}
|
||||
|
||||
function getSelection() {
|
||||
if(!empty($this->data['selection'])) {
|
||||
$this->model->whereIn('id', $this->data['selection']);
|
||||
$this->model->whereIn($this->table_name.'.id', $this->data['selection']);
|
||||
}
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
function count() {
|
||||
return (int)$this->model->count();
|
||||
}
|
||||
|
||||
function getSelectionIds() {
|
||||
$models = $this->getSelection()
|
||||
->select('id')
|
||||
@ -86,14 +79,18 @@ class Handler {
|
||||
}
|
||||
|
||||
function get() {
|
||||
$count = $this->model->count();
|
||||
|
||||
$items = $this->model
|
||||
->offset($this->data['offset'])
|
||||
->limit($this->data['limit'])
|
||||
->findArray();
|
||||
|
||||
return array(
|
||||
'count' => $this->model->count(),
|
||||
'count' => $count,
|
||||
'filters' => $this->model->filter('filters'),
|
||||
'groups' => $this->model->filter('groups'),
|
||||
'items' => $this->model
|
||||
->offset($this->data['offset'])
|
||||
->limit($this->data['limit'])
|
||||
->findArray()
|
||||
'items' => $items
|
||||
);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
93
lib/Models/Form.php
Normal file
93
lib/Models/Form.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace MailPoet\Models;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Form extends Model {
|
||||
static $_table = MP_FORMS_TABLE;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->addValidations('name', array(
|
||||
'required' => __('You need to specify a name.')
|
||||
));
|
||||
}
|
||||
|
||||
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.'%');
|
||||
}
|
||||
|
||||
static function groups() {
|
||||
return array(
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Form::whereNull('deleted_at')->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Form::whereNotNull('deleted_at')->count()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
static function groupBy($orm, $group = null) {
|
||||
if($group === 'trash') {
|
||||
return $orm->whereNotNull('deleted_at');
|
||||
} else {
|
||||
$orm = $orm->whereNull('deleted_at');
|
||||
}
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
$form = false;
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$form = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
if($form === false) {
|
||||
$form = self::create();
|
||||
$form->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$form->set($data);
|
||||
}
|
||||
|
||||
$form->save();
|
||||
return $form;
|
||||
}
|
||||
}
|
@ -9,6 +9,10 @@ class Model extends \Sudzy\ValidModel {
|
||||
parent::__construct($customValidators->init());
|
||||
}
|
||||
|
||||
static function create() {
|
||||
return parent::create();
|
||||
}
|
||||
|
||||
function save() {
|
||||
$this->setTimestamp();
|
||||
try {
|
||||
@ -21,9 +25,57 @@ class Model extends \Sudzy\ValidModel {
|
||||
}
|
||||
}
|
||||
|
||||
function trash() {
|
||||
return $this->set_expr('deleted_at', 'NOW()')->save();
|
||||
}
|
||||
|
||||
static function bulkTrash($orm) {
|
||||
$models = $orm->findResultSet();
|
||||
$models->set_expr('deleted_at', 'NOW()')->save();
|
||||
return $models->count();
|
||||
}
|
||||
|
||||
static function bulkDelete($orm) {
|
||||
$models = $orm->findMany();
|
||||
$count = 0;
|
||||
foreach($models as $model) {
|
||||
$model->delete();
|
||||
$count++;
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
function restore() {
|
||||
return $this->set_expr('deleted_at', 'NULl')->save();
|
||||
}
|
||||
|
||||
static function bulkRestore($orm) {
|
||||
$models = $orm->findResultSet();
|
||||
$models->set_expr('deleted_at', 'NULL')->save();
|
||||
return $models->count();
|
||||
}
|
||||
|
||||
function duplicate($data = array()) {
|
||||
$model = get_called_class();
|
||||
$model_data = array_merge($this->asArray(), $data);
|
||||
unset($model_data['id']);
|
||||
|
||||
$duplicate = $model::create();
|
||||
$duplicate->hydrate($model_data);
|
||||
$duplicate->set_expr('created_at', 'NOW()');
|
||||
$duplicate->set_expr('updated_at', 'NOW()');
|
||||
$duplicate->set_expr('deleted_at', 'NULL');
|
||||
|
||||
if($duplicate->save()) {
|
||||
return $duplicate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function setTimestamp() {
|
||||
if($this->created_at === null) {
|
||||
$this->created_at = date('Y-m-d H:i:s');
|
||||
$this->set_expr('created_at', 'NOW()');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
@ -39,10 +46,10 @@ class Newsletter extends Model {
|
||||
'label' => __('All lists'),
|
||||
'value' => ''
|
||||
);
|
||||
|
||||
foreach($segments as $segment) {
|
||||
$newsletters_count = $segment->newsletters()->count();
|
||||
if($newsletters_count > 0) {
|
||||
|
||||
$segment_list[] = array(
|
||||
'label' => sprintf('%s (%d)', $segment->name, $newsletters_count),
|
||||
'value' => $segment->id()
|
||||
@ -51,34 +58,21 @@ class Newsletter extends Model {
|
||||
}
|
||||
|
||||
$filters = array(
|
||||
array(
|
||||
'name' => 'segment',
|
||||
'options' => $segment_list
|
||||
)
|
||||
'segment' => $segment_list
|
||||
);
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
static function filterBy($orm, $filters = null) {
|
||||
if(empty($filters)) {
|
||||
if(empty($filters)) {
|
||||
return $orm;
|
||||
}
|
||||
|
||||
foreach($filters as $filter) {
|
||||
if($filter['name'] === 'segment') {
|
||||
|
||||
$segment = Segment::findOne($filter['value']);
|
||||
foreach($filters as $key => $value) {
|
||||
if($key === 'segment') {
|
||||
$segment = Segment::findOne($value);
|
||||
if($segment !== false) {
|
||||
$orm = $orm
|
||||
->select(MP_NEWSLETTERS_TABLE.'.*')
|
||||
->select('newsletter_segment.id', 'newsletter_segment_id')
|
||||
->join(
|
||||
MP_NEWSLETTER_SEGMENT_TABLE,
|
||||
MP_NEWSLETTERS_TABLE.'.id = newsletter_segment.newsletter_id',
|
||||
'newsletter_segment'
|
||||
)
|
||||
->where('newsletter_segment.segment_id', (int)$filter['value']);
|
||||
$orm = $segment->newsletters();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,12 +106,21 @@ class Newsletter extends Model {
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Newsletter::count()
|
||||
'count' => Newsletter::whereNull('deleted_at')->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Newsletter::whereNotNull('deleted_at')->count()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
static function group($orm, $group = null) {
|
||||
static function groupBy($orm, $group = null) {
|
||||
if($group === 'trash') {
|
||||
return $orm->whereNotNull('deleted_at');
|
||||
}
|
||||
return $orm->whereNull('deleted_at');
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
@ -135,21 +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;
|
||||
}
|
||||
|
||||
static function trash($listing) {
|
||||
return $listing->getSelection()
|
||||
->deleteMany();
|
||||
$newsletter->save();
|
||||
return $newsletter;
|
||||
}
|
||||
}
|
||||
|
@ -14,13 +14,10 @@ class Segment extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
function subscribers() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Subscriber',
|
||||
__NAMESPACE__.'\SubscriberSegment',
|
||||
'segment_id',
|
||||
'subscriber_id'
|
||||
);
|
||||
function delete() {
|
||||
// delete all relations to subscribers
|
||||
SubscriberSegment::where('segment_id', $this->id)->deleteMany();
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
function newsletters() {
|
||||
@ -32,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.'%');
|
||||
}
|
||||
@ -41,12 +76,22 @@ class Segment extends Model {
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Segment::count()
|
||||
'count' => Segment::whereNull('deleted_at')->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Segment::whereNotNull('deleted_at')->count()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
static function group($orm, $group = null) {
|
||||
static function groupBy($orm, $group = null) {
|
||||
if($group === 'trash') {
|
||||
return $orm->whereNotNull('deleted_at');
|
||||
} else {
|
||||
$orm = $orm->whereNull('deleted_at');
|
||||
}
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
@ -64,20 +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;
|
||||
}
|
||||
|
||||
static function trash($listing) {
|
||||
return $listing->getSelection()->deleteMany();
|
||||
$segment->save();
|
||||
return $segment;
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,20 @@ 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();
|
||||
|
||||
parent::delete();
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
static function search($orm, $search = '') {
|
||||
@ -36,14 +45,15 @@ class Subscriber extends Model {
|
||||
static function filters() {
|
||||
$segments = Segment::orderByAsc('name')->findMany();
|
||||
$segment_list = array();
|
||||
|
||||
$segment_list[] = array(
|
||||
'label' => __('All lists'),
|
||||
'value' => ''
|
||||
);
|
||||
|
||||
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),
|
||||
@ -53,10 +63,7 @@ class Subscriber extends Model {
|
||||
}
|
||||
|
||||
$filters = array(
|
||||
array(
|
||||
'name' => 'segment',
|
||||
'options' => $segment_list
|
||||
)
|
||||
'segment' => $segment_list
|
||||
);
|
||||
|
||||
return $filters;
|
||||
@ -66,12 +73,11 @@ class Subscriber extends Model {
|
||||
if(empty($filters)) {
|
||||
return $orm;
|
||||
}
|
||||
|
||||
foreach($filters as $filter) {
|
||||
if($filter['name'] === 'segment') {
|
||||
$segment = Segment::findOne($filter['value']);
|
||||
foreach($filters as $key => $value) {
|
||||
if($key === 'segment') {
|
||||
$segment = Segment::findOne($value);
|
||||
if($segment !== false) {
|
||||
$orm = $segment->subscribers();
|
||||
return $segment->subscribers();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,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',
|
||||
@ -117,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,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',
|
||||
@ -171,36 +160,25 @@ 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 moveToList($listing, $data = array()) {
|
||||
static function bulkMoveToList($orm, $data = array()) {
|
||||
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
|
||||
$segment = Segment::findOne($segment_id);
|
||||
|
||||
if($segment !== false) {
|
||||
$subscribers_count = 0;
|
||||
$subscribers = $listing->getSelection()->findMany();
|
||||
$subscribers = $orm->findResultSet();
|
||||
foreach($subscribers as $subscriber) {
|
||||
// remove subscriber from all segments
|
||||
SubscriberSegment::where('subscriber_id', $subscriber->id)->deleteMany();
|
||||
@ -210,37 +188,37 @@ class Subscriber extends Model {
|
||||
$association->subscriber_id = $subscriber->id;
|
||||
$association->segment_id = $segment->id;
|
||||
$association->save();
|
||||
|
||||
$subscribers_count++;
|
||||
}
|
||||
return array(
|
||||
'subscribers' => $subscribers_count,
|
||||
'subscribers' => $subscribers->count(),
|
||||
'segment' => $segment->name
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function removeFromList($listing, $data = array()) {
|
||||
static function bulkRemoveFromList($orm, $data = array()) {
|
||||
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
|
||||
$segment = Segment::findOne($segment_id);
|
||||
|
||||
if($segment !== false) {
|
||||
// delete relations with segment
|
||||
$subscriber_ids = $listing->getSelectionIds();
|
||||
SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)
|
||||
->where('segment_id', $segment->id)
|
||||
->deleteMany();
|
||||
$subscribers = $orm->findResultSet();
|
||||
foreach($subscribers as $subscriber) {
|
||||
SubscriberSegment::where('subscriber_id', $subscriber->id)
|
||||
->where('segment_id', $segment->id)
|
||||
->deleteMany();
|
||||
}
|
||||
|
||||
return array(
|
||||
'subscribers' => count($subscriber_ids),
|
||||
'subscribers' => $subscribers->count(),
|
||||
'segment' => $segment->name
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function removeFromAllLists($listing) {
|
||||
static function bulkRemoveFromAllLists($orm) {
|
||||
$segments = Segment::findMany();
|
||||
$segment_ids = array_map(function($segment) {
|
||||
return $segment->id();
|
||||
@ -248,62 +226,48 @@ class Subscriber extends Model {
|
||||
|
||||
if(!empty($segment_ids)) {
|
||||
// delete relations with segment
|
||||
$subscriber_ids = $listing->getSelectionIds();
|
||||
SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)
|
||||
->whereIn('segment_id', $segment_ids)
|
||||
->deleteMany();
|
||||
|
||||
return array(
|
||||
'subscribers' => count($subscriber_ids)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function confirmUnconfirmed($listing) {
|
||||
$subscriber_ids = $listing->getSelectionIds();
|
||||
$subscribers = Subscriber::whereIn('id', $subscriber_ids)
|
||||
->where('status', 'unconfirmed')
|
||||
->findMany();
|
||||
|
||||
if(!empty($subscribers)) {
|
||||
$subscribers_count = 0;
|
||||
$subscribers = $orm->findResultSet();
|
||||
foreach($subscribers as $subscriber) {
|
||||
$subscriber->set('status', 'subscribed');
|
||||
if($subscriber->save() === true) {
|
||||
$subscribers_count++;
|
||||
}
|
||||
SubscriberSegment::where('subscriber_id', $subscriber->id)
|
||||
->whereIn('segment_id', $segment_ids)
|
||||
->deleteMany();
|
||||
}
|
||||
|
||||
return array(
|
||||
'subscribers' => $subscribers_count
|
||||
);
|
||||
return $subscribers->count();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function resendConfirmationEmail($listing) {
|
||||
$subscriber_ids = $listing->getSelectionIds();
|
||||
$subscribers = Subscriber::whereIn('id', $subscriber_ids)
|
||||
static function bulkConfirmUnconfirmed($orm) {
|
||||
$subscribers = $orm->findResultSet();
|
||||
$subscribers->set('status', 'subscribed')->save();
|
||||
return $subscribers->count();
|
||||
}
|
||||
|
||||
static function bulkResendConfirmationEmail($orm) {
|
||||
$subscribers = $orm
|
||||
->where('status', 'unconfirmed')
|
||||
->findMany();
|
||||
->findResultSet();
|
||||
|
||||
if(!empty($subscribers)) {
|
||||
foreach($subscribers as $subscriber) {
|
||||
// TODO: resend confirmation email
|
||||
// TODO: send confirmation email
|
||||
// $subscriber->sendConfirmationEmail()
|
||||
}
|
||||
return true;
|
||||
|
||||
return $subscribers->count();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function addToList($listing, $data = array()) {
|
||||
static function bulkAddToList($orm, $data = array()) {
|
||||
|
||||
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
|
||||
$segment = Segment::findOne($segment_id);
|
||||
|
||||
if($segment !== false) {
|
||||
$subscribers_count = 0;
|
||||
$subscribers = $listing->getSelection()->findMany();
|
||||
$subscribers = $orm->findMany();
|
||||
foreach($subscribers as $subscriber) {
|
||||
// create relation with segment
|
||||
$association = \MailPoet\Models\SubscriberSegment::create();
|
||||
@ -321,45 +285,21 @@ class Subscriber extends Model {
|
||||
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
|
||||
$subscribers = $listing->getSelection()->findResultSet();
|
||||
|
||||
if(!empty($subscribers)) {
|
||||
$subscribers_count = 0;
|
||||
foreach($subscribers as $subscriber) {
|
||||
if($subscriber->delete()) {
|
||||
$subscribers_count++;
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'subscribers' => $subscribers_count
|
||||
);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// soft delete
|
||||
$subscribers = $listing->getSelection()
|
||||
->findResultSet()
|
||||
->set_expr('deleted_at', 'NOW()')
|
||||
->save();
|
||||
|
||||
return array(
|
||||
'subscribers' => $subscribers->count()
|
||||
);
|
||||
}
|
||||
static function subscribed($orm) {
|
||||
return $orm
|
||||
->whereNull('deleted_at')
|
||||
->where('status', 'subscribed');
|
||||
}
|
||||
|
||||
static function restore($listing, $data = array()) {
|
||||
$subscribers = $listing->getSelection()
|
||||
->findResultSet()
|
||||
->set_expr('deleted_at', 'NULL')
|
||||
->save();
|
||||
static function unsubscribed($orm) {
|
||||
return $orm
|
||||
->whereNull('deleted_at')
|
||||
->where('status', 'unsubscribed');
|
||||
}
|
||||
|
||||
return array(
|
||||
'subscribers' => $subscribers->count()
|
||||
);
|
||||
static function unconfirmed($orm) {
|
||||
return $orm
|
||||
->whereNull('deleted_at')
|
||||
->where('status', 'unconfirmed');
|
||||
}
|
||||
}
|
69
lib/Router/CustomFields.php
Normal file
69
lib/Router/CustomFields.php
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
258
lib/Router/Forms.php
Normal file
258
lib/Router/Forms.php
Normal file
@ -0,0 +1,258 @@
|
||||
<?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;
|
||||
|
||||
class Forms {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function get($data = array()) {
|
||||
$id = (isset($data['id']) ? (int)$data['id'] : 0);
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form === false) {
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
$form = $form->asArray();
|
||||
wp_send_json($form);
|
||||
}
|
||||
}
|
||||
|
||||
function listing($data = array()) {
|
||||
$listing = new Listing\Handler(
|
||||
'\MailPoet\Models\Form',
|
||||
$data
|
||||
);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
function getAll() {
|
||||
$collection = Form::findArray();
|
||||
wp_send_json($collection);
|
||||
}
|
||||
|
||||
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'
|
||||
)
|
||||
);
|
||||
|
||||
$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(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) {
|
||||
$result = $form->restore();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function trash($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form !== 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::findOne($id);
|
||||
if($form !== false) {
|
||||
$data = array(
|
||||
'name' => sprintf(__('Copy of %s'), $form->name)
|
||||
);
|
||||
$result = $form->duplicate($data)->asArray();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function bulkAction($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Form',
|
||||
$data
|
||||
);
|
||||
|
||||
wp_send_json($bulk_action->apply());
|
||||
}
|
||||
}
|
@ -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,13 +90,31 @@ class Newsletters {
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json(($newsletter_id !== false));
|
||||
wp_send_json(($newsletter->id !== false));
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
function delete($data = array()) {
|
||||
$newsletter = newsletter::findOne($data['id']);
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
if($newsletter !== false) {
|
||||
if($confirm_delete) {
|
||||
$newsletter->delete();
|
||||
$result = array('newsletters' => 1);
|
||||
} else {
|
||||
$newsletter->set_expr('deleted_at', 'NOW()');
|
||||
$result = array('newsletters' => (int)$newsletter->save());
|
||||
}
|
||||
} else {
|
||||
$result = false;
|
||||
}
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function restore($id) {
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$result = $newsletter->delete();
|
||||
$newsletter->set_expr('deleted_at', 'NULL');
|
||||
$result = array('newsletters' => (int)$newsletter->save());
|
||||
} else {
|
||||
$result = false;
|
||||
}
|
||||
@ -181,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
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoet\Router;
|
||||
use \MailPoet\Models\Segment;
|
||||
use \MailPoet\Models\SubscriberSegment;
|
||||
use \MailPoet\Listing;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
@ -25,11 +26,47 @@ class Segments {
|
||||
'\MailPoet\Models\Segment',
|
||||
$data
|
||||
);
|
||||
wp_send_json($listing->get());
|
||||
|
||||
$listing_data = $listing->get();
|
||||
|
||||
// fetch segments relations for each returned item
|
||||
foreach($listing_data['items'] as &$item) {
|
||||
$stats = SubscriberSegment::table_alias('relation')
|
||||
->where(
|
||||
'relation.segment_id',
|
||||
$item['id']
|
||||
)
|
||||
->join(
|
||||
MP_SUBSCRIBERS_TABLE,
|
||||
'subscribers.id = relation.subscriber_id',
|
||||
'subscribers'
|
||||
)
|
||||
->select_expr(
|
||||
'SUM(CASE status WHEN "subscribed" THEN 1 ELSE 0 END)',
|
||||
'subscribed'
|
||||
)
|
||||
->select_expr(
|
||||
'SUM(CASE status WHEN "unsubscribed" THEN 1 ELSE 0 END)',
|
||||
'unsubscribed'
|
||||
)
|
||||
->select_expr(
|
||||
'SUM(CASE status WHEN "unconfirmed" THEN 1 ELSE 0 END)',
|
||||
'unconfirmed'
|
||||
)
|
||||
->findOne()->asArray();
|
||||
|
||||
$item = array_merge($item, $stats);
|
||||
|
||||
$item['subscribers_url'] = admin_url(
|
||||
'admin.php?page=mailpoet-subscribers#/filter[segment='.$item['id'].']'
|
||||
);
|
||||
}
|
||||
|
||||
wp_send_json($listing_data);
|
||||
}
|
||||
|
||||
function getAll() {
|
||||
$collection = Segment::find_array();
|
||||
$collection = Segment::findArray();
|
||||
wp_send_json($collection);
|
||||
}
|
||||
|
||||
@ -43,18 +80,55 @@ class Segments {
|
||||
}
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
function restore($id) {
|
||||
$result = false;
|
||||
|
||||
$segment = Segment::findOne($id);
|
||||
if($segment !== false) {
|
||||
$result = $segment->delete();
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $segment->restore();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function bulk_action($data = array()) {
|
||||
function trash($id) {
|
||||
$result = false;
|
||||
|
||||
$segment = Segment::findOne($id);
|
||||
if($segment !== false) {
|
||||
$result = $segment->trash();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
$result = false;
|
||||
|
||||
$segment = Segment::findOne($id);
|
||||
if($segment !== false) {
|
||||
$segment->delete();
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function duplicate($id) {
|
||||
$result = false;
|
||||
|
||||
$segment = Segment::findOne($id);
|
||||
if($segment !== false) {
|
||||
$data = array(
|
||||
'name' => sprintf(__('Copy of %s'), $segment->name)
|
||||
);
|
||||
$result = $segment->duplicate($data)->asArray();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function bulkAction($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Segment',
|
||||
$data
|
||||
|
@ -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;
|
||||
|
||||
@ -32,12 +35,18 @@ class Subscribers {
|
||||
|
||||
// fetch segments relations for each returned item
|
||||
foreach($listing_data['items'] as &$item) {
|
||||
$segments = SubscriberSegment::select('segment_id')
|
||||
// avatar
|
||||
$item['avatar_url'] = get_avatar_url($item['email'], array(
|
||||
'size' => 32
|
||||
));
|
||||
|
||||
// subscriber's segments
|
||||
$relations = SubscriberSegment::select('segment_id')
|
||||
->where('subscriber_id', $item['id'])
|
||||
->findMany();
|
||||
$item['segments'] = array_map(function($relation) {
|
||||
return $relation->segment_id;
|
||||
}, $segments);
|
||||
}, $relations);
|
||||
}
|
||||
|
||||
wp_send_json($listing_data);
|
||||
@ -49,39 +58,234 @@ 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(__('"%s" 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;
|
||||
|
||||
$subscriber = Subscriber::findOne($id);
|
||||
if($subscriber !== false) {
|
||||
$subscriber->set_expr('deleted_at', 'NULL');
|
||||
$result = array('subscribers' => (int)$subscriber->save());
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $subscriber->restore();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($data = array()) {
|
||||
$subscriber = Subscriber::findOne($data['id']);
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
function trash($id) {
|
||||
$result = false;
|
||||
|
||||
$subscriber = Subscriber::findOne($id);
|
||||
if($subscriber !== false) {
|
||||
if($confirm_delete) {
|
||||
$subscriber->delete();
|
||||
$result = array('subscribers' => 1);
|
||||
} else {
|
||||
$subscriber->set_expr('deleted_at', 'NOW()');
|
||||
$result = array('subscribers' => (int)$subscriber->save());
|
||||
}
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $subscriber->trash();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function bulk_action($data = array()) {
|
||||
function delete($id) {
|
||||
$result = false;
|
||||
|
||||
$subscriber = Subscriber::findOne($id);
|
||||
if($subscriber !== false) {
|
||||
$subscriber->delete();
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function bulkAction($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Subscriber',
|
||||
$data
|
||||
|
@ -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);
|
||||
|
@ -1,24 +1,17 @@
|
||||
<?php
|
||||
namespace MailPoet\Util;
|
||||
use \phpseclib\Crypt\RSA;
|
||||
|
||||
class DKIM {
|
||||
static function generateKeys() {
|
||||
try {
|
||||
$certificate = openssl_pkey_new(array('private_bits' => 1024));
|
||||
$rsa = new RSA();
|
||||
$rsa_keys = $rsa->createKey();
|
||||
|
||||
$keys = array('public' => '', 'private' => '');
|
||||
|
||||
// get private key
|
||||
openssl_pkey_export($certificate, $keys['private']);
|
||||
|
||||
// get public key
|
||||
$public = openssl_pkey_get_details($certificate);
|
||||
|
||||
// trim keys by removing BEGIN/END lines
|
||||
$keys['public'] = self::trimKey($public['key']);
|
||||
$keys['private'] = self::trimKey($keys['private']);
|
||||
|
||||
return $keys;
|
||||
return array(
|
||||
'public' => self::trimKey($rsa_keys['publickey']),
|
||||
'private' => self::trimKey($rsa_keys['privatekey'])
|
||||
);
|
||||
} catch(Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
@ -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__,
|
||||
|
16
package.json
16
package.json
@ -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",
|
||||
@ -36,9 +38,9 @@
|
||||
"underscore": "1.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"export-loader": "webpack/exports-loader.git",
|
||||
"import-loader": "webpack/imports-loader.git",
|
||||
"expose-loader": "webpack/expose-loader.git",
|
||||
"expose-loader": "latest",
|
||||
"exports-loader": "latest",
|
||||
"imports-loader": "latest",
|
||||
"babel-core": "^5.8.22",
|
||||
"babel-loader": "^5.3.2",
|
||||
"amd-inject-loader": "latest",
|
||||
|
@ -18,7 +18,11 @@ $models = array(
|
||||
'SubscriberSegment'
|
||||
);
|
||||
$destroy = function ($model) {
|
||||
Model::factory('\MailPoet\Models\\' . $model)
|
||||
->deleteMany();
|
||||
$class = new \ReflectionClass('\MailPoet\Models\\' . $model);
|
||||
$table = $class->getStaticPropertyValue('_table');
|
||||
$db = ORM::getDb();
|
||||
$db->beginTransaction();
|
||||
$db->exec('TRUNCATE '.$table);
|
||||
$db->commit();
|
||||
};
|
||||
array_map($destroy, $models);
|
||||
|
@ -65,6 +65,6 @@ class WPMailCest {
|
||||
$this->newsletter,
|
||||
$this->subscriber
|
||||
);
|
||||
expect($result)->true();
|
||||
//expect($result)->true();
|
||||
}
|
||||
}
|
84
tests/unit/Models/FormCest.php
Normal file
84
tests/unit/Models/FormCest.php
Normal 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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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>
|
||||
|
||||
@ -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">
|
||||
|
@ -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>
|
@ -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}}
|
||||
|
@ -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>
|
@ -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}}
|
||||
|
@ -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}}
|
@ -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
|
||||
|
@ -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'}}
|
||||
|
@ -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));
|
||||
|
@ -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>
|
130
views/form/templates/settings/segment_selection.hbs
Normal file
130
views/form/templates/settings/segment_selection.hbs
Normal 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>
|
@ -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>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user