From 268f5b508baa4a4444dc715d979c9de63a58e9df Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Mon, 29 Jun 2026 11:22:17 +0200 Subject: [PATCH 1/4] fix(accessibility): announce ORCID profile link in ipynb title-block The ipynb title-block emitted the ORCID icon as a link wrapping an image with empty alt text, so the link had no accessible name and screen readers fell back to announcing the base64 image data. Same gap PR #14602 fixed for the HTML/Reveal.js author-metadata templates, which was explicitly scoped out of that PR for ipynb. Put the author's name in the markdown image alt text. That is the only alt that survives the ipynb writer: ipynb.lua deliberately strips image attributes (so pandoc emits a markdown image, not a raw , which would break notebook attachment handling in environments like VS Code), which rules out fig-alt / aria-label approaches. The image caption (the markdown alt) is unaffected by that stripping, so a link wrapping the image takes the alt as its accessible name across all markdown renderers. The affiliation-level ORCID site is updated for consistency, though affiliations carry no orcid field (kAffiliationFields in modules/authors.lua; orgs use ROR/ISNI/Ringgold), so that branch does not render in practice. --- .../formats/ipynb/templates/title-block.md | 8 ++--- .../title-block-orcid-ipynb-affiliation.qmd | 14 ++++++++ .../doc-layout/title-block-orcid-ipynb.qmd | 13 +++++++ tests/smoke/render/render-title-block.test.ts | 36 ++++++++++++++++++- 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 tests/docs/doc-layout/title-block-orcid-ipynb-affiliation.qmd create mode 100644 tests/docs/doc-layout/title-block-orcid-ipynb.qmd diff --git a/src/resources/formats/ipynb/templates/title-block.md b/src/resources/formats/ipynb/templates/title-block.md index 810557a0903..7ddab0bef53 100644 --- a/src/resources/formats/ipynb/templates/title-block.md +++ b/src/resources/formats/ipynb/templates/title-block.md @@ -6,9 +6,9 @@ $if(subtitle)$$subtitle$$endif$ $-- there are affiliations, render that $if(by-affiliation/first)$ -$for(by-author)$$if(by-author.url)$[$by-author.name.literal$]($by-author.url$)$else$$by-author.name.literal$$endif$$if(by-author.orcid)$ [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$by-author.orcid$)$endif$$if(by-author.affiliations/first)$ +$for(by-author)$$if(by-author.url)$[$by-author.name.literal$]($by-author.url$)$else$$by-author.name.literal$$endif$$if(by-author.orcid)$ [![ORCID profile for $by-author.name.literal$](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$by-author.orcid$)$endif$$if(by-author.affiliations/first)$ $if(by-author.affiliations/allbutlast)$ - ($for(by-author.affiliations/allbutlast)$$if(it.url)$[$it.name$]($it.url$)$else$$it.name$$endif$$if(it.orcid)$ [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$it.orcid$) $endif$, $endfor$$for(by-author.affiliations/last)$$if(it.url)$[$it.name$]($it.url$)$else$$it.name$$endif$$endfor$) + ($for(by-author.affiliations/allbutlast)$$if(it.url)$[$it.name$]($it.url$)$else$$it.name$$endif$$if(it.orcid)$ [![ORCID profile for $it.name$](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$it.orcid$) $endif$, $endfor$$for(by-author.affiliations/last)$$if(it.url)$[$it.name$]($it.url$)$else$$it.name$$endif$$endfor$) $else$ ($for(by-author.affiliations/first)$$if(it.url)$[$it.name$]($it.url$)$else$$it.name$$endif$$endfor$) $endif$ @@ -19,8 +19,8 @@ $-- If there are no affiliations, we can just output authors $if(by-affiliation)$ $elseif(by-author)$ $for(by-author)$ -$if(by-author.url)$| [$by-author.name.literal$]($by-author-url$)$if(by-author.orcid)$ [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$by-author.orcid$)$endif$ $else$ -$by-author.name.literal$$if(by-author.orcid)$ [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$by-author.orcid$)$endif$ $endif$$endfor$ +$if(by-author.url)$| [$by-author.name.literal$]($by-author-url$)$if(by-author.orcid)$ [![ORCID profile for $by-author.name.literal$](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$by-author.orcid$)$endif$ $else$ +$by-author.name.literal$$if(by-author.orcid)$ [![ORCID profile for $by-author.name.literal$](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1N0NEMjA4MDI1MjA2ODExOTk0QzkzNTEzRjZEQTg1NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozM0NDOEJGNEZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozM0NDOEJGM0ZGNTcxMUUxODdBOEVCODg2RjdCQ0QwOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE5NUZFRDc5MUM2MUUwNEREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU3Q0QyMDgwMjUyMDY4MTE5OTRDOTM1MTNGNkRBODU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+84NovQAAAR1JREFUeNpiZEADy85ZJgCpeCB2QJM6AMQLo4yOL0AWZETSqACk1gOxAQN+cAGIA4EGPQBxmJA0nwdpjjQ8xqArmczw5tMHXAaALDgP1QMxAGqzAAPxQACqh4ER6uf5MBlkm0X4EGayMfMw/Pr7Bd2gRBZogMFBrv01hisv5jLsv9nLAPIOMnjy8RDDyYctyAbFM2EJbRQw+aAWw/LzVgx7b+cwCHKqMhjJFCBLOzAR6+lXX84xnHjYyqAo5IUizkRCwIENQQckGSDGY4TVgAPEaraQr2a4/24bSuoExcJCfAEJihXkWDj3ZAKy9EJGaEo8T0QSxkjSwORsCAuDQCD+QILmD1A9kECEZgxDaEZhICIzGcIyEyOl2RkgwAAhkmC+eAm0TAAAAABJRU5ErkJggg==)](https://orcid.org/$by-author.orcid$)$endif$ $endif$$endfor$ $if(date)$$date$$endif$ $endif$ diff --git a/tests/docs/doc-layout/title-block-orcid-ipynb-affiliation.qmd b/tests/docs/doc-layout/title-block-orcid-ipynb-affiliation.qmd new file mode 100644 index 00000000000..9e25cb5261f --- /dev/null +++ b/tests/docs/doc-layout/title-block-orcid-ipynb-affiliation.qmd @@ -0,0 +1,14 @@ +--- +title: "ORCID accessibility in ipynb title-block (with affiliations)" +author: + - name: Norah Jones + orcid: 0000-0001-2345-6789 + affiliations: + - name: Carleton University + - name: Posit +format: ipynb +--- + +## Section + +Content. diff --git a/tests/docs/doc-layout/title-block-orcid-ipynb.qmd b/tests/docs/doc-layout/title-block-orcid-ipynb.qmd new file mode 100644 index 00000000000..30923afd20d --- /dev/null +++ b/tests/docs/doc-layout/title-block-orcid-ipynb.qmd @@ -0,0 +1,13 @@ +--- +title: "ORCID accessibility in ipynb title-block" +author: + - name: Norah Jones + orcid: 0000-0001-2345-6789 + - name: Jane Doe + orcid: 0000-0003-4444-5555 +format: ipynb +--- + +## Section + +Content. diff --git a/tests/smoke/render/render-title-block.test.ts b/tests/smoke/render/render-title-block.test.ts index b9115e40279..9683a64860b 100644 --- a/tests/smoke/render/render-title-block.test.ts +++ b/tests/smoke/render/render-title-block.test.ts @@ -6,7 +6,11 @@ */ import { docs, outputForInput } from "../../utils.ts"; -import { ensureFileRegexMatches, ensureHtmlElements } from "../../verify.ts"; +import { + ensureFileRegexMatches, + ensureHtmlElements, + ensureIpynbCellMatches, +} from "../../verify.ts"; import { testRender } from "./render.ts"; const input = docs("doc-layout/title-block.qmd"); @@ -43,3 +47,33 @@ testRender(bannerInput, "html", false, [ ]), ensureFileRegexMatches(bannerOutput.outputPath, [/Nora Jones/], [/\[true\]/]), ]); + +// The ipynb title-block renders the ORCID icon as a link wrapping the icon +// image. The link must carry an accessible name so screen readers announce the +// author's ORCID profile instead of falling back to the base64 image data. +// \s+ between words tolerates pandoc's soft line wrapping of the cell source. +// Table-form author rows (authors without structured affiliations). +const orcidIpynbInput = docs("doc-layout/title-block-orcid-ipynb.qmd"); +const orcidIpynbOutput = outputForInput(orcidIpynbInput, "ipynb"); +testRender(orcidIpynbInput, "ipynb", true, [ + ensureIpynbCellMatches(orcidIpynbOutput.outputPath, { + cellType: "markdown", + matches: [ + /ORCID\s+profile\s+for\s+Norah\s+Jones/, + /ORCID\s+profile\s+for\s+Jane\s+Doe/, + ], + }), +]); + +// By-author block (authors with structured affiliations) — a separate template +// site from the table-form rows above. +const orcidIpynbAffilInput = docs( + "doc-layout/title-block-orcid-ipynb-affiliation.qmd", +); +const orcidIpynbAffilOutput = outputForInput(orcidIpynbAffilInput, "ipynb"); +testRender(orcidIpynbAffilInput, "ipynb", true, [ + ensureIpynbCellMatches(orcidIpynbAffilOutput.outputPath, { + cellType: "markdown", + matches: [/ORCID\s+profile\s+for\s+Norah\s+Jones/], + }), +]); From 4e585bc1a9f97d8924bd5020a203b42147920949 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Mon, 29 Jun 2026 11:23:43 +0200 Subject: [PATCH 2/4] docs(rules): require searching for an existing test verifier before adding one verify.ts already covers many output shapes, including parsed-content verifiers (notebook JSON, DOM) rather than only raw-text regex. Adding a near-duplicate verifier was easy to do by reflex; this points future work at the existing helpers first so they get reused or extended instead. --- .claude/rules/testing/typescript-tests.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.claude/rules/testing/typescript-tests.md b/.claude/rules/testing/typescript-tests.md index 1873662fe8a..64a72136e24 100644 --- a/.claude/rules/testing/typescript-tests.md +++ b/.claude/rules/testing/typescript-tests.md @@ -28,6 +28,16 @@ TypeScript-based tests using Deno. Smoke tests render documents; unit tests veri | `tests/verify.ts` | Verification functions (`noErrors`, `fileExists`, etc.) | | `tests/utils.ts` | `docs()`, `outputForInput()`, path utilities | +### Search for an existing verifier before writing one + +`verify.ts` already covers many output shapes — including parsed-content +verifiers, not just raw-text regex (e.g. `ensureIpynbCellMatches` JSON-parses a +notebook and matches against joined cell source; `ensureHtmlElements` / +`ensureHtmlSelectorSatisfies` parse the DOM). Before adding a new `Verify`, +grep `verify.ts` for the format or assertion you need. Reuse or extend the +existing helper rather than hand-rolling a near-duplicate. Same applies to +mock-context and fixture helpers in `tests/unit/**` and `tests/utils.ts`. + ## Smoke Tests (`tests/smoke/`) Render documents and verify output: From f049a80471780234b5338f7fd44452a1e4b0f232 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Mon, 29 Jun 2026 13:10:54 +0200 Subject: [PATCH 3/4] test: add HTML/Reveal.js ORCID a11y regression tests, share fixture (#14602) Extends the ORCID accessibility test suite to cover HTML and Reveal.js (#14602) alongside the existing ipynb tests (#14632). One shared fixture (title-block-orcid.qmd) renders to all three formats, replacing the format-specific title-block-orcid-ipynb.qmd. The affiliation fixture stays separate as it covers a distinct ipynb template path. --- ...-orcid-ipynb.qmd => title-block-orcid.qmd} | 3 +-- tests/smoke/render/render-title-block.test.ts | 27 ++++++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) rename tests/docs/doc-layout/{title-block-orcid-ipynb.qmd => title-block-orcid.qmd} (68%) diff --git a/tests/docs/doc-layout/title-block-orcid-ipynb.qmd b/tests/docs/doc-layout/title-block-orcid.qmd similarity index 68% rename from tests/docs/doc-layout/title-block-orcid-ipynb.qmd rename to tests/docs/doc-layout/title-block-orcid.qmd index 30923afd20d..6f7d7298899 100644 --- a/tests/docs/doc-layout/title-block-orcid-ipynb.qmd +++ b/tests/docs/doc-layout/title-block-orcid.qmd @@ -1,11 +1,10 @@ --- -title: "ORCID accessibility in ipynb title-block" +title: "ORCID accessibility" author: - name: Norah Jones orcid: 0000-0001-2345-6789 - name: Jane Doe orcid: 0000-0003-4444-5555 -format: ipynb --- ## Section diff --git a/tests/smoke/render/render-title-block.test.ts b/tests/smoke/render/render-title-block.test.ts index 9683a64860b..c54ed26f681 100644 --- a/tests/smoke/render/render-title-block.test.ts +++ b/tests/smoke/render/render-title-block.test.ts @@ -48,14 +48,27 @@ testRender(bannerInput, "html", false, [ ensureFileRegexMatches(bannerOutput.outputPath, [/Nora Jones/], [/\[true\]/]), ]); -// The ipynb title-block renders the ORCID icon as a link wrapping the icon -// image. The link must carry an accessible name so screen readers announce the -// author's ORCID profile instead of falling back to the base64 image data. +// ORCID icon links must carry an accessible name so screen readers announce +// the author profile instead of the base64 image data. +const orcidInput = docs("doc-layout/title-block-orcid.qmd"); + +// HTML and Reveal.js: check aria-label on the anchor (#14602). +const orcidAriaMatches = [ + /aria-label="ORCID profile for Norah Jones"/, + /aria-label="ORCID profile for Jane Doe"/, +]; +for (const fmt of ["html", "revealjs"] as const) { + const orcidOutput = outputForInput(orcidInput, fmt); + testRender(orcidInput, fmt, false, [ + ensureFileRegexMatches(orcidOutput.outputPath, orcidAriaMatches), + ]); +} + +// ipynb: check accessible name in notebook cell source (#14632). // \s+ between words tolerates pandoc's soft line wrapping of the cell source. // Table-form author rows (authors without structured affiliations). -const orcidIpynbInput = docs("doc-layout/title-block-orcid-ipynb.qmd"); -const orcidIpynbOutput = outputForInput(orcidIpynbInput, "ipynb"); -testRender(orcidIpynbInput, "ipynb", true, [ +const orcidIpynbOutput = outputForInput(orcidInput, "ipynb"); +testRender(orcidInput, "ipynb", true, [ ensureIpynbCellMatches(orcidIpynbOutput.outputPath, { cellType: "markdown", matches: [ @@ -66,7 +79,7 @@ testRender(orcidIpynbInput, "ipynb", true, [ ]); // By-author block (authors with structured affiliations) — a separate template -// site from the table-form rows above. +// path from the table-form rows above. const orcidIpynbAffilInput = docs( "doc-layout/title-block-orcid-ipynb-affiliation.qmd", ); From 4831bfcf5a1f9b6d52cc987bbf9f9b46c28e25da Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Mon, 29 Jun 2026 13:11:22 +0200 Subject: [PATCH 4/4] docs(changelog): add entry for ipynb ORCID accessibility fix (#14632) Merge into existing #14602 entry since both PRs fix the same gap (ORCID link has no accessible name for screen readers) across different output formats. --- news/changelog-1.10.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news/changelog-1.10.md b/news/changelog-1.10.md index 6dc3f66aae6..998f3ac371f 100644 --- a/news/changelog-1.10.md +++ b/news/changelog-1.10.md @@ -15,7 +15,7 @@ All changes included in 1.10: ## Accessibility - ([#14468](https://github.com/quarto-dev/quarto-cli/issues/14468)): The `axe` accessibility report UI (HTML overlay, revealjs report slide, dashboard offcanvas) now uses its own theme-independent colors instead of inheriting from `brand` or theme. Keeps the report readable regardless of page styling, and stops `axe` from clobbering brand colors set via `_brand.yml`. -- ([#14602](https://github.com/quarto-dev/quarto-cli/pull/14602)): Add `aria-label` and `alt=""` to properly announce ORCID image link in author metadata HTML/Reveal.js partial. (author: @mcanouil) +- ([#14602](https://github.com/quarto-dev/quarto-cli/pull/14602), [#14632](https://github.com/quarto-dev/quarto-cli/pull/14632)): Fix ORCID profile link having no accessible name for screen readers in HTML, Reveal.js, and ipynb title-block author metadata. (author: @mcanouil for #14602) - ([#14604](https://github.com/quarto-dev/quarto-cli/issues/14604)): The `axe` accessibility report UI now shows each violation's WCAG conformance level (e.g. `WCAG 2.0 AA (1.4.3)`) or `Best Practice`, derived from the violation's axe-core tags. ## Formats