class BaseSwitcher {
constructor(rootEl){
this.root=rootEl;
this.list=rootEl?.querySelector('.trp-switcher-dropdown-list')||null;
this.isOpen=false;
this._pendingFocusOnOpen=false;
if(!this.root||!this.list) return;
if(!this.list.id){
this.list.id=`trp-list-${Math.random().toString(36).slice(2, 9)}`;
}
this._onTe=(e)=> {
if(e.target!==this.list||e.propertyName!=='max-height') return;
this.root.classList.remove('is-transitioning');
if(!this.isOpen){
this.list.hidden=true;
this.list.setAttribute('inert', '');
}else if(this._pendingFocusOnOpen){
this._pendingFocusOnOpen=false;
const first=this.list.querySelector('[role="option"], a, button, [tabindex]:not([tabindex="-1"])'
);
first?.focus?.({ preventScroll: true });
}};
this.list.addEventListener('transitionend', this._onTe);
this.collapse();
this.setAutoWidth();
this.bindKeyboard();
}
_hasAnimatedTransition(){
if(!this.list) return false;
const cs=getComputedStyle(this.list);
const durationsRaw=cs.transitionDuration||'';
if(!durationsRaw) return false;
const durations=durationsRaw
.split(',')
.map(str=> parseFloat(str)||0);
return durations.some(d=> d > 0);
}
collapse(){
this.list.hidden=true;
this.list.setAttribute('inert', '');
this.setExpanded(false);
this.root.classList.remove('is-transitioning');
}
setAutoWidth(){
const bonusWidth=10;
const cs=getComputedStyle(this.root);
const declaredWidth=cs.getPropertyValue('--switcher-width').trim();
if(declaredWidth==='auto'&&this.root.querySelector('.trp-language-item-name')){
const initialWidth=this.root.getBoundingClientRect().width;
this.root.style.setProperty('--switcher-width', (initialWidth + bonusWidth) + 'px');
}}
setExpanded(open){
const trigger=this.root.querySelector('.trp-language-item__current[role="button"]');
const val=String(!!open);
trigger?.setAttribute('aria-expanded', val);
this.root.classList.toggle('is-open', !!open);
}
setOpen(open, { source=null }={}){
if(!this.root||!this.list||open===this.isOpen) return;
const prefersReduced=window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches;
const hasTransition  = !prefersReduced&&this._hasAnimatedTransition();
this.isOpen=open;
if(!hasTransition){
if(open){
this.list.hidden=false;
this.list.removeAttribute('inert');
this.setExpanded(true);
this._pendingFocusOnOpen=(source?.type==='keydown');
if(this._pendingFocusOnOpen){
this._pendingFocusOnOpen=false;
const first=this.list.querySelector('[role="option"], a, button, [tabindex]:not([tabindex="-1"])'
);
first?.focus?.({ preventScroll: true });
}}else{
this.setExpanded(false);
this.list.hidden=true;
this.list.setAttribute('inert', '');
this._pendingFocusOnOpen=false;
}
return;
}
if(open){
this.list.hidden=false;
this.list.removeAttribute('inert');
this._pendingFocusOnOpen=(source?.type==='keydown');
this.root.classList.add('is-transitioning');
requestAnimationFrame(()=> this.setExpanded(true) );
}else{
this.root.classList.add('is-transitioning');
this.setExpanded(false);
}}
bindKeyboard(){
const trigger=this.root.querySelector('.trp-language-item__current[role="button"]');
if(!trigger) return;
trigger.addEventListener('keydown', (e)=> {
const inList = !!e.target.closest?.('.trp-switcher-dropdown-list');
if(e.key==='Enter'||e.key===' '){
e.preventDefault();
this.setOpen(!this.isOpen, { source: e });
return;
}
if(e.key==='ArrowDown'&&!this.isOpen){
e.preventDefault();
this.setOpen(true, { source: e });
}
if(e.key==='Escape'){
this.setOpen(false, { source: e });
trigger.focus?.();
}});
}}
class ShortcodeSwitcher extends BaseSwitcher {
constructor(wrapper){
const overlay =
wrapper.querySelector('.trp-language-switcher.trp-shortcode-overlay')
|| [...wrapper.querySelectorAll('.trp-language-switcher')]
.find(el=> el.classList.contains('trp-shortcode-overlay'));
overlay.hidden=false;
overlay.removeAttribute('hidden');
overlay.removeAttribute('inert');
if('inert' in overlay) overlay.inert=false;
super(overlay);
if(!this.root||!this.list) return;
const control=this.root.querySelector('.trp-language-item__current[role="button"]');
if(control&&this.list&&!control.hasAttribute('aria-controls')){
control.setAttribute('aria-controls', this.list.id);
}
const isClickMode =
this.root.classList.contains('trp-open-on-click') ||
wrapper.dataset.openMode==='click' ||
wrapper.classList.contains('trp-open-on-click');
if(isClickMode){
this.root.addEventListener('click', (e)=> {
const inList=e.target.closest('.trp-switcher-dropdown-list');
if(!inList){
e.preventDefault();
e.stopPropagation();
this.setOpen(!this.isOpen, { source: e });
}}, true);
this.onDocClick=(evt)=> {
if(!wrapper.contains(evt.target)) this.setOpen(false, { source: evt });
};
document.addEventListener('click', this.onDocClick, true);
wrapper.addEventListener('focusout', ()=> {
setTimeout(()=> {
if(!wrapper.contains(document.activeElement)){
this.setOpen(false, { source: 'keyboard' });
}}, 0);
});
}else{
this.root.addEventListener('mouseenter', (e)=> this.setOpen(true,  { source: e }));
this.root.addEventListener('mouseleave', (e)=> this.setOpen(false, { source: e }));
}}
}
class FloaterSwitcher extends BaseSwitcher {
constructor(el){
super(el);
el.addEventListener('mouseenter', (e)=> this.setOpen(true,  { source: e }));
el.addEventListener('mouseleave', (e)=> this.setOpen(false, { source: e }));
this.onDocClick=(evt)=> { if(!el.contains(evt.target)) this.setOpen(false, { source: evt });};
document.addEventListener('click', this.onDocClick, true);
}}
document.addEventListener('DOMContentLoaded', ()=> {
initLanguageSwitchers(document);
if(inGutenberg() &&
!getEditorDoc().querySelector(WRAPPER)
){
observeWrapperUntilFound();
}
if(!inGutenberg())
observeShortcodeSwitcher();
});
const TRP_BOUND=new WeakSet();
const mark=(el)=> TRP_BOUND.add(el);
const isMarked=(el)=> TRP_BOUND.has(el);
const WRAPPER='.trp-shortcode-switcher__wrapper';
const OVERLAY='.trp-language-switcher:not(.trp-opposite-button)';
function inGutenberg(){
return document.body?.classList?.contains('block-editor-page')
|| !!(window.wp?.data?.select?.('core/block-editor'));
}
function getEditorDoc(){
const ifr=document.querySelector('iframe[name="editor-canvas"], .editor-canvas__iframe');
return (ifr&&ifr.contentDocument) ? ifr.contentDocument:document;
}
function initLanguageSwitchers(root=document){
const floater=root.querySelector('.trp-language-switcher.trp-ls-dropdown:not(.trp-shortcode-switcher):not(.trp-opposite-language)'
);
if(floater)
new FloaterSwitcher(floater);
root.querySelectorAll(WRAPPER)
.forEach(wrapper=> {
const overlay=wrapper.querySelector('.trp-language-switcher:not(.trp-opposite-button)');
if(overlay&&!isMarked(overlay)){
mark(overlay);
new ShortcodeSwitcher(wrapper);
}});
}
function observeShortcodeSwitcher(){
const initWrapper=(wrapper)=> {
if(!wrapper)
return;
const overlay=wrapper.querySelector(OVERLAY);
if(!overlay||isMarked(overlay) )
return;
mark(overlay);
new ShortcodeSwitcher(wrapper);
}
const mo=new MutationObserver(( mutations)=> {
for(const m of mutations){
for(const n of m.addedNodes){
if(n.nodeType!==1)
continue;
if(n.matches?.(WRAPPER) )
initWrapper(n);
n.querySelectorAll?.(WRAPPER).forEach(initWrapper);
}}
});
mo.observe(document, { childList: true, subtree: true });
}
function observeWrapperUntilFound(){
const edDoc=getEditorDoc();
const existing=edDoc.querySelector(WRAPPER);
if(existing){
initLanguageSwitchers(edDoc);
return;
}
const findCanvasIframe=()=> document.querySelector('iframe[name="editor-canvas"], .editor-canvas__iframe');
const iframeNow=findCanvasIframe();
if(iframeNow){
watchIframe(iframeNow);
return;
}
const outerMO=new MutationObserver(( mutations)=> {
for(const m of mutations){
for(const n of m.addedNodes){
if(n.nodeType!==1) continue;
const iframe =
n.matches?.('iframe[name="editor-canvas"], .editor-canvas__iframe')
? n
: n.querySelector?.('iframe[name="editor-canvas"], .editor-canvas__iframe');
if(iframe){
outerMO.disconnect();
watchIframe(iframe);
return;
}
const wrapper =
n.matches?.(WRAPPER)
? n
: n.querySelector?.(WRAPPER);
if(wrapper){
outerMO.disconnect();
initLanguageSwitchers(document);
return;
}}
}});
outerMO.observe(document, { childList: true, subtree: true });
function watchIframe(iframe){
tryAttachInside();
iframe.addEventListener('load', tryAttachInside);
function tryAttachInside(){
let doc;
try {
doc=iframe.contentDocument||iframe.contentWindow?.document;
} catch (e){
console.warn('Cannot access iframe content due to cross-origin restrictions', e);
return;
}
if(!doc) return;
const hit=doc.querySelector(WRAPPER);
if(hit){
initLanguageSwitchers(doc);
return;
}
const innerMO=new MutationObserver(( muts)=> {
for(const mm of muts){
for(const nn of mm.addedNodes){
if(nn.nodeType!==1) continue;
if(nn.matches?.(WRAPPER) ||
nn.querySelector?.(WRAPPER)
){
innerMO.disconnect();
initLanguageSwitchers(doc);
return;
}}
}
if(doc.querySelector(WRAPPER)){
innerMO.disconnect();
initLanguageSwitchers(doc);
}});
innerMO.observe(doc, { childList: true, subtree: true });
}}
};