diff --git a/assets/css/src/admin.styl b/assets/css/src/admin.styl index 294d5a5ecc..32bed150e9 100644 --- a/assets/css/src/admin.styl +++ b/assets/css/src/admin.styl @@ -5,13 +5,15 @@ @require 'common' @require 'modal' @require 'notice' -@require 'parsley' @require 'form_editor' @require 'listing' @require 'box' @require 'breadcrumb' + @require 'form' +@require 'parsley' +@require 'form_validation' @require 'settings' -@require 'progress_bar' \ No newline at end of file +@require 'progress_bar' diff --git a/assets/css/src/form_editor.styl b/assets/css/src/form_editor.styl index 67ed105838..4f2a622699 100644 --- a/assets/css/src/form_editor.styl +++ b/assets/css/src/form_editor.styl @@ -4,6 +4,9 @@ icons = '../img/form_editor_icons.png' handle_icon = '../img/handle.png' +#mailpoet_form_name + font-size: 23px + #mailpoet_form_history display: none @@ -99,6 +102,7 @@ handle_icon = '../img/handle.png' /* MailPoet Form wrapper */ #mailpoet_form_wrapper position: relative + margin: 20px 0 0 0 /* MailPoet Form container */ #mailpoet_form_container diff --git a/assets/css/src/form_validation.styl b/assets/css/src/form_validation.styl new file mode 100644 index 0000000000..558f2c6994 --- /dev/null +++ b/assets/css/src/form_validation.styl @@ -0,0 +1,6 @@ +.parsley-errors-list + margin-top: 8px + +.parsley-required +.parsley-custom-error-message + color: #b94a48 \ No newline at end of file diff --git a/assets/css/src/public.styl b/assets/css/src/public.styl index c5f4f00c0c..1bd2ff2e95 100644 --- a/assets/css/src/public.styl +++ b/assets/css/src/public.styl @@ -1,3 +1,4 @@ @import 'nib' @require 'parsley' +@require 'form_validation' diff --git a/assets/js/src/form_editor/form_editor.js b/assets/js/src/form_editor/form_editor.js index c645dff857..e60f59d8e0 100644 --- a/assets/js/src/form_editor/form_editor.js +++ b/assets/js/src/form_editor/form_editor.js @@ -231,7 +231,7 @@ var WysijaHistory = { /* MailPoet Form */ var WysijaForm = { - version: '0.6', + version: '0.7', options: { container: 'mailpoet_form_container', editor: 'mailpoet_form_editor', @@ -317,6 +317,7 @@ var WysijaForm = { save: function() { var position = 1, data = { + 'name': $F('mailpoet_form_name'), 'settings': $('mailpoet_form_settings').serialize(true), 'body': [], 'styles': (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null diff --git a/assets/js/src/public.js b/assets/js/src/public.js index 52a41bcbd2..8cdbea3d91 100644 --- a/assets/js/src/public.js +++ b/assets/js/src/public.js @@ -20,7 +20,10 @@ function( $('form.mailpoet_form').each(function() { var form = $(this); - form.parsley().on('form:submit', function(parsley) { + form.parsley({ + errorsWrapper: '

', + errorTemplate: '' + }).on('form:submit', function(parsley) { var data = form.serializeObject() || {}; diff --git a/assets/js/src/segments/form.jsx b/assets/js/src/segments/form.jsx index b339f60825..04ac4d8cb6 100644 --- a/assets/js/src/segments/form.jsx +++ b/assets/js/src/segments/form.jsx @@ -42,11 +42,7 @@ define( return (

- Segment Back to list + Segment

- Subscriber Back to list + Subscriber

setupChangelog(); $this->setupPublicAPI(); $this->runQueueSupervisor(); + $this->setupShortcodes(); $this->setupHooks(); $this->setupImages(); } @@ -125,6 +126,10 @@ class Initializer { $changelog->init(); } + function setupShortcodes() { + $shortcodes = new Shortcodes(); + $shortcodes->init(); + } function setupHooks() { $hooks = new Hooks(); $hooks->init(); diff --git a/lib/Config/Menu.php b/lib/Config/Menu.php index 02de34616a..c61eb55d80 100644 --- a/lib/Config/Menu.php +++ b/lib/Config/Menu.php @@ -374,7 +374,8 @@ class Menu { ->findArray(), 'styles' => FormRenderer::getStyles($form), 'date_types' => Block\Date::getDateTypes(), - 'date_formats' => Block\Date::getDateFormats() + 'date_formats' => Block\Date::getDateFormats(), + 'month_names' => Block\Date::getMonthNames() ); echo $this->renderer->render('form/editor.html', $data); diff --git a/lib/Config/Shortcodes.php b/lib/Config/Shortcodes.php new file mode 100644 index 0000000000..b7e2716eb4 --- /dev/null +++ b/lib/Config/Shortcodes.php @@ -0,0 +1,26 @@ + 0) { + $form_widget = new \MailPoet\Form\Widget(); + return $form_widget->widget(array( + 'form' => (int)$params['id'], + 'form_type' => 'shortcode' + )); + } + } +} \ No newline at end of file diff --git a/lib/Form/Block/Base.php b/lib/Form/Block/Base.php index 0c62a6a513..27f912b28b 100644 --- a/lib/Form/Block/Base.php +++ b/lib/Form/Block/Base.php @@ -29,7 +29,13 @@ abstract class Base { } } - $validation = ''; + if($block['type'] === 'radio') { + $rules['group'] = 'custom_field_'.$block['id']; + $rules['errors-container'] = '.mailpoet_error_'.$block['id']; + $rules['required-message'] = __('You need to select at least one option.'); + } + + $validation = array(); if(!empty($rules)) { $rules = array_unique($rules); @@ -37,10 +43,10 @@ abstract class Base { if(is_bool($value)) { $value = ($value) ? 'true' : 'false'; } - $validation .= 'data-parsley-'.$rule.'="'.$value.'"'; + $validation[] = 'data-parsley-'.$rule.'="'.$value.'"'; } } - return $validation; + return join(' ', $validation); } protected static function renderLabel($block) { @@ -86,7 +92,11 @@ abstract class Base { // return field name depending on block data protected static function getFieldName($block = array()) { - return $block['id']; + if((int)$block['id'] > 0) { + return 'cf_'.$block['id']; + } else { + return $block['id']; + } } protected static function getFieldLabel($block = array()) { @@ -98,6 +108,6 @@ abstract class Base { protected static function getFieldValue($block = array()) { return (isset($block['params']['value']) && strlen(trim($block['params']['value'])) > 0) - ? trim($block['params']['value']) : ''; + ? esc_attr(trim($block['params']['value'])) : ''; } } \ No newline at end of file diff --git a/lib/Form/Block/Radio.php b/lib/Form/Block/Radio.php index a8082bfd59..ba3b7c8d71 100644 --- a/lib/Form/Block/Radio.php +++ b/lib/Form/Block/Radio.php @@ -9,14 +9,12 @@ class Radio extends Base { $field_name = static::getFieldName($block); $field_validation = static::getInputValidation($block); - // TODO: check if it still makes sense - // create hidden default value - // $html .= ''; - $html .= '

'; $html .= static::renderLabel($block); + $html .= ''; + foreach($block['params']['values'] as $option) { $html .= ''; } diff --git a/lib/Form/Widget.php b/lib/Form/Widget.php index f1a6af5d4c..f670e03aac 100644 --- a/lib/Form/Widget.php +++ b/lib/Form/Widget.php @@ -36,9 +36,9 @@ class Widget extends \WP_Widget { return parent::__construct( 'mailpoet_form', - __("MailPoet Subscription Form"), + __('MailPoet Form'), array( - 'title' => __("Newsletter subscription form"), + 'description' => __('Add a newsletter subscription form.') ) ); } @@ -196,24 +196,6 @@ class Widget extends \WP_Widget { } } -// mailpoet shortcodes -// form shortcode -add_shortcode('mailpoet_form', 'mailpoet_form_shortcode'); -add_shortcode('wysija_form', 'mailpoet_form_shortcode'); - -function mailpoet_form_shortcode($params = array()) { - // IMPORTANT: this is to make sure MagicMember won't scan our form and find [user_list] as a code they should replace. - remove_shortcode('user_list'); - - if(isset($params['id']) && (int)$params['id'] > 0) { - $form_widget = new \MailPoet\Form\Widget(); - return $form_widget->widget(array( - 'form' => (int)$params['id'], - 'form_type' => 'shortcode' - )); - } -} - // set the content filter to replace the shortcode if(isset($_GET['mailpoet_page']) && strlen(trim($_GET['mailpoet_page'])) > 0) { switch($_GET['mailpoet_page']) { diff --git a/lib/Mailer/MailPoet.php b/lib/Mailer/MailPoet.php index 10763a9363..a62216e35c 100644 --- a/lib/Mailer/MailPoet.php +++ b/lib/Mailer/MailPoet.php @@ -70,7 +70,7 @@ class MailPoet { 'Content-Type' => 'application/json', 'Authorization' => $this->auth() ), - 'body' => json_encode($body) + 'body' => $body ); } } \ No newline at end of file diff --git a/lib/Router/Forms.php b/lib/Router/Forms.php index f506d6948c..ce4c6cf097 100644 --- a/lib/Router/Forms.php +++ b/lib/Router/Forms.php @@ -139,6 +139,7 @@ class Forms { function saveEditor($data = array()) { $form_id = (isset($data['id']) ? (int)$data['id'] : 0); + $name = (isset($data['name']) ? $data['name'] : array()); $body = (isset($data['body']) ? $data['body'] : array()); $settings = (isset($data['settings']) ? $data['settings'] : array()); $styles = (isset($data['styles']) ? $data['styles'] : array()); @@ -187,6 +188,7 @@ class Forms { $form = Form::createOrUpdate(array( 'id' => $form_id, + 'name' => $name, 'body' => $body, 'settings' => $settings, 'styles' => $styles diff --git a/lib/Router/Subscribers.php b/lib/Router/Subscribers.php index 538115a25e..161e1d6305 100644 --- a/lib/Router/Subscribers.php +++ b/lib/Router/Subscribers.php @@ -4,6 +4,7 @@ namespace MailPoet\Router; use MailPoet\Listing; use MailPoet\Models\Subscriber; use MailPoet\Models\SubscriberSegment; +use MailPoet\Models\SubscriberCustomField; use MailPoet\Models\Segment; use MailPoet\Models\Setting; use MailPoet\Models\Form; @@ -140,32 +141,37 @@ class Subscribers { ? '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]; - // } - // } - // } - // } + // custom fields + $custom_fields = array(); + foreach($data as $key => $value) { + if(strpos($key, 'cf_') === 0) { + $custom_fields[substr($key, 3)] = $value; + unset($data[$key]); + } + } // insert new subscriber $subscriber = Subscriber::createOrUpdate($data); if($subscriber === false || !$subscriber->id()) { $errors = array_merge($errors, $subscriber->getValidationErrors()); + } else { + // add custom fields + if(!empty($custom_fields)) { + foreach($custom_fields as $custom_field_id => $value) { + if(is_array($value)) { + // date + $value = mktime(0, 0, 0, $value['month'], $value['day'], $value['year']); + } + $subscriber_custom_field = SubscriberCustomField::create(); + $subscriber_custom_field->hydrate(array( + 'subscriber_id' => $subscriber->id(), + 'custom_field_id' => $custom_field_id, + 'value' => $value + )); + $subscriber_custom_field->save(); + } + } } } else { $subscriber->set('status', ( diff --git a/views/form/editor.html b/views/form/editor.html index 31fca1db67..c77c2cc317 100644 --- a/views/form/editor.html +++ b/views/form/editor.html @@ -2,17 +2,12 @@ <% block title %>

- <%= form.name %> - - <%= __('Edit name' ) %> - <%= __('List of forms' ) %> +

<% endblock %> @@ -122,29 +117,36 @@

-

<%= __('Shortcodes') %>

+

<%= __('Form Placement') %>

- <%= __("You can easily add this form to your theme's in the [link]Widgets area[/link]") + <%= __("Add this form to your sidebar or footer in the [link]Widgets[/link].") | replace({ '[link]': '', '[/link]': '' }) | raw %> -

+

- <%= __('%sHTML%s, %sPHP%s, %siframe%s and %sshortcode%s versions are also available.', 'wysija-newsletters') + <%= __("Copy and paste this [link]shortcode[/link] into a post or page alternatively.") + | replace({ + '[link]': '', + '[/link]': '' + }) + | raw + %> +

+

+ <%= __('%sHTML%s, %sPHP%s and %siframe%s versions are also available.', 'wysija-newsletters') | format( '', '', '', '', '', - '', - '', '' ) | raw @@ -254,6 +256,14 @@ ]; jQuery(function($) { + function mailpoet_form_toggle_segments() { + // hide list selection if a list widget has been dragged into the editor + $('mailpoet_settings_segment_selection')[ + (($$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0) === true) + ? 'hide' : 'show' + ](); + } + function mailpoet_form_fields() { // form editor: default fields var template = Handlebars.compile(jQuery('#form_template_fields').html()); @@ -269,8 +279,13 @@ if(response !== false) { data.fields = $.merge(response, data.fields); } + // render toolbar jQuery('#mailpoet_toolbar_fields').html(template(data)); + + setTimeout(function() { + WysijaForm.init(); + }, 1); }); } window.mailpoet_form_fields = mailpoet_form_fields; @@ -299,7 +314,7 @@ }); // toolbar: open default section - $('.mailpoet_toolbar_section[data-section="settings"]') + $('.mailpoet_toolbar_section[data-section="fields"]') .removeClass('closed'); // form: edit name (in place editor) @@ -385,6 +400,14 @@ return false; }); + // edit name + $('#mailpoet_form_name').on('keyup', function(e) { + if(e.which === 13) { + $('#mailpoet_form_save').trigger('click'); + this.blur(); + } + }); + // preview form $(document).on('click', '#mailpoet_form_preview', function() { //mailpoet_form_save(mailpoet_form_preview); @@ -465,7 +488,7 @@ action: 'exportsEditor', data: $('#mailpoet_form_id').val() }).done(function(response) { - if(response !== false) { + if(response.result !== false) { $('#mailpoet_form_export').html(template({ exports: response })); } }); @@ -483,11 +506,7 @@ // open popup MailPoet.Modal.popup({ title: "<%= __('Add new field') %>", - template: $('#form_template_field_new').html(), - onSuccess: function(data) { - // toggle widgets - WysijaForm.toggleWidgets(); - } + template: $('#form_template_field_new').html() }); return false; @@ -502,7 +521,7 @@ action: 'get', data: id }).done(function(response) { - if(response !== false) { + if(response.result !== false) { MailPoet.Modal.popup({ title: "<%= __('Edit field') %>", template: $('#form_template_field_new').html(), @@ -519,14 +538,14 @@ var name = $(this).siblings('.mailpoet_form_field').attr('wysija_name'); if(window.confirm( - "<%= __('Do you really want to delete this custom field?') %>" + "<%= __('Deleting this field here will delete the data associated to it for all you users. Confirm you want to delete.') %>" )) { MailPoet.Ajax.post({ endpoint: 'customFields', action: 'delete', data: id - }).done(function(response) { - if(response === true) { + }).done(function(result) { + if(result === true) { item.remove(); mailpoet_form_fields(); MailPoet.Notice.success( @@ -546,15 +565,13 @@ }); // get form fields - mailpoet_form_fields().done(function() { - WysijaForm.init(); - }); + mailpoet_form_fields(); // toolbar: segment selection var selected_segments = <%= form.settings.segments | json_encode | raw %>; // enable select2 for segment selection - $('#mailpoet_form_segments').select2({ + var select2 = $('#mailpoet_form_segments').select2({ width:'100%', templateResult: function(item) { if(item.element && item.element.selected) { @@ -563,7 +580,23 @@ return item.text; } } - }).select2('val', <%= form.settings.segments | json_encode | raw %>); + }); + + var hasRemoved = false; + select2.on('select2:unselecting', function(e) { + hasRemoved = true; + }); + select2.on('select2:opening', function(e) { + if(hasRemoved === true) { + hasRemoved = false; + e.preventDefault(); + } + }); + + // set selected values + $('#mailpoet_form_segments') + .val(<%= form.settings.segments | json_encode | raw %>) + .trigger('change'); }); }); diff --git a/views/form/templates/blocks/date_days.hbs b/views/form/templates/blocks/date_days.hbs index 505f7a5890..38e13a0b8e 100644 --- a/views/form/templates/blocks/date_days.hbs +++ b/views/form/templates/blocks/date_days.hbs @@ -1,10 +1,10 @@ -<% set currentDay = 'now'|date("d") %> - +<% set currentDay = 'now' | date('d') | number_format %> \ No newline at end of file diff --git a/views/form/templates/blocks/date_months.hbs b/views/form/templates/blocks/date_months.hbs index 43407fdacd..4ce4d6d3f6 100644 --- a/views/form/templates/blocks/date_months.hbs +++ b/views/form/templates/blocks/date_months.hbs @@ -1,11 +1,12 @@ <% set currentMonth = 'now'|date('n') %> - \ No newline at end of file diff --git a/views/form/templates/blocks/date_years.hbs b/views/form/templates/blocks/date_years.hbs index ac51cd496d..ce13f49914 100644 --- a/views/form/templates/blocks/date_years.hbs +++ b/views/form/templates/blocks/date_years.hbs @@ -4,8 +4,9 @@ \ No newline at end of file diff --git a/views/form/templates/blocks/html.hbs b/views/form/templates/blocks/html.hbs index 323cc70d76..9ae3b42e71 100644 --- a/views/form/templates/blocks/html.hbs +++ b/views/form/templates/blocks/html.hbs @@ -1,9 +1,7 @@ {{#if params.text}} -

- {{#if params.nl2br}} - {{{ nl2br params.text }}} - {{else}} - {{{ params.text }}} - {{/if}} -

+ {{#ifCond params.nl2br '==' '1'}} + {{{ nl2br params.text }}} + {{else}} + {{{ params.text }}} + {{/ifCond}} {{/if}} \ No newline at end of file diff --git a/views/form/templates/blocks/submit.hbs b/views/form/templates/blocks/submit.hbs index 0d21a9874f..177137fc98 100644 --- a/views/form/templates/blocks/submit.hbs +++ b/views/form/templates/blocks/submit.hbs @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/views/form/templates/settings/field_new.hbs b/views/form/templates/settings/field_new.hbs index 400a89a15f..dc9c1cf5d0 100644 --- a/views/form/templates/settings/field_new.hbs +++ b/views/form/templates/settings/field_new.hbs @@ -1,9 +1,20 @@ - + {{#if id}}{{/if}}

-

- +


@@ -49,41 +66,41 @@ $(function() { loadFieldForm(); - }); - $('#form_field_new').on('submit', function(e) { - e.preventDefault(); + $('#form_field_new').parsley().on('form:submit', function(parsley) { + // get data + var data = $(this.$element).serializeObject(); - // get data - var data = $(this).serializeObject(); - MailPoet.Ajax.post({ - endpoint: 'customFields', - action: 'save', - data: data - }).done(function(response) { - if(response.result === true) { - mailpoet_form_fields(); - if(data.id) { - MailPoet.Notice.success( - "<%= __('Updated custom field “"+data.name+"“') %>" - ); + // save custom field + MailPoet.Ajax.post({ + endpoint: 'customFields', + action: 'save', + data: data + }).done(function(response) { + if(response.result === true) { + mailpoet_form_fields(); + if(data.id) { + MailPoet.Notice.success( + "<%= __('Updated custom field “"+data.name+"“') %>" + ); + } else { + MailPoet.Notice.success( + "<%= __('Added custom field “"+data.name+"“') %>" + ); + } + + // close popup + MailPoet.Modal.success(); } else { - MailPoet.Notice.success( - "<%= __('Added custom field “"+data.name+"“') %>" - ); - } - - } else { - if(response.errors.length > 0) { - for(error in response.errors) { - MailPoet.Notice.error(error); + if(response.errors.length > 0) { + $(response.errors).each(function(i, error) { + MailPoet.Notice.error(error); + }); } } - } + }); + return false; }); - - // close popup - return MailPoet.Modal.success(); }); $('#form_field_new #field_type').on('change', function() { diff --git a/views/form/widget.html b/views/form/widget.html index 9a8f7e2c9a..0d6e2888fc 100644 --- a/views/form/widget.html +++ b/views/form/widget.html @@ -15,7 +15,6 @@ #> class="mailpoet_form mailpoet_form_<%= form_type %>" novalidate - data-parsley-validate >