[IMP] about panel: publisher and author, displayed version only
The About panel now names the publisher, TechnoLibre Inc., and the author, Mathieu Benoit, developer, designer and maintainer of the software, above the copyable block. The block carries the displayed version alone: the Windows form (2026.1005.1.0) was a second number for the same release that no changelog names, and the Windows guide points to the executable's file name instead. Copy still takes the block only, never the credits. Checked: node 5174, browser 1161, node-long 129; no capture changes. --- FR --- [IMP] panneau À propos : éditeur et auteur, version affichée seule Le panneau « À propos » nomme l'éditeur, TechnoLibre Inc., et l'auteur, Mathieu Benoit, développeur, concepteur et mainteneur du logiciel, au-dessus du bloc à copier. Le bloc ne porte plus que la version affichée : la forme Windows (2026.1005.1.0) était un second numéro de la même version qu'aucun changelog ne nomme, et le guide Windows renvoie au nom de l'exécutable. « Copier » n'emporte toujours que le bloc, jamais l'éditeur ni l'auteur. Vérifié : node 5174, navigateur 1161, node-long 129 ; aucune capture. Assisted-by: Claude Opus 5.5
This commit is contained in:
parent
86686aebf0
commit
6cd687beb5
13 changed files with 121 additions and 83 deletions
|
|
@ -193,6 +193,9 @@
|
||||||
- Dans un fichier d'objectifs, une ligne sans objectif ni règle est une ligne à
|
- Dans un fichier d'objectifs, une ligne sans objectif ni règle est une ligne à
|
||||||
remplir : l'import la passe sans la refuser, et l'objectif de sa table reste
|
remplir : l'import la passe sans la refuser, et l'objectif de sa table reste
|
||||||
en mise à jour.
|
en mise à jour.
|
||||||
|
- Le panneau « À propos » nomme l'éditeur, TechnoLibre Inc., et l'auteur,
|
||||||
|
Mathieu Benoit, développeur, concepteur et mainteneur du logiciel. Son bloc à
|
||||||
|
copier ne porte plus que la version affichée, sans sa forme Windows.
|
||||||
|
|
||||||
**Version de format des fichiers** : 2. Les étiquettes, les objectifs, leurs
|
**Version de format des fichiers** : 2. Les étiquettes, les objectifs, leurs
|
||||||
règles, les cases nouvelles, le mode des objectifs et l'ordre des priorités
|
règles, les cases nouvelles, le mode des objectifs et l'ordre des priorités
|
||||||
|
|
|
||||||
|
|
@ -156,14 +156,14 @@ La version se lit sans rien chercher :
|
||||||
- dans le **bandeau** en haut de chaque écran, et sur la liste des événements ;
|
- dans le **bandeau** en haut de chaque écran, et sur la liste des événements ;
|
||||||
- dans le **titre de la fenêtre**, après le nom du logiciel ;
|
- dans le **titre de la fenêtre**, après le nom du logiciel ;
|
||||||
- au **pied de chaque page imprimée** ; un badge découpé n’en porte pas ;
|
- au **pied de chaque page imprimée** ; un badge découpé n’en porte pas ;
|
||||||
- dans le panneau « À propos », ouvert depuis le bandeau. Il montre un bloc
|
- dans le panneau « À propos », ouvert depuis le bandeau. Sous l’éditeur,
|
||||||
d’une ligne — la version, la version Windows, la plateforme, la provenance de
|
TechnoLibre Inc., et l’auteur du logiciel, il montre un bloc d’une ligne — la
|
||||||
la construction et la version de format des fichiers — que la commande
|
version, la plateforme, la provenance de la construction et la version de
|
||||||
« Copier » met dans le presse-papiers.
|
format des fichiers — que la commande « Copier » met dans le presse-papiers.
|
||||||
|
|
||||||
Les propriétés du fichier, dans l’Explorateur, montrent la **version
|
Les propriétés du fichier, dans l’Explorateur, écrivent le même numéro
|
||||||
Windows**, une autre écriture du même numéro : le bloc d’« À propos » porte les
|
autrement, `2026.1005.1.0` pour `2026.10.05.01` : citez celui du bandeau ou
|
||||||
deux, ce qui permet de faire le lien.
|
d’« À propos », qui figure aussi dans le nom de l’exécutable.
|
||||||
|
|
||||||
## Signaler un problème
|
## Signaler un problème
|
||||||
|
|
||||||
|
|
|
||||||
16
spec.md
16
spec.md
|
|
@ -6643,7 +6643,7 @@ question. Le logiciel fait donc en sorte qu'on n'ait pas à la chercher.
|
||||||
| **bandeau d'application**, sur tout écran (§ 8.4) | `2026.10.05.01`, avec la provenance et — quand un plan est ouvert — le libellé de mode |
|
| **bandeau d'application**, sur tout écran (§ 8.4) | `2026.10.05.01`, avec la provenance et — quand un plan est ouvert — le libellé de mode |
|
||||||
| **premier écran** (§ 8.1), liste des événements comme répertoire vide | `version 2026.10.05.01`, ou la marque de provenance d'une construction de documentation |
|
| **premier écran** (§ 8.1), liste des événements comme répertoire vide | `version 2026.10.05.01`, ou la marque de provenance d'une construction de documentation |
|
||||||
| **titre de la fenêtre** | `Gestion table tournante Libre — 2026.10.05.01` |
|
| **titre de la fenêtre** | `Gestion table tournante Libre — 2026.10.05.01` |
|
||||||
| **panneau « À propos »** | un bloc d'une ligne que l'opérateur **copie** |
|
| **panneau « À propos »** | un bloc d'une ligne que l'opérateur **copie**, sous l'éditeur et l'auteur |
|
||||||
| **pied de chaque page imprimée** (§ 11.7) | la version, à côté de l'horodatage du placement |
|
| **pied de chaque page imprimée** (§ 11.7) | la version, à côté de l'horodatage du placement |
|
||||||
| **en-tête du fichier d'état** (§ 8.8) | champ `produit_version` |
|
| **en-tête du fichier d'état** (§ 8.8) | champ `produit_version` |
|
||||||
|
|
||||||
|
|
@ -6665,12 +6665,14 @@ moment où l'opérateur peut encore se ménager un retour en arrière, c'est-à-
|
||||||
avant le premier geste.
|
avant le premier geste.
|
||||||
|
|
||||||
**Le bloc copiable** du panneau « À propos » tient en une ligne — version affichée,
|
**Le bloc copiable** du panneau « À propos » tient en une ligne — version affichée,
|
||||||
version Windows, plateforme, provenance de la construction, version de format
|
plateforme, provenance de la construction, version de format des fichiers — et se
|
||||||
des fichiers — et se colle dans un courriel. Un chiffre recopié à la main se
|
colle dans un courriel. Un chiffre recopié à la main se recopie faux. Il ne porte
|
||||||
recopie faux. Il porte les **deux** formes parce qu'un opérateur qui lit la fiche
|
que la version affichée, `2026.10.05.01`, celle du changelog et du nom du
|
||||||
de propriétés du fichier sous Windows y trouve `2026.1005.1.0` et non
|
livrable : la forme Windows, `2026.1005.1.0`, reste dans la fiche de propriétés du
|
||||||
`2026.10.05.01` ; sans la correspondance écrite quelque part, il cite un numéro qui
|
fichier, et le guide Windows renvoie au nom de l'exécutable pour la version.
|
||||||
ne figure dans aucun changelog.
|
Au-dessus du bloc, le panneau nomme l'éditeur, **TechnoLibre Inc.**, et l'auteur,
|
||||||
|
**Mathieu Benoit**, développeur, concepteur et mainteneur du logiciel ; « Copier »
|
||||||
|
ne les emporte pas.
|
||||||
|
|
||||||
**Le pied des impressions** porte la version parce qu'une feuille circule et survit
|
**Le pied des impressions** porte la version parce qu'une feuille circule et survit
|
||||||
à la séance. La règle vaut pour la **page** ; un carton découpé et porté au cou
|
à la séance. La règle vaut pour la **page** ; un carton découpé et porté au cou
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,15 @@
|
||||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) -->
|
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) -->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Le panneau « À propos » (§ 18.6) : le bloc d'une ligne que l'opérateur
|
// Le panneau « À propos » (§ 18.6) : l'éditeur et l'auteur du logiciel,
|
||||||
// copie dans un courriel, tel que blocAPropos l'a composé, et sa copie dans
|
// puis le bloc d'une ligne que l'opérateur copie dans un courriel, tel que
|
||||||
// le presse-papiers de la plateforme. « Copier » remet exactement le texte
|
// blocAPropos l'a composé, et sa copie dans le presse-papiers de la
|
||||||
// affiché ; l'issue de la copie se lit sous les commandes.
|
// plateforme. « Copier » remet exactement le texte du bloc, sans l'éditeur
|
||||||
|
// ni l'auteur ; l'issue de la copie se lit sous les commandes.
|
||||||
//
|
//
|
||||||
// Habillage : le titre de l'écran, puis une carte qui porte le bloc, sur
|
// Habillage : le titre de l'écran, puis une carte qui porte l'éditeur,
|
||||||
// le fond sourd de la carte, et les commandes — « Copier », l'action
|
// l'auteur en gras et son rôle dans l'encre secondaire, le bloc, sur le
|
||||||
|
// fond sourd de la carte, et les commandes — « Copier », l'action
|
||||||
// principale, et « Fermer ». Une copie refusée se dit dans l'encre du
|
// principale, et « Fermer ». Une copie refusée se dit dans l'encre du
|
||||||
// refus.
|
// refus.
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
|
|
@ -36,6 +38,11 @@
|
||||||
<h1>{t('coquille.apropos.titre')}</h1>
|
<h1>{t('coquille.apropos.titre')}</h1>
|
||||||
<Carte>
|
<Carte>
|
||||||
<div class="contenu">
|
<div class="contenu">
|
||||||
|
<div class="credits" data-credits>
|
||||||
|
<p data-editeur>{t('coquille.apropos.editeur')}</p>
|
||||||
|
<p class="auteur" data-auteur>{t('coquille.apropos.auteur')}</p>
|
||||||
|
<p class="role" data-role>{t('coquille.apropos.role')}</p>
|
||||||
|
</div>
|
||||||
<p class="bloc" data-bloc>{bloc}</p>
|
<p class="bloc" data-bloc>{bloc}</p>
|
||||||
<div class="commandes">
|
<div class="commandes">
|
||||||
<Commande cle="coquille.apropos.copier" nom="copier" variante="principale" executer={copier} />
|
<Commande cle="coquille.apropos.copier" nom="copier" variante="principale" executer={copier} />
|
||||||
|
|
@ -73,6 +80,20 @@
|
||||||
|
|
||||||
/* Le bloc se sélectionne d'un clic, entier, et se coupe où il faut
|
/* Le bloc se sélectionne d'un clic, entier, et se coupe où il faut
|
||||||
plutôt que de déborder. */
|
plutôt que de déborder. */
|
||||||
|
.credits {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--espace-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auteur {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role {
|
||||||
|
color: var(--couleur-page-texte-secondaire);
|
||||||
|
}
|
||||||
|
|
||||||
.bloc {
|
.bloc {
|
||||||
padding: var(--espace-3) var(--espace-4);
|
padding: var(--espace-3) var(--espace-4);
|
||||||
border: 1px solid var(--couleur-carte-filet);
|
border: 1px solid var(--couleur-carte-filet);
|
||||||
|
|
|
||||||
|
|
@ -544,7 +544,7 @@ describe('« À propos » (§ 18.6)', () => {
|
||||||
|
|
||||||
test('le panneau s’ouvre depuis le bandeau sur la liste puis sur un événement ; « Copier » remet exactement le bloc affiché', async () => {
|
test('le panneau s’ouvre depuis le bandeau sur la liste puis sur un événement ; « Copier » remet exactement le bloc affiché', async () => {
|
||||||
const m = await monter({ fichiers: [fichier('bal', 'Bal des Grisailles')] });
|
const m = await monter({ fichiers: [fichier('bal', 'Bal des Grisailles')] });
|
||||||
const attendu = blocAPropos({ version: VERSION, plateforme: m.fs.nature, provenance: 'test', format: FORMAT }, t);
|
const attendu = blocAPropos({ version: VERSION.affichee, plateforme: m.fs.nature, provenance: 'test', format: FORMAT }, t);
|
||||||
dans(m, '[data-commande="apropos"]').click();
|
dans(m, '[data-commande="apropos"]').click();
|
||||||
flushSync();
|
flushSync();
|
||||||
expect(visible(panneau(m))).toBe(true);
|
expect(visible(panneau(m))).toBe(true);
|
||||||
|
|
@ -564,6 +564,22 @@ describe('« À propos » (§ 18.6)', () => {
|
||||||
expect(visible(panneau(m))).toBe(true);
|
expect(visible(panneau(m))).toBe(true);
|
||||||
expect(dans(m, '[data-bloc]').textContent).toBe(attendu);
|
expect(dans(m, '[data-bloc]').textContent).toBe(attendu);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('l’éditeur, l’auteur et son rôle s’y lisent, au-dessus du bloc ; « Copier » ne les emporte pas, ni la forme Windows', async () => {
|
||||||
|
const m = await monter();
|
||||||
|
dans(m, '[data-commande="apropos"]').click();
|
||||||
|
flushSync();
|
||||||
|
const credits = dans(m, '[data-credits]');
|
||||||
|
expect(visible(credits)).toBe(true);
|
||||||
|
expect(dans(m, '[data-editeur]').textContent.trim()).toBe('TechnoLibre Inc.');
|
||||||
|
expect(dans(m, '[data-auteur]').textContent.trim()).toBe('Mathieu Benoit');
|
||||||
|
expect(dans(m, '[data-role]').textContent.trim()).toBe('Développeur, concepteur et mainteneur du logiciel');
|
||||||
|
expect(credits.compareDocumentPosition(dans(m, '[data-bloc]')) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
||||||
|
expect(panneau(m).textContent.includes(VERSION.windows)).toBe(false);
|
||||||
|
dans(m, '[data-commande="copier"]').click();
|
||||||
|
await vi.waitFor(() => expect(m.presse.copies).toEqual([dans(m, '[data-bloc]').textContent]));
|
||||||
|
expect(m.presse.copies[0]).not.toContain('TechnoLibre Inc.');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('thème (§ 19.2)', () => {
|
describe('thème (§ 19.2)', () => {
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,6 @@
|
||||||
demonstrations,
|
demonstrations,
|
||||||
formatCourant,
|
formatCourant,
|
||||||
produitVersion,
|
produitVersion,
|
||||||
versionWindows,
|
|
||||||
// () => Promise<{regulier: Uint8Array, gras: Uint8Array}> : les octets
|
// () => Promise<{regulier: Uint8Array, gras: Uint8Array}> : les octets
|
||||||
// de la police que la production de la planche embarque (§ 11.1).
|
// de la police que la production de la planche embarque (§ 11.1).
|
||||||
polices,
|
polices,
|
||||||
|
|
@ -110,12 +109,9 @@
|
||||||
const { t } = creerTraduction([...TABLES_APPLICATION, ...TABLES_INTERFACE], { langue });
|
const { t } = creerTraduction([...TABLES_APPLICATION, ...TABLES_INTERFACE], { langue });
|
||||||
const format = creerFormat(t);
|
const format = creerFormat(t);
|
||||||
// Le bloc « À propos » se compose au montage, avant toute séance : une
|
// Le bloc « À propos » se compose au montage, avant toute séance : une
|
||||||
// forme de la version que les dépendances ne portent pas lève RangeError
|
// version que les dépendances ne portent pas lève RangeError ici, et App
|
||||||
// ici, et App ne se monte pas avec un bloc copiable faux (§ 18.6).
|
// ne se monte pas avec un bloc copiable faux (§ 18.6).
|
||||||
const bloc = blocAPropos(
|
const bloc = blocAPropos({ version: produitVersion, plateforme: fs.nature, provenance, format: formatCourant }, t);
|
||||||
{ version: { affichee: produitVersion, windows: versionWindows }, plateforme: fs.nature, provenance, format: formatCourant },
|
|
||||||
t,
|
|
||||||
);
|
|
||||||
const seanceApp = creerSeance({
|
const seanceApp = creerSeance({
|
||||||
fs,
|
fs,
|
||||||
horloge,
|
horloge,
|
||||||
|
|
|
||||||
|
|
@ -2,43 +2,38 @@
|
||||||
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||||
|
|
||||||
// Le panneau « À propos » et la version à l'écran (§ 18.6). Le bloc tient en
|
// Le panneau « À propos » et la version à l'écran (§ 18.6). Le bloc tient en
|
||||||
// une ligne, que l'opérateur copie dans un courriel : il porte les deux
|
// une ligne, que l'opérateur copie dans un courriel : il porte la version
|
||||||
// formes de la version, l'affichée et celle que montrent les propriétés du
|
// affichée, celle que nomment le changelog et le nom du livrable. Sa
|
||||||
// fichier sous Windows, que scripts/version.js engendre. Sa composition est
|
// composition est une seule clé de la table de la coquille : la langue
|
||||||
// une seule clé de la table de la coquille : la langue témoin l'encadre une
|
// témoin l'encadre une fois, en entier. La version et la provenance à l'écran se définissent
|
||||||
// fois, en entier. La version et la provenance à l'écran se définissent
|
|
||||||
// dans l'application (version.js), que le papier lit aussi : ce module les
|
// dans l'application (version.js), que le papier lit aussi : ce module les
|
||||||
// réexporte.
|
// réexporte.
|
||||||
export { provenanceVisible, versionVisible } from '../application/version.js';
|
export { provenanceVisible, versionVisible } from '../application/version.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bloc d'une ligne du panneau « À propos » (§ 18.6) : nom, version affichée,
|
* Bloc d'une ligne du panneau « À propos » (§ 18.6) : nom, version affichée,
|
||||||
* version Windows, plateforme, provenance, version de format, séparés par
|
* plateforme, provenance, version de format, séparés par « · ». La
|
||||||
* « · ». La provenance s'y lit sous son libellé, ou sous son propre nom
|
* provenance s'y lit sous son libellé, ou sous son propre nom quand le mode
|
||||||
* quand le mode n'en a pas ; la plateforme sous sa nature.
|
* n'en a pas ; la plateforme sous sa nature.
|
||||||
*
|
*
|
||||||
* @param {Object} champs
|
* @param {Object} champs
|
||||||
* @param {{affichee: string, windows: string}} champs.version les deux formes
|
* @param {string} champs.version la version affichée, celle que reçoit App
|
||||||
* de la version, celles que reçoit App (produitVersion, versionWindows)
|
* (produitVersion)
|
||||||
* @param {string} champs.plateforme la nature du système de fichiers
|
* @param {string} champs.plateforme la nature du système de fichiers
|
||||||
* @param {string} champs.provenance le mode de construction de Vite
|
* @param {string} champs.provenance le mode de construction de Vite
|
||||||
* @param {number} champs.format la version de format des fichiers
|
* @param {number} champs.format la version de format des fichiers
|
||||||
* @param {(cle: string, details?: Object) => string} t
|
* @param {(cle: string, details?: Object) => string} t
|
||||||
* @returns {string} sans saut de ligne
|
* @returns {string} sans saut de ligne
|
||||||
* @throws {RangeError} une forme de la version absente, vide ou qui n'est
|
* @throws {RangeError} une version absente, vide ou qui n'est pas une
|
||||||
* pas une chaîne, en la nommant : une dépendance d'App oubliée
|
* chaîne : une dépendance d'App oubliée échoue au montage, plutôt
|
||||||
* échoue au montage, plutôt que de donner un bloc copiable faux
|
* que de donner un bloc copiable faux
|
||||||
*/
|
*/
|
||||||
export function blocAPropos({ version, plateforme, provenance, format }, t) {
|
export function blocAPropos({ version, plateforme, provenance, format }, t) {
|
||||||
for (const forme of ['affichee', 'windows']) {
|
if (typeof version !== 'string' || version === '') {
|
||||||
const valeur = version[forme];
|
throw new RangeError(`À propos : la version manque (${JSON.stringify(version) ?? 'undefined'})`);
|
||||||
if (typeof valeur !== 'string' || valeur === '') {
|
|
||||||
throw new RangeError(`À propos : la version ${forme} manque (${JSON.stringify(valeur) ?? 'undefined'})`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return t('coquille.apropos.bloc', {
|
return t('coquille.apropos.bloc', {
|
||||||
affichee: version.affichee,
|
version,
|
||||||
windows: version.windows,
|
|
||||||
plateforme,
|
plateforme,
|
||||||
provenance,
|
provenance,
|
||||||
format,
|
format,
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||||
|
|
||||||
// Le bloc « À propos » (§ 18.6) : une ligne que l'opérateur copie dans un
|
// Le bloc « À propos » (§ 18.6) : une ligne que l'opérateur copie dans un
|
||||||
// courriel — nom, version affichée, version Windows, plateforme, provenance,
|
// courriel — nom, version affichée, plateforme, provenance, version de
|
||||||
// version de format. Ce qui tient lieu de version à l'écran, et la
|
// format. Ce qui tient lieu de version à l'écran, et la
|
||||||
// provenance, s'éprouvent avec leur définition (src/application/version.js),
|
// provenance, s'éprouvent avec leur définition (src/application/version.js),
|
||||||
// que ce module réexporte.
|
// que ce module réexporte.
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
|
|
@ -20,15 +20,15 @@ const { t } = creerTraduction([...TABLES_APPLICATION, ...TABLES_INTERFACE]);
|
||||||
const temoin = creerTraduction([...TABLES_APPLICATION, ...TABLES_INTERFACE], { langue: 'temoin' }).t;
|
const temoin = creerTraduction([...TABLES_APPLICATION, ...TABLES_INTERFACE], { langue: 'temoin' }).t;
|
||||||
|
|
||||||
describe('blocAPropos (§ 18.6)', () => {
|
describe('blocAPropos (§ 18.6)', () => {
|
||||||
test('une ligne : nom, version affichée, version Windows, plateforme, provenance, format, séparés par « · »', () => {
|
test('une ligne : nom, version affichée, plateforme, provenance, format, séparés par « · » ; la forme Windows n’y est pas', () => {
|
||||||
assert.match(VERSION.windows ?? '', /^\d+\.\d+\.\d+\.0$/, 'VERSION.windows engendré');
|
const bloc = blocAPropos({ version: VERSION.affichee, plateforme: 'electron', provenance: 'livraison', format: FORMAT }, t);
|
||||||
const bloc = blocAPropos({ version: VERSION, plateforme: 'electron', provenance: 'livraison', format: FORMAT }, t);
|
|
||||||
assert.equal(typeof bloc, 'string');
|
assert.equal(typeof bloc, 'string');
|
||||||
assert.doesNotMatch(bloc, /[\n\r\u{2028}\u{2029}]/u);
|
assert.doesNotMatch(bloc, /[\n\r\u{2028}\u{2029}]/u);
|
||||||
|
assert.match(VERSION.affichee, /^\d{4}\.\d{2}\.\d{2}\.\d{2}$/);
|
||||||
|
assert.equal(bloc.includes(VERSION.windows), false, bloc);
|
||||||
assert.deepEqual(bloc.split(' \u{00B7} '), [
|
assert.deepEqual(bloc.split(' \u{00B7} '), [
|
||||||
t('coquille.nom'),
|
t('coquille.nom'),
|
||||||
VERSION.affichee,
|
VERSION.affichee,
|
||||||
VERSION.windows,
|
|
||||||
'electron',
|
'electron',
|
||||||
libelleProvenance('livraison'),
|
libelleProvenance('livraison'),
|
||||||
t('coquille.apropos.format', { format: FORMAT }),
|
t('coquille.apropos.format', { format: FORMAT }),
|
||||||
|
|
@ -45,31 +45,32 @@ describe('blocAPropos (§ 18.6)', () => {
|
||||||
];
|
];
|
||||||
assert.ok(cas.length > 0);
|
assert.ok(cas.length > 0);
|
||||||
for (const [plateforme, provenance, libelle] of cas) {
|
for (const [plateforme, provenance, libelle] of cas) {
|
||||||
const champs = blocAPropos({ version: VERSION, plateforme, provenance, format: FORMAT }, t).split(' \u{00B7} ');
|
const champs = blocAPropos({ version: VERSION.affichee, plateforme, provenance, format: FORMAT }, t).split(' \u{00B7} ');
|
||||||
assert.equal(champs[3], plateforme, provenance);
|
assert.equal(champs[2], plateforme, provenance);
|
||||||
assert.equal(champs[4], libelle, provenance);
|
assert.equal(champs[3], libelle, provenance);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('une forme de la version absente, vide ou qui n’est pas une chaîne lève RangeError en la nommant : jamais un bloc copiable faux', () => {
|
test('une version absente, vide ou qui n’est pas une chaîne lève RangeError : jamais un bloc copiable faux', () => {
|
||||||
const fautes = [undefined, null, '', 7];
|
const fautes = [undefined, null, '', 7, VERSION];
|
||||||
assert.equal(fautes.length, 4);
|
assert.equal(fautes.length, 5);
|
||||||
for (const faute of fautes) {
|
for (const faute of fautes) {
|
||||||
for (const [forme, version] of [
|
|
||||||
['windows', { affichee: VERSION.affichee, windows: faute }],
|
|
||||||
['affichee', { affichee: faute, windows: VERSION.windows }],
|
|
||||||
]) {
|
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => blocAPropos({ version, plateforme: 'web', provenance: 'test', format: FORMAT }, t),
|
() => blocAPropos({ version: faute, plateforme: 'web', provenance: 'test', format: FORMAT }, t),
|
||||||
(erreur) => erreur instanceof RangeError && erreur.message.includes(forme),
|
(erreur) => erreur instanceof RangeError && erreur.message.includes('version'),
|
||||||
`${forme} ${String(faute)}`,
|
String(faute),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
test('l’éditeur, l’auteur et son rôle ont chacun leur libellé', () => {
|
||||||
|
assert.equal(t('coquille.apropos.editeur'), 'TechnoLibre Inc.');
|
||||||
|
assert.equal(t('coquille.apropos.auteur'), 'Mathieu Benoit');
|
||||||
|
assert.equal(t('coquille.apropos.role'), 'Développeur, concepteur et mainteneur du logiciel');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('en langue témoin, le bloc entier est encadré une fois', () => {
|
test('en langue témoin, le bloc entier est encadré une fois', () => {
|
||||||
const bloc = blocAPropos({ version: VERSION, plateforme: 'web', provenance: 'test', format: FORMAT }, temoin);
|
const bloc = blocAPropos({ version: VERSION.affichee, plateforme: 'web', provenance: 'test', format: FORMAT }, temoin);
|
||||||
const { ouverture, fermeture } = MARQUE_TEMOIN;
|
const { ouverture, fermeture } = MARQUE_TEMOIN;
|
||||||
assert.ok(bloc.startsWith(ouverture) && bloc.endsWith(fermeture), bloc);
|
assert.ok(bloc.startsWith(ouverture) && bloc.endsWith(fermeture), bloc);
|
||||||
assert.equal(bloc.split(ouverture).length, 2, bloc);
|
assert.equal(bloc.split(ouverture).length, 2, bloc);
|
||||||
|
|
@ -78,7 +79,7 @@ describe('blocAPropos (§ 18.6)', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('la version de l’interface vient des dépendances (§ 13.4, § 18.6)', () => {
|
describe('la version de l’interface vient des dépendances (§ 13.4, § 18.6)', () => {
|
||||||
test('App.svelte ne lit pas la version engendrée : la version affichée et la forme Windows arrivent par ses propriétés, produitVersion et versionWindows', () => {
|
test('App.svelte ne lit pas la version engendrée : la version affichée arrive par sa propriété produitVersion, et la forme Windows n’y entre pas', () => {
|
||||||
const source = readFileSync(new URL('./App.svelte', import.meta.url), 'utf8');
|
const source = readFileSync(new URL('./App.svelte', import.meta.url), 'utf8');
|
||||||
const imports = [...source.matchAll(/^\s*import\s[^;]*?from\s+'([^']+)'/gmu)].map(([, chemin]) => chemin);
|
const imports = [...source.matchAll(/^\s*import\s[^;]*?from\s+'([^']+)'/gmu)].map(([, chemin]) => chemin);
|
||||||
assert.ok(imports.length > 0, 'des imports relevés');
|
assert.ok(imports.length > 0, 'des imports relevés');
|
||||||
|
|
@ -86,7 +87,7 @@ describe('la version de l’interface vient des dépendances (§ 13.4, § 18.6)'
|
||||||
imports.filter((chemin) => chemin.includes('version.genere')),
|
imports.filter((chemin) => chemin.includes('version.genere')),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
assert.match(source, /\bversionWindows\b/u);
|
assert.doesNotMatch(source, /\bversionWindows\b/u);
|
||||||
assert.match(source, /blocAPropos\(\s*\{\s*version:\s*\{\s*affichee:\s*produitVersion,\s*windows:\s*versionWindows\s*\}/u);
|
assert.match(source, /blocAPropos\(\s*\{\s*version:\s*produitVersion,/u);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -37,18 +37,17 @@ export const TABLE = new Map([
|
||||||
|
|
||||||
['coquille.liste', 'Liste des événements'],
|
['coquille.liste', 'Liste des événements'],
|
||||||
|
|
||||||
// Le panneau « À propos ». Le bloc : nom, version affichée, version
|
// Le panneau « À propos ». Le bloc : nom, version affichée, plateforme,
|
||||||
// Windows, plateforme, provenance — son libellé, ou le mode lui-même quand
|
// provenance — son libellé, ou le mode lui-même quand il n'en a pas —,
|
||||||
// il n'en a pas —, version de format.
|
// version de format. Sous lui, l'éditeur et l'auteur du logiciel.
|
||||||
['coquille.apropos.titre', 'À propos'],
|
['coquille.apropos.titre', 'À propos'],
|
||||||
[
|
[
|
||||||
'coquille.apropos.bloc',
|
'coquille.apropos.bloc',
|
||||||
({ affichee, windows, plateforme, provenance, format }, texte) => {
|
({ version, plateforme, provenance, format }, texte) => {
|
||||||
const cle = `coquille.provenance.${provenance}`;
|
const cle = `coquille.provenance.${provenance}`;
|
||||||
return [
|
return [
|
||||||
texte('coquille.nom'),
|
texte('coquille.nom'),
|
||||||
affichee,
|
version,
|
||||||
windows,
|
|
||||||
plateforme,
|
plateforme,
|
||||||
texte.existe(cle) ? texte(cle) : provenance,
|
texte.existe(cle) ? texte(cle) : provenance,
|
||||||
texte('coquille.apropos.format', { format }),
|
texte('coquille.apropos.format', { format }),
|
||||||
|
|
@ -56,6 +55,9 @@ export const TABLE = new Map([
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
['coquille.apropos.format', ({ format }) => `format ${format}`],
|
['coquille.apropos.format', ({ format }) => `format ${format}`],
|
||||||
|
['coquille.apropos.editeur', 'TechnoLibre Inc.'],
|
||||||
|
['coquille.apropos.auteur', 'Mathieu Benoit'],
|
||||||
|
['coquille.apropos.role', 'Développeur, concepteur et mainteneur du logiciel'],
|
||||||
['coquille.apropos.copier', 'Copier'],
|
['coquille.apropos.copier', 'Copier'],
|
||||||
['coquille.apropos.fermer', 'Fermer'],
|
['coquille.apropos.fermer', 'Fermer'],
|
||||||
['coquille.apropos.copie', 'Bloc copié dans le presse-papiers'],
|
['coquille.apropos.copie', 'Bloc copié dans le presse-papiers'],
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ const LETTRE = /\p{L}/u;
|
||||||
* racines: string[] }, valeurs de la plus longue à la plus courte.
|
* racines: string[] }, valeurs de la plus longue à la plus courte.
|
||||||
*/
|
*/
|
||||||
async function donneesConnues(contexte, { cellules = [] } = {}) {
|
async function donneesConnues(contexte, { cellules = [] } = {}) {
|
||||||
const valeurs = new Set([VERSION.affichee, VERSION.windows, PROVENANCE, ...CATALOGUE.map(({ nom }) => nom), ...cellules]);
|
const valeurs = new Set([VERSION.affichee, PROVENANCE, ...CATALOGUE.map(({ nom }) => nom), ...cellules]);
|
||||||
const racines = new Set();
|
const racines = new Set();
|
||||||
const personne = (p) => {
|
const personne = (p) => {
|
||||||
for (const v of [p.nom, p.prenom, p.appartenance, p.courriel, p.titrePressenti, p.notes, ...(p.etiquettes ?? [])]) if (v) valeurs.add(v);
|
for (const v of [p.nom, p.prenom, p.appartenance, p.courriel, p.titrePressenti, p.notes, ...(p.etiquettes ?? [])]) if (v) valeurs.add(v);
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,6 @@ mount(App, {
|
||||||
demonstrations: demonstrationsLivrees(),
|
demonstrations: demonstrationsLivrees(),
|
||||||
formatCourant: FORMAT,
|
formatCourant: FORMAT,
|
||||||
produitVersion: VERSION.affichee,
|
produitVersion: VERSION.affichee,
|
||||||
versionWindows: VERSION.windows,
|
|
||||||
polices: chargerPolices,
|
polices: chargerPolices,
|
||||||
imprimante,
|
imprimante,
|
||||||
sectionQualite: chargerSectionQualite,
|
sectionQualite: chargerSectionQualite,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ const ENTREES = [
|
||||||
['data-annonces', 'événement : la zone des annonces à côté de la tête', ['']],
|
['data-annonces', 'événement : la zone des annonces à côté de la tête', ['']],
|
||||||
['data-apercu', 'import : l’aperçu d’un fichier ou d’un collage', ['']],
|
['data-apercu', 'import : l’aperçu d’un fichier ou d’un collage', ['']],
|
||||||
['data-attente-demonstration', 'accueil : le message d’une démonstration cliquée pendant un chargement', ['']],
|
['data-attente-demonstration', 'accueil : le message d’une démonstration cliquée pendant un chargement', ['']],
|
||||||
|
['data-auteur', 'à propos : l’auteur du logiciel', ['']],
|
||||||
['data-autre', 'accueil : le choix d’un autre dossier de travail', ['']],
|
['data-autre', 'accueil : le choix d’un autre dossier de travail', ['']],
|
||||||
['data-autre-chemin', 'accueil : le chemin de l’autre dossier de travail', ['']],
|
['data-autre-chemin', 'accueil : le chemin de l’autre dossier de travail', ['']],
|
||||||
['data-avancement', 'génération : la barre d’avancement', ['']],
|
['data-avancement', 'génération : la barre d’avancement', ['']],
|
||||||
|
|
@ -58,6 +59,7 @@ const ENTREES = [
|
||||||
['data-corbeille', 'accueil : la corbeille', ['']],
|
['data-corbeille', 'accueil : la corbeille', ['']],
|
||||||
['data-corbeille-dossier', 'accueil : un dossier de la corbeille', null],
|
['data-corbeille-dossier', 'accueil : un dossier de la corbeille', null],
|
||||||
['data-course', 'qualité : la ligne de tête de la performance du calcul', ['']],
|
['data-course', 'qualité : la ligne de tête de la performance du calcul', ['']],
|
||||||
|
['data-credits', 'à propos : l’éditeur et l’auteur, au-dessus du bloc', ['']],
|
||||||
['data-critere', 'propositions : un nom de la phrase de l’ordre, par le critère qui classe sa valeur, objectifs et animateurs compris', null],
|
['data-critere', 'propositions : un nom de la phrase de l’ordre, par le critère qui classe sa valeur, objectifs et animateurs compris', null],
|
||||||
['data-defaut', 'tables : le réglage du défaut de places', ['']],
|
['data-defaut', 'tables : le réglage du défaut de places', ['']],
|
||||||
['data-demonstration', 'accueil : une démonstration, par sa clé', null],
|
['data-demonstration', 'accueil : une démonstration, par sa clé', null],
|
||||||
|
|
@ -73,6 +75,7 @@ const ENTREES = [
|
||||||
['data-duree', 'génération : la durée estimée', ['']],
|
['data-duree', 'génération : la durée estimée', ['']],
|
||||||
['data-echec-section', 'événement : la phrase d’une section chargée à part qui ne s’est pas chargée, par son nom', null],
|
['data-echec-section', 'événement : la phrase d’une section chargée à part qui ne s’est pas chargée, par son nom', null],
|
||||||
['data-ecran', 'un écran de l’application', ['accueil', 'apercu', 'apropos', 'evenement', 'recuperation']],
|
['data-ecran', 'un écran de l’application', ['accueil', 'apercu', 'apropos', 'evenement', 'recuperation']],
|
||||||
|
['data-editeur', 'à propos : l’éditeur du logiciel', ['']],
|
||||||
['data-encodage', 'import : l’encodage nommé', ['']],
|
['data-encodage', 'import : l’encodage nommé', ['']],
|
||||||
['data-enonce', 'un énoncé : diagnostic, ou défaut des tables', null],
|
['data-enonce', 'un énoncé : diagnostic, ou défaut des tables', null],
|
||||||
['data-enregistre', 'import : le chemin des refus enregistrés', ['']],
|
['data-enregistre', 'import : le chemin des refus enregistrés', ['']],
|
||||||
|
|
@ -178,6 +181,7 @@ const ENTREES = [
|
||||||
['data-repere', 'qualité : le tracé d’un repère — plafond, borne ou règle à 100 % (cent) —, par son genre', null],
|
['data-repere', 'qualité : le tracé d’un repère — plafond, borne ou règle à 100 % (cent) —, par son genre', null],
|
||||||
['data-reserve', 'plan : la réserve d’un tour', null],
|
['data-reserve', 'plan : la réserve d’un tour', null],
|
||||||
['data-retenu', 'propositions : la ligne du retenu', null],
|
['data-retenu', 'propositions : la ligne du retenu', null],
|
||||||
|
['data-role', 'à propos : le rôle de l’auteur', ['']],
|
||||||
['data-rubrique-rencontres', 'participants : la rubrique « Rencontres » de la fiche', ['']],
|
['data-rubrique-rencontres', 'participants : la rubrique « Rencontres » de la fiche', ['']],
|
||||||
['data-secours', 'récupération : une source de secours', null],
|
['data-secours', 'récupération : une source de secours', null],
|
||||||
['data-segment', 'qualité : un segment de barre, par son genre', null],
|
['data-segment', 'qualité : un segment de barre, par son genre', null],
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,6 @@ export async function monterApp({
|
||||||
demonstrations: demonstrations ?? demonstrationsLivrees(),
|
demonstrations: demonstrations ?? demonstrationsLivrees(),
|
||||||
formatCourant: formatCourant ?? FORMAT,
|
formatCourant: formatCourant ?? FORMAT,
|
||||||
produitVersion: VERSION.affichee,
|
produitVersion: VERSION.affichee,
|
||||||
versionWindows: VERSION.windows,
|
|
||||||
polices,
|
polices,
|
||||||
imprimante,
|
imprimante,
|
||||||
sectionQualite,
|
sectionQualite,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue