@glitchr/transparent 1.0.80 → 1.0.82
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 +1 -1
- package/src/js/transparent.js +140 -16
package/package.json
CHANGED
package/src/js/transparent.js
CHANGED
|
@@ -274,12 +274,48 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
274
274
|
FADEOUT : "fade-out",
|
|
275
275
|
POSTACTIVE : "post-active",
|
|
276
276
|
|
|
277
|
-
NOTIFICATION: "notification"
|
|
277
|
+
NOTIFICATION: "notification",
|
|
278
|
+
OFFLINE : "offline"
|
|
278
279
|
};
|
|
279
280
|
|
|
280
281
|
var isReady = false;
|
|
281
282
|
var rescueMode = false;
|
|
282
283
|
|
|
284
|
+
// ─── OFFLINE DETECTION ──────────────────────────────────────────
|
|
285
|
+
// Two-source signal:
|
|
286
|
+
// 1. window 'online'/'offline' events fired by the browser when the
|
|
287
|
+
// OS-level connectivity changes (Wi-Fi off, airplane mode, etc.)
|
|
288
|
+
// 2. AJAX network errors during navigation — if a request fails with
|
|
289
|
+
// status 0 (and wasn't aborted), the device probably can't reach
|
|
290
|
+
// the server even though navigator.onLine may still be true.
|
|
291
|
+
// The `html.offline` class is the public surface — the project's CSS
|
|
292
|
+
// styles the YouTube-style "Offline" banner from there. Custom events
|
|
293
|
+
// `transparent:offline` and `transparent:online` give JS hooks too.
|
|
294
|
+
var isOnline = (typeof navigator !== "undefined") ? navigator.onLine !== false : true;
|
|
295
|
+
Transparent.isOnline = function() { return isOnline; }
|
|
296
|
+
function setOnlineStatus(online) {
|
|
297
|
+
if (online === isOnline) return; // no change
|
|
298
|
+
isOnline = online;
|
|
299
|
+
if (online) {
|
|
300
|
+
$($(document).find("html")[0]).removeClass(State.OFFLINE);
|
|
301
|
+
dispatchEvent(new Event("transparent:online"));
|
|
302
|
+
} else {
|
|
303
|
+
$($(document).find("html")[0]).addClass(State.OFFLINE);
|
|
304
|
+
dispatchEvent(new Event("transparent:offline"));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (typeof window !== "undefined") {
|
|
308
|
+
window.addEventListener("online", function() { setOnlineStatus(true); });
|
|
309
|
+
window.addEventListener("offline", function() { setOnlineStatus(false); });
|
|
310
|
+
}
|
|
311
|
+
// Apply initial state synchronously so first-paint reflects offline if applicable.
|
|
312
|
+
if (!isOnline) {
|
|
313
|
+
// Use the document element directly here — Transparent.html isn't initialized yet at module-eval time.
|
|
314
|
+
var _htmlEl = document.documentElement;
|
|
315
|
+
if (_htmlEl && _htmlEl.classList) _htmlEl.classList.add(State.OFFLINE);
|
|
316
|
+
}
|
|
317
|
+
// ────────────────────────────────────────────────────────────────
|
|
318
|
+
|
|
283
319
|
Transparent.html = $($(document).find("html")[0]);
|
|
284
320
|
Transparent.html.addClass(Transparent.state.ROOT+ " " + Transparent.state.LOADING + " " + Transparent.state.FIRST);
|
|
285
321
|
|
|
@@ -861,6 +897,15 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
861
897
|
}
|
|
862
898
|
var fadeInTime = 0;
|
|
863
899
|
var fadeInRemainingTime = 0;
|
|
900
|
+
// Schedule fn for after the currently in-flight fadeIn animation has
|
|
901
|
+
// finished. Used by handleResponse's three reload/redirect paths to
|
|
902
|
+
// ensure the loader is at full opacity before the browser unloads.
|
|
903
|
+
function _waitForFadeIn(fn) {
|
|
904
|
+
var elapsed = Date.now() - fadeInTime;
|
|
905
|
+
var remaining = fadeInRemainingTime - elapsed;
|
|
906
|
+
if (remaining > 0) setTimeout(fn, remaining + 30);
|
|
907
|
+
else fn();
|
|
908
|
+
}
|
|
864
909
|
Transparent.fadeIn = function(activeCallback = function() {}) {
|
|
865
910
|
_tx("fadeIn ENTRY");
|
|
866
911
|
if(!Transparent.html.hasClass(Transparent.state.PREACTIVE)) {
|
|
@@ -1026,7 +1071,22 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1026
1071
|
Transparent.fadeOut();
|
|
1027
1072
|
}
|
|
1028
1073
|
|
|
1029
|
-
Transparent.userScroll = function(el = undefined) {
|
|
1074
|
+
Transparent.userScroll = function(el = undefined) {
|
|
1075
|
+
// Defensive: closestScrollable() can return a value without .prop
|
|
1076
|
+
// when called from event handlers on transient DOM (e.g. ajaxer
|
|
1077
|
+
// result containers, sticky-scrollpercent triggers fired during
|
|
1078
|
+
// infinite-scroll while the page is transitioning). The app-defer.js
|
|
1079
|
+
// wrapper around $.fn.closestScrollable is supposed to enforce the
|
|
1080
|
+
// jQuery return, but races with timing-sensitive callers can still
|
|
1081
|
+
// hit this. Default to true ("user is scrolling, don't autoscroll").
|
|
1082
|
+
try {
|
|
1083
|
+
var $target = $(el === undefined ? document.documentElement : el);
|
|
1084
|
+
if (!$target || !$target.length) return true;
|
|
1085
|
+
var $scroll = $target.closestScrollable && $target.closestScrollable();
|
|
1086
|
+
if (!$scroll || typeof $scroll.prop !== "function") return true;
|
|
1087
|
+
return $scroll.prop("user-scroll") ?? true;
|
|
1088
|
+
} catch (e) { return true; }
|
|
1089
|
+
}
|
|
1030
1090
|
Transparent.scrollTo = function(dict, el = window, callback = function() {})
|
|
1031
1091
|
{
|
|
1032
1092
|
setTimeout(function() {
|
|
@@ -1290,9 +1350,28 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1290
1350
|
$(this).stop();
|
|
1291
1351
|
});
|
|
1292
1352
|
|
|
1353
|
+
// Defer the DOM swap until #page's opacity transition has had a
|
|
1354
|
+
// chance to finish. Read the transition-duration from getComputedStyle
|
|
1355
|
+
// (closure-local — no module state shared between navigations) so
|
|
1356
|
+
// this stays in sync with whatever the project's CSS uses. Without
|
|
1357
|
+
// this delay, a fast/cached AJAX response can land the swap while
|
|
1358
|
+
// #page is still partway through the LOADING-induced fade-out,
|
|
1359
|
+
// making the content change visible to the user (the original
|
|
1360
|
+
// flicker).
|
|
1361
|
+
var _swapDelay = 1;
|
|
1362
|
+
try {
|
|
1363
|
+
var _pageEl = $(Settings.identifier)[0];
|
|
1364
|
+
if (_pageEl) {
|
|
1365
|
+
var _dur = 1000 * Transparent.parseDuration(
|
|
1366
|
+
window.getComputedStyle(_pageEl).transitionDuration || "0"
|
|
1367
|
+
);
|
|
1368
|
+
if (_dur > 1) _swapDelay = _dur;
|
|
1369
|
+
}
|
|
1370
|
+
} catch(e) {}
|
|
1371
|
+
|
|
1293
1372
|
setTimeout(function() {
|
|
1294
1373
|
|
|
1295
|
-
_tx("onLoad BODY (after
|
|
1374
|
+
_tx("onLoad BODY (after " + _swapDelay + "ms)");
|
|
1296
1375
|
// Transfert attributes
|
|
1297
1376
|
Transparent.transferAttributes(dom);
|
|
1298
1377
|
|
|
@@ -1486,11 +1565,19 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1486
1565
|
(function() {
|
|
1487
1566
|
function doCallback() {
|
|
1488
1567
|
_tx("doCallback FIRES → callback() (which starts fadeOut)");
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1568
|
+
// requestAnimationFrame here guarantees the browser has had one
|
|
1569
|
+
// full frame to apply the new page's stylesheets and re-layout
|
|
1570
|
+
// before fadeOut starts. Without it, fadeOut can animate the
|
|
1571
|
+
// loader away while the new page is still rendered with the
|
|
1572
|
+
// previous layout's styles — the article→home flicker the
|
|
1573
|
+
// [TX] trace masked via instrumentation overhead.
|
|
1574
|
+
requestAnimationFrame(function() {
|
|
1575
|
+
$('head').append(function() {
|
|
1576
|
+
$(Settings.identifier).append(function() {
|
|
1577
|
+
callback();
|
|
1578
|
+
dispatchEvent(new Event('transparent:load'));
|
|
1579
|
+
dispatchEvent(new Event('load'));
|
|
1580
|
+
});
|
|
1494
1581
|
});
|
|
1495
1582
|
});
|
|
1496
1583
|
}
|
|
@@ -1535,7 +1622,7 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1535
1622
|
}
|
|
1536
1623
|
})();
|
|
1537
1624
|
|
|
1538
|
-
}.bind(this),
|
|
1625
|
+
}.bind(this), _swapDelay);
|
|
1539
1626
|
}
|
|
1540
1627
|
|
|
1541
1628
|
function uuidv4() {
|
|
@@ -1739,6 +1826,17 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1739
1826
|
if (ajaxSemaphore) return;
|
|
1740
1827
|
if (url == location) return;
|
|
1741
1828
|
|
|
1829
|
+
// Block navigation when offline. Project CSS / JS can react to
|
|
1830
|
+
// html.offline + the transparent:offline event to surface a banner.
|
|
1831
|
+
// The event is re-dispatched here on each attempted navigation so a
|
|
1832
|
+
// listener can briefly flash/highlight the banner to acknowledge the
|
|
1833
|
+
// click instead of doing nothing silently.
|
|
1834
|
+
if (!isOnline || (typeof navigator !== "undefined" && navigator.onLine === false)) {
|
|
1835
|
+
setOnlineStatus(false);
|
|
1836
|
+
dispatchEvent(new Event("transparent:offline"));
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1742
1840
|
if((e.type == Transparent.state.CLICK || e.type == Transparent.state.HASHCHANGE) && url.pathname == location.pathname && url.search == location.search && type != "POST") {
|
|
1743
1841
|
|
|
1744
1842
|
if(!url.hash) return;
|
|
@@ -1858,12 +1956,18 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1858
1956
|
history.pushState({uuid: uuid, status:status, method: method, data: {}, href: responseURL}, '', responseURL);
|
|
1859
1957
|
|
|
1860
1958
|
// Page not recognized.. just go fetch by yourself.. no POST information transmitted..
|
|
1861
|
-
|
|
1862
|
-
|
|
1959
|
+
// Defer the redirect until fadeIn settles, same reasoning as the
|
|
1960
|
+
// html.reload path above.
|
|
1961
|
+
if(!Transparent.isPage(dom)) {
|
|
1962
|
+
_waitForFadeIn(function() { window.location.href = url; });
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1863
1965
|
|
|
1864
1966
|
// Layout not compatible.. needs to be reloaded (exception when POST is detected..)
|
|
1865
|
-
if(!Transparent.isCompatiblePage(dom, method, data))
|
|
1866
|
-
|
|
1967
|
+
if(!Transparent.isCompatiblePage(dom, method, data)) {
|
|
1968
|
+
_waitForFadeIn(function() { window.location.href = url; });
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1867
1971
|
|
|
1868
1972
|
// Mark layout as known
|
|
1869
1973
|
if(!Transparent.isKnownLayout(dom)) {
|
|
@@ -1896,8 +2000,18 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1896
2000
|
|
|
1897
2001
|
dispatchEvent(new Event('transparent:'+switchLayout));
|
|
1898
2002
|
|
|
1899
|
-
if($(dom).find("html").hasClass(Transparent.state.RELOAD) || $(dom).find("html").hasClass(Transparent.state.DISABLE))
|
|
1900
|
-
|
|
2003
|
+
if($(dom).find("html").hasClass(Transparent.state.RELOAD) || $(dom).find("html").hasClass(Transparent.state.DISABLE)) {
|
|
2004
|
+
// Defer the reload until fadeIn has finished, so the loader is
|
|
2005
|
+
// at full opacity when the browser unloads. Without this, a
|
|
2006
|
+
// fast AJAX response can fire reload() while fadeIn is still
|
|
2007
|
+
// mid-animation: the browser swaps to a page that starts with
|
|
2008
|
+
// .active (loader at 100%), and the user perceives a snap
|
|
2009
|
+
// from in-progress opacity to full. Reading as "fade-out then
|
|
2010
|
+
// fade-in" because the partial loader receded as the browser
|
|
2011
|
+
// swapped frames.
|
|
2012
|
+
_waitForFadeIn(function() { window.location.reload(); });
|
|
2013
|
+
return;
|
|
2014
|
+
}
|
|
1901
2015
|
|
|
1902
2016
|
// Kick off preloads for stylesheets the new page needs but aren't yet in <head>.
|
|
1903
2017
|
// They download in parallel during the fadeIn animation so onLoad() finds them
|
|
@@ -1959,7 +2073,17 @@ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addE
|
|
|
1959
2073
|
headers: Settings["headers"] || {},
|
|
1960
2074
|
xhr: function () { return xhr; },
|
|
1961
2075
|
success: function (html, status, request) { _tx("ajax SUCCESS", "status=" + request.status); return handleResponse(uuid, request.status, type, data, xhr, request); },
|
|
1962
|
-
error: function (request, ajaxOptions, thrownError) {
|
|
2076
|
+
error: function (request, ajaxOptions, thrownError) {
|
|
2077
|
+
_tx("ajax ERROR", "status=" + request.status + " textStatus=" + ajaxOptions);
|
|
2078
|
+
// status=0 with non-abort textStatus typically means the device
|
|
2079
|
+
// couldn't reach the server: dropped connection, DNS failure,
|
|
2080
|
+
// captive portal, etc. Flip to offline so the project's banner
|
|
2081
|
+
// surfaces even if navigator.onLine still reports true.
|
|
2082
|
+
if (request.status === 0 && ajaxOptions !== "abort") {
|
|
2083
|
+
setOnlineStatus(false);
|
|
2084
|
+
}
|
|
2085
|
+
return handleResponse(uuid, request.status, type, data, xhr, request);
|
|
2086
|
+
}
|
|
1963
2087
|
});
|
|
1964
2088
|
}
|
|
1965
2089
|
|