For reference: * https://www.w3.org/TR/dpub-aria-1.1/ * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
1. Wrap ToC in the "<nav>" tag 2. Add "doc-toc" DPUB-ARIA role --- html.c | 4 ++++ html.h | 1 + mdoc_html.c | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/html.c b/html.c index 65c31b64..4710bab7 100644 --- a/html.c +++ b/html.c @@ -110,6 +110,7 @@ static const struct htmldata htmltags[TAG_MAX] = { {"munderover", 0}, {"munder", 0}, {"mover", 0}, + {"nav", HTML_NLALL}, }; /* Avoid duplicate HTML id= attributes. */ @@ -708,6 +709,9 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) case 'i': attr = "id"; break; + case 'r': + attr = "role"; + break; case '?': attr = arg1; arg1 = va_arg(ap, char *); diff --git a/html.h b/html.h index dda19b8a..5e2adc06 100644 --- a/html.h +++ b/html.h @@ -70,6 +70,7 @@ enum htmltag { TAG_MUNDEROVER, TAG_MUNDER, TAG_MOVER, + TAG_NAV, TAG_MAX }; diff --git a/mdoc_html.c b/mdoc_html.c index 2dde0531..d85df753 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -515,7 +515,7 @@ static int mdoc_sh_pre(MDOC_ARGS) { struct roff_node *sn, *subn; - struct tag *t, *tsec, *tsub; + struct tag *t, *tnav, *tsec, *tsub; char *id; int sc; @@ -536,6 +536,7 @@ mdoc_sh_pre(MDOC_ARGS) break; if (sc < 2) break; + tnav = print_otag(h, TAG_NAV, "r", "doc-toc"); t = print_otag(h, TAG_H1, "c", "Sh"); print_text(h, "TABLE OF CONTENTS"); print_tagq(h, t); @@ -568,6 +569,7 @@ mdoc_sh_pre(MDOC_ARGS) print_tagq(h, tsec); } print_tagq(h, t); + print_tagq(h, tnav); print_otag(h, TAG_SECTION, "c", "Sh"); break; case ROFFT_HEAD: -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
--- html.h | 26 ++++++++++++++++++++++++++ mdoc_html.c | 5 +++-- regress/mdoc/Er/tag.out_html | 2 +- regress/mdoc/Rs/paragraph.out_html | 2 +- regress/mdoc/Sh/paragraph.out_html | 2 +- regress/mdoc/Sh/tag.out_html | 8 ++++---- regress/mdoc/Tg/warn.out_html | 2 +- 7 files changed, 37 insertions(+), 10 deletions(-) diff --git a/html.h b/html.h index 5e2adc06..dc4febf2 100644 --- a/html.h +++ b/html.h @@ -74,6 +74,32 @@ enum htmltag { TAG_MAX }; +static const char * const dpubroles[SEC__MAX] = { + NULL, /* SEC_NONE */ + "doc-abstract", /* SEC_NAME */ + "doc-abstract", /* SEC_LIBRARY */ + "doc-part", /* SEC_SYNOPSIS */ + "doc-part", /* SEC_DESCRIPTION */ + "doc-part", /* SEC_CONTEXT */ + "doc-part", /* SEC_IMPLEMENTATION */ + "doc-part", /* SEC_RETURN_VALUES */ + "doc-part", /* SEC_ENVIRONMENT */ + "doc-part", /* SEC_FILES */ + "doc-part", /* SEC_EXIT_STATUS */ + "doc-example", /* SEC_EXAMPLES */ + "doc-part", /* SEC_DIAGNOSTICS */ + "doc-part", /* SEC_COMPATIBILITY */ + "doc-part", /* SEC_ERRORS */ + "doc-part", /* SEC_SEE_ALSO */ + "doc-part", /* SEC_STANDARDS */ + "doc-part", /* SEC_HISTORY */ + "doc-aknowledgments", /* SEC_AUTHORS */ + "doc-part", /* SEC_CAVEATS */ + "doc-part", /* SEC_BUGS */ + "doc-part", /* SEC_SECURITY */ + "doc-part", /* SEC_CUSTOM */ +}; + struct tag { struct tag *next; int refcnt; diff --git a/mdoc_html.c b/mdoc_html.c index d85df753..31cfaac2 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -525,7 +525,8 @@ mdoc_sh_pre(MDOC_ARGS) if ((h->oflags & HTML_TOC) == 0 || h->flags & HTML_TOCDONE || n->sec <= SEC_SYNOPSIS) { - print_otag(h, TAG_SECTION, "c", "Sh"); + print_otag(h, TAG_SECTION, "cr", + "Sh", dpubroles[n->sec]); break; } h->flags |= HTML_TOCDONE; @@ -570,7 +571,7 @@ mdoc_sh_pre(MDOC_ARGS) } print_tagq(h, t); print_tagq(h, tnav); - print_otag(h, TAG_SECTION, "c", "Sh"); + print_otag(h, TAG_SECTION, "cr", "Sh", dpubroles[n->sec]); break; case ROFFT_HEAD: print_otag_id(h, TAG_H1, "Sh", n); diff --git a/regress/mdoc/Er/tag.out_html b/regress/mdoc/Er/tag.out_html index 80daa28b..276bf29b 100644 --- a/regress/mdoc/Er/tag.out_html +++ b/regress/mdoc/Er/tag.out_html @@ -4,7 +4,7 @@ </dl> <a class="permalink" href="#two"><code class="Er" id="two">two</code></a> </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh" id="ERRORS"><a class="permalink" href="#ERRORS">ERRORS</a></h1> <dl class="Bl-tag"> <dt id="ENOENT">[<a class="permalink" href="#ENOENT"><code class="Er">ENOENT</code></a>]</dt> diff --git a/regress/mdoc/Rs/paragraph.out_html b/regress/mdoc/Rs/paragraph.out_html index bfb0a724..9c197182 100644 --- a/regress/mdoc/Rs/paragraph.out_html +++ b/regress/mdoc/Rs/paragraph.out_html @@ -4,7 +4,7 @@ <p class="Pp">in a paragraph: <cite class="Rs"><span class="RsA">another author</span>, <i class="RsB">another book</i>.</cite></p> </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE ALSO</a></h1> <p class="Pp">initial reference:</p> diff --git a/regress/mdoc/Sh/paragraph.out_html b/regress/mdoc/Sh/paragraph.out_html index 82ede5be..604153cd 100644 --- a/regress/mdoc/Sh/paragraph.out_html +++ b/regress/mdoc/Sh/paragraph.out_html @@ -5,5 +5,5 @@ <p class="Pp">subsection paragraph</p> </section> </section> -<section class="Sh"> +<section class="Sh" role="doc-example"> <h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1> diff --git a/regress/mdoc/Sh/tag.out_html b/regress/mdoc/Sh/tag.out_html index 0dd39398..88f65803 100644 --- a/regress/mdoc/Sh/tag.out_html +++ b/regress/mdoc/Sh/tag.out_html @@ -1,11 +1,11 @@ <p class="Pp">Text in the subsection.</p> </section> </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh" id="DESCRIPTION~2"><a class="permalink" href="#DESCRIPTION~2">DESCRIPTION</a></h1> <p class="Pp">Text in duplicate description section.</p> </section> -<section class="Sh"> +<section class="Sh" role="doc-example"> <h1 class="Sh" id="examples"><a class="permalink" href="#examples">EXAMPLES</a></h1> <p class="Pp">Text introducing examples.</p> <section class="Ss"> @@ -17,11 +17,11 @@ <p class="Pp">More example text.</p> </section> </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh" id="WEIRD_SECTION"><a class="permalink" href="#WEIRD_SECTION"> WEIRD SECTION </a></h1> <p class="Pp">Text in weird section.</p> </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh"> </h1> <p class="Pp">Text in section with empty header.</p> diff --git a/regress/mdoc/Tg/warn.out_html b/regress/mdoc/Tg/warn.out_html index a7f92574..7c7d7943 100644 --- a/regress/mdoc/Tg/warn.out_html +++ b/regress/mdoc/Tg/warn.out_html @@ -6,6 +6,6 @@ <p class="Pp">subtext</p> </section> </section> -<section class="Sh"> +<section class="Sh" role="doc-example"> <h1 class="Sh" id="examples"><a class="permalink" href="#examples">EXAMPLES</a></h1> <p class="Pp">example text</p> -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
--- mdoc_html.c | 2 +- regress/mdoc/Sh/paragraph.out_html | 2 +- regress/mdoc/Sh/tag.out_html | 4 ++-- regress/mdoc/Tg/warn.out_html | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mdoc_html.c b/mdoc_html.c index 31cfaac2..076a6bac 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -592,7 +592,7 @@ mdoc_ss_pre(MDOC_ARGS) switch (n->type) { case ROFFT_BLOCK: html_close_paragraph(h); - print_otag(h, TAG_SECTION, "c", "Ss"); + print_otag(h, TAG_SECTION, "cr", "Ss", "doc-chapter"); break; case ROFFT_HEAD: print_otag_id(h, TAG_H2, "Ss", n); diff --git a/regress/mdoc/Sh/paragraph.out_html b/regress/mdoc/Sh/paragraph.out_html index 604153cd..21da3acc 100644 --- a/regress/mdoc/Sh/paragraph.out_html +++ b/regress/mdoc/Sh/paragraph.out_html @@ -1,5 +1,5 @@ <p class="Pp">descriptive text</p> -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="Subsection"><a class="permalink" href="#Subsection">Subsection</a></h2> <p class="Pp">initial subsection text</p> <p class="Pp">subsection paragraph</p> diff --git a/regress/mdoc/Sh/tag.out_html b/regress/mdoc/Sh/tag.out_html index 88f65803..8304ed5c 100644 --- a/regress/mdoc/Sh/tag.out_html +++ b/regress/mdoc/Sh/tag.out_html @@ -8,11 +8,11 @@ <section class="Sh" role="doc-example"> <h1 class="Sh" id="examples"><a class="permalink" href="#examples">EXAMPLES</a></h1> <p class="Pp">Text introducing examples.</p> -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="example"><a class="permalink" href="#example">Subsection</a></h2> <p class="Pp">Example text.</p> </section> -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="Sub-section"><a class="permalink" href="#Sub-section">Sub-section</a></h2> <p class="Pp">More example text.</p> </section> diff --git a/regress/mdoc/Tg/warn.out_html b/regress/mdoc/Tg/warn.out_html index 7c7d7943..673580fe 100644 --- a/regress/mdoc/Tg/warn.out_html +++ b/regress/mdoc/Tg/warn.out_html @@ -1,7 +1,7 @@ <p class="Pp" id="start-tag">initial text <a class="permalink" href="#macro"><code class="Ic" id="macro">macro</code></a> too many badstart badend whitespace <mark id="sub"></mark></p> -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="double"><a class="permalink" href="#double">Subsection</a></h2> <p class="Pp">subtext</p> </section> -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
--- man_html.c | 5 ++++- regress/man/IP/literal.out_html | 4 ++-- regress/man/SH/paragraph.out_html | 4 ++-- regress/man/SS/paragraph.out_html | 4 ++-- regress/man/TP/vert.out_html | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/man_html.c b/man_html.c index 5f715cf0..ee3df208 100644 --- a/man_html.c +++ b/man_html.c @@ -322,7 +322,10 @@ man_SH_pre(MAN_ARGS) switch (n->type) { case ROFFT_BLOCK: html_close_paragraph(h); - print_otag(h, TAG_SECTION, "c", class); + if (n->tok == MAN_SH) + print_otag(h, TAG_SECTION, "cr", class, "doc-part"); + else + print_otag(h, TAG_SECTION, "cr", class, "doc-chapter"); break; case ROFFT_HEAD: print_otag_id(h, tag, class, n); diff --git a/regress/man/IP/literal.out_html b/regress/man/IP/literal.out_html index ceb26a56..caf883f4 100644 --- a/regress/man/IP/literal.out_html +++ b/regress/man/IP/literal.out_html @@ -17,7 +17,7 @@ text</pre> literal paragraph</pre> regular text -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="literal_into_indented_paragraph"><a class="permalink" href="#literal_into_indented_paragraph">literal into indented paragraph</a></h2> <p class="Pp">regular text</p> @@ -33,7 +33,7 @@ text</pre> </dl> <p class="Pp">new regular paragraph</p> </section> -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="literal_out_of_indented_paragraph"><a class="permalink" href="#literal_out_of_indented_paragraph">literal out of indented paragraph</a></h2> <p class="Pp">regular text</p> diff --git a/regress/man/SH/paragraph.out_html b/regress/man/SH/paragraph.out_html index abe932b4..177b66a8 100644 --- a/regress/man/SH/paragraph.out_html +++ b/regress/man/SH/paragraph.out_html @@ -1,8 +1,8 @@ </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1> <p class="Pp">This text immediately follows a section header.</p> <p class="Pp">This is a paragraph.</p> </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1> diff --git a/regress/man/SS/paragraph.out_html b/regress/man/SS/paragraph.out_html index 22591deb..b940af89 100644 --- a/regress/man/SS/paragraph.out_html +++ b/regress/man/SS/paragraph.out_html @@ -1,9 +1,9 @@ -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="First_subsection"><a class="permalink" href="#First_subsection">First subsection</a></h2> <p class="Pp">This text immediately follows a subsection header.</p> <p class="Pp">This is a paragraph.</p> </section> -<section class="Ss"> +<section class="Ss" role="doc-chapter"> <h2 class="Ss" id="Second_subsection"><a class="permalink" href="#Second_subsection">Second subsection</a></h2> diff --git a/regress/man/TP/vert.out_html b/regress/man/TP/vert.out_html index 4499432b..551893b9 100644 --- a/regress/man/TP/vert.out_html +++ b/regress/man/TP/vert.out_html @@ -1,5 +1,5 @@ </section> -<section class="Sh"> +<section class="Sh" role="doc-part"> <h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1> <dl class="Bl-tag"> <dt id="tag"><a class="permalink" href="#tag">tag</a></dt> -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
--- cgi.c | 61 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/cgi.c b/cgi.c index da9e408d..71f9a8ac 100644 --- a/cgi.c +++ b/cgi.c @@ -431,7 +431,8 @@ resp_searchform(const struct req *req, enum focus focus) { int i; - printf("<form action=\"/%s\" method=\"get\" " + printf("<header>\n" + "<form role=\"search\" action=\"/%s\" method=\"get\" " "autocomplete=\"off\" autocapitalize=\"none\">\n" " <fieldset>\n" " <legend>Manual Page Search Parameters</legend>\n", @@ -457,7 +458,7 @@ resp_searchform(const struct req *req, enum focus focus) /* Write section selector. */ - puts(" <select name=\"sec\">"); + puts(" <select name=\"sec\" aria-label=\"Manual section\">"); for (i = 0; i < sec_MAX; i++) { printf(" <option value=\"%s\"", sec_numbers[i]); if (NULL != req->q.sec && @@ -469,7 +470,7 @@ resp_searchform(const struct req *req, enum focus focus) /* Write architecture selector. */ - printf( " <select name=\"arch\">\n" + printf( " <select name=\"arch\" aria-label=\"CPU architecture\">\n" " <option value=\"default\""); if (NULL == req->q.arch) printf(" selected=\"selected\""); @@ -499,7 +500,8 @@ resp_searchform(const struct req *req, enum focus focus) } puts(" </fieldset>\n" - "</form>"); + "</form>\n" + "</header>"); } static int @@ -557,13 +559,17 @@ pg_index(const struct req *req) resp_begin_html(200, NULL, NULL); resp_searchform(req, FOCUS_QUERY); - printf("<p>\n" + printf("<main>\n" + "<p role=\"doc-notice\" aria-label=\"Usage\">\n" "This web interface is documented in the\n" - "<a class=\"Xr\" href=\"/%s%sman.cgi.8\">man.cgi(8)</a>\n" + "<a class=\"Xr\" href=\"/%s%sman.cgi.8\"" + " aria-label=\"man dot CGI, section 8\">man.cgi(8)</a>\n" "manual, and the\n" - "<a class=\"Xr\" href=\"/%s%sapropos.1\">apropos(1)</a>\n" + "<a class=\"Xr\" href=\"/%s%sapropos.1\"" + " aria-label=\"apropos, section 1\">apropos(1)</a>\n" "manual explains the query syntax.\n" - "</p>\n", + "</p>\n" + "</main>\n", scriptname, *scriptname == '\0' ? "" : "/", scriptname, *scriptname == '\0' ? "" : "/"); resp_end_html(); @@ -575,9 +581,11 @@ pg_noresult(const struct req *req, int code, const char *http_msg, { resp_begin_html(code, http_msg, NULL); resp_searchform(req, FOCUS_QUERY); - puts("<p>"); + puts("<main>"); + puts("<p role=\"doc-notice\" aria-label=\"No result\">"); puts(user_msg); puts("</p>"); + puts("</main>"); resp_end_html(); } @@ -586,12 +594,14 @@ pg_error_badrequest(const char *msg) { resp_begin_html(400, "Bad Request", NULL); - puts("<h1>Bad Request</h1>\n" - "<p>\n"); + puts("<main>" + "<h1>Bad Request</h1>\n" + "<p role=\"doc-notice\" aria-label=\"Bad Request\">\n"); puts(msg); printf("Try again from the\n" "<a href=\"/%s\">main page</a>.\n" - "</p>", scriptname); + "</p>\n" + "</main>", scriptname); resp_end_html(); } @@ -599,7 +609,7 @@ static void pg_error_internal(void) { resp_begin_html(500, "Internal Server Error", NULL); - puts("<p>Internal Server Error</p>"); + puts("<main><p role=\"doc-notice\">Internal Server Error</p></main>"); resp_end_html(); } @@ -625,7 +635,7 @@ pg_redirect(const struct req *req, const char *name) static void pg_searchres(const struct req *req, struct manpage *r, size_t sz) { - char *arch, *archend; + char *arch, *archend, *name = NULL, *label = NULL; const char *sec; size_t i, iuse; int archprio, archpriouse; @@ -704,11 +714,20 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz) req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY); if (sz > 1) { + puts("<nav>"); puts("<table class=\"results\">"); for (i = 0; i < sz; i++) { + // FIXME: there has to be a way to do this without + // truncating + name = mandoc_strdup(r[i].names); + name[strlen(name)-3] = '\0'; + mandoc_asprintf(&label, "%s, section %d", + name, r[i].sec); + printf(" <tr>\n" " <td>" - "<a class=\"Xr\" href=\"/"); + "<a class=\"Xr\" aria-label=\"%s\" href=\"/", + label); if (*scriptname != '\0') printf("%s/", scriptname); if (strcmp(req->q.manpath, req->p[0])) @@ -720,8 +739,10 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz) html_print(r[i].output); puts("</span></td>\n" " </tr>"); + free(label); } puts("</table>"); + puts("</nav>"); } if (req->q.equal || sz == 1) { @@ -743,7 +764,9 @@ resp_catman(const struct req *req, const char *file) int italic, bold; if ((f = fopen(file, "r")) == NULL) { - puts("<p>You specified an invalid manual file.</p>"); + puts("<p role=\"doc-notice\">\n" + " You specified an invalid manual file.\n" + "</p>"); return; } @@ -880,7 +903,9 @@ resp_format(const struct req *req, const char *file) int usepath; if (-1 == (fd = open(file, O_RDONLY))) { - puts("<p>You specified an invalid manual file.</p>"); + puts("<p role=\"doc-notice\">\n" + " You specified an invalid manual file.\n" + "</p>"); return; } @@ -900,10 +925,12 @@ resp_format(const struct req *req, const char *file) usepath ? req->q.manpath : "", usepath ? "/" : ""); vp = html_alloc(&conf); + puts("<main>"); if (meta->macroset == MACROSET_MDOC) html_mdoc(vp, meta); else html_man(vp, meta); + puts("</main>"); html_free(vp); mparse_free(mp); -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
Never hear "mdoc, left parenthesis, 7, right parenthesis" again. --- html.c | 3 +++ mdoc_html.c | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/html.c b/html.c index 4710bab7..3239a09b 100644 --- a/html.c +++ b/html.c @@ -709,6 +709,9 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) case 'i': attr = "id"; break; + case 'l': + attr = "aria-label"; + break; case 'r': attr = "role"; break; diff --git a/mdoc_html.c b/mdoc_html.c index 076a6bac..cf2e8804 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -667,26 +667,35 @@ mdoc_nm_pre(MDOC_ARGS) static int mdoc_xr_pre(MDOC_ARGS) { + char *name = NULL, *section = NULL, *label = NULL; + if (NULL == n->child) return 0; + name = n->child->string; + label = name; + if (NULL != n->child->next) + section = n->child->next->string; + + if (NULL != section) + mandoc_asprintf(&label, "%s, section %s", name, section); + if (h->base_man1) - print_otag(h, TAG_A, "chM", "Xr", - n->child->string, n->child->next == NULL ? - NULL : n->child->next->string); + print_otag(h, TAG_A, "clhM", "Xr", label, name, section); else - print_otag(h, TAG_A, "c", "Xr"); + print_otag(h, TAG_A, "cl", "Xr", label); - n = n->child; - print_text(h, n->string); + free(label); + + print_text(h, name); - if (NULL == (n = n->next)) + if (NULL == section) return 0; h->flags |= HTML_NOSPACE; print_text(h, "("); h->flags |= HTML_NOSPACE; - print_text(h, n->string); + print_text(h, section); h->flags |= HTML_NOSPACE; print_text(h, ")"); return 0; -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
--- html.c | 3 +++ mdoc_html.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/html.c b/html.c index 3239a09b..c45e9ee0 100644 --- a/html.c +++ b/html.c @@ -715,6 +715,9 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) case 'r': attr = "role"; break; + case 's': + attr = "aria-hidden"; + break; case '?': attr = arg1; arg1 = va_arg(ap, char *); diff --git a/mdoc_html.c b/mdoc_html.c index cf2e8804..85aadc4e 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -484,7 +484,8 @@ mdoc_root_pre(const struct roff_meta *meta, struct html *h) mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); - t = print_otag(h, TAG_TABLE, "c", "head"); + // Tell screen readers to skip the section + t = print_otag(h, TAG_TABLE, "cs", "head", "true"); tt = print_otag(h, TAG_TR, ""); print_otag(h, TAG_TD, "c", "head-ltitle"); -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
--- man_html.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/man_html.c b/man_html.c index ee3df208..95e041f0 100644 --- a/man_html.c +++ b/man_html.c @@ -270,7 +270,8 @@ man_root_pre(const struct roff_meta *man, struct html *h) assert(man->msec); mandoc_asprintf(&title, "%s(%s)", man->title, man->msec); - t = print_otag(h, TAG_TABLE, "c", "head"); + // Tell screen readers to skip the section + t = print_otag(h, TAG_TABLE, "cs", "head", "true"); tt = print_otag(h, TAG_TR, ""); print_otag(h, TAG_TD, "c", "head-ltitle"); -- 2.35.1 -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
Hello Anna, thank you for sending your patches. I agree that accessibility is an important goal. Anna wrote on Tue, Jun 21, 2022 at 05:27:41PM +0500: > For reference: > * https://www.w3.org/TR/dpub-aria-1.1/ > * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ These documents are extremely long (which is unfortunately the case for many other W3C documents too, and which is a common effect of design by committee in general). An unfortunate consequence is that i will have to read them selectively, and even that may take time. Three other goals of the mandoc project, in addition to accessibility, are (1) simplicity, (2) standard conformance, and (3) consistency. There are more goals, like correctness, robustness, security etc., but those matter less in the present context. These goals have a number fo implications: - (1) simplicity means that i do not want to add redundant or unnecessarily long markup. For example, i would not want to add ARIA properties if the HTML element used already implies the role, or can be changed to imply the role. As another example, when adding a new wrapper element for ARIA purposes, i would want to check whether the immediately surrounding, adjacent, or contained elements can be simplified. From a brief review, i suspect that your patches are already quite good in this respect, but i want to check such aspects for every change. - (2) standard conformance is in particular related to https://www.w3.org/TR/wai-aria-1.1/ section 1.4 Co-Evolution. I want both HTML elements and properties and ARIA properties used as standardized, but i fear there may still be places where elements are abused and more standard-conforming elements can be chosen. So whenever changing an element, i want to check the immediate vicinity for conformance. - (3) consistency implies that if one technique is chosen - respecting simplicity and conformance as described above - at one place, then it should be used throughout for the respective mdoc(7) or man(7) macro or for the respective HTML element. This is particularly important for languages that are as large as HTML, CSS, and ARIA: They usually provide several different ways to achieve a similar effect, and unless consistency is taken very seriously, markup chaos typically ensues. For these reasons, i never accept patch series. Instead, i will consider each patch separately. Let's see how that goes. One final question: Do you have a good way for testing? Is there a difference in the diff in the amount of effort for: 1. testing an uncommitted diff 2. testing a committed diff 3. testing a diff deployed to man.openbsd.org ? Yours, Ingo -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
On 2022-06-22 21:15, Ingo Schwarze wrote: > One final question: > Do you have a good way for testing? I don't understand the question. * If testing mandoc, then `./regress.pl . html`. * If testing keyboard navigation, then any GUI browser. * If testing screen reader support, then Orca (some people use Odilia) with Firefox or Chromium. > Is there a difference in the diff in the amount of effort for: > 1. testing an uncommitted diff > 2. testing a committed diff > 3. testing a diff deployed to man.openbsd.org ? Failed to parse that too. -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
Hi Anna, Anna “CyberTailor” wrote on Thu, Jun 23, 2022 at 12:40:43AM +0500: > On 2022-06-22 21:15, Ingo Schwarze wrote: >> One final question: >> Do you have a good way for testing? > I don't understand the question. > * If testing mandoc, then `./regress.pl . html`. > * If testing keyboard navigation, then any GUI browser. > * If testing screen reader support, then Orca (some people use Odilia) > with Firefox or Chromium. >> Is there a difference in the diff in the amount of effort for: >> 1. testing an uncommitted diff >> 2. testing a committed diff >> 3. testing a diff deployed to man.openbsd.org ? > Failed to parse that too. Sorry, i meant s/in the diff//, i.e. "Is there a difference in the amount of effort for:" But i think i understand your answer anyway, you can easily test in all required respects, and it doesn't really matter whether patches that need testing are uncommitted, committed, or deployed. Yours, Ingo -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
Hi Anna, i agree with the findamental idea of your patch titled "Add DPUB-ARIA roles to sections", but i have a few questions and i think there are number of details that need to be resolved before it becomes ready for commit. Anna "CyberTailor" wrote on Tue, Jun 21, 2022 at 05:27:43PM +0500: > diff --git a/html.h b/html.h > index 5e2adc06..dc4febf2 100644 > --- a/html.h > +++ b/html.h > @@ -74,6 +74,32 @@ enum htmltag { > TAG_MAX > }; > > +static const char * const dpubroles[SEC__MAX] = { > + NULL, /* SEC_NONE */ > + "doc-abstract", /* SEC_NAME */ I'm not sure this is correct. The doc-abstract role is defined as: A short summary of the principal ideas, concepts, and conclusions of the work, or of a section or excerpt within it. But the NAME section merely contains a title and a subtitle for the document as a whole, which is much less than an abstract. Could we somehow mark the NAME section as containing nothing but document titles? Specifically, .Nm gives the main title and .Nd feels like "doc-subtitle" to me. > + "doc-abstract", /* SEC_LIBRARY */ This is clearly wrong. The LIBRARY section does not contain an abstract. While i consider the LIBRARY section ill-designed in the first place, some operating systems use it, so you are right the we need to make it clear what it contains. It typically consists of a single line containing only a few words, not even a complete sentence, for example any of the following lines: Standard C Library (libc, -lc) Math Library (libm, -lm) Backtrace Information Library (libexecinfo, -lexecinfo) Netgraph User Library (libnetgraph, -lnetgraph) Begemot SNMP library (libbsnmp, -lbsnmp) System Utilities Library (libutil, -lutil) Video Graphics Library (libvgl, -lvgl) library "libcap_net" library "libcap_syslog" library "libcapsicum" library "libstats" The jemalloc(3) page in FreeBSD is an aberration rather than the norm. I'm not even convinced assigning a region or section class to the LIBRARY section makes sense at all. Maybe there is a better alternative which does not mark it as a region or section? Besically, its function is part of the function of the SYNOPSIS: Explain the syntax needed to use the functions documented in this manual page. Admittedly not the syntax needed in the C source code, but the syntax needed when calling ld(1). > + "doc-part", /* SEC_SYNOPSIS */ This seems unfortunate, too. The SYNOPSIS typically does not contain any free-form text, but only a formalized syntax summary. Is there a role that might apply to formal syntax descriptions somewhere? So far, i failed to find one. If nobody comes up with a better idea, maybe we might consider (ab)using "doc-abstract" here? > + "doc-part", /* SEC_DESCRIPTION */ > + "doc-part", /* SEC_CONTEXT */ > + "doc-part", /* SEC_IMPLEMENTATION */ > + "doc-part", /* SEC_RETURN_VALUES */ > + "doc-part", /* SEC_ENVIRONMENT */ > + "doc-part", /* SEC_FILES */ > + "doc-part", /* SEC_EXIT_STATUS */ I don't think doc-part is adequate for these. DPUB-ARIA defines it as follows: A major structural division in a work that contains a set of related sections dealing with a particular subject, narrative arc, or similar encapsulated theme. Things like SEC_CONTEXT, SEC_RETURN_VALUES, SEC_ENVIRONMENT, SEC_FILES, and SEC_EXIT_STATUS certainly aren't "major structural divisions", and even for SEC_DESCRIPTION, it's the exception rather than the rule for it to contain "a set of related sections". If i understand DPUB-ARIA correctly, doc-part is higher level than doc-chapter, i.e. a part usually consists of multiple chapters. So if we use DPUB-ARIA here at all, doc-chapter would seem more appropriate. But even that is decribed as: A major thematic section of content in a work. That doesn't fit well for SEC_FILES and the like. Is it maybe better to simply use the "region" role defined in the WAI-ARIA standard itself? It is described as: A perceivable section containing content that is relevant to a specific, author-specified purpose and sufficiently important that users will likely want to be able to navigate to the section easily and to have it listed in a summary of the page. That seems to apply even to smaller sections like SEC_FILES. If we want to use role="region", HTML-ARIA tells me that it's already the default "if the <section> element has an accessible name. Otherwise, no corresponding role." See: https://www.w3.org/TR/html-aria/ It would seem logical to me that, if the first child of the <section> element is <h1> or <h2>, the "accessible name" would automatically be taken from that header element. But HTML-AAM-1.0 given me the impression this is not the case: https://www.w3.org/TR/html-aam-1.0/#section-elements-and-grouping-content-elements-not-listed-elsewhere 4.16.1 Section and Grouping Element Accessible Name Computation 1. If the element has an aria-label or an aria-labelledby attribute the accessible name is to be calculated using the algorithm defined in Accessible Name and Description: Computation and API Mappings. 2. Otherwise use the title attribute. 3. If none of the above yield a usable text string there is no accessible name. Does that really mean that we have to specify aria-labelledby="..." on each and every <section> element? Is there no way to get accessible section names with less verbosity in the HTML code? > + "doc-example", /* SEC_EXAMPLES */ [...] > + "doc-aknowledgments", /* SEC_AUTHORS */ This is the bright side of this message: I agree with those two. Yours, Ingo -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
Hello Anna, Anna "CyberTailor" wrote on Tue, Jun 21, 2022 at 05:27:47PM +0500: > Never hear "mdoc, left parenthesis, 7, right parenthesis" again. Indeed, as i noticed in the past when sitting next to people who were using screen readers, it is quite annoying when the screen reader reads out punctuation verbosely. It takes significant time, which is bad because using a screen reader is already slower than reading text using your eyes, and it also distracts from listening to the actual text. So even though the approach you propose results in a bit of verbosity in the HTML code, i don't think that can be avoided if we are serious about accessibility. > diff --git a/html.c b/html.c > index 4710bab7..3239a09b 100644 > --- a/html.c > +++ b/html.c > @@ -709,6 +709,9 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) > case 'i': > attr = "id"; > break; > + case 'l': > + attr = "aria-label"; > + break; I expect that "aria-label" attributes will be needed for relatively few purposes in manual pages, so for now, i prefer using the generic "?" format letter. If it turns out i'm wrong and we need "aria-label" in more places than i expect, we can always add a dedicated "l" format letter later. > diff --git a/mdoc_html.c b/mdoc_html.c > index 076a6bac..cf2e8804 100644 > --- a/mdoc_html.c > +++ b/mdoc_html.c > @@ -667,26 +667,35 @@ mdoc_nm_pre(MDOC_ARGS) > static int > mdoc_xr_pre(MDOC_ARGS) > { > + char *name = NULL, *section = NULL, *label = NULL; > + I dislike assignments in declarations and usually avoid them, in particular when they are redundant (like, in this case, for the name variable). > if (NULL == n->child) > return 0; > > + name = n->child->string; > + label = name; > + if (NULL != n->child->next) > + section = n->child->next->string; > + > + if (NULL != section) > + mandoc_asprintf(&label, "%s, section %s", name, section); > + > if (h->base_man1) > - print_otag(h, TAG_A, "chM", "Xr", > - n->child->string, n->child->next == NULL ? > - NULL : n->child->next->string); > + print_otag(h, TAG_A, "clhM", "Xr", label, name, section); > else > - print_otag(h, TAG_A, "c", "Xr"); > + print_otag(h, TAG_A, "cl", "Xr", label); > > - n = n->child; > - print_text(h, n->string); > + free(label); There is quite a bad bug here. If no section is specified in the document, we have label == n->child->string at this point, so we would wrongly free a field of the syntax tree, resulting in a double free error when the whole tree is freed later on. > + > + print_text(h, name); > > - if (NULL == (n = n->next)) > + if (NULL == section) > return 0; > > h->flags |= HTML_NOSPACE; > print_text(h, "("); > h->flags |= HTML_NOSPACE; > - print_text(h, n->string); > + print_text(h, section); > h->flags |= HTML_NOSPACE; > print_text(h, ")"); > return 0; I committed the following variation of your patch. In case you find a problem with it, we can tweak it in the tree. Yours, Ingo Log Message: ----------- If an .Xr macro contains a section argument, write an aria-label attribute such that users of screen readers aren't forced to listen to lengthy and distracting readings like "mdoc, left parenthesis, 7, right parenthesis". Based on a patch from Anna Vyalkova <cyber at sysrq dot in>, significantly tweaked by me. Modified Files: -------------- mandoc: LICENSE mdoc_html.c Revision Data ------------- Index: mdoc_html.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/mdoc_html.c,v retrieving revision 1.343 retrieving revision 1.344 diff -Lmdoc_html.c -Lmdoc_html.c -u -p -r1.343 -r1.344 --- mdoc_html.c +++ mdoc_html.c @@ -1,7 +1,8 @@ /* $Id$ */ /* - * Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014-2022 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2022 Anna Vyalkova <cyber@sysrq.in> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -665,26 +666,34 @@ mdoc_nm_pre(MDOC_ARGS) static int mdoc_xr_pre(MDOC_ARGS) { - if (NULL == n->child) + char *name, *section, *label; + + if (n->child == NULL) return 0; + name = n->child->string; + if (n->child->next != NULL) { + section = n->child->next->string; + mandoc_asprintf(&label, "%s, section %s", name, section); + } else + section = label = NULL; + if (h->base_man1) - print_otag(h, TAG_A, "chM", "Xr", - n->child->string, n->child->next == NULL ? - NULL : n->child->next->string); + print_otag(h, TAG_A, "chM?", "Xr", + name, section, "aria-label", label); else - print_otag(h, TAG_A, "c", "Xr"); + print_otag(h, TAG_A, "c?", "Xr", "aria-label", label); - n = n->child; - print_text(h, n->string); + free(label); + print_text(h, name); - if (NULL == (n = n->next)) + if (section == NULL) return 0; h->flags |= HTML_NOSPACE; print_text(h, "("); h->flags |= HTML_NOSPACE; - print_text(h, n->string); + print_text(h, section); h->flags |= HTML_NOSPACE; print_text(h, ")"); return 0; Index: LICENSE =================================================================== RCS file: /home/cvs/mandoc/mandoc/LICENSE,v retrieving revision 1.22 retrieving revision 1.23 diff -LLICENSE -LLICENSE -u -p -r1.22 -r1.23 --- LICENSE +++ LICENSE @@ -4,8 +4,8 @@ With the exceptions noted below, all non in the mandoc toolkit are protected by the Copyright of the following developers: +Copyright (c) 2010-2022 Ingo Schwarze <schwarze@openbsd.org> Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> -Copyright (c) 2010-2021 Ingo Schwarze <schwarze@openbsd.org> Copyright (c) 1999, 2004, 2017 Marc Espie <espie@openbsd.org> Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org> Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> @@ -13,6 +13,7 @@ Copyright (c) 2014 Baptiste Daroussin <b Copyright (c) 2016 Ed Maste <emaste@freebsd.org> Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org> Copyright (c) 2017 Anthony Bentley <bentley@openbsd.org> +Copyright (c) 2022 Anna Vyalkova <cyber@sysrq.in> Copyright (c) 1998, 2004, 2010, 2015 Todd C. Miller <Todd.Miller@courtesan.com> Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net> Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
Hello Anna, i agree with your apparent goal to not force the listener to wait for unnecessary chatter to finish. Then again, aria-hidden="true" looks like quite a big hammer to me, and before wielding that one, i'd like to look at the big picture of document structure first. Unfortunately, that big picture of how HTML elements and ARIA roles work together to convey the overall document structure appears to be scattered around at least five lengthy documents: WAI-ARIA, ARIA-APG, HTML-ARIA, HTML-AAM, and DPUB-ARIA. So i compiled the essentials of these five documents into the following short tree structure. Each line has four optional fields: HTML element, default ARIA role, role category in parentheses, and a comment. I omitted elements and roles that i deem unlikely to occur in manual pages. <html> document (structure) - use reading mode here <head> no role can be assigned <body> no role can be assigned <header> banner (landmark) - site-oriented, e.g. logo, site name, search tool <form> form (landmark) search (landmark) - special case of form, use for man.cgi in the future doc-pageheader <main> main (landmark) - main content of the document - use in the future instead of <div class="manual-text">? doc-subtitle - could maybe be used for .Nd doc-abstract - could maybe be used for the SYNOPSIS <nav> navigation (landmark) - internal or external links doc-toc - used for -O toc <article> article (structure) - independent part doc-part doc-chapter <section> region (landmark) - could maybe be used for .Sh <h1> - <h6> heading (structure) <ul>, <ol>, <mewnu> list (structure) <li> listitem (structure) <table> table (structure) <th> columnheader (structure) <thead>, <tbody>, <tfoot> rowgroup (structure) <tr> row (structure) <th> rowheader (structure) <td>, <th> cell (structure) doc-example - use for EXAMPLES in the future doc-bibliography - could maybe be used for .Rs in the future doc-acknowledgments - use for AUTHORS in the furture doc-pagefooter <footer> contentinfo (landmark) - information about document, e.g. (c), privacy <aside> complementary (landmark) - independent but related content The two tables we are talking about here and in your next patch are currently marked as class="head" and class="foot", which is good enough to support the current mandoc.css but is unhelpful with respect to ARIA. Let's consider which are the two places in the above tree where these two tables occur. The "head" table comes immediately after the search form and immediately before the NAME section, i.e. shortly before the .Nd line. The only node between "search" and "Nd" in the above tree is "doc-pageheader". The "foot" table comes after AUTHORS. The <footer> and <aside> elements and the contentinfo and complementary landmarks are inadequate for the content of the "foot" table, which leaves us with doc-pagefooter as the only option. Conidering their DPUB-ARIA description, doc-pageheader and doc-pagefooter maybe aren't perfect fits for these two tables, but i think close enough to make their use acceptable. What do you think about the following plan? 1. Replace the ideosyncratic <div class="manual-text"> with the standard <main> element. We could maybe keep the class="manual-text" attribute on the <main> element for backward compatibility. Then again, users of -T html are likely to have to adapt their CSS code to the change from <div> to <main> anyway, so i'd lean twoards deleting the custom class: <main> alone feels like fully expressing the intention, and when it comes to CSS, doing the same with less is more. 2. Instead of <table class="head">, say <table role="doc-pageheader">. 3. Instead of <table class="foot">, say <table role="doc-pagefooter">. It that enough to convince screen readers to refrain from pointless chatter, or is the big hammer of aria-hidden="true" still needed? I wouldn't be opposed to saying <table role="doc-pageheader" aria-hidden="true"> if you think that is better than just <table role="doc-pageheader">. I'm not sending a patch yet because i'd like to learn your opinion on these ideas first. Two minor remarks regarding your patch follow inline below. Yours, Ingo Anna “CyberTailor” wrote on Tue, Jun 21, 2022 at 05:27:48PM +0500: > diff --git a/html.c b/html.c > index 3239a09b..c45e9ee0 100644 > --- a/html.c > +++ b/html.c > @@ -715,6 +715,9 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) > case 'r': > attr = "role"; > break; > + case 's': > + attr = "aria-hidden"; > + break; The format letter 's' cannot be used for this purpose because it is already taken, see https://mandoc.bsd.lv/man/mandoc_html.3.html#s > case '?': > attr = arg1; > arg1 = va_arg(ap, char *); > diff --git a/mdoc_html.c b/mdoc_html.c > index cf2e8804..85aadc4e 100644 > --- a/mdoc_html.c > +++ b/mdoc_html.c > @@ -484,7 +484,8 @@ mdoc_root_pre(const struct roff_meta *meta, struct html *h) > mandoc_asprintf(&title, "%s(%s)", > meta->title, meta->msec); > > - t = print_otag(h, TAG_TABLE, "c", "head"); > + // Tell screen readers to skip the section In OpenBSD C code, we *never* use // for comments, but always /* */. > + t = print_otag(h, TAG_TABLE, "cs", "head", "true"); > tt = print_otag(h, TAG_TR, ""); > > print_otag(h, TAG_TD, "c", "head-ltitle"); -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
On 2022-06-26 17:51, Ingo Schwarze wrote: > The two tables we are talking about here and in your next patch are > currently marked as class="head" and class="foot", which is good enough > to support the current mandoc.css but is unhelpful with respect to ARIA. > > Let's consider which are the two places in the above tree > where these two tables occur. > > The "head" table comes immediately after the search form and immediately > before the NAME section, i.e. shortly before the .Nd line. The only > node between "search" and "Nd" in the above tree is "doc-pageheader". > > The "foot" table comes after AUTHORS. The <footer> and <aside> elements > and the contentinfo and complementary landmarks are inadequate for the > content of the "foot" table, which leaves us with doc-pagefooter > as the only option. > > Conidering their DPUB-ARIA description, doc-pageheader and doc-pagefooter > maybe aren't perfect fits for these two tables, but i think close enough > to make their use acceptable. > > What do you think about the following plan? > > 1. Replace the ideosyncratic <div class="manual-text"> > with the standard <main> element. > We could maybe keep the class="manual-text" attribute > on the <main> element for backward compatibility. > Then again, users of -T html are likely to have to adapt > their CSS code to the change from <div> to <main> anyway, > so i'd lean twoards deleting the custom class: <main> alone > feels like fully expressing the intention, and when it comes > to CSS, doing the same with less is more. Agree. > 2. Instead of <table class="head">, say <table role="doc-pageheader">. I'd better wrap it in a <header> tag. Using semantic HTML is better than ARIA. > 3. Instead of <table class="foot">, say <table role="doc-pagefooter">. Same but with <footer>. > It that enough to convince screen readers to refrain from pointless > chatter, or is the big hammer of aria-hidden="true" still needed? > I wouldn't be opposed to saying > > <table role="doc-pageheader" aria-hidden="true"> > > if you think that is better than just <table role="doc-pageheader">. I'll test both variants later and send a patch with whatever works best. > > I'm not sending a patch yet because i'd like to learn your opinion > on these ideas first. > > Two minor remarks regarding your patch follow inline below. > > Yours, > Ingo > > Anna “CyberTailor” wrote on Tue, Jun 21, 2022 at 05:27:48PM +0500: > > > diff --git a/html.c b/html.c > > index 3239a09b..c45e9ee0 100644 > > --- a/html.c > > +++ b/html.c > > @@ -715,6 +715,9 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) > > case 'r': > > attr = "role"; > > break; > > + case 's': > > + attr = "aria-hidden"; > > + break; > > The format letter 's' cannot be used for this purpose because it is > already taken, see > > https://mandoc.bsd.lv/man/mandoc_html.3.html#s > > > case '?': > > attr = arg1; > > arg1 = va_arg(ap, char *); > > diff --git a/mdoc_html.c b/mdoc_html.c > > index cf2e8804..85aadc4e 100644 > > --- a/mdoc_html.c > > +++ b/mdoc_html.c > > @@ -484,7 +484,8 @@ mdoc_root_pre(const struct roff_meta *meta, struct html *h) > > mandoc_asprintf(&title, "%s(%s)", > > meta->title, meta->msec); > > > > - t = print_otag(h, TAG_TABLE, "c", "head"); > > + // Tell screen readers to skip the section > > In OpenBSD C code, we *never* use // for comments, but always /* */. > > > + t = print_otag(h, TAG_TABLE, "cs", "head", "true"); > > tt = print_otag(h, TAG_TR, ""); > > > > print_otag(h, TAG_TD, "c", "head-ltitle"); Got it. -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv
Hello Anna, Anna wrote on Tue, Jun 21, 2022 at 05:27:46PM +0500: > cgi.c | 61 ++++++++++++++++++++++++++++++++++++++++++----------------- > 1 file changed, 44 insertions(+), 17 deletions(-) While i did a lot of nitpicking on your other patches, i decided to commit this one almost unchanged with only tiny tweaks, see the commit appended below. Even in the existing code before your patch, there are likely some ways how the structure of both the C and the HTML code can be improved, and this patch clearly moves into the right direction, so just moving ahead seemed better than excessive scrutiny in this case. We can polish it further in the tree when we see the need. There is one exception. I did not yet merge the part you marked with FIXME: > puts("<table class=\"results\">"); > for (i = 0; i < sz; i++) { > + // FIXME: there has to be a way to do this without > + // truncating > + name = mandoc_strdup(r[i].names); > + name[strlen(name)-3] = '\0'; > + mandoc_asprintf(&label, "%s, section %d", > + name, r[i].sec); > + > printf(" <tr>\n" > " <td>" > - "<a class=\"Xr\" href=\"/"); > + "<a class=\"Xr\" aria-label=\"%s\" href=\"/", > + label); > if (*scriptname != '\0') > printf("%s/", scriptname); While i agree with your intention, i think it's better to consider in detail how to best do this before committing. Yours, Ingo Log Message: ----------- Improve accessibility of man.cgi(8) in various respects, in particular adding <header>, <main>, and <nav> elements and role and aria-label attributes in several places. Patch from Anna Vyalkova <cyber at sysrq dot in>, minimally tweaked by me. Modified Files: -------------- mandoc: cgi.c Revision Data ------------- Index: cgi.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/cgi.c,v retrieving revision 1.176 retrieving revision 1.177 diff -Lcgi.c -Lcgi.c -u -p -r1.176 -r1.177 --- cgi.c +++ cgi.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2014-2019, 2021 Ingo Schwarze <schwarze@usta.de> * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2022 Anna Vyalkova <cyber@sysrq.in> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -431,7 +432,8 @@ resp_searchform(const struct req *req, e { int i; - printf("<form action=\"/%s\" method=\"get\" " + printf("<header>\n" + "<form role=\"search\" action=\"/%s\" method=\"get\" " "autocomplete=\"off\" autocapitalize=\"none\">\n" " <fieldset>\n" " <legend>Manual Page Search Parameters</legend>\n", @@ -457,7 +459,7 @@ resp_searchform(const struct req *req, e /* Write section selector. */ - puts(" <select name=\"sec\">"); + puts(" <select name=\"sec\" aria-label=\"manual section\">"); for (i = 0; i < sec_MAX; i++) { printf(" <option value=\"%s\"", sec_numbers[i]); if (NULL != req->q.sec && @@ -469,7 +471,7 @@ resp_searchform(const struct req *req, e /* Write architecture selector. */ - printf( " <select name=\"arch\">\n" + printf( " <select name=\"arch\" aria-label=\"CPU architecture\">\n" " <option value=\"default\""); if (NULL == req->q.arch) printf(" selected=\"selected\""); @@ -499,7 +501,8 @@ resp_searchform(const struct req *req, e } puts(" </fieldset>\n" - "</form>"); + "</form>\n" + "</header>"); } static int @@ -557,13 +560,17 @@ pg_index(const struct req *req) resp_begin_html(200, NULL, NULL); resp_searchform(req, FOCUS_QUERY); - printf("<p>\n" + printf("<main>\n" + "<p role=\"doc-notice\" aria-label=\"usage\">\n" "This web interface is documented in the\n" - "<a class=\"Xr\" href=\"/%s%sman.cgi.8\">man.cgi(8)</a>\n" + "<a class=\"Xr\" href=\"/%s%sman.cgi.8\"" + " aria-label=\"man dot CGI, section 8\">man.cgi(8)</a>\n" "manual, and the\n" - "<a class=\"Xr\" href=\"/%s%sapropos.1\">apropos(1)</a>\n" + "<a class=\"Xr\" href=\"/%s%sapropos.1\"" + " aria-label=\"apropos, section 1\">apropos(1)</a>\n" "manual explains the query syntax.\n" - "</p>\n", + "</p>\n" + "</main>\n", scriptname, *scriptname == '\0' ? "" : "/", scriptname, *scriptname == '\0' ? "" : "/"); resp_end_html(); @@ -575,9 +582,11 @@ pg_noresult(const struct req *req, int c { resp_begin_html(code, http_msg, NULL); resp_searchform(req, FOCUS_QUERY); - puts("<p>"); + puts("<main>"); + puts("<p role=\"doc-notice\" aria-label=\"no result\">"); puts(user_msg); puts("</p>"); + puts("</main>"); resp_end_html(); } @@ -586,12 +595,14 @@ pg_error_badrequest(const char *msg) { resp_begin_html(400, "Bad Request", NULL); - puts("<h1>Bad Request</h1>\n" - "<p>\n"); + puts("<main>\n" + "<h1>Bad Request</h1>\n" + "<p role=\"doc-notice\" aria-label=\"Bad Request\">"); puts(msg); printf("Try again from the\n" "<a href=\"/%s\">main page</a>.\n" - "</p>", scriptname); + "</p>\n" + "</main>", scriptname); resp_end_html(); } @@ -599,7 +610,7 @@ static void pg_error_internal(void) { resp_begin_html(500, "Internal Server Error", NULL); - puts("<p>Internal Server Error</p>"); + puts("<main><p role=\"doc-notice\">Internal Server Error</p></main>"); resp_end_html(); } @@ -704,6 +715,7 @@ pg_searchres(const struct req *req, stru req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY); if (sz > 1) { + puts("<nav>"); puts("<table class=\"results\">"); for (i = 0; i < sz; i++) { printf(" <tr>\n" @@ -722,6 +734,7 @@ pg_searchres(const struct req *req, stru " </tr>"); } puts("</table>"); + puts("</nav>"); } if (req->q.equal || sz == 1) { @@ -743,7 +756,9 @@ resp_catman(const struct req *req, const int italic, bold; if ((f = fopen(file, "r")) == NULL) { - puts("<p>You specified an invalid manual file.</p>"); + puts("<p role=\"doc-notice\">\n" + " You specified an invalid manual file.\n" + "</p>"); return; } @@ -880,7 +895,9 @@ resp_format(const struct req *req, const int usepath; if (-1 == (fd = open(file, O_RDONLY))) { - puts("<p>You specified an invalid manual file.</p>"); + puts("<p role=\"doc-notice\">\n" + " You specified an invalid manual file.\n" + "</p>"); return; } -- To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv