Skip to content

Commit f11bb7d

Browse files
committed
Change knowls to being buttons that open modal dialogs.
This definitively solves the problem of placement of the knowl content. The old method of trying to find a place to put the content in an accordion is entirely unreliable, and depends on the problem author not doing bad things. Technically a knowl link is not a link at all anymore. In fact it is now a button. Although, it really wasn't a link before either. It was an anchor with a href to the root fragment, and the default action for that was disabled by JavaScript. There is a new option that can be passed to the `knowlLink` method. That is a `title`. This `title` will be used for the title of the modal dialog if provided. Otherwise first required argument of the `knowlLink` (the `$display_text`) will be used for the modal dialog title.
1 parent b2f97b8 commit f11bb7d

File tree

4 files changed

+167
-206
lines changed

4 files changed

+167
-206
lines changed

htdocs/js/Knowls/knowl.css

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

htdocs/js/Knowls/knowl.js

Lines changed: 55 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -15,111 +15,92 @@
1515
};
1616

1717
const initializeKnowl = (knowl) => {
18-
if (getComputedStyle(knowl)?.display === '') {
19-
setTimeout(() => initializeKnowl(knowl), 100);
20-
return;
21-
}
22-
23-
knowl.dataset.bsToggle = 'collapse';
24-
if (!knowl.knowlContainer) {
25-
knowl.knowlContainer = document.createElement('div');
26-
knowl.knowlContainer.id = `knowl-uid-${knowlUID++}`;
27-
knowl.knowlContainer.classList.add('collapse');
18+
knowl.dataset.bsToggle = 'modal';
19+
if (!knowl.knowlModal) {
20+
knowl.knowlModal = document.createElement('div');
21+
knowl.knowlModal.id = `knowl-uid-${knowlUID++}`;
22+
knowl.knowlModal.classList.add('modal', 'fade');
23+
knowl.knowlModal.tabIndex = -1;
24+
knowl.knowlModal.setAttribute('aria-labelledby', `${knowl.knowlModal.id}-title`);
25+
knowl.knowlModal.setAttribute('aria-hidden', 'true');
2826

29-
const knowlOutput = document.createElement('div');
30-
knowlOutput.classList.add('knowl-output');
27+
const knowlDialog = document.createElement('div');
28+
knowlDialog.classList.add('modal-dialog', 'modal-dialog-centered', 'modal-dialog-scrollable');
29+
knowl.knowlModal.append(knowlDialog);
3130

3231
const knowlContent = document.createElement('div');
33-
knowlContent.classList.add('knowl-content');
34-
knowlOutput.append(knowlContent);
32+
knowlContent.classList.add('modal-content');
33+
knowlDialog.append(knowlContent);
34+
35+
const knowlHeader = document.createElement('div');
36+
knowlHeader.classList.add('modal-header');
37+
38+
const knowlTitle = document.createElement('h1');
39+
knowlTitle.classList.add('modal-title', 'fs-5');
40+
knowlTitle.id = `${knowl.knowlModal.id}-title`;
41+
knowlTitle.textContent = knowl.dataset.knowlTitle || knowl.textContent;
42+
43+
const closeButton = document.createElement('button');
44+
closeButton.type = 'button';
45+
closeButton.classList.add('btn-close');
46+
closeButton.dataset.bsDismiss = 'modal';
47+
closeButton.setAttribute('aria-label', 'Close');
48+
49+
knowlHeader.append(knowlTitle, closeButton);
50+
51+
const knowlBody = document.createElement('div');
52+
knowlBody.classList.add('modal-body');
53+
54+
knowlContent.append(knowlHeader, knowlBody);
3555

3656
if (knowl.dataset.knowlUrl) {
3757
const knowlFooter = document.createElement('div');
38-
knowlFooter.classList.add('knowl-footer');
58+
knowlFooter.classList.add('modal-footer', 'knowl-footer', 'justify-content-center', 'p-1');
3959
knowlFooter.textContent = knowl.dataset.knowlUrl;
40-
knowlOutput.append(knowlFooter);
60+
knowlContent.append(knowlFooter);
4161
}
4262

43-
knowl.knowlContainer.appendChild(knowlOutput);
44-
45-
knowl.knowlContainer.addEventListener('show.bs.collapse', () => knowl.classList.add('active'));
46-
knowl.knowlContainer.addEventListener('hide.bs.collapse', () => knowl.classList.remove('active'));
47-
48-
// If the knowl is inside a table row, then insert a new row into the table after that one to contain
49-
// the knowl content. If the knowl is inside a list element, then insert the content after the list
50-
// element. Otherwise insert the content either before the first sibling that follows it that is
51-
// display block, or append it to the first ancestor that is display block.
52-
let insertElt = knowl.closest('tr');
53-
if (insertElt) {
54-
const row = document.createElement('tr');
55-
const td = document.createElement('td');
56-
td.colSpan = insertElt.childElementCount;
57-
td.appendChild(knowl.knowlContainer);
58-
row.appendChild(td);
59-
insertElt.after(row);
60-
} else {
61-
insertElt = knowl.closest('li');
62-
if (insertElt) {
63-
const newDiv = document.createElement('div');
64-
newDiv.append(knowl.knowlContainer);
65-
insertElt.append(newDiv);
66-
} else {
67-
let append = false;
68-
insertElt = knowl;
69-
do {
70-
const lastElt = insertElt;
71-
insertElt = lastElt.nextElementSibling;
72-
if (!insertElt) {
73-
insertElt = lastElt.parentNode;
74-
append = true;
75-
}
76-
} while (getComputedStyle(insertElt)?.getPropertyValue('display') !== 'block');
63+
// Insert the knowl modal into the end of the closest div ancestor.
64+
// If no such element is found, there is not much else that can be done, so just bail.
65+
const insertElt = knowl.closest('div');
66+
if (insertElt) insertElt.append(knowl.knowlModal);
67+
else return;
7768

78-
if (append) insertElt.append(knowl.knowlContainer);
79-
else insertElt.before(knowl.knowlContainer);
80-
}
81-
}
82-
83-
knowl.dataset.bsTarget = `#${knowl.knowlContainer.id}`;
69+
knowl.dataset.bsTarget = `#${knowl.knowlModal.id}`;
8470

8571
if (knowl.dataset.knowlContents) {
8672
// Inline html
87-
if (knowl.dataset.base64 == '1') {
88-
if (window.Base64) setInnerHTML(knowlContent, Base64.decode(knowl.dataset.knowlContents));
89-
else {
90-
setInnerHTML(knowlContent, 'ERROR: Base64 decoding not available');
91-
knowlContent.classList.add('knowl-error');
92-
}
93-
} else {
94-
setInnerHTML(knowlContent, knowl.dataset.knowlContents);
95-
}
73+
setInnerHTML(knowlBody, knowl.dataset.knowlContents);
74+
9675
// If we are using MathJax, then render math content.
9776
if (window.MathJax) {
98-
MathJax.startup.promise = MathJax.startup.promise.then(() =>
99-
MathJax.typesetPromise([knowlContent])
100-
);
77+
MathJax.startup.promise = MathJax.startup.promise.then(() => MathJax.typesetPromise([knowlBody]));
10178
}
10279
} else if (knowl.dataset.knowlUrl) {
10380
// Retrieve url content.
10481
fetch(knowl.dataset.knowlUrl)
10582
.then((response) => (response.ok ? response.text() : response))
10683
.then((data) => {
10784
if (typeof data == 'object') {
108-
knowlContent.textContent = `ERROR: ${data.status} ${data.statusText}`;
109-
knowlContent.classList.add('knowl-error');
85+
knowlBody.textContent = `ERROR: ${data.status} ${data.statusText}`;
86+
knowlBody.classList.add('knowl-error');
11087
} else {
111-
setInnerHTML(knowlContent, data);
88+
setInnerHTML(knowlBody, data);
11289
}
11390
// If we are using MathJax, then render math content.
11491
if (window.MathJax) {
11592
MathJax.startup.promise = MathJax.startup.promise.then(() =>
116-
MathJax.typesetPromise([knowlContent])
93+
MathJax.typesetPromise([knowlBody])
11794
);
11895
}
96+
})
97+
.catch((err) => {
98+
knowlBody.textContent = `ERROR: ${err}`;
99+
knowlBody.classList.add('knowl-error');
119100
});
120101
} else {
121-
knowlContent.textContent = 'ERROR: knowl content not provided.';
122-
knowlContent.classList.add('knowl-error');
102+
knowlBody.textContent = 'ERROR: knowl content not provided.';
103+
knowlBody.classList.add('knowl-error');
123104
}
124105
}
125106
};

htdocs/js/Knowls/knowl.scss

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
.knowl {
2+
color: #00a;
3+
background-color: #eef;
4+
border: 1px solid #88f;
5+
border-radius: 3px;
6+
cursor: pointer;
7+
8+
&:hover {
9+
color: #006;
10+
background-color: #ccf;
11+
border-color: #33f;
12+
}
13+
14+
&:focus-visible {
15+
border-color: #33f;
16+
box-shadow: 0px 0px 0px 0.2rem #5555ff88;
17+
outline: 0;
18+
}
19+
}
20+
21+
li > .knowl {
22+
margin: 0.2rem 0;
23+
}
24+
25+
.knowl-error {
26+
color: darkred;
27+
}
28+
29+
.knowl-footer {
30+
font-size: x-small;
31+
background: #eef;
32+
color: #555;
33+
}
34+
35+
// MathJax sets the z-index to 200 which is far below a modal dialog at 1055. So raise that above the modal dialog.
36+
// This is really a bug in MathJax. MathJax should handle this differently.
37+
.CtxtMenu_MenuFrame {
38+
z-index: 1060 !important;
39+
40+
.CtxtMenu_Menu {
41+
z-index: 1060;
42+
}
43+
}

0 commit comments

Comments
 (0)