Compare commits
99 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
2ef5096fa9 | |||
95cfe2d8ec | |||
49676b3fc5 | |||
c96ac06423 | |||
6a3166c311 | |||
0017df1c2d | |||
f2a0d4ce96 | |||
cb50517cbc | |||
0fedd1779f | |||
1625e1771b | |||
bde78b607b | |||
f3c58c27be | |||
9fec460295 | |||
162859529e | |||
3bdaaf8368 | |||
f6ab0050b2 | |||
10a20935c3 | |||
8135b677f7 | |||
90382bc86d | |||
47af8939cc | |||
4a0deb2182 | |||
3a206b2c88 | |||
70cfcbe7cc | |||
6342cb17bd | |||
64c35b12c8 | |||
6a14f97419 | |||
dfec34eda9 | |||
893231e8e5 | |||
e9110680ee | |||
7b54285ca6 | |||
33ea16eb0f | |||
b1ae07d38e | |||
3f168d052f | |||
158d26ef86 | |||
ae03ee2c46 | |||
ad0adb48e1 | |||
ff5353c894 | |||
abb2389378 | |||
3cf50810f9 | |||
20a6e6d6de | |||
0b1fc8f6c3 | |||
0a771acb02 | |||
0199e2c7e1 | |||
d1f407bf19 | |||
f18d2842b9 | |||
f640cbb307 | |||
b20d92c9b1 | |||
795485d42a | |||
dfadda2d12 | |||
31305a04c0 | |||
cfdb886e88 | |||
1ce4b16327 | |||
b12f7f29de | |||
5473f94e24 | |||
a31dce6226 | |||
d996b78561 | |||
c2e7513381 | |||
541696863e | |||
6c8d2be18c | |||
907fe585de | |||
e24f8c9653 | |||
5df0475b1a | |||
cf154455e3 | |||
dcfe6357cf | |||
983df216f3 | |||
f750d2359f |
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,4 +15,5 @@ temp
|
||||
wysija-newsletters.zip
|
||||
tests/javascript/testBundles
|
||||
assets/css/*.css
|
||||
assets/js/*.js
|
||||
assets/js/*.js
|
||||
.vagrant
|
||||
|
10
RoboFile.php
10
RoboFile.php
@ -47,6 +47,10 @@ class RoboFile extends \Robo\Tasks {
|
||||
->run();
|
||||
}
|
||||
|
||||
function watchJs() {
|
||||
$this->_exec('./node_modules/webpack/bin/webpack.js --watch');
|
||||
}
|
||||
|
||||
function compileAll() {
|
||||
$this->compileJs();
|
||||
$this->compileCss();
|
||||
@ -61,7 +65,8 @@ class RoboFile extends \Robo\Tasks {
|
||||
'assets/css/src/admin.styl',
|
||||
'assets/css/src/newsletter_editor/newsletter_editor.styl',
|
||||
'assets/css/src/public.styl',
|
||||
'assets/css/src/rtl.styl'
|
||||
'assets/css/src/rtl.styl',
|
||||
'assets/css/src/importExport.styl'
|
||||
);
|
||||
|
||||
$this->_exec(join(' ', array(
|
||||
@ -113,7 +118,6 @@ class RoboFile extends \Robo\Tasks {
|
||||
function testFailed() {
|
||||
$this->loadEnv();
|
||||
$this->_exec('vendor/bin/codecept build');
|
||||
$this->startPhantomJS();
|
||||
$this->_exec('vendor/bin/codecept run -g failed');
|
||||
}
|
||||
|
||||
@ -121,4 +125,4 @@ class RoboFile extends \Robo\Tasks {
|
||||
$dotenv = new Dotenv\Dotenv(__DIR__);
|
||||
$dotenv->load();
|
||||
}
|
||||
}
|
||||
}
|
67
Vagrantfile
vendored
Normal file
67
Vagrantfile
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.name = "phoenix"
|
||||
v.memory = "2048"
|
||||
end
|
||||
|
||||
config.vm.define :web do |web|
|
||||
web.vm.box = "ubuntu/trusty64"
|
||||
web.vm.hostname = "phoenix"
|
||||
web.vm.network "forwarded_port", guest: 80, host: 8080
|
||||
web.vm.synced_folder(
|
||||
".",
|
||||
"/var/www/html/wp-content/plugins/wysija-newsletters",
|
||||
create: true,
|
||||
owner: "vagrant",
|
||||
group: "www-data"
|
||||
)
|
||||
|
||||
web.vm.provision "shell", inline: <<-SHELL
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y apache2 curl zip sendmail git build-essential
|
||||
|
||||
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password root'
|
||||
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password root'
|
||||
sudo apt-get install -y mysql-server-5.5
|
||||
|
||||
sudo apt-get install -y php5 libapache2-mod-php5 php5-curl php5-gd php5-mcrypt php5-readline mysql-server-5.5 php5-mysql php-apc
|
||||
sudo sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php5/apache2/php.ini
|
||||
sudo sed -i "s/display_errors = .*/display_errors = On/" /etc/php5/apache2/php.ini
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
sudo wget https://github.com/calvinlough/sqlbuddy/raw/gh-pages/sqlbuddy.zip -O /var/www/html/sqlbuddy.zip
|
||||
sudo rm index.html
|
||||
unzip sqlbuddy.zip
|
||||
|
||||
sudo curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
|
||||
sudo chmod +x wp-cli.phar
|
||||
sudo mv wp-cli.phar /usr/local/bin/wp
|
||||
sudo wp core download --allow-root
|
||||
mysql -uroot -proot -e "create database wordpress"
|
||||
sudo wp core config --allow-root --dbname=wordpress --dbuser=root --dbpass=root
|
||||
sudo wp core install --allow-root --url="http://localhost:8080" --title=WordPress --admin_user=admin --admin_password=password --admin_email=test@mailpoet-container.com
|
||||
|
||||
sudo sed -i "s/upload_max_filesize = .*/upload_max_filesize = 32M/" /etc/php5/apache2/php.ini
|
||||
sudo sed -i "s/post_max_size = .*/post_max_size = 32M/" /etc/php5/apache2/php.ini
|
||||
sudo chown -hR vagrant:www-data /var/www/html/
|
||||
sudo a2enmod rewrite > /dev/null 2>&1
|
||||
|
||||
cd /var/www/html/wp-content/plugins/wysija-newsletters
|
||||
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
sudo add-apt-repository -y ppa:chris-lea/node.js
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
sudo sed -i "s/export APACHE_RUN_USER.*/export APACHE_RUN_USER=vagrant/" /etc/apache2/envvars
|
||||
sudo chown -R vagrant:www-data /var/lock/apache2
|
||||
|
||||
sudo service apache2 restart
|
||||
SHELL
|
||||
end
|
||||
end
|
@ -5,7 +5,7 @@
|
||||
@require 'common'
|
||||
@require 'modal'
|
||||
@require 'notice'
|
||||
@require 'validation_engine'
|
||||
@require 'parsley'
|
||||
|
||||
@require 'form_editor'
|
||||
@require 'listing'
|
||||
|
@ -1,3 +1,6 @@
|
||||
@require 'codemirror/lib/codemirror.css'
|
||||
@require 'codemirror/theme/neo.css'
|
||||
|
||||
icons = '../img/form_editor_icons.png'
|
||||
handle_icon = '../img/handle.png'
|
||||
|
||||
|
78
assets/css/src/importExport.styl
Normal file
78
assets/css/src/importExport.styl
Normal file
@ -0,0 +1,78 @@
|
||||
.mailpoet_hidden, .mailpoet_validation_error
|
||||
display none
|
||||
|
||||
.form-table
|
||||
th
|
||||
width 300px
|
||||
|
||||
#paste_input
|
||||
width 100%
|
||||
|
||||
input[type="radio"]
|
||||
margin-right 0.5em !important
|
||||
& + span
|
||||
margin-right 2.5em
|
||||
|
||||
span
|
||||
&.mailpoet_mailchimp-key-status
|
||||
&.mailpoet_mailchimp-ok
|
||||
&:before
|
||||
content "\2713"
|
||||
color #0e90d2
|
||||
margin-left 15px
|
||||
&.mailpoet_mailchimp-error
|
||||
&:before
|
||||
content "\2717"
|
||||
color #900
|
||||
margin-left 15px
|
||||
|
||||
#subscribers_data
|
||||
overflow auto
|
||||
table
|
||||
width auto
|
||||
td
|
||||
padding 0.5em
|
||||
& > table
|
||||
& > tbody
|
||||
& > td
|
||||
padding 0.5em
|
||||
& > tr
|
||||
&:nth-child(odd)
|
||||
background #f9f9f9
|
||||
.mailpoet_header
|
||||
text-transform uppercase
|
||||
font-weight 600
|
||||
text-decoration underline
|
||||
|
||||
#subscribers_data th:first-child, #subscribers_data td:first-child
|
||||
width 10em !important
|
||||
text-align center !important
|
||||
padding 0 1em 0 1em !important
|
||||
vertical-align inherit !important
|
||||
|
||||
#subscribers_data
|
||||
& > table
|
||||
& > thead
|
||||
& > tr
|
||||
& > th
|
||||
& > span
|
||||
width 15em !important
|
||||
|
||||
.mailpoet_data_match
|
||||
color #0e90d2
|
||||
margin-left 0.25em
|
||||
|
||||
.mailpoet_import_error, .mailpoet_validation_error
|
||||
color #900
|
||||
|
||||
tr
|
||||
&.mailpoet_segments
|
||||
& > td
|
||||
& > a
|
||||
margin-left 15px
|
||||
|
||||
span
|
||||
&.select2-search
|
||||
&.select2-search--dropdown
|
||||
display none !important
|
||||
|
@ -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
|
||||
|
@ -45,7 +45,8 @@
|
||||
&::before
|
||||
content: '\f140'
|
||||
|
||||
.mailpoet_save_as_template_container
|
||||
.mailpoet_save_as_template_container,
|
||||
.mailpoet_export_template_container
|
||||
border-radius(3px)
|
||||
float: left
|
||||
clear: both
|
||||
@ -55,7 +56,8 @@
|
||||
background-color: $white-color
|
||||
border: 1px solid $structure-border-color
|
||||
|
||||
.mailpoet_save_as_template_title
|
||||
.mailpoet_save_as_template_title,
|
||||
.mailpoet_export_template_title
|
||||
font-size: 1.1em
|
||||
|
||||
.mailpoet_editor_last_saved
|
||||
|
@ -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,19 @@
|
||||
.mailpoet_image_block
|
||||
|
||||
img
|
||||
vertical-align: bottom
|
||||
max-width: 100%
|
||||
width: auto
|
||||
height: auto
|
||||
|
||||
&.mailpoet_full_image
|
||||
padding-left: 0
|
||||
padding-right: 0
|
||||
margin-bottom: 0
|
||||
|
||||
img
|
||||
width: 100%
|
||||
|
||||
.mailpoet_content a:hover
|
||||
cursor: all-scroll
|
||||
|
||||
img
|
||||
vertical-align: bottom
|
||||
max-width: $newsletter-width
|
||||
width: 100%
|
||||
height: auto
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Fix select2 z-index to work with MailPoet.Modal */
|
||||
.select2-dropdown
|
||||
z-index: 101000
|
||||
z-index: 101000 !important
|
||||
|
||||
/* Remove input field styles from select2 type input */
|
||||
.select2-container
|
||||
|
27
assets/css/src/parsley.styl
Normal file
27
assets/css/src/parsley.styl
Normal file
@ -0,0 +1,27 @@
|
||||
input.parsley-success,
|
||||
select.parsley-success,
|
||||
textarea.parsley-success
|
||||
color #468847
|
||||
background-color #DFF0D8
|
||||
border 1px solid #D6E9C6
|
||||
|
||||
input.parsley-error,
|
||||
select.parsley-error,
|
||||
textarea.parsley-error
|
||||
color #B94A48
|
||||
background-color #F2DEDE
|
||||
border 1px solid #EED3D7
|
||||
|
||||
.parsley-errors-list
|
||||
margin 2px 0 3px
|
||||
padding 0
|
||||
list-style-type none
|
||||
font-size 0.9em
|
||||
line-height 0.9em
|
||||
opacity 0
|
||||
transition all .3s ease-in
|
||||
-o-transition all .3s ease-in
|
||||
-moz-transition all .3s ease-in
|
||||
-webkit-transition all .3s ease-in
|
||||
&.filled
|
||||
opacity 1
|
@ -0,0 +1,3 @@
|
||||
@import 'nib'
|
||||
|
||||
@require 'parsley'
|
||||
|
@ -1,141 +0,0 @@
|
||||
lesscss-percentage(n)
|
||||
(n * 100)%
|
||||
popupBg = rgb(0, 87, 154, 1)
|
||||
popupTextColor = rgb(255, 255, 255, 1)
|
||||
borderColor = rgb(255, 255, 255, 1)
|
||||
borderWidth = 1px
|
||||
popupFontSize = 12px
|
||||
popupRadius = 0
|
||||
popupShadowWidth = 2px
|
||||
popupShadowColor = rgb(51, 51, 51, 1)
|
||||
/* Z-INDEX */
|
||||
.formError
|
||||
z-index 990
|
||||
.formError .formErrorContent
|
||||
z-index 991
|
||||
.formError .formErrorArrow
|
||||
z-index 996
|
||||
.ui-dialog .formError
|
||||
z-index 5000
|
||||
.ui-dialog .formError .formErrorContent
|
||||
z-index 5001
|
||||
.ui-dialog .formError .formErrorArrow
|
||||
z-index 5006
|
||||
.inputContainer
|
||||
position relative
|
||||
float left
|
||||
.formError
|
||||
position absolute
|
||||
top 300px
|
||||
left 300px
|
||||
display block
|
||||
cursor pointer
|
||||
text-align left
|
||||
.formError.inline
|
||||
position relative
|
||||
top 0
|
||||
left 0
|
||||
display inline-block
|
||||
.ajaxSubmit
|
||||
padding 20px
|
||||
background #55ea55
|
||||
border 1px solid #999
|
||||
display none
|
||||
.formError .formErrorContent
|
||||
width 100%
|
||||
background popupBg
|
||||
position relative
|
||||
color popupTextColor
|
||||
min-width 120px
|
||||
font-size popupFontSize
|
||||
border borderWidth solid borderColor
|
||||
box-shadow 0 0 popupShadowWidth popupShadowColor
|
||||
-moz-box-shadow 0 0 popupShadowWidth popupShadowColor
|
||||
-webkit-box-shadow 0 0 popupShadowWidth popupShadowColor
|
||||
-o-box-shadow 0 0 popupShadowWidth popupShadowColor
|
||||
padding 4px 10px 4px 10px
|
||||
border-radius popupRadius
|
||||
-moz-border-radius popupRadius
|
||||
-webkit-border-radius popupRadius
|
||||
-o-border-radius popupRadius
|
||||
.formError.inline .formErrorContent
|
||||
box-shadow none
|
||||
-moz-box-shadow none
|
||||
-webkit-box-shadow none
|
||||
-o-box-shadow none
|
||||
border none
|
||||
border-radius 0
|
||||
-moz-border-radius 0
|
||||
-webkit-border-radius 0
|
||||
-o-border-radius 0
|
||||
.greenPopup .formErrorContent
|
||||
background #33be40
|
||||
.blackPopup .formErrorContent
|
||||
background #393939
|
||||
color #FFF
|
||||
.formError .formErrorArrow
|
||||
width 15px
|
||||
margin -2px 0 0 13px
|
||||
position relative
|
||||
body[dir='rtl'] .formError .formErrorArrow, body.rtl .formError .formErrorArrow
|
||||
margin -2px 13px 0 0
|
||||
.formError .formErrorArrowBottom
|
||||
box-shadow none
|
||||
-moz-box-shadow none
|
||||
-webkit-box-shadow none
|
||||
-o-box-shadow none
|
||||
margin 0px 0 0 12px
|
||||
top 2px
|
||||
.formError .formErrorArrow div
|
||||
border-left borderWidth solid borderColor
|
||||
border-right borderWidth solid borderColor
|
||||
box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
|
||||
-moz-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
|
||||
-webkit-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
|
||||
-o-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
|
||||
font-size 0px
|
||||
height 1px
|
||||
background popupBg
|
||||
margin 0 auto
|
||||
line-height 0
|
||||
font-size 0
|
||||
display block
|
||||
.formError .formErrorArrowBottom div
|
||||
box-shadow none
|
||||
-moz-box-shadow none
|
||||
-webkit-box-shadow none
|
||||
-o-box-shadow none
|
||||
.greenPopup .formErrorArrow div
|
||||
background #33be40
|
||||
.blackPopup .formErrorArrow div
|
||||
background #393939
|
||||
color #FFF
|
||||
.formError .formErrorArrow .line10
|
||||
width 13px
|
||||
border none
|
||||
.formError .formErrorArrow .line9
|
||||
width 11px
|
||||
border none
|
||||
.formError .formErrorArrow .line8
|
||||
width 11px
|
||||
.formError .formErrorArrow .line7
|
||||
width 9px
|
||||
.formError .formErrorArrow .line6
|
||||
width 7px
|
||||
.formError .formErrorArrow .line5
|
||||
width 5px
|
||||
.formError .formErrorArrow .line4
|
||||
width 3px
|
||||
.formError .formErrorArrow .line3
|
||||
width ceil((borderWidth / 2))
|
||||
border-left borderWidth solid borderColor
|
||||
border-right borderWidth solid borderColor
|
||||
border-bottom 0 solid borderColor
|
||||
.formError .formErrorArrow .line2
|
||||
width 3px
|
||||
border none
|
||||
background borderColor
|
||||
.formError .formErrorArrow .line1
|
||||
width 1px
|
||||
border none
|
||||
background borderColor
|
8
assets/js/lib/analytics.js
Normal file
8
assets/js/lib/analytics.js
Normal file
@ -0,0 +1,8 @@
|
||||
(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
|
||||
for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
|
||||
|
||||
mixpanel.init("f683d388fb25fcf331f1b2b5c4449798");
|
||||
|
||||
if (typeof mailpoet_analytics_data === 'object') {
|
||||
mixpanel.track('Wysija Usage', mailpoet_analytics_data || {});
|
||||
}
|
4
assets/js/lib/prototype.min.js
vendored
Normal file
4
assets/js/lib/prototype.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
assets/js/lib/scriptaculous.min.js
vendored
Normal file
2
assets/js/lib/scriptaculous.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
170
assets/js/src/export/export.js
Normal file
170
assets/js/src/export/export.js
Normal file
@ -0,0 +1,170 @@
|
||||
define(
|
||||
[
|
||||
'underscore',
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'handlebars',
|
||||
'select2'
|
||||
],
|
||||
function (
|
||||
_,
|
||||
jQuery,
|
||||
MailPoet,
|
||||
Handlebars
|
||||
) {
|
||||
if (!jQuery("#mailpoet_subscribers_export").length) {
|
||||
return;
|
||||
}
|
||||
jQuery(document).ready(function () {
|
||||
if (!exportData.segments) {
|
||||
return;
|
||||
}
|
||||
var subscribers_export_template =
|
||||
Handlebars.compile(jQuery('#mailpoet_subscribers_export_template').html());
|
||||
|
||||
//render template
|
||||
jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(exportData));
|
||||
|
||||
// define reusable variables
|
||||
var segmentsContainerElement = jQuery("#export_lists"),
|
||||
subscriberFieldsContainerElement = jQuery("#export_columns"),
|
||||
exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]'),
|
||||
groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]'),
|
||||
nextStepButton = jQuery("a.mailpoet_export_process"),
|
||||
renderSegmentsAndFields = function (container, data) {
|
||||
if (container.data('select2')) {
|
||||
container
|
||||
.html('')
|
||||
.select2('destroy');
|
||||
}
|
||||
container
|
||||
.select2({
|
||||
data: data,
|
||||
width: '20em',
|
||||
templateResult: function (item) {
|
||||
return (item.subscriberCount > 0)
|
||||
? item.name + ' (' + item.subscriberCount + ')'
|
||||
: item.name;
|
||||
},
|
||||
templateSelection: function (item) {
|
||||
return (item.subscriberCount > 0)
|
||||
? item.name + ' (' + item.subscriberCount + ')'
|
||||
: item.name;
|
||||
}
|
||||
})
|
||||
.on('select2:selecting', function (selectEvent) {
|
||||
var selectElement = this,
|
||||
selectedOptionId = selectEvent.params.args.data.id,
|
||||
fieldsToExclude = [
|
||||
'select',
|
||||
'deselect'
|
||||
];
|
||||
if (_.contains(fieldsToExclude, selectedOptionId)) {
|
||||
selectEvent.preventDefault();
|
||||
if (selectedOptionId === 'deselect') {
|
||||
jQuery(selectElement).select2('val', '');
|
||||
} else {
|
||||
var allOptions = [];
|
||||
_.each(container.find('option'), function (field) {
|
||||
if (!_.contains(fieldsToExclude, field.value)) {
|
||||
allOptions.push(field.value);
|
||||
}
|
||||
});
|
||||
jQuery(selectElement).select2('val', allOptions);
|
||||
}
|
||||
jQuery(selectElement).select2('close');
|
||||
}
|
||||
})
|
||||
.on('change', function () {
|
||||
if ((exportData.segments && segmentsContainerElement.select2('data').length && subscriberFieldsContainerElement.select2('data').length)
|
||||
||
|
||||
(!exportData.segments && subscriberFieldsContainerElement.select2('data').length)
|
||||
) {
|
||||
toggleNextStepButton('on');
|
||||
}
|
||||
else {
|
||||
toggleNextStepButton('off');
|
||||
}
|
||||
|
||||
if (segmentsContainerElement.select2('data').length > 1 && exportData.groupBySegmentOption) {
|
||||
jQuery('.mailpoet_group_by_list').show();
|
||||
}
|
||||
else if (exportData.groupBySegmentOption) {
|
||||
jQuery('.mailpoet_group_by_list').hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
renderSegmentsAndFields(subscriberFieldsContainerElement, subscriberFieldsSelect2);
|
||||
renderSegmentsAndFields(segmentsContainerElement, segments);
|
||||
|
||||
subscriberFieldsContainerElement.select2('val', [
|
||||
'status',
|
||||
'email',
|
||||
'first_name',
|
||||
'last_name'
|
||||
]);
|
||||
|
||||
exportConfirmedOptionElement.change(function () {
|
||||
var selectedSegments = segmentsContainerElement.val();
|
||||
if (this.value == 1) {
|
||||
exportData.exportConfirmedOption = true;
|
||||
renderSegmentsAndFields(segmentsContainerElement, segmentsWithConfirmedSubscribers);
|
||||
}
|
||||
else {
|
||||
exportData.exportConfirmedOption = false;
|
||||
renderSegmentsAndFields(segmentsContainerElement, segments);
|
||||
}
|
||||
segmentsContainerElement.select2('val', selectedSegments);
|
||||
});
|
||||
|
||||
function toggleNextStepButton(condition) {
|
||||
var disabled = 'button-disabled';
|
||||
if (condition === 'on') {
|
||||
nextStepButton.removeClass(disabled);
|
||||
}
|
||||
else {
|
||||
nextStepButton.addClass(disabled);
|
||||
}
|
||||
}
|
||||
|
||||
nextStepButton.click(function () {
|
||||
if (jQuery(this).hasClass('button-disabled')) {
|
||||
return;
|
||||
}
|
||||
MailPoet.Modal.loading(true);
|
||||
MailPoet.Ajax
|
||||
.post({
|
||||
endpoint: 'ImportExport',
|
||||
action: 'processExport',
|
||||
data: JSON.stringify({
|
||||
'exportConfirmedOption': exportData.exportConfirmedOption,
|
||||
'exportFormatOption': jQuery(':radio[name="option_format"]:checked').val(),
|
||||
'groupBySegmentOption': (groupBySegmentOptionElement.is(":visible")) ? groupBySegmentOptionElement.prop('checked') : false,
|
||||
'segments': (exportData.segments) ? segmentsContainerElement.val() : false,
|
||||
'subscriberFields': subscriberFieldsContainerElement.val()
|
||||
})
|
||||
})
|
||||
.done(function (response) {
|
||||
MailPoet.Modal.loading(false);
|
||||
if (response.result === false) {
|
||||
MailPoet.Notice.error(response.error);
|
||||
} else {
|
||||
resultMessage = MailPoetI18n.exportMessage
|
||||
.replace('%1$s', '<strong>' + response.data.totalExported + '</strong>')
|
||||
.replace('[link]', '<a href="' + response.data.exportFileURL + '" target="_blank" >')
|
||||
.replace('[/link]', '</a>');
|
||||
jQuery('#export_result_notice > ul > li').html(resultMessage);
|
||||
jQuery('#export_result_notice').show();
|
||||
window.location.href = response.data.exportFileURL;
|
||||
}
|
||||
})
|
||||
.error(function (error) {
|
||||
MailPoet.Modal.loading(false);
|
||||
MailPoet.Notice.error(
|
||||
MailPoetI18n.serverError + error.statusText.toLowerCase() + '.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,10 +1,12 @@
|
||||
define([
|
||||
'react',
|
||||
'react-dom',
|
||||
'jquery',
|
||||
'select2'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
ReactDOM,
|
||||
jQuery
|
||||
) {
|
||||
var Selection = React.createClass({
|
||||
@ -16,50 +18,72 @@ function(
|
||||
},
|
||||
componentDidMount: function() {
|
||||
this.loadCachedItems();
|
||||
},
|
||||
componentDidUpdate: function() {
|
||||
this.setupSelect2();
|
||||
},
|
||||
setupSelect2: function() {
|
||||
if(this.state.initialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.props.field.select2 && Object.keys(this.props.item).length > 0) {
|
||||
var select2 = jQuery('#'+this.props.field.id).select2({
|
||||
width: (this.props.width || ''),
|
||||
templateResult: function(item) {
|
||||
if (item.element && item.element.selected) {
|
||||
return null;
|
||||
} else {
|
||||
return item.text;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
select2.on('change', this.handleChange)
|
||||
|
||||
select2.select2(
|
||||
componentDidUpdate: function(prevProps, prevState) {
|
||||
if(
|
||||
(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]
|
||||
);
|
||||
|
||||
this.setState({ initialized: true });
|
||||
}
|
||||
|
||||
this.setupSelect2();
|
||||
},
|
||||
setupSelect2: function() {
|
||||
if(
|
||||
!this.props.field.multiple
|
||||
|| this.state.initialized === true
|
||||
|| this.refs.select === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
var select2 = jQuery('#'+this.refs.select.id).select2({
|
||||
width: (this.props.width || ''),
|
||||
templateResult: function(item) {
|
||||
if(item.element && item.element.selected) {
|
||||
return null;
|
||||
} else {
|
||||
return item.text;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
select2.on('change', this.handleChange);
|
||||
select2.select2(
|
||||
'val',
|
||||
this.props.item[this.props.field.name]
|
||||
);
|
||||
|
||||
this.setState({ initialized: true });
|
||||
},
|
||||
loadCachedItems: function() {
|
||||
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
|
||||
var items = window['mailpoet_'+this.props.field.endpoint];
|
||||
|
||||
if(this.props.field['filter'] !== undefined) {
|
||||
items = items.filter(this.props.field.filter);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
items: items
|
||||
});
|
||||
}
|
||||
},
|
||||
handleChange: function() {
|
||||
handleChange: function(e) {
|
||||
if(this.props.onValueChange !== undefined) {
|
||||
if(this.props.field.multiple) {
|
||||
value = jQuery('#'+this.refs.select.id).select2('val');
|
||||
} else {
|
||||
value = e.target.value;
|
||||
}
|
||||
this.props.onValueChange({
|
||||
target: {
|
||||
value: jQuery('#'+this.props.field.id).select2('val'),
|
||||
value: value,
|
||||
name: this.props.field.name
|
||||
}
|
||||
});
|
||||
@ -67,36 +91,33 @@ function(
|
||||
return true;
|
||||
},
|
||||
render: function() {
|
||||
if(this.state.items.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
var options = this.state.items.map(function(item, index) {
|
||||
return (
|
||||
<option
|
||||
key={ item.id }
|
||||
value={ item.id }
|
||||
>
|
||||
{ item.name }
|
||||
</option>
|
||||
);
|
||||
});
|
||||
|
||||
var default_value = (
|
||||
(this.props.item !== undefined && this.props.field.name !== undefined)
|
||||
? this.props.item[this.props.field.name]
|
||||
: null
|
||||
);
|
||||
|
||||
var options = this.state.items.map(function(item, index) {
|
||||
return (
|
||||
<select
|
||||
id={ this.props.field.id }
|
||||
placeholder={ this.props.field.placeholder }
|
||||
multiple={ this.props.field.multiple }
|
||||
onChange={ this.handleChange }
|
||||
defaultValue={ default_value }
|
||||
>{ options }</select>
|
||||
<option
|
||||
key={ item.id }
|
||||
value={ item.id }
|
||||
>
|
||||
{ item.name }
|
||||
</option>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var default_value = (
|
||||
(this.props.item !== undefined && this.props.field.name !== undefined)
|
||||
? this.props.item[this.props.field.name]
|
||||
: null
|
||||
);
|
||||
|
||||
return (
|
||||
<select
|
||||
id={ this.props.field.id || this.props.field.name }
|
||||
ref="select"
|
||||
placeholder={ this.props.field.placeholder }
|
||||
multiple={ this.props.field.multiple }
|
||||
onChange={ this.handleChange }
|
||||
defaultValue={ default_value }
|
||||
>{ options }</select>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -88,23 +88,23 @@ define(
|
||||
}).done(function(response) {
|
||||
this.setState({ loading: false });
|
||||
|
||||
if(response === true) {
|
||||
if(response.result === true) {
|
||||
if(this.props.onSuccess !== undefined) {
|
||||
this.props.onSuccess()
|
||||
this.props.onSuccess();
|
||||
} else {
|
||||
this.history.pushState(null, '/')
|
||||
}
|
||||
|
||||
if(this.props.params.id !== undefined) {
|
||||
this.props.messages['updated']();
|
||||
this.props.messages.onUpdate();
|
||||
} else {
|
||||
this.props.messages['created']();
|
||||
this.props.messages.onCreate();
|
||||
}
|
||||
} else {
|
||||
if(response === false) {
|
||||
// unknown error occurred
|
||||
} else {
|
||||
this.setState({ errors: response });
|
||||
if(response.result === false) {
|
||||
if(response.errors.length > 0) {
|
||||
this.setState({ errors: response.errors });
|
||||
}
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
@ -121,13 +121,15 @@ define(
|
||||
return true;
|
||||
},
|
||||
render: function() {
|
||||
var errors = this.state.errors.map(function(error, index) {
|
||||
return (
|
||||
<p key={ 'error-'+index } className="mailpoet_error">
|
||||
{ error }
|
||||
</p>
|
||||
);
|
||||
});
|
||||
if(this.state.errors !== undefined) {
|
||||
var errors = this.state.errors.map(function(error, index) {
|
||||
return (
|
||||
<p key={ 'error-'+index } className="mailpoet_error">
|
||||
{ error }
|
||||
</p>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
var formClasses = classNames(
|
||||
'mailpoet_form',
|
||||
|
@ -1,993 +0,0 @@
|
||||
/*
|
||||
* name: MailPoet Form Editor
|
||||
* author: Jonathan Labreuille
|
||||
* company: Wysija
|
||||
* framework: prototype 1.7.2
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
Event.cacheDelegated = {};
|
||||
Object.extend(document, (function () {
|
||||
var cache = Event.cacheDelegated;
|
||||
|
||||
function getCacheForSelector(selector) {
|
||||
return cache[selector] = cache[selector] || {};
|
||||
}
|
||||
|
||||
function getWrappersForSelector(selector, eventName) {
|
||||
var c = getCacheForSelector(selector);
|
||||
return c[eventName] = c[eventName] || [];
|
||||
}
|
||||
|
||||
function findWrapper(selector, eventName, handler) {
|
||||
var c = getWrappersForSelector(selector, eventName);
|
||||
return c.find(function (wrapper) {
|
||||
return wrapper.handler === handler
|
||||
});
|
||||
}
|
||||
|
||||
function destroyWrapper(selector, eventName, handler) {
|
||||
var c = getCacheForSelector(selector);
|
||||
if (!c[eventName]) return false;
|
||||
var wrapper = findWrapper(selector, eventName, handler)
|
||||
c[eventName] = c[eventName].without(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function createWrapper(selector, eventName, handler, context) {
|
||||
var wrapper, c = getWrappersForSelector(selector, eventName);
|
||||
if (c.pluck('handler').include(handler)) return false;
|
||||
wrapper = function (event) {
|
||||
var element = event.findElement(selector);
|
||||
if (element) handler.call(context || element, event, element);
|
||||
};
|
||||
wrapper.handler = handler;
|
||||
c.push(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
return {
|
||||
delegate: function (selector, eventName, handler, context) {
|
||||
var wrapper = createWrapper.apply(null, arguments);
|
||||
if (wrapper) document.observe(eventName, wrapper);
|
||||
return document;
|
||||
},
|
||||
stopDelegating: function (selector, eventName, handler) {
|
||||
var length = arguments.length;
|
||||
switch (length) {
|
||||
case 2:
|
||||
getWrappersForSelector(selector, eventName).each(function (wrapper) {
|
||||
document.stopDelegating(selector, eventName, wrapper.handler);
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
Object.keys(getCacheForSelector(selector)).each(function (eventName) {
|
||||
document.stopDelegating(selector, eventName);
|
||||
});
|
||||
break;
|
||||
case 0:
|
||||
Object.keys(cache).each(function (selector) {
|
||||
document.stopDelegating(selector);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
var wrapper = destroyWrapper.apply(null, arguments);
|
||||
if (wrapper) document.stopObserving(eventName, wrapper);
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
||||
})());
|
||||
|
||||
var Observable = (function () {
|
||||
function getEventName(name, namespace) {
|
||||
name = name.substring(2);
|
||||
if (namespace) name = namespace + ':' + name;
|
||||
return name.underscore().split('_').join(':');
|
||||
}
|
||||
|
||||
function getHandlers(klass) {
|
||||
var proto = klass.prototype,
|
||||
namespace = proto.namespace;
|
||||
return Object.keys(proto).grep(/^on/).inject($H(), function (handlers, name) {
|
||||
if (name === 'onDomLoaded') return handlers;
|
||||
handlers.set(getEventName(name, namespace), getWrapper(proto[name], klass));
|
||||
return handlers;
|
||||
});
|
||||
}
|
||||
|
||||
function getWrapper(handler, klass) {
|
||||
return function (event) {
|
||||
return handler.call(new klass(this), event, event.memo);
|
||||
}
|
||||
}
|
||||
|
||||
function onDomLoad(selector, klass) {
|
||||
$$(selector).each(function (element) {
|
||||
new klass(element).onDomLoaded();
|
||||
});
|
||||
}
|
||||
return {
|
||||
observe: function (selector) {
|
||||
if (!this.handlers) this.handlers = {};
|
||||
if (this.handlers[selector]) return;
|
||||
var klass = this;
|
||||
if (this.prototype.onDomLoaded) document.loaded ? onDomLoad(selector, klass) : document.observe('dom:loaded', onDomLoad.curry(selector, klass));
|
||||
this.handlers[selector] = getHandlers(klass).each(function (handler) {
|
||||
document.delegate(selector, handler.key, handler.value);
|
||||
});
|
||||
},
|
||||
stopObserving: function (selector) {
|
||||
if (!this.handlers || !this.handlers[selector]) return;
|
||||
this.handlers[selector].each(function (handler) {
|
||||
document.stopDelegating(selector, handler.key, handler.value);
|
||||
});
|
||||
delete this.handlers[selector];
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// override droppables
|
||||
Object.extend(Droppables, {
|
||||
deactivate: Droppables.deactivate.wrap(function (proceed, drop, draggable) {
|
||||
if (drop.onLeave) drop.onLeave(draggable, drop.element);
|
||||
return proceed(drop);
|
||||
}),
|
||||
activate: Droppables.activate.wrap(function (proceed, drop, draggable) {
|
||||
if (drop.onEnter) drop.onEnter(draggable, drop.element);
|
||||
return proceed(drop);
|
||||
}),
|
||||
show: function (point, element) {
|
||||
if (!this.drops.length) return;
|
||||
var drop, affected = [];
|
||||
this.drops.each(function (drop) {
|
||||
if (Droppables.isAffected(point, element, drop)) affected.push(drop);
|
||||
});
|
||||
if (affected.length > 0) drop = Droppables.findDeepestChild(affected);
|
||||
if (this.last_active && this.last_active !== drop) this.deactivate(this.last_active, element);
|
||||
if (drop) {
|
||||
Position.within(drop.element, point[0], point[1]);
|
||||
if (drop.onHover) drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
|
||||
if (drop !== this.last_active) Droppables.activate(drop, element);
|
||||
}
|
||||
},
|
||||
displayArea: function(draggable) {
|
||||
if(!this.drops.length) return;
|
||||
|
||||
// hide controls when displaying drop areas.
|
||||
WysijaForm.hideBlockControls();
|
||||
|
||||
this.drops.each(function (drop, iterator) {
|
||||
if(drop.element.hasClassName('block_placeholder')) {
|
||||
drop.element.addClassName('active');
|
||||
}
|
||||
});
|
||||
},
|
||||
hideArea: function() {
|
||||
if (!this.drops.length) return;
|
||||
this.drops.each(function (drop, iterator) {
|
||||
if(drop.element.hasClassName('block_placeholder')) {
|
||||
drop.element.removeClassName('active');
|
||||
} else if(drop.element.hasClassName('image_placeholder')) {
|
||||
drop.element.removeClassName('active');
|
||||
drop.element.up().removeClassName('active');
|
||||
} else if(drop.element.hasClassName('text_placeholder')) {
|
||||
drop.element.removeClassName('active');
|
||||
}
|
||||
});
|
||||
},
|
||||
reset: function (draggable) {
|
||||
if (this.last_active) this.deactivate(this.last_active, draggable);
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
Wysija History handling
|
||||
POTENTIAL FEATURES:
|
||||
- set a maximum number of items to be stored
|
||||
|
||||
*/
|
||||
var WysijaHistory = {
|
||||
container: 'mailpoet_form_history',
|
||||
size: 30,
|
||||
enqueue: function(element) {
|
||||
// create deep clone (includes child elements) of passed element
|
||||
var clone = element.clone(true);
|
||||
|
||||
// check if the field is unique
|
||||
if(parseInt(clone.readAttribute('wysija_unique'), 10) === 1) {
|
||||
// check if the field is already in the queue
|
||||
$(WysijaHistory.container).select('[wysija_field="'+clone.readAttribute('wysija_field')+'"]').invoke('remove');
|
||||
}
|
||||
|
||||
// check history size
|
||||
if($(WysijaHistory.container).select('> div').length >= WysijaHistory.size) {
|
||||
// remove oldest element (last in the list)
|
||||
$(WysijaHistory.container).select('> div').last().remove();
|
||||
}
|
||||
|
||||
// store block in history
|
||||
$(WysijaHistory.container).insert({ top: clone });
|
||||
},
|
||||
dequeue: function() {
|
||||
// pop last block off the history
|
||||
var block = $(WysijaHistory.container).select('div').first();
|
||||
|
||||
if(block !== undefined) {
|
||||
// insert block back into the editor
|
||||
$(WysijaForm.options.body).insert({top: block});
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
$(WysijaHistory.container).innerHTML = '';
|
||||
},
|
||||
remove: function(field) {
|
||||
$(WysijaHistory.container).select('[wysija_field="'+field+'"]').invoke('remove');
|
||||
}
|
||||
};
|
||||
|
||||
/* MailPoet Form */
|
||||
var WysijaForm = {
|
||||
version: '0.6',
|
||||
options: {
|
||||
container: 'mailpoet_form_container',
|
||||
editor: 'mailpoet_form_editor',
|
||||
body: 'mailpoet_form_body',
|
||||
toolbar: 'mailpoet_form_toolbar',
|
||||
templates: 'wysija_widget_templates',
|
||||
debug: false
|
||||
},
|
||||
toolbar: {
|
||||
effect: null,
|
||||
x: null,
|
||||
y: null,
|
||||
top: null,
|
||||
left: null
|
||||
},
|
||||
scroll: {
|
||||
top: 0,
|
||||
left: 0
|
||||
},
|
||||
flags: {
|
||||
doSave: false
|
||||
},
|
||||
locks: {
|
||||
dragging: false,
|
||||
selectingColor: false,
|
||||
showingTools: false
|
||||
},
|
||||
encodeHtmlValue: function(str) {
|
||||
return str.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"');
|
||||
// ": fix for FileMerge because the previous line fucks up its syntax coloring
|
||||
},
|
||||
decodeHtmlValue: function(str) {
|
||||
return str.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"');
|
||||
// ": fix for FileMerge because the previous line fucks up its syntax coloring
|
||||
},
|
||||
loading: function(is_loading) {
|
||||
if(is_loading) {
|
||||
$(WysijaForm.options.editor).addClassName('loading');
|
||||
$(WysijaForm.options.toolbar).addClassName('loading');
|
||||
} else {
|
||||
$(WysijaForm.options.editor).removeClassName('loading');
|
||||
$(WysijaForm.options.toolbar).removeClassName('loading');
|
||||
}
|
||||
},
|
||||
loadStatic: function(blocks) {
|
||||
$A(blocks).each(function(block) {
|
||||
// create block
|
||||
WysijaForm.Block.create(block, $('block_placeholder'));
|
||||
});
|
||||
},
|
||||
load: function(form) {
|
||||
if(form.data === undefined) return;
|
||||
|
||||
// load body
|
||||
if(form.data.body !== undefined) {
|
||||
$A(form.data.body).each(function(block) {
|
||||
// create block
|
||||
WysijaForm.Block.create(block, $('block_placeholder'));
|
||||
});
|
||||
|
||||
// load settings
|
||||
var settings_elements = $('mailpoet_form_settings').getElements();
|
||||
settings_elements.each(function(setting) {
|
||||
// skip lists
|
||||
if(setting.name === 'lists') {
|
||||
return true;
|
||||
} else if(setting.name === 'on_success') {
|
||||
// if the input value is equal to the one stored in the settings
|
||||
if(setting.value === form.data.settings[setting.name]) {
|
||||
// check selected value
|
||||
$(setting).checked = true;
|
||||
}
|
||||
} else if(form.data.settings[setting.name] !== undefined) {
|
||||
if(typeof form.data.settings[setting.name] === 'string') {
|
||||
setting.setValue(WysijaForm.decodeHtmlValue(form.data.settings[setting.name]));
|
||||
} else {
|
||||
setting.setValue(form.data.settings[setting.name]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
save: function() {
|
||||
var position = 1,
|
||||
data = {
|
||||
'version': WysijaForm.version,
|
||||
'settings': $('mailpoet_form_settings').serialize(true),
|
||||
'body': [],
|
||||
'styles': (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
|
||||
};
|
||||
// body
|
||||
WysijaForm.getBlocks().each(function(b) {
|
||||
var block_data = (typeof(b.block['save']) === 'function') ? b.block.save() : null;
|
||||
|
||||
if(block_data !== null) {
|
||||
// set block position
|
||||
block_data['position'] = position;
|
||||
|
||||
// increment position
|
||||
position++;
|
||||
|
||||
// add block data to body
|
||||
data['body'].push(block_data);
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
init: function() {
|
||||
// set document scroll
|
||||
info('init -> set scroll offsets');
|
||||
WysijaForm.setScrollOffsets();
|
||||
|
||||
// position toolbar
|
||||
info('init -> set toolbar position');
|
||||
WysijaForm.setToolbarPosition();
|
||||
|
||||
// enable droppable targets
|
||||
info('init -> make droppable');
|
||||
WysijaForm.makeDroppable();
|
||||
|
||||
// enable sortable
|
||||
info('init -> make sortable');
|
||||
WysijaForm.makeSortable();
|
||||
|
||||
// hide controls
|
||||
info('init -> hide controls');
|
||||
WysijaForm.hideControls();
|
||||
|
||||
// hide settings
|
||||
info('init -> hide settings');
|
||||
WysijaForm.hideSettings();
|
||||
|
||||
// set settings buttons position
|
||||
info('init -> init settings');
|
||||
WysijaForm.setSettingsPosition();
|
||||
|
||||
// toggle widgets
|
||||
info('init -> toggle widgets');
|
||||
WysijaForm.toggleWidgets();
|
||||
},
|
||||
getFieldData: function(element) {
|
||||
// get basic field data
|
||||
var data = {
|
||||
type: element.readAttribute('wysija_type'),
|
||||
field: element.readAttribute('wysija_field'),
|
||||
name: element.readAttribute('wysija_name'),
|
||||
unique: parseInt(element.readAttribute('wysija_unique') || 0, 10),
|
||||
static: parseInt(element.readAttribute('wysija_static') || 0, 10),
|
||||
element: element,
|
||||
params: ''
|
||||
};
|
||||
|
||||
// get params (may be empty)
|
||||
if(element.readAttribute('wysija_params') !== null && element.readAttribute('wysija_params').length > 0) {
|
||||
data.params = JSON.parse(element.readAttribute('wysija_params'));
|
||||
}
|
||||
return data;
|
||||
},
|
||||
toggleWidgets: function() {
|
||||
$$('a[wysija_unique="1"]').invoke('removeClassName', 'disabled');
|
||||
|
||||
// loop through each unique field already inserted in the editor and disable its toolbar equivalent
|
||||
$$('#'+WysijaForm.options.editor+' [wysija_unique="1"]').each(function(element) {
|
||||
var field = $$('#'+WysijaForm.options.toolbar+' [wysija_field="'+element.readAttribute('wysija_field')+'"]').first();
|
||||
if(field !== undefined) {
|
||||
field.addClassName('disabled');
|
||||
}
|
||||
});
|
||||
|
||||
// hide list selection if a list widget has been dragged into the editor
|
||||
$('mailpoet_settings_list_selection')[(($$('#'+WysijaForm.options.editor+' [wysija_field="list"]').length > 0) === true) ? 'hide': 'show']();
|
||||
},
|
||||
setBlockPositions: function(event, target) {
|
||||
// release dragging lock
|
||||
WysijaForm.locks.dragging = false;
|
||||
|
||||
var index = 1;
|
||||
WysijaForm.getBlocks().each(function (container) {
|
||||
container.setPosition(index++);
|
||||
// remove z-index value to avoid issues when resizing images
|
||||
if(container['block'] !== undefined) {
|
||||
container.block.element.setStyle({zIndex: ''});
|
||||
}
|
||||
});
|
||||
|
||||
if(target !== undefined) {
|
||||
// get placeholders (previous placeholder matches the placeholder linked to the next block)
|
||||
var block_placeholder = $(target.element.readAttribute('wysija_placeholder')),
|
||||
previous_placeholder = target.element.previous('.block_placeholder');
|
||||
|
||||
if(block_placeholder !== null) {
|
||||
// put block placeholder before the current block
|
||||
target.element.insert({before: block_placeholder});
|
||||
|
||||
// if the next block is a wysija_block, insert previous placeholder
|
||||
if(target.element.next() !== undefined && target.element.next().hasClassName('mailpoet_form_block') && previous_placeholder !== undefined) {
|
||||
target.element.insert({after: previous_placeholder});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setScrollOffsets: function() {
|
||||
WysijaForm.scroll = document.viewport.getScrollOffsets();
|
||||
},
|
||||
hideSettings: function() {
|
||||
$(WysijaForm.options.container).select('.wysija_settings').invoke('hide');
|
||||
},
|
||||
setSettingsPosition: function() {
|
||||
// get viewport offsets and dimensions
|
||||
var viewportHeight = document.viewport.getHeight(),
|
||||
blockPadding = 5;
|
||||
|
||||
$(WysijaForm.options.container).select('.wysija_settings').each(function(element) {
|
||||
// get parent dimensions and position
|
||||
var parentDim = element.up('.mailpoet_form_block').getDimensions(),
|
||||
parentPos = element.up('.mailpoet_form_block').cumulativeOffset(),
|
||||
is_visible = (parentPos.top <= (WysijaForm.scroll.top + viewportHeight)) ? true : false,
|
||||
buttonMargin = 5,
|
||||
relativeTop = buttonMargin;
|
||||
|
||||
if(is_visible) {
|
||||
// desired position is set to center of viewport
|
||||
var absoluteTop = parseInt(WysijaForm.scroll.top + ((viewportHeight / 2) - (element.getHeight() / 2)), 10),
|
||||
parentTop = parseInt(parentPos.top - blockPadding, 10),
|
||||
parentBottom = parseInt(parentPos.top + parentDim.height - blockPadding, 10);
|
||||
|
||||
// always center
|
||||
relativeTop = parseInt((parentDim.height / 2) - (element.getHeight() / 2), 10);
|
||||
}
|
||||
// set position for button
|
||||
$(element).setStyle({
|
||||
left: parseInt((parentDim.width / 2) - (element.getWidth() / 2)) + 'px',
|
||||
top: relativeTop + 'px'
|
||||
});
|
||||
});
|
||||
},
|
||||
initToolbarPosition: function() {
|
||||
if(WysijaForm.toolbar.top === null) WysijaForm.toolbar.top = parseInt($(WysijaForm.options.container).positionedOffset().top);
|
||||
if(WysijaForm.toolbar.y === null) WysijaForm.toolbar.y = parseInt(WysijaForm.toolbar.top);
|
||||
|
||||
if(isRtl) {
|
||||
if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = 0;
|
||||
} else {
|
||||
if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = parseInt($(WysijaForm.options.container).positionedOffset().left);
|
||||
}
|
||||
if(WysijaForm.toolbar.x === null) WysijaForm.toolbar.x = parseInt(WysijaForm.toolbar.left + $(WysijaForm.options.container).getDimensions().width + 15);
|
||||
|
||||
},
|
||||
setToolbarPosition: function() {
|
||||
WysijaForm.initToolbarPosition();
|
||||
|
||||
var position = { top: WysijaForm.toolbar.y + 'px', visibility: 'visible' };
|
||||
|
||||
if(isRtl) {
|
||||
position.right = WysijaForm.toolbar.x + 'px';
|
||||
} else {
|
||||
position.left = WysijaForm.toolbar.x + 'px';
|
||||
}
|
||||
|
||||
$(WysijaForm.options.toolbar).setStyle(position);
|
||||
},
|
||||
updateToolbarPosition: function() {
|
||||
// init toolbar position (updates scroll and toolbar y)
|
||||
WysijaForm.initToolbarPosition();
|
||||
|
||||
// cancel previous effect
|
||||
if(WysijaForm.toolbar.effect !== null) WysijaForm.toolbar.effect.cancel();
|
||||
|
||||
if(WysijaForm.scroll.top >= (WysijaForm.toolbar.top - 20)) {
|
||||
WysijaForm.toolbar.y = parseInt(20 + WysijaForm.scroll.top);
|
||||
// start effect
|
||||
WysijaForm.toolbar.effect = new Effect.Move(WysijaForm.options.toolbar, {
|
||||
x: WysijaForm.toolbar.x,
|
||||
y: WysijaForm.toolbar.y,
|
||||
mode: 'absolute',
|
||||
duration: 0.2
|
||||
});
|
||||
} else {
|
||||
$(WysijaForm.options.toolbar).setStyle({
|
||||
left: WysijaForm.toolbar.x + 'px',
|
||||
top: WysijaForm.toolbar.top + 'px'
|
||||
});
|
||||
}
|
||||
},
|
||||
blockDropOptions: {
|
||||
accept: $w('mailpoet_form_field'), // acceptable items (classes array)
|
||||
onEnter: function (draggable, droppable) {
|
||||
$(droppable).addClassName('hover');
|
||||
},
|
||||
onLeave: function (draggable, droppable) {
|
||||
$(droppable).removeClassName('hover');
|
||||
},
|
||||
onDrop: function (draggable, droppable) {
|
||||
// custom data for images
|
||||
droppable.fire('wjfe:item:drop', WysijaForm.getFieldData(draggable));
|
||||
$(droppable).removeClassName('hover');
|
||||
}
|
||||
},
|
||||
hideControls: function() {
|
||||
try {
|
||||
return WysijaForm.getBlocks().invoke('hideControls');
|
||||
} catch(e) { return; }
|
||||
},
|
||||
hideTools: function() {
|
||||
$$('.wysija_tools').invoke('hide');
|
||||
WysijaForm.locks.showingTools = false;
|
||||
},
|
||||
instances: {},
|
||||
get: function (element, type) {
|
||||
if(type === undefined) type = 'block';
|
||||
// identify element
|
||||
var id = element.identify();
|
||||
var instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
|
||||
|
||||
WysijaForm.instances[id] = instance;
|
||||
return instance;
|
||||
},
|
||||
makeDroppable: function() {
|
||||
Droppables.add('block_placeholder', WysijaForm.blockDropOptions);
|
||||
},
|
||||
makeSortable: function () {
|
||||
var body = $(WysijaForm.options.body);
|
||||
Sortable.create(body, {
|
||||
tag: 'div',
|
||||
only: 'mailpoet_form_block',
|
||||
scroll: window,
|
||||
handle: 'handle',
|
||||
constraint: 'vertical'
|
||||
|
||||
});
|
||||
Draggables.removeObserver(body);
|
||||
Draggables.addObserver({
|
||||
element: body,
|
||||
onStart: WysijaForm.startBlockPositions,
|
||||
onEnd: WysijaForm.setBlockPositions
|
||||
});
|
||||
},
|
||||
hideBlockControls: function() {
|
||||
$$('.wysija_controls').invoke('hide');
|
||||
this.getBlockElements().invoke('removeClassName', 'hover');
|
||||
},
|
||||
getBlocks: function () {
|
||||
return WysijaForm.getBlockElements().map(function (element) {
|
||||
return WysijaForm.get(element);
|
||||
});
|
||||
},
|
||||
getBlockElements: function () {
|
||||
return $(WysijaForm.options.container).select('.mailpoet_form_block');
|
||||
},
|
||||
startBlockPositions: function(event, target) {
|
||||
if(target.element.hasClassName('mailpoet_form_block')) {
|
||||
// store block placeholder id for the block that is being repositionned
|
||||
if(target.element.previous('.block_placeholder') !== undefined) {
|
||||
target.element.writeAttribute('wysija_placeholder', target.element.previous('.block_placeholder').identify());
|
||||
}
|
||||
}
|
||||
WysijaForm.locks.dragging = true;
|
||||
},
|
||||
encodeURIComponent: function(str) {
|
||||
// check if it's a url and if so, prevent encoding of protocol
|
||||
var regexp = new RegExp(/^http[s]?:\/\//),
|
||||
protocol = regexp.exec(str);
|
||||
|
||||
if(protocol === null) {
|
||||
// this is not a url so encode the whole thing
|
||||
return encodeURIComponent(str).replace(/[!'()*]/g, escape);
|
||||
} else if(protocol.length === 1) {
|
||||
// this is a url, so do not encode the protocol
|
||||
return encodeURI(str).replace(/[!'()*]/g, escape);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
WysijaForm.DraggableItem = Class.create({
|
||||
initialize: function (element) {
|
||||
this.elementType = $(element).readAttribute('wysija_type');
|
||||
this.element = $(element).down() || $(element);
|
||||
this.clone = this.cloneElement();
|
||||
this.insert();
|
||||
},
|
||||
STYLES: new Template('position: absolute; top: #{top}px; left: #{left}px;'),
|
||||
cloneElement: function () {
|
||||
var clone = this.element.clone(),
|
||||
offset = this.element.cumulativeOffset(),
|
||||
list = this.getList(),
|
||||
styles = this.STYLES.evaluate({
|
||||
top: offset.top - list.scrollTop,
|
||||
left: offset.left - list.scrollLeft
|
||||
});
|
||||
clone.setStyle(styles);
|
||||
|
||||
clone.addClassName('mailpoet_form_widget');
|
||||
clone.addClassName(this.elementType);
|
||||
clone.innerHTML = this.element.innerHTML;
|
||||
return clone;
|
||||
},
|
||||
getOffset: function () {
|
||||
return this.element.offsetTop - this.getList().scrollTop;
|
||||
},
|
||||
getList: function () {
|
||||
return this.element.up('ul');
|
||||
},
|
||||
insert: function () {
|
||||
$$("body")[0].insert(this.clone);
|
||||
},
|
||||
onMousedown: function (event) {
|
||||
var draggable = new Draggable(this.clone, {
|
||||
scroll: window,
|
||||
onStart: function () {
|
||||
Droppables.displayArea(draggable);
|
||||
},
|
||||
onEnd: function (drag) {
|
||||
drag.destroy();
|
||||
drag.element.remove();
|
||||
Droppables.hideArea();
|
||||
},
|
||||
starteffect: function (element) {
|
||||
new Effect.Opacity(element, {
|
||||
duration: 0.2,
|
||||
from: element.getOpacity(),
|
||||
to: 0.7
|
||||
});
|
||||
},
|
||||
endeffect: Prototype.emptyFunction
|
||||
});
|
||||
draggable.initDrag(event);
|
||||
draggable.startDrag(event);
|
||||
return draggable;
|
||||
}
|
||||
});
|
||||
Object.extend(WysijaForm.DraggableItem, Observable).observe('a[class="mailpoet_form_field"]');
|
||||
|
||||
|
||||
WysijaForm.Block = Class.create({
|
||||
/* Invoked on load */
|
||||
initialize: function(element) {
|
||||
info('block -> init');
|
||||
|
||||
this.element = $(element);
|
||||
this.block = new WysijaForm.Widget(this.element);
|
||||
|
||||
// enable block placeholder
|
||||
this.block.makeBlockDroppable();
|
||||
|
||||
// setup events
|
||||
if(this.block['setup'] !== undefined) {
|
||||
this.block.setup();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
setPosition: function(position) {
|
||||
this.element.writeAttribute('wysija_position', position);
|
||||
},
|
||||
hideControls: function() {
|
||||
if(this['getControls']) {
|
||||
this.element.removeClassName('hover');
|
||||
this.getControls().hide();
|
||||
}
|
||||
},
|
||||
showControls: function() {
|
||||
if(this['getControls']) {
|
||||
this.element.addClassName('hover');
|
||||
try {
|
||||
this.getControls().show();
|
||||
} catch(e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
},
|
||||
makeBlockDroppable: function() {
|
||||
if(this.isBlockDroppableEnabled() === false) {
|
||||
var block_placeholder = this.getBlockDroppable();
|
||||
Droppables.add(block_placeholder.identify(), WysijaForm.blockDropOptions);
|
||||
block_placeholder.addClassName('enabled');
|
||||
}
|
||||
},
|
||||
removeBlockDroppable: function() {
|
||||
if(this.isBlockDroppableEnabled()) {
|
||||
var block_placeholder = this.getBlockDroppable();
|
||||
Droppables.remove(block_placeholder.identify());
|
||||
block_placeholder.removeClassName('enabled');
|
||||
}
|
||||
},
|
||||
isBlockDroppableEnabled: function() {
|
||||
// if the block_placeholder does not exist, create it
|
||||
var block_placeholder = this.getBlockDroppable();
|
||||
if(block_placeholder === null) {
|
||||
return this.createBlockDroppable().hasClassName('enabled');
|
||||
} else {
|
||||
return block_placeholder.hasClassName('enabled');
|
||||
}
|
||||
},
|
||||
createBlockDroppable: function() {
|
||||
info('block -> createBlockDroppable');
|
||||
this.element.insert({before: '<div class=\"block_placeholder\">'+$('block_placeholder').innerHTML+'</div>'});
|
||||
return this.element.previous('.block_placeholder');
|
||||
},
|
||||
getBlockDroppable: function() {
|
||||
if(this.element.previous() === undefined || this.element.previous().hasClassName('block_placeholder') === false) {
|
||||
return null;
|
||||
} else {
|
||||
return this.element.previous();
|
||||
}
|
||||
},
|
||||
getControls: function() {
|
||||
return this.element.down('.wysija_controls');
|
||||
},
|
||||
setupControls: function() {
|
||||
// enable controls
|
||||
this.controls = this.getControls();
|
||||
|
||||
if(this.controls) {
|
||||
// setup events for block controls
|
||||
this.element.observe('mouseover', function() {
|
||||
// special cases where controls shouldn't be displayed
|
||||
if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true || WysijaForm.locks.showingTools === true) return;
|
||||
|
||||
// set block flag
|
||||
this.element.addClassName('hover');
|
||||
|
||||
// show controls
|
||||
this.showControls();
|
||||
|
||||
// show settings if present
|
||||
if(this.element.down('.wysija_settings') !== undefined) {
|
||||
this.element.down('.wysija_settings').show();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.element.observe('mouseout', function() {
|
||||
// special cases where controls shouldn't hide
|
||||
if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true) return;
|
||||
|
||||
// hide controls
|
||||
this.hideControls();
|
||||
|
||||
// hide settings if present
|
||||
if(this.element.down('.wysija_settings') !== undefined) {
|
||||
this.element.down('.wysija_settings').hide();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
|
||||
// setup click event for remove button
|
||||
this.removeButton = this.controls.down('.remove') || null;
|
||||
if(this.removeButton !== null) {
|
||||
this.removeButton.observe('click', function() {
|
||||
this.removeBlock();
|
||||
this.removeButton.stopObserving('click');
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// setup click event for settings button
|
||||
this.settingsButton = this.element.down('.settings') || null;
|
||||
|
||||
if(this.settingsButton !== null) {
|
||||
this.settingsButton.observe('click', function(event) {
|
||||
// TODO: refactor
|
||||
var block = $(event.target).up('.mailpoet_form_block') || null;
|
||||
if(block !== null) {
|
||||
var field = WysijaForm.getFieldData(block);
|
||||
this.editSettings();
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
removeBlock: function(callback) {
|
||||
info('block -> removeBlock');
|
||||
|
||||
// save block in history
|
||||
WysijaHistory.enqueue(this.element);
|
||||
|
||||
Effect.Fade(this.element.identify(), {
|
||||
duration: 0.2,
|
||||
afterFinish: function(effect) {
|
||||
if(effect.element.next('.mailpoet_form_block') !== undefined && callback !== false) {
|
||||
// show controls of next block to allow mass delete
|
||||
WysijaForm.get(effect.element.next('.mailpoet_form_block')).block.showControls();
|
||||
}
|
||||
// remove placeholder
|
||||
if(effect.element.previous('.block_placeholder') !== undefined) {
|
||||
effect.element.previous('.block_placeholder').remove();
|
||||
}
|
||||
|
||||
// remove element from the DOM
|
||||
this.element.remove();
|
||||
|
||||
// reset block positions
|
||||
WysijaForm.setBlockPositions();
|
||||
|
||||
// toggle widgets
|
||||
WysijaForm.toggleWidgets();
|
||||
|
||||
// optional callback execution after completely removing block
|
||||
if(callback !== undefined && typeof(callback) === 'function') {
|
||||
callback();
|
||||
}
|
||||
|
||||
// remove block instance
|
||||
delete WysijaForm.instances[this.element.identify()];
|
||||
}.bind(this)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/* Invoked on item dropped */
|
||||
WysijaForm.Block.create = function(block, target) {
|
||||
if($('form_template_'+block.type) === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var body = $(WysijaForm.options.body),
|
||||
block_template = Handlebars.compile($('form_template_block').innerHTML),
|
||||
template = Handlebars.compile($('form_template_'+block.type).innerHTML),
|
||||
output = '';
|
||||
|
||||
// set block template (depending on the block type)
|
||||
block.template = template(block);
|
||||
output = block_template(block);
|
||||
|
||||
// check if the new block is unique and if there's already an instance
|
||||
// of it in the history. If so, remove its former instance from the history
|
||||
if(block.unique === 1) {
|
||||
WysijaHistory.remove(block.field);
|
||||
}
|
||||
|
||||
// if the drop target was the bottom placeholder
|
||||
if(target.identify() === 'block_placeholder') {
|
||||
// insert block at the bottom
|
||||
body.insert(output);
|
||||
//block = body.childElements().last();
|
||||
} else {
|
||||
// insert block before the drop target
|
||||
target.insert({before: output });
|
||||
//block = target.previous('.mailpoet_form_block');
|
||||
}
|
||||
// refresh sortable items
|
||||
WysijaForm.makeSortable();
|
||||
|
||||
// refresh block positions
|
||||
WysijaForm.setBlockPositions();
|
||||
|
||||
// position settings
|
||||
WysijaForm.setSettingsPosition();
|
||||
};
|
||||
|
||||
document.observe('wjfe:item:drop', function(event) {
|
||||
info('create block');
|
||||
WysijaForm.Block.create(event.memo, event.target);
|
||||
|
||||
// hide block controls
|
||||
info('hide controls');
|
||||
WysijaForm.hideBlockControls();
|
||||
|
||||
// toggle widgets
|
||||
setTimeout(function() {
|
||||
WysijaForm.toggleWidgets();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
/* Form Widget */
|
||||
WysijaForm.Widget = Class.create(WysijaForm.Block, {
|
||||
initialize: function(element) {
|
||||
info('widget -> init');
|
||||
this.element = $(element);
|
||||
return this;
|
||||
},
|
||||
setup: function() {
|
||||
info('widget -> setup');
|
||||
this.setupControls();
|
||||
},
|
||||
save: function() {
|
||||
info('widget -> save');
|
||||
var data = this.getData();
|
||||
|
||||
if(data.element !== undefined) {
|
||||
delete data.element;
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
setData: function(data) {
|
||||
var current_data = this.getData(),
|
||||
params = $H(current_data.params).merge(data.params).toObject();
|
||||
|
||||
// update type if it changed
|
||||
if(data.type !== undefined && data.type !== current_data.type) {
|
||||
this.element.writeAttribute('wysija_type', data.type);
|
||||
}
|
||||
|
||||
// update params
|
||||
this.element.writeAttribute('wysija_params', JSON.stringify(params));
|
||||
},
|
||||
getData: function() {
|
||||
var data = WysijaForm.getFieldData(this.element);
|
||||
|
||||
// decode params
|
||||
if(data.params.length > 0) {
|
||||
data.params = JSON.parse(data.params);
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
getControls: function() {
|
||||
return this.element.down('.wysija_controls');
|
||||
},
|
||||
remove: function() {
|
||||
this.removeBlock();
|
||||
},
|
||||
redraw: function(data) {
|
||||
// set parameters
|
||||
this.setData(data);
|
||||
var options = this.getData();
|
||||
// redraw block
|
||||
var block_template = Handlebars.compile($('form_template_block').innerHTML),
|
||||
template = Handlebars.compile($('form_template_'+options.type).innerHTML),
|
||||
data = $H(options).merge({ template: template(options) }).toObject();
|
||||
this.element.replace(block_template(data));
|
||||
|
||||
WysijaForm.init();
|
||||
},
|
||||
editSettings: function() {
|
||||
MailPoet.Modal.popup({
|
||||
title: 'Edit field settings', // TODO: translate!
|
||||
template: jQuery('#form_template_field_settings').html(),
|
||||
data: this.getData(),
|
||||
onSuccess: function() {
|
||||
var data = jQuery('#form_field_settings').serializeObject();
|
||||
this.redraw(data);
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
getSettings: function() {
|
||||
return this.element.down('.wysija_settings');
|
||||
}
|
||||
});
|
||||
|
||||
/* When dom is loaded, initialize WysijaForm */
|
||||
document.observe('dom:loaded', WysijaForm.init);
|
||||
|
||||
/* LOGGING */
|
||||
function info(value) {
|
||||
if(WysijaForm.options.debug === false) return;
|
||||
|
||||
if(!(window.console && console.log)) {
|
||||
(function() {
|
||||
var noop = function() {};
|
||||
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
|
||||
var length = methods.length;
|
||||
var console = window.console = {};
|
||||
while(length--) {
|
||||
console[methods[length]] = noop;
|
||||
}
|
||||
}());
|
||||
}
|
||||
try {
|
||||
console.log('[DEBUG] '+value);
|
||||
} catch(e) {}
|
||||
}
|
1026
assets/js/src/form_editor/form_editor.js
Normal file
1026
assets/js/src/form_editor/form_editor.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,56 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, History } from 'react-router'
|
||||
import MailPoet from 'mailpoet'
|
||||
import Form from 'form/form.jsx'
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
type: 'selection',
|
||||
endpoint: 'segments'
|
||||
}
|
||||
]
|
||||
|
||||
const messages = {
|
||||
updated: function() {
|
||||
MailPoet.Notice.success('Form successfully updated!');
|
||||
},
|
||||
created: function() {
|
||||
MailPoet.Notice.success('Form successfully added!');
|
||||
}
|
||||
}
|
||||
|
||||
const FormForm = React.createClass({
|
||||
mixins: [
|
||||
History
|
||||
],
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Form <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
endpoint="forms"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
onSuccess={ this.history.goBack } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = FormForm
|
@ -2,7 +2,6 @@ import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, Route, IndexRoute } from 'react-router'
|
||||
import FormList from 'forms/list.jsx'
|
||||
import FormForm from 'forms/form.jsx'
|
||||
import createHashHistory from 'history/lib/createHashHistory'
|
||||
|
||||
let history = createHashHistory({ queryKey: false })
|
||||
@ -20,8 +19,6 @@ if(container) {
|
||||
<Router history={ history }>
|
||||
<Route path="/" component={ App }>
|
||||
<IndexRoute component={ FormList } />
|
||||
<Route path="new" component={ FormForm } />
|
||||
<Route path="edit/:id" component={ FormForm } />
|
||||
<Route path="*" component={ FormList } />
|
||||
</Route>
|
||||
</Router>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, Link, History } from 'react-router'
|
||||
import { Router, Link } from 'react-router'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import classNames from 'classnames'
|
||||
import MailPoet from 'mailpoet'
|
||||
@ -11,6 +11,11 @@ const columns = [
|
||||
label: 'Name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
@ -20,57 +25,57 @@ const columns = [
|
||||
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
let count = ~~response.forms;
|
||||
let message = null;
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form was moved to the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms were moved to the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
message = (
|
||||
'1 form was moved to the trash.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d forms were moved to the trash.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDelete: function(response) {
|
||||
let count = ~~response.forms;
|
||||
let message = null;
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form was permanently deleted.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms were permanently deleted.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
message = (
|
||||
'1 form was permanently deleted.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d forms were permanently deleted.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onRestore: function(response) {
|
||||
let count = ~~response.forms;
|
||||
let message = null;
|
||||
if(response) {
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form has been restored from the trash.'
|
||||
);
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms have been restored from the trash.'
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
message = (
|
||||
'1 form has been restored from the trash.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
message = (
|
||||
'%$1d forms have been restored from the trash.'
|
||||
).replace('%$1d', count);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -78,32 +83,26 @@ const messages = {
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
link: function(item) {
|
||||
return (
|
||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
||||
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>Edit</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'duplicate_form',
|
||||
refresh: true,
|
||||
link: function(item) {
|
||||
return (
|
||||
<a
|
||||
href="javascript:;"
|
||||
onClick={ this.onDuplicate.bind(null, item) }
|
||||
>Duplicate</a>
|
||||
);
|
||||
},
|
||||
onDuplicate: function(item) {
|
||||
MailPoet.Ajax.post({
|
||||
label: 'Duplicate',
|
||||
onClick: function(item, refresh) {
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'forms',
|
||||
action: 'duplicate',
|
||||
data: item.id
|
||||
}).done(function() {
|
||||
}).done(function(response) {
|
||||
MailPoet.Notice.success(
|
||||
('List "%$1s" has been duplicated.').replace('%$1s', item.name)
|
||||
('Form "%$1s" has been duplicated.').replace('%$1s', response.name)
|
||||
);
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -113,17 +112,22 @@ const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
getData: function() {
|
||||
return {
|
||||
confirm: false
|
||||
}
|
||||
},
|
||||
onSuccess: messages.onDelete
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
|
||||
const FormList = React.createClass({
|
||||
renderItem: function(form, actions) {
|
||||
createForm() {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'forms',
|
||||
action: 'create'
|
||||
}).done(function(response) {
|
||||
if(response !== false) {
|
||||
window.location = response;
|
||||
}
|
||||
});
|
||||
},
|
||||
renderItem(form, actions) {
|
||||
let row_classes = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
@ -157,10 +161,16 @@ const FormList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Forms <Link className="add-new-h2" to="/new">New</Link>
|
||||
Forms <a
|
||||
className="add-new-h2"
|
||||
href="javascript:;"
|
||||
onClick={ this.createForm }
|
||||
>New</a>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
location={ this.props.location }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
search={ false }
|
||||
limit={ 1000 }
|
||||
|
3
assets/js/src/helpscout.js
Normal file
3
assets/js/src/helpscout.js
Normal file
@ -0,0 +1,3 @@
|
||||
define([], function() {
|
||||
!function(e,o,n){window.HSCW=o,window.HS=n,n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={},t.readyQueue=[],t.config=function(e){this.userConfig=e},t.ready=function(e){this.readyQueue.push(e)},o.config={docs:{enabled:!1,baseUrl:""},contact:{enabled:!0,formId:"e5c408c7-895e-11e5-9e75-0a7d6919297d"}};var r=e.getElementsByTagName("script")[0],c=e.createElement("script");c.type="text/javascript",c.async=!0,c.src="https://djtflbt20bdde.cloudfront.net/",r.parentNode.insertBefore(c,r)}(document,window.HSCW||{},window.HS||{});
|
||||
});
|
1131
assets/js/src/import/import.js
Normal file
1131
assets/js/src/import/import.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -15,16 +15,16 @@ function(
|
||||
this.setState({
|
||||
action: e.target.value,
|
||||
extra: false
|
||||
});
|
||||
}, function() {
|
||||
var action = this.getSelectedAction();
|
||||
|
||||
var action = this.getSelectedAction();
|
||||
|
||||
// action on select callback
|
||||
if(action !== null && action['onSelect'] !== undefined) {
|
||||
this.setState({
|
||||
extra: action.onSelect(e)
|
||||
});
|
||||
}
|
||||
// action on select callback
|
||||
if(action !== null && action['onSelect'] !== undefined) {
|
||||
this.setState({
|
||||
extra: action.onSelect(e)
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
handleApplyAction: function(e) {
|
||||
e.preventDefault();
|
||||
@ -85,7 +85,12 @@ function(
|
||||
Select bulk action
|
||||
</label>
|
||||
|
||||
<select ref="action" value={ this.state.action } onChange={this.handleChangeAction}>
|
||||
<select
|
||||
name="bulk_actions"
|
||||
ref="action"
|
||||
value={ this.state.action }
|
||||
onChange={this.handleChangeAction}
|
||||
>
|
||||
<option value="">Bulk Actions</option>
|
||||
{ this.props.bulk_actions.map(function(action, index) {
|
||||
return (
|
||||
|
@ -36,7 +36,6 @@ function(
|
||||
let default_value = false;
|
||||
if(selected_filters[filter] !== undefined && selected_filters[filter]) {
|
||||
default_value = selected_filters[filter]
|
||||
|
||||
} else {
|
||||
jQuery(`select[name="${filter}"]`).val('');
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
column.is_primary = (index === 0);
|
||||
column.sorted = (this.props.sort_by === column.name)
|
||||
? this.props.sort_order
|
||||
: 'asc';
|
||||
: 'desc';
|
||||
return (
|
||||
<ListingColumn
|
||||
onSort={this.props.onSort}
|
||||
@ -32,6 +32,7 @@ define(['react', 'classnames'], function(React, classNames) {
|
||||
</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="select_all"
|
||||
ref="toggle"
|
||||
checked={ this.props.selection }
|
||||
onChange={ this.handleSelectItems } />
|
||||
|
@ -34,11 +34,9 @@ define(
|
||||
};
|
||||
},
|
||||
handleSelectItem: function(e) {
|
||||
var is_checked = jQuery(e.target).is(':checked');
|
||||
|
||||
this.props.onSelectItem(
|
||||
parseInt(e.target.value, 10),
|
||||
is_checked
|
||||
e.target.checked
|
||||
);
|
||||
|
||||
return !e.target.checked;
|
||||
@ -61,11 +59,12 @@ define(
|
||||
if(this.props.is_selectable === true) {
|
||||
checkbox = (
|
||||
<th className="check-column" scope="row">
|
||||
<label className="screen-reader-text">
|
||||
{ 'Select ' + this.props.item.email }</label>
|
||||
<label className="screen-reader-text">{
|
||||
'Select ' + this.props.item[this.props.columns[0].name]
|
||||
}</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
defaultValue={ this.props.item.id }
|
||||
value={ this.props.item.id }
|
||||
checked={
|
||||
this.props.item.selected || this.props.selection === 'all'
|
||||
}
|
||||
@ -267,7 +266,7 @@ define(
|
||||
is_selectable={ this.props.is_selectable }
|
||||
item_actions={ this.props.item_actions }
|
||||
group={ this.props.group }
|
||||
key={ 'item-' + index }
|
||||
key={ `item-${item.id}-${index}` }
|
||||
item={ item } />
|
||||
);
|
||||
}.bind(this))}
|
||||
@ -393,7 +392,7 @@ define(
|
||||
},
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
const params = nextProps.params || {}
|
||||
//this.initWithParams(params)
|
||||
this.initWithParams(params)
|
||||
},
|
||||
getItems: function() {
|
||||
if(this.isMounted()) {
|
||||
@ -420,7 +419,13 @@ define(
|
||||
groups: response.groups || [],
|
||||
count: response.count || 0,
|
||||
loading: false
|
||||
});
|
||||
}, function() {
|
||||
if(this.props['onGetItems'] !== undefined) {
|
||||
this.props.onGetItems(
|
||||
~~(this.state.groups[0]['count'])
|
||||
);
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
@ -506,7 +511,7 @@ define(
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'bulk_action',
|
||||
action: 'bulkAction',
|
||||
data: data
|
||||
}).done(function(response) {
|
||||
this.getItems();
|
||||
|
@ -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);
|
||||
|
@ -203,6 +203,9 @@ define([
|
||||
changeBoolField: function(field, event) {
|
||||
this.model.set(field, (jQuery(event.target).val() === 'true') ? true : false);
|
||||
},
|
||||
changeBoolCheckboxField: function(field, event) {
|
||||
this.model.set(field, (!!jQuery(event.target).prop('checked')));
|
||||
},
|
||||
changeColorField: function(field, event) {
|
||||
var value = jQuery(event.target).val();
|
||||
if (value === '') {
|
||||
|
@ -162,10 +162,10 @@ define([
|
||||
this.toolsView = new Module.ContainerBlockToolsView({
|
||||
model: this.model,
|
||||
tools: {
|
||||
settings: this.renderOptions.depth > 1,
|
||||
settings: this.renderOptions.depth === 1,
|
||||
delete: this.renderOptions.depth === 1,
|
||||
move: this.renderOptions.depth === 1,
|
||||
layerSelector: this.renderOptions.depth === 1,
|
||||
layerSelector: false,
|
||||
},
|
||||
});
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
@ -265,6 +265,41 @@ define([
|
||||
behaviors: {
|
||||
ColorPickerBehavior: {},
|
||||
},
|
||||
regions: {
|
||||
columnsSettingsRegion: '.mailpoet_container_columns_settings',
|
||||
},
|
||||
initialize: function() {
|
||||
base.BlockSettingsView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this._columnsSettingsView = new (Module.ContainerBlockColumnsSettingsView)({
|
||||
collection: this.model.get('blocks'),
|
||||
});
|
||||
},
|
||||
onRender: function() {
|
||||
this.columnsSettingsRegion.show(this._columnsSettingsView);
|
||||
},
|
||||
});
|
||||
|
||||
Module.ContainerBlockColumnsSettingsView = Marionette.CollectionView.extend({
|
||||
getChildView: function() { return Module.ContainerBlockColumnSettingsView; },
|
||||
childViewOptions: function(model, index) {
|
||||
return {
|
||||
columnIndex: index,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
Module.ContainerBlockColumnSettingsView = Marionette.ItemView.extend({
|
||||
getTemplate: function() { return templates.containerBlockColumnSettings; },
|
||||
initialize: function(options) {
|
||||
this.columnNumber = (options.columnIndex || 0) + 1;
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
columnNumber: this.columnNumber,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
Module.OneColumnContainerWidgetView = base.WidgetView.extend({
|
||||
|
@ -66,7 +66,7 @@ define([
|
||||
"keyup .mailpoet_field_image_link": _.partial(this.changeField, "link"),
|
||||
"keyup .mailpoet_field_image_address": _.partial(this.changeField, "src"),
|
||||
"keyup .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
|
||||
"change .mailpoet_field_image_padded": _.partial(this.changeBoolField, "padded"),
|
||||
"change .mailpoet_field_image_padded": _.partial(this.changeBoolCheckboxField, "padded"),
|
||||
"change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"),
|
||||
"click .mailpoet_field_image_select_another_image": "showMediaManager",
|
||||
"click .mailpoet_done_editing": "close",
|
||||
|
@ -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,15 +72,26 @@ 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() {
|
||||
@ -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);
|
||||
|
||||
WordpressComponent.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,
|
||||
@ -131,6 +146,9 @@ define([
|
||||
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.postsBlock; },
|
||||
modelEvents: {},
|
||||
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);
|
||||
@ -142,6 +160,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;
|
||||
@ -216,6 +241,7 @@ define([
|
||||
insertPosts: function() {
|
||||
this.model.trigger('insertSelectedPosts');
|
||||
this.model.destroy();
|
||||
this.close();
|
||||
},
|
||||
});
|
||||
|
||||
@ -307,11 +333,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 +344,7 @@ define([
|
||||
_.each(postTypes, function(type) {
|
||||
select.append(jQuery('<option>', {
|
||||
value: type.name,
|
||||
text: type.labels.singular_name,
|
||||
text: type.label,
|
||||
}));
|
||||
});
|
||||
select.val(selectedValue);
|
||||
|
@ -1,9 +1,13 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'mailpoet',
|
||||
'notice',
|
||||
'backbone',
|
||||
'backbone.marionette'
|
||||
], function(App, MailPoet, Backbone, Marionette) {
|
||||
'backbone.marionette',
|
||||
'jquery',
|
||||
'blob',
|
||||
'filesaver'
|
||||
], function(App, MailPoet, Notice, Backbone, Marionette, jQuery, Blob, FileSaver) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -52,6 +56,18 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
Module.exportTemplate = function(options) {
|
||||
var data = _.extend(options || {}, {
|
||||
body: App.getBody(),
|
||||
});
|
||||
var blob = new Blob(
|
||||
[JSON.stringify(data)],
|
||||
{ type: 'application/json;charset=utf-8' }
|
||||
);
|
||||
|
||||
FileSaver.saveAs(blob, 'template.json');
|
||||
};
|
||||
|
||||
Module.SaveView = Marionette.LayoutView.extend({
|
||||
getTemplate: function() { return templates.save; },
|
||||
events: {
|
||||
@ -62,7 +78,8 @@ define([
|
||||
'click .mailpoet_save_template': 'toggleSaveAsTemplate',
|
||||
'click .mailpoet_save_as_template': 'saveAsTemplate',
|
||||
/* Export template */
|
||||
'click .mailpoet_save_export': 'exportTemplate',
|
||||
'click .mailpoet_save_export': 'toggleExportTemplate',
|
||||
'click .mailpoet_export_template': 'exportTemplate',
|
||||
},
|
||||
initialize: function(options) {
|
||||
App.getChannel().on('beforeEditorSave', this.beforeSave, this);
|
||||
@ -117,12 +134,33 @@ define([
|
||||
|
||||
this.hideOptionContents();
|
||||
},
|
||||
toggleExportTemplate: function() {
|
||||
this.$('.mailpoet_export_template_container').toggleClass('mailpoet_hidden');
|
||||
this.toggleSaveOptions();
|
||||
},
|
||||
hideExportTemplate: function() {
|
||||
this.$('.mailpoet_export_template_container').addClass('mailpoet_hidden');
|
||||
},
|
||||
exportTemplate: function() {
|
||||
console.log('Exporting template');
|
||||
this.hideOptionContents();
|
||||
var templateName = this.$('.mailpoet_export_template_name').val(),
|
||||
templateDescription = this.$('.mailpoet_export_template_description').val();
|
||||
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(App.getConfig().get('translations.templateNameMissing'));
|
||||
} else if (templateDescription === '') {
|
||||
MailPoet.Notice.error(App.getConfig().get('translations.templateDescriptionMissing'));
|
||||
} else {
|
||||
console.log('Exporting template with ', templateName, templateDescription);
|
||||
Module.exportTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
});
|
||||
this.hideExportTemplate();
|
||||
}
|
||||
},
|
||||
hideOptionContents: function() {
|
||||
this.hideSaveAsTemplate();
|
||||
this.hideExportTemplate();
|
||||
this.$('.mailpoet_save_options').addClass('mailpoet_hidden');
|
||||
},
|
||||
next: function() {
|
||||
|
@ -56,7 +56,7 @@ define([
|
||||
};
|
||||
|
||||
Module.getTransformedPosts = function(options) {
|
||||
return Module._cachedQuery({
|
||||
return Module._query({
|
||||
action: 'getTransformedPosts',
|
||||
options: options,
|
||||
});
|
||||
|
@ -35,7 +35,9 @@ define(
|
||||
id: "mailpoet_segments",
|
||||
endpoint: "segments",
|
||||
multiple: true,
|
||||
select2: true
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'sender',
|
||||
|
@ -1,6 +1,7 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'underscore',
|
||||
'mailpoet',
|
||||
'react-router',
|
||||
'classnames',
|
||||
@ -8,11 +9,67 @@ define(
|
||||
],
|
||||
function(
|
||||
React,
|
||||
_,
|
||||
MailPoet,
|
||||
Router,
|
||||
classNames,
|
||||
Breadcrumb
|
||||
) {
|
||||
|
||||
var ImportTemplate = React.createClass({
|
||||
saveTemplate: function(template) {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletterTemplates',
|
||||
action: 'save',
|
||||
data: template
|
||||
}).done(function(response) {
|
||||
if(response === true) {
|
||||
this.props.onImport(template);
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (_.size(this.refs.templateFile.files) <= 0) return false;
|
||||
|
||||
var file = _.first(this.refs.templateFile.files),
|
||||
reader = new FileReader(),
|
||||
saveTemplate = this.saveTemplate;
|
||||
|
||||
reader.onload = function(e) {
|
||||
try {
|
||||
saveTemplate(JSON.parse(e.target.result));
|
||||
} catch (err) {
|
||||
MailPoet.Notice.error('This template file appears to be malformed. Please try another one.');
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
reader.readAsText(file);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2>Import a template</h2>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<input type="file" placeholder="Select a .json file to upload" ref="templateFile" />
|
||||
|
||||
<p className="submit">
|
||||
<input
|
||||
className="button button-primary"
|
||||
type="submit"
|
||||
value="Upload" />
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var NewsletterTemplates = React.createClass({
|
||||
mixins: [
|
||||
Router.History
|
||||
@ -62,11 +119,11 @@ define(
|
||||
body: template.body
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response === true) {
|
||||
if(response.result === true) {
|
||||
// TODO: Move this URL elsewhere
|
||||
window.location = 'admin.php?page=mailpoet-newsletter-editor&id=' + this.props.params.id;
|
||||
} else {
|
||||
response.map(function(error) {
|
||||
response.errors.map(function(error) {
|
||||
MailPoet.Notice.error(error);
|
||||
});
|
||||
}
|
||||
@ -93,6 +150,9 @@ define(
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
},
|
||||
handleTemplateImport: function() {
|
||||
this.getTemplates();
|
||||
},
|
||||
render: function() {
|
||||
var templates = this.state.templates.map(function(template, index) {
|
||||
var deleteLink = (
|
||||
@ -152,6 +212,8 @@ define(
|
||||
<ul className={ boxClasses }>
|
||||
{ templates }
|
||||
</ul>
|
||||
|
||||
<ImportTemplate onImport={this.handleTemplateImport} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -47,6 +47,8 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
type: 'success',
|
||||
message: '',
|
||||
static: false,
|
||||
hideClose: false,
|
||||
id: null,
|
||||
scroll: false,
|
||||
timeout: 2000,
|
||||
onOpen: null,
|
||||
@ -60,6 +62,9 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
// clone element
|
||||
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
||||
|
||||
// add data-id to the element
|
||||
if (this.options.id) this.element.attr('data-id', 'notice_' + this.options.id);
|
||||
|
||||
// remove id from clone
|
||||
this.element.removeAttr('id');
|
||||
|
||||
@ -73,7 +78,6 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
}
|
||||
|
||||
// listen to remove event
|
||||
var element = this.element;
|
||||
jQuery(this.element).on('close', function() {
|
||||
jQuery(this).fadeOut(200, function() {
|
||||
// on close callback
|
||||
@ -148,7 +152,7 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
// if the notice is not static, it has to disappear after a timeout
|
||||
if(this.options.static === false) {
|
||||
this.element.delay(this.options.timeout).trigger('close');
|
||||
} else {
|
||||
} else if (this.options.hideClose === false) {
|
||||
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
|
||||
this.element.find('.mailpoet_notice_close').on('click', function() {
|
||||
jQuery(this).trigger('close');
|
||||
@ -163,6 +167,14 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
hide: function(all) {
|
||||
if(all !== undefined && all === true) {
|
||||
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
||||
} else if (all !== undefined && jQuery.isArray(all)) {
|
||||
for (var id in all) {
|
||||
jQuery('[data-id="notice_' + all[id] + '"]')
|
||||
.trigger('close');
|
||||
}
|
||||
} if (all !== undefined) {
|
||||
jQuery('[data-id="notice_' + all + '"]')
|
||||
.trigger('close');
|
||||
} else {
|
||||
jQuery('.mailpoet_notice.updated:not([id]), .mailpoet_notice.error:not([id])')
|
||||
.trigger('close');
|
||||
@ -188,4 +200,4 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
}, options));
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
@ -1,88 +1,78 @@
|
||||
define('public', ['mailpoet', 'jquery', 'jquery-validation'],
|
||||
function(MailPoet, $) {
|
||||
'use strict';
|
||||
|
||||
define([
|
||||
'mailpoet',
|
||||
'jquery',
|
||||
'parsleyjs'
|
||||
],
|
||||
function(
|
||||
MailPoet,
|
||||
jQuery,
|
||||
Parsley
|
||||
) {
|
||||
jQuery(function($) {
|
||||
function isSameDomain(url) {
|
||||
var link = document.createElement('a');
|
||||
link.href = url;
|
||||
return (window.location.hostname === link.hostname);
|
||||
}
|
||||
|
||||
function formatData(raw) {
|
||||
var data = {};
|
||||
|
||||
$.each(raw, function(index, value) {
|
||||
if(value.name.endsWith('[]')) {
|
||||
var value_name = value.name.substr(0, value.name.length - 2);
|
||||
// it's an array
|
||||
if(data[value_name] === undefined) {
|
||||
data[value_name] = [];
|
||||
}
|
||||
data[value_name].push(value.value);
|
||||
} else {
|
||||
data[value.name] = value.value;
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
// setup form validation
|
||||
$('form.mailpoet_form').each(function() {
|
||||
$(this).validate({
|
||||
submitHandler: function(form) {
|
||||
var data = $(form).serializeArray() || {};
|
||||
var form = $(this);
|
||||
|
||||
// clear messages
|
||||
$(form).find('.mailpoet_message').html('');
|
||||
form.parsley().on('form:submit', function(parsley) {
|
||||
|
||||
// check if we're on the same domain
|
||||
if(isSameDomain(MailPoetForm.ajax_url) === false) {
|
||||
// non ajax post request
|
||||
return true;
|
||||
} else {
|
||||
// ajax request
|
||||
MailPoet.Ajax.post({
|
||||
url: MailPoetForm.ajax_url,
|
||||
token: MailPoetForm.token,
|
||||
endpoint: 'subscribers',
|
||||
action: 'save',
|
||||
data: formatData(data),
|
||||
onSuccess: function(response) {
|
||||
if(response !== true) {
|
||||
// errors
|
||||
$.each(response, function(index, error) {
|
||||
$(form)
|
||||
.find('.mailpoet_message')
|
||||
.append('<p class="mailpoet_validate_error">'+
|
||||
error+
|
||||
'</p>');
|
||||
});
|
||||
} else {
|
||||
// successfully subscribed
|
||||
if(response.page !== undefined) {
|
||||
// go to page
|
||||
window.location.href = response.page;
|
||||
} else if(response.message !== undefined) {
|
||||
// display success message
|
||||
$(form)
|
||||
.find('.mailpoet_message')
|
||||
.html('<p class="mailpoet_validate_success">'+
|
||||
response.message+
|
||||
'</p>');
|
||||
}
|
||||
var data = form.serializeObject() || {};
|
||||
|
||||
// reset form
|
||||
$(form).trigger('reset');
|
||||
}
|
||||
// clear messages
|
||||
form.find('.mailpoet_message').html('');
|
||||
|
||||
// check if we're on the same domain
|
||||
if(isSameDomain(MailPoetForm.ajax_url) === false) {
|
||||
// non ajax post request
|
||||
return true;
|
||||
} else {
|
||||
// ajax request
|
||||
MailPoet.Ajax.post({
|
||||
url: MailPoetForm.ajax_url,
|
||||
token: MailPoetForm.token,
|
||||
endpoint: 'subscribers',
|
||||
action: 'subscribe',
|
||||
data: data
|
||||
}).done(function(response) {
|
||||
if(response.result !== true) {
|
||||
// errors
|
||||
$.each(response.errors, function(index, error) {
|
||||
form
|
||||
.find('.mailpoet_message')
|
||||
.append('<p class="mailpoet_validate_error">'+
|
||||
error+
|
||||
'</p>');
|
||||
});
|
||||
} else {
|
||||
// successfully subscribed
|
||||
if(response.page !== undefined) {
|
||||
// go to page
|
||||
window.location.href = response.page;
|
||||
} else if(response.message !== undefined) {
|
||||
// display success message
|
||||
form
|
||||
.find('.mailpoet_message')
|
||||
.html('<p class="mailpoet_validate_success">'+
|
||||
response.message+
|
||||
'</p>');
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
||||
// reset form
|
||||
form.trigger('reset');
|
||||
// reset validation
|
||||
parsley.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
@ -26,10 +26,10 @@ define(
|
||||
];
|
||||
|
||||
var messages = {
|
||||
updated: function() {
|
||||
onUpdate: function() {
|
||||
MailPoet.Notice.success('Segment successfully updated!');
|
||||
},
|
||||
created: function() {
|
||||
onCreate: function() {
|
||||
MailPoet.Notice.success('Segment successfully added!');
|
||||
}
|
||||
};
|
||||
@ -54,7 +54,7 @@ define(
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
onSuccess={ this.history.goBack } />
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Router, Route, Link } from 'react-router'
|
||||
import { Router, Link } from 'react-router'
|
||||
|
||||
import jQuery from 'jquery'
|
||||
import MailPoet from 'mailpoet'
|
||||
@ -40,10 +40,10 @@ var columns = [
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was moved to the trash.'
|
||||
@ -61,7 +61,7 @@ var messages = {
|
||||
},
|
||||
onDelete: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was permanently deleted.'
|
||||
@ -79,7 +79,7 @@ var messages = {
|
||||
},
|
||||
onRestore: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment has been restored from the trash.'
|
||||
@ -97,7 +97,7 @@ var messages = {
|
||||
}
|
||||
};
|
||||
|
||||
var item_actions = [
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
@ -133,7 +133,7 @@ var item_actions = [
|
||||
}
|
||||
];
|
||||
|
||||
var bulk_actions = [
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
@ -141,7 +141,7 @@ var bulk_actions = [
|
||||
}
|
||||
];
|
||||
|
||||
var SegmentList = React.createClass({
|
||||
const SegmentList = React.createClass({
|
||||
renderItem: function(segment, actions) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
|
@ -73,7 +73,7 @@ define(
|
||||
}));
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
Backbone.history.start();
|
||||
if (!Backbone.History.started) Backbone.history.start();
|
||||
});
|
||||
}
|
||||
);
|
@ -37,14 +37,25 @@ define(
|
||||
'subscribed': 'Subscribed',
|
||||
'unsubscribed': 'Unsubscribed'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
type: 'selection',
|
||||
placeholder: "Select a list",
|
||||
endpoint: "segments",
|
||||
multiple: true,
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
updated: function() {
|
||||
onUpdate: function() {
|
||||
MailPoet.Notice.success('Subscriber successfully updated!');
|
||||
},
|
||||
created: function() {
|
||||
onCreate: function() {
|
||||
MailPoet.Notice.success('Subscriber successfully added!');
|
||||
}
|
||||
};
|
||||
@ -71,7 +82,7 @@ define(
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
onSuccess={ this.history.goBack } />
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -101,7 +101,10 @@ const bulk_actions = [
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'move_to_segment',
|
||||
endpoint: 'segments'
|
||||
endpoint: 'segments',
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -127,7 +130,10 @@ const bulk_actions = [
|
||||
onSelect: function() {
|
||||
let field = {
|
||||
id: 'add_to_segment',
|
||||
endpoint: 'segments'
|
||||
endpoint: 'segments',
|
||||
filter: function(segment) {
|
||||
return !!(!segment.deleted_at);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -270,11 +276,16 @@ const SubscriberList = React.createClass({
|
||||
</div>
|
||||
);
|
||||
},
|
||||
onGetItems: function(count) {
|
||||
jQuery('#mailpoet_export_button')[(count > 0) ? 'show' : 'hide']();
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscribers <Link className="add-new-h2" to="/new">New</Link>
|
||||
<a className="add-new-h2" href="?page=mailpoet-import#step1">Import</a>
|
||||
<a id="mailpoet_export_button" className="add-new-h2" href="?page=mailpoet-export">Export</a>
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
@ -285,6 +296,7 @@ const SubscriberList = React.createClass({
|
||||
columns={ columns }
|
||||
bulk_actions={ bulk_actions }
|
||||
messages={ messages }
|
||||
onGetItems={ this.onGetItems }
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
264
assets/js/src/vendor_static/jquery.sticky-kit.js
Normal file
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);
|
||||
|
19
build
19
build
@ -7,21 +7,20 @@ rm wysija-newsletters.zip;
|
||||
mkdir wysija-newsletters;
|
||||
|
||||
# Production assets.
|
||||
npm install;
|
||||
./do compile:all;
|
||||
|
||||
# Production libraries.
|
||||
rm -rf vendor;
|
||||
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;
|
||||
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;
|
||||
@ -37,6 +36,4 @@ zip -r wysija-newsletters.zip wysija-newsletters;
|
||||
rm -rf wysija-newsletters;
|
||||
|
||||
# Reinstall dev dependencies.
|
||||
rm composer.lock;
|
||||
./composer.phar install;
|
||||
./do install;
|
||||
|
63
composer.lock
generated
63
composer.lock
generated
@ -160,16 +160,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v5.2.13",
|
||||
"version": "v5.2.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "45df3a88f7f46071e10d0b600f228d19f95911b3"
|
||||
"reference": "e774bc9152de85547336e22b8926189e582ece95"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/45df3a88f7f46071e10d0b600f228d19f95911b3",
|
||||
"reference": "45df3a88f7f46071e10d0b600f228d19f95911b3",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e774bc9152de85547336e22b8926189e582ece95",
|
||||
"reference": "e774bc9152de85547336e22b8926189e582ece95",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -180,7 +180,8 @@
|
||||
"phpunit/phpunit": "4.7.*"
|
||||
},
|
||||
"suggest": {
|
||||
"league/oauth2-client": "Needed for Gmail's XOAUTH2 authentication system"
|
||||
"league/oauth2-client": "Needed for XOAUTH2 authentication",
|
||||
"league/oauth2-google": "Needed for Gmail XOAUTH2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -216,7 +217,7 @@
|
||||
}
|
||||
],
|
||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"time": "2015-09-14 09:18:12"
|
||||
"time": "2015-11-01 10:15:28"
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
@ -456,16 +457,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.23.0",
|
||||
"version": "v1.23.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "5868cd822fd6cf626d5f805439575f9c323cee2a"
|
||||
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/5868cd822fd6cf626d5f805439575f9c323cee2a",
|
||||
"reference": "5868cd822fd6cf626d5f805439575f9c323cee2a",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
|
||||
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -513,22 +514,22 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2015-10-29 23:29:01"
|
||||
"time": "2015-11-05 12:49:06"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "codeception/codeception",
|
||||
"version": "2.1.3",
|
||||
"version": "2.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codeception/Codeception.git",
|
||||
"reference": "cd810cb78a869408602e17271f9b7368b09a7ca8"
|
||||
"reference": "6a812e8a0d1b1db939a29b4dc14cb398b21b6112"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/cd810cb78a869408602e17271f9b7368b09a7ca8",
|
||||
"reference": "cd810cb78a869408602e17271f9b7368b09a7ca8",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/6a812e8a0d1b1db939a29b4dc14cb398b21b6112",
|
||||
"reference": "6a812e8a0d1b1db939a29b4dc14cb398b21b6112",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -595,7 +596,7 @@
|
||||
"functional testing",
|
||||
"unit testing"
|
||||
],
|
||||
"time": "2015-10-02 09:38:59"
|
||||
"time": "2015-11-12 03:57:06"
|
||||
},
|
||||
{
|
||||
"name": "codeception/verify",
|
||||
@ -739,16 +740,16 @@
|
||||
},
|
||||
{
|
||||
"name": "facebook/webdriver",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/facebook/php-webdriver.git",
|
||||
"reference": "fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5"
|
||||
"reference": "a6e209a309bf7cd71acf15476f40b11a25d5a79d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5",
|
||||
"reference": "fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5",
|
||||
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/a6e209a309bf7cd71acf15476f40b11a25d5a79d",
|
||||
"reference": "a6e209a309bf7cd71acf15476f40b11a25d5a79d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -778,7 +779,7 @@
|
||||
"selenium",
|
||||
"webdriver"
|
||||
],
|
||||
"time": "2015-08-12 20:21:31"
|
||||
"time": "2015-11-03 22:17:22"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
@ -895,16 +896,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e"
|
||||
"reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/4ef919b0cf3b1989523138b60163bbcb7ba1ff7e",
|
||||
"reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/4d0bdbe1206df7440219ce14c972aa57cc5e4982",
|
||||
"reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -949,7 +950,7 @@
|
||||
"stream",
|
||||
"uri"
|
||||
],
|
||||
"time": "2015-08-15 19:32:36"
|
||||
"time": "2015-11-03 01:34:55"
|
||||
},
|
||||
{
|
||||
"name": "henrikbjorn/lurker",
|
||||
@ -1361,16 +1362,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.8.16",
|
||||
"version": "4.8.18",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "625f8c345606ed0f3a141dfb88f4116f0e22978e"
|
||||
"reference": "fa33d4ad96481b91df343d83e8c8aabed6b1dfd3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/625f8c345606ed0f3a141dfb88f4116f0e22978e",
|
||||
"reference": "625f8c345606ed0f3a141dfb88f4116f0e22978e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fa33d4ad96481b91df343d83e8c8aabed6b1dfd3",
|
||||
"reference": "fa33d4ad96481b91df343d83e8c8aabed6b1dfd3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1429,7 +1430,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-10-23 06:48:33"
|
||||
"time": "2015-11-11 11:32:49"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
|
25
lib/Analytics/Reporter.php
Normal file
25
lib/Analytics/Reporter.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace MailPoet\Analytics;
|
||||
|
||||
class Reporter {
|
||||
|
||||
private $fields = array(
|
||||
'Plugin Version' => 'pluginVersion',
|
||||
);
|
||||
|
||||
function __construct() {}
|
||||
|
||||
function getData() {
|
||||
$_this = $this;
|
||||
|
||||
$analytics_data = array_map(function($func) use ($_this) {
|
||||
return $_this->$func();
|
||||
}, $this->fields);
|
||||
|
||||
return $analytics_data;
|
||||
}
|
||||
|
||||
private function pluginVersion() {
|
||||
return MAILPOET_VERSION;
|
||||
}
|
||||
}
|
32
lib/Config/Analytics.php
Normal file
32
lib/Config/Analytics.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Analytics\Reporter;
|
||||
use \MailPoet\Models\Setting;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Analytics {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
add_action('admin_enqueue_scripts', array($this, 'setupAdminDependencies'));
|
||||
}
|
||||
|
||||
function setupAdminDependencies() {
|
||||
if(Setting::getValue('send_analytics_now', false)) {
|
||||
$analytics = new Reporter();
|
||||
wp_enqueue_script(
|
||||
'analytics',
|
||||
Env::$assets_url . '/js/lib/analytics.js',
|
||||
array(),
|
||||
Env::$version
|
||||
);
|
||||
wp_localize_script(
|
||||
'analytics',
|
||||
'mailpoet_analytics_data',
|
||||
$analytics->getData()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
61
lib/Config/Changelog.php
Normal file
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,17 +6,22 @@ if(!defined('ABSPATH')) exit;
|
||||
class Env {
|
||||
public static $version;
|
||||
public static $plugin_name;
|
||||
public static $plugin_url;
|
||||
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;
|
||||
@ -25,32 +30,46 @@ class Env {
|
||||
public 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 = plugins_url() . '/' . basename(Env::$path);
|
||||
self::$views_path = self::$path . '/views';
|
||||
self::$assets_path = self::$path . '/assets';
|
||||
self::$assets_url = plugins_url('/assets', $file);
|
||||
self::$temp_name = 'temp';
|
||||
self::$temp_path = self::$path . '/' . self::$temp_name;
|
||||
self::$languages_path = self::$path . '/lang';
|
||||
self::$lib_path = self::$path . '/lib';
|
||||
self::$plugin_prefix = 'mailpoet_';
|
||||
self::$db_prefix = $wpdb->prefix . self::$plugin_prefix;
|
||||
self::$db_source_name = self::dbSourceName();
|
||||
self::$db_host = DB_HOST;
|
||||
self::$db_port = 3306;
|
||||
self::$db_socket = false;
|
||||
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;
|
||||
}
|
||||
self::$db_name = DB_NAME;
|
||||
self::$db_username = DB_USER;
|
||||
self::$db_password = DB_PASSWORD;
|
||||
self::$db_charset = $wpdb->get_charset_collate();
|
||||
self::$db_source_name = self::dbSourceName(self::$db_host, self::$db_socket, self::$db_port);
|
||||
}
|
||||
|
||||
private static function dbSourceName() {
|
||||
private static function dbSourceName($host, $socket,$port) {
|
||||
$source_name = array(
|
||||
'mysql:host=',
|
||||
DB_HOST,
|
||||
(!$socket) ? 'mysql:host=' : 'mysql:unix_socket=',
|
||||
$host,
|
||||
';',
|
||||
'port=',
|
||||
$port,
|
||||
';',
|
||||
'dbname=',
|
||||
DB_NAME
|
||||
);
|
||||
return implode('', $source_name);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,7 +22,9 @@ class Initializer {
|
||||
$this->setupMenu();
|
||||
$this->setupRouter();
|
||||
$this->setupWidget();
|
||||
$this->setupAnalytics();
|
||||
$this->setupPermissions();
|
||||
$this->setupChangelog();
|
||||
}
|
||||
|
||||
function setupDB() {
|
||||
@ -94,8 +96,18 @@ class Initializer {
|
||||
$widget->init();
|
||||
}
|
||||
|
||||
function setupAnalytics() {
|
||||
$widget = new Analytics();
|
||||
$widget->init();
|
||||
}
|
||||
|
||||
function setupPermissions() {
|
||||
$permissions = new Permissions();
|
||||
$permissions->init();
|
||||
}
|
||||
|
||||
function setupChangelog() {
|
||||
$changelog = new Changelog();
|
||||
$changelog->init();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
|
||||
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;
|
||||
@ -73,30 +78,58 @@ class Menu {
|
||||
'mailpoet-settings',
|
||||
array($this, 'settings')
|
||||
);
|
||||
// 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-form-editor' => 'formEditor',
|
||||
'mailpoet-newsletter-editor' => array($this, 'newletterForm')
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Import'),
|
||||
__('Import'),
|
||||
'manage_options',
|
||||
'mailpoet-import',
|
||||
array($this, 'import')
|
||||
);
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Export'),
|
||||
__('Export'),
|
||||
'manage_options',
|
||||
'mailpoet-export',
|
||||
array($this, 'export')
|
||||
);
|
||||
|
||||
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')
|
||||
);
|
||||
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() {
|
||||
@ -104,26 +137,56 @@ class Menu {
|
||||
echo $this->renderer->render('index.html', $data);
|
||||
}
|
||||
|
||||
function settings() {
|
||||
// flags (available features on WP install)
|
||||
$flags = array();
|
||||
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(is_multisite()) {
|
||||
// get multisite registration option
|
||||
$registration = apply_filters(
|
||||
'wpmu_registration_enabled',
|
||||
get_site_option('registration', 'all')
|
||||
);
|
||||
|
||||
// check if users can register
|
||||
$flags['registration_enabled'] =
|
||||
!(in_array($registration, array('none', 'blog')));
|
||||
} else {
|
||||
// check if users can register
|
||||
$flags['registration_enabled'] =
|
||||
(bool)get_option('users_can_register', false);
|
||||
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);
|
||||
}
|
||||
|
||||
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('update.html', $data);
|
||||
}
|
||||
|
||||
function settings() {
|
||||
$settings = Setting::getAll();
|
||||
|
||||
// dkim: check if public/private keys have been generated
|
||||
@ -143,9 +206,9 @@ class Menu {
|
||||
|
||||
$data = array(
|
||||
'settings' => $settings,
|
||||
'segments' => Segment::findArray(),
|
||||
'segments' => Segment::getPublished()->findArray(),
|
||||
'pages' => Pages::getAll(),
|
||||
'flags' => $flags,
|
||||
'flags' => $this->_getFlags(),
|
||||
'charsets' => Charsets::getAll(),
|
||||
'current_user' => wp_get_current_user(),
|
||||
'permissions' => Permissions::getAll(),
|
||||
@ -158,6 +221,29 @@ class Menu {
|
||||
echo $this->renderer->render('settings.html', $data);
|
||||
}
|
||||
|
||||
private function _getFlags() {
|
||||
// flags (available features on WP install)
|
||||
$flags = array();
|
||||
|
||||
if(is_multisite()) {
|
||||
// get multisite registration option
|
||||
$registration = apply_filters(
|
||||
'wpmu_registration_enabled',
|
||||
get_site_option('registration', 'all')
|
||||
);
|
||||
|
||||
// check if users can register
|
||||
$flags['registration_enabled'] =
|
||||
!(in_array($registration, array('none', 'blog')));
|
||||
} else {
|
||||
// check if users can register
|
||||
$flags['registration_enabled'] =
|
||||
(bool)get_option('users_can_register', false);
|
||||
}
|
||||
|
||||
return $flags;
|
||||
}
|
||||
|
||||
function subscribers() {
|
||||
$data = array();
|
||||
|
||||
@ -193,11 +279,42 @@ class Menu {
|
||||
echo $this->renderer->render('newsletters.html', $data);
|
||||
}
|
||||
|
||||
function newletterForm() {
|
||||
function newletterEditor() {
|
||||
$data = array();
|
||||
wp_enqueue_media();
|
||||
wp_enqueue_script('tinymce-wplink', includes_url('js/tinymce/plugins/wplink/plugin.js'));
|
||||
wp_enqueue_style('editor', includes_url('css/editor.css'));
|
||||
echo $this->renderer->render('newsletter/form.html', $data);
|
||||
}
|
||||
}
|
||||
|
||||
function import() {
|
||||
$import = new BootStrapMenu('import');
|
||||
$data = $import->bootstrap();
|
||||
echo $this->renderer->render('import.html', $data);
|
||||
}
|
||||
|
||||
function export() {
|
||||
$export = new BootStrapMenu('export');
|
||||
$data = $export->bootstrap();
|
||||
echo $this->renderer->render('export.html', $data);
|
||||
}
|
||||
|
||||
function formEditor() {
|
||||
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$form = $form->asArray();
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'form' => $form,
|
||||
'pages' => Pages::getAll(),
|
||||
'segments' => Segment::getPublished()->findArray(),
|
||||
'styles' => FormRenderer::getStyles($form),
|
||||
'date_types' => Block\Date::getDateTypes(),
|
||||
'date_formats' => Block\Date::getDateFormats()
|
||||
);
|
||||
|
||||
echo $this->renderer->render('form/editor.html', $data);
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ class Migrator {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'name varchar(20) NOT NULL,',
|
||||
'value varchar(255) NOT NULL,',
|
||||
'value longtext,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id),',
|
||||
@ -125,7 +125,8 @@ class Migrator {
|
||||
'segment_id mediumint(9) NOT NULL,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)'
|
||||
'PRIMARY KEY (id),',
|
||||
'UNIQUE KEY subscriber_segment (subscriber_id,segment_id)'
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
@ -137,7 +138,8 @@ class Migrator {
|
||||
'segment_id mediumint(9) NOT NULL,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)'
|
||||
'PRIMARY KEY (id),',
|
||||
'UNIQUE KEY newsletter_segment (newsletter_id,segment_id)'
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
@ -147,6 +149,7 @@ class Migrator {
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'name varchar(90) NOT NULL,',
|
||||
'type varchar(90) NOT NULL,',
|
||||
'params longtext NOT NULL,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id),',
|
||||
@ -163,7 +166,8 @@ class Migrator {
|
||||
'value varchar(255) NOT NULL,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)'
|
||||
'PRIMARY KEY (id),',
|
||||
'UNIQUE KEY subscriber_id_custom_field_id (subscriber_id,custom_field_id)'
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
@ -189,7 +193,8 @@ class Migrator {
|
||||
'value varchar(255) NOT NULL,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)'
|
||||
'PRIMARY KEY (id),',
|
||||
'UNIQUE KEY newsletter_id_option_field_id (newsletter_id,option_field_id)'
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
@ -199,6 +204,8 @@ class Migrator {
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'name varchar(90) NOT NULL,',
|
||||
'body longtext,',
|
||||
'settings longtext,',
|
||||
'styles longtext,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Models\Subscriber;
|
||||
use \MailPoet\Util\Security;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
@ -12,16 +13,39 @@ class Widget {
|
||||
add_action('widgets_init', array($this, 'registerWidget'));
|
||||
|
||||
if(!is_admin()) {
|
||||
add_action('widgets_init', array($this, 'setupActions'));
|
||||
//$this->setupActions();
|
||||
add_action('widgets_init', array($this, 'setupDependencies'));
|
||||
} else {
|
||||
add_action('widgets_init', array($this, 'setupAdminDependencies'));
|
||||
}
|
||||
}
|
||||
|
||||
function registerWidget() {
|
||||
register_widget('\MailPoet\Form\Widget');
|
||||
|
||||
// subscribers count shortcode
|
||||
add_shortcode('mailpoet_subscribers_count', array(
|
||||
$this, 'getSubscribersCount'
|
||||
));
|
||||
add_shortcode('wysija_subscribers_count', array(
|
||||
$this, 'getSubscribersCount'
|
||||
));
|
||||
}
|
||||
|
||||
function getSubscribersCount($params) {
|
||||
return Subscriber::filter('subscribed')->count();
|
||||
}
|
||||
|
||||
function setupDependencies() {
|
||||
wp_enqueue_style('mailpoet_public', Env::$assets_url.'/css/public.css');
|
||||
|
||||
wp_enqueue_script('mailpoet_vendor',
|
||||
Env::$assets_url.'/js/vendor.js',
|
||||
array(),
|
||||
Env::$version,
|
||||
true
|
||||
);
|
||||
|
||||
wp_enqueue_script('mailpoet_public',
|
||||
Env::$assets_url.'/js/public.js',
|
||||
array(),
|
||||
@ -36,6 +60,22 @@ class Widget {
|
||||
));
|
||||
}
|
||||
|
||||
function setupAdminDependencies() {
|
||||
wp_enqueue_script('mailpoet_vendor',
|
||||
Env::$assets_url.'/js/vendor.js',
|
||||
array(),
|
||||
Env::$version,
|
||||
true
|
||||
);
|
||||
|
||||
wp_enqueue_script('mailpoet_admin',
|
||||
Env::$assets_url.'/js/mailpoet.js',
|
||||
array(),
|
||||
Env::$version,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
function setupActions() {
|
||||
// ajax requests
|
||||
add_action(
|
||||
@ -55,9 +95,9 @@ class Widget {
|
||||
'admin_post_mailpoet_form_subscribe',
|
||||
'mailpoet_form_subscribe'
|
||||
);
|
||||
/*add_action(
|
||||
add_action(
|
||||
'init',
|
||||
'mailpoet_form_subscribe'
|
||||
);*/
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
103
lib/Form/Block/Base.php
Normal file
103
lib/Form/Block/Base.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
abstract class Base {
|
||||
protected static function getInputValidation($block) {
|
||||
$rules = array();
|
||||
|
||||
if($block['id'] === 'email') {
|
||||
$rules['required'] = true;
|
||||
$rules['error-message'] = __('You need to specify a valid email address');
|
||||
}
|
||||
|
||||
if($block['id'] === 'segments') {
|
||||
$rules['required'] = true;
|
||||
$rules['mincheck'] = 1;
|
||||
$rules['error-message'] = __('You need to select a list');
|
||||
}
|
||||
|
||||
if(!empty($block['params']['required'])) {
|
||||
$rules['required'] = true;
|
||||
}
|
||||
|
||||
if(!empty($block['params']['validate'])) {
|
||||
if($block['params']['validate'] === 'phone') {
|
||||
$rules['pattern'] = "^[\d\+\-\.\(\)\/\s]*$";
|
||||
$rules['error-message'] = __('You need to specify a valid phone number');
|
||||
} else {
|
||||
$rules['type'] = $block['params']['validate'];
|
||||
}
|
||||
}
|
||||
|
||||
$validation = '';
|
||||
|
||||
if(!empty($rules)) {
|
||||
$rules = array_unique($rules);
|
||||
foreach($rules as $rule => $value) {
|
||||
if(is_bool($value)) {
|
||||
$value = ($value) ? 'true' : 'false';
|
||||
}
|
||||
$validation .= 'data-parsley-'.$rule.'="'.$value.'"';
|
||||
}
|
||||
}
|
||||
return $validation;
|
||||
}
|
||||
|
||||
protected static function renderLabel($block) {
|
||||
$html = '';
|
||||
if(
|
||||
isset($block['params']['label_within'])
|
||||
&& $block['params']['label_within']
|
||||
) {
|
||||
return $html;
|
||||
}
|
||||
if(isset($block['params']['label'])
|
||||
&& strlen(trim($block['params']['label'])) > 0) {
|
||||
$html .= '<label class="mailpoet_'.$block['type'].'_label">';
|
||||
$html .= $block['params']['label'];
|
||||
|
||||
if(isset($block['params']['required']) && $block['params']['required']) {
|
||||
$html .= ' <span class="mailpoet_required">*</span>';
|
||||
}
|
||||
|
||||
$html .= '</label>';
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
protected static function renderInputPlaceholder($block) {
|
||||
$html = '';
|
||||
// if the label is displayed as a placeholder,
|
||||
if(
|
||||
isset($block['params']['label_within'])
|
||||
&& $block['params']['label_within']
|
||||
) {
|
||||
// display only label
|
||||
$html .= ' placeholder="';
|
||||
$html .= static::getFieldLabel($block);
|
||||
// add an asterisk if it's a required field
|
||||
if(isset($block['params']['required']) && $block['params']['required']) {
|
||||
$html .= ' *';
|
||||
}
|
||||
$html .= '" ';
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
// return field name depending on block data
|
||||
protected static function getFieldName($block = array()) {
|
||||
return $block['id'];
|
||||
}
|
||||
|
||||
protected static function getFieldLabel($block = array()) {
|
||||
return (isset($block['params']['label'])
|
||||
&& strlen(trim($block['params']['label'])) > 0)
|
||||
? trim($block['params']['label']) : '';
|
||||
}
|
||||
|
||||
protected static function getFieldValue($block = array()) {
|
||||
return (isset($block['params']['value'])
|
||||
&& strlen(trim($block['params']['value'])) > 0)
|
||||
? trim($block['params']['value']) : '';
|
||||
}
|
||||
}
|
43
lib/Form/Block/Checkbox.php
Normal file
43
lib/Form/Block/Checkbox.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Checkbox extends Base {
|
||||
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
$field_name = static::getFieldName($block);
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
// TODO: check if it still makes sense
|
||||
// create hidden default value
|
||||
// $html .= '<input type="hidden"name="'.$field_name.'" value="0" '.static::getInputValidation($block).'/>';
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
foreach($block['params']['values'] as $option) {
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
|
||||
$html .= 'name="'.$field_name.'" ';
|
||||
|
||||
$html .= 'value="1" ';
|
||||
|
||||
$html .= (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'checked="checked"' : '';
|
||||
$html .= $field_validation;
|
||||
|
||||
$html .= ' />'.$option['value'];
|
||||
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
155
lib/Form/Block/Date.php
Normal file
155
lib/Form/Block/Date.php
Normal file
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Date extends Base {
|
||||
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
$html .= static::renderLabel($block);
|
||||
$html .= static::renderDateSelect($block);
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private static function renderDateSelect($block = array()) {
|
||||
$html = '';
|
||||
|
||||
$field_name = static::getFieldName($block);
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
$date_formats = static::getDateFormats();
|
||||
|
||||
// automatically select first date format
|
||||
$date_format = $date_formats[$block['params']['date_type']][0];
|
||||
|
||||
// set date format if specified
|
||||
if(isset($block['params']['date_format'])
|
||||
&& strlen(trim($block['params']['date_format'])) > 0) {
|
||||
$date_format = $block['params']['date_format'];
|
||||
}
|
||||
|
||||
// generate an array of selectors based on date format
|
||||
$date_selectors = explode('/', $date_format);
|
||||
|
||||
foreach($date_selectors as $date_selector) {
|
||||
if($date_selector === 'dd') {
|
||||
$html .= '<select class="mailpoet_date_day" ';
|
||||
$html .= 'name="'.$field_name.'[day]" placeholder="'.__('Day').'">';
|
||||
$html .= static::getDays($block);
|
||||
$html .= '</select>';
|
||||
} else if($date_selector === 'mm') {
|
||||
$html .= '<select class="mailpoet_date_month" ';
|
||||
$html .= 'name="'.$field_name.'[month]" placeholder="'.__('Month').'">';
|
||||
$html .= static::getMonths($block);
|
||||
$html .= '</select>';
|
||||
} else if($date_selector === 'yyyy') {
|
||||
$html .= '<select class="mailpoet_date_year" ';
|
||||
$html .= 'name="'.$field_name.'[year]" placeholder="'.__('Year').'">';
|
||||
$html .= static::getYears($block);
|
||||
$html .= '</select>';
|
||||
}
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function getDateTypes() {
|
||||
return array(
|
||||
'year_month_day' => __('Year, month, day'),
|
||||
'year_month' => __('Year, month'),
|
||||
'month' => __('Month (January, February,...)'),
|
||||
'year' => __('Year')
|
||||
);
|
||||
}
|
||||
|
||||
static function getDateFormats() {
|
||||
return array(
|
||||
'year_month_day' => array('mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy/mm/dd'),
|
||||
'year_month' => array('mm/yyyy', 'yyyy/mm'),
|
||||
'year' => array('yyyy'),
|
||||
'month' => array('mm')
|
||||
);
|
||||
}
|
||||
static function getMonthNames() {
|
||||
return array(__('January'), __('February'), __('March'), __('April'),
|
||||
__('May'), __('June'), __('July'), __('August'), __('September'),
|
||||
__('October'), __('November'), __('December')
|
||||
);
|
||||
}
|
||||
|
||||
static function getMonths($block = array()) {
|
||||
$defaults = array(
|
||||
'selected' => null
|
||||
);
|
||||
|
||||
// is default today
|
||||
if(!empty($block['params']['is_default_today'])) {
|
||||
$defaults['selected'] = (int)strftime('%m');
|
||||
}
|
||||
|
||||
// merge block with defaults
|
||||
$block = array_merge($defaults, $block);
|
||||
|
||||
$month_names = static::getMonthNames();
|
||||
|
||||
$html = '';
|
||||
for($i = 1; $i < 13; $i++) {
|
||||
$is_selected = ($i === $block['selected']) ? 'selected="selected"' : '';
|
||||
$html .= '<option value="'.$i.'" '.$is_selected.'>';
|
||||
$html .= $month_names[$i - 1];
|
||||
$html .= '</option>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function getYears($block = array()) {
|
||||
$defaults = array(
|
||||
'selected' => null,
|
||||
'from' => (int)strftime('%Y') - 100,
|
||||
'to' => (int)strftime('%Y')
|
||||
);
|
||||
// is default today
|
||||
if(!empty($block['params']['is_default_today'])) {
|
||||
$defaults['selected'] = (int)strftime('%Y');
|
||||
}
|
||||
|
||||
// merge block with defaults
|
||||
$block = array_merge($defaults, $block);
|
||||
|
||||
$html = '';
|
||||
|
||||
// return years as an array
|
||||
for($i = (int)$block['to']; $i > (int)($block['from'] - 1); $i--) {
|
||||
$is_selected = ($i === $block['selected']) ? 'selected="selected"' : '';
|
||||
$html .= '<option value="'.$i.'" '.$is_selected.'>'.$i.'</option>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function getDays($block = array()) {
|
||||
$defaults = array(
|
||||
'selected' => null
|
||||
);
|
||||
// is default today
|
||||
if(!empty($block['params']['is_default_today'])) {
|
||||
$defaults['selected'] = (int)strftime('%d');
|
||||
}
|
||||
|
||||
// merge block with defaults
|
||||
$block = array_merge($defaults, $block);
|
||||
|
||||
$html = '';
|
||||
|
||||
// return days as an array
|
||||
for($i = 1; $i < 32; $i++) {
|
||||
$is_selected = ($i === $block['selected']) ? 'selected="selected"' : '';
|
||||
$html .= '<option value="'.$i.'" '.$is_selected.'>'.$i.'</option>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
9
lib/Form/Block/Divider.php
Normal file
9
lib/Form/Block/Divider.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Divider {
|
||||
|
||||
static function render() {
|
||||
return '<hr class="mailpoet_divider" />';
|
||||
}
|
||||
}
|
23
lib/Form/Block/Html.php
Normal file
23
lib/Form/Block/Html.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Html {
|
||||
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
if(isset($block['params']['text']) && $block['params']['text']) {
|
||||
$text = html_entity_decode($block['params']['text'], ENT_QUOTES);
|
||||
}
|
||||
|
||||
if(isset($block['params']['nl2br']) && $block['params']['nl2br']) {
|
||||
$text = nl2br($text);
|
||||
}
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
$html .= $text;
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
36
lib/Form/Block/Input.php
Normal file
36
lib/Form/Block/Input.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Input extends Base {
|
||||
|
||||
static function render($block) {
|
||||
$type = 'text';
|
||||
if($block['id'] === 'email') {
|
||||
$type = 'email';
|
||||
}
|
||||
|
||||
$html = '';
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
$html .= '<input type="'.$type.'" class="mailpoet_input" ';
|
||||
|
||||
$html .= 'name="'.static::getFieldName($block).'" ';
|
||||
|
||||
$html .= 'title="'.static::getFieldLabel($block).'" ';
|
||||
|
||||
$html .= 'value="'.static::getFieldValue($block).'" ';
|
||||
|
||||
$html .= static::renderInputPlaceholder($block);
|
||||
|
||||
$html .= static::getInputValidation($block);
|
||||
|
||||
$html .= '/>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
42
lib/Form/Block/Radio.php
Normal file
42
lib/Form/Block/Radio.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Radio extends Base {
|
||||
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
$field_name = static::getFieldName($block);
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
// TODO: check if it still makes sense
|
||||
// create hidden default value
|
||||
// $html .= '<input type="hidden"name="'.$field_name.'" value="0" '.static::getInputValidation($block).'/>';
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
foreach($block['params']['values'] as $option) {
|
||||
$html .= '<label class="mailpoet_radio_label">';
|
||||
|
||||
$html .= '<input type="radio" class="mailpoet_radio" ';
|
||||
|
||||
$html .= 'name="'.$field_name.'" ';
|
||||
|
||||
$html .= 'value="'.$option['value'].'" ';
|
||||
|
||||
$html .= (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'checked="checked"' : '';
|
||||
$html .= $field_validation;
|
||||
|
||||
$html .= ' /> '.$option['value'];
|
||||
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
37
lib/Form/Block/Segment.php
Normal file
37
lib/Form/Block/Segment.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Segment extends Base {
|
||||
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
$field_name = static::getFieldName($block);
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
if(!empty($block['params']['values'])) {
|
||||
// display values
|
||||
foreach($block['params']['values'] as $segment) {
|
||||
if(!isset($segment['id']) || !isset($segment['name'])) continue;
|
||||
|
||||
$is_checked = (isset($segment['is_checked']) && $segment['is_checked']) ? 'checked="checked"' : '';
|
||||
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
$html .= 'name="'.$field_name.'[]" ';
|
||||
$html .= 'value="'.$segment['id'].'" '.$is_checked.' ';
|
||||
$html .= $field_validation;
|
||||
$html .= ' />'.$segment['name'];
|
||||
$html .= '</label>';
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
36
lib/Form/Block/Select.php
Normal file
36
lib/Form/Block/Select.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Select extends Base {
|
||||
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
$field_name = static::getFieldName($block);
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
$html .= '<select class="mailpoet_select" name="'.$field_name.'">';
|
||||
|
||||
if(isset($block['params']['label_within'])
|
||||
&& $block['params']['label_within']) {
|
||||
$html .= '<option value="">'.static::getFieldLabel($block).'</option>';
|
||||
}
|
||||
|
||||
foreach($block['params']['values'] as $option) {
|
||||
$is_selected = (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'selected="selected"' : '';
|
||||
$html .= '<option value="'.$option['value'].'" '.$is_selected.'>';
|
||||
$html .= $option['value'];
|
||||
$html .= '</option>';
|
||||
}
|
||||
$html .= '</select>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
17
lib/Form/Block/Submit.php
Normal file
17
lib/Form/Block/Submit.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Submit extends Base {
|
||||
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
$html .= '<input class="mailpoet_submit" type="submit" ';
|
||||
|
||||
$html .= 'value="'.static::getFieldLabel($block).'" ';
|
||||
|
||||
$html .= '/>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
28
lib/Form/Block/Textarea.php
Normal file
28
lib/Form/Block/Textarea.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Textarea extends Base {
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
$lines = (isset($block['params']['lines']) ? (int)$block['params']['lines'] : 1);
|
||||
|
||||
$html .= '<textarea class="mailpoet_textarea" rows="'.$lines.'" ';
|
||||
|
||||
$html .= 'name="'.static::getFieldName($block).'"';
|
||||
|
||||
$html .= static::renderInputPlaceholder($block);
|
||||
|
||||
$html .= static::getInputValidation($block);
|
||||
|
||||
$html .= '></textarea>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
95
lib/Form/Renderer.php
Normal file
95
lib/Form/Renderer.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace MailPoet\Form;
|
||||
use MailPoet\Form\Block;
|
||||
use MailPoet\Form\Util;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Renderer {
|
||||
// public: rendering method
|
||||
static function render($form = array()) {
|
||||
$html = static::renderStyles($form);
|
||||
$html .= static::renderHTML($form);
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function renderStyles($form = array()) {
|
||||
$html = '<style type="text/css">';
|
||||
$html .= static::getStyles($form);
|
||||
$html .= '</style>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function renderHTML($form = array()) {
|
||||
if(isset($form['body']) && !empty($form['body'])) {
|
||||
return static::renderBlocks($form['body']);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
static function getStyles($form = array()) {
|
||||
if(isset($form['styles'])
|
||||
&& strlen(trim($form['styles'])) > 0) {
|
||||
return strip_tags($form['styles']);
|
||||
} else {
|
||||
return Util\Styles::$defaults;
|
||||
}
|
||||
}
|
||||
|
||||
// private: rendering methods
|
||||
private static function renderBlocks($blocks = array()) {
|
||||
$html = '';
|
||||
foreach ($blocks as $key => $block) {
|
||||
$html .= static::renderBlock($block)."\n";
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private static function renderBlock($block = array()) {
|
||||
$html = '';
|
||||
switch ($block['type']) {
|
||||
case 'html':
|
||||
$html .= Block\Html::render($block);
|
||||
break;
|
||||
|
||||
case 'divider':
|
||||
$html .= Block\Divider::render();
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
$html .= Block\Checkbox::render($block);
|
||||
break;
|
||||
|
||||
case 'radio':
|
||||
$html .= Block\Radio::render($block);
|
||||
break;
|
||||
|
||||
case 'segment':
|
||||
$html .= Block\Segment::render($block);
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
$html .= Block\Date::render($block);
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
$html .= Block\Select::render($block);
|
||||
break;
|
||||
|
||||
case 'input':
|
||||
$html .= Block\Input::render($block);
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
$html .= Block\Textarea::render($block);
|
||||
break;
|
||||
|
||||
case 'submit':
|
||||
$html .= Block\Submit::render($block);
|
||||
break;
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
}
|
91
lib/Form/Util/Export.php
Normal file
91
lib/Form/Util/Export.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Util;
|
||||
use MailPoet\Form\Widget;
|
||||
|
||||
class Export {
|
||||
static function getAll($form = null) {
|
||||
return array(
|
||||
'html' => static::get('html', $form),
|
||||
'php' => static::get('php', $form),
|
||||
'iframe' => static::get('iframe', $form),
|
||||
'shortcode' => static::get('shortcode', $form),
|
||||
);
|
||||
}
|
||||
|
||||
static function get($type = 'html', $form = null) {
|
||||
switch($type) {
|
||||
case 'iframe':
|
||||
// generate url to load iframe's content
|
||||
$iframe_url = add_query_arg(array(
|
||||
'mailpoet_page' => 'mailpoet_form_iframe',
|
||||
'mailpoet_form' => $form['id']
|
||||
), site_url());
|
||||
|
||||
// generate iframe
|
||||
return '<iframe '.
|
||||
'width="100%" '.
|
||||
'scrolling="no" '.
|
||||
'frameborder="0" '.
|
||||
'src="'.$iframe_url.'" '.
|
||||
'class="mailpoet_form_iframe" '.
|
||||
'vspace="0" '.
|
||||
'tabindex="0" '.
|
||||
'onload="javascript:(this.style.height = this.contentWindow.document.body.scrollHeight + \'px\');"'.
|
||||
'marginwidth="0" '.
|
||||
'marginheight="0" '.
|
||||
'hspace="0" '.
|
||||
'allowtransparency="true"></iframe>';
|
||||
break;
|
||||
|
||||
case 'php':
|
||||
$output = array(
|
||||
'$form_widget = new \MailPoet\Form\Widget();',
|
||||
'echo $form_widget->widget(array(\'form\' => '.(int)$form['id'].', \'form_type\' => \'php\'));'
|
||||
);
|
||||
return join("\n", $output);
|
||||
break;
|
||||
|
||||
case 'html':
|
||||
// TODO: get locale setting in order to load translations
|
||||
$wp_locale = \get_locale();
|
||||
|
||||
$output = array();
|
||||
|
||||
$output[] = '<!-- BEGIN Scripts : you should place them in the header of your theme -->';
|
||||
|
||||
// jQuery
|
||||
$output[] = '<script type="text/javascript" src="'.includes_url().'js/jquery/jquery.js'.'?mpv='.MAILPOET_VERSION.'"></script>';
|
||||
|
||||
// (JS) form validation
|
||||
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'lib/jquery.validationEngine.js?mpv='.MAILPOET_VERSION).'"></script>';
|
||||
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'lib/jquery.validationEngine-en.js?mpv='.MAILPOET_VERSION).'"></script>';
|
||||
|
||||
// (CSS) form validation styles
|
||||
$output[] = '<link rel="stylesheet" type="text/css" href="'.plugins_url('wysija-newsletters/'.'lib/validationEngine.jquery.css?mpv='.MAILPOET_VERSION).'">';
|
||||
|
||||
// (JS) form submission
|
||||
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'www/mailpoet_form_subscribe.js?mpv='.MAILPOET_VERSION).'"></script>';
|
||||
|
||||
// (JS) variables...
|
||||
$output[] = '<script type="text/javascript">';
|
||||
$output[] = ' var MailPoetData = MailPoetData || {';
|
||||
$output[] = ' is_rtl: '.((int)is_rtl()).",";
|
||||
$output[] = ' ajax_url: "'.admin_url('admin-ajax.php').'"';
|
||||
$output[] = ' };';
|
||||
$output[] = '</script>';
|
||||
$output[] = '<!--END Scripts-->';
|
||||
|
||||
$form_widget = new Widget();
|
||||
$output[] = $form_widget->widget(array(
|
||||
'form' => (int)$form['id'],
|
||||
'form_type' => 'php'
|
||||
));
|
||||
return join("\n", $output);
|
||||
break;
|
||||
|
||||
case 'shortcode':
|
||||
return '[mailpoet_form id="'.(int)$form['id'].'"]';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
181
lib/Form/Util/Styles.php
Normal file
181
lib/Form/Util/Styles.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
namespace MailPoet\Form\Util;
|
||||
|
||||
class Styles {
|
||||
private $_stylesheet = null;
|
||||
private $_styles = array();
|
||||
|
||||
static $defaults =<<<EOL
|
||||
/* form */
|
||||
.mailpoet_form {
|
||||
|
||||
}
|
||||
|
||||
/* paragraphs (label + input) */
|
||||
.mailpoet_paragraph {
|
||||
|
||||
}
|
||||
|
||||
/* labels */
|
||||
.mailpoet_input_label,
|
||||
.mailpoet_textarea_label,
|
||||
.mailpoet_select_label,
|
||||
.mailpoet_radio_label,
|
||||
.mailpoet_checkbox_label,
|
||||
.mailpoet_list_label,
|
||||
.mailpoet_date_label {
|
||||
display:block;
|
||||
}
|
||||
|
||||
/* inputs */
|
||||
.mailpoet_input,
|
||||
.mailpoet_textarea,
|
||||
.mailpoet_select,
|
||||
.mailpoet_date {
|
||||
display:block;
|
||||
}
|
||||
|
||||
.mailpoet_checkbox {
|
||||
display:inline;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
.mailpoet_validate_success {
|
||||
color:#468847;
|
||||
}
|
||||
|
||||
.mailpoet_validate_error {
|
||||
color:#B94A48;
|
||||
}
|
||||
EOL;
|
||||
|
||||
function __construct($stylesheet = null) {
|
||||
// store raw styles
|
||||
$this->setStylesheet($stylesheet);
|
||||
|
||||
// extract rules/properties
|
||||
$this->parseStyles();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
function render($prefix = '') {
|
||||
$styles = $this->getStyles();
|
||||
if(!empty($styles)) {
|
||||
$output = array();
|
||||
|
||||
// add prefix on each selector
|
||||
foreach($styles as $style) {
|
||||
// check if selector is an array
|
||||
if(is_array($style['selector'])) {
|
||||
$selector = join(",\n", array_map(function($value) use ($prefix) {
|
||||
return $prefix.' '.$value;
|
||||
}, $style['selector']));
|
||||
} else {
|
||||
$selector = $prefix.' '.$style['selector'];
|
||||
}
|
||||
|
||||
// format selector
|
||||
$output[] = $selector . ' {';
|
||||
|
||||
// format rules
|
||||
if(!empty($style['rules'])) {
|
||||
$rules = join("\n", array_map(function($rule) {
|
||||
return "\t".$rule['property'] . ': ' . $rule['value'].';';
|
||||
}, $style['rules']));
|
||||
|
||||
$output[] = $rules;
|
||||
}
|
||||
|
||||
$output[] = '}';
|
||||
}
|
||||
|
||||
return join("\n", $output);
|
||||
}
|
||||
}
|
||||
|
||||
private function setStylesheet($stylesheet) {
|
||||
$this->_stylesheet = $this->stripComments($stylesheet);
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function stripComments($stylesheet) {
|
||||
// remove comments
|
||||
return preg_replace('!/\*.*?\*/!s', '', $stylesheet);
|
||||
}
|
||||
|
||||
private function getStylesheet() {
|
||||
return $this->_stylesheet;
|
||||
}
|
||||
|
||||
private function setStyles($styles) {
|
||||
$this->_styles = $styles;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getStyles() {
|
||||
return $this->_styles;
|
||||
}
|
||||
|
||||
private function parseStyles() {
|
||||
if($this->getStylesheet() !== null) {
|
||||
// extract selectors and rules
|
||||
preg_match_all( '/(?ims)([a-z0-9\s\.\:#_\-@,]+)\{([^\}]*)\}/',
|
||||
$this->getStylesheet(),
|
||||
$matches
|
||||
);
|
||||
$selectors = $matches[1];
|
||||
$rules = $matches[2];
|
||||
|
||||
// extracted styles
|
||||
$styles = array();
|
||||
|
||||
// loop through each selector
|
||||
foreach($selectors as $index => $selector) {
|
||||
// trim selector
|
||||
$selector = trim($selector);
|
||||
// get selector rules
|
||||
$selector_rules = array_filter(array_map(function($value) {
|
||||
if(strlen(trim($value)) > 0) {
|
||||
// split property / value
|
||||
$pair = explode(':', trim($value));
|
||||
if(isset($pair[0]) && isset($pair[1])) {
|
||||
return array(
|
||||
'property' => $pair[0],
|
||||
'value' => $pair[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
}, explode(';', trim($rules[$index]))));
|
||||
|
||||
// check if we have multiple selectors
|
||||
if(strpos($selector, ',') !== FALSE) {
|
||||
$selectors_array = array_filter(array_map(function($value) {
|
||||
return trim($value);
|
||||
}, explode(',', $selector)));
|
||||
|
||||
// multiple selectors
|
||||
$styles[$index] = array(
|
||||
'selector' => $selectors_array,
|
||||
'rules' => $selector_rules
|
||||
);
|
||||
} else {
|
||||
// it's a single selector
|
||||
$styles[$index] = array(
|
||||
'selector' => $selector,
|
||||
'rules' => $selector_rules
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setStyles($styles);
|
||||
}
|
||||
}
|
||||
|
||||
function __toString() {
|
||||
$this->stripComments();
|
||||
return $this->render();
|
||||
}
|
||||
}
|
@ -1,120 +1,307 @@
|
||||
<?php
|
||||
namespace MailPoet\Form;
|
||||
use \MailPoet\Config\Renderer;
|
||||
use \MailPoet\Models\Form;
|
||||
use \MailPoet\Models\Segment;
|
||||
use \MailPoet\Models\Setting;
|
||||
use \MailPoet\Models\Subscriber;
|
||||
use \MailPoet\Form\Renderer as FormRenderer;
|
||||
use \MailPoet\Form\Util;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Widget extends \WP_Widget {
|
||||
function __construct () {
|
||||
// add_action(
|
||||
// 'wp_ajax_mailpoet_form_subscribe',
|
||||
// array($this, 'subscribe')
|
||||
// );
|
||||
// add_action(
|
||||
// 'wp_ajax_nopriv_mailpoet_form_subscribe',
|
||||
// array($this, 'subscribe')
|
||||
// );
|
||||
// add_action(
|
||||
// 'admin_post_nopriv_mailpoet_form_subscribe',
|
||||
// array($this, 'subscribe')
|
||||
// );
|
||||
// add_action(
|
||||
// 'admin_post_mailpoet_form_subscribe',
|
||||
// array($this, 'subscribe')
|
||||
// );
|
||||
|
||||
// add_action(
|
||||
// 'init',
|
||||
// array($this, 'subscribe')
|
||||
// );
|
||||
|
||||
function __construct() {
|
||||
return parent::__construct(
|
||||
'mailpoet_form',
|
||||
__('MailPoet Subscription Form'),
|
||||
__("MailPoet Subscription Form"),
|
||||
array(
|
||||
'title' => __('Newsletter subscription form')
|
||||
'title' => __("Newsletter subscription form"),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance) {
|
||||
/**
|
||||
* Save the new widget's title.
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ) {
|
||||
$instance = $old_instance;
|
||||
$instance['title'] = strip_tags($new_instance['title']);
|
||||
$instance['form'] = (int)$new_instance['form'];
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the widget's option form.
|
||||
*/
|
||||
public function form($instance) {
|
||||
|
||||
$instance = wp_parse_args(
|
||||
(array)$instance,
|
||||
array(
|
||||
'title' => __('Subscribe to our Newsletter')
|
||||
'title' => __("Subscribe to our Newsletter")
|
||||
)
|
||||
);
|
||||
|
||||
// set title
|
||||
$title = isset($instance['title']) ? strip_tags($instance['title']) : '';
|
||||
|
||||
$output = '';
|
||||
// set form
|
||||
$selected_form = isset($instance['form']) ? (int)($instance['form']) : 0;
|
||||
|
||||
$output .= '<p>';
|
||||
$output .= ' <label for="'.$this->get_field_id('title').'">';
|
||||
$output .= __('Title:' );
|
||||
$output .= ' </label>';
|
||||
$output .= ' <input type="text" class="widefat"';
|
||||
$output .= ' id="'.$this->get_field_id('title').'"';
|
||||
$output .= ' name="'.$this->get_field_name('title').'"';
|
||||
$output .= ' value="'.esc_attr($title).'"';
|
||||
$output .= ' />';
|
||||
$output .= '</p>';
|
||||
$output .= '<p>';
|
||||
$output .= ' <a href="javascript:;" class="mailpoet_form_new">';
|
||||
$output .= __('Create a new form');
|
||||
$output .= ' </a>';
|
||||
$output .= '</p>';
|
||||
|
||||
echo $output;
|
||||
// get forms list
|
||||
$forms = Form::getPublished()->orderByAsc('name')->findArray();
|
||||
?><p>
|
||||
<label for="<?php $this->get_field_id( 'title' ) ?>"><?php _e( 'Title:' ); ?></label>
|
||||
<input
|
||||
type="text"
|
||||
class="widefat"
|
||||
id="<?php echo $this->get_field_id('title') ?>"
|
||||
name="<?php echo $this->get_field_name('title'); ?>"
|
||||
value="<?php echo esc_attr($title); ?>"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<select class="widefat" id="<?php echo $this->get_field_id('form') ?>" name="<?php echo $this->get_field_name('form'); ?>">
|
||||
<?php
|
||||
foreach ($forms as $form) {
|
||||
$is_selected = ($selected_form === (int)$form['id']) ? 'selected="selected"' : '';
|
||||
?>
|
||||
<option value="<?php echo (int)$form['id']; ?>" <?php echo $is_selected; ?>><?php echo esc_html($form['name']); ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<a href="javascript:;" onClick="createSubscriptionForm()" class="mailpoet_form_new"><?php _e("Create a new form"); ?></a>
|
||||
</p>
|
||||
<script type="text/javascript">
|
||||
function createSubscriptionForm() {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'forms',
|
||||
action: 'create'
|
||||
}).done(function(response) {
|
||||
if(response !== false) {
|
||||
window.location = response;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the widget itself.
|
||||
*/
|
||||
function widget($args, $instance = null) {
|
||||
// turn $args into variables
|
||||
extract($args);
|
||||
if($instance === null) { $instance = $args; }
|
||||
|
||||
if($instance === null) {
|
||||
$instance = $args;
|
||||
}
|
||||
|
||||
$title = apply_filters(
|
||||
'widget_title',
|
||||
$instance['title'],
|
||||
!empty($instance['title']) ? $instance['title'] : '',
|
||||
$instance,
|
||||
$this->id_base
|
||||
);
|
||||
|
||||
$form_id = $this->id_base.'_'.$this->number;
|
||||
$form_type = 'widget';
|
||||
// get form
|
||||
$form = Form::getPublished()->findOne($instance['form']);
|
||||
|
||||
$output = '';
|
||||
// if the form was not found, return nothing.
|
||||
if($form === false) {
|
||||
return '';
|
||||
} else {
|
||||
$form = $form->asArray();
|
||||
$form_type = 'widget';
|
||||
if(isset($instance['form_type']) && in_array(
|
||||
$instance['form_type'],
|
||||
array('html', 'php', 'iframe', 'shortcode')
|
||||
)) {
|
||||
$form_type = $instance['form_type'];
|
||||
}
|
||||
|
||||
// before widget
|
||||
$output .= (isset($before_widget) ? $before_widget : '');
|
||||
$settings = (isset($form['settings']) ? $form['settings'] : array());
|
||||
$body = (isset($form['body']) ? $form['body'] : array());
|
||||
$output = '';
|
||||
|
||||
// title
|
||||
$output .= $before_title.$title.$after_title;
|
||||
if(!empty($body)) {
|
||||
$data = array(
|
||||
'form_id' => $this->id_base.'_'.$this->number,
|
||||
'form_type' => $form_type,
|
||||
'form' => $form,
|
||||
'title' => $title,
|
||||
'styles' => FormRenderer::renderStyles($form),
|
||||
'html' => FormRenderer::renderHTML($form),
|
||||
'before_widget' => (!empty($before_widget) ? $before_widget : ''),
|
||||
'after_widget' => (!empty($after_widget) ? $after_widget : ''),
|
||||
'before_title' => (!empty($before_title) ? $before_title : ''),
|
||||
'after_title' => (!empty($after_title) ? $after_title : '')
|
||||
);
|
||||
|
||||
// container
|
||||
$output .= '<div class="mailpoet_form mailpoet_form_'.$form_type.'">';
|
||||
// if(isset($_GET['mailpoet_form']) && (int)$_GET['mailpoet_form'] === $form['id']) {
|
||||
// // form messages (success / error)
|
||||
// $output .= '<div class="mailpoet_message">';
|
||||
// // success message
|
||||
// if(isset($_GET['mailpoet_success'])) {
|
||||
// $output .= '<p class="mailpoet_validate_success">'.strip_tags(urldecode($_GET['mailpoet_success']), '<a><strong><em><br><p>').'</p>';
|
||||
// }
|
||||
// // error message
|
||||
// if(isset($_GET['mailpoet_error'])) {
|
||||
// $output .= '<p class="mailpoet_validate_error">'.strip_tags(urldecode($_GET['mailpoet_error']), '<a><strong><em><br><p>').'</p>';
|
||||
// }
|
||||
// $output .= '</div>';
|
||||
// } else {
|
||||
// $output .= '<div class="mailpoet_message"></div>';
|
||||
// }
|
||||
|
||||
// styles
|
||||
$styles = '.mailpoet_validate_success { color:#468847; }';
|
||||
$styles .= '.mailpoet_validate_error { color:#B94A48; }';
|
||||
$output .= '<style type="text/css">'.$styles.'</style>';
|
||||
// render form
|
||||
$renderer = new Renderer();
|
||||
$renderer = $renderer->init();
|
||||
$output = $renderer->render('form/widget.html', $data);
|
||||
$output = do_shortcode($output);
|
||||
}
|
||||
|
||||
$output .= '<form '.
|
||||
'id="'.$form_id.'" '.
|
||||
'method="post" '.
|
||||
'action="'.admin_url('admin-post.php?action=mailpoet_form_subscribe').'" '.
|
||||
'class="mailpoet_form mailpoet_form_'.$form_type.'" novalidate>';
|
||||
|
||||
$output .= '<div class="mailpoet_message"></div>';
|
||||
|
||||
$output .= ' <p>';
|
||||
$output .= ' <label>'.__('E-mail');
|
||||
$output .= ' <input type="email" name="email"';
|
||||
$output .= ' data-rule-required="true"';
|
||||
$output .= ' data-rule-email="true"';
|
||||
$output .= ' data-msg-required="'.__('Please enter your email address.').'"';
|
||||
$output .= ' data-msg-email="'.__('Please enter a valid email address.').'"';
|
||||
$output .= ' />';
|
||||
$output .= ' </label>';
|
||||
$output .= ' </p>';
|
||||
|
||||
$output .= ' <p>';
|
||||
$output .= ' <label>';
|
||||
$output .= ' <input type="submit" value="'.esc_attr('Subscribe!').'" />';
|
||||
$output .= ' </label>';
|
||||
$output .= ' </p>';
|
||||
|
||||
$output .= '</form>';
|
||||
$output .= '</div>';
|
||||
|
||||
// after widget
|
||||
$output .= (isset($after_widget) ? $after_widget : '');
|
||||
|
||||
echo $output;
|
||||
if($form_type === 'widget') {
|
||||
echo $output;
|
||||
} else {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mailpoet shortcodes
|
||||
// form shortcode
|
||||
add_shortcode('mailpoet_form', 'mailpoet_form_shortcode');
|
||||
add_shortcode('wysija_form', 'mailpoet_form_shortcode');
|
||||
|
||||
function mailpoet_form_shortcode($params = array()) {
|
||||
// IMPORTANT: this is to make sure MagicMember won't scan our form and find [user_list] as a code they should replace.
|
||||
remove_shortcode('user_list');
|
||||
|
||||
if(isset($params['id']) && (int)$params['id'] > 0) {
|
||||
$form_widget = new \MailPoet\Form\Widget();
|
||||
return $form_widget->widget(array(
|
||||
'form' => (int)$params['id'],
|
||||
'form_type' => 'shortcode'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// set the content filter to replace the shortcode
|
||||
if(isset($_GET['mailpoet_page']) && strlen(trim($_GET['mailpoet_page'])) > 0) {
|
||||
switch($_GET['mailpoet_page']) {
|
||||
|
||||
case 'mailpoet_form_iframe':
|
||||
$id = (isset($_GET['mailpoet_form']) && (int)$_GET['mailpoet_form'] > 0) ? (int)$_GET['mailpoet_form'] : null;
|
||||
$form = Form::findOne($id);
|
||||
|
||||
if($form !== false) {
|
||||
// render form
|
||||
$output = Util\Export::get('html', $form->asArray());
|
||||
// $output = do_shortcode($output);
|
||||
print $output;
|
||||
exit;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// add_filter('wp_title', 'mailpoet_meta_page_title'));
|
||||
add_filter('the_title', 'mailpoet_page_title', 10, 2);
|
||||
add_filter('the_content', 'mailpoet_page_content', 98, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function mailpoet_page_title($title = '', $id = null) {
|
||||
// get signup confirmation page id
|
||||
$signup_confirmation = Setting::getValue('signup_confirmation');
|
||||
$page_id = $signup_confirmation['page'];
|
||||
|
||||
// check if we're on the signup confirmation page
|
||||
if((int)$page_id === (int)$id) {
|
||||
global $post;
|
||||
|
||||
// disable comments
|
||||
$post->comment_status = 'close';
|
||||
// disable password
|
||||
$post->post_password = '';
|
||||
|
||||
$subscriber = null;
|
||||
|
||||
// get subscriber key from url
|
||||
$subscriber_digest = (isset($_GET['mailpoet_key']) && strlen(trim($_GET['mailpoet_key'])) === 32) ? trim($_GET['mailpoet_key']) : null;
|
||||
|
||||
if($subscriber_digest !== null) {
|
||||
// get subscriber
|
||||
// TODO: change select() to selectOne() once it's implemented
|
||||
$subscribers = $mailpoet->subscribers()->select(array(
|
||||
'filter' => array(
|
||||
'subscriber_digest' => $subscriber_digest
|
||||
),
|
||||
'limit' => 1
|
||||
));
|
||||
|
||||
if(!empty($subscribers)) {
|
||||
$subscriber = array_shift($subscribers);
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have a subscriber record
|
||||
if($subscriber === null) {
|
||||
return __('Your confirmation link expired, please subscribe again.');
|
||||
} else {
|
||||
// we have a subscriber, let's check its state
|
||||
switch($subscriber['subscriber_state']) {
|
||||
case MailPoetSubscribers::STATE_UNCONFIRMED:
|
||||
case MailPoetSubscribers::STATE_UNSUBSCRIBED:
|
||||
// set subscriber state as confirmed
|
||||
$mailpoet->subscribers()->update(array(
|
||||
'subscriber' => $subscriber['subscriber'],
|
||||
'subscriber_state' => MailPoetSubscribers::STATE_SUBSCRIBED,
|
||||
'subscriber_confirmed_at' => time()
|
||||
));
|
||||
return __("You've subscribed");
|
||||
break;
|
||||
case MailPoetSubscribers::STATE_SUBSCRIBED:
|
||||
return __("You've already subscribed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
||||
function mailpoet_page_content($content = '') {
|
||||
if(strpos($content, '[mailpoet_page]') !== FALSE) {
|
||||
$content = str_replace('[mailpoet_page]', '', $content);
|
||||
}
|
||||
return $content;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
namespace MailPoet\Listing;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class ItemAction {
|
||||
private $model = null;
|
||||
private $action = null;
|
||||
private $data = null;
|
||||
|
||||
function __construct($model_class, $data) {
|
||||
$id = (int)$data['id'];
|
||||
unset($data['id']);
|
||||
$this->action = $data['action'];
|
||||
unset($data['action']);
|
||||
$this->model = $model_class::findOne($id);
|
||||
if(!empty($data)) {
|
||||
$this->data = $data;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
function apply() {
|
||||
if($this->data === null) {
|
||||
return call_user_func_array(
|
||||
array($this->model, $this->action),
|
||||
array()
|
||||
);
|
||||
} else {
|
||||
return call_user_func_array(
|
||||
array($this->model, $this->action),
|
||||
array($this->data)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,12 +16,62 @@ class CustomField extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
function asArray() {
|
||||
$model = parent::asArray();
|
||||
|
||||
$model['params'] = (
|
||||
is_serialized($this->params)
|
||||
? unserialize($this->params)
|
||||
: $this->params
|
||||
);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
function save() {
|
||||
$this->set('params', (
|
||||
is_serialized($this->params)
|
||||
? $this->params
|
||||
: serialize($this->params)
|
||||
));
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
function subscribers() {
|
||||
return $this->has_many_through(
|
||||
return $this->hasManyThrough(
|
||||
__NAMESPACE__ . '\Subscriber',
|
||||
__NAMESPACE__ . '\SubscriberCustomField',
|
||||
'custom_field_id',
|
||||
'subscriber_id'
|
||||
)->select_expr(MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.value');
|
||||
)->selectExpr(MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value');
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
$custom_field = false;
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$custom_field = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
// set name as label by default
|
||||
if(empty($data['params']['label'])) {
|
||||
$data['params']['label'] = $data['name'];
|
||||
}
|
||||
|
||||
if($custom_field === false) {
|
||||
$custom_field = self::create();
|
||||
$custom_field->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$custom_field->set($data);
|
||||
}
|
||||
|
||||
try {
|
||||
$custom_field->save();
|
||||
return $custom_field;
|
||||
} catch(Exception $e) {
|
||||
return $custom_field->getValidationErrors();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -14,6 +14,37 @@ class Form extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
function asArray() {
|
||||
$model = parent::asArray();
|
||||
|
||||
$model['body'] = (
|
||||
is_serialized($this->body)
|
||||
? unserialize($this->body)
|
||||
: $this->body
|
||||
);
|
||||
$model['settings'] = (
|
||||
is_serialized($this->settings)
|
||||
? unserialize($this->settings)
|
||||
: $this->settings
|
||||
);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
function save() {
|
||||
$this->set('body', (
|
||||
is_serialized($this->body)
|
||||
? $this->body
|
||||
: serialize($this->body)
|
||||
));
|
||||
$this->set('settings', (
|
||||
is_serialized($this->settings)
|
||||
? $this->settings
|
||||
: serialize($this->settings)
|
||||
));
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
static function search($orm, $search = '') {
|
||||
return $orm->where_like('name', '%'.$search.'%');
|
||||
}
|
||||
@ -23,12 +54,12 @@ class Form extends Model {
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Form::whereNull('deleted_at')->count()
|
||||
'count' => Form::getPublished()->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Form::whereNotNull('deleted_at')->count()
|
||||
'count' => Form::getTrashed()->count()
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -56,57 +87,7 @@ class Form extends Model {
|
||||
$form->set($data);
|
||||
}
|
||||
|
||||
$saved = $form->save();
|
||||
|
||||
if($saved === true) {
|
||||
return true;
|
||||
} else {
|
||||
$errors = $form->getValidationErrors();
|
||||
if(!empty($errors)) {
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function trash($listing, $data = array()) {
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
if($confirm_delete) {
|
||||
// delete relations with all segments
|
||||
$forms = $listing->getSelection()->findResultSet();
|
||||
if(!empty($forms)) {
|
||||
$forms_count = 0;
|
||||
foreach($forms as $form) {
|
||||
if($form->delete()) {
|
||||
$forms_count++;
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'segments' => $forms_count
|
||||
);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// soft delete
|
||||
$forms = $listing->getSelection()
|
||||
->findResultSet()
|
||||
->set_expr('deleted_at', 'NOW()')
|
||||
->save();
|
||||
|
||||
return array(
|
||||
'segments' => $forms->count()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static function restore($listing, $data = array()) {
|
||||
$forms = $listing->getSelection()
|
||||
->findResultSet()
|
||||
->set_expr('deleted_at', 'NULL')
|
||||
->save();
|
||||
|
||||
return array(
|
||||
'segments' => $forms->count()
|
||||
);
|
||||
$form->save();
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
@ -90,4 +90,12 @@ class Model extends \Sudzy\ValidModel {
|
||||
}, $searchCriteria);
|
||||
return $orm->having_raw(implode(' ' . $searchCondition . ' ', $havingFields), array_values($havingValues));
|
||||
}
|
||||
|
||||
static function getPublished() {
|
||||
return static::whereNull('deleted_at');
|
||||
}
|
||||
|
||||
static function getTrashed() {
|
||||
return static::whereNotNull('deleted_at');
|
||||
}
|
||||
}
|
@ -10,6 +10,21 @@ class Newsletter extends Model {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function save() {
|
||||
if(is_string($this->deleted_at) && strlen(trim($this->deleted_at)) === 0) {
|
||||
$this->set_expr('deleted_at', 'NULL');
|
||||
}
|
||||
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
function delete() {
|
||||
// delete all relations to segments
|
||||
NewsletterSegment::where('newsletter_id', $this->id)->deleteMany();
|
||||
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
function segments() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Segment',
|
||||
@ -99,12 +114,12 @@ class Newsletter extends Model {
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Newsletter::whereNull('deleted_at')->count()
|
||||
'count' => Newsletter::getPublished()->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Newsletter::whereNotNull('deleted_at')->count()
|
||||
'count' => Newsletter::getTrashed()->count()
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -119,8 +134,8 @@ class Newsletter extends Model {
|
||||
static function createOrUpdate($data = array()) {
|
||||
$newsletter = false;
|
||||
|
||||
if(isset($data['id']) && (int) $data['id'] > 0) {
|
||||
$newsletter = self::findOne((int) $data['id']);
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$newsletter = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
if($newsletter === false) {
|
||||
@ -131,16 +146,7 @@ class Newsletter extends Model {
|
||||
$newsletter->set($data);
|
||||
}
|
||||
|
||||
$saved = $newsletter->save();
|
||||
|
||||
if($saved === true) {
|
||||
return $newsletter->id();
|
||||
} else {
|
||||
$errors = $newsletter->getValidationErrors();
|
||||
if(!empty($errors)) {
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
$newsletter->save();
|
||||
return $newsletter;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class Segment extends Model {
|
||||
function delete() {
|
||||
// delete all relations to subscribers
|
||||
SubscriberSegment::where('segment_id', $this->id)->deleteMany();
|
||||
parent::delete();
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
function newsletters() {
|
||||
@ -29,61 +29,15 @@ class Segment extends Model {
|
||||
);
|
||||
}
|
||||
|
||||
static function search($orm, $search = '') {
|
||||
return $orm->where_like('name', '%'.$search.'%');
|
||||
}
|
||||
|
||||
static function groups() {
|
||||
return array(
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Segment::whereNull('deleted_at')->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Segment::whereNotNull('deleted_at')->count()
|
||||
)
|
||||
function subscribers() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Subscriber',
|
||||
__NAMESPACE__.'\SubscriberSegment',
|
||||
'segment_id',
|
||||
'subscriber_id'
|
||||
);
|
||||
}
|
||||
|
||||
static function groupBy($orm, $group = null) {
|
||||
if($group === 'trash') {
|
||||
return $orm->whereNotNull('deleted_at');
|
||||
} else {
|
||||
$orm = $orm->whereNull('deleted_at');
|
||||
}
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
$segment = false;
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$segment = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
if($segment === false) {
|
||||
$segment = self::create();
|
||||
$segment->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$segment->set($data);
|
||||
}
|
||||
|
||||
$saved = $segment->save();
|
||||
|
||||
if($saved === true) {
|
||||
return true;
|
||||
} else {
|
||||
$errors = $segment->getValidationErrors();
|
||||
if(!empty($errors)) {
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function duplicate($data = array()) {
|
||||
$duplicate = parent::duplicate($data);
|
||||
|
||||
@ -100,12 +54,97 @@ class Segment extends Model {
|
||||
return false;
|
||||
}
|
||||
|
||||
function subscribers() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Subscriber',
|
||||
__NAMESPACE__.'\SubscriberSegment',
|
||||
'segment_id',
|
||||
'subscriber_id'
|
||||
function addSubscriber($subscriber_id) {
|
||||
$relation = SubscriberSegment::create();
|
||||
$relation->set('subscriber_id', $subscriber_id);
|
||||
$relation->set('segment_id', $this->id);
|
||||
return $relation->save();
|
||||
}
|
||||
|
||||
function removeSubscriber($subscriber_id) {
|
||||
return SubscriberSegment::where('subscriber_id', $subscriber_id)
|
||||
->where('segment_id', $this->id)
|
||||
->delete();
|
||||
}
|
||||
|
||||
static function search($orm, $search = '') {
|
||||
return $orm->whereLike('name', '%'.$search.'%');
|
||||
}
|
||||
|
||||
static function groups() {
|
||||
return array(
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Segment::getPublished()->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Segment::getTrashed()->count()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static function groupBy($orm, $group = null) {
|
||||
if($group === 'trash') {
|
||||
return $orm->whereNotNull('deleted_at');
|
||||
} else {
|
||||
$orm = $orm->whereNull('deleted_at');
|
||||
}
|
||||
}
|
||||
|
||||
static function getSegmentsForImport() {
|
||||
return self::selectMany(array(self::$_table.'.id', self::$_table.'.name'))
|
||||
->select_expr(
|
||||
'COUNT('.MP_SUBSCRIBER_SEGMENT_TABLE.'.subscriber_id)', 'subscribers'
|
||||
)
|
||||
->left_outer_join(
|
||||
MP_SUBSCRIBER_SEGMENT_TABLE,
|
||||
array(self::$_table.'.id', '=', MP_SUBSCRIBER_SEGMENT_TABLE.'.segment_id'))
|
||||
->group_by(self::$_table.'.id')
|
||||
->group_by(self::$_table.'.name')
|
||||
->findArray();
|
||||
}
|
||||
|
||||
static function getSegmentsForExport($withConfirmedSubscribers = false) {
|
||||
return self::raw_query(
|
||||
'(SELECT segments.id, segments.name, COUNT(relation.subscriber_id) as subscribers ' .
|
||||
'FROM ' . MP_SUBSCRIBER_SEGMENT_TABLE . ' relation ' .
|
||||
'LEFT JOIN ' . self::$_table . ' segments ON segments.id = relation.segment_id ' .
|
||||
'LEFT JOIN ' . MP_SUBSCRIBERS_TABLE . ' subscribers ON subscribers.id = relation.subscriber_id ' .
|
||||
(($withConfirmedSubscribers) ?
|
||||
'WHERE subscribers.status = 1 ' :
|
||||
'WHERE relation.segment_id IS NOT NULL ') .
|
||||
'GROUP BY segments.id) ' .
|
||||
'UNION ALL ' .
|
||||
'(SELECT 0 as id, "' . __('Not In List') . '" as name, COUNT(*) as subscribers ' .
|
||||
'FROM ' . MP_SUBSCRIBERS_TABLE . ' subscribers ' .
|
||||
'LEFT JOIN ' . MP_SUBSCRIBER_SEGMENT_TABLE . ' relation on relation.subscriber_id = subscribers.id ' .
|
||||
(($withConfirmedSubscribers) ?
|
||||
'WHERE relation.subscriber_id is NULL AND subscribers.status = 1 ' :
|
||||
'WHERE relation.subscriber_id is NULL ') .
|
||||
'HAVING subscribers) ' .
|
||||
'ORDER BY name'
|
||||
)->findArray();
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
$segment = false;
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$segment = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
if($segment === false) {
|
||||
$segment = self::create();
|
||||
$segment->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$segment->set($data);
|
||||
}
|
||||
|
||||
$segment->save();
|
||||
return $segment;
|
||||
}
|
||||
}
|
@ -28,6 +28,13 @@ class Setting extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
public static function setValue($key, $value) {
|
||||
return Setting::createOrUpdate(array(
|
||||
'name' => $key,
|
||||
'value' => $value
|
||||
));
|
||||
}
|
||||
|
||||
public static function getAll() {
|
||||
$settingsCollection = self::findMany();
|
||||
$settings = array();
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoet\Models;
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Subscriber extends Model {
|
||||
@ -15,7 +16,16 @@ class Subscriber extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
function delete() {
|
||||
function segments() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Segment',
|
||||
__NAMESPACE__.'\SubscriberSegment',
|
||||
'subscriber_id',
|
||||
'segment_id'
|
||||
);
|
||||
}
|
||||
|
||||
function delete() {
|
||||
// delete all relations to segments
|
||||
SubscriberSegment::where('subscriber_id', $this->id)->deleteMany();
|
||||
|
||||
@ -42,7 +52,9 @@ class Subscriber extends Model {
|
||||
);
|
||||
|
||||
foreach($segments as $segment) {
|
||||
$subscribers_count = $segment->subscribers()->count();
|
||||
$subscribers_count = $segment->subscribers()
|
||||
->whereNull('deleted_at')
|
||||
->count();
|
||||
if($subscribers_count > 0) {
|
||||
$segment_list[] = array(
|
||||
'label' => sprintf('%s (%d)', $segment->name, $subscribers_count),
|
||||
@ -78,33 +90,27 @@ class Subscriber extends Model {
|
||||
array(
|
||||
'name' => 'all',
|
||||
'label' => __('All'),
|
||||
'count' => Subscriber::whereNull('deleted_at')->count()
|
||||
'count' => Subscriber::getPublished()->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'subscribed',
|
||||
'label' => __('Subscribed'),
|
||||
'count' => Subscriber::whereNull('deleted_at')
|
||||
->where('status', 'subscribed')
|
||||
->count()
|
||||
'count' => Subscriber::filter('subscribed')->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'unconfirmed',
|
||||
'label' => __('Unconfirmed'),
|
||||
'count' => Subscriber::whereNull('deleted_at')
|
||||
->where('status', 'unconfirmed')
|
||||
->count()
|
||||
'count' => Subscriber::filter('unconfirmed')->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'unsubscribed',
|
||||
'label' => __('Unsubscribed'),
|
||||
'count' => Subscriber::whereNull('deleted_at')
|
||||
->where('status', 'unsubscribed')
|
||||
->count()
|
||||
'count' => Subscriber::filter('unsubscribed')->count()
|
||||
),
|
||||
array(
|
||||
'name' => 'trash',
|
||||
'label' => __('Trash'),
|
||||
'count' => Subscriber::whereNotNull('deleted_at')->count()
|
||||
'count' => Subscriber::getTrashed()->count()
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -112,12 +118,10 @@ class Subscriber extends Model {
|
||||
static function groupBy($orm, $group = null) {
|
||||
if($group === 'trash') {
|
||||
return $orm->whereNotNull('deleted_at');
|
||||
} else if($group === 'all') {
|
||||
return $orm->whereNull('deleted_at');
|
||||
} else {
|
||||
$orm = $orm->whereNull('deleted_at');
|
||||
|
||||
if(in_array($group, array('subscribed', 'unsubscribed', 'unconfirmed'))) {
|
||||
return $orm->where('status', $group);
|
||||
}
|
||||
return $orm->filter($group);
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,29 +135,41 @@ class Subscriber extends Model {
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END), NULL) as "' . $customField['name'].'"');
|
||||
}
|
||||
$orm = $orm
|
||||
->left_outer_join(
|
||||
->leftOuterJoin(
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
|
||||
array(MP_SUBSCRIBERS_TABLE.'.id', '=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.subscriber_id'))
|
||||
->left_outer_join(
|
||||
->leftOuterJoin(
|
||||
MP_CUSTOM_FIELDS_TABLE,
|
||||
array(MP_CUSTOM_FIELDS_TABLE.'.id','=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.custom_field_id'))
|
||||
->group_by(MP_SUBSCRIBERS_TABLE.'.id');
|
||||
->groupBy(MP_SUBSCRIBERS_TABLE.'.id');
|
||||
return $orm;
|
||||
}
|
||||
|
||||
function segments() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Segment',
|
||||
__NAMESPACE__.'\SubscriberSegment',
|
||||
'subscriber_id',
|
||||
'segment_id'
|
||||
);
|
||||
static function filterWithCustomFieldsForExport($orm) {
|
||||
$orm = $orm->select(MP_SUBSCRIBERS_TABLE.'.*');
|
||||
$customFields = CustomField::findArray();
|
||||
foreach ($customFields as $customField) {
|
||||
$orm = $orm->selectExpr(
|
||||
'CASE WHEN ' .
|
||||
MP_CUSTOM_FIELDS_TABLE . '.id=' . $customField['id'] . ' THEN ' .
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END as "' . $customField['name'].'"');
|
||||
}
|
||||
$orm = $orm
|
||||
->leftOuterJoin(
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
|
||||
array(MP_SUBSCRIBERS_TABLE.'.id', '=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.subscriber_id'))
|
||||
->leftOuterJoin(
|
||||
MP_CUSTOM_FIELDS_TABLE,
|
||||
array(MP_CUSTOM_FIELDS_TABLE.'.id','=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.custom_field_id'));
|
||||
return $orm;
|
||||
}
|
||||
|
||||
function customFields() {
|
||||
return $this->has_many_through(
|
||||
return $this->hasManyThrough(
|
||||
__NAMESPACE__.'\CustomField',
|
||||
__NAMESPACE__.'\SubscriberCustomField',
|
||||
'subscriber_id',
|
||||
@ -166,27 +182,18 @@ class Subscriber extends Model {
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$subscriber = self::findOne((int)$data['id']);
|
||||
unset($data['id']);
|
||||
}
|
||||
|
||||
if($subscriber === false) {
|
||||
$subscriber = self::create();
|
||||
$subscriber->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$subscriber->set($data);
|
||||
}
|
||||
|
||||
$saved = $subscriber->save();
|
||||
|
||||
if($saved === true) {
|
||||
return true;
|
||||
} else {
|
||||
$errors = $subscriber->getValidationErrors();
|
||||
if(!empty($errors)) {
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
$subscriber->save();
|
||||
return $subscriber;
|
||||
}
|
||||
|
||||
static function bulkMoveToList($orm, $data = array()) {
|
||||
@ -299,4 +306,86 @@ class Subscriber extends Model {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function subscribed($orm) {
|
||||
return $orm
|
||||
->whereNull('deleted_at')
|
||||
->where('status', 'subscribed');
|
||||
}
|
||||
|
||||
static function unsubscribed($orm) {
|
||||
return $orm
|
||||
->whereNull('deleted_at')
|
||||
->where('status', 'unsubscribed');
|
||||
}
|
||||
|
||||
static function unconfirmed($orm) {
|
||||
return $orm
|
||||
->whereNull('deleted_at')
|
||||
->where('status', 'unconfirmed');
|
||||
}
|
||||
|
||||
static function createMultiple($columns, $values) {
|
||||
return self::rawExecute(
|
||||
'INSERT INTO `' . self::$_table . '` ' .
|
||||
'(' . implode(', ', $columns) . ') ' .
|
||||
'VALUES ' . rtrim(
|
||||
str_repeat(
|
||||
'(' . rtrim(str_repeat('?,', count($columns)), ',') . ')' . ', '
|
||||
, count($values)
|
||||
)
|
||||
, ', '),
|
||||
Helpers::flattenArray($values)
|
||||
);
|
||||
}
|
||||
|
||||
static function updateMultiple($columns, $subscribers, $currentTime = false) {
|
||||
$ignoreColumnsOnUpdate = array(
|
||||
'email',
|
||||
'created_at'
|
||||
);
|
||||
$subscribers = array_map('array_values', $subscribers);
|
||||
$emailPosition = array_search('email', $columns);
|
||||
$sql =
|
||||
function ($type) use (
|
||||
$columns,
|
||||
$subscribers,
|
||||
$emailPosition,
|
||||
$ignoreColumnsOnUpdate
|
||||
) {
|
||||
return array_filter(
|
||||
array_map(function ($columnPosition, $columnName) use (
|
||||
$type,
|
||||
$subscribers,
|
||||
$emailPosition,
|
||||
$ignoreColumnsOnUpdate
|
||||
) {
|
||||
if(in_array($columnName, $ignoreColumnsOnUpdate)) return;
|
||||
$query = array_map(
|
||||
function ($subscriber) use ($type, $columnPosition, $emailPosition) {
|
||||
return ($type === 'values') ?
|
||||
array(
|
||||
$subscriber[$emailPosition],
|
||||
$subscriber[$columnPosition]
|
||||
) :
|
||||
'WHEN email = ? THEN ?';
|
||||
}, $subscribers);
|
||||
return ($type === 'values') ?
|
||||
Helpers::flattenArray($query) :
|
||||
$columnName . '= (CASE ' . implode(' ', $query) . ' END)';
|
||||
}, array_keys($columns), $columns)
|
||||
);
|
||||
};
|
||||
return self::rawExecute(
|
||||
'UPDATE `' . self::$_table . '` ' .
|
||||
'SET ' . implode(', ', $sql('statement')) . ' '.
|
||||
(($currentTime) ? ', updated_at = "' . $currentTime . '" ' : '') .
|
||||
'WHERE email IN ' .
|
||||
'(' . rtrim(str_repeat('?,', count($subscribers)), ',') . ')',
|
||||
array_merge(
|
||||
Helpers::flattenArray($sql('values')),
|
||||
Helpers::arrayColumn($subscribers, $emailPosition)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Models;
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SubscriberCustomField extends Model {
|
||||
@ -9,4 +11,40 @@ class SubscriberCustomField extends Model {
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
static function createMultiple($values) {
|
||||
$values = array_map('array_values', $values);
|
||||
return self::rawExecute(
|
||||
'INSERT IGNORE INTO `' . self::$_table . '` ' .
|
||||
'(custom_field_id, subscriber_id, value) ' .
|
||||
'VALUES ' . rtrim(
|
||||
str_repeat(
|
||||
'(?, ?, ?)' . ', '
|
||||
, count($values)
|
||||
), ', '
|
||||
),
|
||||
Helpers::flattenArray($values)
|
||||
);
|
||||
}
|
||||
|
||||
static function updateMultiple($values) {
|
||||
self::createMultiple($values);
|
||||
$values = array_map('array_values', $values);
|
||||
self::rawExecute(
|
||||
'UPDATE `' . self::$_table . '` ' .
|
||||
'SET value = ' .
|
||||
'(CASE ' .
|
||||
str_repeat(
|
||||
'WHEN custom_field_id = ? AND subscriber_id = ? THEN ? ',
|
||||
count($values)
|
||||
) .
|
||||
'END) ' .
|
||||
'WHERE subscriber_id IN (' .
|
||||
implode(', ', Helpers::arrayColumn($values, 1)) .
|
||||
') AND custom_field_id IN (' .
|
||||
implode(', ', array_unique(Helpers::arrayColumn($values, 0)))
|
||||
. ') ',
|
||||
Helpers::flattenArray($values)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Models;
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SubscriberSegment extends Model {
|
||||
@ -9,4 +11,47 @@ class SubscriberSegment extends Model {
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
|
||||
static function filterWithCustomFields($orm) {
|
||||
$orm = $orm->select(MP_SUBSCRIBERS_TABLE.'.*');
|
||||
$customFields = CustomField::findArray();
|
||||
foreach ($customFields as $customField) {
|
||||
$orm = $orm->select_expr(
|
||||
'CASE WHEN ' .
|
||||
MP_CUSTOM_FIELDS_TABLE . '.id=' . $customField['id'] . ' THEN ' .
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END as "' . $customField['name'].'"');
|
||||
}
|
||||
$orm = $orm
|
||||
->left_outer_join(
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
|
||||
array(MP_SUBSCRIBERS_TABLE.'.id', '=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.subscriber_id'))
|
||||
->left_outer_join(
|
||||
MP_CUSTOM_FIELDS_TABLE,
|
||||
array(MP_CUSTOM_FIELDS_TABLE.'.id','=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.custom_field_id'));
|
||||
return $orm;
|
||||
}
|
||||
|
||||
static function createMultiple($segmnets, $subscribers) {
|
||||
$values = Helpers::flattenArray(
|
||||
array_map(function ($segment) use ($subscribers) {
|
||||
return array_map(function ($subscriber) use ($segment) {
|
||||
return array(
|
||||
$segment,
|
||||
$subscriber
|
||||
);
|
||||
}, $subscribers);
|
||||
}, $segmnets)
|
||||
);
|
||||
return self::rawExecute(
|
||||
'INSERT IGNORE INTO `' . self::$_table . '` ' .
|
||||
'(segment_id, subscriber_id) ' .
|
||||
'VALUES ' . rtrim(
|
||||
str_repeat(
|
||||
'(?, ?), ', count($subscribers) * count($segmnets)), ', '
|
||||
),
|
||||
$values
|
||||
);
|
||||
}
|
||||
}
|
@ -50,9 +50,11 @@ class MetaInformationManager {
|
||||
// check if the user specified a label to be displayed before the author's name
|
||||
if(strlen($preceded_by) > 0) {
|
||||
$content = stripslashes($preceded_by) . ' ';
|
||||
} else {
|
||||
$content = '';
|
||||
}
|
||||
|
||||
return join(', ', $categories);
|
||||
return $content . join(', ', $categories);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class PostListTransformer {
|
||||
|
||||
function transform($posts) {
|
||||
$results = array();
|
||||
$use_divider = (bool)$this->args['showDivider'];
|
||||
$use_divider = $this->args['showDivider'] === 'true';
|
||||
|
||||
foreach ($posts as $index => $post) {
|
||||
if ($use_divider && $index > 0) {
|
||||
|
@ -22,16 +22,26 @@ class PostTransformer {
|
||||
$content = $content_manager->filterContent($content);
|
||||
|
||||
$structure_transformer = new StructureTransformer();
|
||||
$structure = $structure_transformer->transform($content, (bool)$this->args['imagePadded']);
|
||||
$structure = $structure_transformer->transform($content, $this->args['imagePadded'] === 'true');
|
||||
|
||||
$structure = $this->appendFeaturedImage($post, (bool)$this->args['imagePadded'], $structure);
|
||||
$structure = $this->appendFeaturedImage(
|
||||
$post,
|
||||
$this->args['displayType'],
|
||||
$this->args['imagePadded'] === 'true',
|
||||
$structure
|
||||
);
|
||||
$structure = $this->appendPostTitle($post, $structure);
|
||||
$structure = $this->appendReadMore($post->ID, $structure);
|
||||
|
||||
return $structure;
|
||||
}
|
||||
|
||||
private function appendFeaturedImage($post, $image_padded, $structure) {
|
||||
private function appendFeaturedImage($post, $display_type, $image_padded, $structure) {
|
||||
if ($display_type === 'full') {
|
||||
// No featured images for full posts
|
||||
return $structure;
|
||||
}
|
||||
|
||||
$featured_image = $this->getFeaturedImage(
|
||||
$post->ID,
|
||||
$post->post_title,
|
||||
@ -68,7 +78,7 @@ class PostTransformer {
|
||||
|
||||
return array(
|
||||
'type' => 'image',
|
||||
'link' => '',
|
||||
'link' => get_permalink($post_id),
|
||||
'src' => $image_info[0],
|
||||
'alt' => $alt_text,
|
||||
'padded' => $image_padded,
|
||||
@ -84,6 +94,8 @@ class PostTransformer {
|
||||
}
|
||||
|
||||
private function appendPostTitle($post, $structure) {
|
||||
$title = $this->getPostTitle($post);
|
||||
|
||||
if ($this->args['titlePosition'] === 'inTextBlock') {
|
||||
// Attach title to the first text block
|
||||
$text_block_index = null;
|
||||
@ -94,7 +106,6 @@ class PostTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
$title = $this->getPostTitle($post);
|
||||
if ($text_block_index === null) {
|
||||
$structure[] = array(
|
||||
'type' => 'text',
|
||||
@ -103,6 +114,14 @@ class PostTransformer {
|
||||
} else {
|
||||
$structure[$text_block_index]['text'] = $title . $structure[$text_block_index]['text'];
|
||||
}
|
||||
} elseif ($this->args['titlePosition'] === 'aboveBlock') {
|
||||
array_unshift(
|
||||
$structure,
|
||||
array(
|
||||
'type' => 'text',
|
||||
'text' => $title,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $structure;
|
||||
@ -113,6 +132,15 @@ class PostTransformer {
|
||||
$button = $this->args['readMoreButton'];
|
||||
$button['url'] = get_permalink($post_id);
|
||||
$structure[] = $button;
|
||||
} else {
|
||||
$structure[] = array(
|
||||
'type' => 'text',
|
||||
'text' => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
get_permalink($post_id),
|
||||
$this->args['readMoreText']
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $structure;
|
||||
@ -121,7 +149,7 @@ class PostTransformer {
|
||||
private function getPostTitle($post) {
|
||||
$title = $post->post_title;
|
||||
|
||||
if ((bool)$this->args['titleIsLink']) {
|
||||
if ($this->args['titleIsLink'] === 'true') {
|
||||
$title = '<a href="' . get_permalink($post->ID) . '">' . $title . '</a>';
|
||||
}
|
||||
|
||||
|
69
lib/Router/CustomFields.php
Normal file
69
lib/Router/CustomFields.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace MailPoet\Router;
|
||||
use \MailPoet\Models\CustomField;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class CustomFields {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function getAll() {
|
||||
$collection = CustomField::findMany();
|
||||
$custom_fields = array_map(function($custom_field) {
|
||||
return $custom_field->asArray();
|
||||
}, $collection);
|
||||
|
||||
wp_send_json($custom_fields);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
$result = false;
|
||||
|
||||
$custom_field = CustomField::findOne($id);
|
||||
if($custom_field !== false) {
|
||||
$custom_field->delete();
|
||||
$result = true;
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function save($data = array()) {
|
||||
$custom_field = CustomField::createOrUpdate($data);
|
||||
|
||||
if($custom_field === false) {
|
||||
$result = array(
|
||||
'result' => false,
|
||||
'errors' => array(
|
||||
__('The custom field could not be created.')
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$errors = $custom_field->getValidationErrors();
|
||||
if(!empty($errors)) {
|
||||
$result = array(
|
||||
'result' => false,
|
||||
'errors' => $errors
|
||||
);
|
||||
} else {
|
||||
$result = array(
|
||||
'result' => true,
|
||||
'field' => $custom_field->asArray()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function get($id) {
|
||||
$custom_field = CustomField::findOne($id);
|
||||
if($custom_field === false) {
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
$custom_field = $custom_field->asArray();
|
||||
wp_send_json($custom_field);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
namespace MailPoet\Router;
|
||||
use \MailPoet\Models\Form;
|
||||
use \MailPoet\Form\Renderer as FormRenderer;
|
||||
use \MailPoet\Listing;
|
||||
use \MailPoet\Form\Util;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -16,7 +18,8 @@ class Forms {
|
||||
if($form === false) {
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
wp_send_json($form->asArray());
|
||||
$form = $form->asArray();
|
||||
wp_send_json($form);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +31,22 @@ class Forms {
|
||||
|
||||
$listing_data = $listing->get();
|
||||
|
||||
// fetch segments relations for each returned item
|
||||
foreach($listing_data['items'] as &$item) {
|
||||
// form's segments
|
||||
$form_settings = (
|
||||
(is_serialized($item['settings']))
|
||||
? unserialize($item['settings'])
|
||||
: array()
|
||||
);
|
||||
|
||||
$item['segments'] = (
|
||||
!empty($form_settings['segments'])
|
||||
? $form_settings['segments']
|
||||
: array()
|
||||
);
|
||||
}
|
||||
|
||||
wp_send_json($listing_data);
|
||||
}
|
||||
|
||||
@ -36,55 +55,199 @@ class Forms {
|
||||
wp_send_json($collection);
|
||||
}
|
||||
|
||||
function save($data = array()) {
|
||||
$result = Form::createOrUpdate($data);
|
||||
function create() {
|
||||
// create new form
|
||||
$form_data = array(
|
||||
'name' => __('New form'),
|
||||
'body' => array(
|
||||
array(
|
||||
'id' => 'email',
|
||||
'name' => __('Email'),
|
||||
'type' => 'input',
|
||||
'static' => true,
|
||||
'params' => array(
|
||||
'label' => __('Email'),
|
||||
'required' => true
|
||||
)
|
||||
),
|
||||
array(
|
||||
'id' => 'submit',
|
||||
'name' => __('Submit'),
|
||||
'type' => 'submit',
|
||||
'static' => true,
|
||||
'params' => array(
|
||||
'label' => __('Subscribe!')
|
||||
)
|
||||
)
|
||||
),
|
||||
'settings' => array(
|
||||
'on_success' => 'message',
|
||||
'success_message' => __('Check your inbox or spam folder now to confirm your subscription.'),
|
||||
'segments' => null,
|
||||
'segments_selected_by' => 'admin'
|
||||
)
|
||||
);
|
||||
|
||||
if($result !== true) {
|
||||
wp_send_json($result);
|
||||
$form = Form::createOrUpdate($form_data);
|
||||
|
||||
if($form !== false && $form->id()) {
|
||||
wp_send_json(
|
||||
admin_url('admin.php?page=mailpoet-form-editor&id='.$form->id())
|
||||
);
|
||||
} else {
|
||||
wp_send_json(true);
|
||||
wp_send_json(false);
|
||||
}
|
||||
}
|
||||
|
||||
function save($data = array()) {
|
||||
$form = Form::createOrUpdate($data);
|
||||
|
||||
if($form !== false && $form->id()) {
|
||||
wp_send_json($form->id());
|
||||
} else {
|
||||
wp_send_json($form);
|
||||
}
|
||||
}
|
||||
|
||||
function previewEditor($data = array()) {
|
||||
// html
|
||||
$html = FormRenderer::renderHTML($data);
|
||||
|
||||
// convert shortcodes
|
||||
$html = do_shortcode($html);
|
||||
|
||||
// styles
|
||||
$css = new Util\Styles(FormRenderer::getStyles($data));
|
||||
|
||||
wp_send_json(array(
|
||||
'html' => $html,
|
||||
'css' => $css->render()
|
||||
));
|
||||
}
|
||||
|
||||
function exportsEditor($id) {
|
||||
$exports = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
|
||||
if($form !== false) {
|
||||
$exports = Util\Export::getAll($form->asArray());
|
||||
}
|
||||
|
||||
wp_send_json($exports);
|
||||
}
|
||||
|
||||
function saveEditor($data = array()) {
|
||||
$form_id = (isset($data['id']) ? (int)$data['id'] : 0);
|
||||
$body = (isset($data['body']) ? $data['body'] : array());
|
||||
$settings = (isset($data['settings']) ? $data['settings'] : array());
|
||||
$styles = (isset($data['styles']) ? $data['styles'] : array());
|
||||
|
||||
if(empty($body) || empty($settings)) {
|
||||
// error
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
// check if the form is used as a widget
|
||||
$is_widget = false;
|
||||
$widgets = get_option('widget_mailpoet_form');
|
||||
if(!empty($widgets)) {
|
||||
foreach($widgets as $widget) {
|
||||
if(isset($widget['form']) && (int)$widget['form'] === $form_id) {
|
||||
$is_widget = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the user gets to pick his own lists
|
||||
// or if it's selected by the admin
|
||||
$has_segment_selection = false;
|
||||
|
||||
foreach ($body as $i => $block) {
|
||||
if($block['type'] === 'segment') {
|
||||
$has_segment_selection = true;
|
||||
if(!empty($block['params']['values'])) {
|
||||
$list_selection = array_map(function($segment) {
|
||||
if(!empty($segment)) {
|
||||
return (int)$segment['id'];
|
||||
}
|
||||
}, $block['params']['values']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check list selectio
|
||||
if($has_segment_selection === true) {
|
||||
$settings['segments_selected_by'] = 'user';
|
||||
} else {
|
||||
$settings['segments_selected_by'] = 'admin';
|
||||
}
|
||||
}
|
||||
|
||||
$form = Form::createOrUpdate(array(
|
||||
'id' => $form_id,
|
||||
'body' => $body,
|
||||
'settings' => $settings,
|
||||
'styles' => $styles
|
||||
));
|
||||
|
||||
// response
|
||||
wp_send_json(array(
|
||||
'result' => ($form !== false),
|
||||
'is_widget' => $is_widget
|
||||
));
|
||||
}
|
||||
|
||||
function restore($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$form->set_expr('deleted_at', 'NULL');
|
||||
$result = $form->save();
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $form->restore();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($data = array()) {
|
||||
$form = Form::findOne($data['id']);
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
function trash($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
if($confirm_delete) {
|
||||
$form->delete();
|
||||
$result = true;
|
||||
} else {
|
||||
$form->set_expr('deleted_at', 'NOW()');
|
||||
$result = $form->save();
|
||||
}
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $form->trash();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$form->delete();
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function duplicate($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::duplicate($id);
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$result = $form;
|
||||
$data = array(
|
||||
'name' => sprintf(__('Copy of %s'), $form->name)
|
||||
);
|
||||
$result = $form->duplicate($data)->asArray();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function bulk_action($data = array()) {
|
||||
function bulkAction($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Form',
|
||||
$data
|
||||
|
60
lib/Router/ImportExport.php
Normal file
60
lib/Router/ImportExport.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace MailPoet\Router;
|
||||
|
||||
use MailPoet\Subscribers\ImportExport\Import\MailChimp;
|
||||
use MailPoet\Models\CustomField;
|
||||
use MailPoet\Models\Segment;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class ImportExport {
|
||||
function getMailChimpLists($data) {
|
||||
$mailChimp = new MailChimp($data['api_key']);
|
||||
wp_send_json($mailChimp->getLists());
|
||||
}
|
||||
|
||||
function getMailChimpSubscribers($data) {
|
||||
$mailChimp = new MailChimp($data['api_key']);
|
||||
wp_send_json($mailChimp->getSubscribers($data['lists']));
|
||||
}
|
||||
|
||||
function addSegment($data) {
|
||||
$segment = Segment::createOrUpdate($data);
|
||||
wp_send_json(
|
||||
($segment->id) ?
|
||||
array(
|
||||
'result' => true,
|
||||
'segment' => $segment->asArray()
|
||||
) :
|
||||
array(
|
||||
'result' => false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function addCustomField($data) {
|
||||
$customField = CustomField::create();
|
||||
$customField->hydrate($data);
|
||||
$result = $customField->save();
|
||||
wp_send_json(
|
||||
($result) ?
|
||||
array(
|
||||
'result' => true,
|
||||
'customField' => $customField->asArray()
|
||||
) :
|
||||
array(
|
||||
'result' => false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function processImport($data) {
|
||||
$import = new \MailPoet\Subscribers\ImportExport\Import\Import(json_decode($data, true));
|
||||
wp_send_json($import->process());
|
||||
}
|
||||
|
||||
function processExport($data) {
|
||||
$export = new \MailPoet\Subscribers\ImportExport\Export\Export(json_decode($data, true));
|
||||
wp_send_json($export->process());
|
||||
}
|
||||
}
|
@ -33,7 +33,6 @@ class Newsletters {
|
||||
}, $segments);
|
||||
$newsletter['options'] = $options;
|
||||
|
||||
|
||||
wp_send_json($newsletter);
|
||||
}
|
||||
}
|
||||
@ -54,29 +53,41 @@ class Newsletters {
|
||||
unset($data['options']);
|
||||
}
|
||||
|
||||
$newsletter_id = Newsletter::createOrUpdate($data);
|
||||
$errors = array();
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::createOrUpdate($data);
|
||||
|
||||
if($newsletter !== false && !$newsletter->id()) {
|
||||
$errors = $newsletter->getValidationErrors();
|
||||
} else {
|
||||
$result = true;
|
||||
|
||||
if($newsletter_id !== false) {
|
||||
if(!empty($segment_ids)) {
|
||||
// remove previous relationships with segments
|
||||
NewsletterSegment::where('newsletter_id', $newsletter_id)->deleteMany();
|
||||
// create relationship with segments
|
||||
NewsletterSegment::where('newsletter_id', $newsletter->id)
|
||||
->deleteMany();
|
||||
|
||||
foreach($segment_ids as $segment_id) {
|
||||
$relation = NewsletterSegment::create();
|
||||
$relation->segment_id = $segment_id;
|
||||
$relation->newsletter_id = $newsletter_id;
|
||||
$relation->newsletter_id = $newsletter->id;
|
||||
$relation->save();
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($options)) {
|
||||
NewsletterOption::where('newsletter_id', $newsletter_id)->deletemany();
|
||||
$optionFields = NewsletterOptionField::where('newsletter_type', $data['type'])->findArray();
|
||||
NewsletterOption::where('newsletter_id', $newsletter->id)
|
||||
->deleteMany();
|
||||
|
||||
$optionFields = NewsletterOptionField::where(
|
||||
'newsletter_type',
|
||||
$data['type']
|
||||
)->findArray();
|
||||
|
||||
foreach($optionFields as $optionField) {
|
||||
if(isset($options[$optionField['name']])) {
|
||||
$relation = NewsletterOption::create();
|
||||
$relation->newsletter_id = $newsletter_id;
|
||||
$relation->newsletter_id = $newsletter->id;
|
||||
$relation->option_field_id = $optionField['id'];
|
||||
$relation->value = $options[$optionField['name']];
|
||||
$relation->save();
|
||||
@ -84,35 +95,57 @@ class Newsletters {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json(($newsletter_id !== false));
|
||||
}
|
||||
|
||||
function delete($data = array()) {
|
||||
$newsletter = newsletter::findOne($data['id']);
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
if($newsletter !== false) {
|
||||
if($confirm_delete) {
|
||||
$newsletter->delete();
|
||||
$result = array('newsletters' => 1);
|
||||
} else {
|
||||
$newsletter->set_expr('deleted_at', 'NOW()');
|
||||
$result = array('newsletters' => (int)$newsletter->save());
|
||||
}
|
||||
} else {
|
||||
$result = false;
|
||||
}
|
||||
wp_send_json($result);
|
||||
wp_send_json(array(
|
||||
'result' => $result,
|
||||
'errors' => $errors
|
||||
));
|
||||
}
|
||||
|
||||
function restore($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$newsletter->set_expr('deleted_at', 'NULL');
|
||||
$result = array('newsletters' => (int)$newsletter->save());
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $newsletter->restore();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function trash($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$result = $newsletter->trash();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$newsletter->delete();
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function duplicate($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$data = array(
|
||||
'subject' => sprintf(__('Copy of %s'), $newsletter->subject)
|
||||
);
|
||||
$result = $newsletter->duplicate($data)->asArray();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
@ -199,7 +232,7 @@ class Newsletters {
|
||||
wp_send_json($listing_data);
|
||||
}
|
||||
|
||||
function bulk_action($data = array()) {
|
||||
function bulkAction($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Newsletter',
|
||||
$data
|
||||
|
@ -71,13 +71,20 @@ class Segments {
|
||||
}
|
||||
|
||||
function save($data = array()) {
|
||||
$result = Segment::createOrUpdate($data);
|
||||
$errors = array();
|
||||
$result = false;
|
||||
|
||||
if($result !== true) {
|
||||
wp_send_json($result);
|
||||
$segment = Segment::createOrUpdate($data);
|
||||
|
||||
if($segment !== false && !$segment->id()) {
|
||||
$errors = $segment->getValidationErrors();
|
||||
} else {
|
||||
wp_send_json(true);
|
||||
$result = true;
|
||||
}
|
||||
wp_send_json(array(
|
||||
'result' => $result,
|
||||
'errors' => $errors
|
||||
));
|
||||
}
|
||||
|
||||
function restore($id) {
|
||||
@ -128,16 +135,7 @@ class Segments {
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function item_action($data = array()) {
|
||||
$item_action = new Listing\ItemAction(
|
||||
'\MailPoet\Models\Segment',
|
||||
$data
|
||||
);
|
||||
|
||||
wp_send_json($item_action->apply());
|
||||
}
|
||||
|
||||
function bulk_action($data = array()) {
|
||||
function bulkAction($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Segment',
|
||||
$data
|
||||
|
@ -4,6 +4,9 @@ namespace MailPoet\Router;
|
||||
use MailPoet\Listing;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Models\Segment;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\Form;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -18,7 +21,14 @@ class Subscribers {
|
||||
if($subscriber === false) {
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
wp_send_json($subscriber->asArray());
|
||||
$segments = $subscriber->segments()->findArray();
|
||||
|
||||
$subscriber = $subscriber->asArray();
|
||||
$subscriber['segments'] = array_map(function($segment) {
|
||||
return $segment['id'];
|
||||
}, $segments);
|
||||
|
||||
wp_send_json($subscriber);
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,8 +65,219 @@ class Subscribers {
|
||||
}
|
||||
|
||||
function save($data = array()) {
|
||||
$result = Subscriber::createOrUpdate($data);
|
||||
wp_send_json($result);
|
||||
$errors = array();
|
||||
$result = false;
|
||||
$segments = false;
|
||||
|
||||
if(array_key_exists('segments', $data)) {
|
||||
$segments = $data['segments'];
|
||||
unset($data['segments']);
|
||||
}
|
||||
|
||||
$subscriber = Subscriber::createOrUpdate($data);
|
||||
|
||||
if($subscriber !== false && !$subscriber->id()) {
|
||||
$errors = $subscriber->getValidationErrors();
|
||||
} else {
|
||||
$result = true;
|
||||
|
||||
if($segments !== false) {
|
||||
SubscriberSegment::where('subscriber_id', $subscriber->id)
|
||||
->deleteMany();
|
||||
|
||||
if(!empty($segments)) {
|
||||
foreach($segments as $segment_id) {
|
||||
$relation = SubscriberSegment::create();
|
||||
$relation->segment_id = $segment_id;
|
||||
$relation->subscriber_id = $subscriber->id;
|
||||
$relation->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wp_send_json(array(
|
||||
'result' => $result,
|
||||
'errors' => $errors
|
||||
));
|
||||
}
|
||||
|
||||
function subscribe($data = array()) {
|
||||
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
|
||||
$errors = array();
|
||||
|
||||
$form = Form::findOne($data['form_id']);
|
||||
unset($data['form_id']);
|
||||
if($form === false || !$form->id()) {
|
||||
$errors[] = __('This form does not exist.');
|
||||
}
|
||||
|
||||
if(empty($data['segments'])) {
|
||||
$errors[] = __('You need to select a list');
|
||||
} else {
|
||||
$segments = Segment::whereIn('id', (array)$data['segments'])->findMany();
|
||||
|
||||
if(empty($segments)) {
|
||||
$errors[] = __('You need to select a list');
|
||||
}
|
||||
}
|
||||
unset($data['segments']);
|
||||
|
||||
$subscriber = false;
|
||||
if(!empty($errors)) {
|
||||
wp_send_json(array('errors' => $errors));
|
||||
} else {
|
||||
if(!empty($data['email'])) {
|
||||
$subscriber = Subscriber::where('email', $data['email'])->findOne();
|
||||
}
|
||||
}
|
||||
|
||||
$signup_confirmation = Setting::getValue('signup_confirmation', array());
|
||||
|
||||
if($subscriber === false) {
|
||||
// create new subscriber
|
||||
$data['status'] = (
|
||||
(!empty($signup_confirmation['enabled']))
|
||||
? 'unconfirmed' : 'subscribed'
|
||||
);
|
||||
|
||||
// // set custom fields
|
||||
// $meta_fields = $mailpoet->getOption('mailpoet_subscriber_meta', array());
|
||||
// if(!empty($meta_fields)) {
|
||||
// // loop through data to see if any meta field has been passed
|
||||
// foreach($meta_fields as $field => $field_data) {
|
||||
// // check if it's a mandatory field
|
||||
// $is_required = (isset($field_data['params']['required']) && (bool)$field_data['params']['required'] === true);
|
||||
|
||||
// if(array_key_exists($field, $data)) {
|
||||
// // check if it's a mandatory field
|
||||
// if($is_required === true && empty($data[$field])) {
|
||||
// // if it's missing, throw an error
|
||||
// $errors[] = sprintf(__('"%s" is required'), $field_data['name']);
|
||||
// } else {
|
||||
// // assign field to subscriber
|
||||
// $subscriber[$field] = $data[$field];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// insert new subscriber
|
||||
$subscriber = Subscriber::createOrUpdate($data);
|
||||
|
||||
if($subscriber === false || !$subscriber->id()) {
|
||||
$errors = array_merge($errors, $subscriber->getValidationErrors());
|
||||
}
|
||||
} else {
|
||||
$subscriber->set('status', (
|
||||
!empty($signup_confirmation['enabled'])
|
||||
? 'unconfirmed' : 'subscribed'
|
||||
));
|
||||
|
||||
// restore deleted subscriber
|
||||
if($subscriber->deleted_at !== NULL) {
|
||||
$subscriber->setExpr('deleted_at', 'NULL');
|
||||
}
|
||||
|
||||
if(!$subscriber->save()) {
|
||||
$errors[] = __('An error occurred. Please try again later.');
|
||||
}
|
||||
}
|
||||
|
||||
// get segments
|
||||
// IDEA: $subscriptions->addToSegments($data['segments']);
|
||||
$segments_subscribed = array();
|
||||
foreach($segments as $segment) {
|
||||
if($segment->addSubscriber($subscriber->id())) {
|
||||
$segments_subscribed[] = $segment->id;
|
||||
}
|
||||
}
|
||||
|
||||
// if signup confirmation is enabled and the subscriber is unconfirmed
|
||||
if(!empty($signup_confirmation['enabled'])
|
||||
&& !empty($segments_subscribed)
|
||||
&& $subscriber->status !== 'subscribed'
|
||||
) {
|
||||
// TODO: send confirmation email
|
||||
// resend confirmation email
|
||||
$is_sent = true;
|
||||
/*$is_sent = static::sendSignupConfirmation(
|
||||
$subscriber->asArray(),
|
||||
$segments->asArray()
|
||||
);*/
|
||||
|
||||
// error message if the email could not be sent
|
||||
if($is_sent === false) {
|
||||
$errors[] = __('The signup confirmation email could not be sent. Please check your settings.');
|
||||
}
|
||||
}
|
||||
|
||||
// get success message to display after subscription
|
||||
$form_settings = (
|
||||
isset($form->settings)
|
||||
? unserialize($form->settings) : null
|
||||
);
|
||||
|
||||
if(!empty($errors)) {
|
||||
wp_send_json(array(
|
||||
'result' => false,
|
||||
'errors' => $errors
|
||||
));
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
if($form_settings !== null) {
|
||||
$message = $form_settings['success_message'];
|
||||
|
||||
// url params for non ajax requests
|
||||
if($doing_ajax === false) {
|
||||
// get referer
|
||||
$referer = (wp_get_referer() !== false)
|
||||
? wp_get_referer() : $_SERVER['HTTP_REFERER'];
|
||||
|
||||
// redirection parameters
|
||||
$params = array(
|
||||
'mailpoet_form' => $form->id()
|
||||
);
|
||||
|
||||
// handle success/error messages
|
||||
if($result === false) {
|
||||
$params['mailpoet_error'] = urlencode($message);
|
||||
} else {
|
||||
$params['mailpoet_success'] = urlencode($message);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($form_settings['on_success']) {
|
||||
case 'page':
|
||||
// response depending on context
|
||||
if($doing_ajax === true) {
|
||||
wp_send_json(array(
|
||||
'result' => $result,
|
||||
'page' => get_permalink($form_settings['success_page']),
|
||||
'message' => $message
|
||||
));
|
||||
} else {
|
||||
$redirect_to = ($result === false) ? $referer : get_permalink($form_settings['success_page']);
|
||||
wp_redirect(add_query_arg($params, $redirect_to));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'message':
|
||||
default:
|
||||
// response depending on context
|
||||
if($doing_ajax === true) {
|
||||
wp_send_json(array(
|
||||
'result' => $result,
|
||||
'message' => $message
|
||||
));
|
||||
} else {
|
||||
// redirect to previous page
|
||||
wp_redirect(add_query_arg($params, $referer));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function restore($id) {
|
||||
@ -93,16 +314,7 @@ class Subscribers {
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function item_action($data = array()) {
|
||||
$item_action = new Listing\ItemAction(
|
||||
'\MailPoet\Models\Segment',
|
||||
$data
|
||||
);
|
||||
|
||||
wp_send_json($item_action->apply());
|
||||
}
|
||||
|
||||
function bulk_action($data = array()) {
|
||||
function bulkAction($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Subscriber',
|
||||
$data
|
||||
|
@ -4,17 +4,17 @@ namespace MailPoet\Settings;
|
||||
class Pages {
|
||||
|
||||
static function getAll() {
|
||||
$mailpoet_pages = get_posts(array(
|
||||
$mailpoet_pages = \get_posts(array(
|
||||
'post_type' => 'mailpoet_page'
|
||||
));
|
||||
|
||||
$pages = array();
|
||||
foreach(array_merge($mailpoet_pages, get_pages()) as $page) {
|
||||
foreach(array_merge($mailpoet_pages, \get_pages()) as $page) {
|
||||
$pages[] = array(
|
||||
'id' => $page->ID,
|
||||
'title' => $page->post_title,
|
||||
'preview_url' => get_permalink($page->ID),
|
||||
'edit_url' => get_edit_post_link($page->ID)
|
||||
'preview_url' => \get_permalink($page->ID),
|
||||
'edit_url' => \get_edit_post_link($page->ID)
|
||||
);
|
||||
}
|
||||
|
||||
|
135
lib/Subscribers/ImportExport/BootStrapMenu.php
Normal file
135
lib/Subscribers/ImportExport/BootStrapMenu.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
namespace MailPoet\Subscribers\ImportExport;
|
||||
|
||||
use MailPoet\Models\CustomField;
|
||||
use MailPoet\Models\Segment;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
class BootStrapMenu {
|
||||
function __construct($action = null) {
|
||||
$this->action = $action;
|
||||
}
|
||||
|
||||
function getSegments($withConfirmedSubscribers = false) {
|
||||
$segments = ($this->action === 'import') ?
|
||||
Segment::getSegmentsForImport() :
|
||||
Segment::getSegmentsForExport($withConfirmedSubscribers);
|
||||
return array_map(function ($segment) {
|
||||
return array(
|
||||
'id' => $segment['id'],
|
||||
'name' => $segment['name'],
|
||||
'subscriberCount' => $segment['subscribers']
|
||||
);
|
||||
}, $segments);
|
||||
}
|
||||
|
||||
function getSubscriberFields() {
|
||||
return array(
|
||||
'email' => __('Email'),
|
||||
'first_name' => __('First name'),
|
||||
'last_name' => __('Last name'),
|
||||
'status' => __('Status')
|
||||
/*
|
||||
'confirmed_ip' => __('IP address')
|
||||
'confirmed_at' => __('Subscription date')
|
||||
*/
|
||||
);
|
||||
}
|
||||
|
||||
function formatSubscriberFields($subscriberFields) {
|
||||
return array_map(function ($fieldId, $fieldName) {
|
||||
return array(
|
||||
'id' => $fieldId,
|
||||
'name' => $fieldName,
|
||||
'type' => ($fieldId === 'confirmed_at') ? 'date' : null,
|
||||
'custom' => false
|
||||
);
|
||||
}, array_keys($subscriberFields), $subscriberFields);
|
||||
}
|
||||
|
||||
function getSubscriberCustomFields() {
|
||||
return CustomField::findArray();
|
||||
}
|
||||
|
||||
function formatSubscriberCustomFields($subscriberCustomFields) {
|
||||
return array_map(function ($field) {
|
||||
return array(
|
||||
'id' => $field['id'],
|
||||
'name' => $field['name'],
|
||||
'type' => $field['type'],
|
||||
'custom' => true
|
||||
);
|
||||
}, $subscriberCustomFields);
|
||||
}
|
||||
|
||||
function formatFieldsForSelect2(
|
||||
$subscriberFields,
|
||||
$subscriberCustomFields) {
|
||||
$actions = ($this->action === 'import') ?
|
||||
array(
|
||||
array(
|
||||
'id' => 'ignore',
|
||||
'name' => __('Ignore column...'),
|
||||
),
|
||||
array(
|
||||
'id' => 'create',
|
||||
'name' => __('Create new column...')
|
||||
),
|
||||
) :
|
||||
array(
|
||||
array(
|
||||
'id' => 'select',
|
||||
'name' => __('Select all...'),
|
||||
),
|
||||
array(
|
||||
'id' => 'deselect',
|
||||
'name' => __('Deselect all...')
|
||||
),
|
||||
);
|
||||
$select2Fields = array(
|
||||
array(
|
||||
'name' => __('Actions'),
|
||||
'children' => $actions
|
||||
),
|
||||
array(
|
||||
'name' => __('System columns'),
|
||||
'children' => $this->formatSubscriberFields($subscriberFields)
|
||||
)
|
||||
);
|
||||
if($subscriberCustomFields) {
|
||||
array_push($select2Fields, array(
|
||||
'name' => __('User columns'),
|
||||
'children' => $this->formatSubscriberCustomFields(
|
||||
$subscriberCustomFields
|
||||
)
|
||||
));
|
||||
}
|
||||
return $select2Fields;
|
||||
}
|
||||
|
||||
function bootstrap() {
|
||||
$subscriberFields = $this->getSubscriberFields();
|
||||
$subscriberCustomFields = $this->getSubscriberCustomFields();
|
||||
$data['segments'] = json_encode($this->getSegments());
|
||||
$data['subscriberFieldsSelect2'] = json_encode(
|
||||
$this->formatFieldsForSelect2(
|
||||
$subscriberFields,
|
||||
$subscriberCustomFields
|
||||
)
|
||||
);
|
||||
if($this->action === 'import') {
|
||||
$data['subscriberFields'] = json_encode(
|
||||
array_merge(
|
||||
$this->formatSubscriberFields($subscriberFields),
|
||||
$this->formatSubscriberCustomFields($subscriberCustomFields)
|
||||
)
|
||||
);
|
||||
$data['maxPostSizeBytes'] = Helpers::getMaxPostSize('bytes');
|
||||
$data['maxPostSize'] = Helpers::getMaxPostSize();
|
||||
} else {
|
||||
$data['segmentsWithConfirmedSubscribers'] =
|
||||
json_encode($this->getSegments($withConfirmedSubscribers = true));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
214
lib/Subscribers/ImportExport/Export/Export.php
Normal file
214
lib/Subscribers/ImportExport/Export/Export.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
namespace MailPoet\Subscribers\ImportExport\Export;
|
||||
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Models\CustomField;
|
||||
use MailPoet\Models\Segment;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\XLSXWriter;
|
||||
use Symfony\Component\Console\Helper\Helper;
|
||||
|
||||
class Export {
|
||||
public function __construct($data) {
|
||||
$this->exportConfirmedOption = $data['exportConfirmedOption'];
|
||||
$this->exportFormatOption = $data['exportFormatOption'];
|
||||
$this->groupBySegmentOption = $data['groupBySegmentOption'];
|
||||
$this->segments = $data['segments'];
|
||||
$this->subscribersWithoutSegment = array_search(0, $this->segments);
|
||||
$this->subscriberFields = $data['subscriberFields'];
|
||||
$this->exportFile = $this->getExportFile($this->exportFormatOption);
|
||||
$this->exportFileURL = $this->getExportFileURL($this->exportFile);
|
||||
$this->profilerStart = microtime(true);
|
||||
}
|
||||
|
||||
function process() {
|
||||
$subscribers = $this->getSubscribers();
|
||||
$subscriberCustomFields = $this->getSubscriberCustomFields();
|
||||
$formattedSubscriberFields = $this->formatSubscriberFields(
|
||||
$this->subscriberFields,
|
||||
$subscriberCustomFields
|
||||
);
|
||||
try {
|
||||
if($this->exportFormatOption === 'csv') {
|
||||
$CSVFile = fopen($this->exportFile, 'w');
|
||||
$formatCSV = function ($row) {
|
||||
return '"' . str_replace('"', '\"', $row) . '"';
|
||||
};
|
||||
// add UTF-8 BOM (3 bytes, hex EF BB BF) at the start of the file for
|
||||
// Excel to automatically recognize the encoding
|
||||
fwrite($CSVFile, chr(0xEF) . chr(0xBB) . chr(0xBF));
|
||||
if($this->groupBySegmentOption) {
|
||||
$formattedSubscriberFields[] = __('List');
|
||||
}
|
||||
fwrite(
|
||||
$CSVFile,
|
||||
implode(
|
||||
',',
|
||||
array_map(
|
||||
$formatCSV,
|
||||
$formattedSubscriberFields
|
||||
)
|
||||
) . "\n"
|
||||
);
|
||||
foreach ($subscribers as $subscriber) {
|
||||
$row = $this->formatSubscriberData(
|
||||
$subscriber,
|
||||
$formattedSubscriberFields
|
||||
);
|
||||
if($this->groupBySegmentOption) {
|
||||
$row[] = ucwords($subscriber['segment_name']);
|
||||
}
|
||||
fwrite($CSVFile, implode(',', array_map($formatCSV, $row)) . "\n");
|
||||
}
|
||||
fclose($CSVFile);
|
||||
} else {
|
||||
$writer = new XLSXWriter();
|
||||
$writer->setAuthor('MailPoet (www.mailpoet.com)');
|
||||
$headerRow = array($formattedSubscriberFields);
|
||||
$lastSegment = false;
|
||||
$rows = array();
|
||||
foreach ($subscribers as $subscriber) {
|
||||
if($lastSegment && $lastSegment !== $subscriber['segment_name'] &&
|
||||
$this->groupBySegmentOption
|
||||
) {
|
||||
$writer->writeSheet(
|
||||
array_merge($headerRow, $rows), ucwords($lastSegment)
|
||||
);
|
||||
$rows = array();
|
||||
}
|
||||
// detect RTL language and set Excel to properly display the sheet
|
||||
$RTLRegex = '/\p{Arabic}|\p{Hebrew}/u';
|
||||
if(!$writer->rtl && (
|
||||
preg_grep($RTLRegex, $subscriber) ||
|
||||
preg_grep($RTLRegex, $formattedSubscriberFields))
|
||||
) {
|
||||
$writer->rtl = true;
|
||||
}
|
||||
$rows[] = $this->formatSubscriberData(
|
||||
$subscriber,
|
||||
$formattedSubscriberFields
|
||||
);
|
||||
$lastSegment = $subscriber['segment_name'];
|
||||
}
|
||||
$writer->writeSheet(array_merge($headerRow, $rows), 'MailPoet');
|
||||
$writer->writeToFile($this->exportFile);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return array(
|
||||
'result' => false,
|
||||
'error' => $e->getMessage()
|
||||
);
|
||||
}
|
||||
return array(
|
||||
'result' => true,
|
||||
'data' => array(
|
||||
'totalExported' => count($subscribers),
|
||||
'exportFileURL' => $this->exportFileURL
|
||||
),
|
||||
'profiler' => $this->timeExecution()
|
||||
);
|
||||
}
|
||||
|
||||
function getSubscribers() {
|
||||
$subscribers = Subscriber::
|
||||
left_outer_join(
|
||||
SubscriberSegment::$_table,
|
||||
array(
|
||||
Subscriber::$_table . '.id',
|
||||
'=',
|
||||
SubscriberSegment::$_table . '.subscriber_id'
|
||||
))
|
||||
->left_outer_join(
|
||||
Segment::$_table,
|
||||
array(
|
||||
Segment::$_table . '.id',
|
||||
'=',
|
||||
SubscriberSegment::$_table . '.segment_id'
|
||||
))
|
||||
->orderByAsc('segment_name')
|
||||
->filter('filterWithCustomFieldsForExport');
|
||||
if($this->subscribersWithoutSegment !== false) {
|
||||
$subscribers = $subscribers
|
||||
->selectExpr('CASE WHEN ' . Segment::$_table . '.name IS NOT NULL ' .
|
||||
'THEN ' . Segment::$_table . '.name ' .
|
||||
'ELSE "' . __('Not In List') . '" END as segment_name'
|
||||
)
|
||||
->whereRaw(
|
||||
SubscriberSegment::$_table . '.segment_id IN (' .
|
||||
rtrim(str_repeat('?,', count($this->segments)), ',') . ') ' .
|
||||
'OR ' . SubscriberSegment::$_table . '.segment_id IS NULL ',
|
||||
$this->segments
|
||||
);
|
||||
} else {
|
||||
$subscribers = $subscribers
|
||||
->select(Segment::$_table . '.name', 'segment_name')
|
||||
->whereIn(SubscriberSegment::$_table . '.segment_id', $this->segments);
|
||||
}
|
||||
if(!$this->groupBySegmentOption) {
|
||||
$subscribers =
|
||||
$subscribers->groupBy(Subscriber::$_table . '.id');
|
||||
}
|
||||
if($this->exportConfirmedOption) {
|
||||
$subscribers =
|
||||
$subscribers->where(Subscriber::$_table . '.status', 'subscribed');
|
||||
}
|
||||
return $subscribers->findArray();
|
||||
}
|
||||
|
||||
function getExportFileURL($file) {
|
||||
return sprintf(
|
||||
'%s/%s/%s',
|
||||
Env::$plugin_url,
|
||||
Env::$temp_name,
|
||||
basename($file)
|
||||
);
|
||||
}
|
||||
|
||||
function getExportFile($format) {
|
||||
return sprintf(
|
||||
Env::$temp_path . '/MailPoet_export_%s.%s',
|
||||
substr(md5(time()), 0, 4),
|
||||
$format
|
||||
);
|
||||
}
|
||||
|
||||
function getSubscriberCustomFields() {
|
||||
return Helpers::arrayColumn(
|
||||
CustomField::findArray(),
|
||||
'name',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
|
||||
function formatSubscriberFields($subscriberFields, $subscriberCustomFields) {
|
||||
$bootStrapMenu = new BootStrapMenu();
|
||||
$translatedFields = $bootStrapMenu->getSubscriberFields();
|
||||
return array_map(function ($field) use (
|
||||
$translatedFields, $subscriberCustomFields
|
||||
) {
|
||||
$field = (isset($translatedFields[$field])) ?
|
||||
ucfirst($translatedFields[$field]) :
|
||||
ucfirst($field);
|
||||
return (isset($subscriberCustomFields[$field])) ?
|
||||
$subscriberCustomFields[$field] : $field;
|
||||
}, $subscriberFields);
|
||||
}
|
||||
|
||||
function formatSubscriberData($subscriber, $subscriberCustomFields) {
|
||||
return array_map(function ($field) use (
|
||||
$subscriber, $subscriberCustomFields
|
||||
) {
|
||||
return (isset($subscriberCustomFields[$field])) ?
|
||||
$subscriberCustomFields[$field] :
|
||||
$subscriber[$field];
|
||||
}, $this->subscriberFields);
|
||||
}
|
||||
|
||||
function timeExecution() {
|
||||
$profilerEnd = microtime(true);
|
||||
return ($profilerEnd - $this->profilerStart) / 60;
|
||||
}
|
||||
}
|
304
lib/Subscribers/ImportExport/Import/Import.php
Normal file
304
lib/Subscribers/ImportExport/Import/Import.php
Normal file
@ -0,0 +1,304 @@
|
||||
<?php
|
||||
namespace MailPoet\Subscribers\ImportExport\Import;
|
||||
|
||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberCustomField;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
class Import {
|
||||
public function __construct($data) {
|
||||
$this->subscribersData = $data['subscribers'];
|
||||
$this->segments = $data['segments'];
|
||||
$this->updateSubscribers = $data['updateSubscribers'];
|
||||
$this->subscriberFields = $this->getSubscriberFields(
|
||||
array_keys($this->subscribersData)
|
||||
);
|
||||
$this->subscriberCustomFields = $this->getCustomSubscriberFields(
|
||||
array_keys($this->subscribersData)
|
||||
);
|
||||
$this->subscribersCount = count(reset($this->subscribersData));
|
||||
$this->currentTime = date('Y-m-d H:i:s');
|
||||
$this->profilerStart = microtime(true);
|
||||
}
|
||||
|
||||
function process() {
|
||||
$subscriberFields = $this->subscriberFields;
|
||||
$subscriberCustomFields = $this->subscriberCustomFields;
|
||||
$subscribersData = $this->subscribersData;
|
||||
$subscribersData = $this->filterSubscriberStatus($subscribersData);
|
||||
list($subscribersData, $subscriberFields) = $this->extendSubscribersAndFields(
|
||||
$subscribersData, $subscriberFields
|
||||
);
|
||||
list($existingSubscribers, $newSubscribers) =
|
||||
$this->filterExistingAndNewSubscribers($subscribersData);
|
||||
$createdSubscribers = $updatedSubscribers = array();
|
||||
try {
|
||||
if($newSubscribers) {
|
||||
$createdSubscribers =
|
||||
$this->createOrUpdateSubscribers(
|
||||
'create',
|
||||
$newSubscribers,
|
||||
$subscriberFields,
|
||||
$subscriberCustomFields
|
||||
);
|
||||
}
|
||||
if($existingSubscribers && $this->updateSubscribers) {
|
||||
$updatedSubscribers =
|
||||
$this->createOrUpdateSubscribers(
|
||||
'update',
|
||||
$existingSubscribers,
|
||||
$subscriberFields,
|
||||
$subscriberCustomFields
|
||||
);
|
||||
if($createdSubscribers) {
|
||||
// subtract added from updated subscribers when DB operation takes <1s
|
||||
$updatedSubscribers = array_diff_key(
|
||||
$updatedSubscribers,
|
||||
$createdSubscribers,
|
||||
$subscriberCustomFields
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
return array(
|
||||
'result' => false,
|
||||
'error' => $e->getMessage()
|
||||
);
|
||||
}
|
||||
$segments = new BootStrapMenu('import');
|
||||
return array(
|
||||
'result' => true,
|
||||
'data' => array(
|
||||
'created' => count($createdSubscribers),
|
||||
'updated' => count($updatedSubscribers),
|
||||
'segments' => $segments->getSegments()
|
||||
),
|
||||
'profiler' => $this->timeExecution()
|
||||
);
|
||||
}
|
||||
|
||||
function filterExistingAndNewSubscribers($subscribersData) {
|
||||
$existingRecords = array_filter(
|
||||
array_map(function ($subscriberEmails) {
|
||||
return Subscriber::selectMany(array('email'))
|
||||
->whereIn('email', $subscriberEmails)
|
||||
->findArray();
|
||||
}, array_chunk($subscribersData['email'], 200))
|
||||
);
|
||||
if(!$existingRecords) {
|
||||
return array(
|
||||
false,
|
||||
$subscribersData
|
||||
);
|
||||
}
|
||||
$existingRecords = Helpers::flattenArray($existingRecords);
|
||||
$newRecords = array_keys(
|
||||
array_diff(
|
||||
$subscribersData['email'],
|
||||
$existingRecords
|
||||
)
|
||||
);
|
||||
if(!$newRecords) {
|
||||
return array(
|
||||
$subscribersData,
|
||||
false
|
||||
);
|
||||
}
|
||||
$newSubscribers =
|
||||
array_filter(
|
||||
array_map(function ($subscriber) use ($newRecords) {
|
||||
return array_map(function ($index) use ($subscriber) {
|
||||
return $subscriber[$index];
|
||||
}, $newRecords);
|
||||
}, $subscribersData)
|
||||
);
|
||||
|
||||
$existingSubscribers =
|
||||
array_map(function ($subscriber) use ($newRecords) {
|
||||
return array_values( // reindex array
|
||||
array_filter( // remove NULL entries
|
||||
array_map(function ($index, $data) use ($newRecords) {
|
||||
if(!in_array($index, $newRecords)) return $data;
|
||||
}, array_keys($subscriber), $subscriber)
|
||||
)
|
||||
);
|
||||
}, $subscribersData);
|
||||
return array(
|
||||
$existingSubscribers,
|
||||
$newSubscribers
|
||||
);
|
||||
}
|
||||
|
||||
function extendSubscribersAndFields($subscribersData, $subscriberFields) {
|
||||
$subscribersData['created_at'] = $this->filterSubscriberCreatedAtDate();
|
||||
$subscriberFields[] = 'created_at';
|
||||
return array(
|
||||
$subscribersData,
|
||||
$subscriberFields
|
||||
);
|
||||
}
|
||||
|
||||
function getSubscriberFields($subscriberFields) {
|
||||
return array_values(
|
||||
array_filter(
|
||||
array_map(function ($field) {
|
||||
if(!is_int($field)) return $field;
|
||||
}, $subscriberFields)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getCustomSubscriberFields($subscriberFields) {
|
||||
return array_values(
|
||||
array_filter(
|
||||
array_map(function ($field) {
|
||||
if(is_int($field)) return $field;
|
||||
}, $subscriberFields)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function filterSubscriberCreatedAtDate() {
|
||||
return array_fill(0, $this->subscribersCount, $this->currentTime);
|
||||
}
|
||||
|
||||
function filterSubscriberStatus($subscribersData) {
|
||||
if(!in_array('status', $this->subscriberFields)) return $subscribersData;
|
||||
$statuses = array(
|
||||
'subscribed' => array(
|
||||
'subscribed',
|
||||
'confirmed',
|
||||
1,
|
||||
'1',
|
||||
'true'
|
||||
),
|
||||
'unconfirmed' => array(
|
||||
'unconfirmed',
|
||||
0,
|
||||
"0"
|
||||
),
|
||||
'unsubscribed' => array(
|
||||
'unsubscribed',
|
||||
-1,
|
||||
'-1',
|
||||
'false'
|
||||
)
|
||||
);
|
||||
$subscribersData['status'] = array_map(function ($state) use ($statuses) {
|
||||
if(in_array(strtolower($state), $statuses['subscribed'])) {
|
||||
return 'subscribed';
|
||||
}
|
||||
if(in_array(strtolower($state), $statuses['unsubscribed'])) {
|
||||
return 'unsubscribed';
|
||||
}
|
||||
if(in_array(strtolower($state), $statuses['unconfirmed'])) {
|
||||
return 'unconfirmed';
|
||||
}
|
||||
return 'subscribed'; // make "subscribed" a default status
|
||||
}, $subscribersData['status']);
|
||||
return $subscribersData;
|
||||
}
|
||||
|
||||
function createOrUpdateSubscribers(
|
||||
$action,
|
||||
$subscribersData,
|
||||
$subscriberFields,
|
||||
$subscriberCustomFields
|
||||
) {
|
||||
$subscribersCount = count(reset($subscribersData)) - 1;
|
||||
$subscribers = array_map(function ($index) use ($subscribersData, $subscriberFields) {
|
||||
return array_map(function ($field) use ($index, $subscribersData) {
|
||||
return $subscribersData[$field][$index];
|
||||
}, $subscriberFields);
|
||||
}, range(0, $subscribersCount));
|
||||
$currentTime = ($action === 'update') ? date('Y-m-d H:i:s') : $this->currentTime;
|
||||
foreach (array_chunk($subscribers, 200) as $data) {
|
||||
if($action == 'create') {
|
||||
Subscriber::createMultiple(
|
||||
$subscriberFields,
|
||||
$data
|
||||
);
|
||||
}
|
||||
if($action == 'update') {
|
||||
Subscriber::updateMultiple(
|
||||
$subscriberFields,
|
||||
$data,
|
||||
$currentTime
|
||||
);
|
||||
}
|
||||
}
|
||||
$result = Helpers::arrayColumn( // return id=>email array of results
|
||||
Subscriber::selectMany(
|
||||
array(
|
||||
'id',
|
||||
'email'
|
||||
))
|
||||
->where(($action === 'create') ? 'created_at' : 'updated_at', $currentTime)
|
||||
->findArray(),
|
||||
'email', 'id'
|
||||
);
|
||||
if($subscriberCustomFields) {
|
||||
$this->createOrUpdateCustomFields(
|
||||
($action === 'create') ? 'create' : 'update',
|
||||
$result,
|
||||
$subscribersData,
|
||||
$subscriberCustomFields
|
||||
);
|
||||
}
|
||||
$this->addSubscribersToSegments(
|
||||
array_keys($result),
|
||||
$this->segments
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
|
||||
function createOrUpdateCustomFields(
|
||||
$action,
|
||||
$dbSubscribers,
|
||||
$subscribersData,
|
||||
$subscriberCustomFields
|
||||
) {
|
||||
$subscribers = array_map(
|
||||
function ($column) use ($dbSubscribers, $subscribersData) {
|
||||
$count = range(0, count($subscribersData[$column]) - 1);
|
||||
return array_map(
|
||||
function ($index, $value)
|
||||
use ($dbSubscribers, $subscribersData, $column) {
|
||||
$subscriberId = array_search(
|
||||
$subscribersData['email'][$index],
|
||||
$dbSubscribers
|
||||
);
|
||||
return array(
|
||||
$column,
|
||||
$subscriberId,
|
||||
$value
|
||||
);
|
||||
}, $count, $subscribersData[$column]);
|
||||
}, $subscriberCustomFields)[0];
|
||||
foreach (array_chunk($subscribers, 200) as $data) {
|
||||
if($action === 'create') {
|
||||
SubscriberCustomField::createMultiple(
|
||||
$data
|
||||
);
|
||||
}
|
||||
if($action === 'update') {
|
||||
SubscriberCustomField::updateMultiple(
|
||||
$data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addSubscribersToSegments($subscribers, $segments) {
|
||||
foreach (array_chunk($subscribers, 200) as $data) {
|
||||
SubscriberSegment::createMultiple($segments, $data);
|
||||
}
|
||||
}
|
||||
|
||||
function timeExecution() {
|
||||
$profilerEnd = microtime(true);
|
||||
return ($profilerEnd - $this->profilerStart) / 60;
|
||||
}
|
||||
}
|
156
lib/Subscribers/ImportExport/Import/MailChimp.php
Normal file
156
lib/Subscribers/ImportExport/Import/MailChimp.php
Normal file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
namespace MailPoet\Subscribers\ImportExport\Import;
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
class MailChimp {
|
||||
function __construct($APIKey, $lists = false) {
|
||||
$this->APIKey = $this->getAPIKey($APIKey);
|
||||
$this->maxPostSize = Helpers::getMaxPostSize('bytes');
|
||||
$this->dataCenter = $this->getDataCenter($this->APIKey);
|
||||
$this->listsURL = 'https://%s.api.mailchimp.com/2.0/lists/list?apikey=%s';
|
||||
$this->exportURL = 'https://%s.api.mailchimp.com/export/1.0/list/?apikey=%s&id=%s';
|
||||
}
|
||||
|
||||
function getLists() {
|
||||
if(!$this->APIKey || !$this->dataCenter) {
|
||||
return $this->processError('API');
|
||||
}
|
||||
|
||||
$connection = @fopen(sprintf($this->listsURL, $this->dataCenter, $this->APIKey), 'r');
|
||||
|
||||
if(!$connection) {
|
||||
return $this->processError('connection');
|
||||
} else {
|
||||
$response = '';
|
||||
while (!feof($connection)) {
|
||||
$buffer = fgets($connection, 4096);
|
||||
if(trim($buffer) !== '') {
|
||||
$response .= $buffer;
|
||||
}
|
||||
}
|
||||
fclose($connection);
|
||||
}
|
||||
|
||||
$response = json_decode($response);
|
||||
|
||||
if(!$response) {
|
||||
return $this->processError('API');
|
||||
}
|
||||
|
||||
foreach ($response->data as $list) {
|
||||
$lists[] = array(
|
||||
'id' => $list->id,
|
||||
'name' => $list->name
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'result' => true,
|
||||
'data' => $lists
|
||||
);
|
||||
}
|
||||
|
||||
function getSubscribers($lists = array()) {
|
||||
if(!$this->APIKey || !$this->dataCenter) {
|
||||
return $this->processError('API');
|
||||
}
|
||||
|
||||
if(!$lists) {
|
||||
return $this->processError('lists');
|
||||
}
|
||||
|
||||
$bytesFetched = 0;
|
||||
foreach ($lists as $list) {
|
||||
$url = sprintf($this->exportURL, $this->dataCenter, $this->APIKey, $list);
|
||||
$connection = @fopen($url, 'r');
|
||||
if(!$connection) {
|
||||
return $this->processError('connection');
|
||||
} else {
|
||||
$i = 0;
|
||||
$header = array();
|
||||
while (!feof($connection)) {
|
||||
$buffer = fgets($connection, 4096);
|
||||
if(trim($buffer) !== '') {
|
||||
$obj = json_decode($buffer);
|
||||
if($i === 0) {
|
||||
$header = $obj;
|
||||
if(is_object($header) && isset($header->error)) {
|
||||
return $this->processError('lists');
|
||||
}
|
||||
if(!isset($headerHash)) {
|
||||
$headerHash = md5(implode(',', $header));
|
||||
} else {
|
||||
if(md5(implode(',', $header) !== $headerHash)) {
|
||||
return $this->processError('headers');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$subscribers[] = $obj;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
$bytesFetched += strlen($buffer);
|
||||
if($bytesFetched > $this->maxPostSize) {
|
||||
return $this->processError('size');
|
||||
|
||||
}
|
||||
}
|
||||
fclose($connection);
|
||||
}
|
||||
}
|
||||
|
||||
if(!count($subscribers)) {
|
||||
return $this->processError('subscribers');
|
||||
|
||||
}
|
||||
|
||||
return array(
|
||||
'result' => true,
|
||||
'data' => array(
|
||||
'subscribers' => $subscribers,
|
||||
'invalid' => false,
|
||||
'duplicate' => false,
|
||||
'header' => $header,
|
||||
'count' => count($subscribers)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getDataCenter($APIKey) {
|
||||
// double parantheses: http://phpsadness.com/sad/51
|
||||
return ($APIKey) ? end((explode('-', $APIKey))) : false;
|
||||
}
|
||||
|
||||
function getAPIKey($APIKey) {
|
||||
return (preg_match('/[a-zA-Z0-9]{32}-[a-zA-Z0-9]{3,}/', $APIKey)) ? $APIKey : false;
|
||||
}
|
||||
|
||||
function processError($error) {
|
||||
switch ($error) {
|
||||
case 'API':
|
||||
$errorMessage = __('Invalid API key.');
|
||||
break;
|
||||
case 'connection':
|
||||
$errorMessage = __('Could not connect to your MailChimp account.');
|
||||
break;
|
||||
case 'headers':
|
||||
$errorMessage = __('The selected lists do not have matching columns (headers).');
|
||||
break;
|
||||
case 'size':
|
||||
$errorMessage = __('Information received from MailChimp is too large for processing. Please limit the number of lists.');
|
||||
break;
|
||||
case 'subscribers':
|
||||
$errorMessage = __('Did not find any active subscribers.');
|
||||
break;
|
||||
case 'lists':
|
||||
$errorMessage = __('Did not find any valid lists');
|
||||
break;
|
||||
}
|
||||
return array(
|
||||
'result' => false,
|
||||
'error' => $errorMessage
|
||||
);
|
||||
}
|
||||
}
|
@ -51,9 +51,13 @@ class Handlebars extends \Twig_Extension {
|
||||
|
||||
if($alias !== null) {
|
||||
$output[] = '<script type="text/javascript">';
|
||||
$output[] = ' Handlebars.registerPartial(
|
||||
"'.$alias.'",
|
||||
jQuery("#'.$id.'").html());';
|
||||
$output[] = 'jQuery(function($) {';
|
||||
$output[] = '$(function() {';
|
||||
$output[] = ' Handlebars.registerPartial(
|
||||
"'.$alias.'",
|
||||
jQuery("#'.$id.'").html());';
|
||||
$output[] = '});';
|
||||
$output[] = '});';
|
||||
$output[] = '</script>';
|
||||
}
|
||||
return join("\n", $output);
|
||||
|
167
lib/Util/Helpers.php
Normal file
167
lib/Util/Helpers.php
Normal file
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
namespace MailPoet\Util;
|
||||
|
||||
class Helpers {
|
||||
|
||||
/*
|
||||
* Matches each symbol of PHP date format standard
|
||||
* with jQuery equivalent codeword
|
||||
* @author Tristan Jahier
|
||||
*/
|
||||
static function dateformat_PHP_to_jQueryUI($php_format) {
|
||||
$SYMBOLS_MATCHING = array(
|
||||
// Day
|
||||
'd' => 'dd',
|
||||
'D' => 'D',
|
||||
'j' => 'd',
|
||||
'l' => 'DD',
|
||||
'N' => '',
|
||||
'S' => '',
|
||||
'w' => '',
|
||||
'z' => 'o',
|
||||
// Week
|
||||
'W' => '',
|
||||
// Month
|
||||
'F' => 'MM',
|
||||
'm' => 'mm',
|
||||
'M' => 'M',
|
||||
'n' => 'm',
|
||||
't' => '',
|
||||
// Year
|
||||
'L' => '',
|
||||
'o' => '',
|
||||
'Y' => 'yy',
|
||||
'y' => 'y',
|
||||
// Time
|
||||
'a' => '',
|
||||
'A' => '',
|
||||
'B' => '',
|
||||
'g' => '',
|
||||
'G' => '',
|
||||
'h' => '',
|
||||
'H' => '',
|
||||
'i' => '',
|
||||
's' => '',
|
||||
'u' => ''
|
||||
);
|
||||
$jqueryui_format = "";
|
||||
$escaping = false;
|
||||
for ($i = 0; $i < strlen($php_format); $i++) {
|
||||
$char = $php_format[$i];
|
||||
if($char === '\\') // PHP date format escaping character
|
||||
{
|
||||
$i++;
|
||||
if($escaping) {
|
||||
$jqueryui_format .= $php_format[$i];
|
||||
} else {
|
||||
$jqueryui_format .= '\'' . $php_format[$i];
|
||||
}
|
||||
$escaping = true;
|
||||
} else {
|
||||
if($escaping) {
|
||||
$jqueryui_format .= "'";
|
||||
$escaping = false;
|
||||
}
|
||||
if(isset($SYMBOLS_MATCHING[$char])) {
|
||||
$jqueryui_format .= $SYMBOLS_MATCHING[$char];
|
||||
} else {
|
||||
$jqueryui_format .= $char;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $jqueryui_format;
|
||||
}
|
||||
|
||||
static function getMaxPostSize($bytes = false) {
|
||||
$maxPostSize = ini_get('post_max_size');
|
||||
if(!$bytes) return $maxPostSize;
|
||||
switch (substr ($maxPostSize, -1))
|
||||
{
|
||||
case 'M': case 'm': return (int)$maxPostSize * 1048576;
|
||||
case 'K': case 'k': return (int)$maxPostSize * 1024;
|
||||
case 'G': case 'g': return (int)$maxPostSize * 1073741824;
|
||||
default: return $maxPostSize;
|
||||
}
|
||||
}
|
||||
|
||||
static function flattenArray($array) {
|
||||
if(!$array) return;
|
||||
$flattened_array = array();
|
||||
array_walk_recursive($array, function ($a) use (&$flattened_array) { $flattened_array[] = $a; });
|
||||
return $flattened_array;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using func_get_args() in order to check for proper number ofparameters and trigger errors exactly as the built-in array_column()
|
||||
* does in PHP 5.5.
|
||||
* @author Ben Ramsey (http://benramsey.com)
|
||||
*/
|
||||
static function arrayColumn($input = null, $columnKey = null, $indexKey = null) {
|
||||
$argc = func_num_args();
|
||||
$params = func_get_args();
|
||||
if($argc < 2) {
|
||||
trigger_error("array_column() expects at least 2 parameters, {$argc} given", E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
if(!is_array($params[0])) {
|
||||
trigger_error(
|
||||
'array_column() expects parameter 1 to be array, ' . gettype($params[0]) . ' given',
|
||||
E_USER_WARNING
|
||||
);
|
||||
return null;
|
||||
}
|
||||
if(!is_int($params[1])
|
||||
&& !is_float($params[1])
|
||||
&& !is_string($params[1])
|
||||
&& $params[1] !== null
|
||||
&& !(is_object($params[1]) && method_exists($params[1], '__toString'))
|
||||
) {
|
||||
trigger_error('array_column(): The column key should be either a string or an integer', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
if(isset($params[2])
|
||||
&& !is_int($params[2])
|
||||
&& !is_float($params[2])
|
||||
&& !is_string($params[2])
|
||||
&& !(is_object($params[2]) && method_exists($params[2], '__toString'))
|
||||
) {
|
||||
trigger_error('array_column(): The index key should be either a string or an integer', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
$paramsInput = $params[0];
|
||||
$paramsColumnKey = ($params[1] !== null) ? (string) $params[1] : null;
|
||||
$paramsIndexKey = null;
|
||||
if(isset($params[2])) {
|
||||
if(is_float($params[2]) || is_int($params[2])) {
|
||||
$paramsIndexKey = (int) $params[2];
|
||||
} else {
|
||||
$paramsIndexKey = (string) $params[2];
|
||||
}
|
||||
}
|
||||
$resultArray = array();
|
||||
foreach ($paramsInput as $row) {
|
||||
$key = $value = null;
|
||||
$keySet = $valueSet = false;
|
||||
if($paramsIndexKey !== null && array_key_exists($paramsIndexKey, $row)) {
|
||||
$keySet = true;
|
||||
$key = (string) $row[$paramsIndexKey];
|
||||
}
|
||||
if($paramsColumnKey === null) {
|
||||
$valueSet = true;
|
||||
$value = $row;
|
||||
} elseif(is_array($row) && array_key_exists($paramsColumnKey, $row)) {
|
||||
$valueSet = true;
|
||||
$value = $row[$paramsColumnKey];
|
||||
}
|
||||
if($valueSet) {
|
||||
if($keySet) {
|
||||
$resultArray[$key] = $value;
|
||||
} else {
|
||||
$resultArray[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $resultArray;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user