-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
VACMS-1872: Render child sections. (#1980)
* VACMS-1872: Render child sections. * VACMS-1872: Use accordion pattern + add 508 features. * VACMS-1872: Add /user path to accessibility check. * VACMS-1872: iteration on sections styling. * VACMS-1872: Prevent link and icon overlap. Refactor library. * VACMS-1872: Polished margins for sections block. * VACMS-1872: Switch to placing button in suffix instead of prefix. * VACMS-1872: Menu pattern instead of accordion. * VACMS-1872: Support elements order for keyboard navigation. Co-authored-by: Steve Wirt <[email protected]>
- Loading branch information
Showing
8 changed files
with
254 additions
and
37 deletions.
There are no files selected for viewing
81 changes: 81 additions & 0 deletions
81
docroot/modules/custom/va_gov_user/css/sections_accordion.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
.item-list ul.sections li { | ||
list-style: none; | ||
margin: 0; | ||
padding: 0.1rem; | ||
} | ||
|
||
.item-list ul.sections .item-list ul { | ||
background-color: #ffffff; | ||
margin: 0; | ||
padding: 0 0 0 2em; | ||
} | ||
|
||
.item-list ul.sections .item-list ul.subsections { | ||
padding: 0.5rem 0 0.5rem 2rem; | ||
} | ||
|
||
.item-list > ul.sections > li { | ||
border: 1px solid #aeb0b5; | ||
border-bottom: none; | ||
padding: 0; | ||
position: relative; | ||
} | ||
|
||
.item-list > ul.sections > li:last-child { | ||
border-bottom: 1px solid #aeb0b5; | ||
} | ||
|
||
.item-list > ul.sections > li ul li { | ||
list-style: disc; | ||
} | ||
|
||
.item-list > ul.sections { | ||
margin-left: 0; | ||
max-width: 400px; | ||
} | ||
|
||
.item-list > ul.sections > li > a { | ||
display: block; | ||
padding: 0.5rem; | ||
} | ||
|
||
ul.sections li .toggle { | ||
background-image: url('../images/chevron-disc-down.svg'); | ||
background-size: 1rem; | ||
background-position: 0.75rem .75rem; | ||
background-repeat: no-repeat; | ||
background-color: transparent; | ||
border: 0; | ||
cursor: pointer; | ||
display: block; | ||
height: 100%; | ||
margin: 0; | ||
padding: 0 1.15rem; | ||
position: absolute; | ||
right: 0; | ||
top: 0; | ||
width: 1rem; | ||
} | ||
|
||
ul.sections li .toggle:active, | ||
ul.sections li .toggle:focus, | ||
ul.sections li .toggle:hover { | ||
background-color: #f1f1f1; | ||
} | ||
|
||
.sections > li > a.open { | ||
border-bottom: 1px solid #d6d7d9; | ||
} | ||
|
||
.sections li .toggle.open { | ||
background-color: #f1f1f1; | ||
background-image: url('../images/chevron-disc-up.svg'); | ||
} | ||
|
||
.sections .subsections { | ||
display: block; | ||
} | ||
|
||
.sections .subsections.hidden { | ||
display: none; | ||
} |
1 change: 1 addition & 0 deletions
1
docroot/modules/custom/va_gov_user/images/chevron-disc-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions
23
docroot/modules/custom/va_gov_user/js/sections_accordion.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* @file | ||
*/ | ||
|
||
(function ($, Drupal) { | ||
Drupal.behaviors.vaGovSectionsAccordion = { | ||
attach: function (context, settings) { | ||
// Add aria-hidden attribute to all collapsed areas. | ||
$('.sections').find('.subsections').attr('aria-hidden', true).addClass('hidden'); | ||
|
||
$('.sections .toggle', context).on('click', function (e) { | ||
e.preventDefault(); | ||
$(e.target).toggleClass('open'); | ||
$(e.target).closest('li').find('a').toggleClass('open'); | ||
$(e.target).attr('aria-pressed', function (_, attr) { return !(attr === 'true') }); | ||
$(e.target).attr('aria-expanded', function (_, attr) { return !(attr === 'true') }); | ||
$(e.target).closest('li').find('.subsections').attr('aria-hidden', function (_, attr) { return !(attr === 'true') }); | ||
$(e.target).closest('li').find('.subsections').toggleClass('hidden'); | ||
}); | ||
} | ||
}; | ||
|
||
})(jQuery, window.Drupal); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,12 +4,14 @@ | |
|
||
use Drupal\Core\Access\AccessResult; | ||
use Drupal\Core\Block\BlockBase; | ||
use Drupal\Core\Entity\EntityTypeManagerInterface; | ||
use Drupal\Core\Link; | ||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; | ||
use Drupal\Core\Render\Markup; | ||
use Drupal\Core\Routing\RouteMatchInterface; | ||
use Drupal\Core\Session\AccountInterface; | ||
use Drupal\Core\Url; | ||
use Drupal\va_gov_user\Service\UserPermsService; | ||
use Drupal\views\Views; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
|
||
/** | ||
|
@@ -29,13 +31,6 @@ class UserSections extends BlockBase implements ContainerFactoryPluginInterface | |
*/ | ||
protected $routeMatch; | ||
|
||
/** | ||
* Database connection. | ||
* | ||
* @var \Drupal\Core\Database\Database | ||
*/ | ||
private $database; | ||
|
||
/** | ||
* The entity type manager. | ||
* | ||
|
@@ -53,9 +48,10 @@ class UserSections extends BlockBase implements ContainerFactoryPluginInterface | |
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match, UserPermsService $user_perms) { | ||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match, EntityTypeManagerInterface $entity_type_manager, UserPermsService $user_perms) { | ||
parent::__construct($configuration, $plugin_id, $plugin_definition); | ||
$this->routeMatch = $route_match; | ||
$this->entityTypeManager = $entity_type_manager; | ||
$this->userPerms = $user_perms; | ||
} | ||
|
||
|
@@ -68,6 +64,7 @@ public static function create(ContainerInterface $container, array $configuratio | |
$plugin_id, | ||
$plugin_definition, | ||
$container->get('current_route_match'), | ||
$container->get('entity_type.manager'), | ||
$container->get('va_gov_user.user_perms') | ||
); | ||
} | ||
|
@@ -96,49 +93,130 @@ public function build() { | |
// Get sections assigned to user profile. | ||
$sections = $this->userPerms->getSections($user); | ||
|
||
// Viewed profile is content_admin or administrator | ||
// OR | ||
// user has access to ALL sections - | ||
// Render sections tree. | ||
if ($user->hasRole('content_admin') || $user->hasRole('administrator') || in_array('All sections', $sections)) { | ||
$view = Views::getView('sections_tree'); | ||
$view->setDisplay('block_1'); | ||
$view->preExecute(); | ||
$view->execute(); | ||
|
||
return $view->buildRenderable(); | ||
// User has access only to some sections. | ||
// Compose list. | ||
$entity_storage = $this->entityTypeManager->getStorage('taxonomy_term'); | ||
$tree = $entity_storage->loadTree('administration'); | ||
|
||
foreach ($tree as $key => $term) { | ||
if (!array_key_exists($term->tid, $sections)) { | ||
unset($tree[$key]); | ||
} | ||
} | ||
|
||
// Use has access only to some sections. | ||
// Compose list. | ||
$links = []; | ||
|
||
foreach ($sections as $tid => $term_name) { | ||
$links[$tid] = [ | ||
'title' => $term_name, | ||
'url' => Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $tid]), | ||
]; | ||
foreach ($tree as $term) { | ||
$parent_path = $term->parents[0] ? $this->getArrayKeyPath($links, $term->parents[0]) : NULL; | ||
|
||
// Compose render array of section links while preserving hierarchy. | ||
// This switch accounts for taxonomy terms that are 5 levels deep. | ||
// Sections vocabulary is 4 levels deep. If it grows over 5, this logic | ||
// must be expanded. | ||
$count = count($parent_path); | ||
switch ($count) { | ||
case 1: | ||
$links[$parent_path[0]]['items']['#attributes'] = [ | ||
'id' => 'section-' . $parent_path[0], | ||
'class' => 'subsections', | ||
]; | ||
$links[$parent_path[0]]['items'][$term->tid] = [ | ||
'#type' => 'link', | ||
'#weight' => $term->weight, | ||
'#title' => $term->name, | ||
'#url' => Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $term->tid]), | ||
]; | ||
break; | ||
|
||
case 3: | ||
$links[$parent_path[2]][$parent_path[1]][$parent_path[0]]['items'][$term->tid] = [ | ||
'#type' => 'link', | ||
'#weight' => $term->weight, | ||
'#title' => $term->name, | ||
'#url' => Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $term->tid]), | ||
]; | ||
break; | ||
|
||
case 5: | ||
$links[$parent_path[4]][$parent_path[3]][$parent_path[2]][$parent_path[1]][$parent_path[0]]['items'][$term->tid] = [ | ||
'#type' => 'link', | ||
'#weight' => $term->weight, | ||
'#title' => $term->name, | ||
'#url' => Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $term->tid]), | ||
]; | ||
break; | ||
|
||
default: | ||
$section_link = Link::fromTextAndUrl($term->name, Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $term->tid]))->toString(); | ||
$expand_button = $sections[$term->tid]['hasChildren'] ? Markup::create('<button class="toggle" aria-label="Toggle ' . $term->name . ' section" aria-pressed="false" aria-expanded="false" aria-controls="section-' . $term->tid . '"></button>') : NULL; | ||
$links[$term->tid] = [ | ||
'#type' => 'markup', | ||
'#markup' => $section_link . $expand_button, | ||
'#allowed_tags' => [ | ||
'a', | ||
'button', | ||
], | ||
]; | ||
break; | ||
} | ||
} | ||
|
||
if (!empty($links)) { | ||
return [ | ||
'links' => [ | ||
'#theme' => 'links', | ||
'#links' => $links, | ||
'#theme' => 'item_list', | ||
'#list_type' => 'ul', | ||
'#items' => $links, | ||
'#attributes' => ['class' => 'sections'], | ||
'#attached' => [ | ||
'library' => [ | ||
'va_gov_user/sections_accordion', | ||
], | ||
], | ||
'#prefix' => $this->t('You can edit content in the following VA.gov sections.'), | ||
], | ||
]; | ||
} | ||
else { | ||
// User is not assigned to any sections, display onboarding lingo. | ||
// @todo: Update lingo. | ||
$url = 'mailto:[email protected]?subject=Section%20assignment&body=Dear%20VACMS%20support%20team%2C%0A%5BThis%20is%20a%20template.%20%20You%20can%20delete%20the%20text%20you%20don%E2%80%99t%20need%2C%20and%20feel%20free%20to%20add%20your%20own.%5D%0A%0AI%E2%80%99m%20a%20new%20CMS%20user%2C%20and%20need%20to%20be%20given%20access%20to%20the%20following%20VA.gov%20sections%3A%0A%5BList%20the%20sections%20you%20need%20access%20to%20here.%20If%20you%20aren%E2%80%99t%20sure%2C%20describe%20your%20job%20title%20and%20what%20pages%20you%20need%20to%20work%20on.%5D%0A%0APlease%20assign%20me%20the%20following%20role%3A%20%0A%5BAdd%20which%20role%20you%20need%20here.%5D%0A-%20Content%20editor%3A%20because%20I%20need%20to%20create%2C%20edit%2C%20and%20review%20content%0A-%20Content%20publisher%3A%20because%20I%20also%20need%20to%20publish%20content%0A-%20Content%20admin%3A%20because%20I%20need%20broad%20permissions%2C%20including%20customizing%20URLs%20and%20triggering%20unscheduled%20content%20releases%0A%0AThank%20you.'; | ||
return [ | ||
'section_assignment' => [ | ||
'#markup' => $this->t('Contact #cms-support for VA section assignment.'), | ||
'#markup' => $this->t('You don\'t have permission to access content in any VA.gov sections yet. <a href=":link">Contact VACMS Support to request access</a>.', [':link' => $url]), | ||
], | ||
]; | ||
} | ||
} | ||
|
||
/** | ||
* Return a path for a specified array key. | ||
* | ||
* @param array $array | ||
* Array. | ||
* @param string $lookup | ||
* Array key to look up. | ||
* | ||
* @return array|null | ||
* Array of elements that compose a path to searched key. | ||
*/ | ||
protected function getArrayKeyPath(array $array, $lookup) { | ||
if (array_key_exists($lookup, $array)) { | ||
return [$lookup]; | ||
} | ||
else { | ||
foreach ($array as $key => $subarray) { | ||
if (is_array($subarray) && (is_int($key) || $key === 'items')) { | ||
$path = $this->getArrayKeyPath($subarray, $lookup); | ||
if ($path) { | ||
$path[] = $key; | ||
return $path; | ||
} | ||
} | ||
} | ||
} | ||
return NULL; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
sections_accordion: | ||
css: | ||
component: | ||
css/sections_accordion.css: {} | ||
js: | ||
js/sections_accordion.js: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
d67c6cd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Test Failed:
va/tests/accessibility