mirror of
https://github.com/codex-team/codex.docs.git
synced 2025-08-08 06:55:26 +02:00
sidebar search=>filter
This commit is contained in:
parent
8a865383fa
commit
0619af1bd0
3 changed files with 275 additions and 266 deletions
270
src/frontend/js/classes/sidebar-filter.js
Normal file
270
src/frontend/js/classes/sidebar-filter.js
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
/**
|
||||||
|
* HEIGHT of the header in px
|
||||||
|
*/
|
||||||
|
const HEADER_HEIGHT = 56;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sidebar Search module.
|
||||||
|
*/
|
||||||
|
export default class SidebarFilter {
|
||||||
|
/**
|
||||||
|
* CSS classes
|
||||||
|
*
|
||||||
|
* @returns {Record<string, string>}
|
||||||
|
*/
|
||||||
|
static get CSS() {
|
||||||
|
return {
|
||||||
|
sectionHidden: 'docs-sidebar__section--hidden',
|
||||||
|
sectionTitle: 'docs-sidebar__section-title',
|
||||||
|
sectionTitleSelected: 'docs-sidebar__section-title--selected',
|
||||||
|
sectionList: 'docs-sidebar__section-list',
|
||||||
|
sectionListItem: 'docs-sidebar__section-list-item',
|
||||||
|
sectionListItemWrapperHidden: 'docs-sidebar__section-list-item-wrapper--hidden',
|
||||||
|
sectionListItemSlelected: 'docs-sidebar__section-list-item--selected',
|
||||||
|
sidebarSearchWrapperMac: 'docs-sidebar__search-wrapper-mac',
|
||||||
|
sidebarSearchWrapperOther: 'docs-sidebar__search-wrapper-other',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates base properties
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
/**
|
||||||
|
* Stores refs to HTML elements needed for sidebar filter to work.
|
||||||
|
*/
|
||||||
|
this.sidebar = null;
|
||||||
|
this.sections = [];
|
||||||
|
this.sidebarContent = null;
|
||||||
|
this.search = null;
|
||||||
|
this.searchResults = [];
|
||||||
|
this.selectedSearchResultIndex = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
init(sections, sidebarContent, search)
|
||||||
|
{
|
||||||
|
this.sections = sections;
|
||||||
|
this.sidebarContent = sidebarContent;
|
||||||
|
this.search = search;
|
||||||
|
let className = SidebarFilter.CSS.sidebarSearchWrapperOther;
|
||||||
|
|
||||||
|
// Search initialize with platform specific shortcut.
|
||||||
|
if (window.navigator.userAgent.indexOf('Mac') != -1) {
|
||||||
|
className = SidebarFilter.CSS.sidebarSearchWrapperMac;
|
||||||
|
}
|
||||||
|
this.search.parentElement.classList.add(className);
|
||||||
|
|
||||||
|
// Add event listener for search input.
|
||||||
|
this.search.addEventListener('input', e => {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
this.filterSections(e.target.value);
|
||||||
|
});
|
||||||
|
// Initialize the search results.
|
||||||
|
this.filterSections('');
|
||||||
|
|
||||||
|
// Add event listener for keyboard events.
|
||||||
|
this.search.addEventListener('keydown', e => this.handleKeyboardEvent(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle keyboard events when search input is focused.
|
||||||
|
*
|
||||||
|
* @param {Event} e - Event Object.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
handleKeyboardEvent(e) {
|
||||||
|
// Return if search is not focused.
|
||||||
|
if (this.search !== document.activeElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if enter is pressed and item is focused, then click on focused item.
|
||||||
|
if (e.code === 'Enter' && this.selectedSearchResultIndex !== null) {
|
||||||
|
// goto focused item.
|
||||||
|
this.searchResults[this.selectedSearchResultIndex].element.click();
|
||||||
|
// prevent default action.
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.code === 'ArrowUp' || e.code === 'ArrowDown') {
|
||||||
|
// check for search results.
|
||||||
|
if (this.searchResults.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// get current focused item.
|
||||||
|
const prevSelectedSearchResultIndex = this.selectedSearchResultIndex;
|
||||||
|
|
||||||
|
this.selectedSearchResultIndex = this.getNextSectionOrItemIndex(e.code,
|
||||||
|
this.selectedSearchResultIndex,
|
||||||
|
this.searchResults.length - 1);
|
||||||
|
|
||||||
|
this.blurSectionOrItem(prevSelectedSearchResultIndex);
|
||||||
|
|
||||||
|
this.focusSectionOrItem(this.selectedSearchResultIndex);
|
||||||
|
|
||||||
|
// prevent default action.
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getNextSectionOrItemIndex(code, sectionOrItemIndex, maxNumberOfSectionsOrItems) {
|
||||||
|
let nextSectionOrItemIndex = sectionOrItemIndex;
|
||||||
|
|
||||||
|
if (code === 'ArrowUp') {
|
||||||
|
if (sectionOrItemIndex === null) {
|
||||||
|
return maxNumberOfSectionsOrItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextSectionOrItemIndex--;
|
||||||
|
|
||||||
|
if (nextSectionOrItemIndex < 0) {
|
||||||
|
nextSectionOrItemIndex = maxNumberOfSectionsOrItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextSectionOrItemIndex;
|
||||||
|
}
|
||||||
|
else if (code === 'ArrowDown') {
|
||||||
|
if (sectionOrItemIndex === null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextSectionOrItemIndex++;
|
||||||
|
|
||||||
|
if (nextSectionOrItemIndex > maxNumberOfSectionsOrItems) {
|
||||||
|
nextSectionOrItemIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextSectionOrItemIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
focusSectionOrItem(sectionOrItemIndex) {
|
||||||
|
if (sectionOrItemIndex === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { element, type } = this.searchResults[sectionOrItemIndex];
|
||||||
|
|
||||||
|
if (!element || !type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'title') {
|
||||||
|
element.classList.add(SidebarFilter.CSS.sectionTitleSelected);
|
||||||
|
} else if (type === 'item') {
|
||||||
|
element.classList.add(SidebarFilter.CSS.sectionListItemSlelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollToSectionOrItem(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
blurSectionOrItem(sectionOrItemIndex) {
|
||||||
|
if (sectionOrItemIndex === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { element, type } = this.searchResults[sectionOrItemIndex];
|
||||||
|
|
||||||
|
if (!element || !type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'title') {
|
||||||
|
element.classList.remove(SidebarFilter.CSS.sectionTitleSelected);
|
||||||
|
} else if (type === 'item') {
|
||||||
|
element.classList.remove(SidebarFilter.CSS.sectionListItemSlelected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToSectionOrItem(sectionOrItem) {
|
||||||
|
// check if it's visible.
|
||||||
|
const rect = sectionOrItem.getBoundingClientRect();
|
||||||
|
let elemTop = rect.top;
|
||||||
|
let elemBottom = rect.bottom;
|
||||||
|
const halfOfViewport = window.innerHeight / 2;
|
||||||
|
const scrollTop = this.sidebarContent.scrollTop;
|
||||||
|
|
||||||
|
// scroll top if item is not visible.
|
||||||
|
if (elemTop < HEADER_HEIGHT) {
|
||||||
|
// scroll half viewport up.
|
||||||
|
const nextTop = scrollTop - halfOfViewport;
|
||||||
|
|
||||||
|
// check if element visible after scroll.
|
||||||
|
elemTop = (elemTop + nextTop) < HEADER_HEIGHT ? elemTop : nextTop;
|
||||||
|
this.sidebarContent.scroll({
|
||||||
|
top: elemTop,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
} else if (elemBottom > window.innerHeight) {
|
||||||
|
// scroll bottom if item is not visible.
|
||||||
|
// scroll half viewport down.
|
||||||
|
const nextDown = halfOfViewport + scrollTop;
|
||||||
|
|
||||||
|
// check if element visible after scroll.
|
||||||
|
elemBottom = (elemBottom - nextDown) > window.innerHeight ? elemBottom : nextDown;
|
||||||
|
this.sidebarContent.scroll({
|
||||||
|
top: elemBottom,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterSections(searchValue) {
|
||||||
|
// remove selection from previous search results.
|
||||||
|
this.blurSectionOrItem(this.selectedSearchResultIndex);
|
||||||
|
// empty selected index.
|
||||||
|
this.selectedSearchResultIndex = null;
|
||||||
|
// empty search results.
|
||||||
|
this.searchResults = [];
|
||||||
|
// match search value with sidebar sections.
|
||||||
|
this.sections.forEach(section => {
|
||||||
|
// match with section title.
|
||||||
|
const sectionTitle = section.querySelector('.' + SidebarFilter.CSS.sectionTitle);
|
||||||
|
const isTitleMatch = sectionTitle.innerText.trim().toLowerCase()
|
||||||
|
.indexOf(searchValue.toLowerCase()) !== -1;
|
||||||
|
const matchResults = [];
|
||||||
|
// match with section items.
|
||||||
|
const sectionList = section.querySelector('.' + SidebarFilter.CSS.sectionList);
|
||||||
|
let isSingleItemMatch = false;
|
||||||
|
|
||||||
|
if (sectionList) {
|
||||||
|
const sectionListItems = sectionList.querySelectorAll('.' + SidebarFilter.CSS.sectionListItem);
|
||||||
|
|
||||||
|
sectionListItems.forEach(item => {
|
||||||
|
if (item.innerText.trim().toLowerCase()
|
||||||
|
.indexOf(searchValue.toLowerCase()) !== -1) {
|
||||||
|
// remove hiden class from item.
|
||||||
|
item.parentElement.classList.remove(SidebarFilter.CSS.sectionListItemWrapperHidden);
|
||||||
|
// add item to search results.
|
||||||
|
matchResults.push({
|
||||||
|
element: item,
|
||||||
|
type: 'item',
|
||||||
|
});
|
||||||
|
isSingleItemMatch = true;
|
||||||
|
} else {
|
||||||
|
// hide item if it is not a match.
|
||||||
|
item.parentElement.classList.add(SidebarFilter.CSS.sectionListItemWrapperHidden);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!isTitleMatch && !isSingleItemMatch) {
|
||||||
|
// hide section and it's items are not a match.
|
||||||
|
section.classList.add(SidebarFilter.CSS.sectionHidden);
|
||||||
|
} else {
|
||||||
|
// show section and it's items are a match.
|
||||||
|
section.classList.remove(SidebarFilter.CSS.sectionHidden);
|
||||||
|
// add section title to search results.
|
||||||
|
this.searchResults.push({
|
||||||
|
element: sectionTitle,
|
||||||
|
type: 'title',
|
||||||
|
}, ...matchResults);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,262 +0,0 @@
|
||||||
/**
|
|
||||||
* HEIGHT of the header in px
|
|
||||||
*/
|
|
||||||
const HEADER_HEIGHT = 56;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sidebar module
|
|
||||||
*/
|
|
||||||
export default class SidebarSearch {
|
|
||||||
/**
|
|
||||||
* CSS classes
|
|
||||||
*
|
|
||||||
* @returns {Record<string, string>}
|
|
||||||
*/
|
|
||||||
static get CSS() {
|
|
||||||
return {
|
|
||||||
sectionHidden: 'docs-sidebar__section--hidden',
|
|
||||||
sectionTitle: 'docs-sidebar__section-title',
|
|
||||||
sectionTitleSelected: 'docs-sidebar__section-title--selected',
|
|
||||||
sectionList: 'docs-sidebar__section-list',
|
|
||||||
sectionListItem: 'docs-sidebar__section-list-item',
|
|
||||||
sectionListItemWrapperHidden: 'docs-sidebar__section-list-item-wrapper--hidden',
|
|
||||||
sectionListItemSlelected: 'docs-sidebar__section-list-item--selected',
|
|
||||||
sidebarSearchWrapperMac: 'docs-sidebar__search-wrapper-mac',
|
|
||||||
sidebarSearchWrapperOther: 'docs-sidebar__search-wrapper-other',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates base properties
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
/**
|
|
||||||
* Stores refs to HTML elements needed for correct sidebar work
|
|
||||||
*/
|
|
||||||
this.sidebar = null;
|
|
||||||
this.sections = [];
|
|
||||||
this.sidebarContent = null;
|
|
||||||
this.search = null;
|
|
||||||
this.searchResults = [];
|
|
||||||
this.selectedSearchResultIndex = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} sections
|
|
||||||
* @param {*} sidebarContent
|
|
||||||
* @param {*} search
|
|
||||||
*/
|
|
||||||
init(sections, sidebarContent, search)
|
|
||||||
{
|
|
||||||
this.sections = sections;
|
|
||||||
this.sidebarContent = sidebarContent;
|
|
||||||
this.search = search;
|
|
||||||
let className = SidebarSearch.CSS.sidebarSearchWrapperOther;
|
|
||||||
|
|
||||||
// Search initialize with platform specific shortcut.
|
|
||||||
if (window.navigator.userAgent.indexOf('Mac') != -1) {
|
|
||||||
className = SidebarSearch.CSS.sidebarSearchWrapperMac;
|
|
||||||
}
|
|
||||||
this.search.parentElement.classList.add(className);
|
|
||||||
|
|
||||||
// Add event listener for search input.
|
|
||||||
this.search.addEventListener('input', e => {
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
this.filterSections(e.target.value);
|
|
||||||
});
|
|
||||||
// Initialize the search results.
|
|
||||||
this.filterSections('');
|
|
||||||
|
|
||||||
// Add event listener for keyboard events.
|
|
||||||
this.search.addEventListener('keydown', e => this.handleKeyboardEventOnSearch(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle keyboard events when search input is focused.
|
|
||||||
*
|
|
||||||
* @param {Event} e - Event Object.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
handleKeyboardEventOnSearch(e) {
|
|
||||||
// Return if search is not focused.
|
|
||||||
if (this.search !== document.activeElement) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if enter is pressed and item is focused, then click on focused item.
|
|
||||||
if (e.code === 'Enter' && this.selectedSearchResultIndex !== null) {
|
|
||||||
// goto focused item.
|
|
||||||
this.searchResults[this.selectedSearchResultIndex].element.click();
|
|
||||||
// prevent default action.
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.code === 'ArrowUp' || e.code === 'ArrowDown') {
|
|
||||||
// check for search results.
|
|
||||||
if (this.searchResults.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// get current focused item.
|
|
||||||
const prevSelectedSearchResultIndex = this.selectedSearchResultIndex;
|
|
||||||
|
|
||||||
// get next item index.
|
|
||||||
if (this.selectedSearchResultIndex === null) {
|
|
||||||
// if no item is focused and up press, focus last item.
|
|
||||||
if (e.code === 'ArrowUp') {
|
|
||||||
this.selectedSearchResultIndex = this.searchResults.length - 1;
|
|
||||||
} else if (e.code === 'ArrowDown') {
|
|
||||||
// if no item is focused and down press, focus first item.
|
|
||||||
this.selectedSearchResultIndex = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if item is focused and up press, focus previous item.
|
|
||||||
if (e.code === 'ArrowUp') {
|
|
||||||
this.selectedSearchResultIndex--;
|
|
||||||
if (this.selectedSearchResultIndex < 0) {
|
|
||||||
this.selectedSearchResultIndex = this.searchResults.length - 1;
|
|
||||||
}
|
|
||||||
} else if (e.code === 'ArrowDown') {
|
|
||||||
// if item is focused and down press, focus next item.
|
|
||||||
this.selectedSearchResultIndex++;
|
|
||||||
if (this.selectedSearchResultIndex >= this.searchResults.length) {
|
|
||||||
this.selectedSearchResultIndex = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove focus from previous item.
|
|
||||||
if (prevSelectedSearchResultIndex !== null) {
|
|
||||||
const { element: preElement, type: preType } = this.searchResults[prevSelectedSearchResultIndex];
|
|
||||||
|
|
||||||
if (preElement) {
|
|
||||||
// remove focus from previous item or title.
|
|
||||||
if (preType === 'title') {
|
|
||||||
preElement.classList.remove(SidebarSearch.CSS.sectionTitleSelected);
|
|
||||||
} else if (preType === 'item') {
|
|
||||||
preElement.classList.remove(SidebarSearch.CSS.sectionListItemSlelected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { element, type } = this.searchResults[this.selectedSearchResultIndex];
|
|
||||||
|
|
||||||
if (element) {
|
|
||||||
// add focus to next item or title.
|
|
||||||
if (type === 'title') {
|
|
||||||
element.classList.add(SidebarSearch.CSS.sectionTitleSelected);
|
|
||||||
} else if (type === 'item') {
|
|
||||||
element.classList.add(SidebarSearch.CSS.sectionListItemSlelected);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if it's visible.
|
|
||||||
const rect = element.getBoundingClientRect();
|
|
||||||
let elemTop = rect.top;
|
|
||||||
let elemBottom = rect.bottom;
|
|
||||||
const halfOfViewport = window.innerHeight / 2;
|
|
||||||
const scrollTop = this.sidebarContent.scrollTop;
|
|
||||||
|
|
||||||
// scroll top if item is not visible.
|
|
||||||
if (elemTop < HEADER_HEIGHT) {
|
|
||||||
// scroll half viewport up.
|
|
||||||
const nextTop = scrollTop - halfOfViewport;
|
|
||||||
|
|
||||||
// check if element visible after scroll.
|
|
||||||
elemTop = (elemTop + nextTop) < HEADER_HEIGHT ? elemTop : nextTop;
|
|
||||||
this.sidebarContent.scroll({
|
|
||||||
top: elemTop,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
} else if (elemBottom > window.innerHeight) {
|
|
||||||
// scroll bottom if item is not visible.
|
|
||||||
// scroll half viewport down.
|
|
||||||
const nextDown = halfOfViewport + scrollTop;
|
|
||||||
|
|
||||||
// check if element visible after scroll.
|
|
||||||
elemBottom = (elemBottom - nextDown) > window.innerHeight ? elemBottom : nextDown;
|
|
||||||
this.sidebarContent.scroll({
|
|
||||||
top: elemBottom,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// prevent default action.
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filterSections(searchValue) {
|
|
||||||
// remove selection from previous search results.
|
|
||||||
if (this.selectedSearchResultIndex) {
|
|
||||||
const { element, type } = this.searchResults[this.selectedSearchResultIndex];
|
|
||||||
|
|
||||||
if (element) {
|
|
||||||
// remove focus from previous item or title.
|
|
||||||
if (type === 'title') {
|
|
||||||
element.classList.remove(SidebarSearch.CSS.sectionTitleSelected);
|
|
||||||
} else if (type === 'item') {
|
|
||||||
element.classList.remove(SidebarSearch.CSS.sectionListItemSlelected);
|
|
||||||
}
|
|
||||||
// empty selected index.
|
|
||||||
this.selectedSearchResultIndex = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// empty search results.
|
|
||||||
this.searchResults = [];
|
|
||||||
// match search value with sidebar sections.
|
|
||||||
this.sections.forEach(section => {
|
|
||||||
// match with section title.
|
|
||||||
const sectionTitle = section.querySelector('.' + SidebarSearch.CSS.sectionTitle);
|
|
||||||
let isTitleMatch = true;
|
|
||||||
const matchResults = [];
|
|
||||||
|
|
||||||
if (sectionTitle.innerText.trim().toLowerCase()
|
|
||||||
.indexOf(searchValue.toLowerCase()) === -1) {
|
|
||||||
isTitleMatch = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// match with section items.
|
|
||||||
const sectionList = section.querySelector('.' + SidebarSearch.CSS.sectionList);
|
|
||||||
let isItemMatch = false;
|
|
||||||
|
|
||||||
if (sectionList) {
|
|
||||||
const sectionListItems = sectionList.querySelectorAll('.' + SidebarSearch.CSS.sectionListItem);
|
|
||||||
|
|
||||||
sectionListItems.forEach(item => {
|
|
||||||
if (item.innerText.trim().toLowerCase()
|
|
||||||
.indexOf(searchValue.toLowerCase()) !== -1) {
|
|
||||||
// remove hiden class from item.
|
|
||||||
item.parentElement.classList.remove(SidebarSearch.CSS.sectionListItemWrapperHidden);
|
|
||||||
// add item to search results.
|
|
||||||
matchResults.push({
|
|
||||||
element: item,
|
|
||||||
type: 'item',
|
|
||||||
});
|
|
||||||
isItemMatch = true;
|
|
||||||
} else {
|
|
||||||
// hide item if it is not a match.
|
|
||||||
item.parentElement.classList.add(SidebarSearch.CSS.sectionListItemWrapperHidden);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!isTitleMatch && !isItemMatch) {
|
|
||||||
// hide section and it's items are not a match.
|
|
||||||
section.classList.add(SidebarSearch.CSS.sectionHidden);
|
|
||||||
} else {
|
|
||||||
// show section and it's items are a match.
|
|
||||||
section.classList.remove(SidebarSearch.CSS.sectionHidden);
|
|
||||||
// add section title to search results.
|
|
||||||
this.searchResults.push({
|
|
||||||
element: sectionTitle,
|
|
||||||
type: 'title',
|
|
||||||
}, ...matchResults);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Storage } from '../utils/storage';
|
import { Storage } from '../utils/storage';
|
||||||
import Shortcut from '@codexteam/shortcuts';
|
import Shortcut from '@codexteam/shortcuts';
|
||||||
import SidebarSearch from '../classes/sidebar-search';
|
import SidebarFilter from '../classes/sidebar-filter';
|
||||||
/**
|
/**
|
||||||
* Local storage key
|
* Local storage key
|
||||||
*/
|
*/
|
||||||
|
@ -69,8 +69,8 @@ export default class Sidebar {
|
||||||
|
|
||||||
// Sidebar visibility
|
// Sidebar visibility
|
||||||
this.isVisible = storedVisibility !== 'false';
|
this.isVisible = storedVisibility !== 'false';
|
||||||
// Sidebar search module
|
// Sidebar filter module
|
||||||
this.search = new SidebarSearch();
|
this.filter = new SidebarFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,7 +90,7 @@ export default class Sidebar {
|
||||||
this.nodes.slider.addEventListener('click', () => this.handleSliderClick());
|
this.nodes.slider.addEventListener('click', () => this.handleSliderClick());
|
||||||
|
|
||||||
this.nodes.search = moduleEl.querySelector('.' + Sidebar.CSS.sidebarSearch);
|
this.nodes.search = moduleEl.querySelector('.' + Sidebar.CSS.sidebarSearch);
|
||||||
this.search.init(this.nodes.sections, this.nodes.sidebarContent, this.nodes.search);
|
this.filter.init(this.nodes.sections, this.nodes.sidebarContent, this.nodes.search);
|
||||||
|
|
||||||
this.ready();
|
this.ready();
|
||||||
}
|
}
|
||||||
|
@ -231,6 +231,7 @@ export default class Sidebar {
|
||||||
// make sidebar visible.
|
// make sidebar visible.
|
||||||
this.handleSliderClick();
|
this.handleSliderClick();
|
||||||
}
|
}
|
||||||
|
// focus search input.
|
||||||
this.nodes.search.focus();
|
this.nodes.search.focus();
|
||||||
// Stop propagation of event.
|
// Stop propagation of event.
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue