MediaWiki:Common.js: відмінності між версіями

Віджет «Повідомити про правку» (krai-feedback)
(Back-лінк: над титульним блоком окремим рядком)
(Віджет «Повідомити про правку» (krai-feedback))
Рядок 358: Рядок 358:
   });
   });
});
});
/* === Країнопедія: віджет «Повідомити про правку» (krai-feedback) === */
mw.loader.using(["mediawiki.util"], function () {
  $(function () {
    if (mw.config.get("wgNamespaceNumber") !== 0) return;  // тільки статті
    if (mw.config.get("wgAction") !== "view") return;        // тільки читання
    if (document.getElementById("krai-fb-btn")) return;
    var ENDPOINT = "/feedback.php";
    var loadedAt = Math.floor(Date.now() / 1000);            // ts фіксуємо на завантаженні (>3с завжди)
    var overlay = null;
    var btn = document.createElement("button");
    btn.id = "krai-fb-btn";
    btn.type = "button";
    btn.className = "krai-fb-btn";
    btn.textContent = "✏️ Повідомити про правку";
    document.body.appendChild(btn);
    function buildModal() {
      overlay = document.createElement("div");
      overlay.className = "krai-fb-overlay";
      overlay.innerHTML =
        '<div class="krai-fb-modal" role="dialog" aria-modal="true" aria-labelledby="krai-fb-title">' +
          '<button type="button" class="krai-fb-close" aria-label="Закрити">×</button>' +
          '<h2 id="krai-fb-title" class="krai-fb-title">Повідомити про правку</h2>' +
          '<p class="krai-fb-sub">Помітили неточність або застарілі дані? Напишіть — ми перевіримо й оновимо. Дякуємо 💛</p>' +
          '<form class="krai-fb-form">' +
            '<div class="krai-fb-row krai-fb-kind">' +
              '<label><input type="radio" name="kind" value="fix" checked> Виправлення</label>' +
              '<label><input type="radio" name="kind" value="doubt"> Маю сумнів</label>' +
            '</div>' +
            '<label class="krai-fb-label">Цитата / фрагмент <span>(необов’язково)</span>' +
              '<textarea name="fragment" rows="2" placeholder="Місце, якого стосується правка"></textarea>' +
            '</label>' +
            '<label class="krai-fb-label">Що не так або що виправити?' +
              '<textarea name="comment" rows="4" placeholder="Опишіть коротко"></textarea>' +
            '</label>' +
            '<label class="krai-fb-label">Контакт <span>(необов’язково, якщо треба відповідь)</span>' +
              '<input type="text" name="contact" placeholder="Email або @Telegram"></label>' +
            '<input type="text" name="website" class="krai-fb-hp" tabindex="-1" autocomplete="off" aria-hidden="true">' +
            '<div class="krai-fb-actions">' +
              '<button type="button" class="krai-fb-cancel">Скасувати</button>' +
              '<button type="submit" class="krai-fb-submit">Надіслати</button>' +
            '</div>' +
            '<div class="krai-fb-msg" aria-live="polite"></div>' +
          '</form>' +
        '</div>';
      document.body.appendChild(overlay);
      overlay.addEventListener("click", function (e) { if (e.target === overlay) closeModal(); });
      overlay.querySelector(".krai-fb-close").addEventListener("click", closeModal);
      overlay.querySelector(".krai-fb-cancel").addEventListener("click", closeModal);
      overlay.querySelector(".krai-fb-form").addEventListener("submit", onSubmit);
    }
    function openModal() {
      if (!overlay) buildModal();
      var sel = ((window.getSelection && window.getSelection().toString()) || "").trim();
      if (sel) {
        var f = overlay.querySelector('textarea[name="fragment"]');
        if (f && !f.value) f.value = sel.slice(0, 1000);
      }
      overlay.classList.add("is-open");
      document.addEventListener("keydown", onEsc);
      var c = overlay.querySelector('textarea[name="comment"]');
      if (c) c.focus();
    }
    function closeModal() {
      if (overlay) overlay.classList.remove("is-open");
      document.removeEventListener("keydown", onEsc);
    }
    function onEsc(e) { if (e.key === "Escape") closeModal(); }
    function onSubmit(e) {
      e.preventDefault();
      var form = e.target;
      var msg = form.querySelector(".krai-fb-msg");
      var comment = form.comment.value.trim();
      var fragment = form.fragment.value.trim();
      if (comment.length < 5 && !fragment) {
        msg.className = "krai-fb-msg is-err";
        msg.textContent = "Напишіть, будь ласка, кілька слів про правку.";
        return;
      }
      var submitBtn = form.querySelector(".krai-fb-submit");
      submitBtn.disabled = true;
      msg.className = "krai-fb-msg";
      msg.textContent = "Надсилаю…";
      var data = new FormData();
      data.append("page", mw.config.get("wgPageName") || "");
      data.append("url", location.href);
      data.append("kind", (form.kind.value === "doubt") ? "doubt" : "fix");
      data.append("fragment", fragment);
      data.append("comment", comment);
      data.append("contact", form.contact.value.trim());
      data.append("website", form.website.value);
      data.append("ts", String(loadedAt));
      fetch(ENDPOINT, { method: "POST", body: data, credentials: "same-origin" })
        .then(function (r) { return r.json().catch(function () { return { ok: r.ok }; }); })
        .then(function (res) {
          if (res && res.ok) {
            form.reset();
            msg.className = "krai-fb-msg is-ok";
            msg.textContent = "Дякуємо! Ми перевіримо й оновимо. 💛";
            setTimeout(closeModal, 1800);
          } else {
            throw new Error((res && res.error) || "err");
          }
        })
        .catch(function () {
          msg.className = "krai-fb-msg is-err";
          msg.textContent = "Не вдалося надіслати. Спробуйте ще раз трохи згодом.";
        })
        .then(function () { submitBtn.disabled = false; });
    }
    btn.addEventListener("click", openModal);
  });
});
/* === /krai-feedback === */