Skip to content
quarry Artifact [a679f95cb4]
Login

Artifact [a679f95cb4]

Artifact a679f95cb4feca58c73fdc13b7de33fc98e34ca6f29bc904673be2c0de37534e:


// The new-ticket form's keyboard. Everything here is a shortcut for
// something the form already does without script: submit is the
// button, "open and start another" is the checkbox, a chip is a
// native select a Tab reaches and a letter types into.
(function () {
  "use strict";
  var form = document.querySelector("form[data-hook=ticket-new]");
  if (!form) return;

  function typing(el) {
    if (!el) return false;
    var t = el.tagName;
    return t === "INPUT" || t === "TEXTAREA" || t === "SELECT" || el.isContentEditable;
  }

  // Cmd/Ctrl+Enter files the ticket from anywhere in the form;
  // with Shift it files and comes back for the next one.
  form.addEventListener("keydown", function (e) {
    if (e.key !== "Enter" || !(e.metaKey || e.ctrlKey)) return;
    e.preventDefault();
    var more = form.querySelector("input[name=another]");
    if (more && e.shiftKey) more.checked = true;
    if (form.requestSubmit) form.requestSubmit(); else form.submit();
  });

  // Inside a focused chip, a digit picks that word: 1 is the first word
  // the tracker lists, so the order on screen is the order of the keys.
  form.addEventListener("keydown", function (e) {
    var sel = e.target;
    if (!sel || sel.tagName !== "SELECT" || !sel.closest(".chip")) return;
    if (e.metaKey || e.ctrlKey || e.altKey || !/^[1-9]$/.test(e.key)) return;
    var words = Array.prototype.filter.call(sel.options, function (o) {
      return o.value !== "" && o.value !== "__new";
    });
    var pick = words[Number(e.key) - 1];
    if (!pick) return;
    e.preventDefault();
    sel.value = pick.value;
    sel.dispatchEvent(new Event("change", { bubbles: true }));
  });

  // Choosing a type brings its template into the description — but only
  // into one the reporter has not written in: empty, or still exactly
  // some template. Words somebody typed are never replaced.
  function template(type) {
    var el = form.querySelector('template[data-tn-template="' + (window.CSS && CSS.escape ? CSS.escape(type) : type) + '"]') ||
      form.querySelector('template[data-tn-template=""]');
    return el ? el.content.textContent : "";
  }
  function untouched(text) {
    var t = text.trim();
    if (t === "") return true;
    return Array.prototype.some.call(form.querySelectorAll("template[data-tn-template]"), function (el) {
      return el.content.textContent.trim() === t;
    });
  }
  form.addEventListener("change", function (e) {
    if (!e.target || e.target.name !== "type") return;
    var box = form.querySelector("textarea[name=comment]");
    if (!box || !untouched(box.value)) return;
    box.value = template(e.target.value);
    box.dispatchEvent(new Event("input", { bubbles: true }));
  });

  // A letter outside any text box moves to its chip: S status,
  // V severity, P priority, U subsystem. Only on this page, only when
  // nothing is being typed, and never with a modifier held.
  var keys = { s: "status", v: "severity", p: "priority", u: "subsystem" };
  document.addEventListener("keydown", function (e) {
    if (e.metaKey || e.ctrlKey || e.altKey || typing(document.activeElement)) return;
    var name = keys[e.key];
    if (!name) return;
    var sel = form.querySelector(".chip select[name=" + name + "]");
    if (!sel) return;
    e.preventDefault();
    sel.focus();
  });
})();