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

De Wiki Gla
Ir para navegação Ir para pesquisar
m
m
 
(2 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 3: Linha 3:
       Tooltip: payload codificado em data-tip (Módulo:Item). Corpo vazio no HTML.
       Tooltip: payload codificado em data-tip (Módulo:Item). Corpo vazio no HTML.
       JS decodifica no hover (rápido, sem API) e limpa no mouseout.
       JS decodifica no hover (rápido, sem API) e limpa no mouseout.
      Ícone: span.item-icon + data-i codificado — sem <img> no HTML; JS hidrata
      background-image e remove data-i. Anti-arrastar/cópia/clique-direito leve.
       Defesa leve: hover real + rate limit de decodes para automação.
       Defesa leve: hover real + rate limit de decodes para automação.
     -->
     -->
Linha 33: Linha 35:
             overflow: visible;
             overflow: visible;
             filter: none;
             filter: none;
            -webkit-user-select: none;
            user-select: none;
            -webkit-touch-callout: none;
         }
         }


        .item-icon {
            display: block;
            margin: 0 auto;
            background-repeat: no-repeat;
            background-position: center;
            background-size: contain;
            filter: none;
            box-shadow: none;
            -webkit-user-select: none;
            user-select: none;
            -webkit-user-drag: none;
            -webkit-touch-callout: none;
            pointer-events: none;
        }
        /* Páginas em cache ainda com [[Arquivo:…]] → <img> legado */
         .item-wrapper img {
         .item-wrapper img {
             display: block;
             display: block;
Linha 40: Linha 61:
             filter: none;
             filter: none;
             box-shadow: none;
             box-shadow: none;
            -webkit-user-select: none;
            user-select: none;
            -webkit-user-drag: none;
            -webkit-touch-callout: none;
            pointer-events: none;
         }
         }


Linha 267: Linha 293:
             var MARGIN = 8;
             var MARGIN = 8;
             var GAP = 6;
             var GAP = 6;
             var XOR_KEY = 0x5A;
             var XOR_KEY = 0x5A; /* legado hex — páginas em cache antes do b64 */
             var activeTip = null;
             var activeTip = null;
             var activeWrapper = null;
             var activeWrapper = null;
Linha 309: Linha 335:
             }
             }


             function hexToUtf8String(hex) {
             function bytesToUtf8String(bytes) {
                var bytes = [];
                for (var i = 0; i < hex.length; i += 2) {
                    bytes.push(parseInt(hex.substr(i, 2), 16) ^ XOR_KEY);
                }
                 if (typeof TextDecoder !== "undefined") {
                 if (typeof TextDecoder !== "undefined") {
                     return new TextDecoder("utf-8").decode(new Uint8Array(bytes));
                     return new TextDecoder("utf-8").decode(
                        bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes)
                    );
                 }
                 }
                 var bin = "";
                 var bin = "";
Linha 321: Linha 345:
                     bin += String.fromCharCode(bytes[j]);
                     bin += String.fromCharCode(bytes[j]);
                 }
                 }
                 try {
                 return decodeURIComponent(escape(bin));
                     return decodeURIComponent(escape(bin));
            }
                 } catch (e) {
 
                     return bin;
            function base64ToUtf8String(b64) {
                var bin = atob(b64);
                var bytes = new Uint8Array(bin.length);
                for (var i = 0; i < bin.length; i++) {
                     bytes[i] = bin.charCodeAt(i);
                }
                return bytesToUtf8String(bytes);
            }
 
            function hexToUtf8String(hex) {
                var bytes = [];
                for (var i = 0; i < hex.length; i += 2) {
                    bytes.push(parseInt(hex.substr(i, 2), 16) ^ XOR_KEY);
                 }
                return bytesToUtf8String(bytes);
            }
 
            function payloadToJson(raw) {
                if (!raw) return null;
                if (raw.indexOf("b64:") === 0) {
                     return base64ToUtf8String(raw.slice(4));
                 }
                 }
                return hexToUtf8String(raw);
             }
             }


             function decodePayload(hex) {
             function decodePayload(raw) {
                 if (!hex) return null;
                 if (!raw) return null;
                 if (decodeCache[hex]) return decodeCache[hex];
                 if (decodeCache[raw]) return decodeCache[raw];
                 try {
                 try {
                     var obj = JSON.parse(hexToUtf8String(hex));
                     var obj = JSON.parse(payloadToJson(raw));
                     decodeCache[hex] = obj;
                     decodeCache[raw] = obj;
                     return obj;
                     return obj;
                 } catch (e) {
                 } catch (e) {
Linha 339: Linha 384:
                 }
                 }
             }
             }
            function getThumbUrl(filename, width) {
                var title = "Special:Redirect/file/" + String(filename).replace(/ /g, "_");
                var scriptPath = "";
                try {
                    if (window.mw && mw.config) {
                        scriptPath = mw.config.get("wgScriptPath") || "";
                    }
                } catch (e) { /* ignore */ }
                /* Caminho relativo ao origin da página (HTTPS). mw.util.getUrl
                  pode gerar http://IP/… e o browser bloqueia Mixed Content. */
                return scriptPath + "/index.php?title=" + encodeURIComponent(title) + "&width=" + width;
            }
            function hydrateIcon(el) {
                if (!el || el.getAttribute("data-ready") === "1") return;
                var raw = el.getAttribute("data-i");
                if (!raw) return;
                var p = decodePayload(raw);
                if (!p || !p.i) return;
                var w = p.w || 32;
                var h = p.h || 32;
                el.style.width = w + "px";
                el.style.height = h + "px";
                el.style.backgroundImage = 'url("' + getThumbUrl(p.i, w) + '")';
                el.setAttribute("data-ready", "1");
                el.removeAttribute("data-i");
            }
            function hydrateAllIcons(root) {
                var scope = root || document;
                var icons = scope.querySelectorAll ? scope.querySelectorAll(".item-icon[data-i]") : [];
                for (var i = 0; i < icons.length; i++) {
                    hydrateIcon(icons[i]);
                }
            }
            function watchIconHydration() {
                if (!window.MutationObserver) return;
                var pending = null;
                var observer = new MutationObserver(function (mutations) {
                    var need = false;
                    for (var i = 0; i < mutations.length; i++) {
                        var added = mutations[i].addedNodes;
                        for (var j = 0; j < added.length; j++) {
                            var node = added[j];
                            if (node.nodeType !== 1) continue;
                            if (node.matches && node.matches(".item-icon[data-i]")) {
                                need = true;
                                break;
                            }
                            if (node.querySelector && node.querySelector(".item-icon[data-i]")) {
                                need = true;
                                break;
                            }
                        }
                        if (need) break;
                    }
                    if (!need) return;
                    if (pending) clearTimeout(pending);
                    pending = setTimeout(function () {
                        pending = null;
                        hydrateAllIcons();
                    }, 0);
                });
                observer.observe(document.documentElement, { childList: true, subtree: true });
            }
            window.glaItemHydrateIcons = hydrateAllIcons;
            function protectItemWrapperEvents() {
                document.addEventListener("contextmenu", function (e) {
                    if (e.target.closest && e.target.closest(".item-wrapper")) {
                        e.preventDefault();
                    }
                }, true);
                document.addEventListener("dragstart", function (e) {
                    if (e.target.closest && e.target.closest(".item-wrapper")) {
                        e.preventDefault();
                    }
                }, true);
                document.addEventListener("copy", function (e) {
                    if (e.target.closest && e.target.closest(".item-wrapper")) {
                        e.preventDefault();
                    }
                }, true);
                document.addEventListener("selectstart", function (e) {
                    if (e.target.closest && e.target.closest(".item-wrapper")) {
                        e.preventDefault();
                    }
                }, true);
            }
            if (document.readyState === "loading") {
                document.addEventListener("DOMContentLoaded", function () {
                    hydrateAllIcons();
                    watchIconHydration();
                });
            } else {
                hydrateAllIcons();
                watchIconHydration();
            }
            protectItemWrapperEvents();


             function appendText(el, text) {
             function appendText(el, text) {

Edição atual tal como às 22h24min de 28 de maio de 2026