Xcommunicada: Comics and Graphic Novels as Social Critique
Dr. Lizbette Ocasio-Russe, professor of creative writing at Southern New Hampshire University, discusses t he power of comics and graphic novels and their role of problematizing canonic literature. Her webcomic “Xcommunicada” uses fictional storylines set in nonfictional places to critique heteropatriarchal hegemony that shaped political, economic, and social forces by colonizing and eradicating indigenous natives and their beliefs. “Xcommunicada” celebrates humanity and embraces diverse beliefs, as demonstrated by the protagonist who must get in touch with her ancestors鈥 native beliefs in order to defeat the evil plaguing her home.
exists ---
(function ensure40pxInlineEarly() {
function set40(el) { el && el.style.setProperty('padding-top', '40px', 'important'); }
// If header already parsed, set now; otherwise set as soon as it appears.
const hdrNow = document.getElementById(HEADER_ID);
if (hdrNow) { set40(hdrNow); return; }
new MutationObserver((muts, obs) => {
const hdr = document.getElementById(HEADER_ID);
if (hdr) { set40(hdr); obs.disconnect(); }
}).observe(document.documentElement, { childList: true, subtree: true });
})();
// --- Helpers ---
function hideDiviBars() {
document.querySelectorAll('.divibars-container').forEach(div => {
const content = (div.textContent || '').replace(/\u00A0/g, ' ').trim();
const shouldHide =
!content ||
/all\s*clear/i.test(content) ||
/test/i.test(content) ||
/feed\s*has\s*no\s*items\.?/i.test(content);
if (shouldHide) div.style.setProperty('display', 'none', 'important');
});
}
function isEffectivelyVisible(el) {
if (!el || !el.isConnected) return false;
const target = el.querySelector('.divibars, .divibars-wrapper, .divibars-content') || el;
const cs = getComputedStyle(target);
if (cs.display === 'none' || cs.visibility === 'hidden' || target.hidden) return false;
if (parseFloat(cs.opacity || '1') < 0.05) return false;
if (target.closest('[aria-hidden="true"]')) return false;
const rect = target.getBoundingClientRect();
const hasSize = (rect.width > 0 && rect.height > 0) || (target.offsetWidth > 0 && target.offsetHeight > 0);
if (!hasSize) return false;
const vh = window.innerHeight || document.documentElement.clientHeight;
return rect.bottom > 0 && rect.top < vh;
}
function anyRealBannerVisible() {
// A 鈥渞eal鈥 banner = visible AND not empty/test/all-clear/feed-empty
return Array.from(document.querySelectorAll(CANDS)).some(el => {
if (!isEffectivelyVisible(el)) return false;
const txt = (el.textContent || '').replace(/\u00A0/g, ' ').trim();
if (!txt) return false;
if (/all\s*clear/i.test(txt) || /test/i.test(txt) || /feed\s*has\s*no\s*items\.?/i.test(txt)) return false;
return true;
});
}
function setForce110(on) {
const root = document.documentElement;
const was = root.classList.contains('divibar-force-110');
if (!!on === was) return;
root.classList.add('divibar-atomic');
root.classList.toggle('divibar-force-110', !!on);
// If we鈥檙e NOT forcing 110, clear any stray inline 110 the plugin may add later.
if (!on) {
const hdr = document.getElementById(HEADER_ID);
if (hdr) hdr.style.setProperty('padding-top', '40px', 'important');
}
requestAnimationFrame(() => root.classList.remove('divibar-atomic'));
}
// Debounced 2-frame confirmation to avoid flicker during animations
let raf1 = null, raf2 = null;
function scheduleRecompute() {
if (raf1) return;
raf1 = requestAnimationFrame(() => {
raf1 = null;
hideDiviBars();
const a = anyRealBannerVisible();
raf2 = requestAnimationFrame(() => {
raf2 = null;
const b = anyRealBannerVisible();
setForce110(a && b);
});
});
}
// --- Wiring ---
document.addEventListener('DOMContentLoaded', scheduleRecompute);
window.addEventListener('load', scheduleRecompute);
window.addEventListener('resize', () => { cancelAnimationFrame(raf1); raf1 = null; cancelAnimationFrame(raf2); raf2 = null; scheduleRecompute(); });
new MutationObserver(() => scheduleRecompute()).observe(document.documentElement, {
childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class', 'aria-hidden']
});
document.addEventListener('transitionend', e => { if (e.target && e.target.closest(CANDS)) scheduleRecompute(); });
document.addEventListener('animationend', e => { if (e.target && e.target.closest(CANDS)) scheduleRecompute(); });
document.addEventListener('click', function (e) {
const btn = e.target && e.target.closest('.divibars-close');
if (!btn) return;
setTimeout(() => {
const bar = btn.closest('.divibars-container, [class*="divibar"]');
if (bar) bar.style.setProperty('display', 'none', 'important');
scheduleRecompute();
}, 200);
}, true);
// Initial pass
scheduleRecompute();
})();