Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.
HTML
<div style="max-width:1200px; margin:0 auto; padding:16px; font-family: Arial, Helvetica, sans-serif; background:#ffffff;">
  <div style="border:1px solid #dfe1e6; border-radius:8px; overflow:hidden;">
    <div style="background:#0052CC; color:#fff; padding:14px 16px;">
    <!--
    Confluence/TDN: Cole este HTML no macro "HTML" (não em bloco de código/preformatado).
    Este arquivo é um SNIPPET (sem <html>/<head>/<body>) para reduzir quebra por sanitização.
  -->

    <div style="displaymax-width:flex1200px; align-items:center; gap:12pxmargin:0 auto; padding:16px; font-family: Arial, Helvetica, sans-serif; background:#ffffff;">
      <div  <img id="totvs-logo" alt="TOTVS"style="border:1px solid #dfe1e6; border-radius:8px; overflow:hidden;">
        <div  style="displaybackground:none#0052CC; heightcolor:28px#fff; width:auto; background:#ffffff; border-radius:6px; padding:4px; border:1px solid rgba(255,255,255,0.35);" /14px 16px;">
          <div idstyle="page-title" style="font-size:18px; font-weight:700;">Dicionário de Dados</div>
display:flex; align-items:center; gap:12px;">
        </div>
    </div>

    <div style="background:#f4f5f7; border-top:1px solid #dfe1e6; padding:12px 16px; display:flex; gap:12px; align-items:center; flex-wrap:wrap;">
!-- TOTVS logo (anexo do Confluence/TDN):
               <div style="display:flex; gap:8px; align-items:center;"> - Nome do anexo: "totvs logo.jpg"
        <div style="font-weight:700; color:#172b4d;">Versão:</div>
      - O <div id="version-display" style="background:#fff; border:1px solid #dfe1e6; border-radius:6px; padding:4px 10px; font-weight:700; color:#172b4d;">-</div>JS abaixo tenta carregar primeiro do pageId atual, e cai em fallback se não achar -->
      </div>

      <img
             <div styleid="display:flex; gap:8px; align-items:center;">
totvs-logo"
         <div style="font-weight:700; color:#172b4d;">Atualizado:</div>
     alt="TOTVS"
           <div id="last-update"   style="backgrounddisplay:#fffnone; borderheight:1px solid #dfe1e6; border28px; width:auto; background:#ffffff; border-radius:6px; padding:4px 10px; color:#172b4d;">-</div>border:1px solid rgba(255,255,255,0.35);"
      </div>

      />
   <a id="doc-link" href="#" target="_blank"
      <div id="page-title" style="display:none; margin-left:auto; text-decoration:none; background:#ffffff; color:#0052CC; border:1px solid #0052CC; border-radius:6px; padding:6px 10px; font-size:18px; font-weight:700;">>Dicionário de Dados</div>
        Abrir no GitHub</div>
      </a>
    </div>

        <div idstyle="widget-container" style="min-height:520px; background:#ffffffbackground:#f4f5f7; border-top:1px solid #dfe1e6; padding:12px 16px; display:flex; gap:12px; align-items:center; flex-wrap:wrap;">
          <div style="paddingdisplay:18pxflex; colorgap:#6b778c8px;">Carregando documento...</div> align-items:center;">
    </div>
  </div>
</div>

<script>
(function() {
  const GITHUB_OWNER = 'Juansimeoni';
  const GITHUB_REPO = 'ReleaseDatasul';
  const GITHUB_BRANCH = 'main';
  const GITHUB_PATH_PREFIX = '';

  const GITHUB_RAW_BASE = 'https://raw.githubusercontent.com/' + GITHUB_OWNER + '/' + GITHUB_REPO + '/' + GITHUB_BRANCH + '/';
  const GITHUB_BLOB_BASE = 'https://github.com/' + GITHUB_OWNER + '/' + GITHUB_REPO + '/blob/' + GITHUB_BRANCH + '/';
  const GITHUB_API_BASE = 'https://api.github.com/repos/' + GITHUB_OWNER + '/' + GITHUB_REPO + '/';

  function buildRepoPath(version) {
    const filename = version + '.txt';
    return GITHUB_PATH_PREFIX ? (GITHUB_PATH_PREFIX + '/' + filename) : filename;
  }

  function setLastUpdateText(text) {
    const el = document.getElementById('last-update');
    if (el) el.textContent = text || '-';
  }

  function formatDatePtBr(value) {
    try {
      const d = new Date(value);
      if (isNaN(d.getTime())) return null;
      return d.toLocaleString('pt-BR');
    } catch (e) {
      return null;
    }
  }

  function tryFetchCommitDate(pathInRepo) {
    const url = GITHUB_API_BASE + 'commits?path=' + encodeURIComponent(pathInRepo) +
      '&sha=' + encodeURIComponent(GITHUB_BRANCH) + '&per_page=1';

    return fetch(url, { cache: 'no-store' })
      .then(function(resp) { if (!resp.ok) return null; return resp.json(); })
      .then(function(arr) {
        if (!arr || !arr.length) return null;        <div style="font-weight:700; color:#172b4d;">Versão:</div>
            <div id="version-display" style="background:#fff; border:1px solid #dfe1e6; border-radius:6px; padding:4px 10px; font-weight:700; color:#172b4d;">-</div>
          </div>

          <div style="display:flex; gap:8px; align-items:center;">
            <div style="font-weight:700; color:#172b4d;">Atualizado:</div>
            <div id="last-update" style="background:#fff; border:1px solid #dfe1e6; border-radius:6px; padding:4px 10px; color:#172b4d;">-</div>
          </div>

          <a id="doc-link" href="#" target="_blank" style="display:none; margin-left:auto; text-decoration:none; background:#ffffff; color:#0052CC; border:1px solid #0052CC; border-radius:6px; padding:6px 10px; font-weight:700;">
            Abrir no GitHub
          </a>
        </div>

        <div id="widget-container" style="min-height:520px; background:#ffffff;">
          <!--
            IMPORTANTE (TDN/Confluence):
            - Se o HTML for colado dentro de um bloco PRE/CODE, o Confluence pode inserir </pre> no final.
              Isso quebra o JavaScript e fica preso em "Carregando...".
          -->
          <div style="padding:18px; color:#6b778c;">Carregando documento...</div>
        const</div>
  c = arr[0] || {}; </div>
    </div>

    const<script>
 commit = c.commit || (function() {};
      // Fonte: const committer = commit.committer || {};
    GitHub (RAW)
      // Repo: https://github.com/Juansimeoni/ReleaseDatasul
    const author = commit.author ||// Arquivo esperado: {versao};
  .txt (ex: 12.1.2503.15.txt)
      return committer.date || author.date || nullconst GITHUB_OWNER = 'Juansimeoni';
      })
   const GITHUB_REPO = 'ReleaseDatasul';
   .catch(function() { return null; });
  }

  function getPageVersion() {
 const GITHUB_BRANCH = 'main';
      const versionPatternGITHUB_PATH_PREFIX = ''; //(\d+\.\d+\.\d+(?:\.\d+)?)/; ex: 'releases' (sem / no início e no fim)

      const pageTitleElementGITHUB_RAW_BASE = document.querySelector('h1#title-text, .page-title, h1, [data-page-title]');
    if (pageTitleElement) {'https://raw.githubusercontent.com/' + GITHUB_OWNER + '/' + GITHUB_REPO + '/' + GITHUB_BRANCH + '/';
      const titleTextGITHUB_BLOB_BASE = (pageTitleElement.textContent || '').trim();
      const match = titleText.match(versionPattern)'https://github.com/' + GITHUB_OWNER + '/' + GITHUB_REPO + '/blob/' + GITHUB_BRANCH + '/';
      if (match) return match[1];
    }

    const metaTitle = document.querySelector('meta[property="og:title"], meta[name="title"]');
    if (metaTitleconst GITHUB_API_BASE = 'https://api.github.com/repos/' + GITHUB_OWNER + '/' + GITHUB_REPO + '/';

      function buildRepoPath(version) {
      const titleText const filename = metaTitle.getAttribute('content') ||version + '.txt';
      const match = titleText.match(versionPattern);
      if (match) return match[1];
return GITHUB_PATH_PREFIX ? (GITHUB_PATH_PREFIX + '/' + filename) : filename;
      }

    const titleMatch =function (document.title || '').match(versionPatternsetLastUpdateText(text) {
        const el = document.getElementById('last-update');
        if (titleMatchel) return titleMatch[1];

el.textContent = text || '-';
    return null;
  }

      function getPageIdformatDatePtBr(value) {
        try {
          const qsd = new URLSearchParams(window.location.searchDate(value);
      const   fromQuery = qs.get('pageId')if (isNaN(d.getTime())) return null;
      if   (fromQuery) return String(fromQueryd.toLocaleString('pt-BR');
        } catch (e) {}


          tryreturn {null;
      if (window.AJS && AJS.params && AJS.params.pageId) return String(AJS.params.pageId);  }
      }

    }  catchfunction tryFetchCommitDate(epathInRepo) {}

    return null;
  }

 // functionBusca setTotvsLogo() {
    const logoEl = document.getElementById('totvs-logo');
o último commit do arquivo (public repo, sem token)
     if (!logoEl) return;

   // Endpoint: /commits?path=...&sha=...&per_page=1
       const pageId// =IMPORTANTE getPageId(TDN/Confluence);:
     const filename = 'totvs logo.jpg';
    const encodedName = encodeURIComponent(filename);

// - O macro pode "escapar" '&' dentro de <script> e quebrar a URL.
    const candidates = [];
 // - Use if (pageId) {
      candidates.push('/download/thumbnails/' + pageId + '/' + encodedName\x26 para montar querystring sem caracteres '&' no HTML.
        const url = GITHUB_API_BASE + 'commits?apipath=v2'); + encodeURIComponent(pathInRepo) +
      candidates.push('/download/attachments/' + pageId + '/\x26sha=' + encodedName);
    }
    candidates.push('/download/attachments/649987902/' + encodedName)encodeURIComponent(GITHUB_BRANCH) + '\x26per_page=1';

    let idx = 0;
 return fetch(url,  function tryNext() {
{ cache: 'no-store' })
       if (idx >= candidates.lengththen(function(resp) return;{
      const url = candidates[idx++];
    if (!resp.ok) return null;
 const probe = new Image();
      probe.onload =return functionresp.json();
 {   logoEl.src = url; logoEl.style.display = 'inline-block'; };)
      probe.onerror = function() { tryNext.then(function(arr); };{
      probe.src  = url;
   if }
    tryNext()(!arr || !arr.length) return null;
  }

   setTotvsLogo();

  const container = document.getElementById('widget-container');
  const docLinkc = document.getElementById('doc-link');

  function renderNotAvailable() {
arr[0] || {};
         container.innerHTML =
  const commit =  '<div style="padding:18px; border-left:4px solid #FFAB00; background:#FFFAE6; color:#172b4d;">' +
c.commit || {};
            const committer '<div style="font-weight:700;">Esse documento ainda não está disponível no momento.</div>' +
= commit.committer || {};
            '</div>';
  }

  function getVersionOverrideFromQuery() {const author = commit.author || {};
    try {
      const qs// =prefer new URLSearchParams(window.location.search);
committer date, fallback author date
          const v =return qs.get('version')committer.date || qs.get('versao');author.date || null;
          })
      if  (v && /^\d+\.\d+\.\d+(?:\.\d+)?$/.test(v)) return v;
    } catch (e) {}
    return null;
  }

  const versionResolved = getVersionOverrideFromQuery() || getPageVersion();

  if (!versionResolved) {
    container.innerHTML =
      '<div style="padding:18px; border-left:4px solid #DE350B; background:#FFEBE6; color:#172b4d;">' +
        '<div style="font-weight:700; margin-bottom:6px;">Versão não identificada</div>' +
        '<div>Coloque a versão no título da página, ex: <b>Dicionário de Dados 12.1.2503.14</b></div>' +
      '</div>';
    return;
  }

  const vEl = document.getElementById('version-display');
  const tEl = document.getElementById('page-title');
  if (vEl) vEl.textContent = versionResolved;
  if (tEl) tEl.textContent = 'Dicionário de Dados ' + versionResolved;
  setLastUpdateText(new Date().toLocaleString('pt-BR'));

  const pathInRepo = buildRepoPath(versionResolved);
  const rawUrl = GITHUB_RAW_BASE + pathInRepo;
  const blobUrl = GITHUB_BLOB_BASE + pathInRepo;

  docLink.href = blobUrl;
  docLink.style.display = 'inline-block';

  container.innerHTML = '<div style="padding:18px; color:#6b778c;">Carregando conteúdo do GitHub...</div>';

  fetch(rawUrl, { cache: 'no-store' })
    .then(function(resp) {
      if (!resp.ok) return { ok: false, text: '', lastModified: null };
      const lm = resp.headers ? resp.headers.get('last-modified') : null;
      return resp.text().then(function(t) { return { ok: true, text: t, lastModified: lm }; });
    })
    .then(function(res) {
      const txt = ((res && res.text) ? res.text : '').trim();
      if (!txt) { renderNotAvailable(); return; }

      const lm = res && res.lastModified ? formatDatePtBr(res.lastModified) : null;
      if (lm) setLastUpdateText(lm);

.catch(function() {
            return null;
          });
      }

      function getPageVersion() {
        const versionPattern = /(\d+\.\d+\.\d+(?:\.\d+)?)/;

        const pageTitleElement = document.querySelector('h1#title-text, .page-title, h1, [data-page-title]');
        if (pageTitleElement) {
          const titleText = (pageTitleElement.textContent || '').trim();
          const match = titleText.match(versionPattern);
          if (match) return match[1];
        }

        const metaTitle = document.querySelector('meta[property="og:title"], meta[name="title"]');
        if (metaTitle) {
          const titleText = metaTitle.getAttribute('content') || '';
          const match = titleText.match(versionPattern);
          if (match) return match[1];
        }

        const titleMatch = (document.title || '').match(versionPattern);
        if (titleMatch) return titleMatch[1];

        return null;
      }

      function getPageId() {
        try {
          const qs = new URLSearchParams(window.location.search);
          const fromQuery = qs.get('pageId');
          if (fromQuery) return String(fromQuery);
        } catch (e) { /* ignore */ }

        // Confluence costuma expor isso quando AJS está disponível
        try {
          // Evite '&&' pois o Confluence pode converter para '&&' dentro de <script> e quebrar o JS.
          if (window.AJS) {
            if (AJS.params) {
              if (AJS.params.pageId) return String(AJS.params.pageId);
            }
          }
        } catch (e) { /* ignore */ }

        return null;
      }

      function setTotvsLogo() {
        const logoEl = document.getElementById('totvs-logo');
        if (!logoEl) return;

        const pageId = getPageId();
        const filename = 'totvs logo.jpg';
        const encodedName = encodeURIComponent(filename);

        const candidates = [];
        if (pageId) {
          // thumbnails costuma funcionar melhor no Confluence
          candidates.push('/download/thumbnails/' + pageId + '/' + encodedName + '?api=v2');
          candidates.push('/download/attachments/' + pageId + '/' + encodedName);
        }
        // fallback: página “principal” antiga (se existir o anexo lá também)
        candidates.push('/download/attachments/649987902/' + encodedName);

        let idx = 0;
        function tryNext() {
          // Evite '>=' pois o Confluence pode converter para '>=' dentro de <script> e quebrar o JS.
          if (idx === candidates.length) return;
          const url = candidates[idx++];
          const probe = new Image();
          probe.onload = function() {
            logoEl.src = url;
            logoEl.style.display = 'inline-block';
          };
          probe.onerror = function() {
            tryNext();
          };
          probe.src = url;
        }

        tryNext();
      }

      // Tenta resolver o logo mesmo antes de identificar versão/documento
      setTotvsLogo();

      function renderNotAvailable() {
        // Mantém o link (se existir) para permitir abrir manualmente no GitHub
        container.innerHTML =
          '<div style="padding:18px; border-left:4px solid #FFAB00; background:#FFFAE6; color:#172b4d;">' +
            '<div style="font-weight:700;">Esse documento ainda não está disponível no momento.</div>' +
          '</div>';
      }

      function getVersionOverrideFromQuery() {
        try {
          const qs = new URLSearchParams(window.location.search);
          const v = qs.get('version') || qs.get('versao');
          // Evite '&&' pois o Confluence pode converter para '&&' dentro de <script> e quebrar o JS.
          if (v) {
            if (/^\d+\.\d+\.\d+(?:\.\d+)?$/.test(v)) return v;
          }
        } catch (e) { /* ignore */ }
        return null;
      }

      const version = getPageVersion();
      const container = document.getElementById('widget-container');
      const docLink = document.getElementById('doc-link');

      const versionResolved = getVersionOverrideFromQuery() || version;

      if (!versionResolved) {
        container.innerHTML =
          '<div style="padding:18px; border-left:4px solid #DE350B; background:#FFEBE6; color:#172b4d;">' +
            '<div style="font-weight:700; margin-bottom:6px;">Versão não identificada</div>' +
            '<div>Coloque a versão no título da página, ex: <b>Dicionário de Dados 12.1.2503.14</b></div>' +
          '</div>';
        return;
      }

      document.getElementById('version-display').textContent = versionResolved;
      document.getElementById('page-title').textContent = 'Dicionário de Dados ' + versionResolved;
      setLastUpdateText(new Date().toLocaleString('pt-BR'));

      const pathInRepo = buildRepoPath(versionResolved);
      const rawUrl = GITHUB_RAW_BASE + pathInRepo;
      const blobUrl = GITHUB_BLOB_BASE + pathInRepo;

      // Link para o GitHub (visual)
      docLink.href = blobUrl;
      docLink.textContent = 'Abrir no GitHub';
      docLink.style.display = 'inline-block';

      container.innerHTML =
        '<div style="padding:18px; color:#6b778c;">Carregando conteúdo do GitHub...</div>';

      fetch(rawUrl, { cache: 'no-store' })
        .then(function(resp) {
          if (!resp.ok) return { ok: false, text: '', lastModified: null };
          const lm = resp.headers ? resp.headers.get('last-modified') : null;
          return resp.text().then(function(t) {
            return { ok: true, text: t, lastModified: lm };
          });
        })
        .then(function(res) {
          // Evite '&&' pois o Confluence pode converter para '&&' dentro de <script> e quebrar o JS.
          const txt = ((res ? res.text : '') || '').trim();
          if (!txt) {
            renderNotAvailable();
            return;
          }

          // 1) Fallback rápido: Last-Modified do RAW (não é exatamente "commit date", mas aproxima)
          // Evite '&&' pois o Confluence pode converter para '&&' dentro de <script> e quebrar o JS.
          const lm = (res ? (res.lastModified ? formatDatePtBr(res.lastModified) : null) : null);
          if (lm) setLastUpdateText(lm);

          // 2) Data real do commit via GitHub API (se permitido por CSP)
          tryFetchCommitDate(pathInRepo).then(function(commitIso) {
            const formatted = commitIso ? formatDatePtBr(commitIso) : null;
            if (formatted) setLastUpdateText(formatted);
      });

;
          });

          // Renderiza texto em <pre> preservando formatação
          const pre = document.createElement('pre');
          pre.style.whiteSpace = 'pre-wrap';
          pre.style.margin = '0';
          pre.style.padding = '16px';
          pre.style.borderTop = '1px solid #dfe1e6';
          pre.style.fontFamily = 'Consolas, Menlo, Monaco, \"Courier New\", monospace';
          pre.textContent = txt;

          container.innerHTML = '';
          container.appendChild(pre);
        })
        .catch(function() {
          renderNotAvailable();
        });
    })(); 
    </script>