]> _ Git - ccv-wordpress.git/commitdiff
WIP #3462 @5.5
authorStephen Cameron <stephen@cubedesigners.com>
Mon, 20 Jul 2020 17:00:42 +0000 (19:00 +0200)
committerStephen Cameron <stephen@cubedesigners.com>
Mon, 20 Jul 2020 17:00:42 +0000 (19:00 +0200)
13 files changed:
wp-content/mu-plugins/cube/src/Forms/Builder/Field.php
wp-content/mu-plugins/cube/src/Forms/Builder/Fields/Email.php
wp-content/mu-plugins/cube/src/Forms/Builder/Fields/Hidden.php [new file with mode: 0644]
wp-content/mu-plugins/cube/src/Forms/Consultation.php
wp-content/themes/CCV/app/setup.php
wp-content/themes/CCV/resources/assets/scripts/consultation.js
wp-content/themes/CCV/resources/assets/scripts/flatpickr.js
wp-content/themes/CCV/resources/assets/scripts/forms/forms.js
wp-content/themes/CCV/resources/assets/scripts/forms/parsley-setup.js
wp-content/themes/CCV/resources/views/forms/common/wrapper.blade.php
wp-content/themes/CCV/resources/views/forms/consultation.blade.php
wp-content/themes/CCV/resources/views/forms/contact.blade.php
wp-content/themes/CCV/webpack.mix.js

index d3d8e286ac0f3c594d3161ea9f3c92a0f927f9df..833f8c81c10d58d4f0beb708d769db87b43ef6df 100644 (file)
@@ -7,6 +7,7 @@ class Field
     protected $name;
     protected $type;
     protected $title;
+    protected $value;
     protected $options = [];
     protected $settings = [];
     protected $required = true;
@@ -75,6 +76,22 @@ class Field
         return $this;
     }
 
+    /**
+     * @return string
+     */
+    public function get_value() {
+        return $this->value;
+    }
+
+    /**
+     * Set field value
+     * @param string $value
+     * @return Field
+     */
+    public function value($value): self {
+        $this->value = $value;
+        return $this;
+    }
 
 
     /**
index 203238eae433a3534d9c6746925d25ae73ca9c12..2cc4f16348e1bf69b1ad85a5e66924a551e0757d 100644 (file)
@@ -7,6 +7,10 @@ use Cube\Forms\Builder\Field;
 class Email extends Field
 {
     public function render($settings) {
-        return '<input type="email" name="'. $this->get_name() .'" placeholder="'. $settings['placeholder'] .'" '. $settings['validation'] .'>';
+        // For email fields, Parsley JS behaviour is changed to only re-validate on blur (instead of on each input keystroke)
+        // It needs to be like this because when the form fails validation, it scrolls and focuses on the first error.
+        // While typing an e-mail address, the validation will fail multiple times by default (with each keystroke) until a full address is entered.
+        // To prevent UX problems, it's best to wait until the e-mail field loses focus before trying to re-validate.
+        return '<input type="email" name="'. $this->get_name() .'" placeholder="'. $settings['placeholder'] .'" '. $settings['validation'] .' data-parsley-trigger-after-failure="blur">';
     }
 }
diff --git a/wp-content/mu-plugins/cube/src/Forms/Builder/Fields/Hidden.php b/wp-content/mu-plugins/cube/src/Forms/Builder/Fields/Hidden.php
new file mode 100644 (file)
index 0000000..5d7ad38
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+namespace Cube\Forms\Builder\Fields;
+
+use Cube\Forms\Builder\Field;
+
+class Hidden extends Field
+{
+    public function render($settings) {
+        return '<input type="hidden" name="'. $this->get_name() .'" value="'. $this->get_value() .'">';
+    }
+}
index 202a68c2ef3ebb41fd3862a0463ecf703d70678c..333493e735fd76c119825375c077ebca62344a00 100644 (file)
@@ -6,6 +6,7 @@ use Cube\Forms\Builder\Fields\Binary;
 use Cube\Forms\Builder\Fields\Checkbox;
 use Cube\Forms\Builder\Fields\Date;
 use Cube\Forms\Builder\Fields\Email;
+use Cube\Forms\Builder\Fields\Hidden;
 use Cube\Forms\Builder\Fields\Radio;
 use Cube\Forms\Builder\Fields\Select;
 use Cube\Forms\Builder\Fields\Text;
@@ -87,6 +88,10 @@ class Consultation extends Base
             Textarea::field('imagery-online', __('Images en ligne', 'ccv'))->required(false), // Again, a manually handled field
             Checkbox::field('imagery-posted', __('Images envoyé par courrier', 'ccv'))->required(false),
 
+            // Unique session identifier for uploads that go directly to CCV's NAS (upload.ccv-montpellier.fr)
+            // Made up of timestamp YYMMDDHHMM + nonce
+            Hidden::field('imagery-phone-token', __('ID sur le NAS', 'ccv'))->value(date('ymdHi') . '_'. wp_create_nonce('NAS-upload')),
+
             //=== PERSONAL INFORMATION
             Text::field('last-name', _x('Nom', 'Nom de famille', 'ccv')),
             Text::field('first-name', __('Prénom', 'ccv')),
index fa611b07dacd1e01c24d7c6f4e48fe9276c30076..05ff8832e429aec81608bc87c659fa3ad22749e3 100755 (executable)
@@ -171,7 +171,7 @@ add_filter( 'mce_buttons_2', function($buttons) {
     return $buttons;
 });
 
-// Add format classes to
+// Add format classes to style dropdown
 add_filter( 'tiny_mce_before_init', function($init_array) {
 
     // Text size styles
index b89ffc4daca350290c2fd53977baf5e1f03b4e7b..159ef5813f3d2c00b76d59e52ff15c4d2caadbea 100644 (file)
@@ -2,14 +2,14 @@
 (function($) {
 
   // Check the parent radio button when clicking on any element with this data attribute
-  $(document).on('click', '[data-update-imagery-type]', function () {
+  $(document).on('click', '[data-update-imagery-type]', function(event) {
     let radio = $(this).closest('.imagery-type-wrapper').find('input[name="imagery-type"]');
     radio.prop('checked', true);
     clearPostCheckbox(); // We can clear it here because this event is only triggered by the other options
+    event.preventDefault();
   });
 
   $(document).on('click', 'input[name="imagery-type"]', function() {
-
     if ('imagery_post' !== $(this).attr('id')) {
       clearPostCheckbox();
     }
index e91a51dae6d8bb55f43f3126bce8be9d41753f8b..35fa4a96e7a8429062140bc92ce3f429f58560ad 100644 (file)
@@ -6,5 +6,12 @@
 // Settings come from JSON in the data attribute of the element to make this more flexible
 document.querySelectorAll('[data-flatpickr]')
   .forEach(function(picker) {
-    flatpickr(picker, JSON.parse(picker.dataset.flatpickr));
+    let settings = JSON.parse(picker.dataset.flatpickr);
+
+    // Trigger the input on the text field so that Parsley JS will re-validate the field and clear any errors
+    settings.onClose = function(selectedDates, dateStr, instance) {
+      jQuery(instance.altInput).trigger('input');
+    };
+
+    flatpickr(picker, settings);
   });
index 055a38e6866b6d31f9b62669b42868084b5964d3..784f142276af364ce345175fd897f71e70ed474e 100644 (file)
@@ -38,7 +38,8 @@ function addFormMessage (formEl, message, clear) {
 
   // Finally, scroll to the message in case it isn't in view
   setTimeout(function() {
-    let wrapperOffsetTop = Math.max(0, wrapperElement.getBoundingClientRect().top + window.scrollY - 100); // Scroll just above it to give some space
+    let headerHeight = document.querySelector('header.site').offsetHeight || 0; // Need to account for fixed header when scrolling up
+    let wrapperOffsetTop = Math.max(0, wrapperElement.getBoundingClientRect().top + window.scrollY - headerHeight);
     window.scrollTo({...{top: wrapperOffsetTop}, ...{behavior: 'smooth'}});
   }, 50);
 }
index 7ecda2223fa47145f030a3e7dc168f603bfbd35b..dc4043ef95e600cb182282d2c15bbec8e53a6a10 100644 (file)
@@ -20,7 +20,8 @@
   $.listen('parsley:field:error', function() {
 
     let firstErrorOffset = $('.parsley-error').first().offset();
-    firstErrorOffset.top = Math.max(0, firstErrorOffset.top - 50); // Scroll a bit above the element
+    let headerHeight = document.querySelector('header.site').offsetHeight || 0; // Need to account for fixed header when scrolling up
+    firstErrorOffset.top = Math.max(0, firstErrorOffset.top - headerHeight - 50); // Scroll a bit above the element
 
     window.scrollTo({...firstErrorOffset, ...{behavior: 'smooth'}});
   });
index 6790600bad1f8d3b3dbb1878f9a0bcddba987f12..23ece2670c6b60d4f8a7c2f9afd1094b00e7e50c 100644 (file)
@@ -17,4 +17,5 @@
   <div class="cube-form-messages hidden @stack('message_class')"></div>
 
 </form>
+
 @stack("afterform")
index ed2842ffa538d767209a83a71edf99e650c71491..b0ea82fde316b5105207a81cc82747c336fde52d 100644 (file)
     </div>
 
     {{-- IMAGES ONLINE --}}
-    @php $phonetoken=bin2hex(random_bytes(5)); @endphp
-
     <div class="imagery-type-wrapper flex mb-8">
       <input type="radio" id="imagery_web" name="imagery-type" value="{{ __('Images en ligne', 'ccv') }}">
-      <input type="hidden" name="imagery-phone-token" value="{{ $phonetoken }}">
       <label for="imagery_web" class="imagery-icon">@svg('imagery-web', 'w-22 md:w-20 sm:w-16')</label>
       <div class="ml-4">
         <div class="text-lg sm:text-base font-normal leading-tight mb-1">
 
     {{-- IMAGES FROM PHONE --}}
     <div class="imagery-type-wrapper flex mb-8">
+      {!! $form->input('imagery-phone-token') !!}
       <input type="radio" id="imagery_phone" name="imagery-type" value="{{ __('Images téléversées depuis portable') }}">
       <label for="imagery_phone" class="imagery-icon">@svg('imagery-phone', 'w-22 md:w-20 sm:w-16')</label>
       <div class="ml-4">
 
 </div>
 
+
 @push('afterform')
   <form action="https://upload.ccv-montpellier.fr/upload.php" id="phone-file-upload-form" method="post"
         enctype="multipart/form-data" style="visibility:hidden;height:1px;position:absolute;top:0;">
     <input type="file" multiple="multiple" name="files[]" id="phone-file-upload-field" accept="image/*" capture />
   </form>
   <script>
-    jQuery(function () {
-      // Click browse triggers the file form. It opens the dialog to capture images or browse files
-      jQuery("#phone-image-browse").on('click touchend', function () {
-        jQuery("#phone-file-upload-field").click();
-        return false;
+    (function($) {
+      // Clicking browse triggers the file form. It opens the dialog to capture images or browse files
+      $('#phone-image-browse').on('click touchend', function () {
+        $('#phone-file-upload-field').click();
       });
       // If the field has been updated (e.g not canceled), submit the form
-      jQuery("#phone-file-upload-field").on('change', function () {
+      $('#phone-file-upload-field').on('change', function () {
         var form_data = new FormData();
         var fileInput = document.getElementById('phone-file-upload-field');
 
         // Read selected files
         var totalfiles = fileInput.files.length;
         for (var index = 0; index < totalfiles; index++) {
-          form_data.append("files[]", fileInput.files[index]);
+          form_data.append('files[]', fileInput.files[index]);
         }
-        form_data.append('token', '{{ $phonetoken }}');
+        form_data.append('token', '{{ $form->get_field('imagery-phone-token')->get_value() }}');
 
-        var form = jQuery("#phone-file-upload-form");
-        var button = jQuery("#phone-image-browse");
+        var form = $('#phone-file-upload-form');
+        var button = $('#phone-image-browse');
 
         button.text("{{ __("Chargement des fichiers", 'ccv') }}");
 
         // AJAX request
-        jQuery.ajax({
+        $.ajax({
           url: form.attr('action'),
           type: form.attr('method'),
           data: form_data,
 
         return true;
       });
-    });
+    })(jQuery);
   </script>
 @endpush
 
index c33236dbd91d441730be57e16bc17f8cba1c7c6c..0bd48028aea389243c416a3d81d36ddedd8f9110 100644 (file)
@@ -7,3 +7,9 @@
   {!! $form->field('phone', ['show_title' => false]) !!}
   {!! $form->button(__('Contactez-moi', 'ccv'), ['class' => 'btn mt-8']) !!}
 </div>
+
+
+{{-- Custom classes for form message container (success message) --}}
+@push('message_class')
+  pt-8
+@endpush
index f27f7d84903195fa32bf634f6ac23d7aa1f0c2c2..b9c990a7f1c3e7b13004dd40d8d5815e533d01fd 100644 (file)
@@ -38,7 +38,8 @@ mix
 // Browsersync
 mix.browserSync({
   proxy: proxyURL,
-  port: 63000, // Changed so it works over port forwarding (paris.cubedesigners.com:63000)
+  host: proxyURL, // Enables ccv.test:3000
+  port: 3000,
   open: false,
 });