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.

#EndroitCe qu'il décideEn cas d'oubli
1Resources/bweb/schema/blocks/<type>.jsonPropriétés, sections, événements, validationresolve() renvoie {error: "Schema introuvable pour le type: <type>"} : le panneau n'affiche aucun champ et validate() refuse toute écriture
2Resources/bweb/bspk/<type>.htmlLe HTML réellement renduLe bloc se rend comme un <bspk> vide
3BSPK_SET_STORAGE_WEBPARAM (vc_DragableObject)Présence dans la palette, icône, catégorie, icône dans l'arbrePersonne ne peut le déposer — et voir la remarque de sécurité plus bas
4Misc/lang/<lang>/BSPK.jsonLibellé de palette, libellés des sections et des champs, textes d'aideDes 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 gabaritContient
$1$WebContent.uuidKey — l'uuid du bloc, pour des id uniques
$2L'entité BSPK_WEB_CONTENT (une copie, sauf si updateFromObject est positionné)
$3L'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.html ouvre une nouvelle grille quand la catégorie change et ferme la dernière par son index.
  • La chaîne container ne doit pas changer : legacy-port.js s'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_FieldValue sans aucun message. C'est pourquoi fieldCapture et qrCodeScanner sont rangés dans form alors que les schémas les classent dans others.

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_STORAGE suffit.
  • Vous avez modifié un .4dm de l'hôte : RELOAD PROJECT, puis BSPK_REFRESH_STORAGE.
  • Vous avez modifié le composant (BSPK_SET_STORAGE_WEBPARAM compris) : 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 Try de BSPK_LoadTpl, une fois par le Try de SchemaEngine._loadJson. Le type se résout alors en Null et 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