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 )