feat(planning): grille hebdomadaire complète avec API et filtres
- Connexion API via proxy Angular (résolution CORS, base path /api) - Import CSS ng-zorro global pour les modales et composants - Filtres Camion/Show câblés sur l'affichage de la grille - Camions affichés via TrucksService (linkés au show du même créneau) - Panneau de détails : spectacles + camions du jour sélectionné - Modale de création de spectacle stylisée avec fond et centrage - Positionnement précis des events à la minute dans leur créneau - Auto-scroll vers l'heure courante au chargement - Ligne "maintenant" sur la colonne du jour actuel - Régénération des services OpenAPI (nouveaux noms de types) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+41
-118
@@ -15,11 +15,12 @@ module.exports = contentDisposition
|
||||
module.exports.parse = parse
|
||||
|
||||
/**
|
||||
* TextDecoder instance for UTF-8 decoding when decodeURIComponent fails due to invalid byte sequences.
|
||||
* @type {TextDecoder}
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
const utf8Decoder = new TextDecoder('utf-8')
|
||||
|
||||
var basename = require('path').basename
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
|
||||
/**
|
||||
* RegExp to match non attr-char, *after* encodeURIComponent (i.e. not including "%")
|
||||
@@ -28,6 +29,14 @@ const utf8Decoder = new TextDecoder('utf-8')
|
||||
|
||||
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g // eslint-disable-line no-control-regex
|
||||
|
||||
/**
|
||||
* RegExp to match percent encoding escape.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/
|
||||
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g
|
||||
|
||||
/**
|
||||
* RegExp to match non-latin1 characters.
|
||||
* @private
|
||||
@@ -191,7 +200,7 @@ function createparams (filename, fallback) {
|
||||
var hasFallback = typeof fallbackName === 'string' && fallbackName !== name
|
||||
|
||||
// set extended filename parameter
|
||||
if (hasFallback || !isQuotedString || hasHexEscape(name)) {
|
||||
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
|
||||
params['filename*'] = name
|
||||
}
|
||||
|
||||
@@ -254,41 +263,32 @@ function format (obj) {
|
||||
*/
|
||||
|
||||
function decodefield (str) {
|
||||
const match = EXT_VALUE_REGEXP.exec(str)
|
||||
var match = EXT_VALUE_REGEXP.exec(str)
|
||||
|
||||
if (!match) {
|
||||
throw new TypeError('invalid extended field value')
|
||||
}
|
||||
|
||||
const charset = match[1].toLowerCase()
|
||||
const encoded = match[2]
|
||||
var charset = match[1].toLowerCase()
|
||||
var encoded = match[2]
|
||||
var value
|
||||
|
||||
// to binary string
|
||||
var binary = encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode)
|
||||
|
||||
switch (charset) {
|
||||
case 'iso-8859-1':
|
||||
{
|
||||
const binary = decodeHexEscapes(encoded)
|
||||
return getlatin1(binary)
|
||||
}
|
||||
value = getlatin1(binary)
|
||||
break
|
||||
case 'utf-8':
|
||||
case 'utf8':
|
||||
{
|
||||
try {
|
||||
return decodeURIComponent(encoded)
|
||||
} catch {
|
||||
// Failed to decode with decodeURIComponent, fallback to lenient decoding which replaces invalid UTF-8 byte sequences with the Unicode replacement character
|
||||
// TODO: Consider removing in the next major version to be more strict about invalid percent-encodings
|
||||
const binary = decodeHexEscapes(encoded)
|
||||
|
||||
const bytes = new Uint8Array(binary.length)
|
||||
for (let idx = 0; idx < binary.length; idx++) {
|
||||
bytes[idx] = binary.charCodeAt(idx)
|
||||
}
|
||||
|
||||
return utf8Decoder.decode(bytes)
|
||||
}
|
||||
}
|
||||
value = Buffer.from(binary, 'binary').toString('utf8')
|
||||
break
|
||||
default:
|
||||
throw new TypeError('unsupported charset in extended field')
|
||||
}
|
||||
throw new TypeError('unsupported charset in extended field')
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,6 +384,19 @@ function parse (string) {
|
||||
return new ContentDisposition(type, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Percent decode a single character.
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {string} hex
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function pdecode (str, hex) {
|
||||
return String.fromCharCode(parseInt(hex, 16))
|
||||
}
|
||||
|
||||
/**
|
||||
* Percent encode a single character.
|
||||
*
|
||||
@@ -444,93 +457,3 @@ function ContentDisposition (type, parameters) {
|
||||
this.type = type
|
||||
this.parameters = parameters
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last portion of a path
|
||||
*
|
||||
* @param {string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
function basename (path) {
|
||||
const normalized = path.replaceAll('\\', '/')
|
||||
|
||||
let end = normalized.length
|
||||
while (end > 0 && normalized[end - 1] === '/') {
|
||||
end--
|
||||
}
|
||||
|
||||
if (end === 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
let start = end - 1
|
||||
while (start >= 0 && normalized[start] !== '/') {
|
||||
start--
|
||||
}
|
||||
|
||||
return normalized.slice(start + 1, end)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a character is a hex digit [0-9A-Fa-f]
|
||||
*
|
||||
* @param {string} char
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
function isHexDigit (char) {
|
||||
const code = char.charCodeAt(0)
|
||||
return (
|
||||
(code >= 48 && code <= 57) || // 0-9
|
||||
(code >= 65 && code <= 70) || // A-F
|
||||
(code >= 97 && code <= 102) // a-f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string contains percent encoding escapes.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
function hasHexEscape (str) {
|
||||
const maxIndex = str.length - 3
|
||||
let lastIndex = -1
|
||||
|
||||
while ((lastIndex = str.indexOf('%', lastIndex + 1)) !== -1 && lastIndex <= maxIndex) {
|
||||
if (isHexDigit(str[lastIndex + 1]) && isHexDigit(str[lastIndex + 2])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode hex escapes in a string (e.g., %20 -> space)
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
function decodeHexEscapes (str) {
|
||||
const firstEscape = str.indexOf('%')
|
||||
if (firstEscape === -1) return str
|
||||
|
||||
let result = str.slice(0, firstEscape)
|
||||
for (let idx = firstEscape; idx < str.length; idx++) {
|
||||
if (
|
||||
str[idx] === '%' &&
|
||||
idx + 2 < str.length &&
|
||||
isHexDigit(str[idx + 1]) &&
|
||||
isHexDigit(str[idx + 2])
|
||||
) {
|
||||
result += String.fromCharCode(Number.parseInt(str[idx + 1] + str[idx + 2], 16))
|
||||
idx += 2
|
||||
} else {
|
||||
result += str[idx]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user