Skip to content

Commit e7d0ccc

Browse files
committed
sidebar fixes, improve ability objediting guide
1 parent 29bdc34 commit e7d0ccc

7 files changed

Lines changed: 152 additions & 35 deletions

File tree

_doc/stdlib/objediting/abils.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,21 @@ sections:
1111
### Intro
1212

1313
In Warcraft III most abilities, unlike units, are unique and thus the parent ability must be specified to gain access to custom data fields.
14-
The standard library wraps this nicely by providing classes for each unique spell in `AbilityObjEditing` and presets for channel based custom spells `ChannelAbilityPreset`.
14+
The standard library wraps this nicely with two object editing packages:
15+
16+
- `AbilityObjEditing` provides generated classes for existing Warcraft III abilities, such as `AbilityDefinitionFireBolt`.
17+
- `ChannelAbilityPreset` provides a preset for channel-based custom spells.
18+
19+
The examples below assume these imports:
20+
21+
```wurst
22+
import AbilityObjEditing
23+
import ChannelAbilityPreset
24+
```
1525

1626
### Normal Spells
1727

18-
To generate and modify normal spells, use the correspoding class from `AbilityObjEditing`.
28+
To generate and modify normal spells, use the corresponding class from `AbilityObjEditing`.
1929
E.g. if you want to generate a fireball ability, use `AbilityDefinitionFireBolt` or `AbilityDefinitionPaladinDivineShield` for divine shield.
2030

2131

@@ -45,7 +55,8 @@ But in a more condensed form, and one which automatically adapts if you change t
4555

4656
### Channel Spells
4757

48-
Most custom spells are based on channel. It is a very customizable ability without an effect made exactly for this purpose.
58+
Most triggered custom spells are based on channel. This part uses the separate `ChannelAbilityPreset` package, which builds on the generated ability definitions from `AbilityObjEditing`.
59+
Channel is a very customizable ability without an effect made exactly for this purpose.
4960
By default channel spells emit some odd behaviour, like being invisible and having to "channel" the spell for a duration of time, like Blizzard or Fire Rain.
5061
You can reset all these properties by passing `true` as last argument in the constructor.
5162

_sass/doc.scss

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,8 +719,11 @@ code {
719719
}
720720
}
721721
.doc-sub-menu {
722+
display: none;
722723
list-style: none;
723724
padding-left: 0;
725+
margin: 4px 0 6px;
726+
724727
& > li {
725728
margin-bottom: 10px;
726729
font-size: 14px;
@@ -787,6 +790,20 @@ code {
787790
}
788791
}
789792

793+
.doc-sub-menu .doc-sub-menu {
794+
margin-top: 6px;
795+
796+
& > li {
797+
font-size: 13px;
798+
margin-bottom: 7px;
799+
800+
& > a {
801+
padding-left: 48px;
802+
color: var(--text-color-secondary);
803+
}
804+
}
805+
}
806+
790807
.affix,
791808
.affix-bottom {
792809
width: 230px;
@@ -1188,6 +1205,11 @@ code {
11881205
}
11891206
}
11901207

1208+
.doc-menu li.open > .doc-sub-menu,
1209+
.doc-menu li.active > .doc-sub-menu {
1210+
display: block;
1211+
}
1212+
11911213
.doc-sidebar .affix,
11921214
.doc-sidebar .affix-top,
11931215
.doc-sidebar .affix-bottom {

assets/js/main.js

Lines changed: 115 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,105 @@ function scrollToElement(id) {
4848
return true;
4949
}
5050

51+
function ensureHeadingId(heading, usedIds) {
52+
const fallback = slugify(heading.textContent) || "section";
53+
const base = heading.id || fallback;
54+
let id = base;
55+
let suffix = 2;
56+
57+
while (
58+
usedIds.has(id) ||
59+
(document.getElementById(id) && document.getElementById(id) !== heading)
60+
) {
61+
id = `${base}-${suffix}`;
62+
suffix += 1;
63+
}
64+
65+
heading.id = id;
66+
usedIds.add(id);
67+
return id;
68+
}
69+
70+
function appendTocItem(parent, heading, id, depth) {
71+
const item = document.createElement("li");
72+
item.dataset.tocDepth = String(depth);
73+
74+
const link = document.createElement("a");
75+
link.className = "scrollto";
76+
link.href = `#${id}`;
77+
link.textContent = heading.textContent.trim();
78+
79+
item.appendChild(link);
80+
parent.appendChild(item);
81+
return item;
82+
}
83+
84+
function getSubMenu(parentItem) {
85+
let subMenu = Array.from(parentItem.children).find((child) =>
86+
child.classList.contains("doc-sub-menu")
87+
);
88+
89+
if (!subMenu) {
90+
subMenu = document.createElement("ul");
91+
subMenu.className = "nav doc-sub-menu";
92+
parentItem.appendChild(subMenu);
93+
}
94+
95+
return subMenu;
96+
}
97+
98+
function buildSidebarToc(navContainer) {
99+
const content = document.querySelector(".doc-content");
100+
if (!content) return false;
101+
102+
const headings = Array.from(content.querySelectorAll("h2, h3, h4")).filter(
103+
(heading) => heading.textContent.trim().length > 0
104+
);
105+
if (headings.length === 0) return false;
106+
107+
const hasH2 = headings.some((heading) => heading.tagName === "H2");
108+
const hasH3 = headings.some((heading) => heading.tagName === "H3");
109+
const topLevel = hasH2 ? 2 : hasH3 ? 3 : 4;
110+
const maxLevel = Math.min(topLevel + 2, 4);
111+
const usedIds = new Set();
112+
const stack = [];
113+
let itemCount = 0;
114+
115+
Array.from(navContainer.children).forEach((child) => {
116+
if (!child.classList.contains("nav-heading")) {
117+
child.remove();
118+
}
119+
});
120+
121+
headings.forEach((heading) => {
122+
const level = Number(heading.tagName.substring(1));
123+
if (level < topLevel || level > maxLevel) return;
124+
125+
const id = ensureHeadingId(heading, usedIds);
126+
const parentLevel = level - 1;
127+
let parentItem = null;
128+
129+
for (let candidate = parentLevel; candidate >= topLevel; candidate -= 1) {
130+
if (stack[candidate]) {
131+
parentItem = stack[candidate];
132+
break;
133+
}
134+
}
135+
136+
const depth = parentItem ? level - topLevel : 0;
137+
const parent = parentItem ? getSubMenu(parentItem) : navContainer;
138+
const item = appendTocItem(parent, heading, id, depth);
139+
140+
stack[level] = item;
141+
for (let candidate = level + 1; candidate <= maxLevel; candidate += 1) {
142+
stack[candidate] = null;
143+
}
144+
itemCount += 1;
145+
});
146+
147+
return itemCount > 0;
148+
}
149+
51150
$(document).ready(function () {
52151
$("#cards-wrapper .item-inner").matchHeight();
53152
$("#showcase .card").matchHeight();
@@ -77,37 +176,7 @@ $(document).ready(function () {
77176
scrollToElement(window.location.hash.substring(1));
78177
}
79178

80-
// On dense API-reference pages there can be hundreds of h3 entities; listing them all makes the
81-
// sidebar unusable (and the scroll-spy slow), so fall back to just the h2 group headings.
82-
const h3Count = document.querySelectorAll(".doc-content h3").length;
83-
const headingSelector = h3Count > 80 ? ".doc-content h2" : ".doc-content h2, .doc-content h3";
84-
const headingNodes = Array.from(document.querySelectorAll(headingSelector));
85-
const existingSectionLinks = navContainer.querySelectorAll('a.scrollto[href^="#"]');
86-
87-
// Only auto-generate TOC when the template did not render one from frontmatter sections.
88-
if (existingSectionLinks.length === 0 && headingNodes.length > 0) {
89-
let currentSubList = null;
90-
headingNodes.forEach((heading) => {
91-
const id = heading.id || slugify(heading.textContent);
92-
heading.id = id;
93-
94-
if (heading.tagName === "H2") {
95-
const item = document.createElement("li");
96-
item.innerHTML = `<a class="scrollto" href="#${id}">${heading.textContent}</a>`;
97-
navContainer.appendChild(item);
98-
currentSubList = null;
99-
} else {
100-
if (!currentSubList) {
101-
currentSubList = document.createElement("ul");
102-
currentSubList.className = "nav doc-sub-menu";
103-
navContainer.appendChild(currentSubList);
104-
}
105-
const item = document.createElement("li");
106-
item.innerHTML = `<a class="scrollto" href="#${id}">${heading.textContent}</a>`;
107-
currentSubList.appendChild(item);
108-
}
109-
});
110-
}
179+
buildSidebarToc(navContainer);
111180

112181
const navLinks = Array.from(document.querySelectorAll("a.scrollto[href^='#']"));
113182

@@ -142,6 +211,20 @@ $(document).ready(function () {
142211

143212
let selected = null;
144213

214+
function updateOpenGroups(current) {
215+
navContainer
216+
.querySelectorAll("li.open")
217+
.forEach((item) => item.classList.remove("open"));
218+
219+
let item = current;
220+
while (item && item !== navContainer) {
221+
if (item.tagName === "LI") {
222+
item.classList.add("open");
223+
}
224+
item = item.parentElement ? item.parentElement.closest("li") : null;
225+
}
226+
}
227+
145228
function updateActive() {
146229
const marker = window.innerHeight * 0.24;
147230
let current = offsetMap[0].nav;
@@ -156,6 +239,7 @@ $(document).ready(function () {
156239
if (selected) selected.classList.remove("active");
157240
selected = current;
158241
selected.classList.add("active");
242+
updateOpenGroups(selected);
159243
}
160244
}
161245

387 Bytes
Binary file not shown.
515 Bytes
Binary file not shown.

pagefind/pagefind-entry.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"1.5.2","languages":{"en":{"hash":"en_f693c88132","wasm":"en","page_count":235}},"include_characters":["_","","","","","","","","","_"]}
1+
{"version":"1.5.2","languages":{"en":{"hash":"en_b2672a7d87","wasm":"en","page_count":235}},"include_characters":["_","","","","","","","","","_"]}
2.05 KB
Binary file not shown.

0 commit comments

Comments
 (0)