diff --git a/public/components/icon/icon.js b/public/components/icon/icon.js
index 93dc7577..23b8ce28 100644
--- a/public/components/icon/icon.js
+++ b/public/components/icon/icon.js
@@ -129,6 +129,24 @@ c0-20.25-0.75-88.25 31-88.25c5.25 0 31.25 21.25 65 21.25c11.5 0 22.5-2 33.25-5.7
-1.25-16.5c10.75 3.75 21.75 5.75 33.25 5.75c33.75 0 59.75-21.25 65-21.25c31.75 0 31 68 31 88.25zM448 64c0 35.25-28.75
64-64 64s-64-28.75-64-64s28.75-64 64-64s64 28.75 64 64z"/>
+`,
+ unlock: html`
+
+`,
+ lock: html`
+
`
};
diff --git a/public/components/locker/locker.css b/public/components/locker/locker.css
deleted file mode 100644
index dc641c0d..00000000
--- a/public/components/locker/locker.css
+++ /dev/null
@@ -1,50 +0,0 @@
-#network-locker {
- position: absolute;
- bottom: 10px;
- right: 10px;
- z-index: 30;
- display: flex;
- height: 30px;
- border-radius: 4px;
- align-items: center;
- box-sizing: border-box;
- overflow: hidden;
- background-color: var(--primary);
- transition: 0.3s all linear;
- cursor: pointer;
-}
-
-#network-locker:not(.enabled) {
- background-color: var(--primary);
-}
-
-#network-locker.enabled {
- background-color: #af2222;
-}
-
-#network-locker>i {
- height: inherit;
- padding: 0 5px;
- display: flex;
- align-items: center;
- border-radius: 4px;
- margin-right: 10px;
- transition: 0.3s all linear;
-}
-
-#network-locker>i:not(.enabled) {
- background-color: var(--primary-lighter);
-}
-
-#network-locker>i.enabled {
- background-color: #cb3d3d;
-}
-
-#network-locker>p {
- font-family: mononoki;
- padding-right: 10px;
- display: flex;
- align-items: center;
- height: inherit;
- text-transform: capitalize;
-}
diff --git a/public/components/locker/locker.js b/public/components/locker/locker.js
index 41780227..77ea25c2 100644
--- a/public/components/locker/locker.js
+++ b/public/components/locker/locker.js
@@ -1,21 +1,104 @@
+// Import Third-party Dependencies
+import { LitElement, html, css } from "lit";
+import { classMap } from "lit/directives/class-map.js";
+
// Import Internal Dependencies
import * as utils from "../../common/utils.js";
import { EVENTS } from "../../core/events.js";
+import "../icon/icon.js";
+
+export class Locker extends LitElement {
+ static styles = css`
+#network-locker {
+ position: absolute;
+ bottom: 10px;
+ right: 10px;
+ z-index: 30;
+ display: flex;
+ height: 30px;
+ border-radius: 4px;
+ align-items: center;
+ box-sizing: border-box;
+ overflow: hidden;
+ background-color: var(--primary);
+ transition: 0.3s all linear;
+ cursor: pointer;
+}
+
+#network-locker:not(.enabled) {
+ background-color: var(--primary);
+}
+
+#network-locker.enabled {
+ background-color: #af2222;
+}
+
+#network-locker>div {
+ height: inherit;
+ padding: 0 5px;
+ display: flex;
+ align-items: center;
+ border-radius: 4px;
+ margin-right: 10px;
+ transition: 0.3s all linear;
+}
+
+#network-locker>div>nsecure-icon {
+ margin: 0;
+ transform: translateX(3px);
+}
+
+
+#network-locker>div:not(.enabled) {
+ background-color: var(--primary-lighter);
+}
+
+#network-locker>div.enabled {
+ background-color: #cb3d3d;
+}
+
+#network-locker>p {
+ font-family: mononoki;
+ padding-right: 10px;
+ display: flex;
+ align-items: center;
+ height: inherit;
+ text-transform: capitalize;
+}
+`;
+
+ static get properties() {
+ return {
+ locked: { type: Boolean },
+ unlockAuthorized: { type: Boolean },
+ nsn: { type: Object },
+ isNetworkViewHidden: { type: Boolean }
+ };
+ }
-export class Locker {
- constructor(nsn) {
- this.dom = document.getElementById("network-locker");
- this.networkView = document.getElementById("network--view");
- this.nsn = nsn;
+ constructor() {
+ super();
this.locked = false;
this.unlockAuthorized = true;
- this.renderUnlock();
+ this.isNetworkViewHidden = false;
+ this.hideNetworkView = () => {
+ if (this.isNetworkViewHidden) {
+ return;
+ }
+ this.isNetworkViewHidden = true;
+ };
- document.addEventListener("keydown", (event) => {
- const isNetworkViewHidden = this.networkView.classList.contains("hidden");
+ this.showNetworkView = () => {
+ if (!this.isNetworkViewHidden) {
+ return;
+ }
+ this.isNetworkViewHidden = false;
+ };
+
+ this.onKeyDown = (event) => {
const isTargetInput = event.target.tagName === "INPUT";
const isTargetPopup = event.target.id === "popup--background";
- if (isNetworkViewHidden || isTargetInput || isTargetPopup) {
+ if (this.isNetworkViewHidden || isTargetInput || isTargetPopup) {
return;
}
@@ -26,9 +109,61 @@ export class Locker {
break;
}
}
+ };
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ window.addEventListener(EVENTS.NETWORK_VIEW_HID, this.hideNetworkView);
+ window.addEventListener(EVENTS.NETWORK_VIEW_SHOWED, this.showNetworkView);
+ document.addEventListener("keydown", this.onKeyDown);
+ }
+
+ disconnectedCallback() {
+ window.removeEventListener(EVENTS.NETWORK_VIEW_HID, this.hideNetworkView);
+ window.removeEventListener(EVENTS.NETWORK_VIEW_SHOWED, this.showNetworkView);
+ document.removeEventListener("keydown", this.onKeyDown);
+ super.disconnectedCallback();
+ }
+
+ updated(changedProperties) {
+ if (changedProperties.has("nsn")) {
+ const oldNsn = changedProperties.get("nsn");
+
+ if (oldNsn) {
+ oldNsn.network.off("highlight_done", this.highlightDone);
+ }
+
+ if (this.nsn) {
+ this.nsn.network.on("highlight_done", this.highlightDone);
+ }
+ }
+ }
+
+ render() {
+ const networkLockerClasses = classMap({
+ enabled: this.locked
});
- this.dom.addEventListener("click", () => this.auto());
- this.nsn.network.on("highlight_done", this.highlightDone.bind(this));
+ const iconClasses = classMap({
+ enabled: this.locked
+ });
+
+ return html`
+
+
+
+
${this.locked ? window.i18n[utils.currentLang()].network.locked
+ : window.i18n[utils.currentLang()].network.unlocked}
+
`;
+ }
+
+ auto() {
+ // Refuse locking if there is no multi selections
+ if (this.nsn.lastHighlightedIds === null) {
+ return;
+ }
+
+ this[this.locked ? "unlock" : "lock"]();
}
highlightDone() {
@@ -45,19 +180,9 @@ export class Locker {
this.unlock();
}
- auto() {
- // Refuse locking if there is no multi selections
- if (this.nsn.lastHighlightedIds === null) {
- return;
- }
-
- this[this.locked ? "unlock" : "lock"]();
- }
-
lock() {
if (!this.locked) {
console.log("[LOCKER] lock triggered");
- this.renderLock();
this.locked = true;
window.dispatchEvent(new CustomEvent(EVENTS.LOCKED, { composed: true }));
}
@@ -69,7 +194,6 @@ export class Locker {
}
console.log("[LOCKER] unlock triggered");
- this.renderUnlock();
this.locked = false;
window.dispatchEvent(new CustomEvent(EVENTS.UNLOCKED, { composed: true }));
@@ -83,26 +207,6 @@ export class Locker {
this.nsn.neighbourHighlight(selectedNode, window.i18n[utils.currentLang()]);
}
}
-
- renderLock() {
- this.dom.classList.add("enabled");
- this.dom.querySelector("p").textContent = window.i18n[utils.currentLang()].network.locked;
- this.networkView.classList.add("locked");
-
- const iconElement = this.dom.querySelector("i");
- iconElement.classList.remove("icon-lock-open");
- iconElement.classList.add("icon-lock");
- iconElement.classList.add("enabled");
- }
-
- renderUnlock() {
- this.dom.classList.remove("enabled");
- this.dom.querySelector("p").textContent = window.i18n[utils.currentLang()].network.unlocked;
- this.networkView.classList.remove("locked");
-
- const iconElement = this.dom.querySelector("i");
- iconElement.classList.remove("icon-lock");
- iconElement.classList.remove("enabled");
- iconElement.classList.add("icon-lock-open");
- }
}
+
+customElements.define("nsecure-locker", Locker);
diff --git a/public/components/navigation/navigation.js b/public/components/navigation/navigation.js
index 03ebb0c4..1e692a1e 100644
--- a/public/components/navigation/navigation.js
+++ b/public/components/navigation/navigation.js
@@ -1,5 +1,6 @@
// Import Internal Dependencies
import { PackageInfo } from "../package/package.js";
+import { EVENTS } from "../../core/events.js";
// CONSTANTS
const kAvailableView = new Set([
@@ -122,6 +123,10 @@ export class ViewNavigation {
return;
}
+ if (menuName === "network--view") {
+ window.dispatchEvent(new CustomEvent(EVENTS.NETWORK_VIEW_HID, { composed: true }));
+ }
+
menu.classList.add("hidden");
}
@@ -131,6 +136,10 @@ export class ViewNavigation {
return;
}
+ if (menuName === "network--view") {
+ window.dispatchEvent(new CustomEvent(EVENTS.NETWORK_VIEW_SHOWED, { composed: true }));
+ }
+
menu.classList.remove("hidden");
}
}
diff --git a/public/components/views/home/maintainers/maintainers.js b/public/components/views/home/maintainers/maintainers.js
index 2ff6d423..ff93a6b9 100644
--- a/public/components/views/home/maintainers/maintainers.js
+++ b/public/components/views/home/maintainers/maintainers.js
@@ -523,7 +523,7 @@ export class PopupMaintainer extends LitElement {
.map((spec) => {
const { name, version } = utils.parseNpmSpec(spec);
- return `${name} @${version} `;
+ return `${name}@${version}`;
});
return html`
@@ -565,12 +565,14 @@ export class PopupMaintainer extends LitElement {
const moveTo = currentSelectedNode === null || !nodeIds.includes(currentSelectedNode.nodes[0]);
if (moveTo) {
const origin = this.nsn.network.getViewPosition();
- const closestNode = nodeIds
+ const nodes = nodeIds
.map((id) => {
return { id, pos: this.nsn.network.getPosition(id) };
- })
+ });
+ const closestNode = nodes
.reduce(
- (a, b) => (utils.vec2Distance(origin, a.pos) < utils.vec2Distance(origin, b.pos) ? a : b)
+ (a, b) => (utils.vec2Distance(origin, a.pos) < utils.vec2Distance(origin, b.pos) ? a : b),
+ nodes[0]
);
const scale = nodeIds.length > 3 ? 0.25 : 0.35;
diff --git a/public/core/events.js b/public/core/events.js
index b2a3371f..cffbfb4d 100644
--- a/public/core/events.js
+++ b/public/core/events.js
@@ -7,5 +7,7 @@ export const EVENTS = {
MOVED_TO_NEXT_LOCKED_NODE: "moved-to-next-locked-node",
MOVED_TO_PREVIOUS_LOCKED_NODE: "moved-to-previous-locked-node",
MODAL_CLOSED: "modal-closed",
- MODAL_OPENED: "modal-opened"
+ MODAL_OPENED: "modal-opened",
+ NETWORK_VIEW_HID: "network-view-hid",
+ NETWORK_VIEW_SHOWED: "network-view-showed"
};
diff --git a/public/main.css b/public/main.css
index 57a40373..c9f37642 100644
--- a/public/main.css
+++ b/public/main.css
@@ -4,7 +4,6 @@
@import url("./font/fontello/fontello.css");
@import url("./font/roboto/roboto.css");
@import url("./font/mononoki/mononoki.css");
-@import url("./components/locker/locker.css");
@import url("./components/file-box/file-box.css");
@import url("./components/expandable/expandable.css");
@import url("./components/navigation/navigation.css");
diff --git a/public/main.js b/public/main.js
index 9c2dc00e..9df9c15d 100644
--- a/public/main.js
+++ b/public/main.js
@@ -6,7 +6,7 @@ import { PackageInfo } from "./components/package/package.js";
import { ViewNavigation } from "./components/navigation/navigation.js";
import { Wiki } from "./components/wiki/wiki.js";
import "./components/popup/popup.js";
-import { Locker } from "./components/locker/locker.js";
+import "./components/locker/locker.js";
import "./components/legend/legend.js";
import "./components/locked-navigation/locked-navigation.js";
import { Settings } from "./components/views/settings/settings.js";
@@ -126,7 +126,10 @@ async function init(options = {}) {
i18n: window.i18n[utils.currentLang()],
theme: window.settings.config.theme
});
- window.locker = new Locker(nsn);
+ window.locker = document.createElement("nsecure-locker");
+ window.locker.nsn = nsn;
+ const locker = document.getElementById("network-locker");
+ locker.replaceWith(window.locker);
const legend = document.getElementById("legend");
legend.isVisible = window.settings.config.showFriendlyDependencies;
window.legend = legend;
@@ -263,7 +266,17 @@ function onSettingsSaved(defaultConfig = null) {
updateSettings(defaultConfig);
}
+ const networkView = document.getElementById("network--view");
+
window.addEventListener(EVENTS.SETTINGS_SAVED, async(event) => {
updateSettings(event.detail);
});
+
+ window.addEventListener(EVENTS.LOCKED, () => {
+ networkView.classList.add("locked");
+ });
+
+ window.addEventListener(EVENTS.UNLOCKED, () => {
+ networkView.classList.remove("locked");
+ });
}