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
 
(Uma revisão intermediária pelo mesmo usuário não está sendo mostrada)
Linha 1: Linha 1:
<noinclude>
<noinclude>
   <!--
   <!--
   GLA Wiki — Widget:ReportModal (Extension:Widgets)
   Widget:ReportModal — formulário embutido no corpo da página (sem overlay, sem botão extra).
  Cola isto na página [[Widget:ReportModal]] (conteúdo = HTML + parâmetros MediaWiki {{{...}}}).


   {{#widget:ReportModal|api_base=https://TEU_DEPLOY}}
   {{#widget:ReportModal|api_base=https://TEU_DEPLOY}}


   Opcionais: |label=Texto do botão |wid=2
   Opcionais:
    |wid=2      — vários widgets na mesma página (ids únicos)
    |heading=  — título da caixa (vazio → "Report ou sugestão")
 
  No servidor: REPORTS_CORS_ORIGINS=https://wiki.gla.com.br
-->
-->
</noinclude>
</noinclude>
<style id="gla-reports-widget-styles">
<div class="gla-report-widget-root" data-gla-init="0" data-gla-api="{{{api_base|}}}" data-gla-wid="{{{wid|1}}}"
  .gla-report-widget-root {
  data-gla-heading="{{{heading|}}}"></div>
    display: inline-block;
<script>
     vertical-align: middle;
  /*<![CDATA[*/
  }
  (function () {
     "use strict";


  .gla-reports-overlay {
    var roots = document.currentScript.previousElementSibling;
    position: fixed;
    if (!roots || !roots.classList || !roots.classList.contains("gla-report-widget-root")) {
     inset: 0;
      roots = document.querySelector(".gla-report-widget-root:not([data-gla-init])");
     background: rgba(0, 0, 0, 0.45);
     }
     z-index: 2147483640;
     if (!roots || roots.getAttribute("data-gla-init")) return;
    display: flex;
     roots.setAttribute("data-gla-init", "1");
    align-items: center;
    justify-content: center;
    padding: 16px;
  }


  .gla-reports-overlay[hidden] {
    var REPORTS_API_BASE = (roots.getAttribute("data-gla-api") || "").replace(/\/$/, "");
     display: none !important;
    var wid = String(roots.getAttribute("data-gla-wid") || "1").replace(/[^a-zA-Z0-9_-]/g, "");
  }
     var HEADING = roots.getAttribute("data-gla-heading") || "";
    if (!HEADING) HEADING = "Report ou sugestão";


  .gla-reports-modal-bx {
     var MAX_TITLE = 60;
    max-width: 480px;
     var MAX_BYTES = 5 * 1024 * 1024;
    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 esc(s) {
    font-size: 1.1rem;
      var d = document.createElement("div");
    margin: 0 0 14px;
      d.textContent = s == null ? "" : String(s);
    color: #fff;
      return d.innerHTML;
  }
    }


  .gla-r-field {
    function byId(id) {
    margin-bottom: 12px;
      return document.getElementById(id);
  }
    }


  .gla-r-field label {
    function css() {
    display: block;
      if (byId("gla-reports-inline-css-global")) return;
    font-size: 0.8rem;
      var st = document.createElement("style");
    color: #d1d5db;
      st.id = "gla-reports-inline-css-global";
    margin-bottom: 4px;
      st.textContent =
  }
        ".gla-report-widget-root{width:100%;max-width:520px;margin:1rem 0;display:block;clear:both}" +
        ".gla-reports-inline{max-width:100%;box-sizing:border-box;background:#111827;color:#f9fafb;border-radius:12px;padding:18px 20px;font:14px/1.45 system-ui,sans-serif;border:1px solid #374151;box-shadow:0 8px 24px rgba(0,0,0,.15)}" +
        ".gla-reports-inline-h2{font-size:1.1rem;margin:0 0 14px;color:#fff;font-weight:600}" +
        ".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;align-items:center}" +
        ".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-muted{background:#374151;color:#e5e7eb}" +
        ".gla-r-msg{margin-top:12px;font-size:.85rem;min-height:1.2em}" +
        ".gla-r-msg.gla-r-ok{color:#6ee7b7}" +
        ".gla-r-msg.gla-r-err{color:#fca5a5}";
      document.head.appendChild(st);
    }


  .gla-r-field input[type="text"],
    var mid = "gla-form-" + wid;
  .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 {
    function buildFormBody() {
    min-height: 120px;
      return (
     resize: vertical;
        '<section class="gla-reports-inline" aria-labelledby="' +
  }
        mid +
        '-tit">' +
        '<h2 class="gla-reports-inline-h2" id="' +
        mid +
        '-tit">' +
        esc(HEADING) +
        "</h2>" +
        '<form id="' +
        mid +
        '-f" novalidate>' +
        '<div class="gla-r-field"><label for="' +
        mid +
        '-title">Título <span style="opacity:.65">(opcional, até ' +
        MAX_TITLE +
        " caracteres)</span></label>" +
        '<input type="text" id="' +
        mid +
        '-title" name="name" maxlength="' +
        MAX_TITLE +
        '" autocomplete="off" placeholder="Ex.: erro na página X"/></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="reset" class="gla-r-muted" id="' +
        mid +
        '-reset">' +
        esc("Limpar") +
        "</button></div>" +
        '<p class="gla-r-msg" id="' +
        mid +
        '-msg" role="status"></p>' +
        "</form></section>"
      );
     }


  .gla-r-actions {
    function localFileOk(f) {
    display: flex;
      var t = (f.type || "").toLowerCase();
    gap: 8px;
      var n = (f.name || "").toLowerCase();
    margin-top: 16px;
      if (/^image\/(png|jpeg|gif)$/.test(t)) return true;
    flex-wrap: wrap;
      if (/\.(png|jpe?g|gif)$/.test(n)) return true;
  }
      return false;
    }


  .gla-r-actions button {
     css();
     border-radius: 8px;
     roots.innerHTML = buildFormBody();
     padding: 10px 16px;
    font: inherit;
    border: 0;
    cursor: pointer;
  }


  .gla-r-primary {
    var form = byId(mid + "-f");
     background: #6366f1;
     var btnSend = byId(mid + "-send");
     color: #fff;
     var msg = byId(mid + "-msg");
  }


  .gla-r-secondary {
    if (!REPORTS_API_BASE) {
    background: #374151;
      if (btnSend) btnSend.disabled = true;
     color: #e5e7eb;
      if (msg) {
  }
        msg.textContent = "Configura api_base na wiki: api_base=https://…";
        msg.className = "gla-r-msg gla-r-err";
      }
      return;
     }


  .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 gla-r-err";
        return;
      }
      if (title.length > MAX_TITLE) {
        msg.textContent = "Título longo demais.";
        msg.className = "gla-r-msg gla-r-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 gla-r-err";
</style>
          return;
        }
        if (!localFileOk(f)) {
          msg.textContent = "Só PNG, JPG ou GIF.";
          msg.className = "gla-r-msg gla-r-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.text().then(function (text) {
            var body = {};
            try {
              body = text ? JSON.parse(text) : {};
            } catch (ignore) {
              body = { _raw: text };
            }
            return { ok: r.ok, status: r.status, body: body, raw: text };
          });
        })
        .then(function (result) {
          if (result.ok) {
            msg.textContent = "Enviado. Obrigado!";
            msg.className = "gla-r-msg gla-r-ok";
            form.reset();
          } else {
            var detail =
              (result.body && result.body.error) ||
              (result.raw && result.raw.slice(0, 200)) ||
              "";
            msg.textContent = detail
              ? detail + " (" + result.status + ")"
              : "Erro " + result.status;
            msg.className = "gla-r-msg gla-r-err";
          }
        })
        .catch(function () {
          msg.textContent =
            "Rede ou CORS: confirma api_base e REPORTS_CORS_ORIGINS no servidor.";
          msg.className = "gla-r-msg gla-r-err";
        })
        .then(function () {
          btnSend.disabled = false;
        });
    });
  })();
  /*]]>*/
</script>

Edição atual tal como às 16h07min 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 wid = String(roots.getAttribute("data-gla-wid") || "1").replace(/[^a-zA-Z0-9_-]/g, "");
   var HEADING = roots.getAttribute("data-gla-heading") || "";
   if (!HEADING) HEADING = "Report ou sugestão";
   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-inline-css-global")) return;
     var st = document.createElement("style");
     st.id = "gla-reports-inline-css-global";
     st.textContent =
       ".gla-report-widget-root{width:100%;max-width:520px;margin:1rem 0;display:block;clear:both}" +
       ".gla-reports-inline{max-width:100%;box-sizing:border-box;background:#111827;color:#f9fafb;border-radius:12px;padding:18px 20px;font:14px/1.45 system-ui,sans-serif;border:1px solid #374151;box-shadow:0 8px 24px rgba(0,0,0,.15)}" +
       ".gla-reports-inline-h2{font-size:1.1rem;margin:0 0 14px;color:#fff;font-weight:600}" +
       ".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;align-items:center}" +
       ".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-muted{background:#374151;color:#e5e7eb}" +
       ".gla-r-msg{margin-top:12px;font-size:.85rem;min-height:1.2em}" +
       ".gla-r-msg.gla-r-ok{color:#6ee7b7}" +
       ".gla-r-msg.gla-r-err{color:#fca5a5}";
     document.head.appendChild(st);
   }
   var mid = "gla-form-" + wid;
   function buildFormBody() {
     return (
       '<section class="gla-reports-inline" aria-labelledby="' +
       mid +
       '-tit">' +

'

' + esc(HEADING) + "

" +

       '<form id="' +
       mid +
       '-f" novalidate>' +

'

<label for="' +
       mid +
       '-title">Título (opcional, até ' +
       MAX_TITLE +
       " caracteres)</label>" +
       '<input type="text" id="' +
       mid +
       '-title" name="name" maxlength="' +
       MAX_TITLE +
'" autocomplete="off" placeholder="Ex.: erro na página X"/>

' + '

<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>

" + '

<label for="' +
       mid +
       '-desc">Descrição *</label>' +
       '<textarea id="' +
       mid +
'-desc" name="description" maxlength="8000" required placeholder="Descrição detalhada"></textarea>

' + '

<label for="' +
       mid +
       '-img">Imagem (opcional)</label>' +
       '<input type="file" id="' +
       mid +
'-img" accept="image/png,image/jpeg,image/gif"/>

' + '

' +
       '<button type="submit" class="gla-r-primary" id="' +
       mid +
       '-send">' +
       esc("Enviar") +
       "</button>" +
       '<button type="reset" class="gla-r-muted" id="' +
       mid +
       '-reset">' +
       esc("Limpar") +
"</button>

" + '

' +

       "</form></section>"
     );
   }
   function localFileOk(f) {
     var t = (f.type || "").toLowerCase();
     var n = (f.name || "").toLowerCase();
     if (/^image\/(png|jpeg|gif)$/.test(t)) return true;
     if (/\.(png|jpe?g|gif)$/.test(n)) return true;
     return false;
   }
   css();
   roots.innerHTML = buildFormBody();
   var form = byId(mid + "-f");
   var btnSend = byId(mid + "-send");
   var msg = byId(mid + "-msg");
   if (!REPORTS_API_BASE) {
     if (btnSend) btnSend.disabled = true;
     if (msg) {
       msg.textContent = "Configura api_base na wiki: api_base=https://…";
       msg.className = "gla-r-msg gla-r-err";
     }
     return;
   }
   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 gla-r-err";
       return;
     }
     if (title.length > MAX_TITLE) {
       msg.textContent = "Título longo demais.";
       msg.className = "gla-r-msg gla-r-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 gla-r-err";
         return;
       }
       if (!localFileOk(f)) {
         msg.textContent = "Só PNG, JPG ou GIF.";
         msg.className = "gla-r-msg gla-r-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.text().then(function (text) {
           var body = {};
           try {
             body = text ? JSON.parse(text) : {};
           } catch (ignore) {
             body = { _raw: text };
           }
           return { ok: r.ok, status: r.status, body: body, raw: text };
         });
       })
       .then(function (result) {
         if (result.ok) {
           msg.textContent = "Enviado. Obrigado!";
           msg.className = "gla-r-msg gla-r-ok";
           form.reset();
         } else {
           var detail =
             (result.body && result.body.error) ||
             (result.raw && result.raw.slice(0, 200)) ||
             "";
           msg.textContent = detail
             ? detail + " (" + result.status + ")"
             : "Erro " + result.status;
           msg.className = "gla-r-msg gla-r-err";
         }
       })
       .catch(function () {
         msg.textContent =
           "Rede ou CORS: confirma api_base e REPORTS_CORS_ORIGINS no servidor.";
         msg.className = "gla-r-msg gla-r-err";
       })
       .then(function () {
         btnSend.disabled = false;
       });
   });
 })();
 /*]]>*/

</script>