Webform 6.3.x
Drupal 10.4.x
CSS:
span.ajax-throbber.icon {
min-height: 0px;
min-width: 0px;
padding-left: 0px;
position: relative;
}
.focus-box {
position: absolute;
border: 2px dashed red;
width: 65%; /* sera redéfini via JS */
height: auto;
aspect-ratio: 390 / 280;
resize: none;
cursor: move;
z-index: 11;
box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 0px 9999px;
}
.focus-box::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
bottom: 0;
right: 0;
background: red;
pointer-events: none;
z-index: 12;
clip-path: polygon(100% 0, 0 100%, 100% 100%);
}
#photo-preview {
position: relative;
overflow: hidden;
}
.focus-overlay {
position: absolute;
pointer-events: none;
z-index: 10;
transform: translate(-50%, -50%);
visibility: hidden;
}
.focus-marker {
width: 40px;
height: 40px;
border: 2px solid black;
border-radius: 50%;
background: white;
mix-blend-mode: difference;
color: black;
text-align: center;
line-height: 40px;
font-size: 24px;
font-weight: bold;
user-select: none;
visibility: hidden;
}
#edit-focus-point--wrapper {
visibility: hidden;
}
Javascript
(function (Drupal, drupalSettings) {
// Attend que le DOM soit prêt
document.addEventListener('DOMContentLoaded', function () {
// Stocker les observers pour les réinitialiser
var observer = null;
var globalObserver = null;
// Fonction pour activer/désactiver le throbber et le bouton "Next".
function toggleThrobber(show) {
var $throbber = jQuery('.ajax-throbber');
var $buttonNext = jQuery('button.webform-button--next');
if (show) {
$buttonNext.each(function () {
jQuery(this).prop('disabled', true);
});
$throbber.each(function () {
jQuery(this).show();
});
} else {
$buttonNext.each(function () {
jQuery(this).prop('disabled', false);
});
$throbber.each(function () {
jQuery(this).hide();
});
}
}
// Ajouter dynamiquement le throbber aux wrappers AJAX.
function addThrobberToAjaxWrappers() {
jQuery('div[id^="ajax-wrapper"]').each(function () {
if (!jQuery('body').find('.ajax-throbber').length) {
var $throbber = jQuery('<span class="ajax-throbber glyphicon-spin icon glyphicon glyphicon-refresh" aria-hidden="true"></span>');
$throbber.hide();
jQuery(this).append($throbber);
}
});
}
// Fonction pour vérifier si le bouton "Attachment_upload_button" est présent.
function waitForUploadButton() {
var intervalId = setInterval(function () {
if (jQuery('button[name="Attachment_upload_button"]').length) {
clearInterval(intervalId);
addThrobberToAjaxWrappers();
}
}, 100);
setTimeout(function () {
clearInterval(intervalId);
}, 300000); // 5 minutes max
}
// Observer les changements pour détecter les fichiers téléchargés.
function observeFileUploads() {
// Nettoyer l'ancien observer s'il existe
if (observer) {
observer.disconnect();
}
if (globalObserver) {
globalObserver.disconnect();
}
observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.type === 'childList') {
var hasFiles = jQuery('div.form-item.form-type-checkbox').find('input').length > 0;
// toggleThrobber(!hasFiles);
}
});
});
jQuery('div[id^="ajax-wrapper--"]').each(function () {
observer.observe(this, { childList: true, subtree: true });
});
// Observer tout le document pour détecter les nouveaux ajax-wrapper--
globalObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (node) {
if (node.nodeType === 1 && node.id && node.id.startsWith('ajax-wrapper--')) {
toggleThrobber(false);
observer.observe(node, { childList: true, subtree: true });
}
});
});
});
globalObserver.observe(document.body, { childList: true, subtree: true });
}
// Suivre AJAX pour démarrer et arrêter le throbber.
jQuery(document).ajaxSend(function (event, xhr, settings) {
toggleThrobber(true);
let input_coords = document.querySelector('input[name="focus_box_coords"]');
if (input_coords) input_coords.value = '';
});
jQuery(document).ajaxComplete(function (event, xhr, settings) {
waitForUploadButton();
addThrobberToAjaxWrappers();
observeFileUploads(); // Réinitialiser le MutationObserver après chaque AJAX.
});
// Initialisation.
waitForUploadButton();
addThrobberToAjaxWrappers();
observeFileUploads();
});
Drupal.behaviors.photoPreview = {
attach: function (context, settings) {
const previewContainer = document.getElementById('photo-preview');
if (!previewContainer) {
// Skip if this page/context doesn't have a preview target.
return;
}
// Affiche le preview quand un fichier est présent
once('photoPreview', '.file-link', context).forEach(function (fileLinkWrapper) {
const link = fileLinkWrapper.querySelector('a');
if (link && previewContainer) {
const originalUrl = link.getAttribute('href');
let candidateUrl = originalUrl;
// Tenter de construire une version avec /orig/
if (originalUrl.includes('_sid_')) {
candidateUrl = originalUrl.replace(/_sid_(\/[^\/]+\.(?:jpg|jpeg|png|gif))/i, '_sid_/orig$1');
}
else {
candidateUrl = originalUrl.replace(/\/(\d+)(\/[^\/]+\.(?:jpg|jpeg|png|gif))/i, '/$1/orig$2');
}
// Tester si l'image modifiée existe
const testImage = new Image();
testImage.onload = function () {
// L'image "orig" existe, l'utiliser
previewContainer.innerHTML = '';
previewContainer.innerHTML =
'<img src="' + candidateUrl + '" style="max-width: 585px; max-width: 390px; object-fit: contain;" />';
if (typeof window.photoFocusOverlay === 'function') {
window.photoFocusOverlay();
}
};
testImage.onerror = function () {
// Sinon, utiliser l'original
previewContainer.innerHTML = '';
previewContainer.innerHTML =
'<img src="' + originalUrl + '" style="max-width: 585px; max-width: 390px; object-fit: contain;" />';
if (typeof window.photoFocusOverlay === 'function') {
window.photoFocusOverlay();
}
};
testImage.src = candidateUrl;
}
});
// Une seule fois, enregistrer une fonction globale qui se déclenche après CHAQUE AJAX
if (!window.__photoPreviewAjaxPatched) {
window.__photoPreviewAjaxPatched = true;
// Ceci capture toutes les réponses AJAX Drupal
jQuery(document).ajaxComplete(function (event, xhr, settings) {
const previewContainer = document.getElementById('photo-preview');
const fileLink = document.querySelector('.file-link a');
if (previewContainer && !fileLink) {
previewContainer.innerHTML = '';
previewContainer.removeAttribute('style');
}
});
}
}
};
window.photoFocusOverlay = function () {
const previewContainer = document.getElementById('photo-preview');
const image = previewContainer?.querySelector('img');
if (!image || previewContainer.querySelector('.focus-overlay')) return;
function syncPreviewSize() {
const rect = image.getBoundingClientRect();
previewContainer.style.width = rect.width + 'px';
previewContainer.style.height = rect.height + 'px';
}
function updateCoordsInput(x, y, w, h, containerW, containerH) {
const naturalW = image.naturalWidth;
const naturalH = image.naturalHeight;
const scaleX = naturalW / containerW;
const scaleY = naturalH / containerH;
const x_abs = x * scaleX;
const y_abs = y * scaleY;
const w_abs = w * scaleX;
const h_abs = h * scaleY;
const json = JSON.stringify({ x: x_abs, y: y_abs, w: w_abs, h: h_abs });
const input = document.querySelector('input[name="focus_box_coords"]');
if (input) input.value = json;
}
function enforceAspectRatio(box, container) {
const containerRect = container.getBoundingClientRect();
const aspectRatio = 280 / 390;
let maxWidth = containerRect.width;
let maxHeight = containerRect.height;
// Limit width to container width
let width = Math.min(box.offsetWidth, maxWidth);
let height = width * aspectRatio;
// If height would overflow, scale both down proportionally
if (height > maxHeight) {
height = maxHeight;
width = height / aspectRatio;
}
// Clamp position so box stays fully within container
let left = parseFloat(box.style.left) || 0;
let top = parseFloat(box.style.top) || 0;
left = Math.min(left, containerRect.width - width);
top = Math.min(top, containerRect.height - height);
box.style.width = width + 'px';
box.style.height = height + 'px';
box.style.left = left + 'px';
box.style.top = top + 'px';
updateCoordsInput(left, top, width, height, containerRect.width, containerRect.height);
}
function initOverlay() {
syncPreviewSize();
previewContainer.style.position = 'relative';
previewContainer.querySelectorAll('.focus-overlay, .focus-box').forEach(el => el.remove());
const overlay = document.createElement('div');
overlay.className = 'focus-overlay';
overlay.innerHTML = '<div class="focus-marker">+</div>';
previewContainer.appendChild(overlay);
const focusBox = document.createElement('div');
focusBox.className = 'focus-box';
focusBox.innerHTML = '<div class="resize-handle"></div>';
previewContainer.appendChild(focusBox);
const imgRect = image.getBoundingClientRect();
const containerWidth = imgRect.width;
const containerHeight = imgRect.height;
const input = document.querySelector('input[name="focus_box_coords"]');
let boxWidth, boxHeight, left, top;
if (input && input.value) {
try {
const prev = JSON.parse(input.value);
const scaleX = containerWidth / image.naturalWidth;
const scaleY = containerHeight / image.naturalHeight;
boxWidth = prev.w * scaleX;
boxHeight = prev.h * scaleY;
left = prev.x * scaleX;
top = prev.y * scaleY;
if (top <= 0 && boxHeight < containerHeight) {
top = Math.max((containerHeight - boxHeight) / 2, 1);
}
} catch (e) {
boxWidth = containerWidth * 0.6;
boxHeight = boxWidth * (280 / 390);
left = (containerWidth - boxWidth) / 2;
top = (containerHeight - boxHeight) / 2;
}
} else {
boxWidth = containerWidth * 0.6;
boxHeight = boxWidth * (280 / 390);
left = (containerWidth - boxWidth) / 2;
top = (containerHeight - boxHeight) / 2;
}
focusBox.style.cssText = `
position: absolute;
border: 2px dashed red;
z-index: 11;
overflow: hidden;
touch-action: none;
left: ${left}px;
top: ${top}px;
width: ${boxWidth}px;
height: ${boxHeight}px;
`;
const resizeHandle = focusBox.querySelector('.resize-handle');
resizeHandle.style.cssText = `
position: absolute;
right: 0;
bottom: 0;
width: 20px;
height: 20px;
z-index: 12;
cursor: nwse-resize;
touch-action: none;
`;
let isDragging = false;
let dragOffsetX, dragOffsetY;
focusBox.addEventListener('mousedown', (e) => {
if (e.target === resizeHandle) return;
e.preventDefault();
const rect = focusBox.getBoundingClientRect();
isDragging = 'move';
dragOffsetX = e.clientX - rect.left;
dragOffsetY = e.clientY - rect.top;
});
window.addEventListener('mousemove', (e) => {
if (isDragging !== 'move') return;
e.preventDefault();
const containerRect = previewContainer.getBoundingClientRect();
let newLeft = e.clientX - containerRect.left - dragOffsetX;
let newTop = e.clientY - containerRect.top - dragOffsetY;
newLeft = Math.max(0, Math.min(newLeft, containerRect.width - focusBox.offsetWidth));
newTop = Math.max(0, Math.min(newTop, containerRect.height - focusBox.offsetHeight));
focusBox.style.left = newLeft + 'px';
focusBox.style.top = newTop + 'px';
enforceAspectRatio(focusBox, previewContainer);
});
let resizeStartX;
resizeHandle.addEventListener('mousedown', (e) => {
e.preventDefault();
e.stopPropagation();
resizeStartX = e.clientX;
isDragging = 'resize';
focusBox.dataset.startWidth = focusBox.offsetWidth;
});
window.addEventListener('mousemove', (e) => {
if (isDragging !== 'resize') return;
e.preventDefault();
const dx = e.clientX - resizeStartX;
const newWidth = parseFloat(focusBox.dataset.startWidth) + dx;
focusBox.style.width = newWidth + 'px';
enforceAspectRatio(focusBox, previewContainer);
});
window.addEventListener('mouseup', () => {
isDragging = false;
});
previewContainer.addEventListener('touchstart', (e) => {
if (e.touches.length === 2) {
const dx = e.touches[1].clientX - e.touches[0].clientX;
const dy = e.touches[1].clientY - e.touches[0].clientY;
previewContainer.dataset.pinchStartDistance = Math.hypot(dx, dy);
previewContainer.dataset.startWidth = focusBox.offsetWidth;
} else if (e.touches.length === 1) {
const touch = e.touches[0];
const rect = focusBox.getBoundingClientRect();
const containerRect = previewContainer.getBoundingClientRect();
focusBox.dataset.dragging = 'true';
focusBox.dataset.offsetX = touch.clientX - rect.left;
focusBox.dataset.offsetY = touch.clientY - rect.top;
focusBox.dataset.containerLeft = containerRect.left;
focusBox.dataset.containerTop = containerRect.top;
}
}, { passive: false });
previewContainer.addEventListener('touchmove', (e) => {
const containerRect = previewContainer.getBoundingClientRect();
if (e.touches.length === 2) {
e.preventDefault();
const dx = e.touches[1].clientX - e.touches[0].clientX;
const dy = e.touches[1].clientY - e.touches[0].clientY;
const distance = Math.hypot(dx, dy);
const scale = distance / parseFloat(previewContainer.dataset.pinchStartDistance);
let newWidth = parseFloat(previewContainer.dataset.startWidth) * scale;
focusBox.style.width = newWidth + 'px';
enforceAspectRatio(focusBox, previewContainer);
} else if (e.touches.length === 1 && focusBox.dataset.dragging === 'true') {
e.preventDefault();
const touch = e.touches[0];
const offsetX = parseFloat(focusBox.dataset.offsetX);
const offsetY = parseFloat(focusBox.dataset.offsetY);
const containerLeft = parseFloat(focusBox.dataset.containerLeft);
const containerTop = parseFloat(focusBox.dataset.containerTop);
let newLeft = touch.clientX - containerLeft - offsetX;
let newTop = touch.clientY - containerTop - offsetY;
newLeft = Math.max(0, Math.min(newLeft, containerRect.width - focusBox.offsetWidth));
newTop = Math.max(0, Math.min(newTop, containerRect.height - focusBox.offsetHeight));
focusBox.style.left = newLeft + 'px';
focusBox.style.top = newTop + 'px';
enforceAspectRatio(focusBox, previewContainer);
}
}, { passive: false });
previewContainer.addEventListener('touchend', () => {
focusBox.dataset.dragging = 'false';
});
enforceAspectRatio(focusBox, previewContainer);
window.addEventListener('resize', syncPreviewSize);
}
if (image.complete) {
initOverlay();
} else {
image.addEventListener('load', initOverlay);
}
};
})(Drupal, drupalSettings);
Webform gestionnnaire mon_module/src/Plugin/WebformHandler/CompagnonGestionnaire.php
<?php
namespace Drupal\mon_module\Plugin\WebformHandler;
use Drupal\webform\Plugin\WebformHandlerBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\WebformSubmissionInterface;
use Drupal\image\Entity\ImageStyle;
use Drupal\file\Entity\File;
use Drupal\Core\File\FileSystemInterface;
/**
* Applique le style d’image et calcule l’année pour "Compagnon du mois".
*
* @WebformHandler(
* id = "compagnon_gestionnaire",
* label = @Translation("Compagnon - Gestionnaire"),
* category = @Translation("Traitement personnalisé"),
* description = @Translation("Applique le style d'image et calcule l'année pour le compagnon du mois."),
* cardinality = \Drupal\webform\Plugin\WebformHandlerInterface::CARDINALITY_SINGLE,
* results = \Drupal\webform\Plugin\WebformHandlerInterface::RESULTS_PROCESSED,
* )
*/
class CompagnonGestionnaire extends WebformHandlerBase {
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) {
$data = $webform_submission->getData();
// Appliquer le style d'image "compagnon" si le champ photo est rempli.
if (!empty($data['photo'])) {
$fid = $data['photo'];
$file = File::load($fid);
if ($file) {
$do_image_style = TRUE;
$uri = $file->getFileUri();
$realpath = \Drupal::service('file_system')->realpath($uri);
$image_info = @getimagesize(\Drupal::service('file_system')->realpath($uri));
if ($image_info) {
$width = $image_info[0];
$height = $image_info[1];
$webform_submission = $form_state->getFormObject()->getEntity();
$fs = \Drupal::service('file_system');
// Example - public://webform/compagnon_du_mois/_sid_/filename.jpg.
$source_uri = $file->getFileUri();
// Parse filename.
$filename = basename($source_uri);
$sid = $webform_submission->id();
if (!is_numeric($sid)) {
$sid = '_sid_';
}
// Destination path.
$original_copy_dir = "public://webform/compagnon_du_mois/$sid/orig";
$original_copy_uri = "{$original_copy_dir}/{$filename}";
if ($width == 390 && $height == 280) {
// Image was already styled, copy original back and re-style it.
$do_image_style = FALSE;
if (!file_exists($original_copy_uri) && is_numeric($sid)) {
$unprocessed_original_copy_dir = "public://webform/compagnon_du_mois/_sid_/orig";
$unprocessed_original_copy_uri = "{$unprocessed_original_copy_dir}/{$filename}";
if (file_exists($unprocessed_original_copy_uri) && is_numeric($sid)) {
if (!file_exists($original_copy_dir)) {
$fs->prepareDirectory($original_copy_dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
}
\Drupal::logger('mon_module')->notice('File exists at @path', ['@path' => $unprocessed_original_copy_uri]);
$fs->copy($unprocessed_original_copy_uri, $original_copy_uri , FileSystemInterface::EXISTS_RENAME);
}
}
if (file_exists($original_copy_uri)) {
$fs->copy($original_copy_uri, $source_uri, FileSystemInterface::EXISTS_REPLACE);
// Invalidate the file entity's cache tag.
\Drupal::service('cache_tags.invalidator')->invalidateTags(["file:$fid"]);
// Reload the image.
$file = File::load($fid);
$do_image_style = TRUE;
}
else {
\Drupal::logger('mon_module')->notice('File does not exist at @path', ['@path' => $original_copy_uri]);
}
}
else if (!file_exists($original_copy_uri)) {
if (!file_exists($original_copy_dir)) {
$fs->prepareDirectory($original_copy_dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
}
try {
$copy_dir = "public://webform/compagnon_du_mois/_sid_/orig";
$copy_uri = "{$copy_dir}/{$filename}";
// Next line required for preview that uses js.
$fs->copy($source_uri, $copy_uri, FileSystemInterface::EXISTS_REPLACE);
// This copy required by everytyhing else.
$fs->copy($source_uri, $original_copy_uri, FileSystemInterface::EXISTS_REPLACE);
// Invalidate the file entity's cache tag.
\Drupal::service('cache_tags.invalidator')->invalidateTags(["file:$fid"]);
// Reload the image.
$file = File::load($fid);
$do_image_style = TRUE;
\Drupal::logger('mon_module')->notice('Copied file to @dest', ['@dest' => $original_copy_uri]);
}
catch (\Exception $e) {
\Drupal::logger('mon_module')->error('File copy failed: @msg', ['@msg' => $e->getMessage()]);
}
}
if (is_null($sid)) {
if (file_exists($original_copy_uri)) {
$fs->copy($original_copy_uri, $source_uri, FileSystemInterface::EXISTS_REPLACE);
\Drupal::logger('mon_module')->notice('File already exists at @path', ['@path' => $original_copy_uri]);
// Invalidate the file entity's cache tag.
\Drupal::service('cache_tags.invalidator')->invalidateTags(["file:$fid"]);
// Reload the image.
$file = File::load($fid);
$do_image_style = TRUE;
}
else {
\Drupal::logger('mon_module')->notice('File does not exist at @path', ['@path' => $original_copy_uri]);
}
}
else if (is_numeric($sid)) {
$original_copy_dir = "public://webform/compagnon_du_mois/$sid/orig";
$original_copy_uri = "{$original_copy_dir}/{$filename}";
if (!file_exists($original_copy_uri)) {
$temp_copy_dir = "public://webform/compagnon_du_mois/_sid_/orig";
$temp_copy_uri = "{$original_copy_dir}/{$filename}";
if (file_exists($original_copy_uri)) {
$fs->copy($temp_copy_uri, $original_copy_uri, FileSystemInterface::EXISTS_REPLACE);
}
}
if (file_exists($original_copy_uri)) {
$fs->copy($original_copy_uri, $source_uri, FileSystemInterface::EXISTS_REPLACE);
\Drupal::logger('mon_module')->notice('Copied file to @dest', ['@dest' => $original_copy_uri]);
// Invalidate the file entity's cache tag.
\Drupal::service('cache_tags.invalidator')->invalidateTags(["file:$fid"]);
// Reload the image.
$file = File::load($fid);
$do_image_style = TRUE;
}
}
}
// Appliquer le traitement de l'image à ratio fixe.
if ($do_image_style) {
// Rotation basée sur EXIF AVANT d'appliquer le style.
if (function_exists('exif_read_data') && @exif_imagetype($realpath) === IMAGETYPE_JPEG) {
$exif = @exif_read_data($realpath);
if (!empty($exif['Orientation'])) {
$orientation = (int) $exif['Orientation'];
\Drupal::logger('mon_module')->notice("exif orientation @orientation", ['@orientation' => $orientation]);
if (in_array($orientation, [3, 6, 8])) {
$image = imagecreatefromjpeg($realpath);
if ($image) {
switch ($orientation) {
case 3:
$image = imagerotate($image, 180, 0);
break;
case 6:
$image = imagerotate($image, -90, 0);
break;
case 8:
$image = imagerotate($image, 90, 0);
break;
}
imagejpeg($image, $realpath, 90);
}
}
}
}
$coords_raw = $data['focus_box_coords'] ?? null;
if ($coords_raw && $file) {
$coords = json_decode($coords_raw, TRUE);
if (isset($coords['x'], $coords['y'], $coords['w'], $coords['h'])) {
$x = (int) round($coords['x']);
$y = (int) round($coords['y']);
$w = (int) round($coords['w']);
$h = (int) round($coords['h']);
if ($w > 0 && $h > 0) {
$image = imagecreatefromjpeg($realpath); // adapt if png
$cropped = imagecrop($image, [
'x' => $x,
'y' => $y,
'width' => $w,
'height' => $h,
]);
if ($cropped) {
$resized = imagecreatetruecolor(390, 280);
imagecopyresampled($resized, $cropped, 0, 0, 0, 0, 390, 280, $w, $h );
imagejpeg($resized, $realpath, 90);
imagedestroy($image);
imagedestroy($cropped);
imagedestroy($resized);
clearstatcache(TRUE, $realpath);
$file->setSize(filesize($realpath));
$file->save();
}
}
}
}
}
}
}
// Calcul du champ "year".
$annee_option = $data['annee'] ?? 'this_year';
$soumission_timestamp = $webform_submission->getCompletedTime() ?? \Drupal::time()->getCurrentTime();
$year = (int) \Drupal::service('date.formatter')->format($soumission_timestamp, 'custom', 'Y');
if ($annee_option === 'next_year') {
$year += 1;
}
// Appliquer la valeur au champ 'year'
$webform_submission->setElementData('year', $year);
// Calcul du champ "month".
$mois_option = $data['mois'] ?? 'Janvier';
$month = $this->getNumericMonth($mois_option);
// Appliquer la valeur au champ 'month'
$webform_submission->setElementData('month', $month);
}
/**
* Return the numeric month value after passing a string.
*
* parameter (string) $mois.
* returns (string) $month.
*/
public function getNumericMonth(string $mois) {
switch ($mois) {
case 'Janvier':
case 'January':
$month = 1;
break;
case 'Février':
case 'February':
$month = 2;
break;
case 'Mars':
case 'March':
$month = 3;
break;
case 'Avril':
case 'April':
$month = 4;
break;
case 'Mai':
case 'May':
$month = 5;
break ;
case 'Juin':
case 'June':
$month = 6;
break;
case 'Juillet':
case 'July':
$month = 7;
break;
case 'Août':
case 'August':
$month = 8;
break;
case 'Septembre':
case 'September':
$month = 9;
break;
case 'Octobre':
case 'October':
$month = 10;
break;
case 'Novembre':
case 'November':
$month = 11;
break;
case 'Décembre':
case 'December':
$month = 12;
break;
default:
$month = 1;
break;
}
return $month;
}
}
yaml
debut:
'#type': wizard_page
'#title': Début
choix:
'#type': fieldset
'#title': 'Compagnon de la semaine'
'#open': true
'#required': true
photo:
'#type': image_file
'#title': Photo
'#required': true
'#attributes':
class:
- custom-photo-upload
'#uri_scheme': public
'#min_resolution': 250x200
processed_text_01:
'#type': processed_text
'#text': '<div id="photo-preview"><!-- Placeholder for photo preview --> </div>'
'#format': rich_text_ckeditor5
nom_du_parent:
'#type': textfield
'#title': 'Nom du parent'
'#required': true
nom_du_compagnon:
'#type': textfield
'#title': 'Nom du compagnon'
'#required': true
focus_box_coords:
'#type': hidden
'#default_value': ''
apercu:
'#type': wizard_page
'#title': Aperçu
'#open': true
processed_text:
'#type': processed_text
'#text': '<div class="compagnon-fond"><div class="intro"><p class="intro"><strong>Compagnon de la semaine</strong></p><p class="text-center">Présentez-nous votre adorable boule de poils!</p><div class="align-center wxt-media-w400" style="max-height:285px;max-width:390px;"><div class="field field--name-field-media-image field--type-image field--label-hidden"><img class="img-responsive" loading="lazy" src="[webform_submission:values:photo:value:clear]?[current-date:raw]" width="390" height="280" alt=""></div></div><p class="nom">Nom : <strong>[webform_submission:values:nom_du_compagnon:value:clear]</strong></p><p class="parent">Parent : <strong>[webform_submission:values:nom_du_parent:value:clear]</strong></p><p class="bouton"><a class="btn btn-default btn-white btn-inverse" href="/fr/form/compagnon-du-mois">Soumettre une photo</a></p></div></div>'
'#format': rich_text_ckeditor5
actions:
'#type': webform_actions
'#title': "Bouton(s) d'envoi"
'#submit__attributes':
class:
- btn
- btn-default
- btn-inverse
'#update__label': 'Mise à jour'
'#update__attributes':
class:
- btn
- btn-default
- btn-inverse
'#delete_hide': false
'#delete__attributes':
class:
- btn
- btn-default
- btn-inverse
'#delete__dialog': true