From 43081a464e41a3dc83d2003ef17155ac4bf3119d Mon Sep 17 00:00:00 2001 From: Stephen Cameron Date: Thu, 23 Apr 2020 18:55:28 +0200 Subject: [PATCH] Form handling. WIP #3053 @9 --- wp-content/mu-plugins/cube/src/Forms/Base.php | 69 ++++++++++++++++++- .../cube/src/Forms/Consultation.php | 11 +-- wp-content/mu-plugins/cube/src/Init.php | 1 + .../cube/src/Shortcodes/CCVForm.php | 29 ++++---- .../CCV/resources/assets/scripts/forms.js | 29 ++++++++ .../styles/components/lity-lightbox.styl | 3 +- .../views/forms/consultation.blade.php | 6 +- .../resources/views/forms/training.blade.php | 2 +- .../resources/views/forms/wrapper.blade.php | 14 ++++ wp-content/themes/CCV/webpack.mix.js | 1 + 10 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 wp-content/themes/CCV/resources/assets/scripts/forms.js create mode 100644 wp-content/themes/CCV/resources/views/forms/wrapper.blade.php diff --git a/wp-content/mu-plugins/cube/src/Forms/Base.php b/wp-content/mu-plugins/cube/src/Forms/Base.php index 5e2baf5..8c1e09d 100644 --- a/wp-content/mu-plugins/cube/src/Forms/Base.php +++ b/wp-content/mu-plugins/cube/src/Forms/Base.php @@ -7,6 +7,7 @@ use function Roots\asset; class Base { private $fields = []; + private $action_name = 'cube_forms_process'; // Name of the AJAX action // Field types const BINARY = 'binary'; @@ -18,14 +19,41 @@ class Base const TEXT = 'text'; const TEXTAREA = 'textarea'; + // Early setup called by Init.php in mu-plugin to register + // This is separated from init() so we can set up hooks for every request + // but only register scripts when we are going to display the form... + public function register() { + $this->hook(); + } + + public function hook() { + // Catch AJAX requests (handles both logged in and logged out users) + add_action('wp_ajax_nopriv_'. $this->action_name, [$this, 'process']); + add_action('wp_ajax_'. $this->action_name, [$this, 'process']); + } - public function __construct() { + public function init() { $this->register_scripts(); $this->register_fields(); } public function register_scripts() { + // Base forms functionality + wp_register_script('cube-forms', asset('scripts/forms.js'), ['jquery'], null, true); + wp_enqueue_script('cube-forms'); // Always needed, so enqueue it directly here + + // JS variables + wp_add_inline_script( + 'cube-forms', + 'cube_forms_config = '. json_encode([ + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'action' => $this->action_name, + 'nonce' => wp_create_nonce($this->action_name), + ]), + 'before' // Output before script so we can use the vars + ); + // Elementor has an older, incompatible version of Flatpickr so we need to replace it with our version if (wp_script_is('flatpickr', 'registered')) { wp_deregister_script('flatpickr'); @@ -51,10 +79,16 @@ class Base } - public function register_fields() { + public function register_fields() {} + + public function process() { + print_r($_POST); + die("PROCESSING FORM"); } + + /** * Output field HTML * @param $name @@ -286,6 +320,24 @@ class Base } + /** + * HTML (submit) button + * @param $text Button label + * @param array $settings + * @return string + */ + public function button($text, $settings = []) { + $default_settings = [ + 'type' => 'submit', + 'class' => 'btn', + ]; + + $settings = array_merge($default_settings, $settings); + + return ''; + } + + /** * Set multiple fields at once * @param array $fields @@ -355,6 +407,19 @@ class Base } } + /** + * Get the options for a field + * @param string $name + * @return array + */ + public function getFieldOptions($name) { + if ($this->exists($name) && isset($this->fields[$name]['options'])) { + return $this->fields[$name]['options']; + } + + return []; + } + /** * Helper function to print template code for all fields * @return string diff --git a/wp-content/mu-plugins/cube/src/Forms/Consultation.php b/wp-content/mu-plugins/cube/src/Forms/Consultation.php index e46e376..e4e83e9 100644 --- a/wp-content/mu-plugins/cube/src/Forms/Consultation.php +++ b/wp-content/mu-plugins/cube/src/Forms/Consultation.php @@ -90,12 +90,15 @@ class Consultation extends Base $this->addField('sex', __('Sexe', 'ccv'), self::RADIO, [_x('M', 'Sexe (M)', 'ccv'), _x('F', 'Sexe (F)', 'ccv')]); $this->addField('age', __('Âge :', 'ccv'), self::TEXT); $this->addField('message', __('Avez vous un message (ou une demande) spécifique à nous formuler ?', 'ccv'), self::TEXTAREA); + + // Special field: if a surgeon is selected, their e-mail address will be override the default delivery address $this->addField('surgeon', __('Chirurgien spécifique'), self::SELECT, [ - 'Dr Guilhaume GENESTE', - 'Dr Grégory EDGARD-ROSA', - 'Dr Martin GRAU ORTIZ', - 'Dr Caroline HIRSH', + // TODO: Add proper e-mail addresses here once we have them + 'Dr Guilhaume GENESTE' => 'xxxxx@ccv-montpellier.fr', + 'Dr Grégory EDGARD-ROSA' => 'xxxxx@ccv-montpellier.fr', + 'Dr Martin GRAU ORTIZ' => 'xxxxx@ccv-montpellier.fr', + 'Dr Caroline HIRSH' => 'xxxxx@ccv-montpellier.fr', ]); } } diff --git a/wp-content/mu-plugins/cube/src/Init.php b/wp-content/mu-plugins/cube/src/Init.php index e2550dd..a34dd1a 100644 --- a/wp-content/mu-plugins/cube/src/Init.php +++ b/wp-content/mu-plugins/cube/src/Init.php @@ -18,6 +18,7 @@ final class Init { // Marked as final because this class should never be extende CPT\Person::class, CPT\ScientificNews::class, Shortcodes\CCVForm::class, + Forms\Base::class, ]; } diff --git a/wp-content/mu-plugins/cube/src/Shortcodes/CCVForm.php b/wp-content/mu-plugins/cube/src/Shortcodes/CCVForm.php index 090f92e..01768a4 100644 --- a/wp-content/mu-plugins/cube/src/Shortcodes/CCVForm.php +++ b/wp-content/mu-plugins/cube/src/Shortcodes/CCVForm.php @@ -7,37 +7,34 @@ use function Roots\view; class CCVForm { + public $forms = []; + /** * Common setup, will be automatically triggered by Init class if included */ public function register() { + // Declare available forms (the key is the template name and the value is the form class) + $this->forms = [ + 'consultation' => Forms\Consultation::class, + 'training' => Forms\Training::class, + ]; + // Register [ccv_form] shortcode add_shortcode('ccv_form', [$this, 'shortcode']); - - add_action( 'wp_enqueue_scripts', function() { - // TODO: Register all necessary scripts and styles here (flatpickr, Parsely etc). See https://wordpress.stackexchange.com/q/165754 - }); - } public function shortcode($attributes) { - // TODO: enqueue scripts and styles here when shortcode is actually used (avoids unwanted script inclusion on other pages) - extract(shortcode_atts([ 'name' => '', // Name of the form template ], $attributes)); - // List of all possible forms - $templates = [ - 'consultation' => Forms\Consultation::class, - 'training' => Forms\Training::class, - ]; - - if (array_key_exists($name, $templates)) { - $form = new $templates[$name]; - return view("forms/$name", compact('form')); + if (array_key_exists($name, $this->forms)) { + /* @var $form Forms\Base */ + $form = new $this->forms[$name]; + $form->init(); + return view("forms/wrapper", compact('form', 'name')); } return false; diff --git a/wp-content/themes/CCV/resources/assets/scripts/forms.js b/wp-content/themes/CCV/resources/assets/scripts/forms.js new file mode 100644 index 0000000..7b2bb41 --- /dev/null +++ b/wp-content/themes/CCV/resources/assets/scripts/forms.js @@ -0,0 +1,29 @@ +//=== Cube Forms +// Inspired by HTMLForms: https://github.com/ibericode/html-forms/blob/master/assets/browserify/public.js + +const config = window.cube_forms_config || {}; + +function handleSubmitEvents (e) { + const formEl = e.target; + if (formEl.className.indexOf('cube-form') < 0) { + return + } + e.preventDefault(); // always prevent default because we only want to send via AJAX + submitForm(formEl) +} + +function submitForm(form) { + const formData = new FormData(form); + + formData.append('action', config.action); + formData.append('nonce', config.nonce); + + let request = new XMLHttpRequest(); + //request.onreadystatechange = createRequestHandler(form); + request.open('POST', config.ajax_url, true); + request.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + request.send(formData); + request = null; +} + +document.addEventListener('submit', handleSubmitEvents, false); // useCapture=false to ensure we bubble upwards (and thus can cancel propagation) diff --git a/wp-content/themes/CCV/resources/assets/styles/components/lity-lightbox.styl b/wp-content/themes/CCV/resources/assets/styles/components/lity-lightbox.styl index 89b380d..3f3f0fc 100644 --- a/wp-content/themes/CCV/resources/assets/styles/components/lity-lightbox.styl +++ b/wp-content/themes/CCV/resources/assets/styles/components/lity-lightbox.styl @@ -22,7 +22,6 @@ .lity-content horizontal-spacing(5vw) constrain(padding-top, 5vw) - constrain(padding-bottom, 3.25vw) background-color: #fff width: 90vw // 5% gap on either side max-width: 980px @@ -41,6 +40,8 @@ // but that stops the padding at the bottom working so we unset it > *:first-child max-height: none !important + // Padding applied here instead of in parent because this works more consistently across browsers + constrain(padding-bottom, 3.25vw) .lity-close @apply bg-pink diff --git a/wp-content/themes/CCV/resources/views/forms/consultation.blade.php b/wp-content/themes/CCV/resources/views/forms/consultation.blade.php index 4c98792..f44aee1 100644 --- a/wp-content/themes/CCV/resources/views/forms/consultation.blade.php +++ b/wp-content/themes/CCV/resources/views/forms/consultation.blade.php @@ -272,6 +272,10 @@ {!! $form->field('surgeon', [ 'class' => 'mt-4', 'show_title' => false, + // The options for this field contains the e-mail address as the value but we don't want to expose that here + // so we override options with a new array made up of just their names as both the key and value. + // Once the form is processed, this will be used to look up the e-mail address. + 'options' => array_combine(array_keys($form->getFieldOptions('surgeon')), array_keys($form->getFieldOptions('surgeon'))), 'placeholder' => [ '' => __('Sélectionner') // First select option ] @@ -281,6 +285,6 @@ - + {!! $form->button(__('Envoyer votre demande', 'ccv'), ['class' => 'btn block mt-1v ml-auto']) !!} diff --git a/wp-content/themes/CCV/resources/views/forms/training.blade.php b/wp-content/themes/CCV/resources/views/forms/training.blade.php index 918372b..d20c5d9 100644 --- a/wp-content/themes/CCV/resources/views/forms/training.blade.php +++ b/wp-content/themes/CCV/resources/views/forms/training.blade.php @@ -127,6 +127,6 @@ - + {!! $form->button(__('Envoyer votre demande', 'ccv'), ['class' => 'btn text-lg block mt-2v mx-auto']) !!} diff --git a/wp-content/themes/CCV/resources/views/forms/wrapper.blade.php b/wp-content/themes/CCV/resources/views/forms/wrapper.blade.php new file mode 100644 index 0000000..fdf33c6 --- /dev/null +++ b/wp-content/themes/CCV/resources/views/forms/wrapper.blade.php @@ -0,0 +1,14 @@ +{{-- FORM WRAPPER--}} +
+ + + + + + @includeIf("forms/$name") + +
diff --git a/wp-content/themes/CCV/webpack.mix.js b/wp-content/themes/CCV/webpack.mix.js index 860acca..3dafd0d 100644 --- a/wp-content/themes/CCV/webpack.mix.js +++ b/wp-content/themes/CCV/webpack.mix.js @@ -55,6 +55,7 @@ mix.copy('node_modules/flatpickr/dist/flatpickr.min.js', publicPath`scripts/flat // JavaScript mix.js(src`scripts/app.js`, 'scripts') + .js(src`scripts/forms.js`, 'scripts') .js(src`scripts/consultation.js`, 'scripts') .js(src`scripts/header-slideshow.js`, 'scripts') .js(src`scripts/link-carousel.js`, 'scripts') -- 2.39.5