]> git.plutz.net Git - webpoll/commitdiff
Squashed 'cgilite/' changes from ac4031b..f144a78
authorPaul Hänsch <paul@plutz.net>
Wed, 14 Jan 2026 05:17:52 +0000 (06:17 +0100)
committerPaul Hänsch <paul@plutz.net>
Wed, 14 Jan 2026 05:17:52 +0000 (06:17 +0100)
f144a78 add universal --debug option
8f60061 unified attibute parsing
686647c correct tests for aria-label anchors
5079618 distinct style for block quoting
751908e autocomplete controls in user forms
e6a85aa use accessibility link label for anchor links
6e9a98e Prefer absolute path when using PWD as _DATA directory (i.e. "$PWD" instead of ".")
364b5f4 markdown code cleanup
aa6ce00 Markdown Bugfix: use correct HTML escaping for heading id's (instead of URL escaping)
1ac47c1 fix bidirectional arrow
b7f8f3d bidirectional arrows
71de623 use attributes in wrapper class for fenced code blocks
0c39114 bugfix: prevent content duplication when deleting nonexist key
b8dae07 updated copyright info

git-subtree-dir: cgilite
git-subtree-split: f144a78eb6d7bbe8904d31335af0a4f148774140

cgilite.sh
common.css
db23.sh
markdown.awk
tests-markdown.sh
users.sh

index b2467c335ed55a298651e485ff84143b7dfb23ea..5e4ebbb750c3f29856cb761d3aad7d8578bc233c 100755 (executable)
@@ -3,7 +3,7 @@
 # This is CGIlite.
 # A collection of posix shell functions for writing CGI scripts.
 
-# Copyright 2017 - 2023 Paul Hänsch
+# Copyright 2017 - 2023, 2025 Paul Hänsch
 # 
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -40,14 +40,16 @@ for cgilite_arg in "$@"; do case $cgilite_arg in
   --exec=*) _EXEC="${cgilite_arg#*=}";;
   --data=*) _DATA="${cgilite_arg#*=}";;
   --base=*) _BASE="${cgilite_arg#*=}";;
+ --debug=*) DEBUG="${cgilite_arg#*=}";;
 esac; done
 unset cgilite_arg
 
 _EXEC="${_EXEC:-${0%/*}}"
-_DATA="${_DATA:-.}"
+_DATA="${_DATA:-${PWD:-.}}"
 _EXEC="${_EXEC%/}" _DATA="${_DATA%/}" _BASE="${_BASE%/}"
 
 export _EXEC _DATA _BASE
+[ -n "$DEBUG" ] && exec 2>"${DEBUG}"
 
 # Carriage Return and Line Break characters for convenience
 CR="\r"
@@ -207,7 +209,7 @@ fi
 
 PATH_INFO="$(PATH "/${PATH_INFO#${_BASE}}")"
 
-debug(){ [ $# -gt 0 ] && printf '%s\n' "$@" >&2 || tee -a /dev/stderr; }
+debug(){ [ $# -gt 0 ] && printf '%s\n' "$@" >&2 || tee -a "${DEBUG:-/dev/stderr}"; }
 [ "${DEBUG+x}" ] && env >&2
 
 # general helper functions, see GET, POST, and REF below
index 16e99f23befd1f945ee7efbd71707a48ccd367ad..77ea843ad4fdb23c34e7e50e6a1ad0ecbf7edaaa 100644 (file)
@@ -49,10 +49,11 @@ tt, code, var, samp, kbd { font-family: monospace; }
 kbd { font-style: italic; }
 
 blockquote {
-  background-color: #EEE;
   margin: .5em 0;
-  padding: 1em 2em;
+  padding: 1em;
   white-space: pre-line;
+  border: 1pt solid #888;
+  border-left-width: 8pt;
 }
 
 ul, ol { padding-left: 1.5em; }
diff --git a/db23.sh b/db23.sh
index 8ee6f4fe528ab3e96b9c2cc4bc41fe697220b099..b7ab5485c32b1f0f4a5141303b8b875124e54d77 100755 (executable)
--- a/db23.sh
+++ b/db23.sh
@@ -65,8 +65,12 @@ DB2() {
     delete|remove) key="$(STRING "$1")"
       val="${data#*"${BR}${key}"       *"${BR}"}"
       key="${data%"${BR}${key}"        *"${BR}"*}"
-      [ "${key}${BR}${val}" = "${data}" ] && return 1
-      printf '%s' "${key#"${BR}"}${BR}${val%"${BR}"}"
+      if [ "${val}" = "${data}" ]; then
+        printf %s\\n "${data}"
+        return 1
+      else
+        printf '%s' "${key#"${BR}"}${BR}${val%"${BR}"}"
+      fi
       ;;
     set|store) key="$(STRING "$1")" val=""
       shift 1
index bef97d1b7955191cb6b63af748c761d5288dea3a..d1f6616dd7aa7e93131230a25edc950900ecab5c 100755 (executable)
@@ -5,7 +5,7 @@
 # Meant to support all features of John Grubers basic Markdown
 # + a number of common extensions, mostly inspired by Pandoc Markdown
 
-# Copyright 2021 - 2023 Paul Hänsch
+# Copyright 2021 - 2024 Paul Hänsch
 # 
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -106,21 +106,6 @@ function HTML ( text ) {
   return text;
 }
 
-function URL ( text, sharp ) {
-  gsub( /&/,  "%26",  text );
-  gsub( /"/,  "%22", text );
-  gsub( /'/,  "%27", text );
-  gsub( /`/,  "%60", text );
-  gsub( /\?/,  "%3F", text );
-  if (sharp) gsub( /#/,  "%23", text );
-  gsub( /\[/,  "%5B", text );
-  gsub( /\]/,  "%5D", text );
-  gsub( / /,  "%20", text );
-  gsub( /      /,  "%09", text );
-  gsub( /\\/, "%5C", text );
-  return text;
-}
-
 function inline( line, LOCAL, len, text, code, href, guard, ret ) {
   ret = "";
   while (line !~ /^$/) {
@@ -160,8 +145,6 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
       len = RLENGTH; href = text = substr(line, 1, len);
       sub(/^\[\[/, "", href); sub(/(\|([^]]+))?\]\].*$/, "", href);
       sub(/^\[\[([^]|]+)/, "", text); sub(/\]\].*$/, "", text); sub(/^\|/, "", text);
-      # sub(/^\[\[([^]|]+)(\|([^]]+))?\]\]/, "\\1", href );
-      # sub(/^\[\[([^]|]+)(\|([^]]+))?\]\]/, "\\3", text );
       if ( ! text ) text = href;
       ret = ret "<a href=\"" HTML(href) "\">" HTML(text) "</a>"; line = substr( line, len + 1);
       continue;
@@ -174,7 +157,6 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
       continue;
 
     # quick link email
-    # } else if ( match( line, /^<[a-zA-Z0-9.!#$%&'\''*+\/=?^_`{|}~-]+@[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*>/ ) ) {
     } else if ( match( line, /^<[a-zA-Z0-9.!#$%&'\''*+\/=?^_`{|}~-]+@([a-zA-Z0-9]\.[a-zA-Z0-9]|[a-zA-Z0-9-])+>/ ) ) {
       len = RLENGTH;
       href = HTML( substr( line, 2, len - 2) );
@@ -212,8 +194,6 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
       len = RLENGTH; text = id = substr(line, 1, len);
       sub(/\n.*$/, "", text); sub(/^\[/, "", text); sub(/\] ?\[([^\n]*)\].*$/, "", text);
       sub(/\n.*$/, "",   id); sub(/^\[([^]]+)\] ?\[/, "",   id); sub(/\].*$/, "",   id);
-      # text = gensub(/^\[([^\n]+)\] ?\[([^\n]*)\].*/, "\\1", 1, text );
-      # id = gensub(/^\[([^\n]+)\] ?\[([^\n]*)\].*/, "\\2", 1,   id );
       if ( ! id ) id = text;
 
       if ( rl_href[id] && rl_title[id] ) {
@@ -231,21 +211,20 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
       }
 
     # inline images
-    } else if ( match(line, "^!" lix "\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)(\\{[a-zA-Z \t-]*\\})?") ) {
+    } else if ( match(line, "^!" lix "\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)("rattr")?") ) {
       len = RLENGTH; text = href = title = attrib = substr( line, 1, len);
 
       sub("^!\\[", "", text);
-      sub("\\]\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)(\\{[a-zA-Z \t-]*\\})?$", "", text);
+      sub("\\]\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)("rattr")?$", "", text);
 
       sub("^!" lix "\\([\n\t ]*", "", href);
-      sub("([\n\t ]+" lit ")?[\n\t ]*\\)(\\{[a-zA-Z \t-]*\\})?$", "", href);
+      sub("([\n\t ]+" lit ")?[\n\t ]*\\)("rattr")?$", "", href);
 
       sub("^!" lix "\\([\n\t ]*" lid, "", title);
-      sub("[\n\t ]*\\)(\\{[a-zA-Z \t-]*\\})?$", "", title);
+      sub("[\n\t ]*\\)("rattr")?$", "", title);
       sub("^[\n\t ]+", "", title);
 
-      sub("^!" lix "\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)", "", attrib);
-      sub(/^\{[ \t]*/, "", attrib); sub(/[ \t]*\}$/, "", attrib); gsub(/[ \t]+/, " ", attrib);
+      attrib = _attr(attrib);
 
       if ( match(href, /^<.*>$/) ) { sub(/^</, "", href); sub(/>$/, "", href); }
            if ( match(title, /^".*"$/) ) { sub(/^"/, "", title); sub(/"$/, "", title); }
@@ -266,8 +245,6 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
       len = RLENGTH; text = id = substr(line, 1, len);
       sub(/\n.*$/, "", text); sub(/^!\[/, "", text); sub(/\] ?\[([^\n]*)\].*$/, "", text);
       sub(/\n.*$/, "",   id); sub(/^!\[([^]]+)\] ?\[/, "",   id); sub(/\].*$/, "",   id);
-      # text = gensub(/^!\[([^\n]*)\] ?\[([^\n]*)\].*/, "\\1", 1, substr(line, 1, len) );
-      #   id = gensub(/^!\[([^\n]*)\] ?\[([^\n]*)\].*/, "\\2", 1, substr(line, 1, len) );
       if ( ! id ) id = text;
       if ( rl_href[id] && rl_title[id] ) {
         ret = ret "<img src=\"" HTML(rl_href[id]) "\" alt=\"" HTML(text) "\" title=\"" HTML(rl_title[id]) "\">";
@@ -345,8 +322,7 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
       continue;
 
     # Literal HTML entities
-    # } else if ( match( line, /^&([a-zA-Z]{2,32}|#[0-9]{1,7}|#[xX][0-9a-fA-F]{1,6});/) ) {
-    # mawk does not support repitition ranges
+    # mawk does not support repitition ranges (i.e. "xyz{1,10}")
     } else if ( match( line, /^&[a-zA-Z][a-zA-Z][a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?;/) ) {
       len = RLENGTH;
       ret = ret substr( line, 1, len ); line = substr(line, len + 1);
@@ -360,6 +336,9 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
     } else if ( line ~ /^-->( |$)/) {  # ignore multidash-arrow
       ret = ret "--&gt;"; line = substr(line, 4);
       continue;
+    } else if ( line ~ /^<->( |$)/) {
+      ret = ret "&harr;"; line = substr(line, 4);
+      continue;
     } else if ( line ~ /^<-( |$)/) {
       ret = ret "&larr;"; line = substr(line, 3);
       continue;
@@ -380,8 +359,7 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
   return ret;
 }
 
-function headline( hlvl, htxt, attrib, LOCAL, sec, n, HL) {
-  # match(hstack, /([0-9]+( [0-9]+){5})$/); split( substr(hstack, RSTART),  HL);
+function headline( hlvl, htxt, attrib, LOCAL, sec, n, hid, HL) {
   match(hstack, /([0-9]+( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+))$/); split( substr(hstack, RSTART),  HL);
 
   for ( n = hlvl; n <= 6; n++ ) { sec = sec (HL[n]?"</section>":""); }
@@ -389,15 +367,14 @@ function headline( hlvl, htxt, attrib, LOCAL, sec, n, HL) {
 
   hid = ""; for ( n = 2; n <= blvl; n++) { hid = hid BL[n] "/"; }
   hid = hid HL[1]; for ( n = 2; n <= hlvl; n++) { hid = hid "." HL[n] ; }
-  hid = hid ":" URL(htxt, 1);
+  hid = hid ":" HTML(htxt);  # anchor for TOC and permalink
 
-  # sub(/([0-9]+( [0-9]+){5})$/, "", hstack);
   sub(/([0-9]+( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+))$/, "", hstack);
   hstack = hstack HL[1] " " HL[2] " " HL[3] " " HL[4] " " HL[5] " " HL[6];
 
   return sec "<section class=\"" (attrib ? "h" hlvl " " attrib : "h" hlvl)  "\" id=\"" hid "\">" \
          "<h" hlvl (attrib ? " class=\"" attrib "\"" : "") ">" inline( htxt ) \
-         "<a class=\"anchor\" href=\"#" hid "\"></a>" \
+         "<a class=\"anchor\" href=\"#" hid "\" aria-label=\"#" hid "\"></a>" \
          "</h" hlvl ">\n";
 }
 
@@ -537,13 +514,10 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       # Column Count
       tmp = block; sub( "(\n.*)*$", "", tmp);
       cols = split( tmp, tread, /\+/) - 2;
-      # debug(" Cols: " gensub( "^(\\+(:?-+:?\\+)+)(\n.*)*$", "\\1", 1, block ));
 
       # table alignment
       match(block, "((:?=+:?\\+|(:-+|-+:|:-+:)\\+)+)");
       split( substr(block, RSTART, RLENGTH) , talign, /\+/ );
-      # split( gensub( "^(.*\n)?\\+((:?=+:?\\+|(:-+|-+:|:-+:)\\+)+)(\n.*)$", "\\2", "g", block ), talign, /\+/ );
-      # debug("Align: " gensub( "^(.*\n)?\\+((:?=+:?\\+|(:-+|-+:|:-+:)\\+)+)(\n.*)$", "\\2", "g", block ));
 
       for (cnt = 1; cnt <= cols; cnt++) {
              if (match(talign[cnt], /:(-+|=+):/)) talign[cnt]="center";
@@ -626,7 +600,6 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       guard = substr( block, 1, RLENGTH ); attrib = code = block;
       sub(/^[^\n]+\n/, "", code);
       sub(/^:::+[ \t]*\{?[ \t]*/, "", attrib); sub(/\}?[ \t]*\n.*$/, "", attrib);
-      # attrib = gensub(/^:::+[ \t]*\{?[ \t]*([^\}\n]*)\}?[ \t]*\n.*$/, "\\1", 1, attrib);
       gsub(/[^a-zA-Z0-9_-]+/, " ", attrib);
       gsub(/(^ | $)/, "", attrib);
       if ( match(code, "(^|\n)" guard "+(\n|$)" ) && attrib ) {
@@ -652,12 +625,12 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       guard = substr( block, 1, RLENGTH ); attrib = code = block;
       sub(/^[^\n]+\n/, "", code);
       sub(/^(~~~+|```+)[ \t]*\{?[ \t]*/, "", attrib); sub(/\}?[ \t]*\n.*$/, "", attrib);
-      # attrib = gensub(/^(~~~+|```+)[ \t]*\{?[ \t]*([^\}\n]*)\}?[ \t]*\n.*$/, "\\2", 1, attrib);
       gsub(/[^a-zA-Z0-9_-]+/, " ", attrib);
       gsub(/(^ | $)/, "", attrib);
       if ( match(code, "(^|\n)" guard "+(\n|$)" ) && attrib ) {
         len = RLENGTH; st = RSTART;
-        ret = ret "<pre><code class=\"" attrib "\">" HTML( substr(code, 1, st - 1) ) "</code></pre>\n";
+        ret = ret "<pre class=\"" attrib "\"><code class=\"" attrib "\">" \
+                        HTML( substr(code, 1, st - 1) ) "</code></pre>\n";
         block = substr( code, st + len );
         continue;
 
@@ -675,11 +648,10 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       }
 
     # First Order Heading H1 + Attrib
-    } else if ( match( block, /^([^\n]+)([ \t]*\{([^\}\n]+)\})\n===+(\n|$)/ ) ) {
+    } else if ( match( block, "^([^\n]+)([ \t]*"rattr")\n===+(\n|$)" ) ) {
       len = RLENGTH; text = attrib = block;
       sub(/([ \t]*\{([^\}\n]+)\})\n===+(\n.*)?$/, "", text);
-      sub(/\}\n===+(\n.*)?$/, "", attrib); sub(/^([^\n]+)[ \t]*\{/, "", attrib);
-      gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib);
+      attrib = _attr(attrib);
 
       ret = ret headline(1, text, attrib) ; block = substr( block, len + 1 );
       continue;
@@ -693,11 +665,10 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       continue;
 
     # Second Order Heading H2 + Attrib
-    } else if ( match( block, /^([^\n]+)([ \t]*\{([^\}\n]+)\})\n---+(\n|$)/ ) ) {
+    } else if ( match( block, "^([^\n]+)([ \t]*"rattr")\n---+(\n|$)" ) ) {
       len = RLENGTH; text = attrib = block;
       sub(/([ \t]*\{([^\}\n]+)\})\n---+(\n.*)?$/, "", text);
-      sub(/\}\n---+(\n.*)?$/, "", attrib); sub(/^([^\n]+)[ \t]*\{/, "", attrib);
-      gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib);
+      attrib = _attr(attrib);
 
       ret = ret headline(2, text, attrib) ; block = substr( block, len + 1);
       continue;
@@ -711,27 +682,21 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       continue;
 
     # # Nth Order Heading H1 H2 H3 H4 H5 H6 + Attrib
-    # } else if ( match( block, /^(##?#?#?#?#?)[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[ \t]*[^ \t\n#])+)[ \t]*#*[ \t]*\{[a-zA-Z \t-]*\}(\n|$)/ ) ) {
-    } else if ( match( block, /^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*[\t ]*\{[\ta-zA-Z -]*\}(\n|$)/ ) ) {
+    } else if ( match( block, "^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*[\t ]*"rattr"(\n|$)" ) ) {
       len = RLENGTH; text = attrib = substr(block, 1, len);
       match(block, /^##?#?#?#?#?[^#]/); n = RLENGTH - 1;
-      # sub(/^(##?#?#?#?#?)[ \t]*/, "", text);  # not working in mawk
       text = substr(text, n + 1); sub(/^[ \t]*/, "", text);
       sub(/[ \t]*#*([ \t]*\{([a-zA-Z \t-]*)\})(\n.*)?$/, "", text);
 
-      sub(/^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*[\t ]*\{/, "", attrib);
-      sub(/\}(\n.*)?$/, "", attrib);
-      gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib);
+      attrib = _attr(attrib);
 
       ret = ret headline( n, text, attrib ); block = substr( block, len + 1);
       continue;
 
     # Nth Order Heading H1 H2 H3 H4 H5 H6
-    # } else if ( match( block, /^(##?#?#?#?#?)[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[ \t]*[^ \t\n#])+)[ \t]*#*(\n|$)/ ) ) {
     } else if ( match( block, /^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*(\n|$)/ ) ) {
       len = RLENGTH; text = substr(block, 1, len);
       match(block, /^##?#?#?#?#?[^#]/); n = RLENGTH - 1;
-      # sub(/^(##?#?#?#?#?)[ \t]+/, "", text);  # not working in mawk
       text = substr(text, n + 1); sub(/^[ \t]*/, "", text);
       sub(/[ \t]*#*(\n.*)?$/, "", text);
 
@@ -739,7 +704,7 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       continue;
 
     # block images (wrapped in <figure>)
-    } else if ( match(block, "^!" lix "\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)(\\{[a-zA-Z \t-]*\\})?(\n|$)") ) {
+    } else if ( match(block, "^!" lix "\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)("rattr")?(\n|$)") ) {
       len = RLENGTH; text = href = title = attrib = substr( block, 1, len);
 
       sub("^!\\[", "", text);
@@ -752,9 +717,7 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       sub("[\n\t ]*\\)(\\{[a-zA-Z \t-]*\\})?(\n.*)?$", "", title);
       sub("^[\n\t ]+", "", title);
 
-      sub("^!" lix "\\([\n\t ]*" lid "([\n\t ]+" lit ")?[\n\t ]*\\)", "", attrib);
-      sub("(\n.*)?$", "", attrib);
-      sub(/^\{[ \t]*/, "", attrib); sub(/[ \t]*\}$/, "", attrib); gsub(/[ \t]+/, " ", attrib);
+      attrib = _attr(attrib);
 
       if ( match(href, /^<.*>$/) ) { sub(/^</, "", href); sub(/>$/, "", href); }
            if ( match(title, /^".*"$/) ) { sub(/^"/, "", title); sub(/"$/, "", title); }
@@ -775,8 +738,6 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       len = RLENGTH; text = id = block;
       sub(/(\n.*)?$/, "", text); sub( /^!\[/, "", text); sub(/\] ?\[([^\n]*)\]$/, "", text);
       sub(/(\n.*)?$/, "",   id); sub( /^!\[([^\n]*)\] ?\[/, "",   id); sub(/\]$/, "",   id);
-      # text = gensub(/^!\[([^\n]*)\] ?\[([^\n]*)\](\n.*)?$/, "\\1", 1, block);
-      #   id = gensub(/^!\[([^\n]*)\] ?\[([^\n]*)\](\n.*)?$/, "\\2", 1, block);
       if ( ! id ) id = text;
       if ( rl_href[id] && rl_title[id] ) {
         ret = ret "<figure data-src=\"" HTML(rl_href[id]) "\">" \
@@ -801,7 +762,6 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
     } else if ( match( block, /^<<(([^>]|>[^>])+)>>(\n|$)/ ) ) {
       len = RLENGTH; text = block;
       sub(/^<</, "", text); sub(/>>(\n.*)?$/, "", text);
-      # text = gensub(/^<<(([^>]|>[^>])+)>>(\n.*)?$/, "\\1", 1, block);
       ret = ret "<code class=\"macro\">" HTML(text) "</code>" ; block = substr(block, len + 1);
       continue;
 
@@ -844,7 +804,6 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
       continue;
 
     # Horizontal rule
-    # } else if ( match( block, /(^|\n) ? ? ?((\* *){3,}|(- *){3,}|(_ *){3,})($|\n)/) ) {
     } else if ( match( block, /(^|\n) ? ? ?((\* *)(\* *)(\* *)(\* *)*|(- *)(- *)(- *)(- *)*|(_ *)(_ *)(_ *)(_ *)*)($|\n)/) ) {
       len = RLENGTH; st = RSTART;
       ret = ret _block(substr(block, 1, st - 1)) "<hr>\n"; block = substr(block, st + len);
@@ -866,7 +825,6 @@ function _startlist(block, type, mark, exclude, LOCAL, st, len, list, indent, it
     st = RSTART; len = RLENGTH; list = substr( block, st, len);
 
     sub("^\n", "", list); match(list, "^(   |  | )?"); indent = RLENGTH;
-    # gsub( "(^|\n) {0," indent "}", "\n", list); sub("^\n", "", list);
     # emulate greedy range matcher for mawk
     it = "("; while ( indent > 0 ) { for (k = indent; k > 0; k--) { it = it " "; } it = it "|"; indent--; }
     sub(/\|$/, ")?", it); sub(/^\($/, "", it);
@@ -897,7 +855,6 @@ function _list (block, mark, p, LOCAL, len, st, text, indent, it, task) {
   st = (RLENGTH == -1) ? length(block) + 1 : RSTART;
   text = substr(block, 1, st); block = substr(block, st + 1);
 
-  # gsub("\n {0," indent "}", "\n", text);
   # emulate greedy range matcher for mawk
   it = "("; while ( indent > 0 ) { for (k = indent; k > 0; k--) { it = it " "; } it = it "|"; indent--; }
   sub(/\|$/, ")?", it); sub(/^\($/, "", it);
@@ -931,7 +888,6 @@ function _dlist (block, LOCAL, len, st, text, indent, it, p) {
     sub( "^([ \t]*\n)*", "", text);
     match(text, "^ ? ? ?:(\t| +)"); indent = RLENGTH;
     sub( "^ ? ? ?:(\t| +)", "", text);
-    # gsub( "(^|\n) {0," indent "}", "\n", text );
     # emulate greedy range matcher for mawk
     it = "("; while ( indent > 0 ) { for (k = indent; k > 0; k--) { it = it " "; } it = it "|"; indent--; }
     sub(/\|$/, ")?", it); sub(/^\($/, "", it);
@@ -945,12 +901,18 @@ function _dlist (block, LOCAL, len, st, text, indent, it, p) {
   }
 }
 
+function _attr (attrib) {
+  if ( sub(/.*\{[ \t.#]*/, "", attrib) ) if ( sub(/[ \t]*\}(\n.*)?$/, "", attrib) ) {
+    gsub(/[ \t.#]+/, " ", attrib);
+    return attrib;
+  } else return "";
+}
+
 BEGIN {
   # Global Vars
   file = ""; rl_href[""] = ""; rl_title[""] = "";
   if (ENVIRON["MD_HTML"] == "true") { AllowHTML = "true"; }
   HL[1] = 0; HL[2] = 0; HL[3] = 0; HL[4] = 0; HL[5] = 0; HL[6] = 0;
-  # hls = "0 0 0 0 0 0";
 
   # Universal Patterns
   nu = "([^_\\\\]|\\\\.|_[[:alnum:]])"  # not underline (except when escaped, or inside a word)
@@ -960,6 +922,8 @@ BEGIN {
   iea =    "\\*([^*[:space:]]|[^*[:space:]]" na "*[^*[:space:]])\\*"     # inner <em> (asterisk)
   isa = "\\*\\*([^*[:space:]]|[^*[:space:]]" na "*[^*[:space:]])\\*\\*"  # inner <strong> (asterisk)
 
+  rattr = "\\{[ \t]*([.#]?([a-zA-Z0-9]+-)*[a-zA-Z0-9]+[ \t]+)*([.#]?([a-zA-Z0-9]+-)*[a-zA-Z0-9]+)[ \t]*\\}"
+
   lix="\\[(\\\\[^\n]|[^]\n\\\\[])*\\]"  # link text
   lid="(<(\\\\[^\n]|[^\n<>\\\\])*>|(\\\\.|[^()\"'\\\\])+|([^<\n\t ()\\\\]|\\\\[^\n])(\\\\[\n]|[^\n\t \\(\\)\\\\])*)"  # link dest
   lit="(\"(\\\\.|[^\"\\\\])*\"|'(\\\\.|[^'\\\\])*'|\\((\\\\.|[^\\(\\)\\\\])*\\))"  # link text
@@ -974,7 +938,6 @@ BEGIN {
   # Fill array of reference links
   f = file; rl_id;
   re_reflink = "(^|\n) ? ? ?\\[([^]\n]+)\\]: ([^ \t\n]+)(\n?[ \t]+(\"([^\"]+)\"|'([^']+)'|\\(([^)]+)\\)))?(\n|$)";
-  # /(^|\n) ? ? ?\[([^]\n]+)\]: ([^ \t\n]+)(\n?[ \t]+("([^"]+)"|'([^']+)'|\(([^)]+)\)))?(\n|$)/
   while ( match(f, re_reflink ) ) {
     tt = th = ti = substr(f, RSTART, RLENGTH); f = substr(f, RSTART + RLENGTH);
     sub("(^|\n) ? ? ?\\[", "", ti); sub("\\]: ([^ \t\n]+)(\n?[ \t]+(\"([^\"]+)\"|'([^']+)'|\\(([^)]+)\\)))?(\n.*)?$", "", ti);
@@ -983,16 +946,11 @@ BEGIN {
       sub("(^|\n) ? ? ?\\[([^]\n]+)\\]: ([^ \t\n]+)", "", tt); sub("^\n?[ \t]+", "", tt); sub("(\n.*)?$", "", tt);
     } else { tt = ""; }
     rl_id = ti; rl_href[rl_id] = th; rl_title[rl_id] = tt;
-    # rl_id           = gensub( re_reflink, "\\2", 1, substr(f, RSTART, RLENGTH) );
-    # rl_href[rl_id]  = gensub( re_reflink, "\\3", 1, substr(f, RSTART, RLENGTH) );
-    # rl_title[rl_id] = gensub( re_reflink, "\\5", 1, substr(f, RSTART, RLENGTH) );
-    # f = substr(f, RSTART + RLENGTH);
     rl_title[rl_id] = substr( rl_title[rl_id], 2, length(rl_title[rl_id]) - 2 );
     if ( rl_href[rl_id] ~ /<.*>/ ) rl_href[rl_id] = substr( rl_href[rl_id], 2, length(rl_href[rl_id]) - 2 );
   }
   # Clear reflinks from File
   while( gsub(re_reflink, "\n", file ) );
-  # for (n in rl_href) { debug(n " | " rl_href[n] " | " rl_title[n] ); }
 
   # Run Block Processing -> The Actual Markdown!
   printf "%s", _nblock( file );
index 6df4224d131d6beb7d2f1cab50ab2953517f18aa..37943215ad13785906d6a310f742423d01d26920 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-runtimes="gawk busybox mawk goawk"
+runtimes="${runtimes:-gawk busybox mawk goawk}"
 
 BR='
 '
@@ -93,7 +93,7 @@ assert '[Wikipedia](<http://de.wikipedia.org> "Online Encyclopedia")' "<p><a hre
 assert ' ![Testbild](Test Bild.jpg)' '<p> <img src="Test Bild.jpg" alt="Testbild"></p>' "inline image"
 assert ' ![Testbild](Test Bild.jpg "German Television *test* image ca. 1994")' '<p> <img src="Test Bild.jpg" alt="Testbild" title="German Television *test* image ca. 1994"></p>' "inline image"
 assert ' ![Testbild *ARD*](Test Bild.jpg){tv ard function-check}' '<p> <img src="Test Bild.jpg" alt="Testbild *ARD*" class="tv ard function-check"></p>' "inline image"
-# assert ' ![Testbild *ARD*](Test Bild.jpg){#tv .ard .function-check}' '<p> <img src="Test Bild.jpg" alt="Testbild *ARD*" class="tv ard check"></p>' "inline image id/classes"
+assert ' ![Testbild *ARD*](Test Bild.jpg){#tv .ard .function-check}' '<p> <img src="Test Bild.jpg" alt="Testbild *ARD*" class="tv ard function-check"></p>' "inline image id/classes"
 
 assert '[![Wikipedia](wikilogo.png)](<http://de.wikipedia.org>)'\
        '<p><a href="http://de.wikipedia.org"><img src="wikilogo.png" alt="Wikipedia"></a></p>'\
@@ -185,7 +185,7 @@ not be
 *formatted*
 but &shy; <escaped>
 ```' \
-'<pre><code class="tag code">fenced code will
+'<pre class="tag code"><code class="tag code">fenced code will
 not be
 *formatted*
 but &amp;shy; &lt;escaped&gt;</code></pre>' \
@@ -219,45 +219,45 @@ assert '![Testbild *ARD*](Test Bild.jpg){tv ard function-check}' \
 # Headings
 assert 'Heading first Order
 ============' \
-'<section class="h1" id="1:Heading%20first%20Order"><h1>Heading first Order<a class="anchor" href="#1:Heading%20first%20Order"></a></h1>
+'<section class="h1" id="1:Heading first Order"><h1>Heading first Order<a class="anchor" href="#1:Heading first Order" aria-label="#1:Heading first Order"></a></h1>
 </section>' \
 'Heading h1'
 
 assert 'Heading first Order {.foo #bar}
 ============' \
-'<section class="h1 foo bar" id="1:Heading%20first%20Order"><h1 class="foo bar">Heading first Order<a class="anchor" href="#1:Heading%20first%20Order"></a></h1>
+'<section class="h1 foo bar" id="1:Heading first Order"><h1 class="foo bar">Heading first Order<a class="anchor" href="#1:Heading first Order" aria-label="#1:Heading first Order"></a></h1>
 </section>' \
 'Heading h1 + attributes'
 
 assert 'Heading second Order
 ------------' \
-'<section class="h2" id="0.1:Heading%20second%20Order"><h2>Heading second Order<a class="anchor" href="#0.1:Heading%20second%20Order"></a></h2>
+'<section class="h2" id="0.1:Heading second Order"><h2>Heading second Order<a class="anchor" href="#0.1:Heading second Order" aria-label="#0.1:Heading second Order"></a></h2>
 </section>' \
 'Heading h2'
 
 assert 'Heading second Order {.foo #bar}
 ------------' \
-'<section class="h2 foo bar" id="0.1:Heading%20second%20Order"><h2 class="foo bar">Heading second Order<a class="anchor" href="#0.1:Heading%20second%20Order"></a></h2>
+'<section class="h2 foo bar" id="0.1:Heading second Order"><h2 class="foo bar">Heading second Order<a class="anchor" href="#0.1:Heading second Order" aria-label="#0.1:Heading second Order"></a></h2>
 </section>' \
 'Heading h2 + attributes'
 
 assert '#### Heading four' \
-'<section class="h4" id="0.0.0.1:Heading%20four"><h4>Heading four<a class="anchor" href="#0.0.0.1:Heading%20four"></a></h4>
+'<section class="h4" id="0.0.0.1:Heading four"><h4>Heading four<a class="anchor" href="#0.0.0.1:Heading four" aria-label="#0.0.0.1:Heading four"></a></h4>
 </section>' \
 'Heading arbitrary'
 
 assert '###Heading three ######' \
-'<section class="h3" id="0.0.1:Heading%20three"><h3>Heading three<a class="anchor" href="#0.0.1:Heading%20three"></a></h3>
+'<section class="h3" id="0.0.1:Heading three"><h3>Heading three<a class="anchor" href="#0.0.1:Heading three" aria-label="#0.0.1:Heading three"></a></h3>
 </section>' \
 'Heading arbitrary'
 
 assert '### Heading three ## {foo bar}' \
-'<section class="h3 foo bar" id="0.0.1:Heading%20three"><h3 class="foo bar">Heading three<a class="anchor" href="#0.0.1:Heading%20three"></a></h3>
+'<section class="h3 foo bar" id="0.0.1:Heading three"><h3 class="foo bar">Heading three<a class="anchor" href="#0.0.1:Heading three" aria-label="#0.0.1:Heading three"></a></h3>
 </section>' \
 'Heading arbitrary + attributes'
 
 assert '# Heading \# # {foo bar}' \
-'<section class="h1 foo bar" id="1:Heading%20%5C%23"><h1 class="foo bar">Heading #<a class="anchor" href="#1:Heading%20%5C%23"></a></h1>
+'<section class="h1 foo bar" id="1:Heading &#x5C;#"><h1 class="foo bar">Heading #<a class="anchor" href="#1:Heading &#x5C;#" aria-label="#1:Heading &#x5C;#"></a></h1>
 </section>' \
 'Heading arbitrary + attributes'
 
@@ -395,11 +395,11 @@ sub bar
 
 ##sub2 bar {x}
 ' \
-'<section class="h2" id="0.1:foo"><h2>foo<a class="anchor" href="#0.1:foo"></a></h2>
-</section><section class="h1" id="1:bar"><h1>bar<a class="anchor" href="#1:bar"></a></h1>
-<section class="h2" id="1.1:sub%20bar"><h2>sub bar<a class="anchor" href="#1.1:sub%20bar"></a></h2>
-<section class="h3" id="1.1.1:sub%20sub%20sub"><h3>sub sub sub<a class="anchor" href="#1.1.1:sub%20sub%20sub"></a></h3>
-</section></section><section class="h2 x" id="1.2:sub2%20bar"><h2 class="x">sub2 bar<a class="anchor" href="#1.2:sub2%20bar"></a></h2>
+'<section class="h2" id="0.1:foo"><h2>foo<a class="anchor" href="#0.1:foo" aria-label="#0.1:foo"></a></h2>
+</section><section class="h1" id="1:bar"><h1>bar<a class="anchor" href="#1:bar" aria-label="#1:bar"></a></h1>
+<section class="h2" id="1.1:sub bar"><h2>sub bar<a class="anchor" href="#1.1:sub bar" aria-label="#1.1:sub bar"></a></h2>
+<section class="h3" id="1.1.1:sub sub sub"><h3>sub sub sub<a class="anchor" href="#1.1.1:sub sub sub" aria-label="#1.1.1:sub sub sub"></a></h3>
+</section></section><section class="h2 x" id="1.2:sub2 bar"><h2 class="x">sub2 bar<a class="anchor" href="#1.2:sub2 bar" aria-label="#1.2:sub2 bar"></a></h2>
 </section></section>' \
 'Headline Nesting'
 
@@ -532,8 +532,8 @@ Markdown.awk can run in GNU awk (`gawk`) and in Busybox awk. It is _not_ fully P
 Tests
 -----
 [Link with Title](https://en.wikipedia.org/wiki/Markdown "Markdown in Wikipedia"), *emphasis*, **strong**, **strong containing *emphasis***, `inline code`, `` code with `backticks` ``. See more tests [here](./tests/).' \
-'<section class="h1" id="1:Markdown.awk"><h1>Markdown.awk<a class="anchor" href="#1:Markdown.awk"></a></h1>
-<section class="h2" id="1.1:Supported%20Features%20/%20TODO:"><h2>Supported Features / TODO:<a class="anchor" href="#1.1:Supported%20Features%20/%20TODO:"></a></h2>
+'<section class="h1" id="1:Markdown.awk"><h1>Markdown.awk<a class="anchor" href="#1:Markdown.awk" aria-label="#1:Markdown.awk"></a></h1>
+<section class="h2" id="1.1:Supported Features / TODO:"><h2>Supported Features / TODO:<a class="anchor" href="#1.1:Supported Features / TODO:" aria-label="#1.1:Supported Features / TODO:"></a></h2>
 <ul>
 <li class="task done"><input type=checkbox disabled checked> done</li>
 <li class="task pending"><input type=checkbox disabled> todo</li>
@@ -541,7 +541,7 @@ Tests
 <li>?  unsure (whether to implement)</li>
 <li class="task partial"><input type=checkbox disabled> partial</li>
 </ul>
-<section class="h3" id="1.1.1:Basic%20Markdown%20-%20Block%20elements:"><h3>Basic Markdown - Block elements:<a class="anchor" href="#1.1.1:Basic%20Markdown%20-%20Block%20elements:"></a></h3>
+<section class="h3" id="1.1.1:Basic Markdown - Block elements:"><h3>Basic Markdown - Block elements:<a class="anchor" href="#1.1.1:Basic Markdown - Block elements:" aria-label="#1.1.1:Basic Markdown - Block elements:"></a></h3>
 <ul>
 <li class="task done"><input type=checkbox disabled checked><p> Paragraphs</p>
 <ul>
@@ -557,7 +557,7 @@ Tests
 <li class="task done"><input type=checkbox disabled checked> Horizontal rules</li>
 <li class="task done"><input type=checkbox disabled checked> Verbatim HTML block (disabled by default)</li>
 </ul>
-</section><section class="h3" id="1.1.2:Basic%20Markdown%20-%20Inline%20elements:"><h3>Basic Markdown - Inline elements:<a class="anchor" href="#1.1.2:Basic%20Markdown%20-%20Inline%20elements:"></a></h3>
+</section><section class="h3" id="1.1.2:Basic Markdown - Inline elements:"><h3>Basic Markdown - Inline elements:<a class="anchor" href="#1.1.2:Basic Markdown - Inline elements:" aria-label="#1.1.2:Basic Markdown - Inline elements:"></a></h3>
 <ul>
 <li class="task done"><input type=checkbox disabled checked> Links</li>
 <li class="task done"><input type=checkbox disabled checked> Reference style links</li>
@@ -571,7 +571,7 @@ Tests
 </ul>
 <p>NOTE: Set the environment variable <code>MD_HTML=true</code> to enable verbatim HTML</p>
 
-</section><section class="h3" id="1.1.3:Extensions%20-%20Block%20elements:"><h3>Extensions - Block elements:<a class="anchor" href="#1.1.3:Extensions%20-%20Block%20elements:"></a></h3>
+</section><section class="h3" id="1.1.3:Extensions - Block elements:"><h3>Extensions - Block elements:<a class="anchor" href="#1.1.3:Extensions - Block elements:" aria-label="#1.1.3:Extensions - Block elements:"></a></h3>
 <ul>
 <li class="task done"><input type=checkbox disabled checked> Automatic &lt;section&gt;-wrapping (custom)</li>
 <li><p> ?  Heading identifiers (php md, pandoc)</p>
@@ -610,7 +610,7 @@ Tests
 <li class="task done"><input type=checkbox disabled checked> Metadata blocks (custom)</li>
 <li class="task done"><input type=checkbox disabled checked> Fenced Divs (pandoc)</li>
 </ul>
-</section><section class="h3" id="1.1.4:Extensions%20-%20Inline%20elements:"><h3>Extensions - Inline elements:<a class="anchor" href="#1.1.4:Extensions%20-%20Inline%20elements:"></a></h3>
+</section><section class="h3" id="1.1.4:Extensions - Inline elements:"><h3>Extensions - Inline elements:<a class="anchor" href="#1.1.4:Extensions - Inline elements:" aria-label="#1.1.4:Extensions - Inline elements:"></a></h3>
 <ul>
 <li class="task done"><input type=checkbox disabled checked> Ignore embedded_underscores (php md, pandoc)</li>
 <li class="task done"><input type=checkbox disabled checked> <del>strikeout</del> (pandoc)</li>
@@ -632,10 +632,10 @@ Tests
 <li class="task pending"><input type=checkbox disabled> Automatic em-dash / en-dash</li>
 <li class="task done"><input type=checkbox disabled checked> Automatic &rarr; Arrows &larr; (custom)</li>
 </ul>
-</section></section><section class="h2" id="1.2:Compatibility"><h2>Compatibility<a class="anchor" href="#1.2:Compatibility"></a></h2>
+</section></section><section class="h2" id="1.2:Compatibility"><h2>Compatibility<a class="anchor" href="#1.2:Compatibility" aria-label="#1.2:Compatibility"></a></h2>
 <p>Markdown.awk can run in GNU awk (<code>gawk</code>) and in Busybox awk. It is <em>not</em> fully POSIX compliant and does not run in <code>mawk</code> or <code>nawk</code>. In particular it makes heavy use of the <code>gensub()</code> function and its ability to use paranthesized subexpressions in the replacement text. This feature is not available in the POSIX specified <code>sub()</code> and <code>gsub()</code> functions. Hence it cannot be replaced without effort.</p>
 
-</section><section class="h2" id="1.3:Tests"><h2>Tests<a class="anchor" href="#1.3:Tests"></a></h2>
+</section><section class="h2" id="1.3:Tests"><h2>Tests<a class="anchor" href="#1.3:Tests" aria-label="#1.3:Tests"></a></h2>
 <p><a href="https://en.wikipedia.org/wiki/Markdown" title="Markdown in Wikipedia">Link with Title</a>, <em>emphasis</em>, <strong>strong</strong>, <strong>strong containing <em>emphasis</em></strong>, <code>inline code</code>, <code>code with `backticks`</code>. See more tests <a href="./tests/">here</a>.</p>
 </section></section>' \
 'Full Page (cgilite markdown)'
@@ -718,15 +718,15 @@ Term 2
 
     1.  first list item
     2.  second list item' \
-'<section class="h1" id="1:Headline%20First%20Order"><h1>Headline First Order<a class="anchor" href="#1:Headline%20First%20Order"></a></h1>
-<section class="h2" id="1.1:Headline%20Second%20Order"><h2>Headline Second Order<a class="anchor" href="#1.1:Headline%20Second%20Order"></a></h2>
+'<section class="h1" id="1:Headline First Order"><h1>Headline First Order<a class="anchor" href="#1:Headline First Order" aria-label="#1:Headline First Order"></a></h1>
+<section class="h2" id="1.1:Headline Second Order"><h2>Headline Second Order<a class="anchor" href="#1.1:Headline Second Order" aria-label="#1.1:Headline Second Order"></a></h2>
 <pre><code>Code Block
 with indentation</code></pre>
-<blockquote><section class="h2" id="1/0.1:Blockquote"><h2>Blockquote<a class="anchor" href="#1/0.1:Blockquote"></a></h2>
+<blockquote><section class="h2" id="1/0.1:Blockquote"><h2>Blockquote<a class="anchor" href="#1/0.1:Blockquote" aria-label="#1/0.1:Blockquote"></a></h2>
 <p>like in an email</p>
 </section></blockquote>
 
-<section class="h3" id="1.1.1:Headline%203rd%20order"><h3>Headline 3rd order<a class="anchor" href="#1.1.1:Headline%203rd%20order"></a></h3>
+<section class="h3" id="1.1.1:Headline 3rd order"><h3>Headline 3rd order<a class="anchor" href="#1.1.1:Headline 3rd order" aria-label="#1.1.1:Headline 3rd order"></a></h3>
 <ul>
 <li>unordered List</li>
 </ul>
@@ -762,7 +762,7 @@ list item.</p>
 </ul>
 <hr>
 
-<pre><code class="blue">Fenced Code Block
+<pre class="blue"><code class="blue">Fenced Code Block
 # with verbatim Text
 `and an attribute`</code></pre>
 <div class="line-block">The limerick packs laughs anatomical<br>
@@ -963,7 +963,7 @@ For additional examples, regarding permanent installation and configuration in w
 
 Syntax
 ------
-The wiki syntax is based on John Grubers [Markdown](https://daringfireball.net/projects/markdown/) with extensions borrowed from [Pandoc](https://pandoc.org/MANUAL%202.html#pandocs-markdown) and [PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/). The Markdown parser is provided by [Cgilite](/software/cgilite/) and its full documentation can be looked at [here](/software/cgilite/markdown/).
+The wiki syntax is based on John Grubers [Markdown](https://daringfireball.net/projects/markdown/) with extensions borrowed from [Pandoc](https://pandoc.org/MANUAL 2.html#pandocs-markdown) and [PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/). The Markdown parser is provided by [Cgilite](/software/cgilite/) and its full documentation can be looked at [here](/software/cgilite/markdown/).
 
 <<include --nolink /[wiki]/editorhelp/>>
 
@@ -1017,7 +1017,7 @@ How to write:
  - [Macros](dev-macros/)
  - [Handlers](dev-handlers/)
  - [Parsers](dev-parsers/)' \
-'<section class="h1" id="1:Shellwiki"><h1>Shellwiki<a class="anchor" href="#1:Shellwiki"></a></h1>
+'<section class="h1" id="1:Shellwiki"><h1>Shellwiki<a class="anchor" href="#1:Shellwiki" aria-label="#1:Shellwiki"></a></h1>
 <p>Shellwiki is a Wiki and Content Management System with minimal dependencies. It can run on embedded devices, as well as full size web servers.  Its goals are:</p>
 <ul>
 <li><p><strong>easy deployment</strong></p>
@@ -1054,7 +1054,7 @@ interface. It aims to be secure and predictable. Extensions can
 be written and modified by system administrators.  </p>
 </li>
 </ul>
-<code class="macro">toc 2 2</code><section class="h2" id="1.1:Features"><h2>Features<a class="anchor" href="#1.1:Features"></a></h2>
+<code class="macro">toc 2 2</code><section class="h2" id="1.1:Features"><h2>Features<a class="anchor" href="#1.1:Features" aria-label="#1.1:Features"></a></h2>
 <ul>
 <li><p><strong>Markdown Wiki Syntax</strong></p>
 
@@ -1149,7 +1149,7 @@ visitors into handling GDPR &quot;consent&quot; forms.</p>
 </ul>
 </li>
 </ul>
-</section><section class="h2" id="1.2:Dependencies"><h2>Dependencies<a class="anchor" href="#1.2:Dependencies"></a></h2>
+</section><section class="h2" id="1.2:Dependencies"><h2>Dependencies<a class="anchor" href="#1.2:Dependencies" aria-label="#1.2:Dependencies"></a></h2>
 <p>Shellwiki is based on <a href="/software/cgilite/">cgilite</a>, which is included in the installation. It is written in posix compliant shell script, and the markdown renderer is written in <del>posix compliant</del> AWK. The entire wiki system can run with nothing more than a busybox. In fact it can be served from the rescue shell in a Debian initrd, or from an OpenWRT router.</p>
 
 <p><strong>Its precise requirements are:</strong></p>
@@ -1172,7 +1172,7 @@ visitors into handling GDPR &quot;consent&quot; forms.</p>
 <li><p><em>Optional:</em> Sendmail for sending password reminders, etc.</p>
 </li>
 </ul>
-</section><section class="h2" id="1.3:Installation"><h2>Installation<a class="anchor" href="#1.3:Installation"></a></h2>
+</section><section class="h2" id="1.3:Installation"><h2>Installation<a class="anchor" href="#1.3:Installation" aria-label="#1.3:Installation"></a></h2>
 <p>Also see &rarr; <a href="installation/">installation/</a></p>
 
 <p>You can try out shellwiki right now using busybox:</p>
@@ -1181,10 +1181,10 @@ visitors into handling GDPR &quot;consent&quot; forms.</p>
 ~$ _DATA=~/wikidata busybox nc -llp 1080 -e ~/shellwiki/index.cgi</code></pre>
 <p>For additional examples, regarding permanent installation and configuration in webservers see <a href="installation/">installation/</a>.</p>
 
-</section><section class="h2" id="1.4:Syntax"><h2>Syntax<a class="anchor" href="#1.4:Syntax"></a></h2>
-<p>The wiki syntax is based on John Grubers <a href="https://daringfireball.net/projects/markdown/">Markdown</a> with extensions borrowed from <a href="https://pandoc.org/MANUAL%202.html#pandocs-markdown">Pandoc</a> and <a href="https://michelf.ca/projects/php-markdown/extra/">PHP Markdown Extra</a>. The Markdown parser is provided by <a href="/software/cgilite/">Cgilite</a> and its full documentation can be looked at <a href="/software/cgilite/markdown/">here</a>.</p>
+</section><section class="h2" id="1.4:Syntax"><h2>Syntax<a class="anchor" href="#1.4:Syntax" aria-label="#1.4:Syntax"></a></h2>
+<p>The wiki syntax is based on John Grubers <a href="https://daringfireball.net/projects/markdown/">Markdown</a> with extensions borrowed from <a href="https://pandoc.org/MANUAL 2.html#pandocs-markdown">Pandoc</a> and <a href="https://michelf.ca/projects/php-markdown/extra/">PHP Markdown Extra</a>. The Markdown parser is provided by <a href="/software/cgilite/">Cgilite</a> and its full documentation can be looked at <a href="/software/cgilite/markdown/">here</a>.</p>
 
-<code class="macro">include --nolink /[wiki]/editorhelp/</code></section><section class="h2" id="1.5:Macros"><h2>Macros<a class="anchor" href="#1.5:Macros"></a></h2>
+<code class="macro">include --nolink /[wiki]/editorhelp/</code></section><section class="h2" id="1.5:Macros"><h2>Macros<a class="anchor" href="#1.5:Macros" aria-label="#1.5:Macros"></a></h2>
 <p>Also see &rarr; <a href="macros/">macros/</a></p>
 
 <p>In addition to the Markdown syntax, wiki pages can include Macros, which perform additional functions on a page, like generating an image gallery, including parts of other pages, etc. Macros make Shellwiki truly dynamic and flexible.</p>
@@ -1196,14 +1196,14 @@ visitors into handling GDPR &quot;consent&quot; forms.</p>
 
 <p>Macros are the most easy to write type of extension. See <a href="macros/">Macros</a> for a full list of available macros.</p>
 
-</section><section class="h2" id="1.6:Themes"><h2>Themes<a class="anchor" href="#1.6:Themes"></a></h2>
+</section><section class="h2" id="1.6:Themes"><h2>Themes<a class="anchor" href="#1.6:Themes" aria-label="#1.6:Themes"></a></h2>
 <p>Also see &rarr; <a href="theming/">theming/</a></p>
 
 <p>While Shellwiki supports plugins for <a href="dev-theming/">theming</a>, it&#x27;s apearance can mostly be configured by the user. Pages can be configured to use custom CSS files. In addition page headers and footers are themselves wiki pages which can be modified to add menus, custom logos, links, etc. The same goes for error pages.</p>
 
 <p>For an example, see the <a href="/[wiki]/">technical pages</a> for this wiki.</p>
 
-</section><section class="h2" id="1.7:Multiple%20Languages"><h2>Multiple Languages<a class="anchor" href="#1.7:Multiple%20Languages"></a></h2>
+</section><section class="h2" id="1.7:Multiple Languages"><h2>Multiple Languages<a class="anchor" href="#1.7:Multiple Languages" aria-label="#1.7:Multiple Languages"></a></h2>
 <p>To enable a multilingual setup you must set a default language in your configuration environment:</p>
 
 <pre><code>export LANGUAGE_DEFAULT=en</code></pre>
@@ -1215,12 +1215,12 @@ visitors into handling GDPR &quot;consent&quot; forms.</p>
 
 <p>Header, footer, and error pages will be included from their respective language version, as will all macro includes, etc. Should a page not exist in a given language, the default page will be displayed instead. However, included elements will still be taken from the respective language version, possibly mixing languages between the selected user language and the default.</p>
 
-<section class="h3" id="1.7.1:Constraints%20of%20the%20current%20implementation"><h3>Constraints of the current implementation<a class="anchor" href="#1.7.1:Constraints%20of%20the%20current%20implementation"></a></h3>
+<section class="h3" id="1.7.1:Constraints of the current implementation"><h3>Constraints of the current implementation<a class="anchor" href="#1.7.1:Constraints of the current implementation" aria-label="#1.7.1:Constraints of the current implementation"></a></h3>
 <ul>
 <li>There can be only one default language, with no priority of different fallback languages</li>
 <li>Page URLs can currently not be translated. Doing so would require a model for manually assigning translated page names and would not be trivial to use.</li>
 </ul>
-</section></section><section class="h2" id="1.8:Developer%20Documentation"><h2>Developer Documentation<a class="anchor" href="#1.8:Developer%20Documentation"></a></h2>
+</section></section><section class="h2" id="1.8:Developer Documentation"><h2>Developer Documentation<a class="anchor" href="#1.8:Developer Documentation" aria-label="#1.8:Developer Documentation"></a></h2>
 <p>How to write:</p>
 <ul>
 <li><a href="dev-theming/">Themes</a></li>
index 32299ff1e3f97f26f7cb2c7d3860d56c1a3e83d2..9dfbdfb624b835625757be3d90a7407b93bdf748 100755 (executable)
--- a/users.sh
+++ b/users.sh
@@ -490,9 +490,9 @@ w_user_update(){
        [form #user_update method=POST
          [hidden "uid" "$USER_ID"]
          [p .username Logged in as $USER_NAME]
-         [input type=password name=oldpw placeholder="Current Passphrase"]
-         [input type=password name=pw placeholder="New Passphrase" pattern=".{6,}"]
-         [input type=password name=pwconfirm placeholder="Confirm New Passphrase" pattern=".{6,}"]
+         [input type=password name=oldpw autocomplete="current-password" placeholder="Current Passphrase"]
+         [input type=password name=pw autocomplete="new-password" placeholder="New Passphrase" pattern=".{6,}"]
+         [input type=password name=pwconfirm autocomplete="new-password" placeholder="Confirm New Passphrase" pattern=".{6,}"]
          [submit "action" "user_update" Update Passphrase]
        ]
        EOF
@@ -512,7 +512,7 @@ w_user_register_sendmail(){  # TRANSLATION
          [p We will send an activation mail to your email address.
            You can continue the signup process when you click on the
            activation link in this email.]
-         [input type=email name=email placeholder="Email"]
+         [input type=email name=email autocomplete="email" placeholder="Email"]
          [submit "action" "user_register" Sign Up]
        ]
        EOF
@@ -520,9 +520,9 @@ w_user_register_sendmail(){  # TRANSLATION
 w_user_register_direct(){  # TRANSLATION
   cat <<-EOF
        [form #user_register .registername method=POST
-          [input name=uname placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$" autocomplete=off]
-         [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
-         [input type=password name=pwconfirm placeholder="Confirm Passphrase" pattern=".{6,}"]
+          [input name=uname autocomplete="username" placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$"]
+         [input type=password name=pw autocomplete="new-password" placeholder="Choose Passphrase" pattern=".{6,}"]
+         [input type=password name=pwconfirm autocomplete="new-password" placeholder="Confirm Passphrase" pattern=".{6,}"]
          [submit "action" "user_register" Sign Up]
        ]
        EOF
@@ -548,9 +548,9 @@ w_user_confirm_proceed(){  # TRANSLATION
          $([ "$EMAIL" != '\' ] && printf \
            '[input disabled=disabled value="%s" placeholder="Email"]' "$(UNSTRING "$EMAIL" |HTML)"
          )
-          [input name=uname placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$" autocomplete=off]
-         [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
-         [input type=password name=pwconfirm placeholder="Confirm Passphrase" pattern=".{6,}"]
+          [input name=uname autocomplete="username" placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$"]
+         [input type=password name=pw autocomplete="new-password" placeholder="Choose Passphrase" pattern=".{6,}"]
+         [input type=password name=pwconfirm autocomplete="new-password" placeholder="Confirm Passphrase" pattern=".{6,}"]
          [submit "action" "user_confirm" Finish Registration]
        ]
        EOF
@@ -637,8 +637,8 @@ w_user_invite(){
 w_user_login_logon(){  # TRANSLATION
   cat <<-EOF
        [form #user_login .login method=POST
-         [input name=uname placeholder="Username or Email"]
-         [input type=password name=pw placeholder="Passphrase"]
+         [input name=uname autocomplete="username" placeholder="Username or Email"]
+         [input type=password name=pw autocomplete="current-password" placeholder="Passphrase"]
          [submit "action" "user_login" Login]
        ]
        EOF