Skip to content

Commit 4739411

Browse files
authored
Merge pull request #1168 from helsingborg-stad/refactor/move-select
refactor: move select and nav
2 parents fe83fd3 + 4b64117 commit 4739411

File tree

11 files changed

+358
-510
lines changed

11 files changed

+358
-510
lines changed

source/components/nav/index.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
export class Nav {
2+
private targetItemSelector: string;
3+
4+
constructor(menu: HTMLElement) {
5+
this.targetItemSelector = '.c-nav__item.has-children.has-toggle';
6+
const selectorArray: string[] = [this.targetItemSelector, '> .c-nav__item-wrapper'];
7+
8+
// Allow to click main item if vertical or extended dropdown
9+
if (menu.classList.contains('c-nav--vertical')) {
10+
selectorArray.push('.c-nav__toggle');
11+
}
12+
13+
// Extended dropdown open by clicking main items or subitems on the arrow.
14+
if (menu.classList.contains('c-nav--extended-dropdown')) {
15+
selectorArray.unshift(':scope ul');
16+
selectorArray.push('.c-nav__toggle, :scope > li.has-toggle > .c-nav__item-wrapper');
17+
}
18+
19+
const items = [...menu.querySelectorAll(selectorArray.join(' '))] as HTMLElement[];
20+
21+
if (items.length > 0) {
22+
this.setListeners(items, menu);
23+
}
24+
}
25+
26+
private setListeners(items: HTMLElement[], menu: HTMLElement) {
27+
items.forEach((item) => {
28+
item.addEventListener('click', (e) => {
29+
e.preventDefault();
30+
e.stopPropagation();
31+
if (menu.classList.contains('c-nav--horizontal')) {
32+
this.closeSiblings(item.closest(this.targetItemSelector) as HTMLElement);
33+
}
34+
35+
this.toggleChildren(item.closest(this.targetItemSelector) as HTMLElement);
36+
});
37+
});
38+
}
39+
40+
private closeSiblings(clickItem: HTMLElement) {
41+
const items = this.getSiblings(clickItem);
42+
items.forEach((item) => {
43+
item.classList.remove('is-open');
44+
});
45+
return true;
46+
}
47+
48+
private toggleChildren(toggle: HTMLElement) {
49+
if (!toggle.classList.contains('is-open')) {
50+
this.openChildren(toggle);
51+
return true;
52+
}
53+
this.closeChildren(toggle);
54+
return false;
55+
}
56+
57+
private openChildren(toggle: HTMLElement) {
58+
toggle.classList.add('is-open');
59+
toggle.querySelector('.c-nav__toggle')?.setAttribute('aria-pressed', 'true');
60+
}
61+
62+
private closeChildren(toggle: HTMLElement) {
63+
toggle.classList.remove('is-open');
64+
toggle.querySelector('.c-nav__toggle')?.setAttribute('aria-pressed', 'false');
65+
}
66+
67+
private getSiblings(elem: HTMLElement) {
68+
const siblings: HTMLElement[] = [];
69+
let sibling = elem.parentNode?.firstChild;
70+
while (sibling) {
71+
if (sibling.nodeType === Node.ELEMENT_NODE && sibling !== elem) {
72+
siblings.push(sibling as HTMLElement);
73+
}
74+
sibling = sibling.nextSibling;
75+
}
76+
return siblings;
77+
}
78+
}
79+
80+
// Initialize Nav components on DOMContentLoaded
81+
document.addEventListener('DOMContentLoaded', () => {
82+
const menus = [...document.querySelectorAll('.c-nav.c-nav--depth-1')] as HTMLElement[];
83+
84+
menus.forEach((menu) => {
85+
new Nav(menu);
86+
const observer = new MutationObserver((mutations) => {
87+
mutations.forEach((mutation) => {
88+
if (mutation.type === 'childList' && mutation.addedNodes.length > 0 && ((mutation.target as HTMLElement)?.classList?.contains('c-nav__item') || (mutation.target as HTMLElement)?.classList?.contains('c-nav__extended-content'))) {
89+
[...mutation.addedNodes].forEach((node) => {
90+
if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).classList?.contains('c-nav__child-container') && !(node as HTMLElement).querySelector('.c-nav.preloader')) {
91+
const element = (node as HTMLElement).classList.contains('c-nav') ? node : (node as HTMLElement).querySelector('.c-nav');
92+
93+
if (element) {
94+
new Nav(element as HTMLElement);
95+
}
96+
}
97+
});
98+
}
99+
});
100+
});
101+
observer.observe(menu, { childList: true, subtree: true });
102+
});
103+
});

source/components/nav/nav.ts

Lines changed: 0 additions & 121 deletions
This file was deleted.

source/js/select/SelectComponentObserver.ts renamed to source/components/select/index.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { Select } from "./Select";
1+
import { Select } from './script/select';
22

33
export class SelectComponentObserver {
4-
54
private readonly selectComponentElementAttribute = 'data-js-select-component'; //Add to main div of component
65

76
constructor() {
@@ -14,15 +13,15 @@ export class SelectComponentObserver {
1413
const container = document.documentElement || document.body;
1514
const observerOptions = {
1615
childList: true,
17-
subtree: true
16+
subtree: true,
1817
};
1918

2019
const observer = new MutationObserver((mutations) => {
2120
mutations.forEach((mutation) => {
22-
if (mutation.type === "childList") {
21+
if (mutation.type === 'childList') {
2322
mutation.addedNodes.forEach((node) => {
2423
if (node instanceof HTMLElement) {
25-
let selects = [...node.querySelectorAll(`[${this.selectComponentElementAttribute}]`)];
24+
const selects = [...node.querySelectorAll(`[${this.selectComponentElementAttribute}]`)];
2625

2726
if (node.hasAttribute(this.selectComponentElementAttribute)) {
2827
selects.push(node);
@@ -43,4 +42,10 @@ export class SelectComponentObserver {
4342
new Select(select);
4443
});
4544
}
46-
}
45+
}
46+
47+
// Initialize the SelectComponentObserver when the DOM is fully loaded
48+
document.addEventListener('DOMContentLoaded', () => {
49+
const selectComponentObserverInstance = new SelectComponentObserver();
50+
selectComponentObserverInstance.observe();
51+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
export class IsCheckedToggler {
2+
constructor() {
3+
this.init();
4+
this.observe();
5+
}
6+
7+
private init() {
8+
const initElements = document.querySelectorAll('select[multiple] option');
9+
if (initElements.length) {
10+
initElements.forEach((element) => {
11+
this.applyOnClickEvent(element as HTMLOptionElement);
12+
});
13+
}
14+
}
15+
16+
private applyOnClickEvent(element: HTMLOptionElement): void {
17+
element.addEventListener('mouseup', () => {
18+
this.toggleIsChecked(element);
19+
});
20+
}
21+
22+
private toggleIsChecked(element: HTMLOptionElement) {
23+
const newState = element.defaultSelected === false ? true : false;
24+
25+
if (newState === true) {
26+
element.setAttribute('selected', 'true');
27+
} else {
28+
element.removeAttribute('selected');
29+
}
30+
31+
element.selected = newState;
32+
}
33+
34+
private observe(): void {
35+
const container = document.documentElement || document.body;
36+
const observerOptions = {
37+
childList: true,
38+
subtree: true,
39+
};
40+
41+
const observer = new MutationObserver((mutations) => {
42+
mutations.forEach((mutation) => {
43+
if (mutation.type === 'childList') {
44+
mutation.addedNodes.forEach((node) => {
45+
if (node instanceof HTMLOptionElement) {
46+
this.applyOnClickEvent(node);
47+
}
48+
});
49+
}
50+
});
51+
});
52+
53+
observer.observe(container, observerOptions);
54+
}
55+
}

0 commit comments

Comments
 (0)