1(function () { 2 "use strict"; 3 4 const CLIENT_ID = "49cbb3ba-84fc-452f-a3d1-63112a8d8f76"; 5 const TOKEN_URL = "https://www.wixapis.com/oauth2/token"; 6 const POSTS_QUERY_URL = "https://www.wixapis.com/v3/posts/query"; 7 const POST_BY_SLUG_URL = "https://www.wixapis.com/v3/posts/slugs/"; 8 const CATEGORIES_URL = "https://www.wixapis.com/blog/v3/categories"; 9 const PAGE_SIZE = 6; 10 const PAGE_WINDOW = 3; // números exibidos em torno da página atual (mÃnimo 3), além de primeira/última 11 const TOKEN_KEY = "infonova_wix_visitor_token_v1"; 12 const fallback = (window.INFONOVA_BLOG_FALLBACK && window.INFONOVA_BLOG_FALLBACK.posts) || []; 13 14 const state = { 15 mode: "loading", 16 categories: [], 17 liveCategories: [], 18 page: 1, 19 total: 0, 20 hasNext: false, 21 categoryId: null, 22 categoryLabel: null, 23 search: "" 24 }; 25 26 function escapeHtml(value) { 27 return String(value == null ? "" : value) 28 .replace(/&/g, "&") 29 .replace(/</g, "<") 30 .replace(/>/g, ">") 31 .replace(/"/g, """) 32 .replace(/'/g, "'"); 33 } 34 35 function safeUrl(value) { 36 const raw = String(value || "").trim(); 37 if (!raw) return ""; 38 if (/^(javascript|data):/i.test(raw)) return ""; 39 return raw; 40 } 41 42 function formatDate(value) { 43 if (!value) return ""; 44 const d = new Date(value); 45 if (Number.isNaN(d.getTime())) return ""; 46 return new Intl.DateTimeFormat("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric", timeZone: "America/Sao_Paulo" }).format(d); 47 } 48 49 function fallbackCategories() { 50 const labels = []; 51 fallback.forEach(post => (post.categories || []).forEach(label => { 52 if (label && !labels.includes(label)) labels.push(label); 53 })); 54 return labels.sort((a,b) => a.localeCompare(b, "pt-BR")).map(label => ({ id: "fallback:" + label, label })); 55 } 56 57 async function getVisitorToken() { 58 try { 59 const cached = JSON.parse(sessionStorage.getItem(TOKEN_KEY) || "null"); 60 if (cached && cached.accessToken && cached.expiresAt > Date.now() + 60000) return cached.accessToken; 61 } catch (_) {} 62 63 const response = await fetch(TOKEN_URL, { 64 method: "POST", 65 headers: { "Content-Type": "application/json" }, 66 body: JSON.stringify({ clientId: CLIENT_ID, grantType: "anonymous" }) 67 }); 68 const data = await response.json().catch(() => ({})); 69 if (!response.ok || !data.access_token) throw new Error("Não foi possÃvel autenticar a leitura do Wix Blog."); 70 const tokenData = { 71 accessToken: data.access_token, 72 expiresAt: Date.now() + Math.max(60, Number(data.expires_in || 3600) - 60) * 1000 73 }; 74 try { sessionStorage.setItem(TOKEN_KEY, JSON.stringify(tokenData)); } catch (_) {} 75 return tokenData.accessToken; 76 } 77 78 async function wixFetch(url, options) { 79 const token = await getVisitorToken(); 80 const opts = Object.assign({}, options || {}); 81 opts.headers = Object.assign({ "Content-Type": "application/json", "Authorization": token }, opts.headers || {}); 82 const response = await fetch(url, opts); 83 const data = await response.json().catch(() => ({})); 84 if (!response.ok) { 85 const err = new Error("Wix Blog retornou HTTP " + response.status); 86 err.status = response.status; 87 err.data = data; 88 throw err; 89 } 90 return data; 91 } 92 93 async function getCategories() { 94 const data = await wixFetch(CATEGORIES_URL + "?fieldsets=URL", { method: "GET" }); 95 return data.categories || []; 96 } 97 98 async function queryPosts(params) { 99 params = params || {}; 100 const query = {}; 101 const filter = {}; 102 if (params.categoryId) filter.categoryIds = { "$hasSome": [params.categoryId] }; 103 if (params.search) filter.title = { "$startsWith": params.search };
104 if (Object.keys(filter).length) query.filter = filter; 105 query.sort = [{ fieldName: "firstPublishedDate", order: "DESC" }]; 106 // Paginação por offset: devolve pagingMetadata.total, permitindo numeração real de páginas. 107 query.paging = { limit: PAGE_SIZE, offset: Math.max(0, Number(params.offset) || 0) }; 108 return wixFetch(POSTS_QUERY_URL, { 109 method: "POST", 110 body: JSON.stringify({ fieldsets: ["URL"], query }) 111 }); 112 } 113 114 async function getPostBySlug(slug) { 115 const query = new URLSearchParams(); 116 query.append("fieldsets", "RICH_CONTENT"); 117 query.append("fieldsets", "SEO"); 118 query.append("fieldsets", "URL"); 119 return wixFetch(POST_BY_SLUG_URL + encodeURIComponent(slug) + "?" + query.toString(), { method: "GET" }); 120 } 121 122 function liveImage(post) { 123 return safeUrl( 124 post && post.media && post.media.wixMedia && post.media.wixMedia.image && post.media.wixMedia.image.url || 125 post && post.heroImage && post.heroImage.url || "" 126 ); 127 } 128 129 function categoryLabels(post) { 130 if (post && Array.isArray(post.categories) && post.categories.length) return post.categories; 131 const ids = (post && post.categoryIds) || []; 132 return ids.map(id => { 133 const found = state.liveCategories.find(c => c.id === id); 134 return found ? found.label : ""; 135 }).filter(Boolean); 136 } 137 138 function postHref(slug) { 139 if ((slug || "") === "governanca-de-ti") return "/governanca-de-ti-insight.html"; 140 return "/" + encodeURIComponent(slug || "") + ".html"; 141 } 142 143 function cardHtml(post) { 144 const slug = post.slug || post.seoSlug || ""; 145 const href = postHref(slug); 146 const cats = categoryLabels(post).slice(0, 2); 147 const image = post.image || liveImage(post) || "assets/images/blog/blog-list-1-1.jpg";
148 const title = post.title || "Insight Infonova"; 149 const excerpt = post.excerpt || post.contentText || ""; 150 const author = post.author || "Infonova"; 151 const date = formatDate(post.firstPublishedDate || post.date); 152 return ` 153 <article class="blog-list__single wix-blog-card"> 154 <div class="blog-list__img wix-blog-card__image"> 155 <a href="${href}" aria-label="Abrir ${escapeHtml(title)}"><img src="${escapeHtml(image)}" alt="${escapeHtml(title)}" loading="lazy" decoding="async"></a> 156 ${cats.length ? `<div class="blog-list__tags">${cats.map(c => `<span>${escapeHtml(c)}</span>`).join("")}</div>` : ""} 157 </div> 158 <div class="blog-list__content"> 159 <ul class="blog-list__meta list-unstyled"> 160 <li class="d-flex align-items-center gap-3"> 161 <a href="${href}"><span class="far fa-calendar-alt"></span>${escapeHtml(date)}</a> 162 <span>â¢</span> 163 <a href="${href}"><span class="far fa-user"></span>${escapeHtml(author)}</a> 164 </li> 165 </ul> 166 <h3 class="blog-list__title"><a href="${href}">${escapeHtml(title)}</a></h3> 167 <p class="blog-list__text">${escapeHtml(excerpt)}</p> 168 <div class="blog-list__btn-box"><a href="${href}" class="thm-btn">Saiba Mais<span class="icon-right-arrow"></span></a></div> 169 </div> 170 </article>`; 171 } 172 173 function renderList(posts) { 174 const target = document.getElementById("wix-blog-list"); 175 if (!target) return; 176 if (!posts || !posts.length) { 177 target.innerHTML = `<div class="wix-blog-empty"><h3>Nenhum insight encontrado.</h3><p>Tente outra busca ou categoria.</p></div>`; 178 return; 179 } 180 target.innerHTML = posts.map(cardHtml).join(""); 181 } 182 183 /* ------------------------------------------------------------- 184 Paginação 185 O CSS do template (blog.css) força `transform: rotate(180deg)` 186 no 6º <li>, partindo do pressuposto de que a lista sempre teria 187 exatamente 6 itens. Com paginação dinâmica isso girava um número 188 de página de cabeça para baixo. O bloco abaixo neutraliza a regra 189 e cuida do estado "disabled" e das reticências. 190 ------------------------------------------------------------- */ 191 function ensurePaginationStyles() { 192 if (document.getElementById("wix-blog-pagination-style")) return; 193 const style = document.createElement("style"); 194 style.id = "wix-blog-pagination-style"; 195 style.textContent = ` 196#wix-blog-pagination .pg-pagination li:nth-child(n) a, 197#wix-blog-pagination .pg-pagination li:nth-child(n) a:before, 198#wix-blog-pagination .pg-pagination li:nth-child(n) a:after { transform: none; } 199#wix-blog-pagination .pg-pagination li.disabled a { opacity: .35; pointer-events: none; cursor: default; } 200#wix-blog-pagination .pg-pagination li.gap { color: currentColor; opacity: .55; padding: 0 4px; line-height: 48px; font-weight: 500; user-select: none; } 201#wix-blog-pagination .pg-pagination li a[data-nav] span { display: inline-block; line-height: inherit; } 202@media (max-width: 767px) { 203 #wix-blog-pagination .pg-pagination { gap: 6px; } 204 #wix-blog-pagination .pg-pagination li a { height: 40px; width: 40px; line-height: 40px; font-size: 16px; } 205 #wix-blog-pagination .pg-pagination li.gap { line-height: 40px; padding: 0 2px; } 206} 207`; 208 document.head.appendChild(style); 209 } 210 211 // Janela de páginas: sempre tenta exibir pelo menos 3 números. 212 function pageWindow(current, totalPages) { 213 const size = Math.max(3, PAGE_WINDOW); 214 if (totalPages <= size) { 215 const all = []; 216 for (let i = 1; i <= totalPages; i++) all.push(i); 217 return all; 218 } 219 let start = Math.max(1, current - Math.floor(size / 2)); 220 let end = start + size - 1; 221 if (end > totalPages) { end = totalPages; start = end - size + 1; } 222 const items = []; 223 if (start > 1) { 224 items.push(1); 225 if (start > 2) items.push("gap"); 226 } 227 for (let i = start; i <= end; i++) items.push(i); 228 if (end < totalPages) { 229 if (end < totalPages - 1) items.push("gap"); 230 items.push(totalPages); 231 } 232 return items; 233 } 234 235 function goToPage(page, totalPages) { 236 const target = Math.min(Math.max(1, page), Math.max(1, totalPages)); 237 if (target === state.page) return; 238 state.page = target; 239 if (state.mode === "live") { loadLive().catch(() => loadFallback()); } 240 else { loadFallback(); } 241 scrollToList(); 242 } 243 244 function renderPagination(meta) { 245 const target = document.getElementById("wix-blog-pagination"); 246 if (!target) return; 247 ensurePaginationStyles(); 248 249 const total = Number(meta && meta.total); 250 let totalPages; 251 if (Number.isFinite(total) && total > 0) { 252 totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE)); 253 } else { 254 // Sem "total" na resposta: deduz o mÃnimo possÃvel a partir de hasNext. 255 totalPages = state.page + ((meta && meta.hasNext) || state.hasNext ? 1 : 0); 256 } 257 258 if (totalPages <= 1) { target.innerHTML = ""; return; } 259 if (state.page > totalPages) state.page = totalPages; 260 261 const items = pageWindow(state.page, totalPages).map(item => { 262 if (item === "gap") return `<li class="gap" aria-hidden="true">â¦</li>`; 263 const isActive = item === state.page; 264 return `<li class="count ${isActive ? "active" : ""}"><a href="#" data-page="${item}" aria-label="Página ${item}"${isActive ? ' aria-current="page"' : ""}>${String(item).padStart(2, "0")}</a></li>`; 265 }).join(""); 266 267 const canPrev = state.page > 1; 268 const canNext = state.page < totalPages; 269 270 target.innerHTML = `<ul class="pg-pagination list-unstyled" role="navigation" aria-label="Paginação dos insights"> 271 <li class="prev ${canPrev ? "" : "disabled"}"><a href="#" data-nav="prev" aria-label="Página anterior"><span class="icon-left-arrow-1"></span></a></li> 272 ${items} 273 <li class="next ${canNext ? "" : "disabled"}"><a href="#" data-nav="next" aria-label="Próxima página"><span class="icon-right-arrow-1"></span></a></li> 274 </ul>`; 275 276 target.querySelectorAll("[data-page]").forEach(a => a.addEventListener("click", e => { 277 e.preventDefault(); 278 goToPage(Number(a.dataset.page), totalPages); 279 })); 280 const prev = target.querySelector('[data-nav="prev"]'); 281 const next = target.querySelector('[data-nav="next"]'); 282 if (prev) prev.addEventListener("click", e => { e.preventDefault(); if (canPrev) goToPage(state.page - 1, totalPages); }); 283 if (next) next.addEventListener("click", e => { e.preventDefault(); if (canNext) goToPage(state.page + 1, totalPages); }); 284 } 285 286 function scrollToList() { 287 const el = document.querySelector(".blog-list"); 288 if (el) window.scrollTo({ top: Math.max(0, el.getBoundingClientRect().top + window.scrollY - 120), behavior: "smooth" }); 289 } 290 291 function renderCategories(categories) { 292 state.categories = categories || []; 293 const target = document.getElementById("wix-blog-categories"); 294 if (!target) return;
295 const all = `<li class="${!state.categoryId && !state.categoryLabel ? "active" : ""}"><a href="#" data-category-all>Todos os insights</a></li>`; 296 target.innerHTML = all + state.categories.map(c => `<li class="${state.categoryId === c.id || state.categoryLabel === c.label ? "active" : ""}"><a href="#" data-category-id="${escapeHtml(c.id)}" data-category-label="${escapeHtml(c.label)}">${escapeHtml(c.label)}</a></li>`).join(""); 297 const reset = target.querySelector("[data-category-all]"); 298 if (reset) reset.addEventListener("click", e => { e.preventDefault(); state.categoryId = null; state.categoryLabel = null; resetPaging(); refreshList(); }); 299 target.querySelectorAll("[data-category-id]").forEach(a => a.addEventListener("click", e => { 300 e.preventDefault(); 301 if (state.mode === "live") { state.categoryId = a.dataset.categoryId; state.categoryLabel = a.dataset.categoryLabel; } 302 else { state.categoryId = null; state.categoryLabel = a.dataset.categoryLabel; } 303 resetPaging(); refreshList(); 304 })); 305 } 306 307 function resetPaging() { state.page = 1; state.total = 0; state.hasNext = false; } 308 309 function filteredFallback() { 310 const q = state.search.trim().toLocaleLowerCase("pt-BR"); 311 return fallback.filter(post => { 312 const catOk = !state.categoryLabel || (post.categories || []).includes(state.categoryLabel); 313 const hay = ((post.title || "") + " " + (post.excerpt || "")).toLocaleLowerCase("pt-BR"); 314 const qOk = !q || hay.includes(q); 315 return catOk && qOk; 316 }); 317 } 318 319 function loadFallback() { 320 state.mode = "fallback"; 321 const all = filteredFallback(); 322 const totalPages = Math.max(1, Math.ceil(all.length / PAGE_SIZE)); 323 if (state.page > totalPages) state.page = totalPages; 324 const start = (state.page - 1) * PAGE_SIZE; 325 state.total = all.length; 326 state.hasNext = state.page < totalPages; 327 renderList(all.slice(start, start + PAGE_SIZE)); 328 renderPagination({ total: all.length }); 329 renderCategories(fallbackCategories()); 330 } 331 332 async function loadLive() { 333 const data = await queryPosts({ 334 offset: (state.page - 1) * PAGE_SIZE, 335 categoryId: state.categoryId, 336 search: state.search.trim() 337 }); 338 const posts = data.posts || []; 339 const meta = data.pagingMetadata || {}; 340 state.total = Number(meta.total) || state.total; 341 state.hasNext = !!meta.hasNext; 342 renderList(posts); 343 renderPagination(meta); 344 renderCategories(state.liveCategories); 345 return posts.length; 346 } 347 348 async function refreshList() { 349 if (state.mode === "live") { 350 try { await loadLive(); return; } catch (err) { console.warn("Wix Blog indisponÃvel, usando fallback visual.", err); } 351 } 352 loadFallback(); 353 } 354 355 function setupSearch() { 356 const form = document.getElementById("wix-blog-search-form"); 357 const input = document.getElementById("wix-blog-search-input"); 358 if (!form || !input) return; 359 form.addEventListener("submit", e => { 360 e.preventDefault(); 361 state.search = input.value || ""; 362 resetPaging(); 363 refreshList(); 364 }); 365 } 366 367 async function initList() { 368 setupSearch(); 369 try { 370 state.liveCategories = await getCategories(); 371 const data = await queryPosts({ offset: 0 }); 372 const livePosts = data.posts || []; 373 if (livePosts.length) { 374 state.mode = "live"; 375 const meta = data.pagingMetadata || {}; 376 state.total = Number(meta.total) || 0; 377 state.hasNext = !!meta.hasNext; 378 renderList(livePosts); 379 renderPagination(meta); 380 renderCategories(state.liveCategories); 381 return; 382 } 383 } catch (err) { 384 console.warn("Preview do Wix Blog: ainda sem publicações ao vivo; exibindo fallback visual.", err); 385 } 386 loadFallback(); 387 } 388 389 function wixImageSrc(imageLike) { 390 if (!imageLike) return ""; 391 if (imageLike.url) return safeUrl(imageLike.url); 392 if (imageLike.src && imageLike.src.url) return safeUrl(imageLike.src.url); 393 const id = imageLike.id || (imageLike.src && imageLike.src.id); 394 return id ? "https://static.wixstatic.com/media/" + encodeURIComponent(id).replace(/%7E/g, "~") : ""; 395 } 396 397 function normalizeInternalLink(url) { 398 const raw = safeUrl(url); 399 if (!raw) return ""; 400 try { 401 const parsed = new URL(raw, window.location.href); 402 const host = parsed.hostname.replace(/^www\./, "").toLowerCase(); 403 if (host === "infonova.com.br") { 404 const parts = parsed.pathname.split("/").filter(
404Boolean); 405 const last = parts[parts.length - 1] || ""; 406 if (last && !last.includes(".") && !["solucoes","cases","sobre","contato","metodologia"].includes(last)) return postHref(last); 407 } 408 } catch (_) {} 409 return raw; 410 } 411 412 function renderTextNode(node) { 413 let value = escapeHtml(node && node.textData && node.textData.text || ""); 414 const decorations = node && node.textData && node.textData.decorations || []; 415 decorations.forEach(dec => { 416 const type = dec.type || ""; 417 if (type === "BOLD") value = `<strong>${value}</strong>`; 418 else if (type === "ITALIC") value = `<em>${value}</em>`; 419 else if (type === "UNDERLINE") value = `<u>${value}</u>`; 420 else if (type === "LINK" && dec.linkData && dec.linkData.link) { 421 const link = dec.linkData.link; 422 const href = normalizeInternalLink(link.url || ""); 423 if (href) value = `<a href="${escapeHtml(href)}"${link.target === "BLANK" ? ' target="_blank" rel="noopener"' : ""}>${value}</a>`; 424 } 425 }); 426 return value; 427 } 428 429 function renderRicosNode(node) { 430 if (!node) return ""; 431 const children = () => (node.nodes || []).map(renderRicosNode).join(""); 432 switch (node.type) { 433 case "TEXT": return renderTextNode(node); 434 case "PARAGRAPH": return `<p>${children()}</p>`; 435 case "HEADING": { 436 const level = Math.min(6, Math.max(2, Number(node.headingData && node.headingData.level || 2))); 437 return `<h${level}>${children()}</h${level}>`; 438 } 439 case "BULLETED_LIST": return `<ul>${children()}</ul>`; 440 case "ORDERED_LIST": return `<ol>${children()}</ol>`; 441 case "LIST_ITEM": return `<li>${children()}</li>`; 442 case "BLOCKQUOTE": return `<blockquote>${children()}</blockquote>`; 443 case "CODE_BLOCK": return `<pre><code>${children()}</code></pre>`; 444 case "DIVIDER": return `<hr>`; 445 case "IMAGE": { 446 const data = node.imageData || {}; 447 const src = wixImageSrc(data.image); 448 if (!src) return ""; 449 const alt = data.altText || ""; 450 const linked = data.link && data.link.url ? normalizeInternalLink(data.link.url) : ""; 451 const img = `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" loading="lazy" decoding="async">`; 452 return linked ? `<p class="wix-blog-rich-image"><a href="${escapeHtml(linked)}">${img}</a></p>` : `<p class="wix-blog-rich-image">${img}</p>`; 453 } 454 case "BUTTON": { 455 const data = node.buttonData || {}; 456 const href = data.link ? normalizeInternalLink(data.link.url || "") : ""; 457 return href ? `<p><a class="thm-btn" href="${escapeHtml(href)}">${escapeHtml(data.text || "Saiba mais")}<span class="icon-right-arrow"></span></a></p>` : ""; 458 } 459 case "TABLE": return `<div class="wix-blog-table-wrap"><table>${children()}</table></div>`; 460 case "TABLE_ROW": return `<tr>${children()}</tr>`; 461 case "TABLE_CELL": return `<td>${children()}</td>`; 462 case "CAPTION": return `<figcaption>${children()}</figcaption>`; 463 case "LAYOUT": case "LAYOUT_CELL": case "CARD": case "SMART_BLOCK": case "SMART_BLOCK_CELL": return children(); 464 default: return children(); 465 } 466 } 467 468 function renderRicos(richContent) { 469 if (!richContent || !Array.isArray(richContent.nodes)) return ""; 470 return richContent.nodes.map(renderRicosNode).join(""); 471 } 472 473 function findFallback(slug) { return fallback.find(p => p.slug === slug) || null; } 474 475 function setMeta(post) {
476 const title = post.title || "Insight Infonova"; 477 document.title = title + " | Infonova"; 478 const heading = document.getElementById("wix-blog-page-title"); 479 if (heading) heading.textContent = title; 480 let desc = document.querySelector('meta[name="description"]'); 481 if (!desc) { desc = document.createElement("meta"); desc.name = "description"; document.head.appendChild(desc); } 482 desc.content = String(post.excerpt || post.contentText || "").replace(/\s+/g, " ").slice(0, 160); 483 484 const slug = post.slug || post.seoSlug || slugFromLocation(); 485 const canonicalUrl = slug ? "https://www.infonova.com.br" + postHref(slug) : "https://www.infonova.com.br/blog.html"; 486 let canonical = document.querySelector('link[rel="canonical"]'); 487 if (!canonical) { canonical = document.createElement("link"); canonical.rel = "canonical"; document.head.appendChild(canonical); } 488 canonical.href = canonicalUrl; 489 490 const setMetaProp = (property, content) => { 491 let el = document.querySelector('meta[property="' + property + '"]'); 492 if (!el) { el = document.createElement("meta"); el.setAttribute("property", property); document.head.appendChild(el); } 493 el.setAttribute("content", content || ""); 494 }; 495 setMetaProp("og:type", "article"); 496 setMetaProp("og:title", title); 497 setMetaProp("og:description", desc.content); 498 setMetaProp("og:url", canonicalUrl); 499 const image = post.image || liveImage(post); 500 if (image) setMetaProp("og:image", image); 501 } 502 503 async function renderArticle(post, isFallback) { 504 const target = document.getElementById("wix-blog-article"); 505 if (!target) return; 506 setMeta(post); 507 let cats = categoryLabels(post); 508 if (!cats.length && isFallback) cats = post.categories || []; 509 const image = post.image || liveImage(post); 510 const date = formatDate(post.firstPublishedDate || post.date); 511 const author = post.author || "Infonova"; 512 const body = isFallback ? (post.contentHtml || "") : renderRicos(post.richContent); 513 target.innerHTML = ` 514 <div class="blog-details__single-content"> 515 <ul class="blog-details__meta list-unstyled"> 516 <li><a href="/blog.html"><span class="far fa-calendar-alt"></span>${escapeHtml(date)}</a></li> 517 ${cats.length ? `<li><a href="/blog.html"><span class="far fa-folder"></span>${escapeHtml(cats[0])}</a></li>` : ""} 518 </ul> 519 </div> 520 ${image ? `<div class="blog-details__img wix-blog-hero"><img src="${escapeHtml(image)}" alt="${escapeHtml(post.title || "")}" decoding="async"></div>` : ""} 521 <div class="wix-blog-rich-content">${body || `<p>${escapeHtml(post.excerpt || "Conteúdo indisponÃvel.")}</p>`}</div> 522 ${cats.length ? `<ul class="blog-details__meta list-unstyled wix-blog-bottom-tags"><li class="tags d-flex flex-column flex-lg-row align-items-baseline gap-3"><a class="mb-3" href="/blog.html"><span class="far fa-tag"></span>Tags: </a><div class="d-flex align-items-center gap-2 flex-wrap">${cats.map(c => `<span><a href="/blog.html">${escapeHtml(c)}</a></span>`).join("")}</div></li></ul>` : ""} 523 <div class="blog-details__single-content autor d-flex align-items-center align-items-lg-start flex-lg-row flex-column gap-3 wix-blog-author"><div class="nome text-center text-lg-start"><h2>${escapeHtml(author)}</h2><p>Conteúdo publicado pela Infonova Tecnologia</p></div></div>`; 524 } 525 526 function slugFromLocation() { 527 const params = new URLSearchParams(window.location.search); 528 const q = params.get("slug"); 529 if (q) return q; 530 const parts = window.location.pathname.split("/").filter(Boolean); 531 const last = parts[parts.length - 1] || ""; 532 if (last === "governanca-de-ti-insight.html") return "governanca-de-ti"; 533 if (last.endsWith(".html") && !["insight-interno.html", "insight.html", "blog.html"].includes(last)) return decodeURIComponent(last.slice(0, -5)); 534 return last && !last.endsWith(".html") ? decodeURIComponent(last) : ""; 535 } 536 537 async function initArticle() { 538 const slug = slugFromLocation() || (fallback[0] && fallback[0].slug) || ""; 539 if (!slug) return; 540 try { 541 state.liveCategories = await getCategories(); 542 const data = await getPostBySlug(slug); 543 if (data && data.post) { await renderArticle(data.post, false); return; } 544 } catch (err) { 545 console.warn("Artigo ainda não está publicado no Wix Blog; usando fallback visual quando disponÃvel.", err); 546 } 547 const local = findFallback(slug); 548 if (local) { await renderArticle(local, true); return; } 549 const target = document.getElementById("wix-blog-article"); 550 if (target) target.innerHTML = `<div class="wix-blog-empty"><h3>Insight ainda não disponÃvel.</h3><p>
550Este artigo está em preparação no novo blog da Infonova.</p><p><a href="/blog.html" class="thm-btn">Voltar aos insights<span class="icon-right-arrow"></span></a></p></div>`; 551 } 552 553 window.InfonovaWixBlog = { initList, initArticle }; 554})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.