Enhance IP address tooltip and add Ctrl+Click functionality for scanning
This commit is contained in:
@@ -147,18 +147,128 @@ Vue.component('radius-processing-indicator', {
|
||||
|
||||
/* ---------- Online state chip (fetches radacct when visible) ---------- */
|
||||
Vue.component('radius-online-state', {
|
||||
props: { username: String }, data: () => ({ data: null, observed: false, ob: null }),
|
||||
props: { username: String },
|
||||
data: () => ({
|
||||
data: null,
|
||||
observed: false,
|
||||
ob: null,
|
||||
isHovering: false,
|
||||
ctrlPressed: false,
|
||||
tooltipText: 'IP-Adresse kopieren'
|
||||
}),
|
||||
template: `
|
||||
<div class="radius-scope ros-wrap" ref="root">
|
||||
<template v-if="data===null"><span class="ros-chip skeleton"><span class="dot"></span><span class="skeleton-line" style="width: 80px; height: 18px; margin: auto;"></span></span></template>
|
||||
<template v-else-if="data!==null"><span class="ros-chip" :class="[data.online ? 'on' : 'off', {'is-clickable': data.ip}]" :data-tooltip="data.ip ? 'IP-Adresse kopieren' : null" @click="copyIp($event)"><span class="dot"></span><span class="ip">{{ data.ip || '—' }}</span></span></template>
|
||||
<template v-if="data===null">
|
||||
<span class="ros-chip skeleton"><span class="dot"></span><span class="skeleton-line" style="width: 80px; height: 18px; margin: auto;"></span></span>
|
||||
</template>
|
||||
<template v-else-if="data!==null">
|
||||
<span class="ros-chip"
|
||||
:class="[data.online ? 'on' : 'off', {'is-clickable': data.ip}]"
|
||||
:data-tooltip="tooltipText"
|
||||
@click="onClickIp"
|
||||
@mouseover="onIpMouseOver"
|
||||
@mouseout="onIpMouseOut"
|
||||
>
|
||||
<span class="dot"></span>
|
||||
<span class="ip">{{ data.ip || '—' }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
`,
|
||||
mounted() { this.ob = new IntersectionObserver((en) => { if (en[0].isIntersecting && !this.observed) { this.observed = true; this.fetchState(); } }, { threshold: 0.1 }); if (this.$refs.root) this.ob.observe(this.$refs.root); },
|
||||
beforeDestroy() { this.ob?.disconnect(); },
|
||||
watch: {
|
||||
data(newData) {
|
||||
// Update tooltip text when data is loaded
|
||||
if (newData && newData.ip) {
|
||||
this.tooltipText = 'IP-Adresse kopieren';
|
||||
} else {
|
||||
this.tooltipText = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.ob = new IntersectionObserver((en) => { if (en[0].isIntersecting && !this.observed) { this.observed = true; this.fetchState(); } }, { threshold: 0.1 });
|
||||
if (this.$refs.root) this.ob.observe(this.$refs.root);
|
||||
// Listen for Ctrl/Meta key presses globally
|
||||
document.addEventListener('keydown', this.handleKey);
|
||||
document.addEventListener('keyup', this.handleKey);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.ob?.disconnect();
|
||||
// Clean up global listeners
|
||||
document.removeEventListener('keydown', this.handleKey);
|
||||
document.removeEventListener('keyup', this.handleKey);
|
||||
},
|
||||
methods: {
|
||||
async fetchState() { try { const r = await fetch(`${window.TT_CONFIG['BASE_PATH']}/Radius/proxyUnsecureHTTPRequestToRadius?action2=fetchRadacct&username=${encodeURIComponent(this.username)}`); this.data = r.ok ? await r.json() : { online: false, ip: null }; } catch { this.data = { online: false, ip: null }; } },
|
||||
async copyIp(event) { if (!this.data?.ip) return; const c = event.currentTarget; if (!c || c.classList.contains('is-copied')) return; await window.RadiusUtils.copyToClipboard(this.data.ip); c.classList.add('is-copied'); const o = c.dataset.tooltip; if (o) c.dataset.tooltip = 'Kopiert!'; setTimeout(() => { c.classList.remove('is-copied'); if (o) c.dataset.tooltip = o; }, 1500); }
|
||||
async fetchState() {
|
||||
try {
|
||||
const r = await fetch(`${window.TT_CONFIG['BASE_PATH']}/Radius/proxyUnsecureHTTPRequestToRadius?action2=fetchRadacct&username=${encodeURIComponent(this.username)}`);
|
||||
this.data = r.ok ? await r.json() : { online: false, ip: null };
|
||||
} catch {
|
||||
this.data = { online: false, ip: null };
|
||||
}
|
||||
},
|
||||
async copyIp(event) {
|
||||
if (!this.data?.ip) return;
|
||||
const c = event.currentTarget;
|
||||
if (!c || c.classList.contains('is-copied')) return;
|
||||
await window.RadiusUtils.copyToClipboard(this.data.ip);
|
||||
c.classList.add('is-copied');
|
||||
|
||||
// Temporarily change tooltip to "Kopiert!"
|
||||
const originalTooltip = this.tooltipText;
|
||||
this.tooltipText = 'Kopiert!';
|
||||
|
||||
setTimeout(() => {
|
||||
c.classList.remove('is-copied');
|
||||
// Restore original tooltip
|
||||
this.tooltipText = originalTooltip;
|
||||
// Re-run updateTooltip in case Ctrl is still pressed
|
||||
this.updateTooltip();
|
||||
}, 1500);
|
||||
},
|
||||
// --- New methods for Ctrl+Click ---
|
||||
handleKey(event) {
|
||||
const newCtrlPressed = event.ctrlKey || event.metaKey;
|
||||
if (newCtrlPressed !== this.ctrlPressed) {
|
||||
this.ctrlPressed = newCtrlPressed;
|
||||
// If hovering, update tooltip live
|
||||
if (this.isHovering) {
|
||||
this.updateTooltip();
|
||||
}
|
||||
}
|
||||
},
|
||||
onIpMouseOver(event) {
|
||||
this.isHovering = true;
|
||||
this.ctrlPressed = event.ctrlKey || event.metaKey;
|
||||
this.updateTooltip();
|
||||
},
|
||||
onIpMouseOut() {
|
||||
this.isHovering = false;
|
||||
this.ctrlPressed = false; // Reset on mouse out
|
||||
this.updateTooltip();
|
||||
},
|
||||
updateTooltip() {
|
||||
if (!this.data?.ip) {
|
||||
this.tooltipText = null;
|
||||
} else if (this.isHovering && this.ctrlPressed) {
|
||||
this.tooltipText = 'Scan starten & verbinden';
|
||||
} else {
|
||||
this.tooltipText = 'IP-Adresse kopieren';
|
||||
}
|
||||
},
|
||||
onClickIp(event) {
|
||||
if (!this.data?.ip) return;
|
||||
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
// Ctrl+Click or Meta+Click
|
||||
event.preventDefault();
|
||||
this.$emit('scan-ip', { ip: this.data.ip });
|
||||
} else {
|
||||
// Normal click
|
||||
this.copyIp(event);
|
||||
}
|
||||
}
|
||||
// --- End new methods ---
|
||||
}
|
||||
});
|
||||
|
||||
@@ -247,4 +357,4 @@ Vue.component('radius', {
|
||||
methods: {
|
||||
switchView(v){ this.view=v; if(!this._initFlags||this._initFlags[v])return; let r=''; if(v==='free')r='freeView';else if(v==='unused')r='unusedView'; if(r){this.$nextTick(()=>{const c=this.$refs[r];if(c&&typeof c.initIfNeeded==='function'){c.initIfNeeded();this._initFlags[v]=true;}});}}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user