Compare commits
156 Commits
Author | SHA1 | Date | |
---|---|---|---|
8d61866b77 | |||
0831c748b1 | |||
b2a0bc3860 | |||
1f99345e7b | |||
89782bc94b | |||
155ff09280 | |||
132e6d3342 | |||
f02699158f | |||
be3462925d | |||
3d82230d10 | |||
c20c46fd86 | |||
6e63c72aa5 | |||
e059eec5ea | |||
a2d38c9076 | |||
8d507b2ee0 | |||
5e2979c283 | |||
84ec0de3cd | |||
ee07780833 | |||
ed104156a9 | |||
90f2e9ff9d | |||
98fb7aa65e | |||
a51eb59cf8 | |||
270023b89c | |||
7d77e075e9 | |||
9bbe36b3cb | |||
7a904ed093 | |||
e3c065b353 | |||
4ca2872e0e | |||
ce338f7fe2 | |||
fa28b0a955 | |||
a298650187 | |||
95772ef68a | |||
e1c94db516 | |||
7be1a11d1e | |||
c04b95c09a | |||
cdfeb8d512 | |||
3ef8067968 | |||
9fb04bc3c0 | |||
25727ea0ba | |||
4c8ac369b7 | |||
268dabdc9f | |||
c0ba218949 | |||
ee85139089 | |||
b4f83fe1bd | |||
bd83001ef5 | |||
fb3a9f485f | |||
fd44776ae9 | |||
6dbe338b01 | |||
1f06a7dd0b | |||
37c218f782 | |||
25016f2a8d | |||
792744a270 | |||
c5fbfca132 | |||
c2fde308cb | |||
533d9b0d38 | |||
2035b802e3 | |||
a5e66ec6a0 | |||
beb939df9e | |||
44e342c692 | |||
3a417d460f | |||
1950d6661f | |||
da6e154642 | |||
acebf669a7 | |||
4a2bbe3f88 | |||
9b011c0281 | |||
bf58d8a22d | |||
72d1eb79a6 | |||
bb4893c0a0 | |||
9929cf0aee | |||
83967e84ba | |||
9621cb3ca9 | |||
a413f666fe | |||
d1e2c6c074 | |||
3b6a9f7a6e | |||
d2e5fb89c2 | |||
97d1e95037 | |||
48fbce22e7 | |||
916fe76795 | |||
e10310fb5c | |||
367afcf814 | |||
67fa9e0993 | |||
d7553a5f27 | |||
8c847825fa | |||
d21d9b99b0 | |||
8461c13532 | |||
3b7ffe9ba7 | |||
1724fa22c1 | |||
01089d7a72 | |||
717ebfd20c | |||
daff3d5016 | |||
98fb838169 | |||
f13a4dd4f3 | |||
62a164e4c6 | |||
04238f3339 | |||
bc62474f3c | |||
98005a2a6f | |||
b7fe8dc6d6 | |||
436faea591 | |||
4208b148b4 | |||
5ce5f0bf8a | |||
18518de397 | |||
68f747211a | |||
ebd26ddd98 | |||
924aa0439f | |||
3124d6a61b | |||
149d031b52 | |||
fa96c4697d | |||
d46c9d5412 | |||
9ab8b1f0c5 | |||
9425ac1593 | |||
4e32479609 | |||
7d95b38dc4 | |||
17c83c5bd4 | |||
23bb2f111f | |||
4655b2c64c | |||
84fede11b8 | |||
f37488fc0b | |||
20e2e03982 | |||
a5d96f1534 | |||
a516eb1a95 | |||
6dd8270bec | |||
981cbd579f | |||
52a0aae10f | |||
ebca4257a6 | |||
c3944095bc | |||
a1445d1b6a | |||
e62c24879b | |||
00f06ea202 | |||
32ca24ce38 | |||
44e3adb422 | |||
a1346ebecc | |||
25b51d0446 | |||
556a170903 | |||
7ac386a8e2 | |||
d91b55ec52 | |||
786fbc36a2 | |||
160e8b7a12 | |||
0b1f85da09 | |||
fbc6f54ddc | |||
a603e97b8c | |||
0875b627b6 | |||
035784ece0 | |||
aa93c7349f | |||
82cf4a28fd | |||
832e5ef342 | |||
e3de3a123a | |||
db91590159 | |||
28c61fca0b | |||
e62a8c2ec5 | |||
fdbd1245e3 | |||
0eef46db57 | |||
080ae88a04 | |||
225be9f3cd | |||
c9a42ebb76 | |||
ae9b3df92d | |||
63a08ebb55 |
1
.gitignore
vendored
@ -16,3 +16,4 @@ wysija-newsletters.zip
|
||||
tests/javascript/testBundles
|
||||
assets/css/*.css
|
||||
assets/js/*.js
|
||||
.vagrant
|
||||
|
11
README.md
@ -8,7 +8,6 @@ MailPoet done the right way.
|
||||
```
|
||||
php
|
||||
nodejs
|
||||
phantomjs
|
||||
wordpress
|
||||
```
|
||||
|
||||
@ -47,16 +46,6 @@ $ ./do compile:all
|
||||
$ ./do test:unit
|
||||
```
|
||||
|
||||
- Acceptance tests:
|
||||
```sh
|
||||
$ ./do test:acceptance
|
||||
```
|
||||
|
||||
- Run all tests:
|
||||
```sh
|
||||
$ ./do test:all
|
||||
```
|
||||
|
||||
- Debug tests:
|
||||
```sh
|
||||
$ ./do test:debug
|
||||
|
@ -47,6 +47,15 @@ class RoboFile extends \Robo\Tasks {
|
||||
->run();
|
||||
}
|
||||
|
||||
function watchCss() {
|
||||
$css_files = $this->rsearch('assets/css/src/', array('styl'));
|
||||
$this->taskWatch()
|
||||
->monitor($css_files, function() {
|
||||
$this->compileCss();
|
||||
})
|
||||
->run();
|
||||
}
|
||||
|
||||
function watchJs() {
|
||||
$this->_exec('./node_modules/webpack/bin/webpack.js --watch');
|
||||
}
|
||||
|
@ -5,12 +5,15 @@
|
||||
@require 'common'
|
||||
@require 'modal'
|
||||
@require 'notice'
|
||||
@require 'parsley'
|
||||
|
||||
@require 'form_editor'
|
||||
@require 'listing'
|
||||
@require 'box'
|
||||
@require 'breadcrumb'
|
||||
|
||||
@require 'form'
|
||||
@require 'parsley'
|
||||
@require 'form_validation'
|
||||
|
||||
@require 'settings'
|
||||
@require 'progress_bar'
|
||||
|
@ -26,3 +26,25 @@ textarea.regular-text
|
||||
@media screen and (max-width: 782px)
|
||||
.select2-container
|
||||
width: 100% !important
|
||||
|
||||
// progress bars
|
||||
progress-border-radius = 5px
|
||||
progress-background = #efefef
|
||||
progress-foreground = #69b1e9
|
||||
|
||||
progress
|
||||
background-color: progress-background;
|
||||
height: 2em
|
||||
border: 0
|
||||
width: 100%
|
||||
|
||||
progress::-webkit-progress-bar
|
||||
background-color: progress-background;
|
||||
|
||||
progress::-webkit-progress-value
|
||||
background-color: progress-foreground
|
||||
border-radius: progress-border-radius
|
||||
|
||||
progress::-moz-progress-bar
|
||||
background-color: progress-foreground
|
||||
border-radius: progress-border-radius
|
||||
|
@ -4,6 +4,9 @@
|
||||
icons = '../img/form_editor_icons.png'
|
||||
handle_icon = '../img/handle.png'
|
||||
|
||||
#mailpoet_form_name
|
||||
font-size: 23px
|
||||
|
||||
#mailpoet_form_history
|
||||
display: none
|
||||
|
||||
@ -99,6 +102,7 @@ handle_icon = '../img/handle.png'
|
||||
/* MailPoet Form wrapper */
|
||||
#mailpoet_form_wrapper
|
||||
position: relative
|
||||
margin: 20px 0 0 0
|
||||
|
||||
/* MailPoet Form container */
|
||||
#mailpoet_form_container
|
||||
|
6
assets/css/src/form_validation.styl
Normal file
@ -0,0 +1,6 @@
|
||||
.parsley-errors-list
|
||||
margin-top: 8px
|
||||
|
||||
.parsley-required
|
||||
.parsley-custom-error-message
|
||||
color: #b94a48
|
@ -159,23 +159,6 @@ body.mailpoet_modal_opened
|
||||
margin: 0
|
||||
text-align: right
|
||||
|
||||
.mailpoet_button
|
||||
padding: 3px 15px
|
||||
border: 1px solid #444
|
||||
font-weight: normal
|
||||
cursor: pointer
|
||||
background-color: #222
|
||||
color: #cfcfcf
|
||||
font-size: 1em
|
||||
|
||||
.mailpoet_button:hover
|
||||
background-color: #00aacc
|
||||
color: #fff
|
||||
|
||||
.mailpoet_button:active
|
||||
background-color: #00ccff
|
||||
color: #fff
|
||||
|
||||
@media screen and (max-width: 782px)
|
||||
#mailpoet_modal_overlay.mailpoet_panel_overlay
|
||||
top: 46px
|
||||
|
@ -76,13 +76,24 @@ $layer-selector-width = 30px
|
||||
display: inline-block
|
||||
padding: 2px
|
||||
vertical-align: top
|
||||
animation-background-color()
|
||||
|
||||
.mailpoet_tool
|
||||
padding: 0
|
||||
|
||||
.mailpoet_delete_block_activate
|
||||
max-width: 100%
|
||||
display: inline-block
|
||||
opacity: 1
|
||||
animation-fade-in-and-scale-horizontally()
|
||||
|
||||
.mailpoet_delete_block_confirm,
|
||||
.mailpoet_delete_block_cancel
|
||||
display: none
|
||||
max-width: 0
|
||||
opacity: 0
|
||||
overflow: hidden
|
||||
display: inline-block
|
||||
animation-fade-in-and-scale-horizontally()
|
||||
|
||||
.mailpoet_delete_block_activated
|
||||
width: auto
|
||||
@ -93,11 +104,14 @@ $layer-selector-width = 30px
|
||||
height: auto
|
||||
|
||||
.mailpoet_delete_block_activate
|
||||
display: none
|
||||
overflow: hidden
|
||||
max-width: 0
|
||||
opacity: 0
|
||||
|
||||
.mailpoet_delete_block_confirm,
|
||||
.mailpoet_delete_block_cancel
|
||||
display: inline-block
|
||||
max-width: 100%
|
||||
opacity: 1
|
||||
|
||||
.mailpoet_delete_block_confirm
|
||||
color: $warning-text-color
|
||||
|
@ -52,6 +52,7 @@ $draggable-widget-z-index = 2
|
||||
padding: 0
|
||||
margin: 0
|
||||
z-index: $draggable-widget-z-index
|
||||
animation-fade-in-and-scale-up()
|
||||
|
||||
.mailpoet_widget_icon
|
||||
padding: 0
|
||||
|
@ -48,7 +48,7 @@
|
||||
.mailpoet_save_as_template_container,
|
||||
.mailpoet_export_template_container
|
||||
border-radius(3px)
|
||||
float: left
|
||||
display: inline-block
|
||||
clear: both
|
||||
|
||||
margin-top: 5px
|
||||
|
@ -32,7 +32,7 @@ $widget-icon-width = 30px
|
||||
|
||||
.mailpoet_region_content
|
||||
max-height: 2000px
|
||||
transition: max-height 0.2s ease
|
||||
transition: max-height 300ms ease
|
||||
padding: 0 20px
|
||||
margin-top: 12px
|
||||
|
||||
|
@ -18,3 +18,6 @@
|
||||
|
||||
& > .mailpoet_block
|
||||
width: 100%
|
||||
|
||||
.mailpoet_automated_latest_content_display_options
|
||||
animation-slide-open-downwards()
|
||||
|
@ -30,3 +30,8 @@ $block-hover-highlight-color = $primary-active-color
|
||||
|
||||
.mailpoet_content
|
||||
position: relative
|
||||
|
||||
.mailpoet_block_transition_in
|
||||
animation-fade-in-and-scale-up()
|
||||
.mailpoet_block_transition_out
|
||||
animation-fade-out-and-scale-down()
|
||||
|
@ -79,3 +79,4 @@ $three-column-width = ($newsletter-width / 3) - (2 * $column-margin)
|
||||
box-shadow(inset 1px 2px 1px $primary-inactive-color)
|
||||
color: #656565
|
||||
border-radius(3px)
|
||||
animation-background-color()
|
||||
|
@ -19,6 +19,10 @@ $divider-hover-border-color = $primary-active-color
|
||||
width: 100%
|
||||
border: 1px solid transparent
|
||||
|
||||
.mailpoet_active_divider_style
|
||||
border: 1px solid $active-divider-border-color
|
||||
background: $active-divider-background-color
|
||||
|
||||
.mailpoet_field_divider_style:hover
|
||||
border: 1px solid $divider-hover-border-color
|
||||
|
||||
|
@ -1,15 +1,12 @@
|
||||
.mailpoet_posts_block
|
||||
box-shadow(none)
|
||||
padding-left: 0
|
||||
padding-right: 0
|
||||
|
||||
& > .mailpoet_content
|
||||
font-size: 1em
|
||||
text-align: center
|
||||
background-color: $primary-active-color
|
||||
margin: 20px 0
|
||||
padding: 15px
|
||||
box-shadow(inset 1px 2px 1px $primary-inset-shadow-color)
|
||||
color: $white-color
|
||||
border-radius(3px)
|
||||
.mailpoet_posts_block_posts
|
||||
overflow: auto
|
||||
|
||||
& > .mailpoet_block
|
||||
width: 100%
|
||||
|
||||
.mailpoet_post_selection_filter_row
|
||||
margin-top: 5px
|
||||
@ -18,7 +15,11 @@
|
||||
.mailpoet_posts_categories_and_tags
|
||||
width: 100%
|
||||
|
||||
.mailpoet_settings_posts_show_display_options
|
||||
.mailpoet_settings_posts_display_options
|
||||
.mailpoet_settings_posts_selection
|
||||
animation-slide-open-downwards()
|
||||
|
||||
.mailpoet_settings_posts_show_display_options,
|
||||
.mailpoet_settings_posts_show_post_selection
|
||||
display: block
|
||||
margin-top: 10px
|
||||
|
53
assets/css/src/newsletter_editor/mixins/transitions.styl
Normal file
@ -0,0 +1,53 @@
|
||||
animation-slide-open-downwards()
|
||||
transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
max-height: 2000px
|
||||
opacity: 1
|
||||
|
||||
&.mailpoet_closed
|
||||
max-height: 0
|
||||
opacity: 0
|
||||
overflow-y: hidden
|
||||
|
||||
animation-background-color()
|
||||
transition: background 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
|
||||
animation-fade-in-and-scale-up()
|
||||
animation-name: fadeInAndScaleUp
|
||||
animation-duration: 500ms
|
||||
animation-fill-mode: forwards
|
||||
|
||||
animation-fade-out-and-scale-down()
|
||||
animation-name: fadeOutAndScaleDown
|
||||
animation-duration: 500ms
|
||||
animation-fill-mode: forwards
|
||||
|
||||
animation-fade-in-and-scale-horizontally()
|
||||
transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
|
||||
@keyframes fadeInAndScaleUp {
|
||||
0% {
|
||||
opacity: 0.3
|
||||
max-height: 0
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1
|
||||
max-height: 5000px
|
||||
overflow: hidden
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOutAndScaleDown {
|
||||
0% {
|
||||
opacity: 1
|
||||
max-height: 5000px
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.3
|
||||
max-height: 0
|
||||
overflow: hidden
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
@require 'mixins/border-radius'
|
||||
@require 'mixins/box-shadow'
|
||||
@require 'mixins/filter-shadow'
|
||||
@require 'mixins/transitions'
|
||||
|
||||
@require 'variables'
|
||||
@require 'common'
|
||||
|
29
assets/css/src/progress_bar.styl
Normal file
@ -0,0 +1,29 @@
|
||||
.mailpoet_progress
|
||||
background-color: #efefef
|
||||
height: 25px
|
||||
padding: 0
|
||||
width: 100%
|
||||
margin: 0
|
||||
border-radius: 5px
|
||||
position: relative
|
||||
|
||||
.mailpoet_progress_label
|
||||
position: absolute
|
||||
width: 100%
|
||||
text-align: center
|
||||
display: inline-block
|
||||
margin: 2px 0 0 0
|
||||
|
||||
.mailpoet_progress_bar
|
||||
position: absolute
|
||||
display: inline-block
|
||||
height: 100%
|
||||
border-radius: 3px
|
||||
box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset
|
||||
background-color: #34c2e3
|
||||
background-image: linear-gradient(top, #34c2e3, darken(#34c2e3, 20%))
|
||||
|
||||
.mailpoet_progress_complete
|
||||
.mailpoet_progress_bar
|
||||
background-color: #fecf23
|
||||
background-image: linear-gradient(top, #fecf23, #fd9215)
|
@ -1,3 +1,4 @@
|
||||
@import 'nib'
|
||||
|
||||
@require 'parsley'
|
||||
@require 'form_validation'
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
assets/img/post_notifications_template/ALC-widget-icon.png
Executable file
After Width: | Height: | Size: 3.9 KiB |
BIN
assets/img/post_notifications_template/settings-icon-highlight.png
Executable file
After Width: | Height: | Size: 7.2 KiB |
12
assets/img/preview_magnifying_glass.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="47.002px" height="38.003px" viewBox="0 0 47.002 38.003" enable-background="new 0 0 47.002 38.003" xml:space="preserve">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#565656" d="M46.328,36.365c-1.188,1.725-3.553,2.158-5.273,0.962L25.479,26.52
|
||||
c-1.104-0.763-1.674-2.007-1.631-3.257c-2.006,2.157-4.642,3.606-7.594,4.145c-3.626,0.663-7.288-0.13-10.311-2.227
|
||||
c-3.024-2.098-5.054-5.253-5.714-8.887c-0.661-3.636,0.127-7.31,2.221-10.344c4.325-6.264,12.927-7.834,19.177-3.5
|
||||
c5.672,3.938,7.486,11.412,4.537,17.443c1.152-0.486,2.519-0.392,3.627,0.377l15.58,10.808C47.09,32.274,47.52,34.641,46.328,36.365
|
||||
z M23.235,12.09c-0.459-2.534-1.874-4.734-3.982-6.196C14.897,2.87,8.896,3.963,5.878,8.331c-3.014,4.373-1.922,10.388,2.435,13.408
|
||||
c4.356,3.025,10.356,1.932,13.374-2.438C23.146,17.187,23.696,14.625,23.235,12.09z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/img/sample_template/coffee-grain.jpg
Normal file
After Width: | Height: | Size: 178 KiB |
BIN
assets/img/sample_template/header-v2.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
assets/img/sample_template/map-v2.jpg
Normal file
After Width: | Height: | Size: 130 KiB |
BIN
assets/img/sample_template/sandwich.jpg
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
assets/img/welcome_template/logo-header.gif
Executable file
After Width: | Height: | Size: 4.8 KiB |
102
assets/js/src/cron.jsx
Normal file
@ -0,0 +1,102 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'react-dom',
|
||||
'mailpoet'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
ReactDOM,
|
||||
MailPoet
|
||||
) {
|
||||
var CronControl = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
status: 'loading'
|
||||
};
|
||||
},
|
||||
getDaemonData: function() {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'cron',
|
||||
action: 'getDaemonStatus'
|
||||
})
|
||||
.done(function(response) {
|
||||
jQuery('.button-primary')
|
||||
.removeClass('disabled');
|
||||
if(response.status !== undefined) {
|
||||
this.setState(response);
|
||||
} else {
|
||||
this.replaceState();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
componentDidMount: function() {
|
||||
if(this.isMounted()) {
|
||||
this.getDaemonData();
|
||||
setInterval(this.getDaemonData, 5000);
|
||||
}
|
||||
},
|
||||
controlDaemon: function(action) {
|
||||
jQuery('.button-primary')
|
||||
.addClass('disabled');
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'cron',
|
||||
action: 'controlDaemon',
|
||||
data: {
|
||||
'action': action
|
||||
}
|
||||
})
|
||||
.done(function(response) {
|
||||
if(!response.result) {
|
||||
//this.replaceState();
|
||||
} else {
|
||||
//this.setState(response);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
render: function() {
|
||||
if(this.state.status === 'loading') {
|
||||
return(<div>Loading daemon status...</div>);
|
||||
}
|
||||
switch(this.state.status) {
|
||||
case 'started':
|
||||
return(
|
||||
<div>
|
||||
Cron daemon is running.
|
||||
<br/>
|
||||
<br/>
|
||||
It was started
|
||||
<strong> {this.state.timeSinceStart} </strong> and last executed
|
||||
<strong> {this.state.timeSinceUpdate} </strong> for a total of
|
||||
<strong> {this.state.counter} </strong> times (once every 30 seconds, unless it was interrupted and restarted).
|
||||
<br />
|
||||
<br />
|
||||
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'stop')}>Stop</a>
|
||||
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'pause')}>Pause</a>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case 'paused':
|
||||
case 'stopped':
|
||||
return(
|
||||
<div>
|
||||
Daemon is {this.state.status}
|
||||
<br />
|
||||
<br />
|
||||
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'start')}>Start</a>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const container = document.getElementById('cron_container');
|
||||
|
||||
if(container) {
|
||||
ReactDOM.render(
|
||||
<CronControl />,
|
||||
container
|
||||
);
|
||||
}
|
||||
});
|
@ -23,7 +23,9 @@ function(
|
||||
name={ this.props.field.name }
|
||||
id={ 'field_'+this.props.field.name }
|
||||
value={ this.props.item[this.props.field.name] }
|
||||
onChange={ this.props.onValueChange }>
|
||||
onChange={ this.props.onValueChange }
|
||||
{...this.props.field.validation}
|
||||
>
|
||||
{options}
|
||||
</select>
|
||||
);
|
||||
|
@ -25,13 +25,10 @@ function(
|
||||
(this.props.item !== undefined && prevProps.item !== undefined)
|
||||
&& (this.props.item.id !== prevProps.item.id)
|
||||
) {
|
||||
jQuery('#'+this.refs.select.id).select2(
|
||||
'val',
|
||||
this.props.item[this.props.field.name]
|
||||
);
|
||||
jQuery('#'+this.refs.select.id)
|
||||
.val(this.props.item[this.props.field.name])
|
||||
.trigger('change');
|
||||
}
|
||||
|
||||
this.setupSelect2();
|
||||
},
|
||||
setupSelect2: function() {
|
||||
if(
|
||||
@ -53,7 +50,19 @@ function(
|
||||
}
|
||||
});
|
||||
|
||||
var hasRemoved = false;
|
||||
select2.on('select2:unselecting', function(e) {
|
||||
hasRemoved = true;
|
||||
});
|
||||
select2.on('select2:opening', function(e) {
|
||||
if(hasRemoved === true) {
|
||||
hasRemoved = false;
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
select2.on('change', this.handleChange);
|
||||
|
||||
select2.select2(
|
||||
'val',
|
||||
this.props.item[this.props.field.name]
|
||||
@ -77,7 +86,7 @@ function(
|
||||
handleChange: function(e) {
|
||||
if(this.props.onValueChange !== undefined) {
|
||||
if(this.props.field.multiple) {
|
||||
value = jQuery('#'+this.refs.select.id).select2('val');
|
||||
value = jQuery('#'+this.refs.select.id).val();
|
||||
} else {
|
||||
value = e.target.value;
|
||||
}
|
||||
@ -88,7 +97,6 @@ function(
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
},
|
||||
render: function() {
|
||||
var options = this.state.items.map(function(item, index) {
|
||||
@ -114,8 +122,8 @@ function(
|
||||
ref="select"
|
||||
placeholder={ this.props.field.placeholder }
|
||||
multiple={ this.props.field.multiple }
|
||||
onChange={ this.handleChange }
|
||||
defaultValue={ default_value }
|
||||
{...this.props.field.validation}
|
||||
>{ options }</select>
|
||||
);
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ function(
|
||||
) {
|
||||
var FormFieldText = React.createClass({
|
||||
render: function() {
|
||||
var value = this.props.item[this.props.field.name];
|
||||
if(!value) { value = null; }
|
||||
return (
|
||||
<input
|
||||
type="text"
|
||||
@ -17,10 +19,12 @@ function(
|
||||
}
|
||||
name={ this.props.field.name }
|
||||
id={ 'field_'+this.props.field.name }
|
||||
value={ this.props.item[this.props.field.name] }
|
||||
value={ value }
|
||||
placeholder={ this.props.field.placeholder }
|
||||
defaultValue={ this.props.field.defaultValue }
|
||||
onChange={ this.props.onValueChange } />
|
||||
onChange={ this.props.onValueChange }
|
||||
{...this.props.field.validation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -15,7 +15,9 @@ function(
|
||||
value={ this.props.item[this.props.field.name] }
|
||||
placeholder={ this.props.field.placeholder }
|
||||
defaultValue={ this.props.field.defaultValue }
|
||||
onChange={ this.props.onValueChange } />
|
||||
onChange={ this.props.onValueChange }
|
||||
{...this.props.field.validation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -68,12 +68,25 @@ define(
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// handle validation
|
||||
if(this.props.isValid !== undefined) {
|
||||
if(this.props.isValid() === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
||||
// only get values from displayed fields
|
||||
item = {};
|
||||
var item = {};
|
||||
this.props.fields.map(function(field) {
|
||||
item[field.name] = this.state.item[field.name];
|
||||
if(field['fields'] !== undefined) {
|
||||
field.fields.map(function(subfield) {
|
||||
item[subfield.name] = this.state.item[subfield.name];
|
||||
}.bind(this));
|
||||
} else {
|
||||
item[field.name] = this.state.item[field.name];
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
// set id if specified
|
||||
|
@ -231,7 +231,7 @@ var WysijaHistory = {
|
||||
|
||||
/* MailPoet Form */
|
||||
var WysijaForm = {
|
||||
version: '0.6',
|
||||
version: '0.7',
|
||||
options: {
|
||||
container: 'mailpoet_form_container',
|
||||
editor: 'mailpoet_form_editor',
|
||||
@ -317,6 +317,7 @@ var WysijaForm = {
|
||||
save: function() {
|
||||
var position = 1,
|
||||
data = {
|
||||
'name': $F('mailpoet_form_name'),
|
||||
'settings': $('mailpoet_form_settings').serialize(true),
|
||||
'body': [],
|
||||
'styles': (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
|
||||
|
@ -105,6 +105,9 @@ const item_actions = [
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'trash'
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -79,27 +79,48 @@ define(
|
||||
|
||||
if(custom_actions.length > 0) {
|
||||
item_actions = custom_actions.map(function(action, index) {
|
||||
if(action.refresh) {
|
||||
if(action.display !== undefined) {
|
||||
if(action.display(this.props.item) === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(action.name === 'trash') {
|
||||
return (
|
||||
<span key={ 'action-'+index } className="trash">
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
<a
|
||||
href="javascript:;"
|
||||
onClick={ this.handleTrashItem.bind(
|
||||
null,
|
||||
this.props.item.id
|
||||
) }>
|
||||
Trash
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if(action.refresh) {
|
||||
return (
|
||||
<span
|
||||
onClick={ this.props.onRefreshItems }
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
{ action.link(this.props.item) }
|
||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
||||
</span>
|
||||
);
|
||||
} else if(action.link) {
|
||||
return (
|
||||
<span
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
{ action.link(this.props.item) }
|
||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span
|
||||
key={ 'action-'+index } className={ action.name }>
|
||||
{(index > 0) ? ' | ' : ''}
|
||||
<a href="javascript:;" onClick={
|
||||
(action.onClick !== undefined)
|
||||
? action.onClick.bind(null,
|
||||
@ -108,7 +129,6 @@ define(
|
||||
)
|
||||
: false
|
||||
}>{ action.label }</a>
|
||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -158,17 +178,6 @@ define(
|
||||
<div>
|
||||
<div className="row-actions">
|
||||
{ item_actions }
|
||||
{ ' | ' }
|
||||
<span className="trash">
|
||||
<a
|
||||
href="javascript:;"
|
||||
onClick={ this.handleTrashItem.bind(
|
||||
null,
|
||||
this.props.item.id
|
||||
) }>
|
||||
Trash
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
||||
@ -388,6 +397,12 @@ define(
|
||||
if(this.isMounted()) {
|
||||
const params = this.props.params || {}
|
||||
this.initWithParams(params)
|
||||
|
||||
if(this.props.auto_refresh) {
|
||||
jQuery(document).on('heartbeat-tick.mailpoet', function(e, data) {
|
||||
this.getItems();
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
},
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
@ -637,7 +652,7 @@ define(
|
||||
// bulk actions
|
||||
var bulk_actions = this.props.bulk_actions || [];
|
||||
|
||||
if(this.state.group === 'trash') {
|
||||
if(this.state.group === 'trash' && bulk_actions.length > 0) {
|
||||
bulk_actions = [
|
||||
{
|
||||
name: 'restore',
|
||||
|
@ -47,7 +47,6 @@ define([
|
||||
autoScroll: true,
|
||||
|
||||
onstart: function(event) {
|
||||
console.log('Drag start', event, this);
|
||||
|
||||
if (that.options.cloneOriginal === true) {
|
||||
// Use substitution instead of a clone
|
||||
|
@ -11,10 +11,10 @@ define([
|
||||
'newsletter_editor/blocks/base',
|
||||
'newsletter_editor/blocks/button',
|
||||
'newsletter_editor/blocks/divider',
|
||||
'newsletter_editor/components/wordpress',
|
||||
'newsletter_editor/components/communication',
|
||||
'underscore',
|
||||
'jquery'
|
||||
], function(App, BaseBlock, ButtonBlock, DividerBlock, WordpressComponent, _, jQuery) {
|
||||
], function(App, BaseBlock, ButtonBlock, DividerBlock, CommunicationComponent, _, jQuery) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -69,7 +69,7 @@ define([
|
||||
},
|
||||
fetchPosts: function() {
|
||||
var that = this;
|
||||
WordpressComponent.getTransformedPosts(this.toJSON()).done(function(content) {
|
||||
CommunicationComponent.getTransformedPosts(this.toJSON()).done(function(content) {
|
||||
console.log('ALC fetched', arguments);
|
||||
that.get('_container').get('blocks').reset(content, {parse: true});
|
||||
}).fail(function(error) {
|
||||
@ -161,7 +161,7 @@ define([
|
||||
var that = this;
|
||||
|
||||
// Dynamically update available post types
|
||||
WordpressComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
|
||||
this.$('.mailpoet_automated_latest_content_categories_and_tags').select2({
|
||||
multiple: true,
|
||||
@ -174,10 +174,10 @@ define([
|
||||
},
|
||||
transport: function(options, success, failure) {
|
||||
var taxonomies,
|
||||
promise = WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
promise = CommunicationComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
var promise = CommunicationComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
@ -226,11 +226,11 @@ define([
|
||||
toggleDisplayOptions: function(event) {
|
||||
var el = this.$('.mailpoet_automated_latest_content_display_options'),
|
||||
showControl = this.$('.mailpoet_automated_latest_content_show_display_options');
|
||||
if (el.hasClass('mailpoet_hidden')) {
|
||||
el.removeClass('mailpoet_hidden');
|
||||
if (el.hasClass('mailpoet_closed')) {
|
||||
el.removeClass('mailpoet_closed');
|
||||
showControl.addClass('mailpoet_hidden');
|
||||
} else {
|
||||
el.addClass('mailpoet_hidden');
|
||||
el.addClass('mailpoet_closed');
|
||||
showControl.removeClass('mailpoet_hidden');
|
||||
}
|
||||
},
|
||||
@ -306,7 +306,7 @@ define([
|
||||
_.each(postTypes, function(type) {
|
||||
select.append(jQuery('<option>', {
|
||||
value: type.name,
|
||||
text: type.labels.singular_name,
|
||||
text: type.label,
|
||||
}));
|
||||
});
|
||||
select.val(selectedValue);
|
||||
|
@ -48,6 +48,7 @@ define([
|
||||
},
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
'delete': 'deleteBlock',
|
||||
},
|
||||
events: {
|
||||
"mouseenter": "showTools",
|
||||
@ -88,7 +89,9 @@ define([
|
||||
this.$el.addClass('mailpoet_editor_view_' + this.cid);
|
||||
},
|
||||
initialize: function() {
|
||||
this.on('showSettings', this.showSettings);
|
||||
this.on('showSettings', this.showSettings, this);
|
||||
this.on('dom:refresh', this.showBlock, this);
|
||||
this._isFirstRender = true;
|
||||
},
|
||||
showTools: function(_event) {
|
||||
if (!this.showingToolsDisabled) {
|
||||
@ -114,12 +117,36 @@ define([
|
||||
* Defines drop behavior of BlockView instance
|
||||
*/
|
||||
getDropFunc: function() {
|
||||
var that = this;
|
||||
return function() {
|
||||
var newModel = that.model.clone();
|
||||
//that.model.destroy();
|
||||
return newModel;
|
||||
};
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
this.transitionIn();
|
||||
this._isFirstRender = false;
|
||||
}
|
||||
},
|
||||
deleteBlock: function() {
|
||||
this.transitionOut().done(function() {
|
||||
this.model.destroy();
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('mailpoet_block_transition_in');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('mailpoet_block_transition_out');
|
||||
},
|
||||
_transition: function(className) {
|
||||
var promise = jQuery.Deferred();
|
||||
|
||||
this.$el.addClass(className);
|
||||
this.$el.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd animationend', function() {
|
||||
this.$el.removeClass(className);
|
||||
promise.resolve();
|
||||
}.bind(this));
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
|
||||
@ -168,24 +195,22 @@ define([
|
||||
},
|
||||
deleteBlock: function(event) {
|
||||
event.preventDefault();
|
||||
this.model.destroy();
|
||||
this.model.trigger('delete');
|
||||
return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Module.BlockSettingsView = Marionette.LayoutView.extend({
|
||||
className: 'mailpoet_editor_settings',
|
||||
initialize: function() {
|
||||
var that = this;
|
||||
|
||||
MailPoet.Modal.panel({
|
||||
element: this.$el,
|
||||
template: '',
|
||||
position: 'right',
|
||||
width: App.getConfig().get('sidepanelWidth'),
|
||||
onCancel: function() {
|
||||
that.destroy();
|
||||
},
|
||||
this.destroy();
|
||||
}.bind(this),
|
||||
});
|
||||
},
|
||||
close: function(event) {
|
||||
|
@ -42,16 +42,12 @@ define([
|
||||
Module.ButtonBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_button_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.buttonBlock; },
|
||||
modelEvents: {
|
||||
'change': 'render',
|
||||
},
|
||||
onDragSubstituteBy: function() { return Module.ButtonWidgetView; },
|
||||
initialize: function() {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
var that = this;
|
||||
|
||||
// Listen for attempts to change all dividers in one go
|
||||
this._replaceButtonStylesHandler = function(data) { that.model.set(data); };
|
||||
this._replaceButtonStylesHandler = function(data) { this.model.set(data); }.bind(this);
|
||||
App.getChannel().on('replaceAllButtonStyles', this._replaceButtonStylesHandler);
|
||||
},
|
||||
onRender: function() {
|
||||
|
@ -75,7 +75,8 @@ define([
|
||||
getEmptyView: function() { return Module.ContainerBlockEmptyView; },
|
||||
emptyViewOptions: function() { return { renderOptions: this.renderOptions }; },
|
||||
modelEvents: {
|
||||
'change': 'render'
|
||||
'change': 'render',
|
||||
'delete': 'deleteBlock',
|
||||
},
|
||||
events: {
|
||||
"mouseenter": "showTools",
|
||||
@ -136,6 +137,8 @@ define([
|
||||
},
|
||||
initialize: function(options) {
|
||||
this.renderOptions = _.defaults(options.renderOptions || {}, {});
|
||||
this.on('dom:refresh', this.showBlock, this);
|
||||
this._isFirstRender = true;
|
||||
},
|
||||
// Determines which view type should be used for a child
|
||||
getChildView: function(model) {
|
||||
@ -229,12 +232,37 @@ define([
|
||||
_.extend(this, this._buildRegions(this.regions));
|
||||
},
|
||||
getDropFunc: function() {
|
||||
var that = this;
|
||||
return function() {
|
||||
var newModel = that.model.clone();
|
||||
that.model.destroy();
|
||||
return newModel;
|
||||
};
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
this.transitionIn();
|
||||
this._isFirstRender = false;
|
||||
}
|
||||
},
|
||||
deleteBlock: function() {
|
||||
this.transitionOut().done(function() {
|
||||
this.model.destroy();
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('mailpoet_block_transition_in');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('mailpoet_block_transition_out');
|
||||
},
|
||||
_transition: function(className) {
|
||||
var that = this,
|
||||
promise = jQuery.Deferred();
|
||||
|
||||
this.$el.addClass(className);
|
||||
this.$el.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd animationend', function() {
|
||||
that.$el.removeClass(className);
|
||||
promise.resolve();
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -57,11 +57,9 @@ define([
|
||||
this.listenTo(this.model, 'change:styles.block.padding', this.changePadding);
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
return _.extend({
|
||||
totalHeight: parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px',
|
||||
};
|
||||
}, base.BlockView.prototype.templateHelpers.apply(this));
|
||||
},
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.DividerBlockToolsView({ model: this.model });
|
||||
|
@ -39,9 +39,9 @@ define([
|
||||
Module.FooterBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_footer_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.footerBlock; },
|
||||
modelEvents: {
|
||||
modelEvents: _.extend({
|
||||
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
|
||||
},
|
||||
}, base.BlockView.prototype.modelEvents),
|
||||
onDragSubstituteBy: function() { return Module.FooterWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.FooterBlockToolsView({ model: this.model });
|
||||
|
@ -39,9 +39,9 @@ define([
|
||||
Module.HeaderBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_header_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.headerBlock; },
|
||||
modelEvents: {
|
||||
modelEvents: _.extend({
|
||||
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
|
||||
},
|
||||
}, base.BlockView.prototype.modelEvents),
|
||||
onDragSubstituteBy: function() { return Module.HeaderWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.HeaderBlockToolsView({ model: this.model });
|
||||
|
@ -37,11 +37,9 @@ define([
|
||||
getTemplate: function() { return templates.imageBlock; },
|
||||
onDragSubstituteBy: function() { return Module.ImageWidgetView; },
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
return _.extend({
|
||||
imageMissingSrc: App.getConfig().get('urls.imageMissing'),
|
||||
};
|
||||
}, base.BlockView.prototype.templateHelpers.apply(this));
|
||||
},
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
|
||||
|
@ -18,12 +18,12 @@ define([
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/components/wordpress',
|
||||
'newsletter_editor/components/communication',
|
||||
'newsletter_editor/blocks/base',
|
||||
'newsletter_editor/blocks/button',
|
||||
'newsletter_editor/blocks/divider',
|
||||
'select2'
|
||||
], function(Backbone, Marionette, Radio, _, jQuery, MailPoet, App, WordpressComponent, BaseBlock, ButtonBlock, DividerBlock) {
|
||||
], function(Backbone, Marionette, Radio, _, jQuery, MailPoet, App, CommunicationComponent, BaseBlock, ButtonBlock, DividerBlock) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -31,7 +31,7 @@ define([
|
||||
base = BaseBlock;
|
||||
|
||||
Module.PostsBlockModel = base.BlockModel.extend({
|
||||
stale: ['_selectedPosts', '_availablePosts'],
|
||||
stale: ['_selectedPosts', '_availablePosts', '_transformedPosts'],
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
type: 'posts',
|
||||
@ -63,6 +63,7 @@ define([
|
||||
divider: {},
|
||||
_selectedPosts: [],
|
||||
_availablePosts: [],
|
||||
_transformedPosts: new (App.getBlockTypeModel('container'))(),
|
||||
}, App.getConfig().get('blockDefaults.posts'));
|
||||
},
|
||||
relations: function() {
|
||||
@ -71,20 +72,31 @@ define([
|
||||
divider: App.getBlockTypeModel('divider'),
|
||||
_selectedPosts: Backbone.Collection,
|
||||
_availablePosts: Backbone.Collection,
|
||||
_transformedPosts: App.getBlockTypeModel('container'),
|
||||
};
|
||||
},
|
||||
initialize: function() {
|
||||
var that = this;
|
||||
var that = this,
|
||||
POST_REFRESH_DELAY_MS = 500,
|
||||
refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS),
|
||||
refreshTransformedPosts = _.debounce(this._refreshTransformedPosts.bind(this), POST_REFRESH_DELAY_MS);
|
||||
|
||||
// Attach Radio.Requests API primarily for highlighting
|
||||
_.extend(this, Radio.Requests);
|
||||
|
||||
this.fetchAvailablePosts();
|
||||
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', this._scheduleFetchAvailablePosts, this);
|
||||
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts);
|
||||
|
||||
this.listenTo(this.get('_selectedPosts'), 'add remove reset', refreshTransformedPosts);
|
||||
this.on('change:displayType change:titleFormat change:titlePosition change:titleAlignment change:titleIsLink change:imagePadded change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:showDivider', refreshTransformedPosts);
|
||||
this.listenTo(this.get('readMoreButton'), 'change', refreshTransformedPosts);
|
||||
this.listenTo(this.get('divider'), 'change', refreshTransformedPosts);
|
||||
|
||||
this.on('insertSelectedPosts', this._insertSelectedPosts, this);
|
||||
},
|
||||
fetchAvailablePosts: function() {
|
||||
var that = this;
|
||||
WordpressComponent.getPosts(this.toJSON()).done(function(posts) {
|
||||
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
|
||||
console.log('Posts fetched', arguments);
|
||||
that.get('_availablePosts').reset(posts);
|
||||
that.get('_selectedPosts').reset(); // Empty out the collection
|
||||
@ -93,20 +105,23 @@ define([
|
||||
console.log('Posts fetchPosts error', arguments);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Batch more changes during a specific time, instead of fetching
|
||||
* ALC posts on each model change
|
||||
*/
|
||||
_scheduleFetchAvailablePosts: function() {
|
||||
var timeout = 500,
|
||||
that = this;
|
||||
if (this._fetchPostsTimer !== undefined) {
|
||||
clearTimeout(this._fetchPostsTimer);
|
||||
_refreshTransformedPosts: function() {
|
||||
var that = this,
|
||||
data = this.toJSON();
|
||||
|
||||
data.posts = this.get('_selectedPosts').pluck('ID');
|
||||
|
||||
if (data.posts.length === 0) {
|
||||
this.get('_transformedPosts.blocks').reset();
|
||||
return;
|
||||
}
|
||||
this._fetchPostsTimer = setTimeout(function() {
|
||||
that.fetchAvailablePosts();
|
||||
that._fetchPostsTimer = undefined;
|
||||
}, timeout);
|
||||
|
||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||
console.log('Transformed posts fetched', arguments);
|
||||
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
|
||||
}).fail(function() {
|
||||
console.log('Posts _refreshTransformedPosts error', arguments);
|
||||
});
|
||||
},
|
||||
_insertSelectedPosts: function() {
|
||||
var that = this,
|
||||
@ -118,7 +133,7 @@ define([
|
||||
|
||||
if (data.posts.length === 0) return;
|
||||
|
||||
WordpressComponent.getTransformedPosts(data).done(function(posts) {
|
||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||
console.log('Available posts fetched', arguments);
|
||||
collection.add(posts, { at: index });
|
||||
}).fail(function() {
|
||||
@ -130,10 +145,14 @@ define([
|
||||
Module.PostsBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.postsBlock; },
|
||||
modelEvents: {},
|
||||
modelEvents: {}, // Forcefully disable all events
|
||||
regions: _.extend({
|
||||
postsRegion: '.mailpoet_posts_block_posts',
|
||||
}, base.BlockView.prototype.regions),
|
||||
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
|
||||
initialize: function() {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.toolsView = new Module.PostsBlockToolsView({ model: this.model });
|
||||
this.model.reply('blockView', this.notifyAboutSelf, this);
|
||||
},
|
||||
@ -142,6 +161,13 @@ define([
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
}
|
||||
this.trigger('showSettings');
|
||||
|
||||
var ContainerView = App.getBlockTypeView('container'),
|
||||
renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
};
|
||||
this.postsRegion.show(new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions }));
|
||||
},
|
||||
notifyAboutSelf: function() {
|
||||
return this;
|
||||
@ -197,8 +223,8 @@ define([
|
||||
},
|
||||
switchToDisplayOptions: function() {
|
||||
// Switch content view
|
||||
this.$('.mailpoet_settings_posts_selection').addClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_settings_posts_display_options').removeClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_settings_posts_selection').addClass('mailpoet_closed');
|
||||
this.$('.mailpoet_settings_posts_display_options').removeClass('mailpoet_closed');
|
||||
|
||||
// Switch controls
|
||||
this.$('.mailpoet_settings_posts_show_display_options').addClass('mailpoet_hidden');
|
||||
@ -206,8 +232,8 @@ define([
|
||||
},
|
||||
switchToPostSelection: function() {
|
||||
// Switch content view
|
||||
this.$('.mailpoet_settings_posts_display_options').addClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_settings_posts_selection').removeClass('mailpoet_hidden');
|
||||
this.$('.mailpoet_settings_posts_display_options').addClass('mailpoet_closed');
|
||||
this.$('.mailpoet_settings_posts_selection').removeClass('mailpoet_closed');
|
||||
|
||||
// Switch controls
|
||||
this.$('.mailpoet_settings_posts_show_post_selection').addClass('mailpoet_hidden');
|
||||
@ -216,6 +242,7 @@ define([
|
||||
insertPosts: function() {
|
||||
this.model.trigger('insertSelectedPosts');
|
||||
this.model.destroy();
|
||||
this.close();
|
||||
},
|
||||
});
|
||||
|
||||
@ -245,7 +272,7 @@ define([
|
||||
var that = this;
|
||||
|
||||
// Dynamically update available post types
|
||||
WordpressComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
|
||||
this.$('.mailpoet_posts_categories_and_tags').select2({
|
||||
multiple: true,
|
||||
@ -258,10 +285,10 @@ define([
|
||||
},
|
||||
transport: function(options, success, failure) {
|
||||
var taxonomies,
|
||||
promise = WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
promise = CommunicationComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
var promise = CommunicationComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
@ -307,11 +334,6 @@ define([
|
||||
},
|
||||
}).trigger( 'change' );
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
|
||||
// Force close select2 if it hasn't closed yet
|
||||
this.$('.mailpoet_posts_categories_and_tags').select2('close');
|
||||
},
|
||||
changeField: function(field, event) {
|
||||
this.model.set(field, jQuery(event.target).val());
|
||||
},
|
||||
@ -323,7 +345,7 @@ define([
|
||||
_.each(postTypes, function(type) {
|
||||
select.append(jQuery('<option>', {
|
||||
value: type.name,
|
||||
text: type.labels.singular_name,
|
||||
text: type.label,
|
||||
}));
|
||||
});
|
||||
select.val(selectedValue);
|
||||
|
@ -103,7 +103,8 @@ define([
|
||||
getTemplate: function() { return templates.socialBlock; },
|
||||
childViewContainer: '.mailpoet_social',
|
||||
modelEvents: {
|
||||
'change': 'render'
|
||||
'change': 'render',
|
||||
'delete': 'deleteBlock',
|
||||
},
|
||||
events: {
|
||||
"mouseover": "showTools",
|
||||
@ -145,6 +146,10 @@ define([
|
||||
arguments[0].collection = arguments[0].model.get('icons');
|
||||
Marionette.CompositeView.apply(this, arguments);
|
||||
},
|
||||
initialize: function() {
|
||||
this.on('dom:refresh', this.showBlock, this);
|
||||
this._isFirstRender = true;
|
||||
},
|
||||
// Determines which view type should be used for a child
|
||||
childView: SocialIconView,
|
||||
templateHelpers: function() {
|
||||
@ -170,12 +175,9 @@ define([
|
||||
_event.stopPropagation();
|
||||
},
|
||||
getDropFunc: function() {
|
||||
var that = this;
|
||||
return function() {
|
||||
var newModel = that.model.clone();
|
||||
//that.model.destroy();
|
||||
return newModel;
|
||||
};
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
_buildRegions: function(regions) {
|
||||
var that = this;
|
||||
@ -194,6 +196,34 @@ define([
|
||||
this.regionManager.destroy();
|
||||
_.extend(this, this._buildRegions(this.regions));
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
this.transitionIn();
|
||||
this._isFirstRender = false;
|
||||
}
|
||||
},
|
||||
deleteBlock: function() {
|
||||
this.transitionOut().done(function() {
|
||||
this.model.destroy();
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('mailpoet_block_transition_in');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('mailpoet_block_transition_out');
|
||||
},
|
||||
_transition: function(className) {
|
||||
var that = this,
|
||||
promise = jQuery.Deferred();
|
||||
|
||||
this.$el.addClass(className);
|
||||
this.$el.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd animationend', function() {
|
||||
that.$el.removeClass(className);
|
||||
promise.resolve();
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
|
||||
Module.SocialBlockToolsView = base.BlockToolsView.extend({
|
||||
|
@ -26,6 +26,8 @@ define([
|
||||
getTemplate: function() { return templates.textBlock; },
|
||||
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing
|
||||
initialize: function(options) {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.renderOptions = _.defaults(options.renderOptions || {}, {
|
||||
disableTextEditor: false,
|
||||
});
|
||||
|
@ -70,9 +70,10 @@ define([
|
||||
};
|
||||
|
||||
Module.previewNewsletter = function(options) {
|
||||
return Module._query({
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'preview',
|
||||
options: options,
|
||||
data: options || {},
|
||||
});
|
||||
};
|
||||
|
@ -44,10 +44,10 @@ define([
|
||||
};
|
||||
|
||||
Module.getBody = function() {
|
||||
return JSON.stringify({
|
||||
return {
|
||||
content: App._contentContainer.toJSON(),
|
||||
globalStyles: App.getGlobalStyles().toJSON(),
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Module.toJSON = function() {
|
||||
@ -73,8 +73,7 @@ define([
|
||||
});
|
||||
|
||||
App.on('start', function(options) {
|
||||
// TODO: Other newsletter information will be needed as well.
|
||||
var body = JSON.parse(options.newsletter.body);
|
||||
var body = options.newsletter.body;
|
||||
App._contentContainer = new (App.getBlockTypeModel('container'))(body.content, {parse: true});
|
||||
App._contentContainerView = new (App.getBlockTypeView('container'))({
|
||||
model: App._contentContainer,
|
||||
|
@ -6,8 +6,9 @@ define([
|
||||
'backbone.marionette',
|
||||
'jquery',
|
||||
'blob',
|
||||
'filesaver'
|
||||
], function(App, MailPoet, Notice, Backbone, Marionette, jQuery, Blob, FileSaver) {
|
||||
'filesaver',
|
||||
'html2canvas'
|
||||
], function(App, MailPoet, Notice, Backbone, Marionette, jQuery, Blob, FileSaver, html2canvas) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -46,26 +47,52 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
Module.getThumbnail = function(element, options) {
|
||||
return html2canvas(element, options || {});
|
||||
};
|
||||
|
||||
Module.saveTemplate = function(options) {
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'newsletterTemplates',
|
||||
action: 'save',
|
||||
data: _.extend(options || {}, {
|
||||
var that = this,
|
||||
promise = jQuery.Deferred();
|
||||
|
||||
promise.then(function(thumbnail) {
|
||||
var data = _.extend(options || {}, {
|
||||
thumbnail: thumbnail.toDataURL('image/jpeg'),
|
||||
body: App.getBody(),
|
||||
}),
|
||||
});
|
||||
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'newsletterTemplates',
|
||||
action: 'save',
|
||||
data: data,
|
||||
});
|
||||
});
|
||||
|
||||
Module.getThumbnail(
|
||||
jQuery('#mailpoet_editor_content > .mailpoet_block').get(0)
|
||||
).then(function(thumbnail) {
|
||||
promise.resolve(thumbnail);
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
Module.exportTemplate = function(options) {
|
||||
var data = _.extend(options || {}, {
|
||||
body: App.getBody(),
|
||||
});
|
||||
var blob = new Blob(
|
||||
[JSON.stringify(data)],
|
||||
{ type: 'application/json;charset=utf-8' }
|
||||
);
|
||||
var that = this;
|
||||
return Module.getThumbnail(
|
||||
jQuery('#mailpoet_editor_content > .mailpoet_block').get(0)
|
||||
).then(function(thumbnail) {
|
||||
var data = _.extend(options || {}, {
|
||||
thumbnail: thumbnail.toDataURL('image/jpeg'),
|
||||
body: App.getBody(),
|
||||
});
|
||||
var blob = new Blob(
|
||||
[JSON.stringify(data)],
|
||||
{ type: 'application/json;charset=utf-8' }
|
||||
);
|
||||
|
||||
FileSaver.saveAs(blob, 'template.json');
|
||||
FileSaver.saveAs(blob, 'template.json');
|
||||
});
|
||||
};
|
||||
|
||||
Module.SaveView = Marionette.LayoutView.extend({
|
||||
@ -119,20 +146,48 @@ define([
|
||||
},
|
||||
saveAsTemplate: function() {
|
||||
var templateName = this.$('.mailpoet_save_as_template_name').val(),
|
||||
templateDescription = this.$('.mailpoet_save_as_template_description').val();
|
||||
templateDescription = this.$('.mailpoet_save_as_template_description').val(),
|
||||
that = this;
|
||||
|
||||
console.log('Saving template with ', templateName, templateDescription);
|
||||
Module.saveTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
}).done(function() {
|
||||
console.log('Template saved', arguments);
|
||||
}).fail(function() {
|
||||
// TODO: Handle error messages
|
||||
console.log('Template save failed', arguments);
|
||||
});
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
}
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log('Saving template with ', templateName, templateDescription);
|
||||
Module.saveTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
}).done(function() {
|
||||
console.log('Template saved', arguments);
|
||||
MailPoet.Notice.success(
|
||||
App.getConfig().get('translations.templateSaved'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
}
|
||||
);
|
||||
}).fail(function() {
|
||||
console.log('Template save failed', arguments);
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateSaveFailed'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
}
|
||||
);
|
||||
});
|
||||
this.hideOptionContents();
|
||||
}
|
||||
|
||||
this.hideOptionContents();
|
||||
},
|
||||
toggleExportTemplate: function() {
|
||||
this.$('.mailpoet_export_template_container').toggleClass('mailpoet_hidden');
|
||||
@ -143,12 +198,23 @@ define([
|
||||
},
|
||||
exportTemplate: function() {
|
||||
var templateName = this.$('.mailpoet_export_template_name').val(),
|
||||
templateDescription = this.$('.mailpoet_export_template_description').val();
|
||||
templateDescription = this.$('.mailpoet_export_template_description').val(),
|
||||
that = this;
|
||||
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(App.getConfig().get('translations.templateNameMissing'));
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
}
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
MailPoet.Notice.error(App.getConfig().get('translations.templateDescriptionMissing'));
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log('Exporting template with ', templateName, templateDescription);
|
||||
Module.exportTemplate({
|
||||
|
@ -1,12 +1,13 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/components/communication',
|
||||
'backbone',
|
||||
'backbone.marionette',
|
||||
'backbone.supermodel',
|
||||
'underscore',
|
||||
'jquery',
|
||||
'sticky-kit'
|
||||
], function(App, Backbone, Marionette, SuperModel, _, jQuery, StickyKit) {
|
||||
], function(App, CommunicationComponent, Backbone, Marionette, SuperModel, _, jQuery, StickyKit) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -90,7 +91,6 @@ define([
|
||||
});
|
||||
},
|
||||
onDomRefresh: function() {
|
||||
var that = this;
|
||||
this.$el.parent().stick_in_parent({
|
||||
offset_top: 32,
|
||||
});
|
||||
@ -169,10 +169,8 @@ define([
|
||||
},
|
||||
initialize: function(options) {
|
||||
this.availableStyles = options.availableStyles;
|
||||
var that = this;
|
||||
},
|
||||
onRender: function() {
|
||||
var that = this;
|
||||
this.$('.mailpoet_color').spectrum({
|
||||
clickoutFiresChange: true,
|
||||
showInput: true,
|
||||
@ -229,7 +227,7 @@ define([
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
// TODO: Migrate logic to new AJAX format
|
||||
Wordpress.previewNewsletter(data).done(function(response) {
|
||||
CommunicationComponent.previewNewsletter(data).done(function(response) {
|
||||
if(response.success !== undefined && response.success === true) {
|
||||
MailPoet.Notice.success(App.getConfig().get('translations.testEmailSent'));
|
||||
} else if(response.error !== undefined) {
|
||||
|
@ -72,7 +72,7 @@ define([
|
||||
|
||||
App.getAvailableStyles = Module.getAvailableStyles;
|
||||
|
||||
var body = JSON.parse(options.newsletter.body);
|
||||
var body = options.newsletter.body;
|
||||
this.setGlobalStyles(body.globalStyles);
|
||||
});
|
||||
|
||||
|
@ -21,6 +21,10 @@ define(
|
||||
label: 'Subject',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status'
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists'
|
||||
@ -112,12 +116,101 @@ define(
|
||||
</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'trash'
|
||||
}
|
||||
];
|
||||
|
||||
var NewsletterList = React.createClass({
|
||||
renderItem: function(newsletter, actions) {
|
||||
pauseSending: function(item) {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'sendingQueue',
|
||||
action: 'pause',
|
||||
data: item.id
|
||||
}).done(function() {
|
||||
jQuery('#resume_'+item.id).show();
|
||||
jQuery('#pause_'+item.id).hide();
|
||||
});
|
||||
},
|
||||
resumeSending: function(item) {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'sendingQueue',
|
||||
action: 'resume',
|
||||
data: item.id
|
||||
}).done(function() {
|
||||
jQuery('#pause_'+item.id).show();
|
||||
jQuery('#resume_'+item.id).hide();
|
||||
});
|
||||
},
|
||||
renderStatus: function(item) {
|
||||
if(item.queue === null) {
|
||||
return (
|
||||
<span>Not sent yet.</span>
|
||||
);
|
||||
} else {
|
||||
var progressClasses = classNames(
|
||||
'mailpoet_progress',
|
||||
{ 'mailpoet_progress_complete': item.queue.status === 'completed'}
|
||||
);
|
||||
|
||||
// calculate percentage done
|
||||
var percentage = Math.round(
|
||||
(item.queue.count_processed * 100) / (item.queue.count_total)
|
||||
);
|
||||
|
||||
var label = false;
|
||||
|
||||
if(item.queue.status === 'completed') {
|
||||
label = (
|
||||
<span>
|
||||
Sent to {
|
||||
item.queue.count_processed - item.queue.count_failed
|
||||
} out of { item.queue.count_total }.
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
label = (
|
||||
<span>
|
||||
{ item.queue.count_processed } / { item.queue.count_total }
|
||||
|
||||
<a
|
||||
id={ 'resume_'+item.id }
|
||||
className="button"
|
||||
style={{ display: (item.queue.status === 'paused') ? 'inline-block': 'none' }}
|
||||
href="javascript:;"
|
||||
onClick={ this.resumeSending.bind(null, item) }
|
||||
>Resume</a>
|
||||
<a
|
||||
id={ 'pause_'+item.id }
|
||||
className="button mailpoet_pause"
|
||||
style={{ display: (item.queue.status === null) ? 'inline-block': 'none' }}
|
||||
href="javascript:;"
|
||||
onClick={ this.pauseSending.bind(null, item) }
|
||||
>Pause</a>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={ progressClasses }>
|
||||
<span
|
||||
className="mailpoet_progress_bar"
|
||||
style={ { width: percentage + "%"} }
|
||||
></span>
|
||||
<span className="mailpoet_progress_label">
|
||||
{ percentage + "%" }
|
||||
</span>
|
||||
</div>
|
||||
<p style={{ textAlign:'center' }}>
|
||||
{ label }
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
renderItem: function(newsletter, actions) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
@ -138,6 +231,9 @@ define(
|
||||
</strong>
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column" data-colname="Lists">
|
||||
{ this.renderStatus(newsletter) }
|
||||
</td>
|
||||
<td className="column" data-colname="Lists">
|
||||
{ segments }
|
||||
</td>
|
||||
@ -164,7 +260,8 @@ define(
|
||||
columns={columns}
|
||||
bulk_actions={ bulk_actions }
|
||||
item_actions={ item_actions }
|
||||
messages={ messages } />
|
||||
messages={ messages }
|
||||
auto_refresh={ true } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -37,6 +37,9 @@ define(
|
||||
multiple: true,
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
},
|
||||
validation: {
|
||||
'data-parsley-required': true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -45,17 +48,24 @@ define(
|
||||
tip: "Name & email of yourself or your company.",
|
||||
fields: [
|
||||
{
|
||||
name: 'from_name',
|
||||
name: 'sender_name',
|
||||
type: 'text',
|
||||
placeholder: 'John Doe',
|
||||
defaultValue: settings.from_name
|
||||
defaultValue: (settings.sender !== undefined) ? settings.sender.name : '',
|
||||
validation: {
|
||||
'data-parsley-required': true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'from_email',
|
||||
name: 'sender_address',
|
||||
type: 'text',
|
||||
placeholder: 'john.doe@email.com',
|
||||
defaultValue: settings.from_address
|
||||
},
|
||||
defaultValue: (settings.sender !== undefined) ? settings.sender.address : '',
|
||||
validation: {
|
||||
'data-parsley-required': true,
|
||||
'data-parsley-type': 'email'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -68,20 +78,25 @@ define(
|
||||
{
|
||||
name: 'reply_to_name',
|
||||
type: 'text',
|
||||
placeholder: 'John Doe'
|
||||
placeholder: 'John Doe',
|
||||
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '',
|
||||
},
|
||||
{
|
||||
name: 'reply_to_email',
|
||||
name: 'reply_to_address',
|
||||
type: 'text',
|
||||
placeholder: 'john.doe@email.com'
|
||||
placeholder: 'john.doe@email.com',
|
||||
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : ''
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
updated: function() {
|
||||
MailPoet.Notice.success('The newsletter has been updated!');
|
||||
onUpdate: function() {
|
||||
MailPoet.Notice.success('Newsletter successfully updated!');
|
||||
},
|
||||
onCreate: function() {
|
||||
MailPoet.Notice.success('Newsletter successfully added!');
|
||||
}
|
||||
};
|
||||
|
||||
@ -90,34 +105,43 @@ define(
|
||||
Router.History
|
||||
],
|
||||
handleSend: function() {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'send',
|
||||
data: {
|
||||
id: this.props.params.id,
|
||||
newsletter: jQuery('#mailpoet_newsletter').serializeObject(),
|
||||
segments: jQuery('#mailpoet_segments').val()
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response === true) {
|
||||
this.history.pushState(null, '/');
|
||||
if(jQuery('#mailpoet_newsletter').parsley().validate() === true) {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'sendingQueue',
|
||||
action: 'add',
|
||||
data: {
|
||||
newsletter_id: this.props.params.id,
|
||||
segments: jQuery('#mailpoet_segments').val()
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response.result === true) {
|
||||
this.history.pushState(null, '/');
|
||||
|
||||
MailPoet.Notice.success(
|
||||
'The newsletter has been sent!'
|
||||
);
|
||||
} else {
|
||||
if(response.errors) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.join("<br />")
|
||||
MailPoet.Notice.success(
|
||||
'The newsletter is being sent...'
|
||||
);
|
||||
} else {
|
||||
MailPoet.Notice.error(
|
||||
'An error occurred while trying to send. '+
|
||||
'<a href="?page=mailpoet-settings">Check your settings.</a>'
|
||||
);
|
||||
if(response.errors) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.join("<br />")
|
||||
);
|
||||
} else {
|
||||
MailPoet.Notice.error(
|
||||
'An error occurred while trying to send. '+
|
||||
'<a href="?page=mailpoet-settings">Check your settings.</a>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
componentDidMount: function() {
|
||||
if(this.isMounted()) {
|
||||
jQuery('#mailpoet_newsletter').parsley();
|
||||
}
|
||||
},
|
||||
isValid: function() {
|
||||
return (jQuery('#mailpoet_newsletter').parsley().validate());
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
@ -131,7 +155,8 @@ define(
|
||||
endpoint="newsletters"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages }>
|
||||
messages={ messages }
|
||||
isValid={ this.isValid }>
|
||||
|
||||
<p className="submit">
|
||||
<input
|
||||
|
@ -99,7 +99,7 @@ define(
|
||||
"MailPoet's Guide",
|
||||
description:
|
||||
"This is the standard template that comes with MailPoet.",
|
||||
readonly: true
|
||||
readonly: "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -150,6 +150,13 @@ define(
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
},
|
||||
handleShowTemplate: function(template) {
|
||||
MailPoet.Modal.popup({
|
||||
title: template.name,
|
||||
template: '<div class="mailpoet_boxes_preview" style="background-color: {{ body.globalStyles.body.backgroundColor }}"><img src="{{ thumbnail }}" /></div>',
|
||||
data: template,
|
||||
});
|
||||
},
|
||||
handleTemplateImport: function() {
|
||||
this.getTemplates();
|
||||
},
|
||||
@ -164,11 +171,22 @@ define(
|
||||
Delete
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
), thumbnail = '';
|
||||
|
||||
if (typeof template.thumbnail === 'string'
|
||||
&& template.thumbnail.length > 0) {
|
||||
thumbnail = (
|
||||
<a href="javascript:;" onClick={this.handleShowTemplate.bind(null, template)}>
|
||||
<img src={ template.thumbnail } />
|
||||
<div className="mailpoet_overlay"></div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<li key={ 'template-'+index }>
|
||||
<div className="mailpoet_thumbnail">
|
||||
{ thumbnail }
|
||||
</div>
|
||||
|
||||
<div className="mailpoet_description">
|
||||
@ -192,7 +210,7 @@ define(
|
||||
Preview
|
||||
</a>
|
||||
</div>
|
||||
{ (template.readonly) ? false : deleteLink }
|
||||
{ (template.readonly === "1") ? false : deleteLink }
|
||||
</li>
|
||||
);
|
||||
}.bind(this));
|
||||
|
@ -26,6 +26,7 @@ define(
|
||||
action: 'create',
|
||||
data: {
|
||||
type: type,
|
||||
subject: 'Draft newsletter',
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response.id !== undefined) {
|
||||
|
@ -49,6 +49,7 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
static: false,
|
||||
hideClose: false,
|
||||
id: null,
|
||||
positionAfter: false,
|
||||
scroll: false,
|
||||
timeout: 2000,
|
||||
onOpen: null,
|
||||
@ -69,7 +70,16 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
this.element.removeAttr('id');
|
||||
|
||||
// insert notice after its parent
|
||||
jQuery('#mailpoet_notice_'+this.options.type).after(this.element);
|
||||
var positionAfter;
|
||||
if (typeof this.options.positionAfter === 'object') {
|
||||
positionAfter = this.options.positionAfter;
|
||||
} else if (typeof this.options.positionAfter === 'string') {
|
||||
positionAfter = jQuery(this.options.positionAfter);
|
||||
} else {
|
||||
positionAfter = jQuery('#mailpoet_notice_'+this.options.type);
|
||||
}
|
||||
console.log('positionAfter', typeof this.options.positionAfter);
|
||||
positionAfter.after(this.element);
|
||||
|
||||
// setup onClose callback
|
||||
var onClose = null;
|
||||
|
@ -20,7 +20,10 @@ function(
|
||||
$('form.mailpoet_form').each(function() {
|
||||
var form = $(this);
|
||||
|
||||
form.parsley().on('form:submit', function(parsley) {
|
||||
form.parsley({
|
||||
errorsWrapper: '<p></p>',
|
||||
errorTemplate: '<span></span>'
|
||||
}).on('form:submit', function(parsley) {
|
||||
|
||||
var data = form.serializeObject() || {};
|
||||
|
||||
|
@ -42,11 +42,7 @@ define(
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Segment <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
Segment
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
|
@ -121,6 +121,32 @@ const item_actions = [
|
||||
);
|
||||
refresh();
|
||||
});
|
||||
},
|
||||
display: function(segment) {
|
||||
return (segment.type !== 'wp_users');
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'synchronize_segment',
|
||||
label: 'Update',
|
||||
className: 'update',
|
||||
onClick: function(item, refresh) {
|
||||
MailPoet.Modal.loading(true);
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'segments',
|
||||
action: 'synchronize'
|
||||
}).done(function(response) {
|
||||
MailPoet.Modal.loading(false);
|
||||
if(response === true) {
|
||||
MailPoet.Notice.success(
|
||||
('List "%$1s" has been synchronized.').replace('%$1s', item.name)
|
||||
);
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
display: function(segment) {
|
||||
return (segment.type === 'wp_users');
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -130,15 +156,16 @@ const item_actions = [
|
||||
<a href={ item.subscribers_url }>View subscribers</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'trash',
|
||||
display: function(segment) {
|
||||
return (segment.type !== 'wp_users');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
|
||||
const SegmentList = React.createClass({
|
||||
@ -148,7 +175,6 @@ const SegmentList = React.createClass({
|
||||
'column-primary',
|
||||
'has-row-actions'
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<td className={ rowClasses }>
|
||||
|
@ -15,10 +15,10 @@ define(
|
||||
|
||||
MailPoet.Router = new (Backbone.Router.extend({
|
||||
routes: {
|
||||
'mta(/:method)': 'sendingMethod',
|
||||
'mta(/:group)': 'sendingMethodGroup',
|
||||
'(:tab)': 'tabs',
|
||||
},
|
||||
sendingMethod: function(method) {
|
||||
sendingMethodGroup: function(group) {
|
||||
// display mta tab
|
||||
this.tabs('mta');
|
||||
|
||||
@ -30,13 +30,13 @@ define(
|
||||
// hide "save settings" button
|
||||
jQuery('.mailpoet_settings_submit').hide();
|
||||
|
||||
if(method === null) {
|
||||
if(group === null) {
|
||||
// show sending methods
|
||||
jQuery('.mailpoet_sending_methods').fadeIn();
|
||||
} else {
|
||||
// hide DKIM option when using MailPoet's API
|
||||
jQuery('#mailpoet_mta_dkim')[
|
||||
(method === 'mailpoet')
|
||||
(group === 'mailpoet')
|
||||
? 'hide'
|
||||
: 'show'
|
||||
]();
|
||||
@ -45,7 +45,7 @@ define(
|
||||
jQuery('.mailpoet_sending_methods').hide();
|
||||
|
||||
// display selected sending method's settings
|
||||
jQuery('.mailpoet_sending_method[data-method="'+ method +'"]').show();
|
||||
jQuery('.mailpoet_sending_method[data-group="'+ group +'"]').show();
|
||||
jQuery('#mailpoet_sending_method_setup').fadeIn();
|
||||
}
|
||||
},
|
||||
|
@ -70,11 +70,7 @@ define(
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscriber <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
Subscriber
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
|
@ -20,6 +20,7 @@ define(
|
||||
return;
|
||||
}
|
||||
jQuery(document).ready(function () {
|
||||
jQuery('input[name="select_method"]').attr('checked', false);
|
||||
// configure router
|
||||
router = new (Backbone.Router.extend({
|
||||
routes: {
|
||||
@ -299,11 +300,11 @@ define(
|
||||
var test,
|
||||
cleanEmail =
|
||||
email
|
||||
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
||||
// right trim non-printable characters (e.g., "email@email.com<6F>")
|
||||
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
||||
// right trim non-printable characters (e.g., "email@email.com<6F>")
|
||||
.replace(/^["';.,\s]+|[^\x20-\x7E]+$|["';.,_\s]+$/g, '')
|
||||
// remove spaces (e.g., "email @ email . com")
|
||||
// remove urlencoded characters
|
||||
// remove spaces (e.g., "email @ email . com")
|
||||
// remove urlencoded characters
|
||||
.replace(/\s+|%\d+|,+/g, '')
|
||||
.toLowerCase();
|
||||
|
||||
@ -1000,7 +1001,6 @@ define(
|
||||
}
|
||||
|
||||
function toggleNextStepButton(condition) {
|
||||
console.log(condition);
|
||||
var disabled = 'button-disabled';
|
||||
if (condition === 'on') {
|
||||
nextStepButton.removeClass(disabled);
|
@ -103,7 +103,9 @@ const bulk_actions = [
|
||||
id: 'move_to_segment',
|
||||
endpoint: 'segments',
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
return !!(
|
||||
!segment.deleted_at && segment.type === 'default'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -132,7 +134,9 @@ const bulk_actions = [
|
||||
id: 'add_to_segment',
|
||||
endpoint: 'segments',
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
return !!(
|
||||
!segment.deleted_at && segment.type === 'default'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -159,7 +163,12 @@ const bulk_actions = [
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'remove_from_segment',
|
||||
endpoint: 'segments'
|
||||
endpoint: 'segments',
|
||||
filter: function(segment) {
|
||||
return !!(
|
||||
segment.type === 'default'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -206,6 +215,21 @@ const bulk_actions = [
|
||||
}
|
||||
];
|
||||
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
link: function(item) {
|
||||
return (
|
||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'trash'
|
||||
}
|
||||
];
|
||||
|
||||
const SubscriberList = React.createClass({
|
||||
renderItem: function(subscriber, actions) {
|
||||
let row_classes = classNames(
|
||||
@ -295,6 +319,7 @@ const SubscriberList = React.createClass({
|
||||
onRenderItem={ this.renderItem }
|
||||
columns={ columns }
|
||||
bulk_actions={ bulk_actions }
|
||||
item_actions={ item_actions }
|
||||
messages={ messages }
|
||||
onGetItems={ this.onGetItems }
|
||||
/>
|
||||
|
264
assets/js/src/vendor_static/jquery.sticky-kit.js
Normal file
@ -0,0 +1,264 @@
|
||||
// Generated by CoffeeScript 1.9.2
|
||||
|
||||
/**
|
||||
@license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var $, win;
|
||||
|
||||
$ = this.jQuery || window.jQuery;
|
||||
|
||||
win = $(window);
|
||||
|
||||
$.fn.stick_in_parent = function(opts) {
|
||||
var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming;
|
||||
if (offset_top == null) {
|
||||
offset_top = 0;
|
||||
}
|
||||
if (parent_selector == null) {
|
||||
parent_selector = void 0;
|
||||
}
|
||||
if (inner_scrolling == null) {
|
||||
inner_scrolling = true;
|
||||
}
|
||||
if (sticky_class == null) {
|
||||
sticky_class = "is_stuck";
|
||||
}
|
||||
doc = $(document);
|
||||
if (enable_bottoming == null) {
|
||||
enable_bottoming = true;
|
||||
}
|
||||
outer_width = function(el) {
|
||||
var _el, computed, w;
|
||||
if (window.getComputedStyle) {
|
||||
_el = el[0];
|
||||
computed = window.getComputedStyle(el[0]);
|
||||
w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
|
||||
if (computed.getPropertyValue("box-sizing") !== "border-box") {
|
||||
w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
|
||||
}
|
||||
return w;
|
||||
} else {
|
||||
return el.outerWidth(true);
|
||||
}
|
||||
};
|
||||
fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
|
||||
var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
|
||||
if (elm.data("sticky_kit")) {
|
||||
return;
|
||||
}
|
||||
elm.data("sticky_kit", true);
|
||||
last_scroll_height = doc.height();
|
||||
parent = elm.parent();
|
||||
if (parent_selector != null) {
|
||||
parent = parent.closest(parent_selector);
|
||||
}
|
||||
if (!parent.length) {
|
||||
throw "failed to find stick parent";
|
||||
}
|
||||
fixed = false;
|
||||
bottomed = false;
|
||||
spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
|
||||
if (spacer) {
|
||||
spacer.css('position', elm.css('position'));
|
||||
}
|
||||
recalc = function() {
|
||||
var border_top, padding_top, restore;
|
||||
if (detached) {
|
||||
return;
|
||||
}
|
||||
last_scroll_height = doc.height();
|
||||
border_top = parseInt(parent.css("border-top-width"), 10);
|
||||
padding_top = parseInt(parent.css("padding-top"), 10);
|
||||
padding_bottom = parseInt(parent.css("padding-bottom"), 10);
|
||||
parent_top = parent.offset().top + border_top + padding_top;
|
||||
parent_height = parent.height();
|
||||
if (fixed) {
|
||||
fixed = false;
|
||||
bottomed = false;
|
||||
if (manual_spacer == null) {
|
||||
elm.insertAfter(spacer);
|
||||
spacer.detach();
|
||||
}
|
||||
elm.css({
|
||||
position: "",
|
||||
top: "",
|
||||
width: "",
|
||||
bottom: ""
|
||||
}).removeClass(sticky_class);
|
||||
restore = true;
|
||||
}
|
||||
top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
|
||||
height = elm.outerHeight(true);
|
||||
el_float = elm.css("float");
|
||||
if (spacer) {
|
||||
spacer.css({
|
||||
width: outer_width(elm),
|
||||
height: height,
|
||||
display: elm.css("display"),
|
||||
"vertical-align": elm.css("vertical-align"),
|
||||
"float": el_float
|
||||
});
|
||||
}
|
||||
if (restore) {
|
||||
return tick();
|
||||
}
|
||||
};
|
||||
recalc();
|
||||
|
||||
last_pos = void 0;
|
||||
offset = offset_top;
|
||||
recalc_counter = recalc_every;
|
||||
tick = function() {
|
||||
var css, delta, recalced, scroll, will_bottom, win_height;
|
||||
if (detached) {
|
||||
return;
|
||||
}
|
||||
recalced = false;
|
||||
if (recalc_counter != null) {
|
||||
recalc_counter -= 1;
|
||||
if (recalc_counter <= 0) {
|
||||
recalc_counter = recalc_every;
|
||||
recalc();
|
||||
recalced = true;
|
||||
}
|
||||
}
|
||||
if (!recalced && doc.height() !== last_scroll_height) {
|
||||
recalc();
|
||||
recalced = true;
|
||||
}
|
||||
scroll = win.scrollTop();
|
||||
if (last_pos != null) {
|
||||
delta = scroll - last_pos;
|
||||
}
|
||||
last_pos = scroll;
|
||||
if (fixed) {
|
||||
if (enable_bottoming) {
|
||||
will_bottom = scroll + height + offset > parent_height + parent_top;
|
||||
if (bottomed && !will_bottom) {
|
||||
bottomed = false;
|
||||
elm.css({
|
||||
position: "fixed",
|
||||
bottom: "",
|
||||
top: offset
|
||||
}).trigger("sticky_kit:unbottom");
|
||||
}
|
||||
}
|
||||
if (scroll < top) {
|
||||
fixed = false;
|
||||
offset = offset_top;
|
||||
if (manual_spacer == null) {
|
||||
if (el_float === "left" || el_float === "right") {
|
||||
elm.insertAfter(spacer);
|
||||
}
|
||||
spacer.detach();
|
||||
}
|
||||
css = {
|
||||
position: "",
|
||||
width: "",
|
||||
top: ""
|
||||
};
|
||||
elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
|
||||
}
|
||||
if (inner_scrolling) {
|
||||
win_height = win.height();
|
||||
if (height + offset_top > win_height) {
|
||||
if (!bottomed) {
|
||||
offset -= delta;
|
||||
offset = Math.max(win_height - height, offset);
|
||||
offset = Math.min(offset_top, offset);
|
||||
if (fixed) {
|
||||
elm.css({
|
||||
top: offset + "px"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (scroll > top) {
|
||||
fixed = true;
|
||||
css = {
|
||||
position: "fixed",
|
||||
top: offset
|
||||
};
|
||||
css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
|
||||
elm.css(css).addClass(sticky_class);
|
||||
if (manual_spacer == null) {
|
||||
elm.after(spacer);
|
||||
if (el_float === "left" || el_float === "right") {
|
||||
spacer.append(elm);
|
||||
}
|
||||
}
|
||||
elm.trigger("sticky_kit:stick");
|
||||
}
|
||||
}
|
||||
if (fixed && enable_bottoming) {
|
||||
if (will_bottom == null) {
|
||||
will_bottom = scroll + height + offset > parent_height + parent_top;
|
||||
}
|
||||
if (!bottomed && will_bottom) {
|
||||
bottomed = true;
|
||||
if (parent.css("position") === "static") {
|
||||
parent.css({
|
||||
position: "relative"
|
||||
});
|
||||
}
|
||||
return elm.css({
|
||||
position: "absolute",
|
||||
bottom: padding_bottom,
|
||||
top: "auto"
|
||||
}).trigger("sticky_kit:bottom");
|
||||
}
|
||||
}
|
||||
};
|
||||
recalc_and_tick = function() {
|
||||
recalc();
|
||||
return tick();
|
||||
};
|
||||
detach = function() {
|
||||
detached = true;
|
||||
win.off("touchmove", tick);
|
||||
win.off("scroll", tick);
|
||||
win.off("resize", recalc_and_tick);
|
||||
$(document.body).off("sticky_kit:recalc", recalc_and_tick);
|
||||
elm.off("sticky_kit:detach", detach);
|
||||
elm.removeData("sticky_kit");
|
||||
elm.css({
|
||||
position: "",
|
||||
bottom: "",
|
||||
top: "",
|
||||
width: ""
|
||||
});
|
||||
parent.position("position", "");
|
||||
if (fixed) {
|
||||
if (manual_spacer == null) {
|
||||
if (el_float === "left" || el_float === "right") {
|
||||
elm.insertAfter(spacer);
|
||||
}
|
||||
spacer.remove();
|
||||
}
|
||||
return elm.removeClass(sticky_class);
|
||||
}
|
||||
};
|
||||
win.on("touchmove", tick);
|
||||
win.on("scroll", tick);
|
||||
win.on("resize", recalc_and_tick);
|
||||
$(document.body).on("sticky_kit:recalc", recalc_and_tick);
|
||||
elm.on("sticky_kit:detach", detach);
|
||||
return setTimeout(tick, 0);
|
||||
};
|
||||
for (i = 0, len = this.length; i < len; i++) {
|
||||
elm = this[i];
|
||||
fn($(elm));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
43
build
@ -1,43 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Remove previous build.
|
||||
rm wysija-newsletters.zip;
|
||||
|
||||
# Create temp dir.
|
||||
mkdir wysija-newsletters;
|
||||
|
||||
# Production assets.
|
||||
./do compile:all;
|
||||
|
||||
# Production libraries.
|
||||
rm -rf vendor;
|
||||
rm -rf node_modules;
|
||||
rm composer.lock;
|
||||
./composer.phar install --no-dev;
|
||||
|
||||
# Copy release folders.
|
||||
cp -Rf lang wysija-newsletters;
|
||||
cp -RfL assets wysija-newsletters;
|
||||
cp -Rf lib wysija-newsletters;
|
||||
cp -Rf vendor wysija-newsletters;
|
||||
cp -Rf views wysija-newsletters;
|
||||
rm -Rf wysija-newsletters/assets/css/src;
|
||||
rm -Rf wysija-newsletters/assets/js/src;
|
||||
|
||||
# Copy release files.
|
||||
cp LICENSE wysija-newsletters;
|
||||
cp index.php wysija-newsletters;
|
||||
cp mailpoet.php wysija-newsletters;
|
||||
cp readme.txt wysija-newsletters;
|
||||
cp uninstall.php wysija-newsletters;
|
||||
|
||||
# Zip final release.
|
||||
zip -r wysija-newsletters.zip wysija-newsletters;
|
||||
|
||||
# Remove temp dir.
|
||||
rm -rf wysija-newsletters;
|
||||
|
||||
# Reinstall dev dependencies.
|
||||
rm composer.lock;
|
||||
./composer.phar install;
|
||||
./do install;
|
42
build.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
plugin_name='mailpoet'
|
||||
|
||||
# Remove previous build.
|
||||
rm $plugin_name.zip
|
||||
|
||||
# Create temp dir.
|
||||
mkdir $plugin_name
|
||||
|
||||
# Production assets.
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
./do compile:all
|
||||
|
||||
# Production libraries.
|
||||
./composer.phar install --no-dev
|
||||
|
||||
# Copy release folders.
|
||||
cp -Rf lang $plugin_name
|
||||
cp -RfL assets $plugin_name
|
||||
cp -Rf lib $plugin_name
|
||||
cp -Rf vendor $plugin_name
|
||||
cp -Rf views $plugin_name
|
||||
rm -Rf $plugin_name/assets/css/src
|
||||
rm -Rf $plugin_name/assets/js/src
|
||||
|
||||
# Copy release files.
|
||||
cp LICENSE $plugin_name
|
||||
cp index.php $plugin_name
|
||||
cp $plugin_name.php $plugin_name
|
||||
cp readme.txt $plugin_name
|
||||
cp uninstall.php $plugin_name
|
||||
|
||||
# Zip final release.
|
||||
zip -r $plugin_name.zip $plugin_name
|
||||
|
||||
# Remove temp dir.
|
||||
rm -rf $plugin_name
|
||||
|
||||
# Reinstall dev dependencies.
|
||||
./composer.phar install
|
@ -8,7 +8,9 @@
|
||||
"tburry/pquery": "*",
|
||||
"j4mie/paris": "1.5.4",
|
||||
"swiftmailer/swiftmailer": "^5.4",
|
||||
"phpseclib/phpseclib": "*"
|
||||
"phpseclib/phpseclib": "*",
|
||||
"mtdowling/cron-expression": "^1.0",
|
||||
"nesbot/carbon": "^1.21"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/codeception": "*",
|
||||
|
468
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": "7d7ef94b6e40ac2b2d594e5832d7e16d",
|
||||
"content-hash": "2e70c335edf7429df0794ebf49e2f210",
|
||||
"hash": "4720dce62e4a6a7bf4d3ba3944b9c2b9",
|
||||
"content-hash": "748470f0803c52a798a4ecd1bb8a93b9",
|
||||
"packages": [
|
||||
{
|
||||
"name": "cerdic/css-tidy",
|
||||
@ -158,6 +158,97 @@
|
||||
],
|
||||
"time": "2014-09-23 10:49:36"
|
||||
},
|
||||
{
|
||||
"name": "mtdowling/cron-expression",
|
||||
"version": "v1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mtdowling/cron-expression.git",
|
||||
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412",
|
||||
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Cron": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due",
|
||||
"keywords": [
|
||||
"cron",
|
||||
"schedule"
|
||||
],
|
||||
"time": "2015-01-11 23:07:46"
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
"version": "1.21.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||
"reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7b08ec6f75791e130012f206e3f7b0e76e18e3d7",
|
||||
"reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"symfony/translation": "~2.6|~3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0|~5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Carbon\\": "src/Carbon/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brian Nesbitt",
|
||||
"email": "brian@nesbot.com",
|
||||
"homepage": "http://nesbot.com"
|
||||
}
|
||||
],
|
||||
"description": "A simple API extension for DateTime.",
|
||||
"homepage": "http://carbon.nesbot.com",
|
||||
"keywords": [
|
||||
"date",
|
||||
"datetime",
|
||||
"time"
|
||||
],
|
||||
"time": "2015-11-04 20:07:17"
|
||||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v5.2.14",
|
||||
@ -403,6 +494,69 @@
|
||||
],
|
||||
"time": "2015-06-06 14:19:39"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/e4ecb9c3ba1304eaf24de15c2d7a428101c1982f",
|
||||
"reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<2.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.7",
|
||||
"symfony/intl": "~2.4",
|
||||
"symfony/yaml": "~2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "To use logging capability in translator",
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Translation\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-18 13:41:01"
|
||||
},
|
||||
{
|
||||
"name": "tburry/pquery",
|
||||
"version": "v1.1.0",
|
||||
@ -783,16 +937,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "6.1.0",
|
||||
"version": "6.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81"
|
||||
"reference": "c6851d6e48f63b69357cbfa55bca116448140e0c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/66fd14b4d0b8f2389eaf37c5458608c7cb793a81",
|
||||
"reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/c6851d6e48f63b69357cbfa55bca116448140e0c",
|
||||
"reference": "c6851d6e48f63b69357cbfa55bca116448140e0c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -841,7 +995,7 @@
|
||||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"time": "2015-09-08 17:36:26"
|
||||
"time": "2015-11-23 00:47:50"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
@ -1961,16 +2115,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "07d664a052572ccc28eb2ab7dbbe82155b1ad367"
|
||||
"reference": "bd28847ea2193916074c7b11d4fdd78570049694"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/07d664a052572ccc28eb2ab7dbbe82155b1ad367",
|
||||
"reference": "07d664a052572ccc28eb2ab7dbbe82155b1ad367",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/bd28847ea2193916074c7b11d4fdd78570049694",
|
||||
"reference": "bd28847ea2193916074c7b11d4fdd78570049694",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1993,7 +2147,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\BrowserKit\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2011,20 +2168,20 @@
|
||||
],
|
||||
"description": "Symfony BrowserKit Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-23 14:47:27"
|
||||
"time": "2015-11-02 20:20:53"
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "831f88908b51b9ce945f5e6f402931d1ac544423"
|
||||
"reference": "61973327bfb054f6f470de7be033a28b76c1dc20"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/831f88908b51b9ce945f5e6f402931d1ac544423",
|
||||
"reference": "831f88908b51b9ce945f5e6f402931d1ac544423",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/61973327bfb054f6f470de7be033a28b76c1dc20",
|
||||
"reference": "61973327bfb054f6f470de7be033a28b76c1dc20",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2040,7 +2197,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Config\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2058,20 +2218,20 @@
|
||||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-11-02 20:20:53"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "5efd632294c8320ea52492db22292ff853a43766"
|
||||
"reference": "16bb1cb86df43c90931df65f529e7ebd79636750"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/5efd632294c8320ea52492db22292ff853a43766",
|
||||
"reference": "5efd632294c8320ea52492db22292ff853a43766",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/16bb1cb86df43c90931df65f529e7ebd79636750",
|
||||
"reference": "16bb1cb86df43c90931df65f529e7ebd79636750",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2096,7 +2256,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Console\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2114,20 +2277,20 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-20 14:38:46"
|
||||
"time": "2015-11-18 09:54:26"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "e1b865b26be4a56d22a8dee398375044a80c865b"
|
||||
"reference": "abb47717fb88aebd9437da2fc8bb01a50a36679f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/e1b865b26be4a56d22a8dee398375044a80c865b",
|
||||
"reference": "e1b865b26be4a56d22a8dee398375044a80c865b",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/abb47717fb88aebd9437da2fc8bb01a50a36679f",
|
||||
"reference": "abb47717fb88aebd9437da2fc8bb01a50a36679f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2142,7 +2305,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\CssSelector\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2164,20 +2330,20 @@
|
||||
],
|
||||
"description": "Symfony CssSelector Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-10-30 20:10:21"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "5fef7d8b80d8f9992df99d8ee283f420484c9612"
|
||||
"reference": "b33593cbfe1d81b50d48353f338aca76a08658d8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5fef7d8b80d8f9992df99d8ee283f420484c9612",
|
||||
"reference": "5fef7d8b80d8f9992df99d8ee283f420484c9612",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b33593cbfe1d81b50d48353f338aca76a08658d8",
|
||||
"reference": "b33593cbfe1d81b50d48353f338aca76a08658d8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2198,7 +2364,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\DomCrawler\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2216,20 +2385,20 @@
|
||||
],
|
||||
"description": "Symfony DomCrawler Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-11-02 20:20:53"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8"
|
||||
"reference": "7e2f9c31645680026c2372edf66f863fc7757af5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87a5db5ea887763fa3a31a5471b512ff1596d9b8",
|
||||
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7e2f9c31645680026c2372edf66f863fc7757af5",
|
||||
"reference": "7e2f9c31645680026c2372edf66f863fc7757af5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2255,7 +2424,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\EventDispatcher\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2273,20 +2445,20 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-10-30 20:10:21"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "56fd6df73be859323ff97418d97edc1d756df6df"
|
||||
"reference": "8e173509d7fdbbba3cf34d6d072f2073c0210c1d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/56fd6df73be859323ff97418d97edc1d756df6df",
|
||||
"reference": "56fd6df73be859323ff97418d97edc1d756df6df",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/8e173509d7fdbbba3cf34d6d072f2073c0210c1d",
|
||||
"reference": "8e173509d7fdbbba3cf34d6d072f2073c0210c1d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2301,7 +2473,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Filesystem\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2319,20 +2494,20 @@
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-18 20:23:18"
|
||||
"time": "2015-11-18 13:41:01"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "2ffb4e9598db3c48eb6d0ae73b04bbf09280c59d"
|
||||
"reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/2ffb4e9598db3c48eb6d0ae73b04bbf09280c59d",
|
||||
"reference": "2ffb4e9598db3c48eb6d0ae73b04bbf09280c59d",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/a06a0c0ff7db3736a50d530c908cca547bf13da9",
|
||||
"reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2347,7 +2522,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Finder\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2365,20 +2543,20 @@
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-10-30 20:10:21"
|
||||
},
|
||||
{
|
||||
"name": "symfony/form",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/form.git",
|
||||
"reference": "b93fcb816bec2b8470ea9d54e4b6658b2461b83c"
|
||||
"reference": "0a2c2ce0d4bd3c50bb0ae4e75ac27e5274c25e81"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/form/zipball/b93fcb816bec2b8470ea9d54e4b6658b2461b83c",
|
||||
"reference": "b93fcb816bec2b8470ea9d54e4b6658b2461b83c",
|
||||
"url": "https://api.github.com/repos/symfony/form/zipball/0a2c2ce0d4bd3c50bb0ae4e75ac27e5274c25e81",
|
||||
"reference": "0a2c2ce0d4bd3c50bb0ae4e75ac27e5274c25e81",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2416,7 +2594,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Form\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2434,20 +2615,20 @@
|
||||
],
|
||||
"description": "Symfony Form Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-27 15:38:06"
|
||||
"time": "2015-11-23 10:34:14"
|
||||
},
|
||||
{
|
||||
"name": "symfony/intl",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/intl.git",
|
||||
"reference": "330f52a996749eb6a2fdc1506c7a4868e070d678"
|
||||
"reference": "6c6c3aa69f68aff72e48a9bfc11f24680e23eb2d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/intl/zipball/330f52a996749eb6a2fdc1506c7a4868e070d678",
|
||||
"reference": "330f52a996749eb6a2fdc1506c7a4868e070d678",
|
||||
"url": "https://api.github.com/repos/symfony/intl/zipball/6c6c3aa69f68aff72e48a9bfc11f24680e23eb2d",
|
||||
"reference": "6c6c3aa69f68aff72e48a9bfc11f24680e23eb2d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2474,6 +2655,9 @@
|
||||
],
|
||||
"files": [
|
||||
"Resources/stubs/functions.php"
|
||||
],
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@ -2508,20 +2692,20 @@
|
||||
"l10n",
|
||||
"localization"
|
||||
],
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-11-18 13:41:01"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/options-resolver.git",
|
||||
"reference": "85fd10e551677d3c9a4632def78b8ec4670b247d"
|
||||
"reference": "d6b7d3452b4cfff89b642993e02fea7cc254530e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/85fd10e551677d3c9a4632def78b8ec4670b247d",
|
||||
"reference": "85fd10e551677d3c9a4632def78b8ec4670b247d",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/d6b7d3452b4cfff89b642993e02fea7cc254530e",
|
||||
"reference": "d6b7d3452b4cfff89b642993e02fea7cc254530e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2536,7 +2720,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\OptionsResolver\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2559,20 +2746,20 @@
|
||||
"configuration",
|
||||
"options"
|
||||
],
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-11-18 13:41:01"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "4a959dd4e19c2c5d7512689413921e0a74386ec7"
|
||||
"reference": "f6290983c8725d0afa29bdc3e5295879de3e58f5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/4a959dd4e19c2c5d7512689413921e0a74386ec7",
|
||||
"reference": "4a959dd4e19c2c5d7512689413921e0a74386ec7",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/f6290983c8725d0afa29bdc3e5295879de3e58f5",
|
||||
"reference": "f6290983c8725d0afa29bdc3e5295879de3e58f5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2587,7 +2774,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Process\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2605,20 +2795,20 @@
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-23 14:47:27"
|
||||
"time": "2015-11-19 16:11:24"
|
||||
},
|
||||
{
|
||||
"name": "symfony/property-access",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/property-access.git",
|
||||
"reference": "368b784738fa932e6d86866038312b03e073a824"
|
||||
"reference": "49d76463a54d8b3005fa58f3b8df41d0ae206eaa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/property-access/zipball/368b784738fa932e6d86866038312b03e073a824",
|
||||
"reference": "368b784738fa932e6d86866038312b03e073a824",
|
||||
"url": "https://api.github.com/repos/symfony/property-access/zipball/49d76463a54d8b3005fa58f3b8df41d0ae206eaa",
|
||||
"reference": "49d76463a54d8b3005fa58f3b8df41d0ae206eaa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2633,7 +2823,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\PropertyAccess\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2662,20 +2855,20 @@
|
||||
"property path",
|
||||
"reflection"
|
||||
],
|
||||
"time": "2015-10-23 14:47:27"
|
||||
"time": "2015-11-18 13:41:01"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/routing.git",
|
||||
"reference": "f353e1f588679c3ec987624e6c617646bd01ba38"
|
||||
"reference": "7450f6196711b124fb8b04a12286d01a0401ddfe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/f353e1f588679c3ec987624e6c617646bd01ba38",
|
||||
"reference": "f353e1f588679c3ec987624e6c617646bd01ba38",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/7450f6196711b124fb8b04a12286d01a0401ddfe",
|
||||
"reference": "7450f6196711b124fb8b04a12286d01a0401ddfe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2708,7 +2901,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Routing\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2732,85 +2928,25 @@
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2015-10-27 15:38:06"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "6ccd9289ec1c71d01a49d83480de3b5293ce30c8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/6ccd9289ec1c71d01a49d83480de3b5293ce30c8",
|
||||
"reference": "6ccd9289ec1c71d01a49d83480de3b5293ce30c8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<2.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.7",
|
||||
"symfony/intl": "~2.4",
|
||||
"symfony/yaml": "~2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "To use logging capability in translator",
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Translation\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-27 15:38:06"
|
||||
"time": "2015-11-18 13:41:01"
|
||||
},
|
||||
{
|
||||
"name": "symfony/twig-bridge",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/twig-bridge.git",
|
||||
"reference": "3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f"
|
||||
"reference": "7c491aa71af4320747f81ab0140eac4f0ad5509b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f",
|
||||
"reference": "3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/7c491aa71af4320747f81ab0140eac4f0ad5509b",
|
||||
"reference": "7c491aa71af4320747f81ab0140eac4f0ad5509b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"twig/twig": "~1.20|~2.0"
|
||||
"twig/twig": "~1.23|~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/asset": "~2.7",
|
||||
@ -2852,7 +2988,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Bridge\\Twig\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2870,20 +3009,20 @@
|
||||
],
|
||||
"description": "Symfony Twig Bridge",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-11-02 20:25:31"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d"
|
||||
"reference": "4cfcd7a9fceba662b3c036b7d9a91f6197af046c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/eca9019c88fbe250164affd107bc8057771f3f4d",
|
||||
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/4cfcd7a9fceba662b3c036b7d9a91f6197af046c",
|
||||
"reference": "4cfcd7a9fceba662b3c036b7d9a91f6197af046c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2898,7 +3037,10 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -2916,7 +3058,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-11-18 13:41:01"
|
||||
},
|
||||
{
|
||||
"name": "twig/extensions",
|
||||
|
@ -23,4 +23,9 @@ class Activator {
|
||||
$populator = new Populator();
|
||||
$populator->up();
|
||||
}
|
||||
|
||||
function deactivate() {
|
||||
$migrator = new Migrator();
|
||||
$migrator->down();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ class Analytics {
|
||||
}
|
||||
|
||||
function init() {
|
||||
add_action('admin_enqueue_scripts', array($this, 'setupAdminDependencies'));
|
||||
// review: this creates a fatal error when mailpoet tables are dropped.
|
||||
//add_action('admin_enqueue_scripts', array($this, 'setupAdminDependencies'));
|
||||
}
|
||||
|
||||
function setupAdminDependencies() {
|
||||
|
61
lib/Config/Changelog.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Models\Setting;
|
||||
|
||||
class Changelog {
|
||||
function init() {
|
||||
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
|
||||
|
||||
// don't run any check when it's an ajax request
|
||||
if($doing_ajax) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't run any check when we're not on our pages
|
||||
if(
|
||||
!(isset($_GET['page']))
|
||||
or
|
||||
(isset($_GET['page']) && strpos($_GET['page'], 'mailpoet') !== 0)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action(
|
||||
'admin_init',
|
||||
array($this, 'check')
|
||||
);
|
||||
}
|
||||
|
||||
function check() {
|
||||
$version = Setting::getValue('version', null);
|
||||
$redirect_url = null;
|
||||
|
||||
if($version === null) {
|
||||
// new install
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet-welcome');
|
||||
} else if($version !== Env::$version) {
|
||||
// update
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet-update');
|
||||
}
|
||||
|
||||
if($redirect_url !== null) {
|
||||
// save version number
|
||||
Setting::setValue('version', Env::$version);
|
||||
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
|
||||
if($redirect_url !== $current_url) {
|
||||
wp_safe_redirect(
|
||||
add_query_arg(
|
||||
array(
|
||||
'mailpoet_redirect' => urlencode($current_url)
|
||||
),
|
||||
$redirect_url
|
||||
)
|
||||
);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,34 +4,37 @@ namespace MailPoet\Config;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Env {
|
||||
public static $version;
|
||||
public static $plugin_name;
|
||||
public static $file;
|
||||
public static $path;
|
||||
public static $views_path;
|
||||
public static $assets_path;
|
||||
public static $assets_url;
|
||||
public static $temp_name;
|
||||
public static $temp_path;
|
||||
public static $languages_path;
|
||||
public static $lib_path;
|
||||
public static $plugin_prefix;
|
||||
public static $db_prefix;
|
||||
public static $db_source_name;
|
||||
public static $db_host;
|
||||
public static $db_socket;
|
||||
public static $db_port;
|
||||
public static $db_name;
|
||||
public static $db_username;
|
||||
public static $db_password;
|
||||
public static $db_charset;
|
||||
static $version;
|
||||
static $plugin_name;
|
||||
static $plugin_url;
|
||||
static $plugin_path;
|
||||
static $file;
|
||||
static $path;
|
||||
static $views_path;
|
||||
static $assets_path;
|
||||
static $assets_url;
|
||||
static $temp_name;
|
||||
static $temp_path;
|
||||
static $languages_path;
|
||||
static $lib_path;
|
||||
static $plugin_prefix;
|
||||
static $db_prefix;
|
||||
static $db_source_name;
|
||||
static $db_host;
|
||||
static $db_socket;
|
||||
static $db_port;
|
||||
static $db_name;
|
||||
static $db_username;
|
||||
static $db_password;
|
||||
static $db_charset;
|
||||
|
||||
public static function init($file, $version) {
|
||||
static function init($file, $version) {
|
||||
global $wpdb;
|
||||
self::$version = $version;
|
||||
self::$plugin_name = 'mailpoet';
|
||||
self::$file = $file;
|
||||
self::$path = dirname(self::$file);
|
||||
self::$plugin_name = 'mailpoet';
|
||||
self::$plugin_url = plugin_dir_url(__FILE__);
|
||||
self::$views_path = self::$path . '/views';
|
||||
self::$assets_path = self::$path . '/assets';
|
||||
self::$assets_url = plugins_url('/assets', $file);
|
||||
@ -44,11 +47,12 @@ class Env {
|
||||
self::$db_host = DB_HOST;
|
||||
self::$db_port = 3306;
|
||||
self::$db_socket = false;
|
||||
if (preg_match('/(?=:\d+$)/', DB_HOST)) {
|
||||
if(preg_match('/(?=:\d+$)/', DB_HOST)) {
|
||||
list(self::$db_host, self::$db_port) = explode(':', DB_HOST);
|
||||
}
|
||||
else if (preg_match('/:/', DB_HOST)) {
|
||||
self::$db_socket = true;
|
||||
} else {
|
||||
if(preg_match('/:/', DB_HOST)) {
|
||||
self::$db_socket = true;
|
||||
}
|
||||
}
|
||||
self::$db_name = DB_NAME;
|
||||
self::$db_username = DB_USER;
|
||||
@ -57,7 +61,7 @@ class Env {
|
||||
self::$db_source_name = self::dbSourceName(self::$db_host, self::$db_socket, self::$db_port);
|
||||
}
|
||||
|
||||
private static function dbSourceName($host, $socket,$port) {
|
||||
private static function dbSourceName($host, $socket, $port) {
|
||||
$source_name = array(
|
||||
(!$socket) ? 'mysql:host=' : 'mysql:unix_socket=',
|
||||
$host,
|
||||
@ -70,4 +74,19 @@ class Env {
|
||||
);
|
||||
return implode('', $source_name);
|
||||
}
|
||||
|
||||
static function isPluginActivated() {
|
||||
$activatesPlugins = get_option('active_plugins');
|
||||
$isActivated = (
|
||||
in_array(
|
||||
sprintf('%s/%s.php', basename(self::$path), self::$plugin_name),
|
||||
$activatesPlugins
|
||||
) ||
|
||||
in_array(
|
||||
sprintf('%s/%s.php', explode('/', plugin_basename(__FILE__))[0], self::$plugin_name),
|
||||
$activatesPlugins
|
||||
)
|
||||
);
|
||||
return ($isActivated) ? true : false;
|
||||
}
|
||||
}
|
56
lib/Config/Hooks.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
|
||||
class Hooks {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
// WP Users synchronization
|
||||
add_action(
|
||||
'user_register',
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
);
|
||||
add_action(
|
||||
'added_existing_user',
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
);
|
||||
add_action(
|
||||
'profile_update',
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
);
|
||||
add_action(
|
||||
'delete_user',
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
);
|
||||
// multisite
|
||||
add_action(
|
||||
'deleted_user',
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
);
|
||||
add_action(
|
||||
'remove_user_from_blog',
|
||||
'\MailPoet\Segments\WP::synchronizeUser',
|
||||
1
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'image_size_names_choose',
|
||||
array(
|
||||
$this,
|
||||
'appendImageSizes'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function appendImageSizes($sizes) {
|
||||
return array_merge($sizes, array(
|
||||
'mailpoet_newsletter_max' => __('MailPoet Newsletter'),
|
||||
));
|
||||
}
|
||||
}
|
@ -2,7 +2,9 @@
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Models;
|
||||
use MailPoet\Cron\Supervisor;
|
||||
use MailPoet\Router;
|
||||
use MailPoet\Models\Setting;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -24,6 +26,12 @@ class Initializer {
|
||||
$this->setupWidget();
|
||||
$this->setupAnalytics();
|
||||
$this->setupPermissions();
|
||||
$this->setupChangelog();
|
||||
$this->setupPublicAPI();
|
||||
$this->runQueueSupervisor();
|
||||
$this->setupShortcodes();
|
||||
$this->setupHooks();
|
||||
$this->setupImages();
|
||||
}
|
||||
|
||||
function setupDB() {
|
||||
@ -32,7 +40,8 @@ class Initializer {
|
||||
\ORM::configure('password', Env::$db_password);
|
||||
\ORM::configure('logging', WP_DEBUG);
|
||||
\ORM::configure('driver_options', array(
|
||||
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
|
||||
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
|
||||
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET TIME_ZONE = "+00:00"'
|
||||
));
|
||||
|
||||
$subscribers = Env::$db_prefix . 'subscribers';
|
||||
@ -40,6 +49,8 @@ class Initializer {
|
||||
$newsletters = Env::$db_prefix . 'newsletters';
|
||||
$newsletter_templates = Env::$db_prefix . 'newsletter_templates';
|
||||
$segments = Env::$db_prefix . 'segments';
|
||||
$filters = Env::$db_prefix . 'filters';
|
||||
$segment_filter = Env::$db_prefix . 'segment_filter';
|
||||
$forms = Env::$db_prefix . 'forms';
|
||||
$subscriber_segment = Env::$db_prefix . 'subscriber_segment';
|
||||
$newsletter_segment = Env::$db_prefix . 'newsletter_segment';
|
||||
@ -47,11 +58,15 @@ class Initializer {
|
||||
$subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field';
|
||||
$newsletter_option_fields = Env::$db_prefix . 'newsletter_option_fields';
|
||||
$newsletter_option = Env::$db_prefix . 'newsletter_option';
|
||||
$sending_queues = Env::$db_prefix . 'sending_queues';
|
||||
$newsletter_statistics = Env::$db_prefix . 'newsletter_statistics';
|
||||
|
||||
define('MP_SUBSCRIBERS_TABLE', $subscribers);
|
||||
define('MP_SETTINGS_TABLE', $settings);
|
||||
define('MP_NEWSLETTERS_TABLE', $newsletters);
|
||||
define('MP_SEGMENTS_TABLE', $segments);
|
||||
define('MP_FILTERS_TABLE', $filters);
|
||||
define('MP_SEGMENT_FILTER_TABLE', $segment_filter);
|
||||
define('MP_FORMS_TABLE', $forms);
|
||||
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
|
||||
define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates);
|
||||
@ -60,6 +75,8 @@ class Initializer {
|
||||
define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field);
|
||||
define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields);
|
||||
define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option);
|
||||
define('MP_SENDING_QUEUE_TABLE', $sending_queues);
|
||||
define('MP_NEWSLETTER_STATISTICS_TABLE', $newsletter_statistics);
|
||||
}
|
||||
|
||||
function setupActivator() {
|
||||
@ -96,6 +113,7 @@ class Initializer {
|
||||
}
|
||||
|
||||
function setupAnalytics() {
|
||||
|
||||
$widget = new Analytics();
|
||||
$widget->init();
|
||||
}
|
||||
@ -104,4 +122,34 @@ class Initializer {
|
||||
$permissions = new Permissions();
|
||||
$permissions->init();
|
||||
}
|
||||
|
||||
function setupChangelog() {
|
||||
$changelog = new Changelog();
|
||||
$changelog->init();
|
||||
}
|
||||
|
||||
function setupShortcodes() {
|
||||
$shortcodes = new Shortcodes();
|
||||
$shortcodes->init();
|
||||
}
|
||||
function setupHooks() {
|
||||
$hooks = new Hooks();
|
||||
$hooks->init();
|
||||
}
|
||||
|
||||
function setupPublicAPI() {
|
||||
$publicAPI = new PublicAPI();
|
||||
$publicAPI->init();
|
||||
}
|
||||
|
||||
function runQueueSupervisor() {
|
||||
try {
|
||||
$supervisor = new Supervisor();
|
||||
$supervisor->checkDaemon();
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
function setupImages() {
|
||||
add_image_size('mailpoet_newsletter_max', 1320);
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Form\Block;
|
||||
use MailPoet\Form\Renderer as FormRenderer;
|
||||
use MailPoet\Models\CustomField;
|
||||
use MailPoet\Models\Form;
|
||||
use MailPoet\Models\Segment;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Settings\Charsets;
|
||||
use MailPoet\Settings\Hosts;
|
||||
use MailPoet\Settings\Pages;
|
||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||
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;
|
||||
use \MailPoet\Util\Permissions;
|
||||
use \MailPoet\Util\DKIM;
|
||||
use MailPoet\Util\DKIM;
|
||||
use MailPoet\Util\Permissions;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -24,7 +25,10 @@ class Menu {
|
||||
function init() {
|
||||
add_action(
|
||||
'admin_menu',
|
||||
array($this, 'setup')
|
||||
array(
|
||||
$this,
|
||||
'setup'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -34,7 +38,10 @@ class Menu {
|
||||
'MailPoet',
|
||||
'manage_options',
|
||||
'mailpoet',
|
||||
array($this, 'welcome'),
|
||||
array(
|
||||
$this,
|
||||
'home'
|
||||
),
|
||||
$this->assets_url . '/img/menu_icon.png',
|
||||
30
|
||||
);
|
||||
@ -44,7 +51,10 @@ class Menu {
|
||||
__('Newsletters'),
|
||||
'manage_options',
|
||||
'mailpoet-newsletters',
|
||||
array($this, 'newsletters')
|
||||
array(
|
||||
$this,
|
||||
'newsletters'
|
||||
)
|
||||
);
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
@ -52,7 +62,10 @@ class Menu {
|
||||
__('Forms'),
|
||||
'manage_options',
|
||||
'mailpoet-forms',
|
||||
array($this, 'forms')
|
||||
array(
|
||||
$this,
|
||||
'forms'
|
||||
)
|
||||
);
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
@ -60,7 +73,10 @@ class Menu {
|
||||
__('Subscribers'),
|
||||
'manage_options',
|
||||
'mailpoet-subscribers',
|
||||
array($this, 'subscribers')
|
||||
array(
|
||||
$this,
|
||||
'subscribers'
|
||||
)
|
||||
);
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
@ -68,7 +84,10 @@ class Menu {
|
||||
__('Segments'),
|
||||
'manage_options',
|
||||
'mailpoet-segments',
|
||||
array($this, 'segments')
|
||||
array(
|
||||
$this,
|
||||
'segments'
|
||||
)
|
||||
);
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
@ -76,7 +95,10 @@ class Menu {
|
||||
__('Settings'),
|
||||
'manage_options',
|
||||
'mailpoet-settings',
|
||||
array($this, 'settings')
|
||||
array(
|
||||
$this,
|
||||
'settings'
|
||||
)
|
||||
);
|
||||
add_submenu_page(
|
||||
null,
|
||||
@ -84,7 +106,10 @@ class Menu {
|
||||
__('Import'),
|
||||
'manage_options',
|
||||
'mailpoet-import',
|
||||
array($this, 'import')
|
||||
array(
|
||||
$this,
|
||||
'import'
|
||||
)
|
||||
);
|
||||
add_submenu_page(
|
||||
null,
|
||||
@ -92,33 +117,71 @@ class Menu {
|
||||
__('Export'),
|
||||
'manage_options',
|
||||
'mailpoet-export',
|
||||
array($this, 'export')
|
||||
array(
|
||||
$this,
|
||||
'export'
|
||||
)
|
||||
);
|
||||
// add_submenu_page(
|
||||
// 'mailpoet',
|
||||
// __('Newsletter editor'),
|
||||
// __('Newsletter editor'),
|
||||
// 'manage_options',
|
||||
// 'mailpoet-newsletter-editor',
|
||||
// array($this, 'newletterEditor')
|
||||
// );
|
||||
$this->registered_pages();
|
||||
}
|
||||
|
||||
function registered_pages() {
|
||||
global $_registered_pages;
|
||||
$pages = array(
|
||||
'mailpoet-welcome' => array($this, 'welcome'),
|
||||
'mailpoet-form-editor' => array($this, 'formEditor'),
|
||||
'mailpoet-newsletter-editor' => array($this, 'newletterEditor')
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Welcome'),
|
||||
__('Welcome'),
|
||||
'manage_options',
|
||||
'mailpoet-welcome',
|
||||
array(
|
||||
$this,
|
||||
'welcome'
|
||||
)
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Update'),
|
||||
__('Update'),
|
||||
'manage_options',
|
||||
'mailpoet-update',
|
||||
array(
|
||||
$this,
|
||||
'update'
|
||||
)
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Form editor'),
|
||||
__('Form editor'),
|
||||
'manage_options',
|
||||
'mailpoet-form-editor',
|
||||
array(
|
||||
$this,
|
||||
'formEditor'
|
||||
)
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Newsletter editor'),
|
||||
__('Newsletter editor'),
|
||||
'manage_options',
|
||||
'mailpoet-newsletter-editor',
|
||||
array(
|
||||
$this,
|
||||
'newletterEditor'
|
||||
)
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'mailpoet',
|
||||
__('Cron'),
|
||||
__('Cron'),
|
||||
'manage_options',
|
||||
'mailpoet-cron',
|
||||
array(
|
||||
$this,
|
||||
'cron'
|
||||
)
|
||||
);
|
||||
foreach($pages as $menu_slug => $callback) {
|
||||
$hookname = get_plugin_page_hookname($menu_slug, null);
|
||||
if(!empty($hookname)) {
|
||||
add_action($hookname, $callback);
|
||||
}
|
||||
$_registered_pages[$hookname] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function home() {
|
||||
@ -127,12 +190,52 @@ class Menu {
|
||||
}
|
||||
|
||||
function welcome() {
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
$redirect_url =
|
||||
(!empty($_GET['mailpoet_redirect']))
|
||||
? urldecode($_GET['mailpoet_redirect'])
|
||||
: wp_get_referer();
|
||||
|
||||
if(
|
||||
$redirect_url === $current_url
|
||||
or
|
||||
strpos($redirect_url, 'mailpoet') === false
|
||||
) {
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'settings' => Setting::getAll(),
|
||||
'current_user' => wp_get_current_user()
|
||||
'current_user' => wp_get_current_user(),
|
||||
'redirect_url' => $redirect_url
|
||||
);
|
||||
echo $this->renderer->render('welcome.html', $data);
|
||||
}
|
||||
|
||||
function update() {
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
$redirect_url =
|
||||
(!empty($_GET['mailpoet_redirect']))
|
||||
? urldecode($_GET['mailpoet_redirect'])
|
||||
: wp_get_referer();
|
||||
|
||||
if(
|
||||
$redirect_url === $current_url
|
||||
or
|
||||
strpos($redirect_url, 'mailpoet') === false
|
||||
) {
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'settings' => Setting::getAll(),
|
||||
'current_user' => wp_get_current_user(),
|
||||
'redirect_url' => $redirect_url
|
||||
);
|
||||
|
||||
echo $this->renderer->render('welcome.html', $data);
|
||||
echo $this->renderer->render('update.html', $data);
|
||||
}
|
||||
|
||||
function settings() {
|
||||
@ -155,7 +258,8 @@ class Menu {
|
||||
|
||||
$data = array(
|
||||
'settings' => $settings,
|
||||
'segments' => Segment::getPublished()->findArray(),
|
||||
'segments' => Segment::getPublished()
|
||||
->findArray(),
|
||||
'pages' => Pages::getAll(),
|
||||
'flags' => $this->_getFlags(),
|
||||
'charsets' => Charsets::getAll(),
|
||||
@ -183,11 +287,14 @@ class Menu {
|
||||
|
||||
// check if users can register
|
||||
$flags['registration_enabled'] =
|
||||
!(in_array($registration, array('none', 'blog')));
|
||||
!(in_array($registration, array(
|
||||
'none',
|
||||
'blog'
|
||||
)));
|
||||
} else {
|
||||
// check if users can register
|
||||
$flags['registration_enabled'] =
|
||||
(bool)get_option('users_can_register', false);
|
||||
(bool) get_option('users_can_register', false);
|
||||
}
|
||||
|
||||
return $flags;
|
||||
@ -198,7 +305,7 @@ class Menu {
|
||||
|
||||
$data['segments'] = Segment::findArray();
|
||||
|
||||
echo $this->renderer->render('subscribers.html', $data);
|
||||
echo $this->renderer->render('subscribers/subscribers.html', $data);
|
||||
}
|
||||
|
||||
function segments() {
|
||||
@ -219,17 +326,22 @@ class Menu {
|
||||
$data = array();
|
||||
|
||||
$data['segments'] = Segment::findArray();
|
||||
$settings = Setting::findArray();
|
||||
$data['settings'] = array();
|
||||
foreach($settings as $setting) {
|
||||
$data['settings'][$setting['name']] = $setting['value'];
|
||||
}
|
||||
$data['settings'] = Setting::getAll();
|
||||
$data['roles'] = $wp_roles->get_names();
|
||||
echo $this->renderer->render('newsletters.html', $data);
|
||||
}
|
||||
|
||||
function newletterEditor() {
|
||||
$data = array();
|
||||
$custom_fields = array_map(function($field) {
|
||||
return array(
|
||||
'text' => $field['name'],
|
||||
'shortcode' => 'field:' . $field['id'],
|
||||
);
|
||||
}, CustomField::findArray());
|
||||
|
||||
$data = array(
|
||||
'customFields' => $custom_fields,
|
||||
);
|
||||
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'));
|
||||
@ -239,17 +351,17 @@ class Menu {
|
||||
function import() {
|
||||
$import = new BootStrapMenu('import');
|
||||
$data = $import->bootstrap();
|
||||
echo $this->renderer->render('import.html', $data);
|
||||
echo $this->renderer->render('subscribers/importExport/import.html', $data);
|
||||
}
|
||||
|
||||
function export() {
|
||||
$export = new BootStrapMenu('export');
|
||||
$data = $export->bootstrap();
|
||||
echo $this->renderer->render('export.html', $data);
|
||||
echo $this->renderer->render('subscribers/importExport/export.html', $data);
|
||||
}
|
||||
|
||||
function formEditor() {
|
||||
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
|
||||
$id = (isset($_GET['id']) ? (int) $_GET['id'] : 0);
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$form = $form->asArray();
|
||||
@ -258,12 +370,18 @@ class Menu {
|
||||
$data = array(
|
||||
'form' => $form,
|
||||
'pages' => Pages::getAll(),
|
||||
'segments' => Segment::getPublished()->findArray(),
|
||||
'segments' => Segment::getPublic()
|
||||
->findArray(),
|
||||
'styles' => FormRenderer::getStyles($form),
|
||||
'date_types' => Block\Date::getDateTypes(),
|
||||
'date_formats' => Block\Date::getDateFormats()
|
||||
'date_formats' => Block\Date::getDateFormats(),
|
||||
'month_names' => Block\Date::getMonthNames()
|
||||
);
|
||||
|
||||
echo $this->renderer->render('form/editor.html', $data);
|
||||
}
|
||||
|
||||
function cron() {
|
||||
echo $this->renderer->render('cron.html');
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ class Migrator {
|
||||
'subscriber_custom_field',
|
||||
'newsletter_option_fields',
|
||||
'newsletter_option',
|
||||
'sending_queues',
|
||||
'newsletter_statistics',
|
||||
'forms'
|
||||
);
|
||||
}
|
||||
@ -39,7 +41,7 @@ class Migrator {
|
||||
function down() {
|
||||
global $wpdb;
|
||||
|
||||
$drop_table = function($model) {
|
||||
$drop_table = function($model) use($wpdb) {
|
||||
$table = $this->prefix . $model;
|
||||
$wpdb->query("DROP TABLE {$table}");
|
||||
};
|
||||
@ -50,6 +52,7 @@ class Migrator {
|
||||
function subscribers() {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'wp_user_id bigint(20) NULL,',
|
||||
'first_name tinytext NOT NULL,',
|
||||
'last_name tinytext NOT NULL,',
|
||||
'email varchar(150) NOT NULL,',
|
||||
@ -81,6 +84,10 @@ class Migrator {
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'subject varchar(250) NOT NULL,',
|
||||
'type varchar(20) NOT NULL DEFAULT "standard",',
|
||||
'sender_address varchar(150) NOT NULL,',
|
||||
'sender_name varchar(150) NOT NULL,',
|
||||
'reply_to_address varchar(150) NOT NULL,',
|
||||
'reply_to_name varchar(150) NOT NULL,',
|
||||
'preheader varchar(250) NOT NULL,',
|
||||
'body longtext,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
@ -96,7 +103,9 @@ class Migrator {
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'name varchar(250) NOT NULL,',
|
||||
'description varchar(250) NOT NULL,',
|
||||
'body longtext,',
|
||||
'body LONGTEXT,',
|
||||
'thumbnail LONGTEXT,',
|
||||
'readonly TINYINT(1) DEFAULT 0,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)'
|
||||
@ -106,14 +115,15 @@ class Migrator {
|
||||
|
||||
function segments() {
|
||||
$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,',
|
||||
'PRIMARY KEY (id),',
|
||||
'UNIQUE KEY name (name)'
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'name varchar(90) NOT NULL,',
|
||||
'type varchar(90) NOT NULL DEFAULT "default",',
|
||||
'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,',
|
||||
'PRIMARY KEY (id),',
|
||||
'UNIQUE KEY name (name)'
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
@ -123,6 +133,7 @@ class Migrator {
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'subscriber_id mediumint(9) NOT NULL,',
|
||||
'segment_id mediumint(9) NOT NULL,',
|
||||
'status varchar(12) NOT NULL DEFAULT "subscribed",',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id),',
|
||||
@ -199,6 +210,41 @@ class Migrator {
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
function sending_queues() {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'newsletter_id mediumint(9) NOT NULL,',
|
||||
'subscribers longtext,',
|
||||
'status varchar(12) NULL DEFAULT NULL,',
|
||||
'priority mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_total mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_to_process mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_failed mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'processed_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||
'PRIMARY KEY (id)',
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
function newsletter_statistics() {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'newsletter_id mediumint(9) NOT NULL,',
|
||||
'subscriber_id mediumint(9) NOT NULL,',
|
||||
'queue_id mediumint(9) NOT NULL,',
|
||||
'sent_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||
'PRIMARY KEY (id)',
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
function forms() {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
|
@ -1,6 +1,14 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Config\PopulatorData\Templates\FranksRoastHouseTemplate;
|
||||
use MailPoet\Config\PopulatorData\Templates\BlankTemplate;
|
||||
use MailPoet\Config\PopulatorData\Templates\WelcomeTemplate;
|
||||
use MailPoet\Config\PopulatorData\Templates\PostNotificationsBlankTemplate;
|
||||
use \MailPoet\Models\Segment;
|
||||
use \MailPoet\Segments\WP;
|
||||
use \MailPoet\Models\Setting;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
||||
@ -10,6 +18,7 @@ class Populator {
|
||||
$this->prefix = Env::$db_prefix;
|
||||
$this->models = array(
|
||||
'newsletter_option_fields',
|
||||
'newsletter_templates',
|
||||
);
|
||||
}
|
||||
|
||||
@ -36,6 +45,64 @@ class Populator {
|
||||
};
|
||||
|
||||
array_map(array($this, 'populate'), $this->models);
|
||||
|
||||
$this->createDefaultSegments();
|
||||
$this->createDefaultSettings();
|
||||
}
|
||||
|
||||
private function createDefaultSettings() {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
// user name
|
||||
$user_name = '';
|
||||
if($current_user->user_firstname) {
|
||||
$user_name = $current_user->user_firstname;
|
||||
}
|
||||
if($current_user->user_lastname) {
|
||||
if($user_name) {
|
||||
$user_name .= ' '.$current_user->user_lastname;
|
||||
}
|
||||
}
|
||||
if(!$user_name) {
|
||||
$user_name = $current_user->display_name;
|
||||
}
|
||||
|
||||
// default from name & address
|
||||
Setting::setValue('sender', array(
|
||||
'name' => $user_name,
|
||||
'address' => $current_user->user_email
|
||||
));
|
||||
}
|
||||
|
||||
private function createDefaultSegments() {
|
||||
// WP Users segment
|
||||
$wp_users_segment = Segment::getWPUsers();
|
||||
|
||||
if($wp_users_segment === false) {
|
||||
// create the wp users list
|
||||
$wp_users_segment = Segment::create();
|
||||
$wp_users_segment->hydrate(array(
|
||||
'name' => __('WordPress Users'),
|
||||
'description' =>
|
||||
__('The list containing all of your WordPress users.'),
|
||||
'type' => 'wp_users'
|
||||
));
|
||||
$wp_users_segment->save();
|
||||
}
|
||||
|
||||
// Synchronize WP Users
|
||||
WP::synchronizeUsers();
|
||||
|
||||
// Default segment
|
||||
if(Segment::where('type', 'default')->count() === 0) {
|
||||
$default_segment = Segment::create();
|
||||
$default_segment->hydrate(array(
|
||||
'name' => __('My First List'),
|
||||
'description' =>
|
||||
__('The list created automatically on install of MailPoet')
|
||||
));
|
||||
$default_segment->save();
|
||||
}
|
||||
}
|
||||
|
||||
function newsletter_option_fields() {
|
||||
@ -84,6 +151,15 @@ class Populator {
|
||||
);
|
||||
}
|
||||
|
||||
private function newsletter_templates() {
|
||||
return array(
|
||||
(new FranksRoastHouseTemplate(Env::$assets_url))->get(),
|
||||
(new BlankTemplate(Env::$assets_url))->get(),
|
||||
(new WelcomeTemplate(Env::$assets_url))->get(),
|
||||
(new PostNotificationsBlankTemplate(Env::$assets_url))->get(),
|
||||
);
|
||||
}
|
||||
|
||||
private function populate($model) {
|
||||
$rows = $this->$model();
|
||||
$table = $this->prefix . $model;
|
||||
|
213
lib/Config/PopulatorData/Templates/BlankTemplate.php
Normal file
350
lib/Config/PopulatorData/Templates/FranksRoastHouseTemplate.php
Normal file
295
lib/Config/PopulatorData/Templates/WelcomeTemplate.php
Normal file
49
lib/Config/PublicAPI.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Cron\Daemon;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class PublicAPI {
|
||||
function __construct() {
|
||||
# http://example.com/?mailpoet-api§ion=&action=&payload=
|
||||
$this->api = isset($_GET['mailpoet-api']) ? true : false;
|
||||
$this->section = isset($_GET['section']) ? $_GET['section'] : false;
|
||||
$this->action = isset($_GET['action']) ?
|
||||
Helpers::underscoreToCamelCase($_GET['action']) :
|
||||
false;
|
||||
$this->payload = isset($_GET['payload']) ?
|
||||
json_decode(urldecode($_GET['payload']), true) :
|
||||
false;
|
||||
}
|
||||
|
||||
function init() {
|
||||
if(!$this->api && !$this->section) return;
|
||||
$this->_checkAndCallMethod($this, $this->section, $terminate = true);
|
||||
}
|
||||
|
||||
function queue() {
|
||||
try {
|
||||
$queue = new Daemon($this->payload);
|
||||
$this->_checkAndCallMethod($queue, $this->action);
|
||||
} catch(\Exception $e) {
|
||||
// mailer configuration error
|
||||
}
|
||||
}
|
||||
|
||||
private function _checkAndCallMethod($class, $method, $terminate = false) {
|
||||
if(!method_exists($class, $method)) {
|
||||
if(!$terminate) return;
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
exit;
|
||||
}
|
||||
call_user_func(
|
||||
array(
|
||||
$class,
|
||||
$method
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
26
lib/Config/Shortcodes.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
|
||||
class Shortcodes {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
// form widget shortcode
|
||||
add_shortcode('mailpoet_form', array($this, 'formWidget'));
|
||||
add_shortcode('wysija_form', array($this, 'formWidget'));
|
||||
}
|
||||
|
||||
function formWidget($params = array()) {
|
||||
// IMPORTANT: fixes conflict with MagicMember
|
||||
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'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
@ -61,19 +61,25 @@ class Widget {
|
||||
}
|
||||
|
||||
function setupAdminDependencies() {
|
||||
wp_enqueue_script('mailpoet_vendor',
|
||||
Env::$assets_url.'/js/vendor.js',
|
||||
array(),
|
||||
Env::$version,
|
||||
true
|
||||
);
|
||||
if(
|
||||
empty($_GET['page'])
|
||||
or
|
||||
isset($_GET['page']) && strpos($_GET['page'], 'mailpoet') === false
|
||||
) {
|
||||
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
|
||||
);
|
||||
wp_enqueue_script('mailpoet_admin',
|
||||
Env::$assets_url.'/js/mailpoet.js',
|
||||
array(),
|
||||
Env::$version,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function setupActions() {
|
||||
|
36
lib/Cron/BootStrapMenu.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use MailPoet\Models\Setting;
|
||||
|
||||
class BootStrapMenu {
|
||||
function __construct() {
|
||||
$this->daemon = Setting::where('name', 'cron_daemon')
|
||||
->findOne();
|
||||
}
|
||||
|
||||
function bootStrap() {
|
||||
return ($this->daemon) ?
|
||||
array_merge(
|
||||
array(
|
||||
'timeSinceStart' =>
|
||||
Carbon::createFromFormat(
|
||||
'Y-m-d H:i:s',
|
||||
$this->daemon->created_at,
|
||||
'UTC'
|
||||
)
|
||||
->diffForHumans(),
|
||||
'timeSinceUpdate' =>
|
||||
Carbon::createFromFormat(
|
||||
'Y-m-d H:i:s',
|
||||
$this->daemon->updated_at,
|
||||
'UTC'
|
||||
)
|
||||
->diffForHumans()
|
||||
),
|
||||
json_decode($this->daemon->value, true)
|
||||
) :
|
||||
"false";
|
||||
}
|
||||
}
|
132
lib/Cron/Daemon.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use MailPoet\Cron\Workers\SendingQueue;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Util\Security;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Daemon {
|
||||
function __construct($payload = array()) {
|
||||
set_time_limit(0);
|
||||
ignore_user_abort();
|
||||
list ($this->daemon, $this->daemonData) = $this->getDaemon();
|
||||
$this->refreshedToken = $this->refreshToken();
|
||||
$this->payload = $payload;
|
||||
$this->timer = microtime(true);
|
||||
}
|
||||
|
||||
function start() {
|
||||
if(!isset($this->payload['session'])) {
|
||||
$this->abortWithError('missing session ID');
|
||||
}
|
||||
$this->manageSession('start');
|
||||
$daemon = $this->daemon;
|
||||
$daemonData = $this->daemonData;
|
||||
if(!$daemon) {
|
||||
$daemon = Setting::create();
|
||||
$daemon->name = 'cron_daemon';
|
||||
$daemonData = array(
|
||||
'status' => null,
|
||||
'counter' => 0
|
||||
);
|
||||
$daemon->value = json_encode($daemonData);
|
||||
$daemon->save();
|
||||
}
|
||||
if($daemonData['status'] !== 'started') {
|
||||
$_SESSION['cron_daemon'] = 'started';
|
||||
$daemonData['status'] = 'started';
|
||||
$daemonData['token'] = $this->refreshedToken;
|
||||
$_SESSION['cron_daemon'] = array('result' => true);
|
||||
$this->manageSession('end');
|
||||
$daemon->value = json_encode($daemonData);
|
||||
$daemon->save();
|
||||
$this->callSelf();
|
||||
} else {
|
||||
$_SESSION['cron_daemon'] = array(
|
||||
'result' => false,
|
||||
'error' => 'already started'
|
||||
);
|
||||
}
|
||||
$this->manageSession('end');
|
||||
}
|
||||
|
||||
function run() {
|
||||
if(!$this->daemon || $this->daemonData['status'] !== 'started') {
|
||||
$this->abortWithError('not running');
|
||||
}
|
||||
if(!isset($this->payload['token']) ||
|
||||
$this->payload['token'] !== $this->daemonData['token']
|
||||
) {
|
||||
$this->abortWithError('invalid token');
|
||||
}
|
||||
|
||||
try {
|
||||
$sendingQueue = new SendingQueue($this->timer);
|
||||
$sendingQueue->process();
|
||||
} catch(Exception $e) {
|
||||
}
|
||||
|
||||
$elapsedTime = microtime(true) - $this->timer;
|
||||
if($elapsedTime < 30) {
|
||||
sleep(30 - $elapsedTime);
|
||||
}
|
||||
|
||||
// after each execution, read daemon in case it's status was modified
|
||||
list($daemon, $daemonData) = $this->getDaemon();
|
||||
$daemonData['counter']++;
|
||||
$daemonData['token'] = $this->refreshedToken;
|
||||
$daemon->value = json_encode($daemonData);
|
||||
$daemon->save();
|
||||
if($daemonData['status'] === 'strated') $this->callSelf();
|
||||
}
|
||||
|
||||
function getDaemon() {
|
||||
$daemon = Setting::where('name', 'cron_daemon')
|
||||
->findOne();
|
||||
return array(
|
||||
($daemon) ? $daemon : null,
|
||||
($daemon) ? json_decode($daemon->value, true) : null
|
||||
);
|
||||
}
|
||||
|
||||
function refreshToken() {
|
||||
return Security::generateRandomString();
|
||||
}
|
||||
|
||||
function manageSession($action) {
|
||||
switch($action) {
|
||||
case 'start':
|
||||
if(session_id()) {
|
||||
session_write_close();
|
||||
}
|
||||
session_id($this->payload['session']);
|
||||
session_start();
|
||||
break;
|
||||
case 'end':
|
||||
session_write_close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function callSelf() {
|
||||
$payload = json_encode(array('token' => $this->refreshedToken));
|
||||
Supervisor::getRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=run&payload=' . urlencode($payload)
|
||||
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
function abortWithError($error) {
|
||||
wp_send_json(
|
||||
array(
|
||||
'result' => false,
|
||||
'error' => $error
|
||||
));
|
||||
exit;
|
||||
}
|
||||
}
|
84
lib/Cron/Supervisor.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Models\Setting;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Supervisor {
|
||||
function __construct($forceStart = false) {
|
||||
$this->forceStart = $forceStart;
|
||||
if(!Env::isPluginActivated()) {
|
||||
throw new \Exception('Database has not been configured.');
|
||||
}
|
||||
list ($this->daemon, $this->daemonData) = $this->getDaemon();
|
||||
}
|
||||
|
||||
function checkDaemon() {
|
||||
if(!$this->daemon) {
|
||||
return $this->startDaemon();
|
||||
}
|
||||
if(!$this->forceStart && $this->daemonData['status'] === 'stopped') {
|
||||
return;
|
||||
}
|
||||
$currentTime = Carbon::now('UTC');
|
||||
$lastUpdateTime = Carbon::createFromFormat(
|
||||
'Y-m-d H:i:s',
|
||||
$this->daemon->updated_at, 'UTC'
|
||||
);
|
||||
$timeSinceLastStart = $currentTime->diffInSeconds($lastUpdateTime);
|
||||
if($timeSinceLastStart < 40) return;
|
||||
$this->daemonData['status'] = null;
|
||||
$this->daemon->value = json_encode($this->daemonData);
|
||||
$this->daemon->save();
|
||||
return $this->startDaemon();
|
||||
}
|
||||
|
||||
function startDaemon() {
|
||||
if(!session_id()) session_start();
|
||||
$sessionId = session_id();
|
||||
session_write_close();
|
||||
$_SESSION['cron_daemon'] = null;
|
||||
$payload = json_encode(array('session' => $sessionId));
|
||||
self::getRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=start&payload=' . urlencode($payload)
|
||||
);
|
||||
session_start();
|
||||
$daemonStatus = $_SESSION['cron_daemon'];
|
||||
unset($_SESSION['daemon']);
|
||||
session_write_close();
|
||||
return $daemonStatus;
|
||||
}
|
||||
|
||||
function getDaemon() {
|
||||
$daemon = Setting::where('name', 'cron_daemon')
|
||||
->findOne();
|
||||
$daemonData = ($daemon) ? json_decode($daemon->value, true) : false;
|
||||
return array(
|
||||
$daemon,
|
||||
$daemonData
|
||||
);
|
||||
}
|
||||
|
||||
static function getRemoteUrl($url) {
|
||||
$args = array(
|
||||
'timeout' => 1,
|
||||
'user-agent' => 'MailPoet (www.mailpoet.com)'
|
||||
);
|
||||
wp_remote_get(
|
||||
self::getSiteUrl() . $url,
|
||||
$args
|
||||
);
|
||||
}
|
||||
|
||||
static function getSiteUrl() {
|
||||
if(preg_match('!:\d+/!', site_url())) return site_url();
|
||||
preg_match('!http://(?P<host>.*?):(?P<port>\d+)!', site_url(), $server);
|
||||
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||
return ($fp) ?
|
||||
site_url() :
|
||||
preg_replace('/(?=:\d+):\d+/', '$1', site_url());
|
||||
}
|
||||
}
|
114
lib/Cron/Workers/SendingQueue.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron\Workers;
|
||||
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterStatistics;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Router\Mailer;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SendingQueue {
|
||||
function __construct($timer = false) {
|
||||
$this->timer = ($timer) ? $timer : microtime(true);
|
||||
}
|
||||
|
||||
function process() {
|
||||
$queues =
|
||||
\MailPoet\Models\SendingQueue::orderByDesc('priority')
|
||||
->whereNull('deleted_at')
|
||||
->whereNull('status')
|
||||
->findResultSet();
|
||||
foreach($queues as $queue) {
|
||||
$newsletter = Newsletter::findOne($queue->newsletter_id);
|
||||
if(!$newsletter) {
|
||||
continue;
|
||||
};
|
||||
$newsletter = $newsletter->asArray();
|
||||
$mailer = new Mailer($httpRequest = false);
|
||||
if(!empty($newsletter['sender_address']) &&
|
||||
!empty($newsletter['sender_name'])
|
||||
) {
|
||||
$mailer->fromName = $newsletter['sender_name'];
|
||||
$mailer->fromEmail = $newsletter['sender_address'];
|
||||
$mailer->fromNameEmail = sprintf(
|
||||
'%s <%s>',
|
||||
$mailer->fromName,
|
||||
$mailer->fromEmail
|
||||
);
|
||||
}
|
||||
if(!empty($newsletter['reply_to_address']) &&
|
||||
!empty($newsletter['reply_to_name'])
|
||||
) {
|
||||
$mailer->replyToName = $newsletter['reply_to_name'];
|
||||
$mailer->replyToEmail = $newsletter['reply_to_address'];
|
||||
$mailer->replyToNameEmail = sprintf(
|
||||
'%s <%s>',
|
||||
$mailer->replyToName,
|
||||
$mailer->replyToEmail
|
||||
);
|
||||
}
|
||||
$mailer->mailer = $mailer->buildMailer();
|
||||
$renderer = new Renderer(json_decode($newsletter['body'], true));
|
||||
$newsletter = array(
|
||||
'subject' => $newsletter['subject'],
|
||||
'id' => $newsletter['id'],
|
||||
'body' => array(
|
||||
'html' => $renderer->renderAll(),
|
||||
'text' => ''
|
||||
// TODO: add text body
|
||||
)
|
||||
);
|
||||
$subscribers = json_decode($queue->subscribers, true);
|
||||
$subscribersToProcess = $subscribers['to_process'];
|
||||
if(!isset($subscribers['failed'])) $subscribers['failed'] = array();
|
||||
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
|
||||
foreach(array_chunk($subscribersToProcess, 200) as $subscriberIds) {
|
||||
$dbSubscribers = Subscriber::whereIn('id', $subscriberIds)
|
||||
->findArray();
|
||||
foreach($dbSubscribers as $i => $dbSubscriber) {
|
||||
$this->checkExecutionTimer();
|
||||
// TODO: replace shortcodes in the newsletter
|
||||
$result = $mailer->mailer->send(
|
||||
$newsletter,
|
||||
$mailer->transformSubscriber($dbSubscriber)
|
||||
);
|
||||
$newsletterStatistics = NewsletterStatistics::create();
|
||||
$newsletterStatistics->subscriber_id = $dbSubscriber['id'];
|
||||
$newsletterStatistics->newsletter_id = $newsletter['id'];
|
||||
$newsletterStatistics->queue_id = $queue->id;
|
||||
$newsletterStatistics->save();
|
||||
if($result) {
|
||||
$subscribers['processed'][] = $dbSubscriber['id'];
|
||||
} else {
|
||||
$subscribers['failed'][] = $dbSubscriber['id'];
|
||||
}
|
||||
$subscribers['to_process'] = array_values(
|
||||
array_diff(
|
||||
$subscribers['to_process'],
|
||||
array_merge($subscribers['processed'], $subscribers['failed'])
|
||||
)
|
||||
);
|
||||
$queue->count_processed =
|
||||
count($subscribers['processed']) + count($subscribers['failed']);
|
||||
$queue->count_to_process = count($subscribers['to_process']);
|
||||
$queue->count_failed = count($subscribers['failed']);
|
||||
$queue->count_total =
|
||||
$queue->count_processed + $queue->count_to_process;
|
||||
if(!$queue->count_to_process) {
|
||||
$queue->processed_at = date('Y-m-d H:i:s');
|
||||
$queue->status = 'completed';
|
||||
}
|
||||
$queue->subscribers = json_encode($subscribers);
|
||||
$queue->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkExecutionTimer() {
|
||||
$elapsedTime = microtime(true) - $this->timer;
|
||||
if($elapsedTime >= 28) throw new \Exception('Maximum execution time reached.');
|
||||
}
|
||||
}
|
@ -29,7 +29,13 @@ abstract class Base {
|
||||
}
|
||||
}
|
||||
|
||||
$validation = '';
|
||||
if($block['type'] === 'radio') {
|
||||
$rules['group'] = 'custom_field_'.$block['id'];
|
||||
$rules['errors-container'] = '.mailpoet_error_'.$block['id'];
|
||||
$rules['required-message'] = __('You need to select at least one option.');
|
||||
}
|
||||
|
||||
$validation = array();
|
||||
|
||||
if(!empty($rules)) {
|
||||
$rules = array_unique($rules);
|
||||
@ -37,10 +43,10 @@ abstract class Base {
|
||||
if(is_bool($value)) {
|
||||
$value = ($value) ? 'true' : 'false';
|
||||
}
|
||||
$validation .= 'data-parsley-'.$rule.'="'.$value.'"';
|
||||
$validation[] = 'data-parsley-'.$rule.'="'.$value.'"';
|
||||
}
|
||||
}
|
||||
return $validation;
|
||||
return join(' ', $validation);
|
||||
}
|
||||
|
||||
protected static function renderLabel($block) {
|
||||
@ -86,7 +92,11 @@ abstract class Base {
|
||||
|
||||
// return field name depending on block data
|
||||
protected static function getFieldName($block = array()) {
|
||||
return $block['id'];
|
||||
if((int)$block['id'] > 0) {
|
||||
return 'cf_'.$block['id'];
|
||||
} else {
|
||||
return $block['id'];
|
||||
}
|
||||
}
|
||||
|
||||
protected static function getFieldLabel($block = array()) {
|
||||
@ -98,6 +108,6 @@ abstract class Base {
|
||||
protected static function getFieldValue($block = array()) {
|
||||
return (isset($block['params']['value'])
|
||||
&& strlen(trim($block['params']['value'])) > 0)
|
||||
? trim($block['params']['value']) : '';
|
||||
? esc_attr(trim($block['params']['value'])) : '';
|
||||
}
|
||||
}
|
@ -9,14 +9,12 @@ class Radio extends Base {
|
||||
$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);
|
||||
|
||||
$html .= '<span class="mailpoet_error_'.$block['id'].'"></span>';
|
||||
|
||||
foreach($block['params']['values'] as $option) {
|
||||
$html .= '<label class="mailpoet_radio_label">';
|
||||
|
||||
@ -24,13 +22,13 @@ class Radio extends Base {
|
||||
|
||||
$html .= 'name="'.$field_name.'" ';
|
||||
|
||||
$html .= 'value="'.$option['value'].'" ';
|
||||
$html .= 'value="'.esc_attr($option['value']).'" ';
|
||||
|
||||
$html .= (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'checked="checked"' : '';
|
||||
$html .= $field_validation;
|
||||
|
||||
$html .= ' /> '.$option['value'];
|
||||
$html .= ' /> '.esc_attr($option['value']);
|
||||
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
@ -36,9 +36,9 @@ class Widget extends \WP_Widget {
|
||||
|
||||
return parent::__construct(
|
||||
'mailpoet_form',
|
||||
__("MailPoet Subscription Form"),
|
||||
__('MailPoet Form'),
|
||||
array(
|
||||
'title' => __("Newsletter subscription form"),
|
||||
'description' => __('Add a newsletter subscription form.')
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -196,24 +196,6 @@ class Widget extends \WP_Widget {
|
||||
}
|
||||
}
|
||||
|
||||
// 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']) {
|
||||
|
@ -31,16 +31,21 @@ class AmazonSES {
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
return array(
|
||||
$body = array(
|
||||
'Action' => 'SendEmail',
|
||||
'Version' => '2010-12-01',
|
||||
'Source' => $this->from,
|
||||
'Destination.ToAddresses.member.1' => $subscriber,
|
||||
'Message.Subject.Data' => $newsletter['subject'],
|
||||
'Message.Body.Html.Data' => $newsletter['body']['html'],
|
||||
'Message.Body.Text.Data' => $newsletter['body']['text'],
|
||||
'ReturnPath' => $this->from
|
||||
);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
$body['Message.Body.Html.Data'] = $newsletter['body']['html'];
|
||||
}
|
||||
if(!empty($newsletter['body']['text'])) {
|
||||
$body['Message.Body.Text.Data'] = $newsletter['body']['text'];
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
||||
|
@ -22,15 +22,20 @@ class ElasticEmail {
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
return array(
|
||||
$body = array(
|
||||
'api_key' => $this->apiKey,
|
||||
'from' => $this->fromEmail,
|
||||
'from_name' => $this->fromName,
|
||||
'to' => $subscriber,
|
||||
'subject' => $newsletter['subject'],
|
||||
'body_html' => $newsletter['body']['html'],
|
||||
'body_text' => $newsletter['body']['text']
|
||||
'subject' => $newsletter['subject']
|
||||
);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
$body['body_html'] = $newsletter['body']['html'];
|
||||
}
|
||||
if(!empty($newsletter['body']['text'])) {
|
||||
$body['body_text'] = $newsletter['body']['text'];
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
||||
|