@glitchr/transparent 1.0.71 → 1.0.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glitchr/transparent",
3
- "version": "1.0.71",
3
+ "version": "1.0.81",
4
4
  "description": "Transparent SPA Application",
5
5
  "main": "src/index.js",
6
6
  "access": "public",
@@ -228,6 +228,29 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
228
228
  return false;
229
229
  }
230
230
 
231
+ // ─── NAVIGATION TRACE LOG ───────────────────────────────────────
232
+ // Gated on Settings.debug. Set 'debug': true in Transparent.ready({...})
233
+ // to surface a per-step trace prefixed with "[TX]" in the console.
234
+ // Cheap when disabled — single boolean check, no allocation.
235
+ function _tx(tag, extra) {
236
+ if (!Settings || !Settings.debug) return;
237
+ try {
238
+ var cls = document.documentElement.className;
239
+ var t = performance.now().toFixed(1);
240
+ var here = (document.querySelector("#page") || document.documentElement);
241
+ var lay = here.getAttribute && (here.getAttribute("data-layout") || "?");
242
+ var path = location.pathname;
243
+ console.log("%c[TX]", "color:#0a0;font-weight:bold",
244
+ "+" + t + "ms", tag,
245
+ "path=" + path,
246
+ "layout=" + lay,
247
+ "ajaxSem=" + (typeof ajaxSemaphore === "undefined" ? "?" : ajaxSemaphore),
248
+ "classes=[" + cls + "]",
249
+ extra || "");
250
+ } catch(e) {}
251
+ }
252
+ // ────────────────────────────────────────────────────────────────
253
+
231
254
  const State = Transparent.state = {
232
255
 
233
256
  ROOT : "transparent",
@@ -246,9 +269,9 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
246
269
  CLICK : "click",
247
270
 
248
271
  PREACTIVE : "pre-active",
249
- FADEIN : "fade-in",
272
+ FADEIN : "fade-in",
250
273
  ACTIVE : "active",
251
- FADEOUT : "fade-out",
274
+ FADEOUT : "fade-out",
252
275
  POSTACTIVE : "post-active",
253
276
 
254
277
  NOTIFICATION: "notification"
@@ -836,11 +859,10 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
836
859
 
837
860
  return {delay:delay, duration:duration};
838
861
  }
839
-
840
862
  var fadeInTime = 0;
841
863
  var fadeInRemainingTime = 0;
842
864
  Transparent.fadeIn = function(activeCallback = function() {}) {
843
-
865
+ _tx("fadeIn ENTRY");
844
866
  if(!Transparent.html.hasClass(Transparent.state.PREACTIVE)) {
845
867
  Transparent.html.addClass(Transparent.state.PREACTIVE);
846
868
  dispatchEvent(new Event('transparent:'+Transparent.state.PREACTIVE));
@@ -876,7 +898,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
876
898
  }
877
899
 
878
900
  Transparent.fadeOut = function(activeCallback = function() {}) {
879
-
901
+ _tx("fadeOut ENTRY");
880
902
  if(!Transparent.html.hasClass(Transparent.state.ACTIVE)) {
881
903
  Transparent.html.addClass(Transparent.state.ACTIVE);
882
904
  dispatchEvent(new Event('transparent:'+Transparent.state.ACTIVE));
@@ -897,8 +919,6 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
897
919
  Transparent.callback(function() {
898
920
 
899
921
  Transparent.html.removeClass(Transparent.state.FADEOUT);
900
- ajaxSemaphore = false;
901
-
902
922
  if(Transparent.html.hasClass(Transparent.state.LOADING)) {
903
923
 
904
924
  dispatchEvent(new Event('transparent:'+Transparent.state.LOADING));
@@ -906,7 +926,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
906
926
  Object.values(Transparent.state).forEach(e => Transparent.html.removeClass(e));
907
927
  Transparent.html.addClass(Transparent.state.ROOT + " " + Transparent.state.READY);
908
928
  }
909
-
929
+
910
930
  Transparent.html.addClass(Transparent.state.POSTACTIVE);
911
931
 
912
932
  var active = Transparent.activeTime();
@@ -1272,6 +1292,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1272
1292
 
1273
1293
  setTimeout(function() {
1274
1294
 
1295
+ _tx("onLoad BODY (after 1ms)");
1275
1296
  // Transfert attributes
1276
1297
  Transparent.transferAttributes(dom);
1277
1298
 
@@ -1295,8 +1316,8 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1295
1316
 
1296
1317
  found = this.isEqualNode(el);
1297
1318
  // Also match identical <style> tags by content
1298
- if(!found && el.tagName === 'STYLE' && this.tagName === 'STYLE' &&
1299
- el.textContent && this.textContent &&
1319
+ if(!found && el.tagName === 'STYLE' && this.tagName === 'STYLE' &&
1320
+ el.textContent && this.textContent &&
1300
1321
  el.textContent.length > 100 && this.textContent.length === el.textContent.length) {
1301
1322
  found = this.textContent === el.textContent;
1302
1323
  }
@@ -1318,7 +1339,8 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1318
1339
 
1319
1340
  if(this.tagName == "SCRIPT" && Settings["global_code"] != true) {
1320
1341
 
1321
- // For inline scripts (without src), create and execute
1342
+ // For inline scripts (without src), recreate so the browser will execute.
1343
+ // Simply re-appending the same <script> node doesn't execute it.
1322
1344
  if(!this.src || this.src === '') {
1323
1345
  var script = document.createElement("script");
1324
1346
  script.text = this.innerHTML;
@@ -1348,13 +1370,6 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1348
1370
  }
1349
1371
  });
1350
1372
 
1351
- // Collect link[rel="stylesheet"] elements inserted by the head merge above
1352
- var _newStyleLinks = [];
1353
- $("head").children("link[rel='stylesheet']").each(function() {
1354
- var h = this.getAttribute("href");
1355
- if(h && !_existingStyleHrefs[h]) _newStyleLinks.push(this);
1356
- });
1357
-
1358
1373
  var bodyScript = $(dom).find("body > script");
1359
1374
  bodyScript.each(function() {
1360
1375
 
@@ -1366,7 +1381,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1366
1381
 
1367
1382
  if(this.tagName == "SCRIPT" && Settings["global_code"] != true) {
1368
1383
 
1369
- // For inline scripts (without src), create and execute
1384
+ // Same inline-script recreation as for <head>.
1370
1385
  if(!this.src || this.src === '') {
1371
1386
  var script = document.createElement("script");
1372
1387
  script.text = this.innerHTML;
@@ -1401,7 +1416,13 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1401
1416
  // Make sure name/layout keep the same after a page change (tolerance for POST or GET requests)
1402
1417
  if(oldPage.attr("data-layout") != undefined && page.attr("data-layout") != undefined) {
1403
1418
 
1404
- var switchLayout = Transparent.state.SWITCH.replace("X", page.attr("data-layout")).replace("Y", oldPage.attr("data-layout"));
1419
+ // X = prevLayout, Y = newLayout — must match the formula in handleResponse
1420
+ // (line ~1852: SWITCH.replace("X", prevLayout).replace("Y", newLayout)).
1421
+ // If these disagreed, the cleanup filter below would not recognize the
1422
+ // switchLayout class that handleResponse added to <html> and would strip
1423
+ // it before its CSS transition could play — visible as a race only in
1424
+ // whichever direction the project's CSS actually styles.
1425
+ var switchLayout = Transparent.state.SWITCH.replace("X", oldPage.attr("data-layout")).replace("Y", page.attr("data-layout"));
1405
1426
  page.attr("data-layout-prev", oldPage.attr("data-layout"));
1406
1427
  }
1407
1428
 
@@ -1410,10 +1431,13 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1410
1431
  var oldHtmlClass = Array.from(($(Transparent.html).attr("class") || "").split(" "));
1411
1432
  var removeHtmlClass = oldHtmlClass.filter(x => !htmlClass.includes(x) && switchLayout != x && !states.includes(x));
1412
1433
 
1434
+ _tx("onLoad classMgmt", "switchLayout=" + switchLayout + " remove=[" + removeHtmlClass.join(",") + "] add=[" + htmlClass.join(",") + "]");
1413
1435
  Transparent.html.removeClass(removeHtmlClass).addClass(htmlClass);
1436
+ _tx("onLoad PAGE_SWAP_BEGIN", "oldLayout=" + (oldPage.attr("data-layout")||"?") + " newLayout=" + (page.attr("data-layout")||"?"));
1414
1437
  $(page).insertBefore(oldPage);
1415
1438
 
1416
1439
  oldPage.remove();
1440
+ _tx("onLoad PAGE_SWAP_DONE");
1417
1441
 
1418
1442
  if(Settings["global_code"] == true) Transparent.evalScript($(page)[0]);
1419
1443
  document.dispatchEvent(new Event('DOMContentLoaded'));
@@ -1449,33 +1473,67 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1449
1473
  }
1450
1474
  }
1451
1475
 
1476
+ // Collect link[rel="stylesheet"] elements inserted by the head merge above
1477
+ var _newStyleLinks = [];
1478
+ $("head").children("link[rel='stylesheet']").each(function() {
1479
+ var h = this.getAttribute("href");
1480
+ if(h && !_existingStyleHrefs[h]) _newStyleLinks.push(this);
1481
+ });
1482
+
1452
1483
  // Wait for any newly added layout stylesheets to finish loading before
1453
1484
  // calling callback() / fadeOut() — otherwise #page becomes visible while
1454
1485
  // the new CSS is still being parsed, causing a flash of unstyled content.
1455
1486
  (function() {
1456
1487
  function doCallback() {
1457
- $('head').append(function() {
1458
- $(Settings.identifier).append(function() {
1459
- callback();
1460
- dispatchEvent(new Event('transparent:load'));
1461
- dispatchEvent(new Event('load'));
1488
+ _tx("doCallback FIRES → callback() (which starts fadeOut)");
1489
+ // requestAnimationFrame here guarantees the browser has had one
1490
+ // full frame to apply the new page's stylesheets and re-layout
1491
+ // before fadeOut starts. Without it, fadeOut can animate the
1492
+ // loader away while the new page is still rendered with the
1493
+ // previous layout's styles — the article→home flicker the
1494
+ // [TX] trace masked via instrumentation overhead.
1495
+ requestAnimationFrame(function() {
1496
+ $('head').append(function() {
1497
+ $(Settings.identifier).append(function() {
1498
+ callback();
1499
+ dispatchEvent(new Event('transparent:load'));
1500
+ dispatchEvent(new Event('load'));
1501
+ });
1462
1502
  });
1463
1503
  });
1464
1504
  }
1465
- if(_newStyleLinks.length === 0) {
1505
+ // For cached stylesheets, the browser may fire `load` synchronously on
1506
+ // DOM insertion — BEFORE we can attach a listener — so listener-only
1507
+ // waits get stuck on the 3 s guard. `.sheet !== null` indicates the
1508
+ // CSSStyleSheet is already parsed and ready, which is the right
1509
+ // condition to count it as "done." Cross-origin sheets still expose
1510
+ // `.sheet` even though `.cssRules` throws — `.sheet !== null` is
1511
+ // portable.
1512
+ function isStyleLoaded(link) {
1513
+ try { return link.sheet !== null; } catch(e) { return true; }
1514
+ }
1515
+ var pending = _newStyleLinks.filter(function(l) { return !isStyleLoaded(l); });
1516
+ _tx("stylesheet-wait BEGIN", "newLinks=" + _newStyleLinks.length + " cachedSkipped=" + (_newStyleLinks.length - pending.length) + " pending=" + pending.length);
1517
+ if(pending.length === 0) {
1518
+ _tx("stylesheet-wait IMMEDIATE → doCallback");
1466
1519
  doCallback();
1467
1520
  } else {
1468
- var remaining = _newStyleLinks.length;
1521
+ var remaining = pending.length;
1469
1522
  var fired = false;
1470
1523
  // Safety valve: if a stylesheet fails or stalls, don't block forever.
1471
1524
  var guard = setTimeout(function() {
1472
- if(!fired) { fired = true; doCallback(); }
1525
+ if(!fired) {
1526
+ _tx("stylesheet-wait GUARD fired (3s)", "remaining=" + remaining);
1527
+ fired = true; doCallback();
1528
+ }
1473
1529
  }, 3000);
1474
- _newStyleLinks.forEach(function(link) {
1475
- function onDone() {
1530
+ pending.forEach(function(link) {
1531
+ function onDone(e) {
1532
+ _tx("stylesheet-wait link.load", "remaining=" + (remaining-1) + " href=" + link.getAttribute("href"));
1476
1533
  if(--remaining <= 0 && !fired) {
1477
1534
  fired = true;
1478
1535
  clearTimeout(guard);
1536
+ _tx("stylesheet-wait ALL_LOADED → doCallback");
1479
1537
  doCallback();
1480
1538
  }
1481
1539
  }
@@ -1597,7 +1655,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1597
1655
  var ajaxSemaphore = false;
1598
1656
  var formSubmission = false;
1599
1657
  function __main__(e) {
1600
-
1658
+ _tx("__main__ ENTRY", "event=" + e.type + (e.target && e.target.tagName ? " target=" + e.target.tagName : ""));
1601
1659
  // Disable transparent JS (e.g. during development..)
1602
1660
  if(Settings.disable) return;
1603
1661
 
@@ -1714,25 +1772,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1714
1772
  $(Transparent.html).stop();
1715
1773
 
1716
1774
  Transparent.html.addClass(Transparent.state.LOADING);
1717
-
1718
- var fadeInDone = false;
1719
- var pendingResponseArgs = null;
1720
-
1721
- function tryDispatch(args) {
1722
- if (args !== undefined) pendingResponseArgs = args;
1723
- if (fadeInDone && pendingResponseArgs !== null)
1724
- handleResponse(...pendingResponseArgs);
1725
- }
1726
-
1727
- // Lock navigation for the full transition (fadeIn + page swap + fadeOut).
1728
- // Released inside Transparent.fadeOut's final cleanup, covering both the
1729
- // AJAX path and the popstate/cached-response path.
1730
- ajaxSemaphore = true;
1731
-
1732
- Transparent.fadeIn(function() {
1733
- fadeInDone = true;
1734
- tryDispatch();
1735
- });
1775
+ Transparent.fadeIn();
1736
1776
 
1737
1777
  function isJsonResponse(str) {
1738
1778
  try { JSON.parse(str); return true; }
@@ -1740,8 +1780,10 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1740
1780
  }
1741
1781
 
1742
1782
  function handleResponse(uuid, status = 200, method = null, data = null, xhr = null, request = null) {
1783
+ _tx("handleResponse ENTRY", "status=" + status + " method=" + method);
1743
1784
 
1744
-
1785
+ ajaxSemaphore = false;
1786
+
1745
1787
  var responseURL;
1746
1788
  responseURL = xhr !== null ? xhr.responseURL : url.href;
1747
1789
 
@@ -1797,7 +1839,6 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1797
1839
  else location.reload();
1798
1840
  }
1799
1841
 
1800
- ajaxSemaphore = false;
1801
1842
  return dispatchEvent(new Event('load'));
1802
1843
  }
1803
1844
 
@@ -1858,6 +1899,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1858
1899
  Transparent.html.addClass(Transparent.state.SAME);
1859
1900
 
1860
1901
  var switchLayout = Transparent.state.SWITCH.replace("X", prevLayout).replace("Y", newLayout);
1902
+ _tx("handleResponse switchLayout", "prev=" + prevLayout + " new=" + newLayout + " adds=." + switchLayout);
1861
1903
  Transparent.html.addClass(switchLayout);
1862
1904
 
1863
1905
  dispatchEvent(new Event('transparent:'+switchLayout));
@@ -1915,6 +1957,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1915
1957
  if(form) form.dispatchEvent(new SubmitEvent("submit", { submitter: formTrigger }));
1916
1958
  var xhr = new XMLHttpRequest();
1917
1959
 
1960
+ ajaxSemaphore = true;
1918
1961
  return jQuery.ajax({
1919
1962
  url: url.href,
1920
1963
  type: type,
@@ -1923,12 +1966,12 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
1923
1966
  processData: false,
1924
1967
  headers: Settings["headers"] || {},
1925
1968
  xhr: function () { return xhr; },
1926
- success: function (html, status, request) { return tryDispatch([uuid, request.status, type, data, xhr, request]); },
1927
- error: function (request, ajaxOptions, thrownError) { return tryDispatch([uuid, request.status, type, data, xhr, request]); }
1969
+ success: function (html, status, request) { _tx("ajax SUCCESS", "status=" + request.status); return handleResponse(uuid, request.status, type, data, xhr, request); },
1970
+ error: function (request, ajaxOptions, thrownError) { _tx("ajax ERROR", "status=" + request.status); return handleResponse(uuid, request.status, type, data, xhr, request); }
1928
1971
  });
1929
1972
  }
1930
1973
 
1931
- return tryDispatch([history.state.uuid, history.state.status, history.state.method, history.state.data]);
1974
+ return handleResponse(history.state.uuid, history.state.status, history.state.method, history.state.data);
1932
1975
  }
1933
1976
 
1934
1977
  // Update history if not refreshing page or different page (avoid double pushState)