Form editor
- new/edit in forms listing goes to editor - fixed editor dependencies (via Webpack) - updated forms table schema - saving/loading a form works
This commit is contained in:
@ -1,3 +1,6 @@
|
|||||||
|
@require 'codemirror/lib/codemirror.css'
|
||||||
|
@require 'codemirror/theme/neo.css'
|
||||||
|
|
||||||
icons = '../img/form_editor_icons.png'
|
icons = '../img/form_editor_icons.png'
|
||||||
handle_icon = '../img/handle.png'
|
handle_icon = '../img/handle.png'
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ const item_actions = [
|
|||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
link: function(item) {
|
link: function(item) {
|
||||||
return (
|
return (
|
||||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
<a href={ `admin.php?page=mailpoet-form-editor&id=${item.id}` }>Edit</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -117,7 +117,19 @@ const bulk_actions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const FormList = React.createClass({
|
const FormList = React.createClass({
|
||||||
renderItem: function(form, actions) {
|
createForm() {
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'forms',
|
||||||
|
action: 'save',
|
||||||
|
data: {
|
||||||
|
name: "New form"
|
||||||
|
}
|
||||||
|
}).done(function(response) {
|
||||||
|
window.location =
|
||||||
|
'admin.php?page=mailpoet-form-editor&id='+ parseInt(response, 10);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
renderItem(form, actions) {
|
||||||
let row_classes = classNames(
|
let row_classes = classNames(
|
||||||
'manage-column',
|
'manage-column',
|
||||||
'column-primary',
|
'column-primary',
|
||||||
@ -151,7 +163,11 @@ const FormList = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="title">
|
<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>
|
</h2>
|
||||||
|
|
||||||
<Listing
|
<Listing
|
||||||
|
@ -3,6 +3,7 @@ namespace MailPoet\Config;
|
|||||||
use \MailPoet\Models\Segment;
|
use \MailPoet\Models\Segment;
|
||||||
use \MailPoet\Models\Setting;
|
use \MailPoet\Models\Setting;
|
||||||
use \MailPoet\Models\Form;
|
use \MailPoet\Models\Form;
|
||||||
|
use \MailPoet\Form\Renderer as FormRenderer;
|
||||||
use \MailPoet\Settings\Hosts;
|
use \MailPoet\Settings\Hosts;
|
||||||
use \MailPoet\Settings\Pages;
|
use \MailPoet\Settings\Pages;
|
||||||
use \MailPoet\Settings\Charsets;
|
use \MailPoet\Settings\Charsets;
|
||||||
@ -203,20 +204,26 @@ class Menu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formEditor() {
|
function formEditor() {
|
||||||
$data = array();
|
|
||||||
|
|
||||||
$form = array(
|
$form = array(
|
||||||
'name' => __('My new form')
|
'name' => __('My new form')
|
||||||
);
|
);
|
||||||
|
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
|
||||||
$id = (isset($_POST['id']) ? (int)$_POST['id'] : 0);
|
|
||||||
$form = Form::findOne($id);
|
$form = Form::findOne($id);
|
||||||
if($form !== false) {
|
if($form !== false) {
|
||||||
|
$segments = $form->segments();
|
||||||
$form = $form->asArray();
|
$form = $form->asArray();
|
||||||
|
$form['segments'] = array_map(function($segment) {
|
||||||
|
return $segment['id'];
|
||||||
|
}, $segments->findArray());
|
||||||
}
|
}
|
||||||
$data['form'] = $form;
|
|
||||||
|
|
||||||
$data['segments'] = Segment::findArray();
|
$data = array(
|
||||||
|
'form' => $form,
|
||||||
|
'pages' => Pages::getAll(),
|
||||||
|
'segments' => Segment::findArray(),
|
||||||
|
'styles' => FormRenderer::getStyles($form)
|
||||||
|
);
|
||||||
|
|
||||||
echo $this->renderer->render('form/editor.html', $data);
|
echo $this->renderer->render('form/editor.html', $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ class Migrator {
|
|||||||
$attributes = array(
|
$attributes = array(
|
||||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||||
'name varchar(90) NOT NULL,',
|
'name varchar(90) NOT NULL,',
|
||||||
'body longtext,',
|
'data longtext,',
|
||||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
|
@ -57,6 +57,10 @@ class Form extends Model {
|
|||||||
$form = self::findOne((int)$data['id']);
|
$form = self::findOne((int)$data['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!empty($data['data'])) {
|
||||||
|
$data['data'] = json_encode($data['data']);
|
||||||
|
}
|
||||||
|
|
||||||
if($form === false) {
|
if($form === false) {
|
||||||
$form = self::create();
|
$form = self::create();
|
||||||
$form->hydrate($data);
|
$form->hydrate($data);
|
||||||
|
@ -75,13 +75,72 @@ class Forms {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($form === false) {
|
if($form !== false && $form->id()) {
|
||||||
wp_send_json($form->getValidationErrors());
|
wp_send_json($form->id());
|
||||||
} else {
|
} else {
|
||||||
wp_send_json(true);
|
wp_send_json($form);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function save_editor($data = array()) {
|
||||||
|
$form_id = (isset($data['id']) ? (int)$data['id'] : 0);
|
||||||
|
$form_data = (isset($data['form']) ? $data['form'] : array());
|
||||||
|
|
||||||
|
if(empty($form_data)) {
|
||||||
|
// error
|
||||||
|
wp_send_json(false);
|
||||||
|
} else {
|
||||||
|
// check if the form is displayed as a widget (we'll display a different "saved!" message in this case)
|
||||||
|
$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_list_selection = false;
|
||||||
|
|
||||||
|
|
||||||
|
$blocks = (isset($form_data['body']) ? $form_data['body'] : array());
|
||||||
|
if(!empty($blocks)) {
|
||||||
|
foreach ($blocks as $i => $block) {
|
||||||
|
if($block['type'] === 'list') {
|
||||||
|
$has_list_selection = true;
|
||||||
|
if(!empty($block['params']['values'])) {
|
||||||
|
$list_selection = array_map(function($segment) {
|
||||||
|
return (int)$segment['id'];
|
||||||
|
}, $block['params']['values']);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check list selectio
|
||||||
|
if($has_list_selection === true) {
|
||||||
|
$form_data['lists_selected_by'] = 'user';
|
||||||
|
} else {
|
||||||
|
$form_data['lists_selected_by'] = 'admin';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = Form::createOrUpdate(array(
|
||||||
|
'id' => $form_id,
|
||||||
|
'data' => $form_data
|
||||||
|
));
|
||||||
|
|
||||||
|
// response
|
||||||
|
wp_send_json(array(
|
||||||
|
'result' => ($form !== false),
|
||||||
|
'is_widget' => $is_widget
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
function restore($id) {
|
function restore($id) {
|
||||||
$result = false;
|
$result = false;
|
||||||
|
|
||||||
|
@ -34,28 +34,31 @@
|
|||||||
<div>
|
<div>
|
||||||
<!-- Form settings -->
|
<!-- Form settings -->
|
||||||
<form id="mailpoet_form_settings" action="" method="POST">
|
<form id="mailpoet_form_settings" action="" method="POST">
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
id="mailpoet_form_id"
|
||||||
|
value="<%= form.id | default(0) %>"
|
||||||
|
/>
|
||||||
<div id="mailpoet_settings_list_selection">
|
<div id="mailpoet_settings_list_selection">
|
||||||
<!-- Form settings: list selection -->
|
<!-- Form settings: list selection -->
|
||||||
<p>
|
<p>
|
||||||
<strong><%= __('This form adds subscribers to these lists:') %></strong>
|
<strong><%= __('This form adds subscribers to these segments:') %></strong>
|
||||||
</p>
|
</p>
|
||||||
<select name="lists" data-placeholder="<%= __('Choose a list') %>" multiple>
|
<select
|
||||||
|
id="mailpoet_form_segments"
|
||||||
|
name="segments"
|
||||||
|
data-placeholder="<%= __('Choose a list') %>"
|
||||||
|
multiple
|
||||||
|
>
|
||||||
<% for segment in segments %>
|
<% for segment in segments %>
|
||||||
<option value="<%= segment.id %>"
|
<option value="<%= segment.id %>"><%= segment.name %></option>
|
||||||
<% if segment.id in form.segments %>
|
|
||||||
selected="selected"
|
|
||||||
<% endif %>
|
|
||||||
><%= segment.name %></option>
|
|
||||||
<% endfor %>
|
<% endfor %>
|
||||||
</select>
|
</select>
|
||||||
<!-- error if user tries to save and has not selected a list -->
|
|
||||||
<p class="mailpoet_error" data-error="admin_no_list">
|
|
||||||
<%= __('You have to select at least 1 list') %>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="mailpoet_on_success">
|
<div id="mailpoet_on_success">
|
||||||
<!-- Form settings: after submit -->
|
<!-- Form settings: after submit -->
|
||||||
|
<input type="hidden" name="on_success" value="message" />
|
||||||
<p>
|
<p>
|
||||||
<label><strong><%= __('After submit...') %></strong></label>
|
<label><strong><%= __('After submit...') %></strong></label>
|
||||||
<label>
|
<label>
|
||||||
@ -63,6 +66,7 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
name="on_success"
|
name="on_success"
|
||||||
value="message"
|
value="message"
|
||||||
|
<% if(on_success == 'message') %>checked="checked"<% endif %>
|
||||||
/><%= __('Show message') %>
|
/><%= __('Show message') %>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@ -71,6 +75,7 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
name="on_success"
|
name="on_success"
|
||||||
value="page"
|
value="page"
|
||||||
|
<% if(on_success == 'page') %>checked="checked"<% endif %>
|
||||||
/><%= __('Go to page') %>
|
/><%= __('Go to page') %>
|
||||||
</label>
|
</label>
|
||||||
</p>
|
</p>
|
||||||
@ -93,10 +98,10 @@
|
|||||||
>
|
>
|
||||||
<select name="success_page">
|
<select name="success_page">
|
||||||
<% for page in pages %>
|
<% for page in pages %>
|
||||||
<option value="<%= page.ID %>"
|
<option value="<%= page.id %>"
|
||||||
<%- if form.data.settings.success_page != page.ID %>
|
<%- if form.data.settings.success_page != page.id %>
|
||||||
<%=- ' selected="selected"' %>
|
<%=- ' selected="selected"' %>
|
||||||
<%- endif %>><%= page.post_title %></option>
|
<%- endif %>><%= page.title %></option>
|
||||||
<% endfor %>
|
<% endfor %>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
@ -173,8 +178,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= javascript(
|
<%= javascript(
|
||||||
|
'vendor.js',
|
||||||
'lib/prototype.min.js',
|
'lib/prototype.min.js',
|
||||||
'lib/scriptaculous.min.js',
|
'lib/scriptaculous.min.js',
|
||||||
|
'form_editor_lib.js',
|
||||||
'form_editor.js'
|
'form_editor.js'
|
||||||
)%>
|
)%>
|
||||||
|
|
||||||
@ -309,20 +316,26 @@
|
|||||||
|
|
||||||
// save change if necessary
|
// save change if necessary
|
||||||
if(new_value !== '' && current_value !== new_value) {
|
if(new_value !== '' && current_value !== new_value) {
|
||||||
console.log('TODO: form->save', {
|
MailPoet.Ajax.post({
|
||||||
form: <%= form.id | default(0) %>,
|
endpoint: 'forms',
|
||||||
form_name: new_value,
|
action: 'save',
|
||||||
|
data: {
|
||||||
|
id: $('#mailpoet_form_id').val(),
|
||||||
|
name: new_value
|
||||||
|
}
|
||||||
|
}).done(function(response) {
|
||||||
|
MailPoet.Notice.success(
|
||||||
|
"<%= __('Form name successfully updated!') %>"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
MailPoet.Notice.success("<%= __('Form name successfully updated!') %>");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// on dom loaded
|
// on dom loaded
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
// load form
|
// load form
|
||||||
WysijaForm.load(<%= form | json_encode | raw %>);
|
WysijaForm.load(<%= form.data | raw %>);
|
||||||
|
|
||||||
// save form
|
// save form
|
||||||
$('#mailpoet_form_save').on('click', function() {
|
$('#mailpoet_form_save').on('click', function() {
|
||||||
@ -349,58 +362,35 @@
|
|||||||
mailpoet_form_export();
|
mailpoet_form_export();
|
||||||
|
|
||||||
function mailpoet_form_save(callback) {
|
function mailpoet_form_save(callback) {
|
||||||
console.log('TODO: form->save');
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'forms',
|
||||||
// if there is a callback, call it!
|
action: 'save_editor',
|
||||||
if(callback !== undefined) {
|
data: {
|
||||||
callback();
|
id: $('#mailpoet_form_id').val(),
|
||||||
}
|
form: WysijaForm.save()
|
||||||
/*mailpoet_post_json('form_save.php', {
|
|
||||||
form: <%= form.form %>,
|
|
||||||
data: WysijaForm.save()
|
|
||||||
}, function(response) {
|
|
||||||
if(response.result === false) {
|
|
||||||
var error = null;
|
|
||||||
if(response.error !== undefined) {
|
|
||||||
// display custom error message
|
|
||||||
error = $('.mailpoet_error[data-error="'+response.error+'"]');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(error !== null) {
|
|
||||||
$(error).show();
|
|
||||||
} else {
|
|
||||||
// display unknown error message
|
|
||||||
MailPoet.Notice.error("<%= __('An unknown error occurred. Please try again or get in touch with our support.') %>", { scroll: true });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if there is a callback, call it!
|
|
||||||
if(callback !== undefined) {
|
|
||||||
callback();
|
|
||||||
} else {
|
|
||||||
// otherwise display a success message
|
|
||||||
|
|
||||||
$success_message = str_replace(array(
|
|
||||||
'[link_widget]',
|
|
||||||
'[/link_widget]'
|
|
||||||
), array(
|
|
||||||
'<a href="'.admin_url('widgets.php').'" target="_blank">',
|
|
||||||
'</a>'
|
|
||||||
),
|
|
||||||
__('Saved! Add this form to [link_widget]a widget[/link_widget].')
|
|
||||||
);
|
|
||||||
?>
|
|
||||||
var success_message = "<?php echo addslashes($success_message); ?>";
|
|
||||||
|
|
||||||
if(response.is_widget === true) {
|
|
||||||
success_message = "<?php esc_html_e("Saved! The changes are already active in your widget."); ?>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// display success message and scroll to it
|
|
||||||
MailPoet.Notice.hide(true);
|
|
||||||
MailPoet.Notice.success(success_message, { scroll: true, static: true });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});*/
|
}).done(function(response) {
|
||||||
|
var message = null;
|
||||||
|
|
||||||
|
if(response.is_widget === true) {
|
||||||
|
message = "<%= __('Saved! The changes are already active in your widget.') %>";
|
||||||
|
} else {
|
||||||
|
message = "<%= __('Saved! Add this form to %1$sa widget%2$s.') | format("<a href='widgets.php' target='_blank'>", '</a>') | raw %>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message !== null) {
|
||||||
|
MailPoet.Notice.hide();
|
||||||
|
MailPoet.Notice.success(message, {
|
||||||
|
scroll: true,
|
||||||
|
static: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a callback, call it!
|
||||||
|
if(callback !== undefined) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// toolbar: on success toggle
|
// toolbar: on success toggle
|
||||||
@ -505,15 +495,15 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// toolbar: list selection
|
// toolbar: list selection
|
||||||
var selected_lists = <%= form.segments | json_encode | raw %>;
|
var selected_segments = <%= form.segments | json_encode | raw %>;
|
||||||
var selected_lists_ids = [];
|
var selected_segments_ids = [];
|
||||||
if(selected_lists !== null) {
|
if(selected_segments !== null) {
|
||||||
selected_lists_ids = selected_lists.map(function(segment) {
|
selected_segments_ids = selected_segments.map(function(segment) {
|
||||||
return parseInt(segment.id, 10);
|
return parseInt(segment.id, 10);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// enable select2 for list selection
|
// enable select2 for list selection
|
||||||
$('select[name="lists"]').select2({
|
$('#mailpoet_form_segments').select2({
|
||||||
width:'100%',
|
width:'100%',
|
||||||
templateResult: function(item) {
|
templateResult: function(item) {
|
||||||
if(item.element && item.element.selected) {
|
if(item.element && item.element.selected) {
|
||||||
@ -522,7 +512,7 @@
|
|||||||
return item.text;
|
return item.text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}).select2('val', <%= form.segments | json_encode | raw %>);
|
||||||
|
|
||||||
// subscriber meta fields
|
// subscriber meta fields
|
||||||
var meta_fields = [
|
var meta_fields = [
|
||||||
|
@ -35,6 +35,10 @@ baseConfig = {
|
|||||||
test: /\.jsx$/,
|
test: /\.jsx$/,
|
||||||
loader: 'babel-loader'
|
loader: 'babel-loader'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
include: require.resolve('codemirror'),
|
||||||
|
loader: 'expose-loader?CodeMirror',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
include: require.resolve('backbone'),
|
include: require.resolve('backbone'),
|
||||||
loader: 'expose-loader?Backbone',
|
loader: 'expose-loader?Backbone',
|
||||||
@ -79,8 +83,8 @@ config.push(_.extend({}, baseConfig, {
|
|||||||
'settings/tabs.js'
|
'settings/tabs.js'
|
||||||
],
|
],
|
||||||
form_editor_lib: [
|
form_editor_lib: [
|
||||||
'select2',
|
'codemirror',
|
||||||
'codemirror'
|
'codemirror/mode/css/css'
|
||||||
],
|
],
|
||||||
newsletter_editor: [
|
newsletter_editor: [
|
||||||
'underscore',
|
'underscore',
|
||||||
@ -159,7 +163,6 @@ config.push(_.extend({}, baseConfig, {
|
|||||||
'select2',
|
'select2',
|
||||||
'blob',
|
'blob',
|
||||||
'filesaver',
|
'filesaver',
|
||||||
|
|
||||||
'newsletter_editor/communicationsFix.js',
|
'newsletter_editor/communicationsFix.js',
|
||||||
'newsletter_editor/App',
|
'newsletter_editor/App',
|
||||||
'newsletter_editor/components/config.js',
|
'newsletter_editor/components/config.js',
|
||||||
|
Reference in New Issue
Block a user