App-Netdisco
view release on metacpan or search on metacpan
share/public/javascripts/netdisco-portcontrol.js view on Meta::CPAN
td.blur();
});
}
/**
* Opens the confirmation modal for a VLAN change, saving the port once the
* user dismisses it.
* @param {HTMLElement} cell the contenteditable cell holding the new VLAN
* @returns {void}
*/
function confirmPvidChange(cell) {
var modal = document.getElementById('nd_portlog');
if (!(modal instanceof HTMLElement)) return;
modal.addEventListener('hidden.bs.modal', function() {
port_control(cell); // save
}, { once: true });
bootstrap.Modal.getOrCreateInstance(modal).show();
}
/**
* Turns an edited ACL rule label into a hidden field the admin form
* submits, then presses the row's own update button.
* @param {HTMLInputElement} cell the contenteditable field holding the rule label
* @param {HTMLElement} td the containing editable cell
* @param {string} className the hidden input's class, left or right
* @param {string} inputName the hidden input's form field name, left or right
* @returns {boolean} whether the field was promoted. An empty field promotes
* nothing, and the caller must return without its usual cleanup in that
* case, matching the original guard that returned from the whole keydown
* handler rather than only from this step.
*/
function promoteAclRuleField(cell, td, className, inputName) {
if (cell.value.length == 0) return false;
var input = document.createElement('input');
input.className = className;
input.dataset.form = 'update';
input.name = inputName;
input.type = 'hidden';
input.value = Math.floor( Date.now() / 1000 ) + '.' + window.btoa(cell.value);
td.appendChild(input);
var row = cell.closest('tr');
var button = row && row.querySelector('button.nd_adminbutton[name="update"]');
if (button instanceof HTMLElement) button.click();
return true;
}
// on load, establish global delegations for now and future
document.addEventListener('DOMContentLoaded', function() {
// for growl-like functionality, check for notifications periodically
if (nd_check_userlog) {
(function worker() {
ndRequest.getJSON(uri_base + '/ajax/userlog')
.then(function(data) {
for (var i = 0; i < data['error'].length; i++) {
ndToast.error(data['error'][i], 'Failed Job:');
}
for (i = 0; i < data['done'].length; i++) {
ndToast.success(data['done'][i], 'Successful Job:');
}
// Schedule next request when the current one's complete
setTimeout(worker, 5000);
})
.catch(function() {
// after failure, try less often
setTimeout(worker, 60000);
});
})();
}
// Cast once: querySelectorAll's own return type carries only Element, and
// that leaves every event registered below untyped for its listener too.
var tabContents = /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.tab-content'));
// toggle visibility of port up/down and edit controls
tabContents.forEach(function (root) {
root.addEventListener('mouseenter', function (event) {
var t = targetClosest(event, '.nd_editable-cell');
// Native mouseenter/mouseleave fire separately at every ancestor whose
// own boundary the pointer crossed, not just the delegate match, so a
// move between the cell's own icon children must not retrigger this.
if (!t || !root.contains(t) || event.target !== t) return;
var hand = queryElement(t, ':scope > .nd_hand-icon');
if (hand) hand.style.display = 'inline';
if (document.activeElement !== t) {
var edit = queryElement(t, ':scope > .nd_edit-icon'); // ports
if (edit) edit.style.display = 'inline';
var row = t.closest('tr');
if (row) row.querySelectorAll('.nd_device-details-edit').forEach(function (el) { if (el instanceof HTMLElement) el.style.display = 'inline' }); // details
}
}, true);
});
tabContents.forEach(function (root) {
root.addEventListener('mouseleave', function (event) {
var t = targetClosest(event, '.nd_editable-cell');
// Same crossed-boundary reasoning as the mouseenter handler above: a
// move between the cell's own icon children must not hide them.
if (!t || !root.contains(t) || event.target !== t) return;
hideWithTooltip(t.querySelector(':scope > .nd_hand-icon'));
if (document.activeElement !== t) {
var edit = queryElement(t, ':scope > .nd_edit-icon'); // ports
if (edit) edit.style.display = 'none';
var row = t.closest('tr');
if (row) row.querySelectorAll('.nd_device-details-edit').forEach(function (el) { if (el instanceof HTMLElement) el.style.display = 'none' }); // details
}
}, true);
});
tabContents.forEach(function (root) {
root.addEventListener('focus', function (event) {
var t = targetClosest(event, '[contenteditable=true]');
if (!t || !root.contains(t)) return;
var edit = queryElement(t, ':scope > .nd_edit-icon'); // ports
if (edit) edit.style.display = 'none';
var row = t.closest('tr');
if (row) row.querySelectorAll('.nd_device-details-edit').forEach(function (el) { if (el instanceof HTMLElement) el.style.display = 'none' }); // details
}, true);
});
// to tell whether bootstrap's modal had Submit button pressed :(
const portsPane = document.getElementById('ports_pane');
if (portsPane) {
portsPane.addEventListener('click', function (event) {
var t = targetClosest(event, '#nd_portlog-submit');
if (!t || !portsPane.contains(t)) return;
nd_save_ok = true;
});
( run in 4.171 seconds using v1.01-cache-2.11-cpan-85d3896f969 )