diff --git a/lib/classes/globalsearch/GlobalSearchCourses.php b/lib/classes/globalsearch/GlobalSearchCourses.php index bf29ca04ecbcbf7e78a9be33f935f3b858b0f796..9de5535dba2166d271aafa9fb07f0417525d4a11 100644 --- a/lib/classes/globalsearch/GlobalSearchCourses.php +++ b/lib/classes/globalsearch/GlobalSearchCourses.php @@ -225,9 +225,9 @@ class GlobalSearchCourses extends GlobalSearchModule implements GlobalSearchFull array_map( function ($lecturer, $index) use ($search, $course) { if ($index < 3) { - return '<a href="' . URLHelper::getURL('dispatch.php/profile', ['username' => $lecturer->username]) . '">' . self::mark($lecturer->getUserFullname(), $search) . '</a>'; + return self::mark($lecturer->getUserFullname(), $search); } else if ($index == 3) { - return '<a href="' . URLHelper::getURL('dispatch.php/course/details/index/' . $course->id) . '">... (' . _('mehr') . ') </a>'; + return '... (' . _('mehr') . ')'; } }, $lecturers, diff --git a/lib/classes/globalsearch/GlobalSearchCourseware.php b/lib/classes/globalsearch/GlobalSearchCourseware.php index d4c53b168d10e59344be3f47cb0549ec530ebca7..de069fe887e83b9875029a621807aac25b11fc90 100644 --- a/lib/classes/globalsearch/GlobalSearchCourseware.php +++ b/lib/classes/globalsearch/GlobalSearchCourseware.php @@ -142,7 +142,7 @@ class GlobalSearchCourseware extends GlobalSearchModule implements GlobalSearchF 'description' => $description, 'url' => $pageData['url'], 'img' => $structural_element->image ? $structural_element->getImageUrl() : Icon::create('courseware')->asImagePath(), - 'additional' => '<a href="' . htmlReady($pageData['originUrl']) . '" title="' . htmlReady($pageData['originName']) . '">' . htmlReady($pageData['originName']) . '</a>', + 'additional' => htmlReady($pageData['originName']), 'date' => $date->format('d.m.Y H:i'), 'structural-element-id' => $structural_element->id, 'expand' => null diff --git a/lib/classes/globalsearch/GlobalSearchMessages.php b/lib/classes/globalsearch/GlobalSearchMessages.php index d1a91a52f135b97627280c5c391aa228b9c30108..5f64b40413b0eec9d95d60bab45d7412bceab682 100644 --- a/lib/classes/globalsearch/GlobalSearchMessages.php +++ b/lib/classes/globalsearch/GlobalSearchMessages.php @@ -79,11 +79,7 @@ class GlobalSearchMessages extends GlobalSearchModule if ($user) { $username = $user->getFullName(); - $additional = sprintf( - '<a href="%s">%s</a>', - URLHelper::getLink('dispatch.php/profile', ['username' => $user->username]), - self::mark($user->getFullName(), $search) - ); + $additional = self::mark($user->getFullName(), $search); } } diff --git a/lib/classes/globalsearch/GlobalSearchMyCourses.php b/lib/classes/globalsearch/GlobalSearchMyCourses.php index f8f2f11ec6995330406f0e0768728828b9d8a234..6558f787ba5113a6428aa12faf982496ded828c1 100644 --- a/lib/classes/globalsearch/GlobalSearchMyCourses.php +++ b/lib/classes/globalsearch/GlobalSearchMyCourses.php @@ -162,9 +162,9 @@ class GlobalSearchMyCourses extends GlobalSearchModule array_map( function ($lecturer, $index) use ($search, $course) { if ($index < 3) { - return '<a href="' . URLHelper::getURL('dispatch.php/profile', ['username' => $lecturer->username]) . '">' . self::mark($lecturer->getUserFullname(), $search) . '</a>'; + return self::mark($lecturer->getUserFullname(), $search); } else if ($index == 3) { - return '<a href="' . URLHelper::getURL('dispatch.php/course/details/index/' . $course->id) . '">... (' . _('mehr') . ') </a>'; + return '... (' . _('mehr') . ')'; } }, $lecturers, diff --git a/lib/classes/globalsearch/GlobalSearchUsers.php b/lib/classes/globalsearch/GlobalSearchUsers.php index fb8677ae626432bb339bbc6fc6fa53b6a5c3c84e..458f0982101628d314a9b51726b76908380de077 100644 --- a/lib/classes/globalsearch/GlobalSearchUsers.php +++ b/lib/classes/globalsearch/GlobalSearchUsers.php @@ -86,7 +86,7 @@ class GlobalSearchUsers extends GlobalSearchModule implements GlobalSearchFullte ['username' => $user->username], true ), - 'additional' => '<a href="' . URLHelper::getLink('dispatch.php/profile', ['username' => $user->username]) . '">' . self::mark($user->username, $search) . '</a>', + 'additional' => self::mark($user->username, $search), 'expand' => self::getSearchURL($search), 'img' => Avatar::getAvatar($user->id)->getUrl(Avatar::MEDIUM), ]; diff --git a/resources/assets/javascripts/bootstrap/global_search.js b/resources/assets/javascripts/bootstrap/global_search.js index 4d0738ed62d95ebba5dd0659d42eb5c19c07917a..a85f2f0d831690737e32879c802465c6fbbe43fe 100644 --- a/resources/assets/javascripts/bootstrap/global_search.js +++ b/resources/assets/javascripts/bootstrap/global_search.js @@ -36,6 +36,51 @@ STUDIP.domReady(() => { return false; } }); + $('#globalsearch-input').on('keypress', function(e) { + if (e.which === 13) { + STUDIP.GlobalSearch.doSearch(); + return false; + } + }); + $('#globalsearch-searchbar').on('keydown', function(e) { + if (e.originalEvent.code === 'ArrowDown') { + if ($('#globalsearch-list [role=listitem]:focus').length === 0) { + $('#globalsearch-list [role=listitem]:visible').first().focus(); + } else { + let n = $('#globalsearch-list [role=listitem]:focus').next(); + if (n.length > 0 && n.is('[role=listitem]:visible')) { + n.focus(); + } else { + n = $('#globalsearch-list [role=listitem]:focus').parent().next().find('[role=listitem]:visible').first(); + if (n.length > 0) { + n.focus(); + } else { + $('#globalsearch-list [role=listitem]:visible').first().focus(); + } + } + } + return false; + } + if (e.originalEvent.code === 'ArrowUp') { + if ($('#globalsearch-list [role=listitem]:focus').length === 0) { + $('#globalsearch-list [role=listitem]:visible').last().focus(); + } else { + let n = $('#globalsearch-list [role=listitem]:focus').prev(); + if (n.length > 0 && n.is('[role=listitem]:visible')) { + n.focus(); + } else { + n = $('#globalsearch-list [role=listitem]:focus').parent().prev().find('[role=listitem]:visible').last(); + if (n.length > 0) { + n.focus(); + } else { + $('#globalsearch-list [role=listitem]:visible').last().focus(); + } + } + } + return false; + } + }); + // Close search on click on page. $('#navigation-level-1, #current-page-structure, #main-footer').on('click', function() { diff --git a/resources/assets/javascripts/lib/global_search.js b/resources/assets/javascripts/lib/global_search.js index 05a53aa320016300f6290867ad99ea1d0af084b5..394b7e30a33fecf553fc24a17d5a728e2a8058fb 100644 --- a/resources/assets/javascripts/lib/global_search.js +++ b/resources/assets/javascripts/lib/global_search.js @@ -9,6 +9,7 @@ const GlobalSearch = { */ toggleSearchBar: function(visible, cleanup) { $('#globalsearch-searchbar').toggleClass('is-visible', visible); + $('#globalsearch-input').attr('aria-expanded', visible ? 'true' : 'false'); $('#globalsearch-input').toggleClass('hidden-small-down', !visible); $('#globalsearch-icon').toggleClass('hidden-small-down', visible); $('#globalsearch-clear').toggleClass('hidden-small-down', !visible); @@ -70,7 +71,7 @@ const GlobalSearch = { // Iterate over each result category. $.each(json, function(name, value) { // Create an <article> for category. - var category = $(`<article id="globalsearch-${name}">`), + var category = $(`<article id="globalsearch-${name}" role="list">`), header = $('<header>').appendTo(category), counter = 0; @@ -96,7 +97,7 @@ const GlobalSearch = { // Process results and create corresponding entries. $.each(value.content, function(index, result) { // Create single result entry. - var single = $('<section>'), + var single = $(`<a href="${result.url}" role="listitem" ${dataDialog}>`), data = $('<div class="globalsearch-result-data">'), details = $('<div class="globalsearch-result-details">'); @@ -107,17 +108,17 @@ const GlobalSearch = { // Which result types should be opened via dialog? const openInDialog = ['GlobalSearchFiles', 'GlobalSearchMessages']; var dataDialog = (openInDialog.indexOf(name) >= 0 ? dataDialog = 'data-dialog' : dataDialog = ''); - var link = $(`<a href="${result.url}" ${dataDialog}>`).appendTo(single); + //var link = $(`<a href="${result.url}" ${dataDialog}>`).appendTo(single); // Optional image... if (result.img !== null) { $(`<img src="${result.img}" alt="">`) .wrap('<div class="globalsearch-result-img">') .parent() // Element is now the wrapper - .appendTo(link); + .appendTo(single); } - link.append(data); + single.append(data); // Name/title $('<div class="globalsearch-result-title">') @@ -144,7 +145,7 @@ const GlobalSearch = { if (result.date !== null) { $('<div class="globalsearch-result-time">') .html(result.date) - .appendTo(link); + .appendTo(single); } // "Expand" attribute for further, result-related search @@ -178,6 +179,7 @@ const GlobalSearch = { GlobalSearch.lastSearch = null; $('#globalsearch-searchbar').removeClass('is-visible has-value'); + $('#globalsearch-input').attr('aria-expanded', 'false'); $('#globalsearch-input').val(''); $('#globalsearch-results').html(''); $('#globalsearch-input').focus(); diff --git a/resources/assets/stylesheets/scss/globalsearch.scss b/resources/assets/stylesheets/scss/globalsearch.scss index 4faee5feabd8cf621ef34c5252b7058a295a93e5..ef7c6e652f82da4c3ccc192955470c89829b9a5d 100644 --- a/resources/assets/stylesheets/scss/globalsearch.scss +++ b/resources/assets/stylesheets/scss/globalsearch.scss @@ -171,7 +171,7 @@ } } - section { + a[role=listitem] { display: flex; flex-direction: row; flex-wrap: nowrap; @@ -189,7 +189,7 @@ display: none; } - & > a { + & > span.detail { display: flex; flex-direction: row; flex-wrap: nowrap; diff --git a/templates/globalsearch/searchbar.php b/templates/globalsearch/searchbar.php index 93a8ab512247879ea2601880b65cbdee74e0a781..837931cf3f15cb25c0cc658d9da6fa6b682b3b58 100644 --- a/templates/globalsearch/searchbar.php +++ b/templates/globalsearch/searchbar.php @@ -1,6 +1,16 @@ -<div id="globalsearch-searchbar" role="search" aria-label="<?= _('Globale Suche') ?>"> - <input class="hidden-small-down" type="text" name="globalsearchterm" id="globalsearch-input" - placeholder="<?= _('Was suchen Sie?') ?>" role="searchbox"> +<div id="globalsearch-searchbar" + role="search" + aria-label="<?= _('Globale Suche') ?>"> + <input class="hidden-small-down" + type="text" + name="globalsearchterm" + id="globalsearch-input" + placeholder="<?= _('Was suchen Sie?') ?>" + role="combobox" + aria-haspopup="listbox" + aria-expanded="false" + aria-controls="globalsearch-list" + aria-label="Suche nach Objekten und Personen in Stud.IP"> <?= Icon::create('decline', Icon::ROLE_INACTIVE)->asInput([ 'id' => 'globalsearch-clear', 'class' => 'hidden-small-down', @@ -10,7 +20,8 @@ 'id' => 'globalsearch-icon', 'alt' => _('Suche starten') ]) ?> - <div id="globalsearch-list"> + <div id="globalsearch-list" + role="listbox"> <a href="#" id="globalsearch-togglehints" data-toggle-text="<?= _('Tipps ausblenden') ?>"> <?= _('Tipps einblenden') ?> </a>