Mudanças entre as edições de "Widget:Teste"
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 | GLA — Widget:ReportModal (Extension:Widgets) | ||
{{#widget: | 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= | Uso: {{#widget:ReportModal|api_base=https://TEU_DEPLOY}} | ||
Opcionais: |label=... |wid=2 | |||
No servidor: REPORTS_CORS_ORIGINS com o origin da wiki. | |||
--> | --> | ||
</noinclude> | </noinclude> | ||
< | <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> | ||
<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 = | |||
'<div class="gla-reports-overlay" id="' + | |||
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>"; | |||
} | |||
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> | |||
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>