mirror of https://github.com/ColorlibHQ/AdminLTE
REJack
5 years ago
2 changed files with 227 additions and 0 deletions
@ -0,0 +1,225 @@ |
|||||||
|
/** |
||||||
|
* -------------------------------------------- |
||||||
|
* AdminLTE SidebarSearch.js |
||||||
|
* License MIT |
||||||
|
* -------------------------------------------- |
||||||
|
*/ |
||||||
|
|
||||||
|
import $, { trim } from 'jquery' |
||||||
|
|
||||||
|
/** |
||||||
|
* Constants |
||||||
|
* ==================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
const NAME = 'SidebarSearch' |
||||||
|
const DATA_KEY = 'lte.sidebar-search' |
||||||
|
const JQUERY_NO_CONFLICT = $.fn[NAME] |
||||||
|
|
||||||
|
const CLASS_NAME_OPEN = 'sidebar-search-open' |
||||||
|
const CLASS_NAME_ICON_SEARCH = 'fa-search' |
||||||
|
const CLASS_NAME_ICON_CLOSE = 'fa-times' |
||||||
|
const CLASS_NAME_HEADER = 'nav-header' |
||||||
|
const CLASS_NAME_SEARCH_RESULTS = 'sidebar-search-results' |
||||||
|
const CLASS_NAME_LIST_GROUP = 'list-group' |
||||||
|
|
||||||
|
const SELECTOR_DATA_WIDGET = '[data-widget="sidebar-search"]' |
||||||
|
const SELECTOR_SIDEBAR = '.main-sidebar .nav-sidebar' |
||||||
|
const SELECTOR_NAV_LINK = '.nav-link' |
||||||
|
const SELECTOR_NAV_TREEVIEW = '.nav-treeview' |
||||||
|
const SELECTOR_SEARCH_INPUT = `${SELECTOR_DATA_WIDGET} .form-control` |
||||||
|
const SELECTOR_SEARCH_BUTTON = `${SELECTOR_DATA_WIDGET} .btn` |
||||||
|
const SELECTOR_SEARCH_ICON = `${SELECTOR_SEARCH_BUTTON} i` |
||||||
|
const SELECTOR_SEARCH_LIST_GROUP = `.${CLASS_NAME_LIST_GROUP}` |
||||||
|
const SELECTOR_SEARCH_RESULTS = `.${CLASS_NAME_SEARCH_RESULTS}` |
||||||
|
const SELECTOR_SEARCH_RESULTS_GROUP = `${SELECTOR_SEARCH_RESULTS} .${CLASS_NAME_LIST_GROUP}` |
||||||
|
|
||||||
|
const Default = { |
||||||
|
arrowSign: '->', |
||||||
|
minLength: 3, |
||||||
|
maxResults: 7, |
||||||
|
notFoundText: 'No element found!' |
||||||
|
} |
||||||
|
|
||||||
|
const SearchItems = [] |
||||||
|
|
||||||
|
/** |
||||||
|
* Class Definition |
||||||
|
* ==================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
class SidebarSearch { |
||||||
|
constructor(_element, _options) { |
||||||
|
this.element = _element |
||||||
|
this.options = $.extend({}, Default, _options) |
||||||
|
this.items = [] |
||||||
|
} |
||||||
|
|
||||||
|
// Public
|
||||||
|
|
||||||
|
init() { |
||||||
|
if ($(SELECTOR_DATA_WIDGET).next(SELECTOR_SEARCH_RESULTS).length == 0) { |
||||||
|
$(SELECTOR_DATA_WIDGET).after( |
||||||
|
$('<div />', { class: CLASS_NAME_SEARCH_RESULTS }) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
if ($(SELECTOR_SEARCH_RESULTS).children(SELECTOR_SEARCH_LIST_GROUP).length == 0) { |
||||||
|
$(SELECTOR_SEARCH_RESULTS).append( |
||||||
|
$('<div />', { class: CLASS_NAME_LIST_GROUP }) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
this._addNotFound() |
||||||
|
|
||||||
|
$(SELECTOR_SIDEBAR).children().each((i, child) => { |
||||||
|
this._parseItem(child) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
search() { |
||||||
|
const searchValue = $(SELECTOR_SEARCH_INPUT).val().toLowerCase() |
||||||
|
if (searchValue.length < this.options.minLength) { |
||||||
|
$(SELECTOR_SEARCH_RESULTS_GROUP).empty() |
||||||
|
this._addNotFound() |
||||||
|
this.close() |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const searchResults = SearchItems.filter(item => (item.name).toLowerCase().includes(searchValue)) |
||||||
|
const endResults = $(searchResults.slice(0, this.options.maxResults)) |
||||||
|
$(SELECTOR_SEARCH_RESULTS_GROUP).empty() |
||||||
|
|
||||||
|
if (endResults.length === 0) { |
||||||
|
this._addNotFound() |
||||||
|
} else { |
||||||
|
endResults.each((i, result) => { |
||||||
|
$(SELECTOR_SEARCH_RESULTS_GROUP).append(this._renderItem(result.name, result.link, result.path)) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
this.open() |
||||||
|
} |
||||||
|
|
||||||
|
open() { |
||||||
|
$(SELECTOR_DATA_WIDGET).parent().addClass(CLASS_NAME_OPEN) |
||||||
|
$(SELECTOR_SEARCH_ICON).removeClass(CLASS_NAME_ICON_SEARCH).addClass(CLASS_NAME_ICON_CLOSE) |
||||||
|
} |
||||||
|
|
||||||
|
close() { |
||||||
|
$(SELECTOR_DATA_WIDGET).parent().removeClass(CLASS_NAME_OPEN) |
||||||
|
$(SELECTOR_SEARCH_ICON).removeClass(CLASS_NAME_ICON_CLOSE).addClass(CLASS_NAME_ICON_SEARCH) |
||||||
|
} |
||||||
|
|
||||||
|
toggle() { |
||||||
|
if ($(SELECTOR_DATA_WIDGET).parent().hasClass(CLASS_NAME_OPEN)) { |
||||||
|
this.close() |
||||||
|
} else { |
||||||
|
this.open() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Private
|
||||||
|
|
||||||
|
_parseItem(item, path = []) { |
||||||
|
if ($(item).hasClass(CLASS_NAME_HEADER)) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const itemObject = {} |
||||||
|
const navLink = $(item).clone().find(`> ${SELECTOR_NAV_LINK}`) |
||||||
|
const navTreeview = $(item).clone().find(`> ${SELECTOR_NAV_TREEVIEW}`) |
||||||
|
|
||||||
|
const link = navLink.attr('href') |
||||||
|
const name = navLink.find('p').children().remove().end().text() |
||||||
|
|
||||||
|
itemObject.name = this._trimText(name) |
||||||
|
itemObject.link = link |
||||||
|
itemObject.path = path |
||||||
|
|
||||||
|
if (navTreeview.length === 0) { |
||||||
|
SearchItems.push(itemObject) |
||||||
|
} else { |
||||||
|
const newPath = itemObject.path.concat([itemObject.name]) |
||||||
|
navTreeview.children().each((i, child) => { |
||||||
|
this._parseItem(child, newPath) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_trimText(text) { |
||||||
|
return trim(text.replace(/(\r\n|\n|\r)/gm, ' ')) |
||||||
|
} |
||||||
|
|
||||||
|
_renderItem(name, link, path) { |
||||||
|
return `<a href="${link}" class="list-group-item">
|
||||||
|
<div class="search-title"> |
||||||
|
${name} |
||||||
|
</div> |
||||||
|
<div class="search-path"> |
||||||
|
${path.join(` ${this.options.arrowSign} `)} |
||||||
|
</div> |
||||||
|
</a>` |
||||||
|
} |
||||||
|
|
||||||
|
_addNotFound() { |
||||||
|
$(SELECTOR_SEARCH_RESULTS_GROUP).append(this._renderItem(this.options.notFoundText, '#', [])) |
||||||
|
} |
||||||
|
|
||||||
|
// Static
|
||||||
|
|
||||||
|
static _jQueryInterface(config) { |
||||||
|
let data = $(this).data(DATA_KEY) |
||||||
|
|
||||||
|
if (!data) { |
||||||
|
data = $(this).data() |
||||||
|
} |
||||||
|
|
||||||
|
const _options = $.extend({}, Default, typeof config === 'object' ? config : data) |
||||||
|
const plugin = new SidebarSearch($(this), _options) |
||||||
|
|
||||||
|
$(this).data(DATA_KEY, typeof config === 'object' ? config : data) |
||||||
|
|
||||||
|
if (typeof config === 'string' && config.match(/init|toggle|close|open|search/)) { |
||||||
|
plugin[config]() |
||||||
|
} else { |
||||||
|
plugin.init() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Data API |
||||||
|
* ==================================================== |
||||||
|
*/ |
||||||
|
$(document).on('click', SELECTOR_SEARCH_BUTTON, event => { |
||||||
|
event.preventDefault() |
||||||
|
|
||||||
|
SidebarSearch._jQueryInterface.call($(SELECTOR_DATA_WIDGET), 'toggle') |
||||||
|
}) |
||||||
|
|
||||||
|
$(document).on('keyup', SELECTOR_SEARCH_INPUT, () => { |
||||||
|
let timer = 0 |
||||||
|
clearTimeout(timer) |
||||||
|
timer = setTimeout(() => { |
||||||
|
SidebarSearch._jQueryInterface.call($(SELECTOR_DATA_WIDGET), 'search') |
||||||
|
}, 100) |
||||||
|
}) |
||||||
|
|
||||||
|
$(window).on('load', () => { |
||||||
|
SidebarSearch._jQueryInterface.call($(SELECTOR_DATA_WIDGET), 'init') |
||||||
|
}) |
||||||
|
|
||||||
|
/** |
||||||
|
* jQuery API |
||||||
|
* ==================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
$.fn[NAME] = SidebarSearch._jQueryInterface |
||||||
|
$.fn[NAME].Constructor = SidebarSearch |
||||||
|
$.fn[NAME].noConflict = function () { |
||||||
|
$.fn[NAME] = JQUERY_NO_CONFLICT |
||||||
|
return SidebarSearch._jQueryInterface |
||||||
|
} |
||||||
|
|
||||||
|
export default SidebarSearch |
Loading…
Reference in new issue