Skip to content

Expandasearch #3433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
64 changes: 58 additions & 6 deletions phpmyfaq/assets/scss/layout/_autocomplete.scss
Original file line number Diff line number Diff line change
@@ -1,34 +1,84 @@
.searchContainer {
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
display: none;
padding: 3px 0px;

#expandaSearch {
border-radius: 10px;
}

.bi-close{
position: absolute;
top: -16px;
left: 7px;
font-size: 45px;
color: var(--bs-gray-400);
cursor: pointer;
}

.bi-close:before{
content: "×";
font-weight: bold;
}
}

.search {
position: relative;
box-shadow: 0 0 40px rgba(51, 51, 51, 0.1);
background-color: transparent;

input {
height: 60px;
height: 50px;
text-indent: 25px;

&:focus {
box-shadow: none;
border: 2px solid var(--bs-primary);
padding-right: 110px;
padding-left: 15px;
}
}

.bi-search {
position: absolute;
top: 18px;
left: 18px;
&.searchClosed {
display: inline-block;

form {
background: white;
border-radius: 10px;
width: fit-content;
padding: 3px;
}

.bi-close {
display: none;
}

input {
visibility: hidden;
position: absolute;
border: none;
}

button {
position: unset;
}

}

button {
position: absolute;
top: 5px;
right: 5px;
height: 50px;
height: 40px;
padding-top: 0.25rem;
}
}

.autocomplete {
@extend .list-group;
z-index: 1200;
}

.autocomplete > div {
Expand All @@ -42,3 +92,5 @@
@extend .list-group-item-info;
cursor: pointer;
}


13 changes: 13 additions & 0 deletions phpmyfaq/assets/scss/layout/_navigation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,16 @@
@extend .px-2;
@extend .link-light;
}

@media (min-width: 992px) {
li.searchNav {
display: none !important;
}
div.searchContainer {
display: block;
}
}
.pmf-nav-link.active {
border-radius: 5px;
background-color: var(--bs-primary);
}
5 changes: 4 additions & 1 deletion phpmyfaq/assets/src/frontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
handleShowFaq,
handleUserVoting,
} from './faq';
import { handleAutoComplete, handleQuestion } from './search';
import { handleAutoComplete, handleQuestion, handleExpandaSearch } from './search';
import {
handleDeleteBookmarks,
handleRegister,
Expand Down Expand Up @@ -98,4 +98,7 @@ document.addEventListener('DOMContentLoaded', () => {

// AutoComplete
handleAutoComplete();

// set up expandaSearch
handleExpandaSearch();
});
61 changes: 61 additions & 0 deletions phpmyfaq/assets/src/search/expandasearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Expandasearch functionality JavaScript part
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*
* @package phpMyFAQ
* @author Thorsten Rinne <[email protected]>
* @copyright 2014-2025 phpMyFAQ Team
* @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
* @link https://www.phpmyfaq.de
* @since 2014-11-23
*/

export const handleExpandaSearch = (): void => {

let searchContainer: HTMLElement | null = document.getElementById('expandaSearch');
let menuList: HTMLElement | null = document.querySelector('#pmf-top-navbar ul');
let closeBtn: HTMLElement | null = document.querySelector('.searchContainer .bi-close');
let timeOut: int | null;

function showSearch(event: MouseEvent): void {
if (searchContainer && searchContainer.querySelector('button') && !searchContainer.querySelector('button').disabled) return;
event.stopPropagation();
if (menuList) menuList.style.display = "none";
if (searchContainer && searchContainer.querySelector('input')) searchContainer.querySelector('input').value = "";
if (searchContainer) searchContainer.classList.remove('searchClosed');
if (searchContainer && searchContainer.querySelector('button')) searchContainer.querySelector('button').disabled = false;
if (searchContainer && searchContainer.querySelector('input')) searchContainer.querySelector('input').focus();
document.querySelector('div.searchContainer')!.style.width = "75%";
redoTimeout();
}

function hideSearch(event?: MouseEvent): void {
if (document.querySelector('ul.autocomplete')) return;
if (searchContainer && searchContainer.querySelector('button') && searchContainer.querySelector('button').disabled) return;
if (event) event.stopPropagation();
if (searchContainer) searchContainer.classList.add('searchClosed');
if (searchContainer && searchContainer.querySelector('button')) searchContainer.querySelector('button').disabled = true;
if (menuList) menuList.style.display = "";
document.querySelector('div.searchContainer')!.style.width = "";
}

function checkEsc(event: KeyboardEvent): void {
if (event.key === "Escape") {
if (searchContainer && !searchContainer.classList.contains('searchClosed')) hideSearch();
}
}

function redoTimeout() {
clearTimeout(timeOut);
timeOut = setTimeout(hideSearch, 3000);
}

if (searchContainer) searchContainer.addEventListener('click', showSearch);
if (closeBtn) closeBtn.addEventListener('click', hideSearch);

document.querySelector('.search input').addEventListener("keyup", redoTimeout);
document.addEventListener('keydown', checkEsc);
};
1 change: 1 addition & 0 deletions phpmyfaq/assets/src/search/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './autocomplete';
export * from './question';
export * from './expandasearch';
66 changes: 33 additions & 33 deletions phpmyfaq/assets/templates/default/index.twig
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,45 @@
<a class="pmf-nav-link {{ item['active'] }}" href="{{ item['link'] }}">{{ item['name'] }}</a>
</li>
{% endfor %}
{% endif %}
<li class="nav-item pmf-nav-link searchNav">
<a class="pmf-nav-link {{ item['active'] }}" href="./search.html">{{ searchBox }}</a>
</li>
{% endif %}
</ul>

<ul class="navbar-nav flex-row flex-wrap ms-md-auto">
<!-- SEARCH -->
{% if not isMaintenanceMode %}
<div class="searchContainer ms-auto">
{% if not searchTerm %}
<div class="row height d-flex justify-content-center align-items-center">
<div class="">
<div id="expandaSearch" class="search searchClosed">
<form action="./search.html" id="search" method="post" role="search">
<i class="bi bi-close"></i>
<input autocomplete="off" type="text" class="form-control form-control-lg" id="pmf-search-autocomplete"
name="search" placeholder="{{ searchBox }} ..." maxlength="255" value="{{ searchTerm }}">
<button disabled=disabled type="submit" class="btn btn-primary btn-lg">{{ searchBox }}</button>
</form>
</div>
</div>
</div>
{% endif %}
</div>
{% endif %}
<ul class="navbar-nav flex-row flex-wrap ms-md-3">
{% if not isUserLoggedIn %}
{% if isUserRegistrationEnabled and action != "register" %}
<li class="nav-item pmf-nav-link"><a class="pmf-nav-link" href="./user/register">{{ msgRegisterUser }}</a></li>
{% endif %}
{% if action != "login" %}
<li class="nav-item pmf-nav-link "><a class="pmf-nav-link" href="./login">{{ msgLoginUser }}</a></li>
{% endif %}
{% else %}
<li class="nav-item dropdown">
<button type="button" class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle"
data-bs-toggle="dropdown" aria-expanded="false" data-bs-display="static">
{{ msgLoginUser }}
</button>
<ul class="dropdown-menu dropdown-menu-end">
{% if not isUserLoggedIn %}
{% if isUserRegistrationEnabled %}
<li><a class="dropdown-item" href="./user/register">{{ msgRegisterUser }}</a></li>
{% endif %}
<li><a class="dropdown-item" href="./login">{{ msgLoginUser }}</a></li>
{% else %}
<li><a class="dropdown-item" href="./user/ucp">{{ msgUserControlDropDown }}</a></li>
<li><a class="dropdown-item" href="./user/bookmarks">{{ msgBookmarks }}</a></li>
{% if isUserHasAdminRights %}
Expand All @@ -73,37 +96,14 @@
<li><a class="dropdown-item" href="./user/request-removal">{{ msgUserRemoval }}</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="./user/logout?csrf={{ csrfLogout }}">{{ msgLogoutUser }}</a></li>
{% endif %}
</ul>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>

<!-- SEARCH -->
{% if not isMaintenanceMode %}
<div class="container my-5">
<div class="row height d-flex justify-content-center align-items-center">
<div class="col-md-8">
<div class="search">
<form action="./search.html" id="search" method="post" role="search">
<i class="bi bi-search"></i>
<input autocomplete="off" type="text" class="form-control form-control-lg" id="pmf-search-autocomplete"
name="search" placeholder="{{ searchBox }} ..." maxlength="255" value="{{ searchTerm }}">
<button type="submit" class="btn btn-primary btn-lg">{{ searchBox }}</button>
</form>
</div>
<div>
<small class="form-text text-muted">
<a class="help" href="./search.html">{{ msgAdvancedSearch }}</a>
</small>
</div>
</div>
</div>
</div>
{% endif %}

<!-- BREADCRUMB -->
{% if showBreadcrumb %}
<section class="pmf-breadcrumbs">
Expand Down
6 changes: 3 additions & 3 deletions phpmyfaq/src/phpMyFAQ/Category/Order.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ public function getCategoryTree(array $categories, int $parentId = 0): array

foreach ($categories as $category) {
if ((int) $category['parent_id'] === $parentId) {
$children = $this->getCategoryTree($categories, $category['category_id']);
$result[$category['category_id']] = $children;
$children = $this->getCategoryTree($categories, $category['id']);
$result[$category['id']] = $children;
}
}

return $result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ public function index(Request $request): Response

$session = $this->container->get('session');
$categoryOrder = $this->container->get('phpmyfaq.category.order');
$orderedCategories = $categoryOrder->getAllCategories();
$categoryTree = $categoryOrder->getCategoryTree($orderedCategories);
$orderedCategories = $categoryOrder->getAllCategories();
$categoryTree = $categoryOrder->getCategoryTree($categoryInfo);


if (empty($categoryTree)) {
// Fallback if no category order is available
Expand Down
Loading