]> _ Git - ccv-wordpress.git/commitdiff
Form handling. WIP #3053 @9
authorStephen Cameron <stephen@cubedesigners.com>
Thu, 23 Apr 2020 16:55:28 +0000 (18:55 +0200)
committerStephen Cameron <stephen@cubedesigners.com>
Thu, 23 Apr 2020 16:55:28 +0000 (18:55 +0200)
wp-content/mu-plugins/cube/src/Forms/Base.php
wp-content/mu-plugins/cube/src/Forms/Consultation.php
wp-content/mu-plugins/cube/src/Init.php
wp-content/mu-plugins/cube/src/Shortcodes/CCVForm.php
wp-content/themes/CCV/resources/assets/scripts/forms.js [new file with mode: 0644]
wp-content/themes/CCV/resources/assets/styles/components/lity-lightbox.styl
wp-content/themes/CCV/resources/views/forms/consultation.blade.php
wp-content/themes/CCV/resources/views/forms/training.blade.php
wp-content/themes/CCV/resources/views/forms/wrapper.blade.php [new file with mode: 0644]
wp-content/themes/CCV/webpack.mix.js

index 5e2baf589ab6ed46f8829270b37a16f59ceb29f5..8c1e09dec97936611faade680ecea0315aa2e8d8 100644 (file)
@@ -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 '<button type="'. $settings['type'] .'" class="'. $settings['class'] .'">'. $text .'</button>';
+    }
+
+
     /**
      * 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
index e46e3769f564093104f2f32da89c95ad257837e6..e4e83e93dafa545cbaa31fed2024b8b9f899b5e9 100644 (file)
@@ -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',
             ]);
     }
 }
index e2550dd52cf245c34b7a0aff5a10cfbb37348768..a34dd1a55392ac0f2c3b311a43563400d7bd4a5b 100644 (file)
@@ -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,
         ];
     }
 
index 090f92e97e1f462c760aac6bba3afe7eeefc0685..01768a46f0dc80a0fb065539db91357ea032a72e 100644 (file)
@@ -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 (file)
index 0000000..7b2bb41
--- /dev/null
@@ -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)
index 89b380d3352a6857f9a074c582a8de54df2f1361..3f3f0fc75bc1ce7cade1f7d958e46647b150101d 100644 (file)
@@ -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
index 4c9879272bf09565056857d1e23ba4068cd6945f..f44aee1ce1f424e7a779a2a6a429892e9bd46817 100644 (file)
         {!! $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
           ]
 
   </div>
 
-  <button class="btn block mt-1v ml-auto">{{ __('Envoyer votre demande', 'ccv') }}</button>
+  {!! $form->button(__('Envoyer votre demande', 'ccv'), ['class' => 'btn block mt-1v ml-auto']) !!}
 
 </div>
index 918372bd73f07951a19299c55beb3a7fbfa9c370..d20c5d966a6a7720626aa29e8c5d75e92719600c 100644 (file)
 
   </div>
 
-  <button class="btn text-lg block mt-2v mx-auto">{{ __('Envoyer votre demande', 'ccv') }}</button>
+  {!! $form->button(__('Envoyer votre demande', 'ccv'), ['class' => 'btn text-lg block mt-2v mx-auto']) !!}
 
 </div>
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 (file)
index 0000000..fdf33c6
--- /dev/null
@@ -0,0 +1,14 @@
+{{-- FORM WRAPPER--}}
+<form class="cube-form">
+
+  <noscript>
+    <div class="px-4v py-1v text-red font-bold italic">
+      {{ __("Cette demande nécessite l'emploi de JavaScript qui, soit a été désactivé, soit n'est pas reconnu par votre fureteur.", 'ccv') }}
+    </div>
+  </noscript>
+
+  <input type="hidden" name="_form_name" value="{{ $name }}">
+
+  @includeIf("forms/$name")
+
+</form>
index 860acca2a393f4c08a5c906090507afdd610613d..3dafd0de07201867d5c1a137d3861872d24a0d3d 100644 (file)
@@ -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')