{"id":19018466,"date":"2026-09-12T15:35:35","date_gmt":"2026-09-12T15:35:35","guid":{"rendered":"https:\/\/wordpress.org\/support\/?post_type=topic&#038;p=19018466"},"modified":"2026-09-12T16:14:41","modified_gmt":"2026-09-12T16:14:41","slug":"dropdown-js-callback-is-not-a-function-on-repeat-focus","status":"publish","type":"topic","link":"https:\/\/wordpress.org\/support\/topic\/dropdown-js-callback-is-not-a-function-on-repeat-focus\/","title":{"rendered":"dropdown.js callback is not a function on repeat focus"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Bug: <code>dropdown.js<\/code> \u2014 <code>load_tlib()<\/code> throws &#8220;callback is not a function&#8221; on repeat focus\/hover<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Affected asset:<\/strong> <code>https:\/\/cdn.gtranslate.net\/widgets\/latest\/dropdown.js<\/code> (the &#8220;dropdown&#8221; widget variant; other variants may share the same helper \u2014 worth checking <code>float.js<\/code> \/ <code>dwf.js<\/code> \/ <code>globe.js<\/code> too).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Root cause<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>load_tlib(callback)<\/code> is defined as a general-purpose helper that lazy-injects <code>lib.min.js<\/code> and then runs a callback once it&#8217;s loaded:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function load_tlib(callback){<br \/>  if(!window.gt_translate_script){<br \/>    window.gt_translate_script = document.createElement('script');<br \/>    gt_translate_script.src = 'https:\/\/cdn.gtranslate.net\/widgets\/latest\/lib.min.js';<br \/>    document.body.appendChild(gt_translate_script);<br \/>    if(callback) gt_translate_script.addEventListener('load', callback, {once:true});<br \/>  } else {<br \/>    callback &amp;&amp; callback();<br \/>  }<br \/>}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But it is also registered directly as a native DOM event listener:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>e.addEventListener('pointerenter', load_tlib);<br \/>e.addEventListener('focusin', load_tlib);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When the browser invokes an event listener, it always passes the triggering <code>Event<\/code> object as the argument. So on every <code>focusin<\/code>\/<code>pointerenter<\/code> fired this way, <code>callback<\/code> inside <code>load_tlib<\/code> is actually a native <code>Event<\/code>, not a function.<\/p>\n\n\n\n<ul>\n<li><strong>First call<\/strong> (<code>window.gt_translate_script<\/code> not yet set): goes into the <code>if<\/code> branch. <code>gt_translate_script.addEventListener('load', callback, {once:true})<\/code> is called with <code>callback<\/code> = an <code>Event<\/code> object. Per the <code>addEventListener<\/code> spec this is silently ignored (no crash, but also no real &#8220;on load&#8221; callback ever gets registered).<\/li>\n\n\n\n<li><strong>Any subsequent call<\/strong> on the same wrapper (user re-focuses or re-hovers the widget after the first interaction): <code>window.gt_translate_script<\/code> now exists, so execution hits the <code>else<\/code> branch: <code>callback &amp;&amp; callback();<\/code>. <code>callback<\/code> is again a truthy <code>Event<\/code> object, so this attempts to invoke the <code>Event<\/code> instance as a function \u2014 which throws:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>Uncaught TypeError: callback is not a function<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Steps to reproduce<\/strong><\/p>\n\n\n\n<ol>\n<li>Load a page with the dropdown widget using default settings (<code>url_structure: 'none'<\/code>, so the interaction-based lazy-load path runs).<\/li>\n\n\n\n<li>Move keyboard focus into the widget&#8217;s wrapper element once, or hover it with a pointer once \u2014 no error; <code>window.gt_translate_script<\/code> gets set on this first pass.<\/li>\n\n\n\n<li>Move focus\/hover away and then back onto the wrapper a second time (or trigger <code>focusin<\/code>\/<code>pointerenter<\/code> on it again in any way) \u2014 <code>Uncaught TypeError: callback is not a function<\/code> is thrown from the <code>callback &amp;&amp; callback();<\/code> line inside <code>load_tlib<\/code>.<\/li>\n\n\n\n<li>This repeats on every subsequent focus\/hover cycle on the same page load.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Suggested fix<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>load_tlib<\/code> is used both as a plain callback-style helper (e.g. called manually inside <code>doGTranslate<\/code> with a real function) and directly as a native event listener \u2014 these two calling conventions are incompatible without normalizing the argument. Either:<\/p>\n\n\n\n<ul>\n<li>(a) Wrap it before attaching as a listener, so it&#8217;s never invoked with the native <code>Event<\/code> as its argument: <code>e.addEventListener('focusin', () =&gt; load_tlib());e.addEventListener('pointerenter', () =&gt; load_tlib());<\/code><\/li>\n\n\n\n<li>(b) Or guard the type inside <code>load_tlib<\/code> itself, so any non-function argument is ignored instead of crashing: <code>if (typeof callback === 'function') callback(); <\/code>(and the same guard before the <code>addEventListener('load', callback, ...)<\/code> call).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Either change is small, localized to <code>load_tlib<\/code>, and doesn&#8217;t affect the widget&#8217;s public config\/settings.<\/p>\n","protected":false},"template":"","class_list":["post-19018466","topic","type-topic","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic\/19018466","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic"}],"about":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/types\/topic"}],"version-history":[{"count":1,"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic\/19018466\/revisions"}],"predecessor-version":[{"id":19018480,"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic\/19018466\/revisions\/19018480"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/media?parent=19018466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}