Jump to content

MediaWiki:Common.js: Difference between revisions

From Vampiro
Restaurada opção no menu Inserir do VisualEditor + Botões CENSURADO/LIBERADO
Correção de SyntaxError (chave faltante) que derrubava todo o script
Line 1: Line 1:
/* ==========================================================================
/* ==========================================================================
   VAMPIRO: A MÁSCARA — SCRIPTS GLOBAIS, MENU INSERIR & SEGREDO DINÂMICO
   VAMPIRO: A MÁSCARA — SCRIPTS GLOBAIS & SEGREDO DINÂMICO
   ========================================================================== */
   ========================================================================== */


Line 6: Line 6:
   'use strict';
   'use strict';


   // ------------------------------------------------------------------------
   /* ------------------------------------------------------------------
  // 1. LÓGICA DE CENSURA & REVELAÇÃO DINÂMICA ({{Segredo}})
    1. CENSURA & REVELAÇÃO DINÂMICA (leitura de páginas)
  // ------------------------------------------------------------------------
    ------------------------------------------------------------------ */
   function initVtmSecrets() {
   function initVtmSecrets() {
     var secretElements = document.querySelectorAll('[data-vtm-secret="true"]');
     var els = document.querySelectorAll('[data-vtm-secret="true"]');
     if (!secretElements || secretElements.length === 0) return;
     if (!els || !els.length) return;


     var now = new Date();
     var now = new Date();


     secretElements.forEach(function (el) {
     els.forEach(function (el) {
       var liberado = (el.getAttribute('data-liberado') || '').toLowerCase().trim();
       var lib = (el.getAttribute('data-liberado') || '').toLowerCase().trim();
       var dateStr = (el.getAttribute('data-reveal-date') || '').trim();
       var ds  = (el.getAttribute('data-reveal-date') || '').trim();
       var dica = (el.getAttribute('data-dica') || '').trim();
       var dica = (el.getAttribute('data-dica') || '').trim();
       var isRevealed = false;
       var revealed = false;
       var tooltipText = '[ARQUIVO CONFIDENCIAL]';
       var tip = '[ARQUIVO CONFIDENCIAL]';


       if (liberado === 'sim' || liberado === 'true' || liberado === '1' || liberado === 'liberado') {
       if (lib === 'sim' || lib === 'true' || lib === '1') {
         isRevealed = true;
         revealed = true;
       } else if (liberado === 'nao' || liberado === 'false' || liberado === '0' || liberado === 'censurado') {
       } else if (lib === 'nao' || lib === 'false' || lib === '0') {
         isRevealed = false;
         revealed = false;
         tooltipText = '[CLASSIFICADO' + (dica ? ' // ' + dica : '') + ']';
         tip = '[CLASSIFICADO' + (dica ? ' // ' + dica : '') + ']';
       } else if (dateStr) {
       } else if (ds) {
         var targetDate = null;
         var td = null;
         if (dateStr.indexOf('/') !== -1) {
         if (ds.indexOf('/') !== -1) {
           var parts = dateStr.split('/');
           var p = ds.split('/');
           if (parts.length === 3) {
           if (p.length === 3) td = new Date(p[2], parseInt(p[1], 10) - 1, p[0]);
            targetDate = new Date(parts[2], parseInt(parts[1], 10) - 1, parts[0], 0, 0, 0);
          }
         } else {
         } else {
           targetDate = new Date(dateStr);
           td = new Date(ds);
         }
         }
 
         if (td && !isNaN(td.getTime())) {
         if (targetDate && !isNaN(targetDate.getTime())) {
           if (now >= td) {
           if (now >= targetDate) {
             revealed = true;
             isRevealed = true;
           } else {
           } else {
             var formatted = ('0' + targetDate.getDate()).slice(-2) + '/' +
             var f = ('0' + td.getDate()).slice(-2) + '/' +
                            ('0' + (targetDate.getMonth() + 1)).slice(-2) + '/' +
                    ('0' + (td.getMonth() + 1)).slice(-2) + '/' +
                            targetDate.getFullYear();
                    td.getFullYear();
             tooltipText = '[CLASSIFICADO' + (dica ? ' // ' + dica : '') + ' - ' + formatted + ']';
             tip = '[CLASSIFICADO' + (dica ? ' // ' + dica : '') + ' - ' + f + ']';
           }
           }
         }
         }
       }
       }


       if (isRevealed) {
       if (revealed) {
         el.classList.add('is-revealed');
         el.classList.add('is-revealed');
         el.classList.remove('is-redacted');
         el.classList.remove('is-redacted');
Line 57: Line 54:
         el.classList.add('is-redacted');
         el.classList.add('is-redacted');
         el.classList.remove('is-revealed');
         el.classList.remove('is-revealed');
         el.title = tooltipText;
         el.title = tip;
       }
       }
     });
     });
   }
   }


   // ------------------------------------------------------------------------
   /* ------------------------------------------------------------------
  // 2. INTEGRAÇÃO COM VISUALEDITOR: BOTÃO NO MENU "INSERIR"
    2. BOTÕES [ CENSURADO | LIBERADO ] NO MODAL DO VISUALEDITOR
  // ------------------------------------------------------------------------
    ------------------------------------------------------------------ */
   function setupVisualEditorTool() {
   function transformLiberadoInputs() {
     if (!window.mw || !mw.hook) return;
     var inputs = document.querySelectorAll(
 
       '.oo-ui-windowManager input, .oo-ui-windowManager textarea, ' +
    function registerVeTool() {
      '.oo-ui-fieldLayout input, .oo-ui-fieldLayout textarea'
      if (!window.ve || !ve.ui || !ve.ui.toolFactory) return;
     );
 
       if (ve.ui.toolFactory.lookup('vtmSecret')) return;
 
      // Comando de inserção da transclusão da predefinição Segredo
      ve.ui.commandRegistry.register(
        new ve.ui.Command(
          'insertVtmSecret', 'content', 'insert',
          {
            args: [
              [
                {
                  type: 'mwTransclusionInline',
                  attributes: {
                    mw: {
                      parts: [
                        {
                          template: {
                            target: { href: 'Template:Segredo', wt: 'Segredo' },
                            params: {
                              '1': { wt: 'Texto confidencial a ser censurado' },
                              'liberado': { wt: 'nao' }
                            }
                          }
                        ]
                      }
                    }
                  }
                },
                { type: '/mwTransclusionInline' }
              ]
            ],
            supportedSelections: ['linear']
          }
        )
      );
 
      // Tool associado ao menu Inserir
      function VtmSecretVeTool() {
        VtmSecretVeTool.super.apply(this, arguments);
      }
      OO.inheritClass(VtmSecretVeTool, ve.ui.Tool);
      VtmSecretVeTool.static.name = 'vtmSecret';
      VtmSecretVeTool.static.group = 'insert';
      VtmSecretVeTool.static.icon = 'lock';
      VtmSecretVeTool.static.title = '🔒 Censura / Segredo (Confidencial)';
      VtmSecretVeTool.static.commandName = 'insertVtmSecret';
 
      ve.ui.toolFactory.register(VtmSecretVeTool);
    }
 
    mw.hook('ve.loadModules').add(function (addPlugin) {
      addPlugin(registerVeTool);
    });
 
    mw.hook('ve.activationComplete').add(registerVeTool);
 
     if (window.ve && ve.ui && ve.ui.toolFactory) {
      registerVeTool();
    }
  }


  // ------------------------------------------------------------------------
  // 3. ENHANCER UNIVERSAL DO MODAL: BOTÕES [ CENSURADO | LIBERADO ]
  // ------------------------------------------------------------------------
  function transformLiberadoInputs() {
    var inputs = document.querySelectorAll('.oo-ui-windowManager input, .oo-ui-windowManager textarea, .ve-ui-surface input, .oo-ui-fieldLayout input, .oo-ui-fieldLayout textarea');
   
     inputs.forEach(function (input) {
     inputs.forEach(function (input) {
       var container = input.closest('.oo-ui-fieldLayout') ||  
       var container = input.closest('.oo-ui-fieldLayout') ||
                       input.closest('.ve-ui-mwParameterPage') ||  
                       input.closest('.ve-ui-mwParameterPage') ||
                       input.closest('.oo-ui-pageLayout') ||  
                       input.closest('.oo-ui-pageLayout') ||
                       input.parentElement;
                       input.parentElement;
       if (!container) return;
       if (!container) return;


       var textCheck = (container.textContent || '').toLowerCase();
       var txt = (container.textContent || '').toLowerCase();
       if (textCheck.indexOf('liberado') !== -1 && !container.querySelector('.vtm-custom-toggle-box')) {
       if (txt.indexOf('liberado') === -1) return;
       
      if (container.querySelector('.vtm-toggle-box')) return;
        var box = document.createElement('div');
        box.className = 'vtm-custom-toggle-box';
        box.style.cssText = 'display:flex; gap:12px; margin:10px 0 16px 0; width:100%; max-width:460px;';


        var btnCensurado = document.createElement('button');
      var box = document.createElement('div');
        btnCensurado.type = 'button';
      box.className = 'vtm-toggle-box';
        btnCensurado.innerHTML = '⬛ CENSURADO';
      box.style.cssText = 'display:flex;gap:12px;margin:10px 0 16px;width:100%;max-width:460px;';
        btnCensurado.style.cssText = 'flex:1; padding:10px 16px; border-radius:4px; font-weight:800; font-size:0.9em; cursor:pointer; font-family:"Cinzel", Georgia, serif; letter-spacing:1px; transition:all 0.25s ease; outline:none;';


        var btnLiberado = document.createElement('button');
      var btnC = makeToggle('CENSURADO');
        btnLiberado.type = 'button';
      var btnL = makeToggle('LIBERADO');
        btnLiberado.innerHTML = '🔓 LIBERADO';
        btnLiberado.style.cssText = 'flex:1; padding:10px 16px; border-radius:4px; font-weight:800; font-size:0.9em; cursor:pointer; font-family:"Cinzel", Georgia, serif; letter-spacing:1px; transition:all 0.25s ease; outline:none;';


        function renderState(currentVal) {
      function paint(v) {
          var val = (currentVal || '').toLowerCase().trim();
        v = (v || '').toLowerCase().trim();
          if (val === 'sim' || val === '1' || val === 'true' || val === 'liberado') {
        var isLib = (v === 'sim' || v === '1' || v === 'true');
            btnLiberado.style.background = 'linear-gradient(180deg, #1b5e20 0%, #0d3814 100%)';
        // Censurado
            btnLiberado.style.color = '#ffffff';
        btnC.style.background = isLib ? '#121218' : 'linear-gradient(180deg,#5c0f18,#2b060a)';
            btnLiberado.style.border = '2px solid #4caf50';
        btnC.style.color      = isLib ? '#7a7a88' : '#fff';
            btnLiberado.style.boxShadow = '0 0 12px rgba(76, 175, 80, 0.7)';
        btnC.style.border    = isLib ? '1px solid #2d2d38' : '2px solid #ff2a3f';
        btnC.style.boxShadow  = isLib ? 'none' : '0 0 12px rgba(255,42,63,.7)';
        // Liberado
        btnL.style.background = isLib ? 'linear-gradient(180deg,#1b5e20,#0d3814)' : '#121218';
        btnL.style.color     = isLib ? '#fff' : '#7a7a88';
        btnL.style.border     = isLib ? '2px solid #4caf50' : '1px solid #2d2d38';
        btnL.style.boxShadow = isLib ? '0 0 12px rgba(76,175,80,.7)' : 'none';
      }


            btnCensurado.style.background = '#121218';
      btnC.onclick = function (e) {
            btnCensurado.style.color = '#7a7a88';
        e.preventDefault(); e.stopPropagation();
            btnCensurado.style.border = '1px solid #2d2d38';
        setVal(input, 'nao'); paint('nao');
            btnCensurado.style.boxShadow = 'none';
      };
          } else {
      btnL.onclick = function (e) {
            btnCensurado.style.background = 'linear-gradient(180deg, #5c0f18 0%, #2b060a 100%)';
        e.preventDefault(); e.stopPropagation();
            btnCensurado.style.color = '#ffffff';
        setVal(input, 'sim'); paint('sim');
            btnCensurado.style.border = '2px solid #ff2a3f';
      };
            btnCensurado.style.boxShadow = '0 0 12px rgba(255, 42, 63, 0.7)';


            btnLiberado.style.background = '#121218';
      input.addEventListener('input', function () { paint(input.value); });
            btnLiberado.style.color = '#7a7a88';
      paint(input.value || 'nao');
            btnLiberado.style.border = '1px solid #2d2d38';
            btnLiberado.style.boxShadow = 'none';
          }
        }


        btnCensurado.onclick = function (e) {
      box.appendChild(btnC);
          e.preventDefault();
      box.appendChild(btnL);
          e.stopPropagation();
          input.value = 'nao';
          input.dispatchEvent(new Event('input', { bubbles: true }));
          input.dispatchEvent(new Event('change', { bubbles: true }));
          if (window.$) { $(input).trigger('input').trigger('change'); }
          renderState('nao');
        };


        btnLiberado.onclick = function (e) {
      var wrap = input.closest('.oo-ui-textInputWidget') ||
          e.preventDefault();
                input.closest('.oo-ui-inputWidget') || input;
          e.stopPropagation();
      wrap.parentNode.insertBefore(box, wrap);
          input.value = 'sim';
      wrap.style.display = 'none';
          input.dispatchEvent(new Event('input', { bubbles: true }));
    });
          input.dispatchEvent(new Event('change', { bubbles: true }));
  }
          if (window.$) { $(input).trigger('input').trigger('change'); }
          renderState('sim');
        };


        input.addEventListener('input', function () {
  function makeToggle(label) {
          renderState(input.value);
    var b = document.createElement('button');
        });
    b.type = 'button';
 
    b.textContent = (label === 'CENSURADO' ? '⬛ ' : '🔓 ') + label;
        renderState(input.value || 'nao');
    b.style.cssText = 'flex:1;padding:10px 16px;border-radius:4px;font-weight:800;' +
      'font-size:.9em;cursor:pointer;font-family:"Cinzel",Georgia,serif;' +
      'letter-spacing:1px;transition:all .25s ease;outline:none;';
    return b;
  }


        box.appendChild(btnCensurado);
  function setVal(input, v) {
        box.appendChild(btnLiberado);
    input.value = v;
 
    input.dispatchEvent(new Event('input', { bubbles: true }));
        var targetWrapper = input.closest('.oo-ui-textInputWidget') || input.closest('.oo-ui-inputWidget') || input;
    input.dispatchEvent(new Event('change', { bubbles: true }));
        targetWrapper.parentNode.insertBefore(box, targetWrapper);
    if (window.$) { $(input).trigger('input').trigger('change'); }
        targetWrapper.style.display = 'none';
      }
    });
   }
   }


   setInterval(transformLiberadoInputs, 250);
   setInterval(transformLiberadoInputs, 300);


   // ------------------------------------------------------------------------
   /* ------------------------------------------------------------------
  // 4. BARRA DE FERRAMENTAS NO EDITOR DE CÓDIGO-FONTE (#wpTextbox1)
    3. BARRA DE FERRAMENTAS NO EDITOR DE CÓDIGO-FONTE (#wpTextbox1)
  // ------------------------------------------------------------------------
    ------------------------------------------------------------------ */
   function initVtmQuickToolbar() {
   function initVtmQuickToolbar() {
     var textbox = document.getElementById('wpTextbox1');
     var tb = document.getElementById('wpTextbox1');
     if (!textbox) return;
     if (!tb || document.getElementById('vtm-editor-quickbar')) return;
    if (document.getElementById('vtm-editor-quickbar')) return;


     var bar = document.createElement('div');
     var bar = document.createElement('div');
     bar.id = 'vtm-editor-quickbar';
     bar.id = 'vtm-editor-quickbar';
    bar.className = 'vtm-editor-quickbar';
     bar.style.cssText =
     bar.style.cssText = 'display:flex; flex-wrap:wrap; gap:8px; align-items:center; padding:10px 14px; margin:10px 0; background:linear-gradient(90deg, #181014 0%, #0d0d12 100%); border:1px solid #3d0a12; border-left:4px solid #8b0000; border-radius:4px; font-family:"Cinzel", Georgia, serif; box-shadow:0 4px 14px rgba(0,0,0,0.6); z-index:99;';
      'display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:10px 14px;' +
      'margin:10px 0;background:linear-gradient(90deg,#181014,#0d0d12);' +
      'border:1px solid #3d0a12;border-left:4px solid #8b0000;border-radius:4px;' +
      'font-family:"Cinzel",Georgia,serif;box-shadow:0 4px 14px rgba(0,0,0,.6);z-index:99;';


     var label = document.createElement('span');
     var lbl = document.createElement('span');
     label.style.cssText = 'color:#c5a059; font-size:0.85em; font-weight:700; text-transform:uppercase; letter-spacing:1px; margin-right:6px;';
     lbl.style.cssText = 'color:#c5a059;font-size:.85em;font-weight:700;text-transform:uppercase;letter-spacing:1px;margin-right:6px;';
     label.textContent = '🩸 Ferramentas:';
     lbl.textContent = 'Ferramentas:';
     bar.appendChild(label);
     bar.appendChild(lbl);


     bar.appendChild(makeBtn(
     bar.appendChild(makeBtn('⬛ Censurar Trecho', '#240c12', '#ff2a3f', function () {
      '⬛ Censurar Trecho',
       wrapSelection(tb, '{{Segredo|', '|liberado=nao}}', 'Texto censurado');
       'Envolve o texto com {{Segredo|...|liberado=nao}}',
    }));
      '#240c12', '#ff2a3f',
    bar.appendChild(makeBtn('🔓 Inserir Liberado', '#0d2915', '#2e7d32', function () {
       function () { insertSecretWithStatus(textbox, 'nao'); }
       wrapSelection(tb, '{{Segredo|', '|liberado=sim}}', 'Texto revelado');
     ));
    }));
    bar.appendChild(makeBtn('📁 Dossiê Bloco', '#181822', '#3d0a12', function () {
      wrapSelection(tb,
        '\n{{Segredo|tipo=bloco|nivel=CONFIDENCIAL|data=AAAA-MM-DD|dica=Operação|\n',
        '\n}}\n',
        'Relatório confidencial...');
    }));
     bar.appendChild(makeBtn('🗑️ Remover Censura', '#1a1a22', '#4a4a58', function () {
      removeSecret(tb);
    }));


     bar.appendChild(makeBtn(
     tb.parentNode.insertBefore(bar, tb);
      '🔓 Inserir Liberado',
      'Envolve o texto com {{Segredo|...|liberado=sim}}',
      '#0d2915', '#2e7d32',
      function () { insertSecretWithStatus(textbox, 'sim'); }
    ));
 
    bar.appendChild(makeBtn(
      '📁 Dossiê Bloco',
      'Insere bloco confidencial completo',
      '#181822', '#3d0a12',
      function () { insertSecretBlock(textbox); }
    ));
 
    bar.appendChild(makeBtn(
      '🗑️ Remover Censura',
      'Remove a marcação {{Segredo|...}} mantendo o texto interno',
      '#1a1a22', '#4a4a58',
      function () { removeSecret(textbox); }
    ));
 
    textbox.parentNode.insertBefore(bar, textbox);
   }
   }


   function makeBtn(text, title, bg, border, onclick) {
   function makeBtn(text, bg, border, fn) {
     var btn = document.createElement('button');
     var b = document.createElement('button');
     btn.type = 'button';
     b.type = 'button';
     btn.style.cssText = 'background:' + bg + '; color:#ffffff; border:1px solid ' + border + '; border-radius:3px; padding:6px 12px; font-size:0.82em; font-weight:700; cursor:pointer; display:inline-flex; align-items:center; gap:4px; transition:all 0.2s ease;';
     b.textContent = text;
     btn.textContent = text;
    b.style.cssText =
    btn.title = title;
      'background:' + bg + ';color:#fff;border:1px solid ' + border +
    btn.onmouseover = function () { btn.style.opacity = '0.85'; };
      ';border-radius:3px;padding:6px 12px;font-size:.82em;font-weight:700;' +
     btn.onmouseout = function () { btn.style.opacity = '1'; };
      'cursor:pointer;display:inline-flex;align-items:center;gap:4px;transition:all .2s ease;';
     btn.onclick = function (e) { e.preventDefault(); onclick(); };
     b.onmouseover = function () { b.style.opacity = '.85'; };
     return btn;
     b.onmouseout = function () { b.style.opacity = '1'; };
     b.onclick = function (e) { e.preventDefault(); fn(); };
     return b;
   }
   }


   function insertSecretWithStatus(textbox, status) {
   function wrapSelection(tb, pre, post, placeholder) {
     var start = textbox.selectionStart;
     var s = tb.selectionStart, e = tb.selectionEnd;
    var end = textbox.selectionEnd;
     var txt = tb.value, sel = txt.substring(s, e) || placeholder;
     var text = textbox.value;
     tb.value = txt.substring(0, s) + pre + sel + post + txt.substring(e);
    var selected = text.substring(start, end);
     tb.focus();
 
     tb.setSelectionRange(s + pre.length, s + pre.length + sel.length);
    var pre = '{{Segredo|';
     if (window.$) { $(tb).trigger('input').trigger('change'); }
    var defaultText = selected || 'Texto sensível';
    var post = '|liberado=' + status + '}}';
 
    var replacement = pre + defaultText + post;
     textbox.value = text.substring(0, start) + replacement + text.substring(end);
 
    var cursorStart = start + pre.length;
     textbox.focus();
     textbox.setSelectionRange(cursorStart, cursorStart + defaultText.length);
 
     if (window.$) { $(textbox).trigger('input').trigger('change'); }
   }
   }


   function insertSecretBlock(textbox) {
   function removeSecret(tb) {
     var start = textbox.selectionStart;
     var s = tb.selectionStart, text = tb.value;
    var end = textbox.selectionEnd;
     var i = text.lastIndexOf('{{Segredo|', s);
    var text = textbox.value;
     if (i === -1) { alert('Nenhum {{Segredo|...}} encontrado.\nPosicione o cursor dentro do trecho.'); return; }
     var selected = text.substring(start, end);
 
     var pre = '\n{{Segredo|tipo=bloco|nivel=CONFIDENCIAL // SEGUNDA INQUISIÇÃO|data=AAAA-MM-DD|dica=Operação Lisboa|\n';
    var defaultText = selected || 'Texto do relatório confidencial...';
    var post = '\n}}\n';


     var replacement = pre + defaultText + post;
     var depth = 0, j, end = -1;
    textbox.value = text.substring(0, start) + replacement + text.substring(end);
     for (j = i; j < text.length - 1; j++) {
 
      if (text[j] === '{' && text[j+1] === '{') { depth++; j++; }
     var cursorStart = start + pre.length;
      else if (text[j] === '}' && text[j+1] === '}') { depth--; if (depth === 0) { end = j + 2; break; } j++; }
    textbox.focus();
    textbox.setSelectionRange(cursorStart, cursorStart + defaultText.length);
 
    if (window.$) { $(textbox).trigger('input').trigger('change'); }
  }
 
  function removeSecret(textbox) {
    var start = textbox.selectionStart;
    var end = textbox.selectionEnd;
    var text = textbox.value;
 
    var searchStart = text.lastIndexOf('{{Segredo|', start);
    if (searchStart === -1) {
      alert('Nenhum {{Segredo|...}} encontrado na posição do cursor.\nPosicione o cursor dentro de um trecho censurado.');
      return;
     }
     }
    if (end === -1) { alert('Fechamento }} não encontrado.'); return; }


     var depth = 0;
     var inner = text.substring(i + '{{Segredo|'.length, end - 2);
     var searchEnd = -1;
     var parts = [], cur = '', d = 0;
     for (var i = searchStart; i < text.length - 1; i++) {
     for (j = 0; j < inner.length; j++) {
       if (text[i] === '{' && text[i + 1] === '{') { depth++; i++; }
       if (inner[j] === '{' && j+1 < inner.length && inner[j+1] === '{') { d++; cur += '{{'; j++; }
       else if (text[i] === '}' && text[i + 1] === '}') {
       else if (inner[j] === '}' && j+1 < inner.length && inner[j+1] === '}') { d--; cur += '}}'; j++; }
        depth--;
      else if (inner[j] === '|' && d === 0) { parts.push(cur); cur = ''; }
        if (depth === 0) { searchEnd = i + 2; break; }
      else { cur += inner[j]; }
        i++;
      }
     }
     }
    parts.push(cur);


     if (searchEnd === -1) {
     var content = '';
      alert('Não foi possível encontrar o fechamento }} correspondente.');
    for (var k = 0; k < parts.length; k++) {
      return;
      if (parts[k].trim().indexOf('=') === -1) { content = parts[k].trim(); break; }
     }
     }


     var fullMatch = text.substring(searchStart, searchEnd);
     tb.value = text.substring(0, i) + content + text.substring(end);
    var inner = fullMatch.substring('{{Segredo|'.length, fullMatch.length - 2);
     tb.focus();
 
     tb.setSelectionRange(i, i + content.length);
    var params = [];
     if (window.$) { $(tb).trigger('input').trigger('change'); }
    var current = '';
    var nestedDepth = 0;
    for (var j = 0; j < inner.length; j++) {
      if (inner[j] === '{' && j + 1 < inner.length && inner[j + 1] === '{') { nestedDepth++; current += '{'; j++; current += '{'; }
      else if (inner[j] === '}' && j + 1 < inner.length && inner[j + 1] === '}') { nestedDepth--; current += '}'; j++; current += '}'; }
      else if (inner[j] === '|' && nestedDepth === 0) { params.push(current); current = ''; }
      else { current += inner[j]; }
    }
    params.push(current);
 
    var contentText = '';
    for (var k = 0; k < params.length; k++) {
      var p = params[k].trim();
      if (p.indexOf('=') === -1) {
        contentText = p;
        break;
      }
    }
 
    if (!contentText) {
      for (var m = 0; m < params.length; m++) {
        if (params[m].indexOf('=') === -1) {
          contentText = params[m];
          break;
        }
      }
    }
 
    contentText = contentText.trim();
    textbox.value = text.substring(0, searchStart) + contentText + text.substring(searchEnd);
     textbox.focus();
     textbox.setSelectionRange(searchStart, searchStart + contentText.length);
 
     if (window.$) { $(textbox).trigger('input').trigger('change'); }
   }
   }


   // ------------------------------------------------------------------------
   /* ------------------------------------------------------------------
  // 5. ANIMAÇÃO DE CASCATA DAS SEÇÕES
    4. ANIMAÇÃO DE CASCATA DAS SEÇÕES
  // ------------------------------------------------------------------------
    ------------------------------------------------------------------ */
   function initSectionAnimation() {
   function initSectionAnimation() {
     var content = document.querySelector('.mw-parser-output');
     var c = document.querySelector('.mw-parser-output');
     if (!content || content.dataset.vtmAnimated === 'true') return;
     if (!c || c.dataset.vtmAnimated === 'true') return;
 
     if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
     if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;


     content.dataset.vtmAnimated = 'true';
     c.dataset.vtmAnimated = 'true';
     var children = Array.from(content.children);
     var kids = Array.from(c.children), secs = [], cur = [];
    var sections = [];
    var currentSection = [];


     children.forEach(function (child) {
     kids.forEach(function (ch) {
       if (
       if (ch.classList.contains('catlinks') || ch.classList.contains('mw-category-generated') ||
        child.classList.contains('catlinks') ||
          ch.tagName === 'SCRIPT' || ch.tagName === 'STYLE' || ch.id === 'vtm-editor-quickbar') {
        child.classList.contains('mw-category-generated') ||
         if (cur.length) { secs.push(cur); cur = []; }
        child.tagName === 'SCRIPT' ||
        child.tagName === 'STYLE' ||
        child.id === 'vtm-editor-quickbar'
      ) {
         if (currentSection.length > 0) { sections.push(currentSection); currentSection = []; }
         return;
         return;
       }
       }
 
       if ((ch.tagName === 'H2' || ch.classList.contains('mw-heading2')) && cur.length) {
       var isH2 = child.tagName === 'H2' || child.classList.contains('mw-heading2');
        secs.push(cur); cur = [];
      if (isH2 && currentSection.length > 0) { sections.push(currentSection); currentSection = []; }
      }
       currentSection.push(child);
       cur.push(ch);
     });
     });
    if (cur.length) secs.push(cur);


     if (currentSection.length > 0) sections.push(currentSection);
     secs.forEach(function (items, idx) {
 
       var w = document.createElement('div');
    sections.forEach(function (sectionElements, index) {
       w.className = 'vtm-section-block';
       var wrapper = document.createElement('div');
       w.style.animationDelay = (0.12 + idx * 0.42).toFixed(2) + 's';
       wrapper.className = 'vtm-section-block';
       var f = items[0];
       wrapper.style.animationDelay = (0.12 + index * 0.42).toFixed(2) + 's';
       if (f && f.parentNode) {
 
         f.parentNode.insertBefore(w, f);
       var firstElem = sectionElements[0];
         items.forEach(function (el) { w.appendChild(el); });
       if (firstElem && firstElem.parentNode) {
         firstElem.parentNode.insertBefore(wrapper, firstElem);
         sectionElements.forEach(function (el) { wrapper.appendChild(el); });
       }
       }
     });
     });
   }
   }


   // ------------------------------------------------------------------------
   /* ------------------------------------------------------------------
  // INICIALIZAÇÃO GERAL
    INICIALIZAÇÃO
  // ------------------------------------------------------------------------
    ------------------------------------------------------------------ */
   function initAll() {
   function initAll() {
     initVtmSecrets();
     initVtmSecrets();
     initSectionAnimation();
     initSectionAnimation();
     initVtmQuickToolbar();
     initVtmQuickToolbar();
    setupVisualEditorTool();
    transformLiberadoInputs();
   }
   }



Revision as of 19:54, 1 September 2026

/* ==========================================================================
   VAMPIRO: A MÁSCARA — SCRIPTS GLOBAIS & SEGREDO DINÂMICO
   ========================================================================== */

(function () {
  'use strict';

  /* ------------------------------------------------------------------
     1. CENSURA & REVELAÇÃO DINÂMICA (leitura de páginas)
     ------------------------------------------------------------------ */
  function initVtmSecrets() {
    var els = document.querySelectorAll('[data-vtm-secret="true"]');
    if (!els || !els.length) return;

    var now = new Date();

    els.forEach(function (el) {
      var lib = (el.getAttribute('data-liberado') || '').toLowerCase().trim();
      var ds  = (el.getAttribute('data-reveal-date') || '').trim();
      var dica = (el.getAttribute('data-dica') || '').trim();
      var revealed = false;
      var tip = '[ARQUIVO CONFIDENCIAL]';

      if (lib === 'sim' || lib === 'true' || lib === '1') {
        revealed = true;
      } else if (lib === 'nao' || lib === 'false' || lib === '0') {
        revealed = false;
        tip = '[CLASSIFICADO' + (dica ? ' // ' + dica : '') + ']';
      } else if (ds) {
        var td = null;
        if (ds.indexOf('/') !== -1) {
          var p = ds.split('/');
          if (p.length === 3) td = new Date(p[2], parseInt(p[1], 10) - 1, p[0]);
        } else {
          td = new Date(ds);
        }
        if (td && !isNaN(td.getTime())) {
          if (now >= td) {
            revealed = true;
          } else {
            var f = ('0' + td.getDate()).slice(-2) + '/' +
                    ('0' + (td.getMonth() + 1)).slice(-2) + '/' +
                    td.getFullYear();
            tip = '[CLASSIFICADO' + (dica ? ' // ' + dica : '') + ' - ' + f + ']';
          }
        }
      }

      if (revealed) {
        el.classList.add('is-revealed');
        el.classList.remove('is-redacted');
        el.title = '[DESCLASSIFICADO' + (dica ? ' // ' + dica : '') + ']';
      } else {
        el.classList.add('is-redacted');
        el.classList.remove('is-revealed');
        el.title = tip;
      }
    });
  }

  /* ------------------------------------------------------------------
     2. BOTÕES [ CENSURADO | LIBERADO ] NO MODAL DO VISUALEDITOR
     ------------------------------------------------------------------ */
  function transformLiberadoInputs() {
    var inputs = document.querySelectorAll(
      '.oo-ui-windowManager input, .oo-ui-windowManager textarea, ' +
      '.oo-ui-fieldLayout input, .oo-ui-fieldLayout textarea'
    );

    inputs.forEach(function (input) {
      var container = input.closest('.oo-ui-fieldLayout') ||
                      input.closest('.ve-ui-mwParameterPage') ||
                      input.closest('.oo-ui-pageLayout') ||
                      input.parentElement;
      if (!container) return;

      var txt = (container.textContent || '').toLowerCase();
      if (txt.indexOf('liberado') === -1) return;
      if (container.querySelector('.vtm-toggle-box')) return;

      var box = document.createElement('div');
      box.className = 'vtm-toggle-box';
      box.style.cssText = 'display:flex;gap:12px;margin:10px 0 16px;width:100%;max-width:460px;';

      var btnC = makeToggle('CENSURADO');
      var btnL = makeToggle('LIBERADO');

      function paint(v) {
        v = (v || '').toLowerCase().trim();
        var isLib = (v === 'sim' || v === '1' || v === 'true');
        // Censurado
        btnC.style.background = isLib ? '#121218' : 'linear-gradient(180deg,#5c0f18,#2b060a)';
        btnC.style.color      = isLib ? '#7a7a88' : '#fff';
        btnC.style.border     = isLib ? '1px solid #2d2d38' : '2px solid #ff2a3f';
        btnC.style.boxShadow  = isLib ? 'none' : '0 0 12px rgba(255,42,63,.7)';
        // Liberado
        btnL.style.background = isLib ? 'linear-gradient(180deg,#1b5e20,#0d3814)' : '#121218';
        btnL.style.color      = isLib ? '#fff' : '#7a7a88';
        btnL.style.border     = isLib ? '2px solid #4caf50' : '1px solid #2d2d38';
        btnL.style.boxShadow  = isLib ? '0 0 12px rgba(76,175,80,.7)' : 'none';
      }

      btnC.onclick = function (e) {
        e.preventDefault(); e.stopPropagation();
        setVal(input, 'nao'); paint('nao');
      };
      btnL.onclick = function (e) {
        e.preventDefault(); e.stopPropagation();
        setVal(input, 'sim'); paint('sim');
      };

      input.addEventListener('input', function () { paint(input.value); });
      paint(input.value || 'nao');

      box.appendChild(btnC);
      box.appendChild(btnL);

      var wrap = input.closest('.oo-ui-textInputWidget') ||
                 input.closest('.oo-ui-inputWidget') || input;
      wrap.parentNode.insertBefore(box, wrap);
      wrap.style.display = 'none';
    });
  }

  function makeToggle(label) {
    var b = document.createElement('button');
    b.type = 'button';
    b.textContent = (label === 'CENSURADO' ? '⬛ ' : '🔓 ') + label;
    b.style.cssText = 'flex:1;padding:10px 16px;border-radius:4px;font-weight:800;' +
      'font-size:.9em;cursor:pointer;font-family:"Cinzel",Georgia,serif;' +
      'letter-spacing:1px;transition:all .25s ease;outline:none;';
    return b;
  }

  function setVal(input, v) {
    input.value = v;
    input.dispatchEvent(new Event('input', { bubbles: true }));
    input.dispatchEvent(new Event('change', { bubbles: true }));
    if (window.$) { $(input).trigger('input').trigger('change'); }
  }

  setInterval(transformLiberadoInputs, 300);

  /* ------------------------------------------------------------------
     3. BARRA DE FERRAMENTAS NO EDITOR DE CÓDIGO-FONTE (#wpTextbox1)
     ------------------------------------------------------------------ */
  function initVtmQuickToolbar() {
    var tb = document.getElementById('wpTextbox1');
    if (!tb || document.getElementById('vtm-editor-quickbar')) return;

    var bar = document.createElement('div');
    bar.id = 'vtm-editor-quickbar';
    bar.style.cssText =
      'display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:10px 14px;' +
      'margin:10px 0;background:linear-gradient(90deg,#181014,#0d0d12);' +
      'border:1px solid #3d0a12;border-left:4px solid #8b0000;border-radius:4px;' +
      'font-family:"Cinzel",Georgia,serif;box-shadow:0 4px 14px rgba(0,0,0,.6);z-index:99;';

    var lbl = document.createElement('span');
    lbl.style.cssText = 'color:#c5a059;font-size:.85em;font-weight:700;text-transform:uppercase;letter-spacing:1px;margin-right:6px;';
    lbl.textContent = 'Ferramentas:';
    bar.appendChild(lbl);

    bar.appendChild(makeBtn('⬛ Censurar Trecho', '#240c12', '#ff2a3f', function () {
      wrapSelection(tb, '{{Segredo|', '|liberado=nao}}', 'Texto censurado');
    }));
    bar.appendChild(makeBtn('🔓 Inserir Liberado', '#0d2915', '#2e7d32', function () {
      wrapSelection(tb, '{{Segredo|', '|liberado=sim}}', 'Texto revelado');
    }));
    bar.appendChild(makeBtn('📁 Dossiê Bloco', '#181822', '#3d0a12', function () {
      wrapSelection(tb,
        '\n{{Segredo|tipo=bloco|nivel=CONFIDENCIAL|data=AAAA-MM-DD|dica=Operação|\n',
        '\n}}\n',
        'Relatório confidencial...');
    }));
    bar.appendChild(makeBtn('🗑️ Remover Censura', '#1a1a22', '#4a4a58', function () {
      removeSecret(tb);
    }));

    tb.parentNode.insertBefore(bar, tb);
  }

  function makeBtn(text, bg, border, fn) {
    var b = document.createElement('button');
    b.type = 'button';
    b.textContent = text;
    b.style.cssText =
      'background:' + bg + ';color:#fff;border:1px solid ' + border +
      ';border-radius:3px;padding:6px 12px;font-size:.82em;font-weight:700;' +
      'cursor:pointer;display:inline-flex;align-items:center;gap:4px;transition:all .2s ease;';
    b.onmouseover = function () { b.style.opacity = '.85'; };
    b.onmouseout  = function () { b.style.opacity = '1'; };
    b.onclick = function (e) { e.preventDefault(); fn(); };
    return b;
  }

  function wrapSelection(tb, pre, post, placeholder) {
    var s = tb.selectionStart, e = tb.selectionEnd;
    var txt = tb.value, sel = txt.substring(s, e) || placeholder;
    tb.value = txt.substring(0, s) + pre + sel + post + txt.substring(e);
    tb.focus();
    tb.setSelectionRange(s + pre.length, s + pre.length + sel.length);
    if (window.$) { $(tb).trigger('input').trigger('change'); }
  }

  function removeSecret(tb) {
    var s = tb.selectionStart, text = tb.value;
    var i = text.lastIndexOf('{{Segredo|', s);
    if (i === -1) { alert('Nenhum {{Segredo|...}} encontrado.\nPosicione o cursor dentro do trecho.'); return; }

    var depth = 0, j, end = -1;
    for (j = i; j < text.length - 1; j++) {
      if (text[j] === '{' && text[j+1] === '{') { depth++; j++; }
      else if (text[j] === '}' && text[j+1] === '}') { depth--; if (depth === 0) { end = j + 2; break; } j++; }
    }
    if (end === -1) { alert('Fechamento }} não encontrado.'); return; }

    var inner = text.substring(i + '{{Segredo|'.length, end - 2);
    var parts = [], cur = '', d = 0;
    for (j = 0; j < inner.length; j++) {
      if (inner[j] === '{' && j+1 < inner.length && inner[j+1] === '{') { d++; cur += '{{'; j++; }
      else if (inner[j] === '}' && j+1 < inner.length && inner[j+1] === '}') { d--; cur += '}}'; j++; }
      else if (inner[j] === '|' && d === 0) { parts.push(cur); cur = ''; }
      else { cur += inner[j]; }
    }
    parts.push(cur);

    var content = '';
    for (var k = 0; k < parts.length; k++) {
      if (parts[k].trim().indexOf('=') === -1) { content = parts[k].trim(); break; }
    }

    tb.value = text.substring(0, i) + content + text.substring(end);
    tb.focus();
    tb.setSelectionRange(i, i + content.length);
    if (window.$) { $(tb).trigger('input').trigger('change'); }
  }

  /* ------------------------------------------------------------------
     4. ANIMAÇÃO DE CASCATA DAS SEÇÕES
     ------------------------------------------------------------------ */
  function initSectionAnimation() {
    var c = document.querySelector('.mw-parser-output');
    if (!c || c.dataset.vtmAnimated === 'true') return;
    if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

    c.dataset.vtmAnimated = 'true';
    var kids = Array.from(c.children), secs = [], cur = [];

    kids.forEach(function (ch) {
      if (ch.classList.contains('catlinks') || ch.classList.contains('mw-category-generated') ||
          ch.tagName === 'SCRIPT' || ch.tagName === 'STYLE' || ch.id === 'vtm-editor-quickbar') {
        if (cur.length) { secs.push(cur); cur = []; }
        return;
      }
      if ((ch.tagName === 'H2' || ch.classList.contains('mw-heading2')) && cur.length) {
        secs.push(cur); cur = [];
      }
      cur.push(ch);
    });
    if (cur.length) secs.push(cur);

    secs.forEach(function (items, idx) {
      var w = document.createElement('div');
      w.className = 'vtm-section-block';
      w.style.animationDelay = (0.12 + idx * 0.42).toFixed(2) + 's';
      var f = items[0];
      if (f && f.parentNode) {
        f.parentNode.insertBefore(w, f);
        items.forEach(function (el) { w.appendChild(el); });
      }
    });
  }

  /* ------------------------------------------------------------------
     INICIALIZAÇÃO
     ------------------------------------------------------------------ */
  function initAll() {
    initVtmSecrets();
    initSectionAnimation();
    initVtmQuickToolbar();
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initAll);
  } else {
    initAll();
  }

  if (window.mw && window.mw.hook) {
    window.mw.hook('wikipage.content').add(function () {
      initVtmSecrets();
      initSectionAnimation();
    });
  }
})();