class Base
{
private $fields = [];
+ private $action_name = 'cube_forms_process'; // Name of the AJAX action
// Field types
const BINARY = 'binary';
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');
}
- public function register_fields() {
+ public function register_fields() {}
+
+ public function process() {
+ print_r($_POST);
+ die("PROCESSING FORM");
}
+
+
/**
* Output field HTML
* @param $name
}
+ /**
+ * 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
}
}
+ /**
+ * 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
$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',
]);
}
}
CPT\Person::class,
CPT\ScientificNews::class,
Shortcodes\CCVForm::class,
+ Forms\Base::class,
];
}
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;
--- /dev/null
+//=== 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)
.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
// 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
{!! $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>
</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>
--- /dev/null
+{{-- 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>
// 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')