Base configuration
parent
dbe828b8d4
commit
c3c5d28aff
@ -0,0 +1,3 @@
|
|||||||
|
# Recipe Manager
|
||||||
|
|
||||||
|
WebSite for managing game recipes
|
@ -1,10 +1,12 @@
|
|||||||
import './bootstrap.js';
|
//region CSS
|
||||||
/*
|
import './styles/app.scss';
|
||||||
* Welcome to your app's main JavaScript file!
|
//endregion
|
||||||
*
|
//region Bootstrap
|
||||||
* This file will be included onto the page via the importmap() Twig function,
|
import 'bootstrap';
|
||||||
* which should already be in your base.html.twig.
|
//endregion
|
||||||
*/
|
//region jQuery
|
||||||
import './styles/app.css';
|
import 'jqueryLocal'; // Declare $ as a global variable, accessible in all files
|
||||||
|
//endregion
|
||||||
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');
|
//region FontAwesome
|
||||||
|
import 'fontawesome';
|
||||||
|
//endregion
|
@ -1,5 +0,0 @@
|
|||||||
import { startStimulusApp } from '@symfony/stimulus-bundle';
|
|
||||||
|
|
||||||
const app = startStimulusApp();
|
|
||||||
// register any custom, 3rd party controllers here
|
|
||||||
// app.register('some_controller_name', SomeImportedController);
|
|
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"controllers": {
|
|
||||||
"@symfony/ux-turbo": {
|
|
||||||
"turbo-core": {
|
|
||||||
"enabled": true,
|
|
||||||
"fetch": "eager"
|
|
||||||
},
|
|
||||||
"mercure-turbo-stream": {
|
|
||||||
"enabled": false,
|
|
||||||
"fetch": "eager"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"entrypoints": []
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
const nameCheck = /^[-_a-zA-Z0-9]{4,22}$/;
|
|
||||||
const tokenCheck = /^[-_\/+a-zA-Z0-9]{24,}$/;
|
|
||||||
|
|
||||||
// Generate and double-submit a CSRF token in a form field and a cookie, as defined by Symfony's SameOriginCsrfTokenManager
|
|
||||||
document.addEventListener('submit', function (event) {
|
|
||||||
generateCsrfToken(event.target);
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
// When @hotwired/turbo handles form submissions, send the CSRF token in a header in addition to a cookie
|
|
||||||
// The `framework.csrf_protection.check_header` config option needs to be enabled for the header to be checked
|
|
||||||
document.addEventListener('turbo:submit-start', function (event) {
|
|
||||||
const h = generateCsrfHeaders(event.detail.formSubmission.formElement);
|
|
||||||
Object.keys(h).map(function (k) {
|
|
||||||
event.detail.formSubmission.fetchRequest.headers[k] = h[k];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// When @hotwired/turbo handles form submissions, remove the CSRF cookie once a form has been submitted
|
|
||||||
document.addEventListener('turbo:submit-end', function (event) {
|
|
||||||
removeCsrfToken(event.detail.formSubmission.formElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
export function generateCsrfToken (formElement) {
|
|
||||||
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
|
|
||||||
|
|
||||||
if (!csrfField) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
|
|
||||||
let csrfToken = csrfField.value;
|
|
||||||
|
|
||||||
if (!csrfCookie && nameCheck.test(csrfToken)) {
|
|
||||||
csrfField.setAttribute('data-csrf-protection-cookie-value', csrfCookie = csrfToken);
|
|
||||||
csrfField.defaultValue = csrfToken = btoa(String.fromCharCode.apply(null, (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(18))));
|
|
||||||
csrfField.dispatchEvent(new Event('change', { bubbles: true }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (csrfCookie && tokenCheck.test(csrfToken)) {
|
|
||||||
const cookie = csrfCookie + '_' + csrfToken + '=' + csrfCookie + '; path=/; samesite=strict';
|
|
||||||
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateCsrfHeaders (formElement) {
|
|
||||||
const headers = {};
|
|
||||||
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
|
|
||||||
|
|
||||||
if (!csrfField) {
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
|
|
||||||
|
|
||||||
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
|
|
||||||
headers[csrfCookie] = csrfField.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeCsrfToken (formElement) {
|
|
||||||
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
|
|
||||||
|
|
||||||
if (!csrfField) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
|
|
||||||
|
|
||||||
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
|
|
||||||
const cookie = csrfCookie + '_' + csrfField.value + '=0; path=/; samesite=strict; max-age=0';
|
|
||||||
|
|
||||||
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stimulusFetch: 'lazy' */
|
|
||||||
export default 'csrf-protection-controller';
|
|
@ -1,16 +0,0 @@
|
|||||||
import { Controller } from '@hotwired/stimulus';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is an example Stimulus controller!
|
|
||||||
*
|
|
||||||
* Any element with a data-controller="hello" attribute will cause
|
|
||||||
* this controller to be executed. The name "hello" comes from the filename:
|
|
||||||
* hello_controller.js -> "hello"
|
|
||||||
*
|
|
||||||
* Delete this file or adapt it for your use!
|
|
||||||
*/
|
|
||||||
export default class extends Controller {
|
|
||||||
connect() {
|
|
||||||
this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,148 @@
|
|||||||
|
//region Datatables.net
|
||||||
|
import 'datatables.net';
|
||||||
|
import 'datatables.net-dt/css/dataTables.dataTables.min.css';
|
||||||
|
//endregion
|
||||||
|
//region Bootstrap 5 styling for Datatables.net
|
||||||
|
import 'datatables.net-bs5';
|
||||||
|
import 'datatables.net-bs5/css/dataTables.bootstrap5.min.css';
|
||||||
|
//endregion
|
||||||
|
//region Custom style for Datatables.net
|
||||||
|
import './styles/datatables.scss';
|
||||||
|
//endregion
|
||||||
|
import 'jqueryLocal';
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('table.table-datatable').each(function () {
|
||||||
|
const self = $(this);
|
||||||
|
|
||||||
|
//region Options du datatable
|
||||||
|
let options = {
|
||||||
|
paging: self.data('sortPaging', false),
|
||||||
|
pageLength: self.data('sortPerPage', 50),
|
||||||
|
processing: true,
|
||||||
|
layout: self.data(
|
||||||
|
'sortLayout',
|
||||||
|
{
|
||||||
|
topStart: null,
|
||||||
|
topEnd: null,
|
||||||
|
bottomStart: null,
|
||||||
|
bottomEnd: 'paging',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
//endregion
|
||||||
|
//region Gestion tri initial
|
||||||
|
let initialSort = [];
|
||||||
|
$('> thead > tr > th[data-sort-onLoad]', this).each(function () {
|
||||||
|
let self = $(this);
|
||||||
|
initialSort.push(
|
||||||
|
{
|
||||||
|
index: self.index(),
|
||||||
|
priority: self.data('sortOnload'),
|
||||||
|
direction: self.data('sortOrder', 'asc').toLowerCase(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
initialSort.sort(function (sort1, sort2) {
|
||||||
|
if (sort1.priority === sort2.priority) {
|
||||||
|
return sort1.index - sort2.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sort1.priority - sort2.priority;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (initialSort.length > 0) {
|
||||||
|
options.order = [];
|
||||||
|
initialSort.forEach(function (sortOrder) {
|
||||||
|
options.order.push([sortOrder.index, sortOrder.direction]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
//region Gestion sens de tri (1er clic ou initial si concerné)
|
||||||
|
let descSort = [];
|
||||||
|
$('> thead > tr > th[data-sort-order]', this).each(function () {
|
||||||
|
const self = $(this);
|
||||||
|
if (self.data('sortOrder', 'asc').toLowerCase() === 'desc') {
|
||||||
|
descSort.push(self.index());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (descSort.length > 0) {
|
||||||
|
if (!options.hasOwnProperty('columnDefs')) {
|
||||||
|
options.columnDefs = [];
|
||||||
|
}
|
||||||
|
options.columnDefs.push(
|
||||||
|
{
|
||||||
|
targets: descSort,
|
||||||
|
orderSequence: ['desc', 'asc'],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
//region Gestion désactivation tri
|
||||||
|
let disabledSort = [];
|
||||||
|
$('> thead > tr > th[data-sort]', this).each(function () {
|
||||||
|
const self = $(this);
|
||||||
|
if (!self.data('sort', true)) {
|
||||||
|
disabledSort.push(self.index());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (disabledSort.length > 0) {
|
||||||
|
if (!options.hasOwnProperty('columnDefs')) {
|
||||||
|
options.columnDefs = [];
|
||||||
|
}
|
||||||
|
options.columnDefs.push(
|
||||||
|
{
|
||||||
|
targets: disabledSort,
|
||||||
|
orderable: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
//region Gestion nom des colonnes
|
||||||
|
const columnsName = $('> thead > tr > th[data-sort-name]', this);
|
||||||
|
if (columnsName.length > 0) {
|
||||||
|
if (!options.hasOwnProperty('columnDefs')) {
|
||||||
|
options.columnDefs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
columnsName.each(function () {
|
||||||
|
const self = $(this);
|
||||||
|
const name = self.data('sortName', '');
|
||||||
|
if (name !== '') {
|
||||||
|
options.columnDefs.push(
|
||||||
|
{
|
||||||
|
targets: self.index(),
|
||||||
|
name: name,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
//region Gestion de AJAX
|
||||||
|
const ajaxUrl = self.data('sortAjax', false);
|
||||||
|
if (ajaxUrl !== false) {
|
||||||
|
options.serverSide = true;
|
||||||
|
options.ajax = {
|
||||||
|
url: ajaxUrl,
|
||||||
|
type: 'POST',
|
||||||
|
//createCDATASection: '',
|
||||||
|
cache: self.data('sortAjaxCache', false),
|
||||||
|
};
|
||||||
|
|
||||||
|
options.columns = [];
|
||||||
|
columnsName.each(function () {
|
||||||
|
const self = $(this);
|
||||||
|
const name = self.data('sortName', '');
|
||||||
|
if (name !== '') {
|
||||||
|
options.columns[self.index()] = {
|
||||||
|
data: name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
self.DataTable(options);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,8 @@
|
|||||||
|
import '@fortawesome/fontawesome-svg-core/styles.min.css';
|
||||||
|
|
||||||
|
import {library} from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import {dom} from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import {fas} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
library.add(fas);
|
||||||
|
dom.watch();
|
@ -0,0 +1,44 @@
|
|||||||
|
//region Import jQuery itself
|
||||||
|
import $ from 'jquery';
|
||||||
|
//endregion
|
||||||
|
import Utils from 'utils';
|
||||||
|
|
||||||
|
window.$ = $; // Ensure $ is available everywhere
|
||||||
|
window.jQuery = $; // Ensure global “jQuery” property available: necessary to use bootstrap event in jQuery.on ?
|
||||||
|
|
||||||
|
(function ($) {
|
||||||
|
//region .data
|
||||||
|
const jqueryDataOrig = $.fn.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a DOM "data" value
|
||||||
|
*
|
||||||
|
* @param {string} key The "data" key
|
||||||
|
* @param {any} defaultValue The default value
|
||||||
|
*
|
||||||
|
* @return {any} The "data" value
|
||||||
|
*/
|
||||||
|
$.fn.data = function (key, defaultValue = undefined) {
|
||||||
|
const value = jqueryDataOrig.apply(this, [key]);
|
||||||
|
if (Utils.isUndefined(value)) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
//endregion
|
||||||
|
//region .matchTag
|
||||||
|
/**
|
||||||
|
* Check if a jQuery element is one of the tags
|
||||||
|
*
|
||||||
|
* @param {string} tag The tag to check
|
||||||
|
* @param {string} extraTags Extra tags to check
|
||||||
|
*
|
||||||
|
* @return {boolean} True if the element is one of the tags
|
||||||
|
*/
|
||||||
|
$.fn.matchTag = function (tag, ...extraTags) {
|
||||||
|
extraTags.push(tag);
|
||||||
|
extraTags = extraTags.map((tag) => tag.toUpperCase());
|
||||||
|
return $.inArray(this.prop('tagName').toUpperCase(), extraTags) !== -1;
|
||||||
|
};
|
||||||
|
//endregion
|
||||||
|
})($);
|
@ -0,0 +1,72 @@
|
|||||||
|
//region Fonctions de base de Bootstrap
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/functions';
|
||||||
|
//endregion
|
||||||
|
//region Color theme
|
||||||
|
//$primary : rgb(0, 0, 0);
|
||||||
|
//$secondary : rgb(102, 102, 102);
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region Autres variables Bootstrap
|
||||||
|
$alert-padding-y : 0.25rem;
|
||||||
|
$alert-padding-x : 0.25rem;
|
||||||
|
$alert-margin-bottom : 0.5rem;
|
||||||
|
//endregion
|
||||||
|
//region Les autres variables de Boostrap
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/variables';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/variables-dark';
|
||||||
|
//endregion
|
||||||
|
//region Maps personnalisés
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region Reste de la configuration de Bootstrap
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/maps';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/mixins';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/utilities';
|
||||||
|
//endregion
|
||||||
|
//region Layout & components de Bootstrap
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/root';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/reboot';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/type';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/images';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/containers';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/grid';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/tables';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/forms';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/buttons';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/transitions';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/dropdown';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/button-group';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/nav';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/navbar';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/card';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/accordion';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/breadcrumb';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/pagination';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/badge';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/alert';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/progress';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/list-group';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/close';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/toasts';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/modal';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/tooltip';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/popover';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/carousel';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/spinners';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/offcanvas';
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/placeholders';
|
||||||
|
//endregion
|
||||||
|
//region Helpers de Boostrap
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/helpers';
|
||||||
|
//endregion
|
||||||
|
//region API de Bootstrap
|
||||||
|
@import '../../vendor/twbs/bootstrap/scss/utilities/api';
|
||||||
|
//endregion
|
||||||
|
//region Classes complémentaires
|
||||||
|
.text-smallCaps {
|
||||||
|
font-variant : small-caps;
|
||||||
|
}
|
||||||
|
.text-overflow-ellipsis {
|
||||||
|
text-overflow : '…';
|
||||||
|
}
|
||||||
|
//endregion
|
@ -0,0 +1,26 @@
|
|||||||
|
header, footer {
|
||||||
|
background-color : var(--bs-body-bg);
|
||||||
|
width : 100%;
|
||||||
|
margin : 0;
|
||||||
|
|
||||||
|
&:not(.overlay-not-fixed) {
|
||||||
|
position : fixed;
|
||||||
|
z-index : 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
top : 0;
|
||||||
|
height : 30px;
|
||||||
|
border-bottom : 1px solid black;
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
bottom : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#div-body {
|
||||||
|
padding-top : 21px;
|
||||||
|
padding-bottom : 0;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
scroll-padding-top : 21px
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
pre.xdebug-var-dump {
|
||||||
|
position : relative;
|
||||||
|
background-color : rgb(255, 255, 255);
|
||||||
|
z-index : 10000;
|
||||||
|
margin-bottom : 0;
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
body {
|
|
||||||
background-color: skyblue;
|
|
||||||
}
|
|
@ -0,0 +1,7 @@
|
|||||||
|
@import 'bootstrap';
|
||||||
|
@import 'xdebug';
|
||||||
|
@import 'layout';
|
||||||
|
|
||||||
|
.required:not(.form-check-label) {
|
||||||
|
color : var(--bs-red);
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order::after,
|
||||||
|
table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order::after,
|
||||||
|
table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order::after,
|
||||||
|
table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order::after,
|
||||||
|
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order::after,
|
||||||
|
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order::after,
|
||||||
|
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order::after,
|
||||||
|
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order::after {
|
||||||
|
margin-top : 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order,
|
||||||
|
table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order,
|
||||||
|
table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order,
|
||||||
|
table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order,
|
||||||
|
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order,
|
||||||
|
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order,
|
||||||
|
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order,
|
||||||
|
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order {
|
||||||
|
position : relative;
|
||||||
|
left : 10px;
|
||||||
|
top : none;
|
||||||
|
bottom : none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dt-container .dt-paging .dt-paging-button {
|
||||||
|
padding : 0;
|
||||||
|
margin : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.dataTable th.dt-type-numeric,
|
||||||
|
table.dataTable th.dt-type-date,
|
||||||
|
table.dataTable td.dt-type-numeric,
|
||||||
|
table.dataTable td.dt-type-date {
|
||||||
|
text-align : left;
|
||||||
|
}
|
@ -0,0 +1,145 @@
|
|||||||
|
export default class Utils {
|
||||||
|
/**
|
||||||
|
* Une variable vaut-elle "undefined" ?
|
||||||
|
*
|
||||||
|
* @param {any} variable La variable à tester
|
||||||
|
*
|
||||||
|
* @returns {boolean} Vrai si la variable vaut "undefined", sinon Faux
|
||||||
|
*/
|
||||||
|
static isUndefined (variable) {
|
||||||
|
return typeof variable === 'undefined';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Une variable est-elle une chaîne de caractère ?
|
||||||
|
*
|
||||||
|
* @param {any} variable La variable à tester
|
||||||
|
*
|
||||||
|
* @returns {boolean} Vrai si la variable est uen chaîne de caractères, sinon Faux
|
||||||
|
*/
|
||||||
|
static isString (variable) {
|
||||||
|
return typeof variable === 'string' || variable instanceof String;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Une variable est-elle une chaine de caractère vide ou équivalent (undefined ou null) ?
|
||||||
|
*
|
||||||
|
* @param {any} variable La variable à tester
|
||||||
|
*
|
||||||
|
* @returns {boolean} Vrai si la variable est une chaine de caractères vide (ou équivalent)
|
||||||
|
*/
|
||||||
|
static empty_str (variable) {
|
||||||
|
return Utils.isUndefined(variable) || variable === null || variable === '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie qu'au moins une case à cocher d'une liste de cases à cocher est bien cochée
|
||||||
|
*
|
||||||
|
* @param {jQuery} list Une liste de case à cocher
|
||||||
|
*
|
||||||
|
* @returns {boolean} Vrai si au moins l'un de case à cocher est cochée.
|
||||||
|
*/
|
||||||
|
static checkAtLeastOnChecked (list) {
|
||||||
|
return list.filter(':checked').length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Est-ce qu'un objet jQuery possède un attribut et qu'il est différent de Faux
|
||||||
|
*
|
||||||
|
* @param {jQuery} objJquery L'objet jQuery
|
||||||
|
* @param {string} attrName Le nom de l'attribut
|
||||||
|
*
|
||||||
|
* @returns {boolean} Vrai si l'attribut existe et est différent de Faux.
|
||||||
|
*/
|
||||||
|
static hasAttr (objJquery, attrName) {
|
||||||
|
let val = objJquery.attr(attrName);
|
||||||
|
return !Utils.isUndefined(val) && val !== false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Récupère le formulaire associé à un champ
|
||||||
|
*
|
||||||
|
* Tient compte de l'attribut "form" si renseigné.
|
||||||
|
*
|
||||||
|
* @param {jQuery} input Le champ pour lequel on veut le formulaire
|
||||||
|
*
|
||||||
|
* @returns {jQuery} Le formulaire correspondant
|
||||||
|
*/
|
||||||
|
static getFormOfInput (input) {
|
||||||
|
let form;
|
||||||
|
|
||||||
|
if (Utils.hasAttr(input, 'form')) {
|
||||||
|
form = $('#' + input.attr('form'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
form = input.parents('form').first();
|
||||||
|
}
|
||||||
|
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime les doublons d'un tableau
|
||||||
|
*
|
||||||
|
* @param {any[]} array Le tableau à dédoublonner
|
||||||
|
*
|
||||||
|
* @returns {any[]} Le tableau dédoublonné
|
||||||
|
*/
|
||||||
|
static array_uniq (array) {
|
||||||
|
return Array.from(new Set(array));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met la première lettre d'une chaine de caractères en majuscule
|
||||||
|
*
|
||||||
|
* @param {string} string La chaine de caractères
|
||||||
|
*
|
||||||
|
* @returns {string} La chaine de caractères avec la première lettre en majuscule
|
||||||
|
*/
|
||||||
|
static string_ucFirst (string) {
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule la taille RÉELLE d'un élément jQuery
|
||||||
|
*
|
||||||
|
* Prends la plus grande valeur entre la hauteur CSS de l'élément et la hauteur réelle de ses enfants.
|
||||||
|
*
|
||||||
|
* Cela permet de "corriger" le problème des conteneurs plus petit que leurs enfants
|
||||||
|
*
|
||||||
|
* @param {jQuery} element
|
||||||
|
*
|
||||||
|
* @returns {int} La hauteur réelle (en px)
|
||||||
|
*/
|
||||||
|
static getElementRealHeight (element) {
|
||||||
|
if (element.length <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const elementHeight = element.outerHeight(true);
|
||||||
|
|
||||||
|
let childrenHeight = 0;
|
||||||
|
element.children().each(function () {
|
||||||
|
childrenHeight = Utils.getElementRealHeight($(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
return parseInt(childrenHeight > elementHeight ? childrenHeight : elementHeight, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajoute des arguments à une URL
|
||||||
|
*
|
||||||
|
* @param {object} arguments Les arguments à ajouter
|
||||||
|
* @param {string} url L'URL à laquelle ajouter les arguments ; celle actuelle (location.href) si non fournie
|
||||||
|
*
|
||||||
|
* @return {string} L'URL de résultat
|
||||||
|
*/
|
||||||
|
static addArgumentsToUrl (args, url = undefined) {
|
||||||
|
if (Utils.isUndefined(url)) {
|
||||||
|
url = document.location.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
let urlObj = new URL(url);
|
||||||
|
for (const [argumentName, argumentValue] of Object.entries(args)) {
|
||||||
|
urlObj.searchParams.set(argumentName, argumentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlObj.toString();
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20250525095556 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', available_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', delivered_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
DROP TABLE messenger_messages
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Misc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common types of flash message
|
||||||
|
*/
|
||||||
|
class FlashType {
|
||||||
|
/**
|
||||||
|
* Information message
|
||||||
|
*/
|
||||||
|
public const INFO = 'info';
|
||||||
|
/**
|
||||||
|
* Success message
|
||||||
|
*/
|
||||||
|
public const SUCCESS = 'success';
|
||||||
|
/**
|
||||||
|
* Warning message
|
||||||
|
*/
|
||||||
|
public const WARNING = 'warning';
|
||||||
|
/**
|
||||||
|
* Error message
|
||||||
|
*/
|
||||||
|
public const ERROR = 'danger';
|
||||||
|
}
|
Loading…
Reference in New Issue