Mudanças entre as edições de "Widget:Teste"

De Wiki Gla
Ir para navegação Ir para pesquisar
m (Página substituída por '<noinclude> <!-- GLA Wiki — Widget:ReportModal (Extension:Widgets) Cola isto na página Widget:ReportModal (conteúdo = HTML + parâmetros MediaWiki {{{...}...')
Etiqueta: Substituído
m
Linha 1: Linha 1:
<noinclude>
<noinclude>
   <!--
   <!--
   GLA Wiki — Widget:ReportModal (Extension:Widgets)
   GLA — Widget:ReportModal (Extension:Widgets)
  Cola isto na página [[Widget:ReportModal]] (conteúdo = HTML + parâmetros MediaWiki {{{...}}}).


   {{#widget:ReportModal|api_base=https://TEU_DEPLOY}}
   Cola **ISTO TUDO** em [[Widget:ReportModal]].
  A versão anterior (.html) estava **truncada** (id="gla-o-{{#widget:}}…") e:
  - quebrava o HTML da página inteira (tags abertas);
  - deixava o overlay visível sem `hidden` → fundo escuro em ecrã completo;
  - podia mostrar {{{...}}} sem expandir.


   Opcionais: |label=Texto do botão |wid=2
  Uso: {{#widget:ReportModal|api_base=https://TEU_DEPLOY}}
   Opcionais: |label=... |wid=2
 
  No servidor: REPORTS_CORS_ORIGINS com o origin da wiki.
-->
-->
</noinclude>
</noinclude>
<style id="gla-reports-widget-styles">
<div class="gla-report-widget-root" data-gla-api="{{{api_base|}}}" data-gla-label="{{{label|Reportar}}}"
   .gla-report-widget-root {
  data-gla-wid="{{{wid|1}}}"></div>
     display: inline-block;
<script>
     vertical-align: middle;
   /*<![CDATA[*/
  }
  (function () {
    "use strict";
    var roots = document.currentScript.previousElementSibling;
    if (!roots || !roots.classList || !roots.classList.contains("gla-report-widget-root")) {
      roots = document.querySelector(".gla-report-widget-root:not([data-gla-init])");
    }
    if (!roots || roots.getAttribute("data-gla-init")) return;
    roots.setAttribute("data-gla-init", "1");
 
    var REPORTS_API_BASE = (roots.getAttribute("data-gla-api") || "").replace(/\/$/, "");
     var BUTTON_LABEL = roots.getAttribute("data-gla-label") || "Reportar";
     var wid = String(roots.getAttribute("data-gla-wid") || "1").replace(/[^a-zA-Z0-9_-]/g, "");
 
    var MAX_TITLE = 60;
    var MAX_BYTES = 5 * 1024 * 1024;
 
    function esc(s) {
      var d = document.createElement("div");
      d.textContent = s == null ? "" : String(s);
      return d.innerHTML;
    }


  .gla-reports-overlay {
    function byId(id) {
    position: fixed;
      return document.getElementById(id);
    inset: 0;
     }
    background: rgba(0, 0, 0, 0.45);
     z-index: 2147483640;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
  }


  .gla-reports-overlay[hidden] {
    function css() {
    display: none !important;
      if (byId("gla-reports-modal-css-global")) return;
  }
      var st = document.createElement("style");
      st.id = "gla-reports-modal-css-global";
      st.textContent =
        ".gla-report-widget-root{display:inline-block;vertical-align:middle}" +
        ".gla-reports-overlay{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:2147483640;display:flex;align-items:center;justify-content:center;padding:16px}" +
        ".gla-reports-overlay[hidden]{display:none!important}" +
        ".gla-reports-modal-bx{max-width:480px;width:100%;max-height:90vh;overflow:auto;background:#111827;color:#f9fafb;border-radius:12px;padding:20px;font:14px/1.45 system-ui,sans-serif;box-shadow:0 24px 48px rgba(0,0,0,.4);border:1px solid #374151}" +
        ".gla-reports-modal-bx h2{font-size:1.1rem;margin:0 0 14px;color:#fff}" +
        ".gla-r-field{margin-bottom:12px}" +
        ".gla-r-field label{display:block;font-size:.8rem;color:#d1d5db;margin-bottom:4px}" +
        ".gla-r-field input[type=text],.gla-r-field select,.gla-r-field textarea{width:100%;box-sizing:border-box;border-radius:8px;border:1px solid #4b5563;background:#1f2937;color:#fff;padding:8px 10px;font:inherit}" +
        ".gla-r-field textarea{min-height:120px;resize:vertical}" +
        ".gla-r-actions{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}" +
        ".gla-r-actions button{border-radius:8px;padding:10px 16px;font:inherit;border:0;cursor:pointer}" +
        ".gla-r-primary{background:#6366f1;color:#fff}" +
        ".gla-r-secondary{background:#374151;color:#e5e7eb}" +
        ".gla-r-msg{margin-top:10px;font-size:.85rem;min-height:1.2em}" +
        ".gla-r-msg.ok{color:#6ee7b7}" +
        ".gla-r-msg.err{color:#fca5a5}" +
        ".gla-report-open-btn{font:inherit;cursor:pointer;border-radius:8px;padding:8px 14px;border:1px solid #4b5563;background:#1f2937;color:#e5e7eb}";
      document.head.appendChild(st);
    }


  .gla-reports-modal-bx {
    var oid = "gla-o-" + wid;
    max-width: 480px;
     var mid = "gla-m-" + wid;
     width: 100%;
    max-height: 90vh;
    overflow: auto;
    background: #111827;
    color: #f9fafb;
    border-radius: 12px;
    padding: 20px;
    font: 14px/1.45 system-ui, sans-serif;
    box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
    border: 1px solid #374151;
  }


  .gla-reports-modal-bx h2 {
    function buildModal(host) {
    font-size: 1.1rem;
      host.innerHTML =
    margin: 0 0 14px;
        '<div class="gla-reports-overlay" id="' +
    color: #fff;
        oid +
  }
        '" hidden role="presentation">' +
        '<div class="gla-reports-modal-bx" role="dialog" aria-modal="true" aria-labelledby="' +
        mid +
        '-t">' +
        '<h2 id="' +
        mid +
        '-t">' +
        esc("Report ou sugestão") +
        "</h2>" +
        '<form id="' +
        mid +
        '-f" novalidate>' +
        '<div class="gla-r-field"><label for="' +
        mid +
        '-title">Título <span style="opacity:.65">(até ' +
        MAX_TITLE +
        " caracteres)</span></label>" +
        '<input type="text" id="' +
        mid +
        '-title" name="name" maxlength="' +
        MAX_TITLE +
        '" placeholder="Opcional"/></div>' +
        '<div class="gla-r-field"><label for="' +
        mid +
        '-cat">Categoria</label>' +
        '<select id="' +
        mid +
        '-cat" name="category" required>' +
        '<option value="report">' +
        esc("Report") +
        "</option>" +
        '<option value="suggestion">' +
        esc("Sugestão") +
        "</option>" +
        "</select></div>" +
        '<div class="gla-r-field"><label for="' +
        mid +
        '-desc">Descrição <span style="color:#fca5a5">*</span></label>' +
        '<textarea id="' +
        mid +
        '-desc" name="description" maxlength="8000" required placeholder="Descrição detalhada"></textarea></div>' +
        '<div class="gla-r-field"><label for="' +
        mid +
        '-img">Imagem (opcional)</label>' +
        '<input type="file" id="' +
        mid +
        '-img" accept="image/png,image/jpeg,image/gif"/></div>' +
        '<div class="gla-r-actions">' +
        '<button type="submit" class="gla-r-primary" id="' +
        mid +
        '-send">' +
        esc("Enviar") +
        "</button>" +
        '<button type="button" class="gla-r-secondary" id="' +
        mid +
        '-cancel">' +
        esc("Fechar") +
        "</button></div>" +
        '<p class="gla-r-msg" id="' +
        mid +
        '-msg"></p>' +
        "</form>" +
        "</div></div>";
    }


  .gla-r-field {
    function openModal(overlay) {
    margin-bottom: 12px;
      overlay.removeAttribute("hidden");
  }
      var t = byId(mid + "-title");
      if (t) t.focus();
    }


  .gla-r-field label {
    function closeModal(overlay) {
    display: block;
      overlay.setAttribute("hidden", "");
    font-size: 0.8rem;
      var m = byId(mid + "-msg");
    color: #d1d5db;
      if (m) {
    margin-bottom: 4px;
        m.textContent = "";
  }
        m.className = "gla-r-msg";
      }
    }


  .gla-r-field input[type="text"],
     css();
  .gla-r-field select,
  .gla-r-field textarea {
     width: 100%;
    box-sizing: border-box;
    border-radius: 8px;
    border: 1px solid #4b5563;
    background: #1f2937;
    color: #fff;
    padding: 8px 10px;
    font: inherit;
  }


  .gla-r-field textarea {
    var btn = document.createElement("button");
     min-height: 120px;
    btn.type = "button";
     resize: vertical;
    btn.className = "gla-report-open-btn";
  }
     btn.textContent = BUTTON_LABEL;
     roots.appendChild(btn);


  .gla-r-actions {
    var modalHost = document.createElement("div");
    display: flex;
     roots.appendChild(modalHost);
     gap: 8px;
     buildModal(modalHost);
    margin-top: 16px;
     flex-wrap: wrap;
  }


  .gla-r-actions button {
     var overlay = byId(oid);
     border-radius: 8px;
     var form = byId(mid + "-f");
     padding: 10px 16px;
     var btnCancel = byId(mid + "-cancel");
     font: inherit;
     var btnSend = byId(mid + "-send");
     border: 0;
     var msg = byId(mid + "-msg");
     cursor: pointer;
  }


  .gla-r-primary {
    if (!REPORTS_API_BASE) {
    background: #6366f1;
      btn.disabled = true;
    color: #fff;
      btn.title = "Define api_base no widget (api_base=https://...)";
  }
      return;
    }


  .gla-r-secondary {
    btn.addEventListener("click", function () {
     background: #374151;
      openModal(overlay);
     color: #e5e7eb;
    });
  }
    btnCancel.addEventListener("click", function () {
      closeModal(overlay);
     });
     overlay.addEventListener("click", function (e) {
      if (e.target === overlay) closeModal(overlay);
    });


  .gla-r-msg {
    form.addEventListener("submit", function (e) {
    margin-top: 10px;
      e.preventDefault();
    font-size: 0.85rem;
      var title = (byId(mid + "-title").value || "").trim();
    min-height: 1.2em;
      var cat = byId(mid + "-cat").value;
  }
      var desc = (byId(mid + "-desc").value || "").trim();
      var fileIn = byId(mid + "-img");


  .gla-r-msg.gla-r-ok {
      msg.textContent = "";
    color: #6ee7b7;
      msg.className = "gla-r-msg";
  }


  .gla-r-msg.gla-r-err {
      if (!desc) {
    color: #fca5a5;
        msg.textContent = "Preencha a descrição.";
  }
        msg.className = "gla-r-msg err";
        return;
      }
      if (title.length > MAX_TITLE) {
        msg.textContent = "Título muito longo.";
        msg.className = "gla-r-msg err";
        return;
      }


  .gla-report-open-btn {
      var fd = new FormData();
    font: inherit;
      if (title) fd.append("name", title);
    cursor: pointer;
      fd.append("category", cat);
    border-radius: 8px;
      fd.append("description", desc);
    padding: 8px 14px;
      if (fileIn.files && fileIn.files[0]) {
    border: 1px solid #4b5563;
        var f = fileIn.files[0];
    background: #1f2937;
        if (f.size > MAX_BYTES) {
    color: #e5e7eb;
          msg.textContent = "Imagem acima de 5 MB.";
  }
          msg.className = "gla-r-msg err";
</style>
          return;
        }
        if (!/^image\/(png|jpeg|gif)$/i.test(f.type)) {
          msg.textContent = "Só PNG, JPG ou GIF.";
          msg.className = "gla-r-msg err";
          return;
        }
        fd.append("image", f);
      }


<div class="gla-report-widget-root" data-gla-init="0" data-gla-api="{{{api_base|}}}" data-gla-wid="{{{wid|1}}}">
      btnSend.disabled = true;
  <button type="button" class="gla-report-open-btn">
      var url = REPORTS_API_BASE + "/api/reports";
    {{{label|Reportar}}}
  </button>


  <div class="gla-reports-overlay" id="gla-o-{{#widget:}}</div>
      fetch(url, { method: "POST", body: fd })
        .then(function (r) {
          return r
            .json()
            .catch(function () {
              return {};
            })
            .then(function (j) {
              return { ok: r.ok, status: r.status, body: j };
            });
        })
        .then(function (result) {
          if (result.ok) {
            msg.textContent = "Enviado. Obrigado!";
            msg.className = "gla-r-msg ok";
            form.reset();
            setTimeout(function () {
              closeModal(overlay);
            }, 1500);
          } else {
            msg.textContent =
              (result.body && result.body.error) || "Erro " + result.status;
            msg.className = "gla-r-msg err";
          }
        })
        .catch(function () {
          msg.textContent =
            "Rede ou CORS: confirma api_base e REPORTS_CORS_ORIGINS no servidor.";
          msg.className = "gla-r-msg err";
        })
        .then(function () {
          btnSend.disabled = false;
        });
    });
  })();
  /*]]>*/
</script>

Edição das 16h03min de 28 de abril de 2026


<script>

 /*<![CDATA[*/
 (function () {
   "use strict";
   var roots = document.currentScript.previousElementSibling;
   if (!roots || !roots.classList || !roots.classList.contains("gla-report-widget-root")) {
     roots = document.querySelector(".gla-report-widget-root:not([data-gla-init])");
   }
   if (!roots || roots.getAttribute("data-gla-init")) return;
   roots.setAttribute("data-gla-init", "1");
   var REPORTS_API_BASE = (roots.getAttribute("data-gla-api") || "").replace(/\/$/, "");
   var BUTTON_LABEL = roots.getAttribute("data-gla-label") || "Reportar";
   var wid = String(roots.getAttribute("data-gla-wid") || "1").replace(/[^a-zA-Z0-9_-]/g, "");
   var MAX_TITLE = 60;
   var MAX_BYTES = 5 * 1024 * 1024;
   function esc(s) {
     var d = document.createElement("div");
     d.textContent = s == null ? "" : String(s);
     return d.innerHTML;
   }
   function byId(id) {
     return document.getElementById(id);
   }
   function css() {
     if (byId("gla-reports-modal-css-global")) return;
     var st = document.createElement("style");
     st.id = "gla-reports-modal-css-global";
     st.textContent =
       ".gla-report-widget-root{display:inline-block;vertical-align:middle}" +
       ".gla-reports-overlay{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:2147483640;display:flex;align-items:center;justify-content:center;padding:16px}" +
       ".gla-reports-overlay[hidden]{display:none!important}" +
       ".gla-reports-modal-bx{max-width:480px;width:100%;max-height:90vh;overflow:auto;background:#111827;color:#f9fafb;border-radius:12px;padding:20px;font:14px/1.45 system-ui,sans-serif;box-shadow:0 24px 48px rgba(0,0,0,.4);border:1px solid #374151}" +
       ".gla-reports-modal-bx h2{font-size:1.1rem;margin:0 0 14px;color:#fff}" +
       ".gla-r-field{margin-bottom:12px}" +
       ".gla-r-field label{display:block;font-size:.8rem;color:#d1d5db;margin-bottom:4px}" +
       ".gla-r-field input[type=text],.gla-r-field select,.gla-r-field textarea{width:100%;box-sizing:border-box;border-radius:8px;border:1px solid #4b5563;background:#1f2937;color:#fff;padding:8px 10px;font:inherit}" +
       ".gla-r-field textarea{min-height:120px;resize:vertical}" +
       ".gla-r-actions{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}" +
       ".gla-r-actions button{border-radius:8px;padding:10px 16px;font:inherit;border:0;cursor:pointer}" +
       ".gla-r-primary{background:#6366f1;color:#fff}" +
       ".gla-r-secondary{background:#374151;color:#e5e7eb}" +
       ".gla-r-msg{margin-top:10px;font-size:.85rem;min-height:1.2em}" +
       ".gla-r-msg.ok{color:#6ee7b7}" +
       ".gla-r-msg.err{color:#fca5a5}" +
       ".gla-report-open-btn{font:inherit;cursor:pointer;border-radius:8px;padding:8px 14px;border:1px solid #4b5563;background:#1f2937;color:#e5e7eb}";
     document.head.appendChild(st);
   }
   var oid = "gla-o-" + wid;
   var mid = "gla-m-" + wid;
   function buildModal(host) {
     host.innerHTML =

'

";

   }
   function openModal(overlay) {
     overlay.removeAttribute("hidden");
     var t = byId(mid + "-title");
     if (t) t.focus();
   }
   function closeModal(overlay) {
     overlay.setAttribute("hidden", "");
     var m = byId(mid + "-msg");
     if (m) {
       m.textContent = "";
       m.className = "gla-r-msg";
     }
   }
   css();
   var btn = document.createElement("button");
   btn.type = "button";
   btn.className = "gla-report-open-btn";
   btn.textContent = BUTTON_LABEL;
   roots.appendChild(btn);
   var modalHost = document.createElement("div");
   roots.appendChild(modalHost);
   buildModal(modalHost);
   var overlay = byId(oid);
   var form = byId(mid + "-f");
   var btnCancel = byId(mid + "-cancel");
   var btnSend = byId(mid + "-send");
   var msg = byId(mid + "-msg");
   if (!REPORTS_API_BASE) {
     btn.disabled = true;
     btn.title = "Define api_base no widget (api_base=https://...)";
     return;
   }
   btn.addEventListener("click", function () {
     openModal(overlay);
   });
   btnCancel.addEventListener("click", function () {
     closeModal(overlay);
   });
   overlay.addEventListener("click", function (e) {
     if (e.target === overlay) closeModal(overlay);
   });
   form.addEventListener("submit", function (e) {
     e.preventDefault();
     var title = (byId(mid + "-title").value || "").trim();
     var cat = byId(mid + "-cat").value;
     var desc = (byId(mid + "-desc").value || "").trim();
     var fileIn = byId(mid + "-img");
     msg.textContent = "";
     msg.className = "gla-r-msg";
     if (!desc) {
       msg.textContent = "Preencha a descrição.";
       msg.className = "gla-r-msg err";
       return;
     }
     if (title.length > MAX_TITLE) {
       msg.textContent = "Título muito longo.";
       msg.className = "gla-r-msg err";
       return;
     }
     var fd = new FormData();
     if (title) fd.append("name", title);
     fd.append("category", cat);
     fd.append("description", desc);
     if (fileIn.files && fileIn.files[0]) {
       var f = fileIn.files[0];
       if (f.size > MAX_BYTES) {
         msg.textContent = "Imagem acima de 5 MB.";
         msg.className = "gla-r-msg err";
         return;
       }
       if (!/^image\/(png|jpeg|gif)$/i.test(f.type)) {
         msg.textContent = "Só PNG, JPG ou GIF.";
         msg.className = "gla-r-msg err";
         return;
       }
       fd.append("image", f);
     }
     btnSend.disabled = true;
     var url = REPORTS_API_BASE + "/api/reports";
     fetch(url, { method: "POST", body: fd })
       .then(function (r) {
         return r
           .json()
           .catch(function () {
             return {};
           })
           .then(function (j) {
             return { ok: r.ok, status: r.status, body: j };
           });
       })
       .then(function (result) {
         if (result.ok) {
           msg.textContent = "Enviado. Obrigado!";
           msg.className = "gla-r-msg ok";
           form.reset();
           setTimeout(function () {
             closeModal(overlay);
           }, 1500);
         } else {
           msg.textContent =
             (result.body && result.body.error) || "Erro " + result.status;
           msg.className = "gla-r-msg err";
         }
       })
       .catch(function () {
         msg.textContent =
           "Rede ou CORS: confirma api_base e REPORTS_CORS_ORIGINS no servidor.";
         msg.className = "gla-r-msg err";
       })
       .then(function () {
         btnSend.disabled = false;
       });
   });
 })();
 /*]]>*/

</script>