From 2ba97c6199a2007f4277a56bc530835d4502a485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20So=C3=B3s?= Date: Thu, 30 Nov 2023 11:29:20 +0100 Subject: [PATCH] Render presentation images without alt text + role attribute. (#7236) --- app/lib/dartdoc/dartdoc_page.dart | 3 +-- app/lib/frontend/dom/dom.dart | 21 +++++++++++++++++++ app/lib/frontend/templates/misc.dart | 3 +-- app/lib/frontend/templates/package_misc.dart | 3 +-- .../templates/views/landing/page.dart | 9 +++----- .../templates/views/shared/detail/header.dart | 6 ++---- .../templates/views/shared/layout.dart | 3 +-- .../templates/views/shared/site_header.dart | 3 +-- app/test/frontend/golden/authorized_page.html | 2 +- app/test/frontend/golden/consent_page.html | 2 +- .../golden/create_publisher_page.html | 2 +- app/test/frontend/golden/error_page.html | 2 +- app/test/frontend/golden/help_page.html | 4 ++-- app/test/frontend/golden/landing_page.html | 4 ++-- .../frontend/golden/my_activity_log_page.html | 2 +- .../frontend/golden/my_liked_packages.html | 2 +- app/test/frontend/golden/my_packages.html | 2 +- app/test/frontend/golden/my_publishers.html | 2 +- .../golden/pkg_activity_log_page.html | 2 +- app/test/frontend/golden/pkg_admin_page.html | 2 +- .../frontend/golden/pkg_changelog_page.html | 2 +- .../frontend/golden/pkg_example_page.html | 2 +- app/test/frontend/golden/pkg_index_page.html | 2 +- .../frontend/golden/pkg_install_page.html | 2 +- app/test/frontend/golden/pkg_score_page.html | 2 +- app/test/frontend/golden/pkg_show_page.html | 2 +- .../golden/pkg_show_page_discontinued.html | 2 +- .../golden/pkg_show_page_flutter_plugin.html | 2 +- .../golden/pkg_show_page_publisher.html | 2 +- .../golden/pkg_show_page_retracted.html | 2 +- ..._page_retracted_non_retracted_version.html | 2 +- .../golden/pkg_show_version_page.html | 2 +- .../frontend/golden/pkg_versions_page.html | 2 +- .../golden/publisher_activity_log_page.html | 2 +- .../frontend/golden/publisher_admin_page.html | 2 +- .../frontend/golden/publisher_list_page.html | 2 +- .../golden/publisher_packages_page.html | 2 +- .../publisher_unlisted_packages_page.html | 2 +- app/test/frontend/golden/search_page.html | 2 +- app/test/frontend/golden/topics_page.html | 4 ++-- .../documentation/oxygen/1.0.0/index.html | 2 +- .../oxygen/1.0.0/oxygen/MainClass-class.html | 2 +- .../1.0.0/oxygen/MainClass/MainClass.html | 2 +- .../oxygen/1.0.0/oxygen/MainClass/text.html | 2 +- .../1.0.0/oxygen/MainClass/toLowerCase.html | 2 +- .../1.0.0/oxygen/MainClass/toString.html | 2 +- .../oxygen/1.0.0/oxygen/TypeEnum.html | 2 +- .../1.0.0/oxygen/TypeEnum/TypeEnum.html | 2 +- .../oxygen/TypeEnum/values-constant.html | 2 +- .../oxygen/1.0.0/oxygen/main.html | 2 +- .../oxygen/1.0.0/oxygen/oxygen-library.html | 2 +- .../documentation/oxygen/2.0.0/index.html | 2 +- .../oxygen/2.0.0/oxygen/MainClass-class.html | 2 +- .../2.0.0/oxygen/MainClass/MainClass.html | 2 +- .../oxygen/2.0.0/oxygen/MainClass/text.html | 2 +- .../2.0.0/oxygen/MainClass/toLowerCase.html | 2 +- .../2.0.0/oxygen/MainClass/toString.html | 2 +- .../oxygen/2.0.0/oxygen/TypeEnum.html | 2 +- .../2.0.0/oxygen/TypeEnum/TypeEnum.html | 2 +- .../oxygen/TypeEnum/values-constant.html | 2 +- .../oxygen/2.0.0/oxygen/main.html | 2 +- .../oxygen/2.0.0/oxygen/oxygen-library.html | 2 +- .../documentation/oxygen/latest/index.html | 2 +- .../oxygen/latest/oxygen/MainClass-class.html | 2 +- .../latest/oxygen/MainClass/MainClass.html | 2 +- .../oxygen/latest/oxygen/MainClass/text.html | 2 +- .../latest/oxygen/MainClass/toLowerCase.html | 2 +- .../latest/oxygen/MainClass/toString.html | 2 +- .../oxygen/latest/oxygen/TypeEnum.html | 2 +- .../latest/oxygen/TypeEnum/TypeEnum.html | 2 +- .../oxygen/TypeEnum/values-constant.html | 2 +- .../oxygen/latest/oxygen/main.html | 2 +- .../oxygen/latest/oxygen/oxygen-library.html | 2 +- .../testdata/goldens/packages/oxygen.html | 2 +- .../goldens/packages/oxygen/changelog.html | 2 +- .../goldens/packages/oxygen/example.html | 2 +- .../goldens/packages/oxygen/install.html | 2 +- .../goldens/packages/oxygen/license.html | 2 +- .../goldens/packages/oxygen/score.html | 2 +- .../goldens/packages/oxygen/versions.html | 2 +- .../packages/oxygen/versions/1.0.0.html | 2 +- .../oxygen/versions/1.0.0/changelog.html | 2 +- .../oxygen/versions/1.0.0/example.html | 2 +- .../oxygen/versions/1.0.0/install.html | 2 +- .../oxygen/versions/1.0.0/license.html | 2 +- .../packages/oxygen/versions/1.0.0/score.html | 2 +- .../packages/oxygen/versions/2.0.0.html | 2 +- 87 files changed, 113 insertions(+), 102 deletions(-) diff --git a/app/lib/dartdoc/dartdoc_page.dart b/app/lib/dartdoc/dartdoc_page.dart index 00ba494598..568258cead 100644 --- a/app/lib/dartdoc/dartdoc_page.dart +++ b/app/lib/dartdoc/dartdoc_page.dart @@ -136,9 +136,8 @@ extension DartDocPageRender on DartDocPage { child: d.img( // TODO: Move this into a class attributes: {'style': 'height: 30px; margin-right: 1em;'}, - image: d.Image( + image: d.Image.decorative( src: staticUrls.dartLogoSvg, - alt: 'Dart', height: 30, width: 30, ), diff --git a/app/lib/frontend/dom/dom.dart b/app/lib/frontend/dom/dom.dart index edb39bb1b2..069ab5c233 100644 --- a/app/lib/frontend/dom/dom.dart +++ b/app/lib/frontend/dom/dom.dart @@ -442,13 +442,33 @@ class Image { final String alt; final int? width; final int? height; + final String? role; Image({ required this.src, required this.alt, required this.width, required this.height, + this.role, }); + + /// Decorative images don't add information to the content of a page. For example, + /// the information provided by the image might already be given using adjacent + /// text, or the image might be included to make the website more visually attractive. + /// In these cases, a `null` (empty) alt text should be provided (`alt=""`) so that + /// they can be ignored by assistive technologies, such as screen readers. + /// + /// Screen readers also allow the use of WAI-ARIA to hide elements by using + /// `role="presentation"`. However, currently, this feature is not as widely + /// supported as using a `null` `alt` attribute. + /// + /// https://www.w3.org/WAI/tutorials/images/decorative/ + Image.decorative({ + required this.src, + required this.width, + required this.height, + }) : alt = '', + role = 'presentation'; } /// Creates an `` Element using the default [DomContext]. @@ -472,6 +492,7 @@ Node img({ if (image.height != null) 'height': image.height.toString(), if (title != null) 'title': title, if (lazy) 'loading': 'lazy', + if (image.role != null) 'role': image.role!, if (attributes != null) ...attributes, }, children: children, diff --git a/app/lib/frontend/templates/misc.dart b/app/lib/frontend/templates/misc.dart index 694f8fe14c..888eb6e741 100644 --- a/app/lib/frontend/templates/misc.dart +++ b/app/lib/frontend/templates/misc.dart @@ -33,9 +33,8 @@ final _helpScoringMarkdown = _readDocContent('help-scoring.md'); final _helpSearchMarkdown = _readDocContent('help-search.md'); final _helpPublishingMarkdown = _readDocContent('help-publishing.md'); -late final _sideImage = d.Image( +late final _sideImage = d.Image.decorative( src: static_files.staticUrls.packagesSideImage, - alt: 'cover image decorating the page', width: 400, height: 400, ); diff --git a/app/lib/frontend/templates/package_misc.dart b/app/lib/frontend/templates/package_misc.dart index 96ec7c47c7..5f6a11bb4f 100644 --- a/app/lib/frontend/templates/package_misc.dart +++ b/app/lib/frontend/templates/package_misc.dart @@ -21,9 +21,8 @@ final coreLibraryBadgeNode = packageBadgeNode(label: 'Core library'); /// Renders the Flutter Favorite badge, used by package listing. final flutterFavoriteBadgeNode = packageBadgeNode( label: 'Flutter Favorite', - icon: d.Image( + icon: d.Image.decorative( src: staticUrls.flutterLogo32x32, - alt: 'Flutter logo', width: 13, height: 13, ), diff --git a/app/lib/frontend/templates/views/landing/page.dart b/app/lib/frontend/templates/views/landing/page.dart index 059458b6ff..4dda2d2cef 100644 --- a/app/lib/frontend/templates/views/landing/page.dart +++ b/app/lib/frontend/templates/views/landing/page.dart @@ -36,9 +36,8 @@ d.Node landingPageNode({ if (_isNotEmptyList(mostPopularPackages)) _block( shortId: 'mp', - image: d.Image( + image: d.Image.decorative( src: staticUrls.getAssetUrl('/static/img/landing-01.webp'), - alt: 'decoration image for package section', width: 351, height: 240, ), @@ -52,9 +51,8 @@ d.Node landingPageNode({ if (_isNotEmptyList(topFlutterPackages)) _block( shortId: 'tf', - image: d.Image( + image: d.Image.decorative( src: staticUrls.getAssetUrl('/static/img/landing-02.webp'), - alt: 'decoration image for package section', width: 306, height: 240, ), @@ -69,9 +67,8 @@ d.Node landingPageNode({ if (_isNotEmptyList(topDartPackages)) _block( shortId: 'td', - image: d.Image( + image: d.Image.decorative( src: staticUrls.getAssetUrl('/static/img/landing-03.webp'), - alt: 'decoration image for package section', width: 370, height: 240, ), diff --git a/app/lib/frontend/templates/views/shared/detail/header.dart b/app/lib/frontend/templates/views/shared/detail/header.dart index 70f35493b3..3f190c43af 100644 --- a/app/lib/frontend/templates/views/shared/detail/header.dart +++ b/app/lib/frontend/templates/views/shared/detail/header.dart @@ -36,10 +36,9 @@ d.Node detailHeaderNode({ d.img( classes: ['ff-banner', 'ff-banner-desktop'], title: 'Package is a Flutter Favorite', - image: d.Image( + image: d.Image.decorative( src: staticUrls .getAssetUrl('/static/img/ff-banner-desktop-2x.png'), - alt: 'large Flutter Favorite logo', width: 150, height: 218, ), @@ -47,10 +46,9 @@ d.Node detailHeaderNode({ d.img( classes: ['ff-banner', 'ff-banner-mobile'], title: 'Package is a Flutter Favorite', - image: d.Image( + image: d.Image.decorative( src: staticUrls .getAssetUrl('/static/img/ff-banner-mobile-2x.png'), - alt: 'small Flutter Favorite logo', width: 94, height: 116, ), diff --git a/app/lib/frontend/templates/views/shared/layout.dart b/app/lib/frontend/templates/views/shared/layout.dart index 710fb76586..8e8dad6191 100644 --- a/app/lib/frontend/templates/views/shared/layout.dart +++ b/app/lib/frontend/templates/views/shared/layout.dart @@ -198,9 +198,8 @@ d.Node pageLayoutNode({ ), d.img( classes: ['logo'], - image: d.Image( + image: d.Image.decorative( src: staticUrls.pubDevLogoSvg, - alt: 'pub.dev package manager', width: 328, height: 70, ), diff --git a/app/lib/frontend/templates/views/shared/site_header.dart b/app/lib/frontend/templates/views/shared/site_header.dart index e6f79051e2..2fda58d802 100644 --- a/app/lib/frontend/templates/views/shared/site_header.dart +++ b/app/lib/frontend/templates/views/shared/site_header.dart @@ -24,9 +24,8 @@ d.Node siteHeaderNode({ href: '/', child: d.img( classes: ['site-logo'], - image: d.Image( + image: d.Image.decorative( src: staticUrls.pubDevLogoSvg, - alt: 'pub logo', width: 140, height: 30, ), diff --git a/app/test/frontend/golden/authorized_page.html b/app/test/frontend/golden/authorized_page.html index c27fbf18f2..0c61e84a4d 100644 --- a/app/test/frontend/golden/authorized_page.html +++ b/app/test/frontend/golden/authorized_page.html @@ -35,7 +35,7 @@