Spaces:
Running
Running
Commit
·
cdfa223
1
Parent(s):
6924d73
Solution 5: JavaScript override of mobile detection + manual tab switching
Browse files- Override navigator.maxTouchPoints and platform to fake desktop
- Manually implement tab panel showing/hiding via JavaScript
- Intercept tab clicks and control display with CSS display property
- Bypasses Gradio's broken mobile tab handling completely
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -1281,6 +1281,18 @@ custom_css = """
|
|
| 1281 |
|
| 1282 |
custom_js = """
|
| 1283 |
function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1284 |
// Add click-to-expand functionality for the plot
|
| 1285 |
document.addEventListener('click', function(e) {
|
| 1286 |
const plot = e.target.closest('.expandable-plot');
|
|
@@ -1299,41 +1311,62 @@ function() {
|
|
| 1299 |
}
|
| 1300 |
});
|
| 1301 |
|
| 1302 |
-
//
|
| 1303 |
-
function
|
| 1304 |
const tabs = document.querySelectorAll('[role="tab"]');
|
| 1305 |
-
|
| 1306 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1307 |
const newTab = tab.cloneNode(true);
|
| 1308 |
tab.parentNode.replaceChild(newTab, tab);
|
| 1309 |
|
| 1310 |
-
// Add
|
| 1311 |
-
|
| 1312 |
-
|
| 1313 |
-
|
| 1314 |
-
|
| 1315 |
-
|
| 1316 |
-
|
| 1317 |
-
|
| 1318 |
-
|
| 1319 |
-
|
| 1320 |
-
|
| 1321 |
-
|
| 1322 |
-
|
| 1323 |
-
|
| 1324 |
-
|
| 1325 |
-
|
| 1326 |
-
|
| 1327 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1328 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1329 |
}
|
| 1330 |
|
| 1331 |
-
// Run
|
| 1332 |
-
setTimeout(
|
| 1333 |
-
setTimeout(
|
| 1334 |
-
setTimeout(
|
|
|
|
| 1335 |
const observer = new MutationObserver(() => {
|
| 1336 |
-
setTimeout(
|
| 1337 |
});
|
| 1338 |
observer.observe(document.body, { childList: true, subtree: true });
|
| 1339 |
}
|
|
|
|
| 1281 |
|
| 1282 |
custom_js = """
|
| 1283 |
function() {
|
| 1284 |
+
// Force desktop mode - override mobile detection
|
| 1285 |
+
Object.defineProperty(navigator, 'maxTouchPoints', {
|
| 1286 |
+
get: () => 0
|
| 1287 |
+
});
|
| 1288 |
+
|
| 1289 |
+
// Override platform if needed
|
| 1290 |
+
try {
|
| 1291 |
+
Object.defineProperty(navigator, 'platform', {
|
| 1292 |
+
get: () => 'MacIntel'
|
| 1293 |
+
});
|
| 1294 |
+
} catch(e) {}
|
| 1295 |
+
|
| 1296 |
// Add click-to-expand functionality for the plot
|
| 1297 |
document.addEventListener('click', function(e) {
|
| 1298 |
const plot = e.target.closest('.expandable-plot');
|
|
|
|
| 1311 |
}
|
| 1312 |
});
|
| 1313 |
|
| 1314 |
+
// Aggressive tab fixing - manually control tab panels
|
| 1315 |
+
function forceTabSwitching() {
|
| 1316 |
const tabs = document.querySelectorAll('[role="tab"]');
|
| 1317 |
+
const tabPanels = document.querySelectorAll('[role="tabpanel"]');
|
| 1318 |
+
|
| 1319 |
+
if (tabs.length === 0 || tabPanels.length === 0) return;
|
| 1320 |
+
|
| 1321 |
+
tabs.forEach((tab, index) => {
|
| 1322 |
+
// Remove old listeners by cloning
|
| 1323 |
const newTab = tab.cloneNode(true);
|
| 1324 |
tab.parentNode.replaceChild(newTab, tab);
|
| 1325 |
|
| 1326 |
+
// Add new click handler that manually shows/hides panels
|
| 1327 |
+
newTab.addEventListener('click', function(e) {
|
| 1328 |
+
e.preventDefault();
|
| 1329 |
+
e.stopPropagation();
|
| 1330 |
+
|
| 1331 |
+
// Hide all panels
|
| 1332 |
+
tabPanels.forEach(panel => {
|
| 1333 |
+
panel.style.display = 'none';
|
| 1334 |
+
panel.setAttribute('aria-hidden', 'true');
|
| 1335 |
+
});
|
| 1336 |
+
|
| 1337 |
+
// Remove selected from all tabs
|
| 1338 |
+
tabs.forEach(t => {
|
| 1339 |
+
t.setAttribute('aria-selected', 'false');
|
| 1340 |
+
t.classList.remove('selected');
|
| 1341 |
+
});
|
| 1342 |
+
|
| 1343 |
+
// Show clicked tab's panel
|
| 1344 |
+
if (tabPanels[index]) {
|
| 1345 |
+
tabPanels[index].style.display = 'block';
|
| 1346 |
+
tabPanels[index].setAttribute('aria-hidden', 'false');
|
| 1347 |
+
}
|
| 1348 |
+
|
| 1349 |
+
// Mark clicked tab as selected
|
| 1350 |
+
this.setAttribute('aria-selected', 'true');
|
| 1351 |
+
this.classList.add('selected');
|
| 1352 |
+
}, true);
|
| 1353 |
});
|
| 1354 |
+
|
| 1355 |
+
// Ensure first tab is initially selected
|
| 1356 |
+
if (tabPanels.length > 0) {
|
| 1357 |
+
tabPanels.forEach((panel, i) => {
|
| 1358 |
+
panel.style.display = i === 0 ? 'block' : 'none';
|
| 1359 |
+
});
|
| 1360 |
+
}
|
| 1361 |
}
|
| 1362 |
|
| 1363 |
+
// Run tab fixing multiple times
|
| 1364 |
+
setTimeout(forceTabSwitching, 200);
|
| 1365 |
+
setTimeout(forceTabSwitching, 800);
|
| 1366 |
+
setTimeout(forceTabSwitching, 1500);
|
| 1367 |
+
|
| 1368 |
const observer = new MutationObserver(() => {
|
| 1369 |
+
setTimeout(forceTabSwitching, 100);
|
| 1370 |
});
|
| 1371 |
observer.observe(document.body, { childList: true, subtree: true });
|
| 1372 |
}
|