Skip to content

Commit 2e5b3d6

Browse files
authored
refactor(expandable): migrate to lit.js (#551)
1 parent 7ba3781 commit 2e5b3d6

File tree

7 files changed

+104
-65
lines changed

7 files changed

+104
-65
lines changed

public/common/utils.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Import Internal Dependencies
22
import avatarURL from "../img/avatar-default.png";
3-
import { createExpandableSpan } from "../components/expandable/expandable.js";
3+
import "../components/expandable/expandable.js";
44

55
window.activeLegendElement = null;
66

@@ -195,11 +195,36 @@ export function createItemsList(node, items = [], options = {}) {
195195
}
196196

197197
if (hideItems && items.length > hideItemsLength) {
198-
fragment.appendChild(createExpandableSpan(hideItemsLength));
198+
const expandableSpan = document.createElement("expandable-span");
199+
expandableSpan.onToggle = (expandable) => toggle(expandable, node, hideItemsLength);
200+
fragment.appendChild(expandableSpan);
199201
}
200202
node.appendChild(fragment);
201203
}
202204

205+
/*
206+
TODO: this util function won't be necessary once the parents of the expandable component will be migrated to lit
207+
becuase the parents will handle the filtering of their children themselves
208+
*/
209+
export function toggle(expandable, parentNode, hideItemsLength) {
210+
expandable.isClosed = !expandable.isClosed;
211+
for (let id = 0; id < parentNode.childNodes.length; id++) {
212+
const node = parentNode.childNodes[id];
213+
if (node.tagName === "EXPANDABLE-SPAN") {
214+
continue;
215+
}
216+
217+
if (node !== this) {
218+
if (expandable.isClosed) {
219+
node.classList.remove("hidden");
220+
}
221+
else if (id >= hideItemsLength) {
222+
node.classList.add("hidden");
223+
}
224+
}
225+
}
226+
}
227+
203228
export function copyToClipboard(str) {
204229
const el = document.createElement("textarea");
205230
el.value = str;

public/components/expandable/expandable.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ span.expandable i {
3232
margin-top: 10px;
3333
}
3434

35-
.home--body .expandable {
35+
.home--body expandable-span {
3636
text-shadow: none;
3737
font-size: 15px;
3838
color: var(--secondary-darker);
Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,45 @@
1+
// Import Third-party Dependencies
2+
import { LitElement, html } from "lit";
3+
import { when } from "lit/directives/when.js";
4+
15
// Import Internal Dependencies
2-
import { createDOMElement, currentLang } from "../../common/utils";
3-
4-
export function createExpandableSpan(
5-
hideItemsLength,
6-
onclick = () => void 0
7-
) {
8-
const lang = currentLang();
9-
const span = createDOMElement("span", {
10-
classList: ["expandable"],
11-
attributes: { "data-value": "closed" },
12-
childs: [
13-
createDOMElement("i", { className: "icon-plus-squared-alt" }),
14-
createDOMElement("p", { text: window.i18n[lang].home.showMore })
15-
]
16-
});
17-
span.addEventListener("click", function itemListClickAction() {
18-
const isClosed = this.getAttribute("data-value") === "closed";
19-
{
20-
const innerI = this.querySelector("i");
21-
innerI.classList.remove(isClosed ? "icon-plus-squared-alt" : "icon-minus-squared-alt");
22-
innerI.classList.add(isClosed ? "icon-minus-squared-alt" : "icon-plus-squared-alt");
23-
}
24-
25-
this.querySelector("p").textContent = isClosed ?
26-
window.i18n[lang].home.showLess : window.i18n[lang].home.showMore;
27-
this.setAttribute("data-value", isClosed ? "opened" : "closed");
28-
29-
for (let id = 0; id < this.parentNode.childNodes.length; id++) {
30-
const node = this.parentNode.childNodes[id];
31-
if (node !== this) {
32-
if (isClosed) {
33-
node.classList.remove("hidden");
34-
}
35-
else if (id >= hideItemsLength) {
36-
node.classList.add("hidden");
37-
}
38-
}
39-
}
40-
onclick(this);
41-
});
42-
43-
return span;
6+
import { currentLang } from "../../common/utils";
7+
8+
class Expandable extends LitElement {
9+
static properties = {
10+
onToggle: { type: Function },
11+
isClosed: { type: Boolean }
12+
};
13+
14+
constructor() {
15+
super();
16+
this.isClosed = false;
17+
this.onToggle = () => void 0;
18+
}
19+
20+
// FIXME: must opt out from the shadow DOM for now because of to be able to apply CSS from fontello
21+
createRenderRoot() {
22+
return this;
23+
}
24+
25+
render() {
26+
const lang = currentLang();
27+
28+
return html`
29+
<span data-value=${this.isClosed ? "opened" : "closed"} @click=${this.#handleClick} class="expandable">
30+
${when(this.isClosed,
31+
() => html`<i class="icon-minus-squared-alt"></i>
32+
<p>${window.i18n[lang].home.showLess}</p>`,
33+
() => html`<i class="icon-plus-squared-alt"></i>
34+
<p>${window.i18n[lang].home.showMore}</p>`
35+
)}
36+
</span>
37+
`;
38+
}
39+
40+
#handleClick() {
41+
this.onToggle(this);
42+
}
4443
}
44+
45+
customElements.define("expandable-span", Expandable);

public/components/gauge/gauge.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Import Internal Dependencies
22
import * as utils from "../../common/utils.js";
3-
import { createExpandableSpan } from "../expandable/expandable.js";
3+
import "../expandable/expandable.js";
44

55
export class Gauge {
66
/**
@@ -80,6 +80,9 @@ export class Gauge {
8080
render() {
8181
const childs = [];
8282
const hideItems = this.data.length > this.maxLength;
83+
const gauge = utils.createDOMElement("div", {
84+
className: "gauge"
85+
});
8386

8487
for (let id = 0; id < this.data.length; id++) {
8588
const { name, value, link = null, chips = null } = this.data[id];
@@ -100,12 +103,13 @@ export class Gauge {
100103
}
101104

102105
if (hideItems) {
103-
childs.push(createExpandableSpan(this.maxLength));
106+
const expandableSpan = document.createElement("expandable-span");
107+
expandableSpan.onToggle = (expandable) => utils.toggle(expandable, gauge, this.maxLength);
108+
childs.push(expandableSpan);
104109
}
105110

106-
return utils.createDOMElement("div", {
107-
className: "gauge",
108-
childs
109-
});
111+
gauge.replaceChildren(...childs);
112+
113+
return gauge;
110114
}
111115
}

public/components/package/pannels/scripts/scripts.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Import Internal Dependencies
22
import * as utils from "../../../../common/utils.js";
3-
import { createExpandableSpan } from "../../../expandable/expandable.js";
3+
import "../../../expandable/expandable.js";
44

55
// CONSTANTS
66
const kUnsafeNpmScripts = new Set([
@@ -24,14 +24,14 @@ export class Scripts {
2424
generate(clone) {
2525
this.setupSignal(clone);
2626

27-
const fragment = this.renderScripts();
2827
const packageScriptsElement = clone.querySelector(".package-scripts");
28+
const fragment = this.renderScripts(packageScriptsElement);
2929
if (fragment === null) {
3030
clone.getElementById("script-title").style.display = "none";
3131
packageScriptsElement.style.display = "none";
3232
}
3333
else {
34-
packageScriptsElement.appendChild(this.renderScripts());
34+
packageScriptsElement.appendChild(this.renderScripts(packageScriptsElement));
3535
}
3636
this.renderDependencies(clone);
3737
this.showHideDependenciesInTree(clone);
@@ -51,7 +51,7 @@ export class Scripts {
5151
}
5252
}
5353

54-
renderScripts() {
54+
renderScripts(packageScriptsElement) {
5555
const fragment = document.createDocumentFragment();
5656
function createPElement(className, text) {
5757
return utils.createDOMElement("p", { className, text });
@@ -86,7 +86,9 @@ export class Scripts {
8686
}
8787

8888
if (hideItems) {
89-
fragment.appendChild(createExpandableSpan(hideItemsLength));
89+
const expandableSpan = document.createElement("expandable-span");
90+
expandableSpan.onToggle = (expandable) => utils.toggle(expandable, packageScriptsElement, hideItemsLength);
91+
fragment.appendChild(expandableSpan);
9092
}
9193

9294
return fragment;

public/components/views/home/home.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getScoreColor, getVCSRepositoryPathAndPlatform } from "@nodesecure/util
66
// Import Internal Dependencies
77
import * as utils from "../../../common/utils.js";
88
import { Gauge } from "../../gauge/gauge.js";
9-
import { createExpandableSpan } from "../../expandable/expandable.js";
9+
import "../../expandable/expandable.js";
1010
import { fetchScorecardData, getScorecardLink } from "../../../common/scorecard.js";
1111

1212
// Import Components
@@ -223,7 +223,11 @@ export class HomeView {
223223
}
224224
else {
225225
if (hideItems) {
226-
fragment.appendChild(createExpandableSpan(maxPackages));
226+
const expandableSpan = document.createElement("expandable-span");
227+
expandableSpan.onToggle = (expandable) => utils.toggle(expandable,
228+
document.querySelector(".home--packages--overview"),
229+
maxPackages);
230+
fragment.appendChild(expandableSpan);
227231
}
228232

229233
document.querySelector(".home--packages--overview")

public/components/views/home/maintainers/maintainers.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Import Internal Dependencies
22
import * as utils from "../../../../common/utils.js";
3-
import { createExpandableSpan } from "../../../expandable/expandable.js";
43
import { PopupTemplate } from "../../../popup/popup.js";
4+
import "../../../expandable/expandable.js";
55

66
export class Maintainers {
77
static whois(name, email) {
@@ -30,8 +30,8 @@ export class Maintainers {
3030
.sort((left, right) => right[1].packages.size - left[1].packages.size));
3131

3232
document.getElementById("authors-count").innerHTML = authors.length;
33-
document.querySelector(".home--maintainers")
34-
.appendChild(this.generate(authors));
33+
const maintainers = document.querySelector(".home--maintainers");
34+
this.generate(authors, maintainers);
3535
}
3636

3737
#highlightContacts(authors) {
@@ -43,7 +43,7 @@ export class Maintainers {
4343
return [...highlightedAuthors, ...authorsRest];
4444
}
4545

46-
generate(authors) {
46+
generate(authors, maintainers) {
4747
const fragment = document.createDocumentFragment();
4848
const hideItems = authors.length > this.maximumMaintainers;
4949

@@ -85,11 +85,14 @@ export class Maintainers {
8585

8686
fragment.appendChild(person);
8787
}
88+
89+
maintainers.appendChild(fragment);
8890
if (hideItems) {
89-
fragment.appendChild(createExpandableSpan(this.maximumMaintainers));
90-
}
91+
const expandableSpan = document.createElement("expandable-span");
92+
expandableSpan.onToggle = (expandable) => utils.toggle(expandable, maintainers, this.maximumMaintainers);
9193

92-
return fragment;
94+
maintainers.appendChild(expandableSpan);
95+
}
9396
}
9497
}
9598

0 commit comments

Comments
 (0)