/* ==UserStyle==
@name           05. Tableaux (détails)
@namespace      www.vayssiere.fr/philippe/accessibilite/stylus
@version        0.2.2
@description    Mise en valeur et comptage des tableaux (et role). Détecte, signale et compte des attributs (scope, col/rowspan, headers)
@author         Philippe Vayssière
@license        AGPL 3.0
==/UserStyle== */

/*
  Base des styles A42 : mettait en valeur les éléments parents table et [role="table"], comptait et affichait le total en sidebar.
  Remanié : lint et factorisation avec :is()
  Ajouts :
    * signaler le contenu dans les tableaux :
      * visuellement th sans scope, avec scope ⏬ ou avec scope ⏩
      * visuellement cellule avec rowspan ou avec colspan et la valeur
    * compter les th sans scope
    * compter les attributs rowspan et colspan
    * compter les attributs headers
    * il n'y a affichage d'un compteur que s'il est supérieur à 0 (avec la limitation des éléments cachés ":has() vs counter-increment")

  @date           2023-05-05
*/
:root {
  --phv-struct: #33c;
  --phv-error: #e00;
  --phv-success: green;
  --phv-warning: #dd9000;
}

* {
  box-sizing: border-box;
}

/* Signaler tableaux
    Message sans role : tableau.
    Avec role : tableau role="table". */
:is(table, [role="table"])::before {
  content: "Tableau";

  display: block;
  font-family: sans-serif !important;
  font-size: 15px !important;
  font-weight: bold;
  color: #fff !important;
  background: var(--phv-success);
}

[role="table"]::before {
  content: "Tableau <" var(--phv-tagname) ' role="' attr(role) '">'
}

[role="table"] { --phv-tagname: "??"; }
table[role="table"] { --phv-tagname: "table"; }
div[role="table"] { --phv-tagname: "div"; }

:is(table, [role="table"]) {
  counter-increment: table-eltrole; /* Comptage du nombre de tableaux : incrément (1/3) */
  display: block;
  outline: solid 5px var(--phv-success) !important;
}

/* Élément table avec un role autre que table
    Message : <table role="sonrole"> */
table[role]:not([role="table"])::before {
  content: 'Plus un tableau <table role="' attr(role) '">';
}

/* Comptage du nombre de tableaux : RÀZ (2/3)
   Et colspan ou rowspan, scope et headers */
html {
  counter-reset: table-eltrole table-span th-no-scope cell-headers;
  /* custom prop invalide quand cela vaut initial => désactive le message
     concernant la présence de headers (est activé au 1er headers rencontré via
     sélecteur :has([headers]) plus bas) */
  --phv-page-has-headers: initial;
  --phv-page-has-no-scope: initial;
  --phv-page-has-colrowspan: initial;
}

/* Comptage
    On compte jusqu'à 3 choses différentes sur les TH et il faut le faire en 1 seule instruction...
*/
th:where([colspan]:not([colspan="1"]), [rowspan]:not([rowspan="1"])) {
  counter-increment: table-span;
}
th:not(:where([scope="col"], [scope="row"])) {
  counter-increment: th-no-scope;
}
th[headers] {
  counter-increment: cell-headers;
}

/* (col|row)span && (no)scope */
th:where([colspan]:not([colspan="1"]), [rowspan]:not([rowspan="1"])):not(:where([scope="col"], [scope="row"])) {
  counter-increment: table-span th-no-scope;
}
/* (col|row)span && headers */
th:where([colspan]:not([colspan="1"]), [rowspan]:not([rowspan="1"]))[headers] {
  counter-increment: table-span cell-headers;
}
/* (no)scope && headers */
th:not(:where([scope="col"], [scope="row"]))[headers] {
  counter-increment: th-no-scope cell-headers;
}

/* Les 3 à la fois */
th:where([colspan]:not([colspan="1"]), [rowspan]:not([rowspan="1"])):not(:where([scope="col"], [scope="row"]))[headers] {
  counter-increment: table-span th-no-scope cell-headers;
}


/* [colspan] et [rowspan] */
[colspan]:not([colspan="1"]),
[rowspan]:not([rowspan="1"]) {
  /* counter-increment: table-span; td comptés ci-dessous, th (complexe) ci-dessus */
  box-shadow: 0 0 1px 2px var(--phv-warning) inset !important;
}

td:where(
  [colspan]:not([colspan="1"]),
  [rowspan]:not([rowspan="1"])
) {
  counter-increment: table-span;
}

[colspan]:not([colspan="1"])::before {
  content: 'colspan="' attr(colspan) '" '
}

[rowspan]:not([rowspan="1"])::before {
  content: 'rowspan="' attr(rowspan) '" '
}

:where(
  [colspan]:not([colspan="1"]),
  [rowspan]:not([rowspan="1"])
)::before {
  line-height: 1.2;
  color: black !important;
  background-color: var(--phv-warning) !important;
}

/*  Active le message concernant la présence de colspan et rowspan
    (idéalement on voudrait éviter les éléments cachés car non comptés
    par counter() mais pas possible en CSS) */
html:has( :where(
  [colspan]:not([colspan="1"]),
  [rowspan]:not([rowspan="1"])
) ) {
  --phv-page-has-colrowspan: ;
}


/* TH */
/* Erreur : absence de scope pertinent */
th:not(:where([scope="col"], [scope="row"])) {
  box-shadow: 0 0 1px 2px var(--phv-error) inset !important;
}

th:not([scope="col"], [scope="row"])::before {
  content: '❌\A0no scope ' !important;
  position: relative;
  line-height: 1.2;
  color: black !important;
  background: pink !important;
}

:not(thead) > tr > th:not([scope]) {
  position: relative;
}

/* Styles selon position du th sans scope */
:where(
  thead > tr > th,
  tr:first-child > th:not(:first-child)
):not([scope])::before {
  display: flex;
  flex-wrap: wrap;
  width: 8ch;
  margin: auto;
}

:not(thead) > tr > th:not([scope])::before {
  float: right;
  padding-left: 2px;
}

/* scope col ou row pertinent */
th:where([scope="col"], [scope="row"]) {
  box-shadow: 0 0 1px 2px var(--phv-struct) inset !important;
}

/* On affiche en ::pseudo "th⏩" ou "th ⏬" pour indiquer la direction */
th[scope="row"] {
  position: relative;
}

th:where([scope="col"], [scope="row"])::before {
  color: black !important;
  background: lightgreen !important;
}

th[scope="col"]::before {
  content: 'TH ⏬';
  display: flex;
  flex-wrap: wrap;
  width: 2.5ch;
  margin: auto;
  text-align: center !important;
}

th[scope="row"]::before {
  content: 'TH⏩';
  position: absolute;
  top: 3px;
  right: 3px;
  padding-left: 2px;
  line-height: 1.2;
}

/*  Active le message concernant l'absence de scope sur th
    (idéalement on voudrait éviter les éléments cachés car non comptés
    par counter() mais pas possible en CSS) */
html:has( th:not([scope="col"]):not([scope="row"]) ) {
  --phv-page-has-no-scope: ;
}


/* Compte l'attribut headers (ici sur td mais aussi th (complexe) ci-dessus) */
td[headers] {
  counter-increment: cell-headers;
}

/*  Active le message concernant la présence de headers
    (idéalement on voudrait éviter les éléments cachés car non comptés
    par counter() mais pas possible en CSS) */
html:has(table:not([hidden])):has([headers]) {
  --phv-page-has-headers: ;
}

/* Affichage global */
html::after {
  /* Préparation du message affiché */
  --phv-cell-headers: "\A" counter(cell-headers) " attributs headers" var(/* toggle */--phv-page-has-headers);
  --phv-table-span-msg: "\A\A⚠ " counter(table-span) " colspan et rowspan" var(/* toggle */--phv-page-has-colrowspan);
  --phv-th-no-scope: '\A\A⚠ ' counter(th-no-scope) ' TH sans scope' var(/* toggle */--phv-page-has-no-scope);

  content: "" counter(table-eltrole) " tableaux" /* Comptage du nombre de tableaux : affichage (3/3) */
  var(--phv-cell-headers, "")
  var(--phv-table-span-msg, "") /* colspan et rowspan */
  var(--phv-th-no-scope, "");

  position: fixed !important;
  top: 20vh !important;
  right: 0 !important;
  z-index: 123456 !important;
  white-space: pre !important;
  width: 300px !important;
  min-height: 170px;
  border: 2px solid white;
  border-right: 0;
  padding: 16px !important;
  line-height: 1.2;
  font-family: sans-serif !important;
  font-family: consolas, monospace !important;
  font-size: 20px !important;
  font-weight: bold;
  letter-spacing: 0.3px;
  color: #fff !important;
  background: purple linear-gradient(to right, #606, purple) !important;
  box-shadow: 0 0 0 2px purple; /* avec border : double bordure blanc / purple */
}
