diff --git a/common-theme/assets/scripts/solo-view.js b/common-theme/assets/scripts/solo-view.js
index 4adfe46e9..cef2f85f7 100644
--- a/common-theme/assets/scripts/solo-view.js
+++ b/common-theme/assets/scripts/solo-view.js
@@ -1,8 +1,10 @@
const elementName = "solo-view";
+
class SoloView extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
+
// State object
this.state = {
currentBlockIndex: 0,
@@ -22,6 +24,7 @@ class SoloView extends HTMLElement {
);
document.addEventListener("keydown", this.handleKeydown.bind(this));
}
+
connectedCallback() {
this.render(); // Render the component
this.cacheDOM(); // Cache necessary DOM elements
@@ -29,11 +32,13 @@ class SoloView extends HTMLElement {
this.handleFragment(); // Check for a fragment in the URL and set to this view if present
this.updateView(); // Initial view update
}
+
disconnectedCallback() {
// Removing window and doc event listeners
window.removeEventListener("hashchange", this.handleFragment.bind(this));
document.removeEventListener("keydown", this.handleKeydown.bind(this));
}
+
// Cache DOM elements
cacheDOM() {
this.state.blocks = [
@@ -49,13 +54,16 @@ class SoloView extends HTMLElement {
'[slot="nav"] .c-solo-view__next'
);
}
+
// Add event listeners
addEventListeners() {
this.state.tocLinks.forEach((link, index) => {
link.addEventListener("click", () => this.updateCurrentBlockIndex(index));
});
+
this.state.navButtons.back.addEventListener("click", this.navigateBack);
this.state.navButtons.next.addEventListener("click", this.navigateNext);
+
this.addEventListener(
"touchstart",
(event) => {
@@ -66,6 +74,7 @@ class SoloView extends HTMLElement {
},
{ passive: true }
);
+
this.addEventListener(
"touchend",
(event) => {
@@ -78,20 +87,25 @@ class SoloView extends HTMLElement {
},
{ passive: true }
);
+
this.addEventListener("keydown", this.handleKeydown, { passive: true });
}
+
// Update current block index
updateCurrentBlockIndex(index) {
this.state.currentBlockIndex = index;
this.updateView();
}
+
// Navigation logic
navigateBack = (event) => {
this.navigate(event, this.state.currentBlockIndex - 1);
};
+
navigateNext = (event) => {
this.navigate(event, this.state.currentBlockIndex + 1);
};
+
navigate = (event, index) => {
if (index < 0 || index >= this.state.blocks.length) {
return;
@@ -101,6 +115,7 @@ class SoloView extends HTMLElement {
event.stopPropagation();
this.state.tocLinks[index].click();
};
+
// Handle swipe gesture
handleSwipeGesture = (startX, endX) => {
const deltaX = endX - startX;
@@ -113,6 +128,7 @@ class SoloView extends HTMLElement {
this.navigateNext(new Event("swipe"));
}
};
+
eventTargetIsHorizontallyScrollable = (event) => {
let el = event.target;
while (el && el.localName !== elementName) {
@@ -123,20 +139,8 @@ class SoloView extends HTMLElement {
}
return false;
}
+
handleKeydown = (event) => {
- // Don't navigate if user is typing in an editable element
- const target = event.target;
- const tagName = target.tagName;
-
- if (
- tagName === 'TEXTAREA' ||
- tagName === 'INPUT' ||
- tagName === 'SELECT' ||
- target.isContentEditable
- ) {
- return;
- }
-
if (event.key === "ArrowLeft") {
this.navigateBack(event);
}
@@ -144,6 +148,7 @@ class SoloView extends HTMLElement {
this.navigateNext(event);
}
};
+
// look for a fragment in the URL and navigate to it if one exists so we can link directly to a view
handleFragment = () => {
const fragment = window.location.hash.substring(1);
@@ -157,17 +162,20 @@ class SoloView extends HTMLElement {
}
}
};
+
// Update view
updateView() {
this.state.blocks.forEach((block, index) => {
block.hidden = index !== this.state.currentBlockIndex;
});
+
this.state.tocLinks.forEach((link, index) => {
link.classList.toggle(
"is-active",
index === this.state.currentBlockIndex
);
});
+
// Hide unusable buttons
this.state.navButtons.back.style.display =
this.state.currentBlockIndex === 0 ? "none" : "inline-flex";
@@ -176,11 +184,13 @@ class SoloView extends HTMLElement {
? "none"
: "inline-flex";
}
+
// Render method with slots and CSS
render() {
this.shadowRoot.innerHTML = `
@@ -208,4 +220,5 @@ class SoloView extends HTMLElement {
`;
}
}
+
customElements.define(elementName, SoloView);