Skip to content

Commit

Permalink
Refactor the matcher logic
Browse files Browse the repository at this point in the history
  • Loading branch information
elchininet committed Jan 12, 2024
1 parent 3e9142b commit 31ba519
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 20 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ frontend:

Depending on the file that you have added to [extra_module_url], you will need to add your configuration in `JSON` or `YAML` format. If you used `custom-sidebar.js` you need to provide the configuration in `JSON` format. If you have used `custom-sidebar-yaml.js` you need to provide the configuration in `YAML` format.

Add a file named `sidebar-order.json` or `sidebar-order.yaml` into your `<config directory>/www/` directory. It could be easier if you copy the [example sidebar-order.json] or the [example sidebar-order.yaml] file, delete the `id` parameter, and edit it to match your needs.
Add a file named `sidebar-config.json` or `sidebar-config.yaml` into your `<config directory>/www/` directory. It could be easier if you copy the [example sidebar-order.json] or the [example sidebar-order.yaml] file, delete the `id` parameter, and edit it to match your needs.

### Configuration options

Expand All @@ -109,14 +109,15 @@ Add a file named `sidebar-order.json` or `sidebar-order.yaml` into your `<config

#### Item properties

| Property | Type | Required | Description |
| --------- | ------- | -------- | ----------- |
| item | String | true | This is a string that will be used to match each sidebar item by its text or its `data-panel` attribute. In the case of the item text, it can be a substring such as `developer` instead of `Developer Tools`. If the `exact` property is not set, it is case insensitive. |
| Property | Type | Required | Description |
| --------- | ------- | --------- | ----------- |
| item | String | true | This is a string that will be used to match each sidebar item by its text, its `data-panel` attribute or its `href`. If the `exact` property is not set, it is case insensitive and it can be a substring such as `developer` instead of `Developer Tools` or `KITCHEN` instead of `kitchen-lights`. |
| match | String | false | This property will define which string will be used to match the `item` property. It has three possible values "text" (default) to match the text content of the element, "data-panel" to match the `data-panel` attribute of the element, or "href", to match the `href` attribute of the element |
| exact | Boolean | false | Specifies whether the `item` string match should be an exact match (`true`) or not (`false`). |
| name | String | false | Changes the name of the sidebar item |
| order | Number | false | Sets the order number of the sidebar item |
| bottom | Boolean | false | Setting this property to `true` will group the item with the bottom items (Configuration, Developer Tools, etc) |
| hide | Boolean | false | Setting this property to `true` will hide the sidebar item |
| exact | Boolean | false | Specifies whether the `item` string match should be an exact match of the item text or an exact match of the `data-panel` attribute (case sensitive) |
| href | String | false | Specifies the `href` of the sidebar item |
| target | String | false | Specifies the [target property] of the sidebar item |
| icon | String | false | Specifies the icon of the sidebar item |
Expand Down Expand Up @@ -174,6 +175,7 @@ order:
#### Notes

* All items in `config.order` should have unique `item` property
* Avoid an `item` property that could match multiple elements. If you find that an item property matches with multiple elements, try to use the `match` and `exact` properties to match the specific item that you want to match.
* The items will be ordered according to their `order` property OR in the order of appearance
* If you use the `order` property, make sure either all items (except hidden ones) have this property, or none of them (otherwise order may be messed up)
* All the items placed in the bottom will be moved to the top by default. If you want to have some items in the bottom you need to add them to the `config.order` and specify their `bottom` property on `true`.
Expand Down
2 changes: 1 addition & 1 deletion src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const NAMESPACE = 'custom-sidebar';
export const CONFIG_PATH = '/local/sidebar-order';
export const CONFIG_PATH = '/local/sidebar-config';
export const MAX_ATTEMPTS = 500;
export const RETRY_DELAY = 50;

Expand Down
39 changes: 26 additions & 13 deletions src/custom-sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
ConfigOrderWithItem,
HomeAssistant,
PartialPanelResolver,
PaperListBox
PaperListBox,
Match
} from '@types';
import {
ELEMENT,
Expand Down Expand Up @@ -185,24 +186,36 @@ class CustomSidebar {

if (!order.length) return;

const itemsArray = Array.from(items);
const matched: Set<Element> = new Set();

const orderWithItems: ConfigOrderWithItem[] = order.map((orderItem: ConfigOrder): ConfigOrderWithItem => {
const { item, new_item, exact } = orderItem;
const { item, match, exact, new_item } = orderItem;
const itemLowerCase = item.toLocaleLowerCase();
const element = new_item
? undefined
: Array.from(items).find((element: Element): boolean => {
const text = element.querySelector(SELECTOR.ITEM_TEXT).textContent.trim();
const dataPanel = element.getAttribute(ATTRIBUTE.PANEL);
if (exact) {
return (
text === item ||
dataPanel === item
: itemsArray.find((element: Element): boolean => {
const text = match === Match.DATA_PANEL
? element.getAttribute(ATTRIBUTE.PANEL)
: (
match === Match.HREF
? element.getAttribute(ATTRIBUTE.HREF)
: element.querySelector(SELECTOR.ITEM_TEXT).textContent.trim()
);

const matchText = (
(!!exact && item === text) ||
(!exact && text.toLowerCase().includes(itemLowerCase))
);
if (matchText) {
if (matched.has(element)) {
return false;
} else {
matched.add(element);
return true;
}
}
if (dataPanel.toLocaleLowerCase() === itemLowerCase) {
return true;
}
return text.toLocaleLowerCase().includes(itemLowerCase);
return false;
});
if (element) {
element.setAttribute(ATTRIBUTE.PROCESSED, 'true');
Expand Down
9 changes: 8 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ export interface PaperListBox extends HTMLElement {
_updateAttrForSelected: () => void;
}

export enum Match {
TEXT = 'text',
DATA_PANEL = 'data-panel',
HREF = 'href'
}

export interface ConfigItem {
item: string;
match?: `${Match}`;
exact?: boolean;
name?: string;
order?: number;
bottom?: boolean;
hide?: boolean;
exact?: boolean;
href?: string;
target?: '_self' | '_blank';
icon?: string;
Expand Down

0 comments on commit 31ba519

Please sign in to comment.