diff --git a/public/common/utils.js b/public/common/utils.js index 7f95e8f9..84daeb05 100644 --- a/public/common/utils.js +++ b/public/common/utils.js @@ -1,6 +1,6 @@ // Import Internal Dependencies import avatarURL from "../img/avatar-default.png"; -import { createExpandableSpan } from "../components/expandable/expandable.js"; +import "../components/expandable/expandable.js"; window.activeLegendElement = null; @@ -195,11 +195,36 @@ export function createItemsList(node, items = [], options = {}) { } if (hideItems && items.length > hideItemsLength) { - fragment.appendChild(createExpandableSpan(hideItemsLength)); + const expandableSpan = document.createElement("expandable-span"); + expandableSpan.onToggle = (expandable) => toggle(expandable, node, hideItemsLength); + fragment.appendChild(expandableSpan); } node.appendChild(fragment); } +/* +TODO: this util function won't be necessary once the parents of the expandable component will be migrated to lit +becuase the parents will handle the filtering of their children themselves +*/ +export function toggle(expandable, parentNode, hideItemsLength) { + expandable.isClosed = !expandable.isClosed; + for (let id = 0; id < parentNode.childNodes.length; id++) { + const node = parentNode.childNodes[id]; + if (node.tagName === "EXPANDABLE-SPAN") { + continue; + } + + if (node !== this) { + if (expandable.isClosed) { + node.classList.remove("hidden"); + } + else if (id >= hideItemsLength) { + node.classList.add("hidden"); + } + } + } +} + export function copyToClipboard(str) { const el = document.createElement("textarea"); el.value = str; diff --git a/public/components/expandable/expandable.css b/public/components/expandable/expandable.css index 9fa87843..3a39f60f 100644 --- a/public/components/expandable/expandable.css +++ b/public/components/expandable/expandable.css @@ -32,7 +32,7 @@ span.expandable i { margin-top: 10px; } -.home--body .expandable { +.home--body expandable-span { text-shadow: none; font-size: 15px; color: var(--secondary-darker); diff --git a/public/components/expandable/expandable.js b/public/components/expandable/expandable.js index 9af6b1de..341b2792 100644 --- a/public/components/expandable/expandable.js +++ b/public/components/expandable/expandable.js @@ -1,44 +1,45 @@ +// Import Third-party Dependencies +import { LitElement, html } from "lit"; +import { when } from "lit/directives/when.js"; + // Import Internal Dependencies -import { createDOMElement, currentLang } from "../../common/utils"; - -export function createExpandableSpan( - hideItemsLength, - onclick = () => void 0 -) { - const lang = currentLang(); - const span = createDOMElement("span", { - classList: ["expandable"], - attributes: { "data-value": "closed" }, - childs: [ - createDOMElement("i", { className: "icon-plus-squared-alt" }), - createDOMElement("p", { text: window.i18n[lang].home.showMore }) - ] - }); - span.addEventListener("click", function itemListClickAction() { - const isClosed = this.getAttribute("data-value") === "closed"; - { - const innerI = this.querySelector("i"); - innerI.classList.remove(isClosed ? "icon-plus-squared-alt" : "icon-minus-squared-alt"); - innerI.classList.add(isClosed ? "icon-minus-squared-alt" : "icon-plus-squared-alt"); - } - - this.querySelector("p").textContent = isClosed ? - window.i18n[lang].home.showLess : window.i18n[lang].home.showMore; - this.setAttribute("data-value", isClosed ? "opened" : "closed"); - - for (let id = 0; id < this.parentNode.childNodes.length; id++) { - const node = this.parentNode.childNodes[id]; - if (node !== this) { - if (isClosed) { - node.classList.remove("hidden"); - } - else if (id >= hideItemsLength) { - node.classList.add("hidden"); - } - } - } - onclick(this); - }); - - return span; +import { currentLang } from "../../common/utils"; + +class Expandable extends LitElement { + static properties = { + onToggle: { type: Function }, + isClosed: { type: Boolean } + }; + + constructor() { + super(); + this.isClosed = false; + this.onToggle = () => void 0; + } + + // FIXME: must opt out from the shadow DOM for now because of to be able to apply CSS from fontello + createRenderRoot() { + return this; + } + + render() { + const lang = currentLang(); + + return html` + +`; + } + + #handleClick() { + this.onToggle(this); + } } + +customElements.define("expandable-span", Expandable); diff --git a/public/components/gauge/gauge.js b/public/components/gauge/gauge.js index 1f6d4cfc..588bb683 100644 --- a/public/components/gauge/gauge.js +++ b/public/components/gauge/gauge.js @@ -1,6 +1,6 @@ // Import Internal Dependencies import * as utils from "../../common/utils.js"; -import { createExpandableSpan } from "../expandable/expandable.js"; +import "../expandable/expandable.js"; export class Gauge { /** @@ -80,6 +80,9 @@ export class Gauge { render() { const childs = []; const hideItems = this.data.length > this.maxLength; + const gauge = utils.createDOMElement("div", { + className: "gauge" + }); for (let id = 0; id < this.data.length; id++) { const { name, value, link = null, chips = null } = this.data[id]; @@ -100,12 +103,13 @@ export class Gauge { } if (hideItems) { - childs.push(createExpandableSpan(this.maxLength)); + const expandableSpan = document.createElement("expandable-span"); + expandableSpan.onToggle = (expandable) => utils.toggle(expandable, gauge, this.maxLength); + childs.push(expandableSpan); } - return utils.createDOMElement("div", { - className: "gauge", - childs - }); + gauge.replaceChildren(...childs); + + return gauge; } } diff --git a/public/components/package/pannels/scripts/scripts.js b/public/components/package/pannels/scripts/scripts.js index cac5e634..ceb69c1d 100644 --- a/public/components/package/pannels/scripts/scripts.js +++ b/public/components/package/pannels/scripts/scripts.js @@ -1,6 +1,6 @@ // Import Internal Dependencies import * as utils from "../../../../common/utils.js"; -import { createExpandableSpan } from "../../../expandable/expandable.js"; +import "../../../expandable/expandable.js"; // CONSTANTS const kUnsafeNpmScripts = new Set([ @@ -24,14 +24,14 @@ export class Scripts { generate(clone) { this.setupSignal(clone); - const fragment = this.renderScripts(); const packageScriptsElement = clone.querySelector(".package-scripts"); + const fragment = this.renderScripts(packageScriptsElement); if (fragment === null) { clone.getElementById("script-title").style.display = "none"; packageScriptsElement.style.display = "none"; } else { - packageScriptsElement.appendChild(this.renderScripts()); + packageScriptsElement.appendChild(this.renderScripts(packageScriptsElement)); } this.renderDependencies(clone); this.showHideDependenciesInTree(clone); @@ -51,7 +51,7 @@ export class Scripts { } } - renderScripts() { + renderScripts(packageScriptsElement) { const fragment = document.createDocumentFragment(); function createPElement(className, text) { return utils.createDOMElement("p", { className, text }); @@ -86,7 +86,9 @@ export class Scripts { } if (hideItems) { - fragment.appendChild(createExpandableSpan(hideItemsLength)); + const expandableSpan = document.createElement("expandable-span"); + expandableSpan.onToggle = (expandable) => utils.toggle(expandable, packageScriptsElement, hideItemsLength); + fragment.appendChild(expandableSpan); } return fragment; diff --git a/public/components/views/home/home.js b/public/components/views/home/home.js index ed354b8b..90f0369b 100644 --- a/public/components/views/home/home.js +++ b/public/components/views/home/home.js @@ -6,7 +6,7 @@ import { getScoreColor, getVCSRepositoryPathAndPlatform } from "@nodesecure/util // Import Internal Dependencies import * as utils from "../../../common/utils.js"; import { Gauge } from "../../gauge/gauge.js"; -import { createExpandableSpan } from "../../expandable/expandable.js"; +import "../../expandable/expandable.js"; import { fetchScorecardData, getScorecardLink } from "../../../common/scorecard.js"; // Import Components @@ -223,7 +223,11 @@ export class HomeView { } else { if (hideItems) { - fragment.appendChild(createExpandableSpan(maxPackages)); + const expandableSpan = document.createElement("expandable-span"); + expandableSpan.onToggle = (expandable) => utils.toggle(expandable, + document.querySelector(".home--packages--overview"), + maxPackages); + fragment.appendChild(expandableSpan); } document.querySelector(".home--packages--overview") diff --git a/public/components/views/home/maintainers/maintainers.js b/public/components/views/home/maintainers/maintainers.js index 23ce1c4b..b2e83936 100644 --- a/public/components/views/home/maintainers/maintainers.js +++ b/public/components/views/home/maintainers/maintainers.js @@ -1,7 +1,7 @@ // Import Internal Dependencies import * as utils from "../../../../common/utils.js"; -import { createExpandableSpan } from "../../../expandable/expandable.js"; import { PopupTemplate } from "../../../popup/popup.js"; +import "../../../expandable/expandable.js"; export class Maintainers { static whois(name, email) { @@ -30,8 +30,8 @@ export class Maintainers { .sort((left, right) => right[1].packages.size - left[1].packages.size)); document.getElementById("authors-count").innerHTML = authors.length; - document.querySelector(".home--maintainers") - .appendChild(this.generate(authors)); + const maintainers = document.querySelector(".home--maintainers"); + this.generate(authors, maintainers); } #highlightContacts(authors) { @@ -43,7 +43,7 @@ export class Maintainers { return [...highlightedAuthors, ...authorsRest]; } - generate(authors) { + generate(authors, maintainers) { const fragment = document.createDocumentFragment(); const hideItems = authors.length > this.maximumMaintainers; @@ -85,11 +85,14 @@ export class Maintainers { fragment.appendChild(person); } + + maintainers.appendChild(fragment); if (hideItems) { - fragment.appendChild(createExpandableSpan(this.maximumMaintainers)); - } + const expandableSpan = document.createElement("expandable-span"); + expandableSpan.onToggle = (expandable) => utils.toggle(expandable, maintainers, this.maximumMaintainers); - return fragment; + maintainers.appendChild(expandableSpan); + } } }