@gouvfr/dsfr-roller 1.0.50 → 1.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SECURITY.md +1 -1
- package/legal/cgu.md +7 -7
- package/package.json +3 -3
- package/src/node/directive/components/table/table-container-directive.js +1 -0
- package/src/node/directive/components/tile/tile-container-directive.js +19 -6
- package/src/node/directive/doc/guidance/guideline-container-directive.js +1 -4
- package/src/node/directive/doc/prevent-permalinks-container-directive.js +12 -0
- package/src/node/gfm/table-header-node.js +0 -1
- package/src/node/gfm/table-node.js +2 -1
- package/src/node/node-factory.js +3 -1
- package/src/node/node.js +1 -1
- package/src/page/body/edit.js +1 -2
- package/src/page/body/mesh.js +55 -0
- package/src/page/scripts/scripts.js +2 -1
- package/src/script/pattern/index.js +3 -0
- package/src/script/pattern/name/add-firstname.js +38 -0
- package/src/script/pattern/name/remove-firstname.js +4 -0
- package/src/script/pattern/name/toggle-disabled.js +8 -0
- package/src/style/main/components/_dsfr-doc-anatomy.scss +1 -0
- package/src/style/main/components/_fr-tile.scss +17 -0
- package/src/style/main/components/_index.scss +1 -0
- package/src/style/main/utility/_dsfr-doc-anchor-heading.scss +5 -0
- package/src/style/main/utility/_index.scss +1 -0
- package/src/template/template.js +28 -2
- package/src/template/templates/editorial-template.js +9 -1
package/SECURITY.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## Sécurité du Système de Design de l
|
|
1
|
+
## Sécurité du Système de Design de l’État
|
|
2
2
|
|
|
3
3
|
L’équipe derrière le Système de Design de l’État prend les risques liés à la sécurité très au sérieux.
|
|
4
4
|
C’est pour cette raison qu’un audit de sécurité à été réalisé sur l’ensemble des composants et des librairies avant la sortie ainsi que la mise en place de bonnes pratiques (double authentification, signature des paquets, etc.).
|
package/legal/cgu.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## CONDITIONS GÉNÉRALES D’UTILISATION DU SYSTÈME DE DESIGN DE L’ÉTAT
|
|
2
2
|
|
|
3
|
-
Le Service d’Information du Gouvernement (« SIG ») vous remercie de bien vouloir lire attentivement l’intégralité des présentes Conditions Générales d’Utilisation (« CGU ») avant d’utiliser la plateforme du Système de Design de l
|
|
3
|
+
Le Service d’Information du Gouvernement (« SIG ») vous remercie de bien vouloir lire attentivement l’intégralité des présentes Conditions Générales d’Utilisation (« CGU ») avant d’utiliser la plateforme du Système de Design de l’État (« Plateforme »). Tout accès, toute utilisation et/ou toute Contribution à la Plateforme est subordonné au respect des présentes CGU. Tout Utilisateur de la Plateforme reconnaît souscrire sans réserve aux présentes CGU et s’engage à les respecter.
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ Le Service d’Information du Gouvernement (« SIG ») vous remercie de bien vou
|
|
|
9
9
|
Le SIG est le pilote de la transformation numérique de la communication de l’État . À ce titre, le SIG a pour mission de placer toutes les actions du Gouvernement sous la marque de l’État afin de garantir l’homogénéité et la reconnaissance de l’ensemble des initiatives ministérielles ou interministérielles.
|
|
10
10
|
Dans ce cadre, le SIG a mis en place la nouvelle stratégie de la marque de l’État pour rendre l’action de l’État plus concrète, lisible et visible grâce à un signe commun pour les citoyens.
|
|
11
11
|
|
|
12
|
-
Dans la continuité de la mise en œuvre de la marque de l’État, le SIG a structuré dans le cadre d’une plateforme, le Système de Design de l
|
|
12
|
+
Dans la continuité de la mise en œuvre de la marque de l’État, le SIG a structuré dans le cadre d’une plateforme, le Système de Design de l’État visant à mettre à disposition des librairies de Ressources permettant notamment de standardiser et d’harmoniser l’expérience numérique de l’État et des citoyens grâce à une interface commune des sites Internet et applications de l’État. Le Système de Design de l’État permet ainsi de générer des économies, en rationalisant les développements numériques, de garantir la qualité et l’efficacité de l’expérience utilisateur, la cohérence et une meilleure reconnaissance des services de l’État.
|
|
13
13
|
|
|
14
14
|
Les présentes Conditions Générales définissent les conditions selon lesquelles l’Utilisateur de l’État ou les Autres Utilisateurs peuvent naviguer sur la Plateforme accessible sur l’URL https://www.systeme-de-design.gouv.fr, accéder et exploiter les Ressources et Contribuer à leur amélioration ou leur enrichissement.
|
|
15
15
|
|
|
@@ -19,13 +19,13 @@ Les présentes Conditions Générales définissent les conditions selon lesquell
|
|
|
19
19
|
|
|
20
20
|
Les termes débutant avec une majuscule dans les présentes CGU, qu’ils soient utilisés au singulier ou au pluriel auront la signification qui leur est attribuée ci-après :
|
|
21
21
|
|
|
22
|
-
* **Communauté** : désigne la communauté en ligne des Utilisateurs et des membres de l’équipe du Système de Design de l
|
|
22
|
+
* **Communauté** : désigne la communauté en ligne des Utilisateurs et des membres de l’équipe du Système de Design de l’État.
|
|
23
23
|
|
|
24
24
|
* **Composants** : désigne les librairies d’éléments destinés aux designers et aux développeurs intégrant des Éléments Graphiques (Fondamentaux Techniques et les Éléments d’Identité), des Éléments d’Interface, des Paquets de codes sources.
|
|
25
25
|
|
|
26
26
|
* **Contribution** : désigne tout élément fourni par l’Utilisateur dans le cadre de l’utilisation de la Plateforme, qu’il s’agisse de la modification d’un Composant ou du développement d’un nouveau Composant.
|
|
27
27
|
|
|
28
|
-
* **Système de Design de l
|
|
28
|
+
* **Système de Design de l’État (DSFR)** : désigne l’ensemble de Composants réutilisables, guidé par des standards et une gouvernance, devant être assemblés pour construire les sites internet et applications mobiles des Entités Autorisées et objet des présentes Conditions Générales.
|
|
29
29
|
|
|
30
30
|
* **Documentation** : désigne les principes d’utilisation des Composants auxquels les Utilisateurs doivent se conformer.
|
|
31
31
|
|
|
@@ -41,11 +41,11 @@ Les termes débutant avec une majuscule dans les présentes CGU, qu’ils soient
|
|
|
41
41
|
|
|
42
42
|
* **Marque de l’Etat** : telle que définie par la circulaire du Premier Ministre en date du 17 février 2020, laquelle précise la stratégie de marque de l’Etat.
|
|
43
43
|
|
|
44
|
-
* **Opérateurs de l’État** : désigne les entités définies chaque année dans l’annexe « Opérateurs de l
|
|
44
|
+
* **Opérateurs de l’État** : désigne les entités définies chaque année dans l’annexe « Opérateurs de l’État » du projet de loi de finances de l’année en cours.
|
|
45
45
|
|
|
46
46
|
* **Paquets de codes sources** : désigne les fichiers de codes sources accessibles sur la plateforme de Git (Github).
|
|
47
47
|
|
|
48
|
-
* **Plateforme** : désigne le site Internet du Système de Design de l
|
|
48
|
+
* **Plateforme** : désigne le site Internet du Système de Design de l’État, permettant aux Utilisateurs de naviguer, utiliser et contribuer au Système de Design de l’État.
|
|
49
49
|
|
|
50
50
|
* **Ressources** : désigne les Composants, la Documentation, le support et les outils mis à disposition de l’Utilisateur sur ou au travers de la Plateforme.
|
|
51
51
|
|
|
@@ -146,7 +146,7 @@ Cette Plateforme est en constante évolution et enrichissement et le SIG ne saur
|
|
|
146
146
|
|
|
147
147
|
### ARTICLE 5 – PROCÉDURE D’AGRÉMENT
|
|
148
148
|
|
|
149
|
-
Conformément à la circulaire n°6120/SG du 14 octobre 2019 relative à l’organisation et la coordination de la communication gouvernementale, toutes les refontes ou créations de site Internet et applications mobiles de communication de l
|
|
149
|
+
Conformément à la circulaire n°6120/SG du 14 octobre 2019 relative à l’organisation et la coordination de la communication gouvernementale, toutes les refontes ou créations de site Internet et applications mobiles de communication de l’État (que le nom de domaine soit en <.gouv.fr>, en <.fr> ou autre) sont obligatoirement soumises à l’agrément du SIG.
|
|
150
150
|
|
|
151
151
|
Les Entités Autorisées doivent solliciter un agrément de principe du SIG, préalablement au lancement des prestations de refonte ou de création d’un site Internet et applications mobiles de communication de l’État pour lequel ils entendent utiliser la Plateforme. Cette demande s’effectue à l’aide du formulaire disponible au lien suivant : https://www.demarches-simplifiees.fr/commencer/agrement-principe-site-internet
|
|
152
152
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gouvfr/dsfr-roller",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.52",
|
|
4
4
|
"description": "Le module `dsfr-roller` permet de publier le site de documentation du Système de Design de l’État - DSFR",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Système de Design de l'État",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
],
|
|
57
57
|
"main": "./index.js",
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@gouvfr/dsfr-forge": "=1.0.
|
|
60
|
-
"@gouvfr/dsfr-publisher": "npm:@gouvfr/dsfr@1.14.
|
|
59
|
+
"@gouvfr/dsfr-forge": "=1.0.52",
|
|
60
|
+
"@gouvfr/dsfr-publisher": "npm:@gouvfr/dsfr@1.14.1-rc.1",
|
|
61
61
|
"deepmerge": "^4.3.1",
|
|
62
62
|
"ejs": "^3.1.10",
|
|
63
63
|
"highlight.js": "^11.10.0",
|
|
@@ -22,6 +22,7 @@ class TableContainerDirective extends Node {
|
|
|
22
22
|
const table = data.children?.find(child => child.type === 'table');
|
|
23
23
|
if (table ) {
|
|
24
24
|
table.caption = directiveLabel.children?.[0]?.value;
|
|
25
|
+
table.multiline = data.properties?.multiline === true;
|
|
25
26
|
}
|
|
26
27
|
return data;
|
|
27
28
|
}
|
|
@@ -25,6 +25,8 @@ class TileContainerDirective extends Node {
|
|
|
25
25
|
structureTile(data) {
|
|
26
26
|
const pictogramUrl = data.properties.pictogram;
|
|
27
27
|
const image = Node.getImageChild(data);
|
|
28
|
+
const imgDarkUrl = data.imgDarkUrl;
|
|
29
|
+
const hasImage = image || imgDarkUrl;
|
|
28
30
|
const contentChildren = data.children.filter(child => !Node.getImageChild(child));
|
|
29
31
|
const title = contentChildren.find(child => child.type === 'heading');
|
|
30
32
|
const description = contentChildren[1];
|
|
@@ -71,7 +73,7 @@ class TileContainerDirective extends Node {
|
|
|
71
73
|
},
|
|
72
74
|
]
|
|
73
75
|
},
|
|
74
|
-
pictogramUrl ||
|
|
76
|
+
pictogramUrl || hasImage ? {
|
|
75
77
|
type: 'htmlContainer',
|
|
76
78
|
tagName: 'div',
|
|
77
79
|
classes: ['fr-tile__header'],
|
|
@@ -120,17 +122,28 @@ class TileContainerDirective extends Node {
|
|
|
120
122
|
}
|
|
121
123
|
]
|
|
122
124
|
} : {},
|
|
123
|
-
|
|
125
|
+
hasImage ? {
|
|
124
126
|
type: 'htmlContainer',
|
|
125
127
|
tagName: 'div',
|
|
126
128
|
classes: ['fr-tile__img'],
|
|
127
129
|
children: [
|
|
128
130
|
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
classes: ['fr-responsive-img', imgDarkUrl ? 'fr-tile__img--light' : ''],
|
|
132
|
+
attributes: {
|
|
133
|
+
'aria-hidden': 'true',
|
|
134
|
+
},
|
|
135
|
+
...image,
|
|
136
|
+
},
|
|
137
|
+
imgDarkUrl ? {
|
|
138
|
+
classes: ['fr-responsive-img', 'fr-tile__img--dark'],
|
|
139
|
+
type: 'image',
|
|
140
|
+
attributes: {
|
|
141
|
+
src: imgDarkUrl,
|
|
142
|
+
'aria-hidden': 'true'
|
|
143
|
+
}
|
|
144
|
+
} : {}
|
|
132
145
|
]
|
|
133
|
-
} : {}
|
|
146
|
+
} : {}
|
|
134
147
|
]
|
|
135
148
|
} : {},
|
|
136
149
|
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Node } from '../../node.js'
|
|
2
|
+
|
|
3
|
+
class PreventPermalinksContainerDirective extends Node {
|
|
4
|
+
async render() {
|
|
5
|
+
const content = await super.render();
|
|
6
|
+
return `<!-- NO_PERMALINK_START -->\n${content}\n<!-- NO_PERMALINK_END -->`;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
PreventPermalinksContainerDirective.NAME = 'dsfr-doc-prevent-permalinks';
|
|
11
|
+
|
|
12
|
+
export { PreventPermalinksContainerDirective };
|
|
@@ -5,7 +5,6 @@ class TableHeaderNode extends TableCellNode {
|
|
|
5
5
|
super(data, 'th');
|
|
6
6
|
if (this.data.scope) {
|
|
7
7
|
this.attributes.setAttribute('scope', this.data.scope);
|
|
8
|
-
if (this.data.scope === 'row') this.attributes.addClass('fr-cell--fixed');
|
|
9
8
|
}
|
|
10
9
|
if (this.data.isColumnHeader) this.attributes.setAttribute('role', 'columnheader');
|
|
11
10
|
}
|
|
@@ -5,6 +5,7 @@ class TableNode extends Node {
|
|
|
5
5
|
constructor (data) {
|
|
6
6
|
super(data);
|
|
7
7
|
this._caption = data.caption;
|
|
8
|
+
this._multiline = data.multiline;
|
|
8
9
|
this.attributes.addClass('fr-table');
|
|
9
10
|
}
|
|
10
11
|
|
|
@@ -70,7 +71,7 @@ class TableNode extends Node {
|
|
|
70
71
|
<div class="fr-table__wrapper">
|
|
71
72
|
<div class="fr-table__container">
|
|
72
73
|
<div class="fr-table__content">
|
|
73
|
-
<table>
|
|
74
|
+
<table ${this._multiline ? 'class="fr-cell--multiline"' : ''}>
|
|
74
75
|
${caption}
|
|
75
76
|
${await this.renderChildren()}
|
|
76
77
|
</table>
|
package/src/node/node-factory.js
CHANGED
|
@@ -59,6 +59,7 @@ import { PageItemCardContainerDirective } from './directive/doc/page-item-card-c
|
|
|
59
59
|
import { VideoLeafDirective } from './directive/doc/video-leaf-directive.js';
|
|
60
60
|
import { ImageTextDirective } from './directive/doc/image-text-directive.js'
|
|
61
61
|
import { ChangelogLeafDirective } from './directive/doc/changelog-leaf-directive.js'
|
|
62
|
+
import { PreventPermalinksContainerDirective } from './directive/doc/prevent-permalinks-container-directive.js';
|
|
62
63
|
|
|
63
64
|
|
|
64
65
|
const NODES = [
|
|
@@ -118,7 +119,8 @@ const DIRECTIVE_CONTAINERS = [
|
|
|
118
119
|
TabsContainerDirective,
|
|
119
120
|
AnatomyContainerDirective,
|
|
120
121
|
GridContainerDirective,
|
|
121
|
-
ColContainerDirective
|
|
122
|
+
ColContainerDirective,
|
|
123
|
+
PreventPermalinksContainerDirective
|
|
122
124
|
];
|
|
123
125
|
const DIRECTIVE_LEAFS = [
|
|
124
126
|
ButtonLeafDirective,
|
package/src/node/node.js
CHANGED
package/src/page/body/edit.js
CHANGED
|
@@ -6,9 +6,8 @@ class Edit {
|
|
|
6
6
|
classes: ['dsfr-doc-edit', 'fr-background-alt--blue-france', `fr-icon-${data.icon ?? 'edit-fill'}`],
|
|
7
7
|
children: [
|
|
8
8
|
{
|
|
9
|
-
type: '
|
|
9
|
+
type: 'paragraph',
|
|
10
10
|
classes: ['dsfr-doc-edit__title', 'fr-h5'],
|
|
11
|
-
depth: data.depth ?? 5,
|
|
12
11
|
children: [
|
|
13
12
|
{
|
|
14
13
|
type: 'text',
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const MAX_MESH_ITEMS = 3;
|
|
2
|
+
|
|
3
|
+
class Mesh {
|
|
4
|
+
constructor(data) {
|
|
5
|
+
const children = [];
|
|
6
|
+
for (const [i, item] of data.items.entries()) {
|
|
7
|
+
if (i >= MAX_MESH_ITEMS) break;
|
|
8
|
+
children.push({
|
|
9
|
+
...item,
|
|
10
|
+
type: 'containerDirective',
|
|
11
|
+
name: 'dsfr-doc-page-item-card',
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
children.sort((a, b) => {
|
|
15
|
+
const textA = a.text.toLowerCase();
|
|
16
|
+
const textB = b.text.toLowerCase();
|
|
17
|
+
return textA.localeCompare(textB);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
this._node ={
|
|
21
|
+
type: 'htmlContainer',
|
|
22
|
+
tagName: 'div',
|
|
23
|
+
classes: ['dsfr-doc-mesh'],
|
|
24
|
+
children: [
|
|
25
|
+
{
|
|
26
|
+
type: 'heading',
|
|
27
|
+
classes: ['dsfr-doc-mesh__title', 'fr-h3'],
|
|
28
|
+
depth: data.depth ?? 5,
|
|
29
|
+
children: [
|
|
30
|
+
{
|
|
31
|
+
type: 'text',
|
|
32
|
+
value: data.title
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'htmlContainer',
|
|
38
|
+
tagName: 'div',
|
|
39
|
+
classes: [
|
|
40
|
+
'fr-grid-row',
|
|
41
|
+
'fr-grid-row--gutters',
|
|
42
|
+
'fr-mb-12v',
|
|
43
|
+
],
|
|
44
|
+
children: children,
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get node () {
|
|
51
|
+
return this._node;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { Mesh };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const getFieldsetElement = (node) => {
|
|
2
|
+
const parent = node.parentNode;
|
|
3
|
+
if (parent.className.indexOf('fr-fieldset__element') > -1) return parent;
|
|
4
|
+
return getFieldsetElement(parent);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
window.addFirstname = (button, id) => {
|
|
8
|
+
button.firstnamesCount = (button.firstnamesCount + 1) || 1;
|
|
9
|
+
|
|
10
|
+
const firstname = getFieldsetElement(document.getElementById(id));
|
|
11
|
+
const reference = getFieldsetElement(button);
|
|
12
|
+
|
|
13
|
+
const copy = firstname.cloneNode(true);
|
|
14
|
+
let html = copy.innerHTML;
|
|
15
|
+
const regexp = new RegExp(id, 'g');
|
|
16
|
+
html = html.replace(regexp, `${id}-added-${button.firstnamesCount}`);
|
|
17
|
+
html = html.replace('name="given-name"', `name="additional-name-${button.firstnamesCount}"`);
|
|
18
|
+
html = html.replace('autocomplete="given-name"', 'autocomplete="additional-name"');
|
|
19
|
+
copy.innerHTML = html;
|
|
20
|
+
|
|
21
|
+
const wrapper = document.createElement('div');
|
|
22
|
+
wrapper.classList.add('fr-input-wrap', 'fr-input-wrap--action');
|
|
23
|
+
|
|
24
|
+
const removeButton = document.createElement('button');
|
|
25
|
+
const labelRemoveButton = '<%= getText("label.remove-firstname", "name") %>';
|
|
26
|
+
removeButton.classList.add('fr-btn', 'fr-btn--secondary', 'fr-icon-delete-line');
|
|
27
|
+
removeButton.innerHTML = labelRemoveButton;
|
|
28
|
+
removeButton.title = labelRemoveButton;
|
|
29
|
+
|
|
30
|
+
removeButton.setAttribute('onclick', 'removeFirstname(this.copy)');
|
|
31
|
+
removeButton.copy = copy;
|
|
32
|
+
|
|
33
|
+
wrapper.appendChild(copy.getElementsByTagName('input')[0]);
|
|
34
|
+
wrapper.appendChild(removeButton);
|
|
35
|
+
copy.getElementsByTagName('label')[0].after(wrapper);
|
|
36
|
+
reference.parentNode.insertBefore(copy, reference);
|
|
37
|
+
document.getElementById(`${id}-added-${button.firstnamesCount}`).focus();
|
|
38
|
+
};
|
package/src/template/template.js
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { Renderable } from '../core/renderable.js';
|
|
2
2
|
import { nodeFactory } from '../node/node-factory.js';
|
|
3
3
|
|
|
4
|
+
const PERMALINK_CONTENT_REGEX = /<!--\s*NO_PERMALINK_START\s*-->\s(?<content>[\s\S]*)\s<!--\s*NO_PERMALINK_END\s*-->/g;
|
|
5
|
+
const PREVENT_PERMALINKS_REGEX = /(?<permalinks><!--\s*NO_PERMALINK_START\s*-->\s(?:[\s\S]*)\s<!--\s*NO_PERMALINK_END\s*-->)/g;
|
|
6
|
+
const HEADING_REGEX = /<h(?<level>[2-6])(?<attrs>[^>]*)>(?<content>.*?)<\/h\1>/g;
|
|
7
|
+
const ATTRIBUTE_ID_REGEX = /\sid=["'](?<id>[^"']+)["']/;
|
|
8
|
+
const PERMALINK_CLASS = 'dsfr-doc-anchor-heading';
|
|
9
|
+
|
|
10
|
+
const injectPermaLink = (match, level, attrs, content) => {
|
|
11
|
+
const idMatch = attrs.match(ATTRIBUTE_ID_REGEX);
|
|
12
|
+
if (!idMatch || !idMatch.groups?.id) return match;
|
|
13
|
+
const link = `<a href="#${idMatch.groups.id}" class="${PERMALINK_CLASS}">${content}</a>`;
|
|
14
|
+
return `<h${level}${attrs}>${link}</h${level}>`;
|
|
15
|
+
};
|
|
16
|
+
|
|
4
17
|
class Template extends Renderable {
|
|
5
|
-
constructor (data) {
|
|
18
|
+
constructor (data, hasPermaLinks = false) {
|
|
6
19
|
super(data);
|
|
7
20
|
nodeFactory.populate(data.fragments);
|
|
21
|
+
this._hasPermaLinks = hasPermaLinks;
|
|
8
22
|
this._content = nodeFactory.create({
|
|
9
23
|
type: 'root',
|
|
10
24
|
children: data.nodes
|
|
@@ -20,7 +34,19 @@ class Template extends Renderable {
|
|
|
20
34
|
}
|
|
21
35
|
|
|
22
36
|
async render () {
|
|
23
|
-
|
|
37
|
+
const html = await this._content.render();
|
|
38
|
+
if (!this._hasPermaLinks) return html;
|
|
39
|
+
return this.addPermaLinks(html);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
addPermaLinks (html) {
|
|
43
|
+
return html.split(PREVENT_PERMALINKS_REGEX).map((part) => {
|
|
44
|
+
const match = PERMALINK_CONTENT_REGEX.exec(part);
|
|
45
|
+
if (match && match.groups && match.groups.content) {
|
|
46
|
+
return match.groups.content;
|
|
47
|
+
}
|
|
48
|
+
return part.replace(HEADING_REGEX, injectPermaLink);
|
|
49
|
+
}).join('');
|
|
24
50
|
}
|
|
25
51
|
|
|
26
52
|
get text () {
|
|
@@ -3,10 +3,11 @@ import { Sidemenu } from '../../component/components/sidemenu.js';
|
|
|
3
3
|
import { Breadcrumb } from '../../component/components/breadcrumb.js';
|
|
4
4
|
import { TOC } from '../../page/body/toc.js';
|
|
5
5
|
import { Edit } from '../../page/body/edit.js';
|
|
6
|
+
import { Mesh } from '../../page/body/mesh.js';
|
|
6
7
|
|
|
7
8
|
class EditorialTemplate extends Template {
|
|
8
9
|
constructor (data) {
|
|
9
|
-
super(data);
|
|
10
|
+
super(data, true);
|
|
10
11
|
|
|
11
12
|
this._hasSidemenu = data?.resource?.navigation?.sidemenu !== undefined;
|
|
12
13
|
if (this._hasSidemenu) this._sidemenu = new Sidemenu(data.resource.navigation.sidemenu, data.resource.badge);
|
|
@@ -18,11 +19,18 @@ class EditorialTemplate extends Template {
|
|
|
18
19
|
|
|
19
20
|
structure (data) {
|
|
20
21
|
this._hasEditUrl = data?.editUrl != null;
|
|
22
|
+
this._hasMesh = data?.mesh?.items?.length;
|
|
23
|
+
|
|
21
24
|
if (this._hasEditUrl) {
|
|
22
25
|
const edit = new Edit({...data.resource.edit, editUrl: data.editUrl, blankLabel: data.fragments.blank});
|
|
23
26
|
data.nodes.push(edit.node);
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
if (this._hasMesh) {
|
|
30
|
+
const mesh = new Mesh({...data.resource.mesh, ...data.mesh});
|
|
31
|
+
data.nodes.push(mesh.node);
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
return super.structure(data);
|
|
27
35
|
}
|
|
28
36
|
|