Ajouter un type de bloc
Un type de bloc existe à quatre endroits. Oubliez-en un et l'échec est silencieux, d'une façon différente à chaque fois : c'est ce qui rend la découverte par tâtonnement si coûteuse.
| # | Endroit | Ce qu'il décide | En cas d'oubli |
|---|---|---|---|
| 1 | Resources/bweb/schema/blocks/<type>.json | Propriétés, sections, événements, validation | resolve() renvoie {error: "Schema introuvable pour le type: <type>"} : le panneau n'affiche aucun champ et validate() refuse toute écriture |
| 2 | Resources/bweb/bspk/<type>.html | Le HTML réellement rendu | Le bloc se rend comme un <bspk> vide |
| 3 | BSPK_SET_STORAGE_WEBPARAM (vc_DragableObject) | Présence dans la palette, icône, catégorie, icône dans l'arbre | Personne ne peut le déposer — et voir la remarque de sécurité plus bas |
| 4 | Misc/lang/<lang>/BSPK.json | Libellé de palette, libellés des sections et des champs, textes d'aide | Des clés brutes (BSPK_myBlock) à l'écran |
Lancez ensuite BSPK_REFRESH_STORAGE. Rien de ce qui précède n'est lu sur le disque au moment du rendu.
1. Le schéma
SchemaEngine.resolve(<type>) fusionne, dans cet ordre : les fragments listés dans includes (tirés de schema/shared.json), le fragment css (schema/css.json, qui injecte aussi stylePresets), puis les properties propres au type — le dernier l'emporte. Le format de déclaration d'une propriété est décrit dans Le contrat properties.
meta porte category, label, icon, draggable, internal, childrenAllowed et render. Les 28 types actuels utilisent tous render: "template" ; aucune autre valeur n'est implémentée.
meta.category n'est pas ce qu'affiche la palette. Les schémas utilisent trois valeurs (container, form, others) ; la palette en utilise six, tirées d'une autre liste (point 3).
2. Le gabarit
BSPK_LoadTpl lit tous les fichiers de Resources/bweb/bspk/ dans Storage.vo_Tpl.bspk, avec pour clé Lowercase(File.name) — sans l'extension. Le moteur de rendu cherche le gabarit par Lowercase($WebContent.type) (dans GG_PROCESS_COMPONENTS).
Le nom du fichier est donc le type, sans tenir compte de la casse. qrCodeScanner.html est trouvé sous qrcodescanner ; slider-part1.html ne correspond à aucun type et ne sert à rien.
Le gabarit passe ensuite par PROCESS 4D TAGS avec trois paramètres :
| Dans le gabarit | Contient |
|---|---|
$1 | $WebContent.uuidKey — l'uuid du bloc, pour des id uniques |
$2 | L'entité BSPK_WEB_CONTENT (une copie, sauf si updateFromObject est positionné) |
$3 | L'objet de travail du moteur de rendu — là où un type peut se transmettre des valeurs supplémentaires (le captcha y dépose vt_CaptchaText) |
Tous les gabarits commencent par le même préambule : prendre $2.properties quand $2 est un objet, sinon décoder $2 en BASE64 et le parser. Cette seconde branche permet à un gabarit d'en appeler un autre directement — captcha.html rend un fieldText de cette façon.
Une erreur de rendu est interceptée et transformée en toast qui nomme le bloc, le type et l'uuid : un gabarit cassé ne fait pas tomber la page. Voir 4D dans BWEB.
3. La palette, et pourquoi elle n'est pas cosmétique
BSPK_SET_STORAGE_WEBPARAM ajoute un objet par type dans Storage.vo_WebParam.vc_DragableObject :
{ "Xliff": "BSPK_myBlock", "dataItem": "myBlock", "icon": "bi-...",
"category": "form", "children": 0 }
Six catégories : container, content, form, data, navigation et model (la zone de modèle, filtrée sauf si GG_IS_MODEL_EDITOR, dans dev-pannel.html).
Trois contraintes pèsent sur cette liste :
- Les entrées d'une même catégorie doivent rester contiguës :
dev-pannel.htmlouvre une nouvelle grille quand la catégorie change et ferme la dernière par son index. - La chaîne
containerne doit pas changer :legacy-port.jss'en sert pour savoir quels blocs acceptent des enfants. - L'icône est réutilisée par l'arbre des blocs (
GG_MODEL_TREE_NODE,navItem.html,navGroup.html) : un type absent de la palette n'y a pas d'icône non plus.
La conséquence de sécurité. GG_WEB_SOCKET_SECURITY_CHECK déduit la liste des types de blocs de saisie de cette même collection :
vc_DragableObject.query("(category = form AND dataItem # button) OR (dataItem = listbox)")
Piège : un nouveau bloc de saisie rangé dans une autre catégorie n'est donc pas traité comme un champ par le contrôle du POST — sa valeur est retirée de
vt_FieldValuesans aucun message. C'est pourquoifieldCaptureetqrCodeScannersont rangés dansformalors que les schémas les classent dansothers.
4. Les traductions
Le libellé de palette est la clé Xliff ; les autres viennent du schéma (meta.label, libellés des sections, label et explanatoryText de chaque propriété). Toutes sont des clés résolues par BSPK_Translate, qui renvoie la clé elle-même quand elle manque : une clé oubliée s'affiche sous la forme BSPK_myBlock au lieu de lever une erreur. Ajoutez-la dans chaque fichier de langue ; les règles d'édition sont dans Les traductions (n'utilisez jamais JSON.stringify sur ces fichiers).
5. Rafraîchir, dans cet ordre
Schémas et gabarits vivent dans Storage, remplis par BSPK_LoadTpl et rafraîchis par BSPK_REFRESH_STORAGE. Ils ne sont plus relus sur le disque à chaque resolve().
- Vous avez modifié un schéma ou un gabarit :
BSPK_REFRESH_STORAGEsuffit. - Vous avez modifié un
.4dmde l'hôte :RELOAD PROJECT, puisBSPK_REFRESH_STORAGE. - Vous avez modifié le composant (
BSPK_SET_STORAGE_WEBPARAMcompris) : redémarrez 4D.
L'ordre compte quand les deux ont changé : rafraîchir d'abord relit la classe encore en mémoire. Voir Recharger ou redémarrer.
Piège : un JSON de schéma mal formé est avalé deux fois — une fois par le
TrydeBSPK_LoadTpl, une fois par leTrydeSchemaEngine._loadJson. Le type se résout alors enNullet le panneau est simplement vide. Validez le JSON avant d'accuser le panneau.
Ce que fait la création d'un bloc à l'exécution
Déposer un bloc depuis la palette envoie addItem: "<type>" à WebFormController.moduleSave. Celui-ci nomme le bloc avec getUniqueBlockName, appelle GG_INIT_CSS_PROPERTIES, puis applique des valeurs CSS par défaut propres à accordion, slider et wrapper. Rien d'autre n'est initialisé : un nouveau type démarre avec des properties vides, donc chaque gabarit doit tolérer une clé absente (voir Le langage 4D).
Voir aussi
- Le contrat properties — déclarer une propriété, et ce que
validate()refuse - Le dev-panel — comment le panneau construit ses champs à partir du schéma
- Les événements et le POST — déclarer
eventset recevoir le POST - Le style : cube CSS et Tailwind — le cube
cssPropertieset l'extraction Tailwind

