You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by hn...@apache.org on 2025/05/26 08:40:29 UTC
(myfaces-tobago) branch main updated (c561864c75 -> d88d709a53)
This is an automated email from the ASF dual-hosted git repository.
hnoeth pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
from c561864c75 build(theme): rebuild
new d074077a0d feature(demo): sidebar navigation
new d88d709a53 build(theme): rebuild
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../js/demo-alert.js => scss/demo-sidebar.scss} | 49 ++++--
.../tobago-example-demo/src/main/scss/demo.scss | 2 +
.../tobago-example-demo/src/main/ts/demo-all.ts | 1 +
.../src/main/ts/demo-sidebar.ts | 176 +++++++++++++++++++++
.../src/main/webapp/css/demo.css | 47 ++++++
.../src/main/webapp/css/demo.css.map | 2 +-
.../src/main/webapp/css/demo.min.css | 2 +-
.../src/main/webapp/css/demo.min.css.map | 2 +-
.../src/main/webapp/js/demo-all.js | 1 +
.../src/main/webapp/js/demo-all.js.map | 2 +-
.../src/main/webapp/js/demo-sidebar.js | 145 +++++++++++++++++
.../src/main/webapp/js/demo-sidebar.js.map | 1 +
.../tobago-example-demo/src/main/webapp/js/demo.js | 145 +++++++++++++++++
.../src/main/webapp/js/demo.js.map | 2 +-
.../tobago-example-demo/src/main/webapp/main.xhtml | 6 +-
15 files changed, 562 insertions(+), 21 deletions(-)
copy tobago-example/tobago-example-demo/src/main/{webapp/js/demo-alert.js => scss/demo-sidebar.scss} (58%)
create mode 100644 tobago-example/tobago-example-demo/src/main/ts/demo-sidebar.ts
create mode 100644 tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js
create mode 100644 tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js.map
(myfaces-tobago) 01/02: feature(demo): sidebar navigation
Posted by hn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
hnoeth pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
commit d074077a0d8fca9f9e8e62e76eacd0ae7189f5f0
Author: Mehriyar Assanimoghaddam <me...@irian.eu>
AuthorDate: Mon Mar 10 12:05:30 2025 +0100
feature(demo): sidebar navigation
Add a sidebar navigation (table of contents). It's visible if the browser window is wide enough.
Prototype implemented by Mehriyar Assanimoghaddam; final implementation by Henning Noeth
---
.../{ts/demo-all.ts => scss/demo-sidebar.scss} | 45 +++++-
.../tobago-example-demo/src/main/scss/demo.scss | 2 +
.../tobago-example-demo/src/main/ts/demo-all.ts | 1 +
.../src/main/ts/demo-sidebar.ts | 176 +++++++++++++++++++++
.../tobago-example-demo/src/main/webapp/main.xhtml | 6 +-
5 files changed, 222 insertions(+), 8 deletions(-)
diff --git a/tobago-example/tobago-example-demo/src/main/ts/demo-all.ts b/tobago-example/tobago-example-demo/src/main/scss/demo-sidebar.scss
similarity index 56%
copy from tobago-example/tobago-example-demo/src/main/ts/demo-all.ts
copy to tobago-example/tobago-example-demo/src/main/scss/demo-sidebar.scss
index 928c85e947..96b890a091 100644
--- a/tobago-example/tobago-example-demo/src/main/ts/demo-all.ts
+++ b/tobago-example/tobago-example-demo/src/main/scss/demo-sidebar.scss
@@ -15,10 +15,41 @@
* limitations under the License.
*/
-import "./demo-alert";
-import "./demo-copy-to-clipboard";
-import "./demo-date";
-import "./demo-highlight";
-import "./demo-inspect";
-import "./demo-login";
-import "./demo-test";
+demo-sidebar {
+ display: block;
+ position: fixed;
+ overflow-y: auto;
+ padding: 1rem;
+ margin-right: 0.5rem;
+
+ nav {
+ > ul {
+ padding-left: 0;
+ }
+
+ ul ul {
+ padding-left: 1rem;
+ }
+
+ a {
+ color: var(--bs-secondary);
+ text-decoration: none;
+ padding-left: 0.5rem;
+
+ &:hover {
+ color: var(--bs-primary);
+ border-left: 2px solid var(--bs-primary);
+ }
+
+ &.active {
+ color: var(--bs-primary);
+ border-left: 2px solid var(--bs-primary);
+ font-weight: 600;
+ }
+ }
+
+ ul, li {
+ list-style: none;
+ }
+ }
+}
diff --git a/tobago-example/tobago-example-demo/src/main/scss/demo.scss b/tobago-example/tobago-example-demo/src/main/scss/demo.scss
index 549f8c4de9..836a8cace4 100644
--- a/tobago-example/tobago-example-demo/src/main/scss/demo.scss
+++ b/tobago-example/tobago-example-demo/src/main/scss/demo.scss
@@ -15,6 +15,8 @@
* limitations under the License.
*/
+@import "demo-sidebar";
+
.hide-navigation {
display: none;
}
diff --git a/tobago-example/tobago-example-demo/src/main/ts/demo-all.ts b/tobago-example/tobago-example-demo/src/main/ts/demo-all.ts
index 928c85e947..049755b3a3 100644
--- a/tobago-example/tobago-example-demo/src/main/ts/demo-all.ts
+++ b/tobago-example/tobago-example-demo/src/main/ts/demo-all.ts
@@ -21,4 +21,5 @@ import "./demo-date";
import "./demo-highlight";
import "./demo-inspect";
import "./demo-login";
+import "./demo-sidebar";
import "./demo-test";
diff --git a/tobago-example/tobago-example-demo/src/main/ts/demo-sidebar.ts b/tobago-example/tobago-example-demo/src/main/ts/demo-sidebar.ts
new file mode 100644
index 0000000000..83bdb3bff9
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/ts/demo-sidebar.ts
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface SectionNode {
+ id: string;
+ title: string;
+ level: number;
+ children: SectionNode[];
+}
+
+export class Sidebar extends HTMLElement {
+ private sectionTree: SectionNode;
+ private scrollThrottleTimeout?: number;
+ private scrollEventListener;
+ private scrollTimeout: number;
+
+ connectedCallback(): void {
+ if (this.fixedHeader) {
+ const resizeObserver = new ResizeObserver(() => {
+ const headerHeight = this.fixedHeader.offsetHeight;
+ const headerMarginBottom = parseFloat(getComputedStyle(this.fixedHeader).marginBottom);
+ this.rootHtml.style.scrollPaddingTop = headerHeight + headerMarginBottom + "px";
+ this.style.top = headerHeight + "px";
+ });
+ resizeObserver.observe(this.fixedHeader);
+ }
+ if (this.fixedFooter) {
+ const resizeObserver = new ResizeObserver(() => this.style.bottom = this.fixedFooter.offsetHeight + "px");
+ resizeObserver.observe(this.fixedFooter);
+ }
+
+ this.insertAdjacentHTML("afterbegin", "<strong>On this page</strong><nav id='tableOfContents'></nav>");
+
+ this.sectionTree = {
+ id: this.rootSection.id,
+ title: this.getSectionTitle(this.rootSection),
+ level: 0,
+ children: []
+ };
+ this.buildSectionTree(this.rootSection, this.sectionTree);
+ this.renderTableOfContent(this.sectionTree, this.tableOfContentsNav);
+ this.updateActiveNavLink();
+
+ this.scrollEventListener = this.scrollEvent.bind(this);
+ window.addEventListener("scroll", this.scrollEventListener);
+ }
+
+ disconnectedCallback(): void {
+ window.removeEventListener("scroll", this.scrollEventListener);
+ window.clearTimeout(this.scrollTimeout);
+ }
+
+ private buildSectionTree(element: HTMLElement, parent: SectionNode): void {
+ for (const child of element.children) {
+ if (child.tagName === "TOBAGO-SECTION") {
+ const sectionNode: SectionNode = {
+ id: child.id,
+ title: this.getSectionTitle(<HTMLElement>child),
+ level: parent ? parent.level + 1 : 0,
+ children: []
+ };
+ parent.children.push(sectionNode);
+ this.buildSectionTree(<HTMLElement>child, sectionNode);
+ } else {
+ this.buildSectionTree(<HTMLElement>child, parent);
+ }
+ }
+ }
+
+ private getSectionTitle(section: HTMLElement): string {
+ const titleSpan = section.querySelector(".tobago-header span");
+ return titleSpan ? titleSpan.textContent.trim() : section.id;
+ }
+
+ private renderTableOfContent(node: SectionNode, parent: HTMLElement): void {
+ const nodeId = this.sanitize(node.id);
+ const nodeTitle = this.sanitize(node.title);
+ parent.insertAdjacentHTML("afterbegin", `<a href="#${nodeId}">${nodeTitle}</a>`);
+
+ const children = node.children;
+ if (children.length > 0) {
+ const ul = document.createElement("ul");
+ parent.insertAdjacentElement("beforeend", ul);
+
+ for (const child of children) {
+ const li = document.createElement("li");
+ ul.insertAdjacentElement("beforeend", li);
+ this.renderTableOfContent(child, li);
+ }
+ }
+ }
+
+ private sanitize(value: string): string {
+ const div = document.createElement("div");
+ div.innerHTML = value;
+ return div.innerText;
+ }
+
+ private scrollEvent(event: Event): void {
+ window.clearTimeout(this.scrollTimeout);
+ this.scrollTimeout = window.setTimeout(() => this.updateActiveNavLink(), 10);
+ }
+
+ private updateActiveNavLink(): void {
+ const scrollPaddingTop = parseFloat(this.rootHtml.style.scrollPaddingTop) + 1;
+ let activeSectionId = this.rootSection.id;
+ let activeSectionTop = this.rootSection.getBoundingClientRect().top;
+
+ this.rootSection.querySelectorAll("tobago-section").forEach((section: HTMLElement) => {
+ const sectionTop = section.getBoundingClientRect().top;
+ if (sectionTop > activeSectionTop && sectionTop <= scrollPaddingTop) {
+ activeSectionId = section.id;
+ activeSectionTop = sectionTop;
+ }
+ });
+
+ this.navLinks.forEach((navLink: HTMLAnchorElement) => {
+ if (navLink.href.endsWith("#" + activeSectionId)) {
+ navLink.classList.add("active");
+ } else {
+ navLink.classList.remove("active");
+ }
+ });
+ }
+
+ get rootHtml(): HTMLElement {
+ const rootNode = this.getRootNode() as ShadowRoot | Document;
+ return rootNode.querySelector<HTMLElement>("html");
+ }
+
+ get fixedHeader(): HTMLElement {
+ const rootNode = this.getRootNode() as ShadowRoot | Document;
+ return rootNode.querySelector<HTMLElement>("tobago-header.sticky-top");
+ }
+
+ get rootSection(): HTMLElement {
+ const rootNode = this.getRootNode() as ShadowRoot | Document;
+ return rootNode.getElementById("page:content");
+ }
+
+ get tableOfContentsNav(): HTMLElement {
+ const rootNode = this.getRootNode() as ShadowRoot | Document;
+ return rootNode.getElementById("tableOfContents");
+ }
+
+ get navLinks(): NodeListOf<HTMLAnchorElement> {
+ return this.tableOfContentsNav.querySelectorAll("a");
+ }
+
+ get fixedFooter(): HTMLElement | null {
+ const rootNode = this.getRootNode() as ShadowRoot | Document;
+ return rootNode.querySelector<HTMLElement>("tobago-footer.fixed-bottom");
+ }
+}
+
+if (typeof window !== "undefined") {
+ window.addEventListener("DOMContentLoaded", function (): void {
+ if (!window.customElements.get("demo-sidebar")) {
+ window.customElements.define("demo-sidebar", Sidebar);
+ }
+ });
+}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/main.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/main.xhtml
index 77827f6e73..c9a249f1a6 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/main.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/main.xhtml
@@ -77,7 +77,7 @@
<tc:panel>
<tc:style customClass="#{navigationState.viewSource ? '' : 'container-lg'}"/>
- <tc:segmentLayout large="2seg 10seg">
+ <tc:segmentLayout large="2seg 8seg 2seg">
<f:event type="preRenderView" listener="#{navigationState.sync}"/>
<tc:panel>
<tc:style customClass="d-lg-block hide-navigation"/>
@@ -107,6 +107,10 @@
</demo-highlight>
</tc:panel>
</tc:splitLayout>
+ <tc:panel>
+ <tc:style customClass="d-lg-block" display="none"/>
+ <demo-sidebar id="sidebar" tabindex="-1"/>
+ </tc:panel>
</tc:segmentLayout>
</tc:panel>
(myfaces-tobago) 02/02: build(theme): rebuild
Posted by hn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
hnoeth pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
commit d88d709a53a3e3eec8377194afd693b563b7e77f
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Mon May 26 10:31:24 2025 +0200
build(theme): rebuild
---
.../src/main/webapp/css/demo.css | 47 +++++++
.../src/main/webapp/css/demo.css.map | 2 +-
.../src/main/webapp/css/demo.min.css | 2 +-
.../src/main/webapp/css/demo.min.css.map | 2 +-
.../src/main/webapp/js/demo-all.js | 1 +
.../src/main/webapp/js/demo-all.js.map | 2 +-
.../src/main/webapp/js/demo-sidebar.js | 145 +++++++++++++++++++++
.../src/main/webapp/js/demo-sidebar.js.map | 1 +
.../tobago-example-demo/src/main/webapp/js/demo.js | 145 +++++++++++++++++++++
.../src/main/webapp/js/demo.js.map | 2 +-
10 files changed, 344 insertions(+), 5 deletions(-)
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css
index a8209ee3c0..463d003062 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css
+++ b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css
@@ -14,6 +14,53 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+demo-sidebar {
+ display: block;
+ position: fixed;
+ overflow-y: auto;
+ padding: 1rem;
+ margin-right: 0.5rem;
+}
+demo-sidebar nav > ul {
+ padding-left: 0;
+}
+demo-sidebar nav ul ul {
+ padding-left: 1rem;
+}
+demo-sidebar nav a {
+ color: var(--bs-secondary);
+ text-decoration: none;
+ padding-left: 0.5rem;
+}
+demo-sidebar nav a:hover {
+ color: var(--bs-primary);
+ border-left: 2px solid var(--bs-primary);
+}
+demo-sidebar nav a.active {
+ color: var(--bs-primary);
+ border-left: 2px solid var(--bs-primary);
+ font-weight: 600;
+}
+demo-sidebar nav ul, demo-sidebar nav li {
+ list-style: none;
+}
+
.hide-navigation {
display: none;
}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css.map b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css.map
index 696bc28243..8e73b8dbe4 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css.map
+++ b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/demo.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;EACE;EACA;EACA;AACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAIA;EACE;;AAEA;EACE;;;AAKN;EACE;EACA;EACA;EACA;;;AAIA;EA [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/demo.scss","../../scss/demo-sidebar.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA;EACE;EACA;EACA;EACA;EACA;;AAGE;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAIJ;EACE;;;ADhCN;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EA [...]
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css
index 74e990fcd7..0206f31034 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css
+++ b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css
@@ -1,2 +1,2 @@
-.hide-navigation{display:none}.navigation-box{--bs-card-border-radius:0;border:none}.box-shadow{box-shadow:0 0 5px 5px rgba(200,200,200,.5)}.demo-selected{background-color:#fdf}#demo-view-source .demo-selected{border:1px solid #ccc}.blue{background-color:#2aabff}.demo-data-attribute{height:100px;border:1px solid #000;border-radius:.25rem}demo-highlight{font-size:75%}.language-markup .token.tag{font-weight:inherit;font-size:inherit;line-height:inherit;white-space:inherit;text-align:inheri [...]
+demo-sidebar{display:block;position:fixed;overflow-y:auto;padding:1rem;margin-right:.5rem}demo-sidebar nav>ul{padding-left:0}demo-sidebar nav ul ul{padding-left:1rem}demo-sidebar nav a{color:var(--bs-secondary);text-decoration:none;padding-left:.5rem}demo-sidebar nav a:hover{color:var(--bs-primary);border-left:2px solid var(--bs-primary)}demo-sidebar nav a.active{color:var(--bs-primary);border-left:2px solid var(--bs-primary);font-weight:600}demo-sidebar nav li,demo-sidebar nav ul{list-s [...]
/*# sourceMappingURL=demo.min.css.map */
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css.map b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css.map
index 2e3f36fc48..5023f04270 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css.map
+++ b/tobago-example/tobago-example-demo/src/main/webapp/css/demo.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["src/main/webapp/css/demo.css"],"names":[],"mappings":"AAgBA,iBACE,QAAS,KAGX,gBACE,wBAAyB,EACzB,OAAQ,KAGV,YACE,WAAY,EAAE,EAAE,IAAI,IAAI,qBAG1B,eACE,iBAAkB,KAGpB,iCACE,OAAQ,IAAI,MAAM,KAGpB,MACE,iBAAkB,QAGpB,qBACE,OAAQ,MACR,OAAQ,IAAI,MAAM,KAClB,cAAe,OAGjB,eACE,UAAW,IASb,4BACE,YAAa,QACb,UAAW,QACX,YAAa,QAEb,YAAa,QACb,WAAY,QACZ,QAAS,QAGX,QACE,cAAe,QAGjB,YACE,cAAe,QAGjB,8BACE,iBAAkB,QAGpB,iCACE,iBAAkB,QAGpB,+BACE,iBAAkB,QAGpB,mBACE,iBAAkB,KAGpB,iBACE,iBAAkB,KAGpB,6BACE, [...]
\ No newline at end of file
+{"version":3,"sources":["src/main/webapp/css/demo.css"],"names":[],"mappings":"AAgCA,aACE,QAAS,MACT,SAAU,MACV,WAAY,KACZ,QAAS,KACT,aAAc,MAEhB,oBACE,aAAc,EAEhB,uBACE,aAAc,KAEhB,mBACE,MAAO,oBACP,gBAAiB,KACjB,aAAc,MAEhB,yBACE,MAAO,kBACP,YAAa,IAAI,MAAM,kBAEzB,0BACE,MAAO,kBACP,YAAa,IAAI,MAAM,kBACvB,YAAa,IAEM,oBAArB,oBACE,WAAY,KAGd,iBACE,QAAS,KAGX,gBACE,wBAAyB,EACzB,OAAQ,KAGV,YACE,WAAY,EAAE,EAAE,IAAI,IAAI,qBAG1B,eACE,iBAAkB,KAGpB,iCACE,OAAQ,IAAI,MAAM,KAGpB,MACE,iBAAkB,QAGpB,qBACE,OAAQ,MACR,OAAQ [...]
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js
index f92f46828f..6a1f966467 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js
@@ -20,5 +20,6 @@ import "./demo-date";
import "./demo-highlight";
import "./demo-inspect";
import "./demo-login";
+import "./demo-sidebar";
import "./demo-test";
//# sourceMappingURL=demo-all.js.map
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js.map b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js.map
index eca2448c4a..3b1922008e 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js.map
+++ b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-all.js.map
@@ -1 +1 @@
-{"version":3,"file":"demo-all.js","sourceRoot":"","sources":["../../ts/demo-all.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,cAAc,CAAC;AACtB,OAAO,0BAA0B,CAAC;AAClC,OAAO,aAAa,CAAC;AACrB,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AACxB,OAAO,cAAc,CAAC;AACtB,OAAO,aAAa,CAAC"}
\ No newline at end of file
+{"version":3,"file":"demo-all.js","sourceRoot":"","sources":["../../ts/demo-all.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,cAAc,CAAC;AACtB,OAAO,0BAA0B,CAAC;AAClC,OAAO,aAAa,CAAC;AACrB,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AACxB,OAAO,cAAc,CAAC;AACtB,OAAO,gBAAgB,CAAC;AACxB,OAAO,aAAa,CAAC"}
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js
new file mode 100644
index 0000000000..6639864172
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export class Sidebar extends HTMLElement {
+ connectedCallback() {
+ if (this.fixedHeader) {
+ const resizeObserver = new ResizeObserver(() => {
+ const headerHeight = this.fixedHeader.offsetHeight;
+ const headerMarginBottom = parseFloat(getComputedStyle(this.fixedHeader).marginBottom);
+ this.rootHtml.style.scrollPaddingTop = headerHeight + headerMarginBottom + "px";
+ this.style.top = headerHeight + "px";
+ });
+ resizeObserver.observe(this.fixedHeader);
+ }
+ if (this.fixedFooter) {
+ const resizeObserver = new ResizeObserver(() => this.style.bottom = this.fixedFooter.offsetHeight + "px");
+ resizeObserver.observe(this.fixedFooter);
+ }
+ this.insertAdjacentHTML("afterbegin", "<strong>On this page</strong><nav id='tableOfContents'></nav>");
+ this.sectionTree = {
+ id: this.rootSection.id,
+ title: this.getSectionTitle(this.rootSection),
+ level: 0,
+ children: []
+ };
+ this.buildSectionTree(this.rootSection, this.sectionTree);
+ this.renderTableOfContent(this.sectionTree, this.tableOfContentsNav);
+ this.updateActiveNavLink();
+ this.scrollEventListener = this.scrollEvent.bind(this);
+ window.addEventListener("scroll", this.scrollEventListener);
+ }
+ disconnectedCallback() {
+ window.removeEventListener("scroll", this.scrollEventListener);
+ window.clearTimeout(this.scrollTimeout);
+ }
+ buildSectionTree(element, parent) {
+ for (const child of element.children) {
+ if (child.tagName === "TOBAGO-SECTION") {
+ const sectionNode = {
+ id: child.id,
+ title: this.getSectionTitle(child),
+ level: parent ? parent.level + 1 : 0,
+ children: []
+ };
+ parent.children.push(sectionNode);
+ this.buildSectionTree(child, sectionNode);
+ }
+ else {
+ this.buildSectionTree(child, parent);
+ }
+ }
+ }
+ getSectionTitle(section) {
+ const titleSpan = section.querySelector(".tobago-header span");
+ return titleSpan ? titleSpan.textContent.trim() : section.id;
+ }
+ renderTableOfContent(node, parent) {
+ const nodeId = this.sanitize(node.id);
+ const nodeTitle = this.sanitize(node.title);
+ parent.insertAdjacentHTML("afterbegin", `<a href="#${nodeId}">${nodeTitle}</a>`);
+ const children = node.children;
+ if (children.length > 0) {
+ const ul = document.createElement("ul");
+ parent.insertAdjacentElement("beforeend", ul);
+ for (const child of children) {
+ const li = document.createElement("li");
+ ul.insertAdjacentElement("beforeend", li);
+ this.renderTableOfContent(child, li);
+ }
+ }
+ }
+ sanitize(value) {
+ const div = document.createElement("div");
+ div.innerHTML = value;
+ return div.innerText;
+ }
+ scrollEvent(event) {
+ window.clearTimeout(this.scrollTimeout);
+ this.scrollTimeout = window.setTimeout(() => this.updateActiveNavLink(), 10);
+ }
+ updateActiveNavLink() {
+ const scrollPaddingTop = parseFloat(this.rootHtml.style.scrollPaddingTop) + 1;
+ let activeSectionId = this.rootSection.id;
+ let activeSectionTop = this.rootSection.getBoundingClientRect().top;
+ this.rootSection.querySelectorAll("tobago-section").forEach((section) => {
+ const sectionTop = section.getBoundingClientRect().top;
+ if (sectionTop > activeSectionTop && sectionTop <= scrollPaddingTop) {
+ activeSectionId = section.id;
+ activeSectionTop = sectionTop;
+ }
+ });
+ this.navLinks.forEach((navLink) => {
+ if (navLink.href.endsWith("#" + activeSectionId)) {
+ navLink.classList.add("active");
+ }
+ else {
+ navLink.classList.remove("active");
+ }
+ });
+ }
+ get rootHtml() {
+ const rootNode = this.getRootNode();
+ return rootNode.querySelector("html");
+ }
+ get fixedHeader() {
+ const rootNode = this.getRootNode();
+ return rootNode.querySelector("tobago-header.sticky-top");
+ }
+ get rootSection() {
+ const rootNode = this.getRootNode();
+ return rootNode.getElementById("page:content");
+ }
+ get tableOfContentsNav() {
+ const rootNode = this.getRootNode();
+ return rootNode.getElementById("tableOfContents");
+ }
+ get navLinks() {
+ return this.tableOfContentsNav.querySelectorAll("a");
+ }
+ get fixedFooter() {
+ const rootNode = this.getRootNode();
+ return rootNode.querySelector("tobago-footer.fixed-bottom");
+ }
+}
+if (typeof window !== "undefined") {
+ window.addEventListener("DOMContentLoaded", function () {
+ if (!window.customElements.get("demo-sidebar")) {
+ window.customElements.define("demo-sidebar", Sidebar);
+ }
+ });
+}
+//# sourceMappingURL=demo-sidebar.js.map
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js.map b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js.map
new file mode 100644
index 0000000000..736c0d7603
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/js/demo-sidebar.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"demo-sidebar.js","sourceRoot":"","sources":["../../ts/demo-sidebar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAMtC,iBAAiB;QACf,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,GAAG,EAAE;gBAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC;gBACnD,MAAM,kBAAkB,GAAG,UAAU,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC;gBACvF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,GAAG,YAAY,GAAG,kBAAkB,GAAG,IAAI,CAAC;gBAChF,IA [...]
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js b/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js
index d6375cc98b..37fb373732 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js
@@ -332,6 +332,151 @@
}
});
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ class Sidebar extends HTMLElement {
+ connectedCallback() {
+ if (this.fixedHeader) {
+ const resizeObserver = new ResizeObserver(() => {
+ const headerHeight = this.fixedHeader.offsetHeight;
+ const headerMarginBottom = parseFloat(getComputedStyle(this.fixedHeader).marginBottom);
+ this.rootHtml.style.scrollPaddingTop = headerHeight + headerMarginBottom + "px";
+ this.style.top = headerHeight + "px";
+ });
+ resizeObserver.observe(this.fixedHeader);
+ }
+ if (this.fixedFooter) {
+ const resizeObserver = new ResizeObserver(() => this.style.bottom = this.fixedFooter.offsetHeight + "px");
+ resizeObserver.observe(this.fixedFooter);
+ }
+ this.insertAdjacentHTML("afterbegin", "<strong>On this page</strong><nav id='tableOfContents'></nav>");
+ this.sectionTree = {
+ id: this.rootSection.id,
+ title: this.getSectionTitle(this.rootSection),
+ level: 0,
+ children: []
+ };
+ this.buildSectionTree(this.rootSection, this.sectionTree);
+ this.renderTableOfContent(this.sectionTree, this.tableOfContentsNav);
+ this.updateActiveNavLink();
+ this.scrollEventListener = this.scrollEvent.bind(this);
+ window.addEventListener("scroll", this.scrollEventListener);
+ }
+ disconnectedCallback() {
+ window.removeEventListener("scroll", this.scrollEventListener);
+ window.clearTimeout(this.scrollTimeout);
+ }
+ buildSectionTree(element, parent) {
+ for (const child of element.children) {
+ if (child.tagName === "TOBAGO-SECTION") {
+ const sectionNode = {
+ id: child.id,
+ title: this.getSectionTitle(child),
+ level: parent ? parent.level + 1 : 0,
+ children: []
+ };
+ parent.children.push(sectionNode);
+ this.buildSectionTree(child, sectionNode);
+ }
+ else {
+ this.buildSectionTree(child, parent);
+ }
+ }
+ }
+ getSectionTitle(section) {
+ const titleSpan = section.querySelector(".tobago-header span");
+ return titleSpan ? titleSpan.textContent.trim() : section.id;
+ }
+ renderTableOfContent(node, parent) {
+ const nodeId = this.sanitize(node.id);
+ const nodeTitle = this.sanitize(node.title);
+ parent.insertAdjacentHTML("afterbegin", `<a href="#${nodeId}">${nodeTitle}</a>`);
+ const children = node.children;
+ if (children.length > 0) {
+ const ul = document.createElement("ul");
+ parent.insertAdjacentElement("beforeend", ul);
+ for (const child of children) {
+ const li = document.createElement("li");
+ ul.insertAdjacentElement("beforeend", li);
+ this.renderTableOfContent(child, li);
+ }
+ }
+ }
+ sanitize(value) {
+ const div = document.createElement("div");
+ div.innerHTML = value;
+ return div.innerText;
+ }
+ scrollEvent(event) {
+ window.clearTimeout(this.scrollTimeout);
+ this.scrollTimeout = window.setTimeout(() => this.updateActiveNavLink(), 10);
+ }
+ updateActiveNavLink() {
+ const scrollPaddingTop = parseFloat(this.rootHtml.style.scrollPaddingTop) + 1;
+ let activeSectionId = this.rootSection.id;
+ let activeSectionTop = this.rootSection.getBoundingClientRect().top;
+ this.rootSection.querySelectorAll("tobago-section").forEach((section) => {
+ const sectionTop = section.getBoundingClientRect().top;
+ if (sectionTop > activeSectionTop && sectionTop <= scrollPaddingTop) {
+ activeSectionId = section.id;
+ activeSectionTop = sectionTop;
+ }
+ });
+ this.navLinks.forEach((navLink) => {
+ if (navLink.href.endsWith("#" + activeSectionId)) {
+ navLink.classList.add("active");
+ }
+ else {
+ navLink.classList.remove("active");
+ }
+ });
+ }
+ get rootHtml() {
+ const rootNode = this.getRootNode();
+ return rootNode.querySelector("html");
+ }
+ get fixedHeader() {
+ const rootNode = this.getRootNode();
+ return rootNode.querySelector("tobago-header.sticky-top");
+ }
+ get rootSection() {
+ const rootNode = this.getRootNode();
+ return rootNode.getElementById("page:content");
+ }
+ get tableOfContentsNav() {
+ const rootNode = this.getRootNode();
+ return rootNode.getElementById("tableOfContents");
+ }
+ get navLinks() {
+ return this.tableOfContentsNav.querySelectorAll("a");
+ }
+ get fixedFooter() {
+ const rootNode = this.getRootNode();
+ return rootNode.querySelector("tobago-footer.fixed-bottom");
+ }
+ }
+ if (typeof window !== "undefined") {
+ window.addEventListener("DOMContentLoaded", function () {
+ if (!window.customElements.get("demo-sidebar")) {
+ window.customElements.define("demo-sidebar", Sidebar);
+ }
+ });
+ }
+
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js.map b/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js.map
index 0fe8a52730..abb447a409 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js.map
+++ b/tobago-example/tobago-example-demo/src/main/webapp/js/demo.js.map
@@ -1 +1 @@
-{"version":3,"file":"demo.js","sources":["demo-alert.js","demo-copy-to-clipboard.js","demo-date.js","demo-highlight.js","demo-inspect.js","demo-login.js","demo-test.js"],"sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements. See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (th [...]
\ No newline at end of file
+{"version":3,"file":"demo.js","sources":["demo-alert.js","demo-copy-to-clipboard.js","demo-date.js","demo-highlight.js","demo-inspect.js","demo-login.js","demo-sidebar.js","demo-test.js"],"sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements. See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, V [...]
\ No newline at end of file