@glitchr/transparent 1.0.54 → 1.0.56

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/js/transparent.js +129 -85
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glitchr/transparent",
3
- "version": "1.0.54",
3
+ "version": "1.0.56",
4
4
  "description": "Transparent SPA Application",
5
5
  "main": "src/index.js",
6
6
  "access": "public",
@@ -1,3 +1,10 @@
1
+ // Modern browser: use passive event listeners where appropriate for better performance
2
+ jQuery.event.special.touchstart = { setup: function( _, ns, handle ) { this.addEventListener("touchstart", handle, { passive: !ns.includes("noPreventDefault") }); } };
3
+ jQuery.event.special.touchmove = { setup: function( _, ns, handle ) { this.addEventListener("touchmove", handle, { passive: !ns.includes("noPreventDefault") }); } };
4
+ jQuery.event.special.wheel = { setup: function( _, ns, handle ) { this.addEventListener("wheel", handle, { passive: true }); } };
5
+ jQuery.event.special.mousewheel = { setup: function( _, ns, handle ) { this.addEventListener("mousewheel", handle, { passive: true }); } };
6
+
7
+ // Transparent.js
1
8
  (function (root, factory) {
2
9
 
3
10
  if (typeof define === 'function' && define.amd) {
@@ -19,6 +26,7 @@
19
26
  if(!newHash) newHash = "";
20
27
  if (newHash !== "" && (''+newHash).charAt(0) !== '#')
21
28
  newHash = '#' + newHash;
29
+
22
30
  var newURL = location.origin+location.pathname+newHash;
23
31
  var newHashElement = $(newHash);
24
32
 
@@ -154,7 +162,7 @@
154
162
 
155
163
  var Transparent = window.Transparent = {};
156
164
  Transparent.version = '0.1.0';
157
-
165
+
158
166
  var Settings = Transparent.settings = {
159
167
  "headers": {},
160
168
  "data": {},
@@ -435,11 +443,16 @@
435
443
  Transparent.addLayout();
436
444
  Transparent.lazyLoad();
437
445
 
438
- Transparent.scrollToHash(location.hash, {}, function() {
439
-
440
- Transparent.activeOut(() => Transparent.html.removeClass(Transparent.state.FIRST));
441
- });
446
+ const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
447
+ const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
448
+ window.previousScroll = {top: scrollTop, left: scrollLeft};
442
449
 
450
+ if($(Transparent.html).hasClass(Transparent.state.FIRST)) {
451
+ Transparent.scrollToHash(location.hash, {}, function() {
452
+ Transparent.activeOut(() => Transparent.html.removeClass(Transparent.state.FIRST));
453
+ });
454
+ }
455
+
443
456
  return this;
444
457
  };
445
458
 
@@ -537,6 +550,7 @@
537
550
  var href = el.target.getAttribute("action");
538
551
  if(!href) href = location.pathname + href;
539
552
 
553
+
540
554
  if (href.startsWith("#")) href = location.pathname + href;
541
555
  if (href.endsWith ("#")) href = href.slice(0, -1);
542
556
 
@@ -551,6 +565,7 @@
551
565
 
552
566
  if(!$(el).hasClass("skip-validation") && !form.checkValidity()) {
553
567
  console.error("Invalid form submission.", el);
568
+ form.classList.add('was-validated');
554
569
  return null;
555
570
  }
556
571
 
@@ -596,6 +611,7 @@
596
611
 
597
612
  if(!$(el).hasClass("skip-validation") && !form.checkValidity()) {
598
613
  console.error("Invalid form submission.", el);
614
+ form.classList.add('was-validated');
599
615
  return null;
600
616
  }
601
617
 
@@ -836,7 +852,7 @@
836
852
  Transparent.html.removeClass(Transparent.state.ACTIVEOUT);
837
853
  if(Transparent.html.hasClass(Transparent.state.LOADING)) {
838
854
 
839
- dispatchEvent(new Event('transparent:'+Transparent.state.LOAD));
855
+ dispatchEvent(new Event('transparent:'+Transparent.state.LOADING));
840
856
 
841
857
  Object.values(Transparent.state).forEach(e => Transparent.html.removeClass(e));
842
858
  Transparent.html.addClass(Transparent.state.ROOT + " " + Transparent.state.READY);
@@ -945,69 +961,73 @@
945
961
  Transparent.userScroll = function(el = undefined) { return $(el === undefined ? document.documentElement : el).closestScrollable().prop("user-scroll") ?? true; }
946
962
  Transparent.scrollTo = function(dict, el = window, callback = function() {})
947
963
  {
948
- el = $(el).length ? $(el)[0] : window;
949
- if (el === window )
950
- el = document.documentElement;
951
- if (el === document)
952
- el = document.documentElement;
953
-
954
- var maxScrollX = $(el).prop("scrollWidth") - Math.round($(el).prop("clientWidth"));
955
- if (maxScrollX == 0) maxScrollX = Math.round($(el).prop("clientWidth"));
956
- var maxScrollY = $(el).prop("scrollHeight") - Math.round($(el).prop("clientHeight"));
957
- if (maxScrollY == 0) maxScrollY = Math.round($(el).prop("clientHeight"));
958
-
959
- scrollTop = Math.max(0, Math.min(dict["top"] ?? $(el).prop("scrollTop"), maxScrollY));
960
- scrollLeft = Math.max(0, Math.min(dict["left"] ?? $(el).prop("scrollLeft"), maxScrollX));
961
-
962
- speed = parseFloat(dict["speed"] ?? 0);
963
- easing = dict["easing"] ?? "swing";
964
- debounce = dict["debounce"] ?? 0;
965
-
966
- duration = 1000*Transparent.parseDuration(dict["duration"] ?? 0);
967
- durationX = 1000*Transparent.parseDuration(dict["duration-x"] ?? dict["duration"] ?? 0);
968
- durationY = 1000*Transparent.parseDuration(dict["duration-y"] ?? dict["duration"] ?? 0);
969
-
970
- if(speed) {
971
-
972
- var currentScrollX = $(el)[0].scrollLeft;
973
- if(currentScrollX < scrollLeft || scrollLeft == 0) // Going to the right
974
- distanceX = Math.abs(scrollLeft - currentScrollX);
975
- else // Going back to 0 position
976
- distanceX = currentScrollX;
977
-
978
- var currentScrollY = $(el)[0].scrollTop;
979
- if(currentScrollY <= scrollTop || scrollTop == 0) // Going to the right
980
- distanceY = Math.abs(scrollTop - currentScrollY);
981
- else // Going back to 0 position
982
- distanceY = currentScrollY;
983
-
984
- durationX = speed ? 1000*distanceX/speed : durationX;
985
- durationY = speed ? 1000*distanceY/speed : durationY;
986
- duration = durationX+durationY;
987
- }
964
+ setTimeout(function() {
988
965
 
989
- var callbackWrapper = function() {
966
+ el = $(el).length ? $(el)[0] : window;
967
+ if (el === window )
968
+ el = document.documentElement;
969
+ if (el === document)
970
+ el = document.documentElement;
971
+
972
+ var maxScrollX = $(el).prop("scrollWidth") - Math.round($(el).prop("clientWidth"));
973
+ if (maxScrollX == 0) maxScrollX = Math.round($(el).prop("clientWidth"));
974
+ var maxScrollY = $(el).prop("scrollHeight") - Math.round($(el).prop("clientHeight"));
975
+ if (maxScrollY == 0) maxScrollY = Math.round($(el).prop("clientHeight"));
976
+
977
+ scrollTop = Math.max(0, Math.min(dict["top"] ?? $(el).prop("scrollTop"), maxScrollY));
978
+ scrollLeft = Math.max(0, Math.min(dict["left"] ?? $(el).prop("scrollLeft"), maxScrollX));
979
+
980
+ speed = parseFloat(dict["speed"] ?? 0);
981
+ easing = dict["easing"] ?? "swing";
982
+ debounce = dict["debounce"] ?? 0;
983
+
984
+ duration = 1000*Transparent.parseDuration(dict["duration"] ?? 0);
985
+ durationX = 1000*Transparent.parseDuration(dict["duration-x"] ?? dict["duration"] ?? 0);
986
+ durationY = 1000*Transparent.parseDuration(dict["duration-y"] ?? dict["duration"] ?? 0);
987
+
988
+ if(speed) {
989
+
990
+ var currentScrollX = $(el)[0].scrollLeft;
991
+ if(currentScrollX < scrollLeft || scrollLeft == 0) // Going to the right
992
+ distanceX = Math.abs(scrollLeft - currentScrollX);
993
+ else // Going back to 0 position
994
+ distanceX = currentScrollX;
995
+
996
+ var currentScrollY = $(el)[0].scrollTop;
997
+ if(currentScrollY <= scrollTop || scrollTop == 0) // Going to the right
998
+ distanceY = Math.abs(scrollTop - currentScrollY);
999
+ else // Going back to 0 position
1000
+ distanceY = currentScrollY;
1001
+
1002
+ durationX = speed ? 1000*distanceX/speed : durationX;
1003
+ durationY = speed ? 1000*distanceY/speed : durationY;
1004
+ duration = durationX+durationY;
1005
+ }
990
1006
 
991
- el.dispatchEvent(new Event('scroll'));
992
- callback();
1007
+ var callbackWrapper = function() {
993
1008
 
994
- $(el).prop("user-scroll", true);
995
- };
1009
+ el.dispatchEvent(new Event('scroll'));
1010
+ callback();
996
1011
 
997
- if(duration == 0) {
1012
+ $(el).prop("user-scroll", true);
1013
+ };
998
1014
 
999
- el.scrollTo(scrollLeft, scrollTop);
1000
- el.dispatchEvent(new Event('scroll'));
1001
- callback();
1015
+ if(duration == 0) {
1002
1016
 
1003
- $(el).prop("user-scroll", true);
1017
+ el.scrollTo(scrollLeft, scrollTop);
1018
+ el.dispatchEvent(new Event('scroll'));
1019
+ callback();
1004
1020
 
1005
- } else {
1021
+ $(el).prop("user-scroll", true);
1006
1022
 
1007
- $(el).animate({scrollTop: scrollTop}, durationY, easing,
1008
- () => $(el).animate({scrollLeft: scrollLeft}, durationX, easing, Transparent.debounce(callbackWrapper, debounce))
1009
- );
1010
- }
1023
+ } else {
1024
+
1025
+ $(el).stop(true).animate({scrollTop: scrollTop}, durationY, easing,
1026
+ () => $(el).stop(true).animate({scrollLeft: scrollLeft}, durationX, easing, Transparent.debounce(callbackWrapper, debounce))
1027
+ );
1028
+ }
1029
+
1030
+ }.bind(this), 1);
1011
1031
 
1012
1032
  return this;
1013
1033
  }
@@ -1194,6 +1214,14 @@
1194
1214
  window.previousLocation = window.location.toString();
1195
1215
  if(callback === null) callback = function() {};
1196
1216
 
1217
+ $(Transparent.html).data("autoscroll-prevent", false);
1218
+ $(Transparent.html).off("wheel.autoscroll DOMMouseScroll.autoscroll mousewheel.autoscroll touchstart.autoscroll");
1219
+ $(Transparent.html).on("wheel.autoscroll DOMMouseScroll.autoscroll mousewheel.autoscroll touchstart.autoscroll", function(e) {
1220
+
1221
+ $(this).prop("user-scroll", true);
1222
+ $(this).stop();
1223
+ });
1224
+
1197
1225
  activeInRemainingTime = activeInRemainingTime - (Date.now() - activeInTime);
1198
1226
  setTimeout(function() {
1199
1227
 
@@ -1386,26 +1414,30 @@
1386
1414
 
1387
1415
  Transparent.scrollToHash = function(hash = window.location.hash, options = {}, callback = function() {}, el = window)
1388
1416
  {
1389
- if (hash !== "") {
1417
+ setTimeout(function() {
1390
1418
 
1391
- if ((''+hash).charAt(0) !== '#')
1392
- hash = '#' + hash;
1419
+ if (hash !== "") {
1393
1420
 
1394
- var hashElement = $(hash)[0] ?? undefined;
1395
- if (hashElement !== undefined) {
1421
+ if ((''+hash).charAt(0) !== '#')
1422
+ hash = '#' + hash;
1396
1423
 
1397
- var scrollTop = hashElement.getBoundingClientRect().top + document.documentElement.scrollTop - Transparent.getScrollPadding().top;
1398
- var scrollLeft = hashElement.getBoundingClientRect().left + document.documentElement.scrollLeft - Transparent.getScrollPadding().left;
1424
+ var hashElement = $(hash)[0] ?? undefined;
1425
+ if (hashElement !== undefined) {
1399
1426
 
1400
- options = Object.assign({duration: Settings["smoothscroll_duration"], speed: Settings["smoothscroll_speed"]}, options, {left:scrollLeft, top:scrollTop});
1401
- }
1427
+ var scrollTop = hashElement.getBoundingClientRect().top + document.documentElement.scrollTop - Transparent.getScrollPadding().top;
1428
+ var scrollLeft = hashElement.getBoundingClientRect().left + document.documentElement.scrollLeft - Transparent.getScrollPadding().left;
1402
1429
 
1403
- var bottomReach = document.body.scrollHeight - (window.scrollY + window.innerHeight) < 1;
1404
- var bottomOverflow = scrollTop > window.scrollY + window.innerHeight;
1405
- }
1430
+ options = Object.assign({duration: Settings["smoothscroll_duration"], speed: Settings["smoothscroll_speed"]}, options, {left:scrollLeft, top:scrollTop});
1431
+ }
1432
+
1433
+ var bottomReach = document.body.scrollHeight - (window.scrollY + window.innerHeight) < 1;
1434
+ var bottomOverflow = scrollTop > window.scrollY + window.innerHeight;
1435
+ }
1406
1436
 
1407
- if(hash === "" || (bottomReach && bottomOverflow)) callback({}, el);
1408
- else Transparent.scrollTo(options, el, callback);
1437
+ if(hash === "" || (bottomReach && bottomOverflow)) callback({}, el);
1438
+ else Transparent.scrollTo(options, el, callback);
1439
+
1440
+ }.bind(this), 1); // minimal delay to ensure the element is rendered
1409
1441
 
1410
1442
  return this;
1411
1443
  }
@@ -1440,7 +1472,10 @@
1440
1472
 
1441
1473
  // Determine link
1442
1474
  const link = Transparent.findLink(e);
1443
- if (link == null) return;
1475
+ if (link == null) {
1476
+ e.preventDefault();
1477
+ return;
1478
+ }
1444
1479
 
1445
1480
  dispatchEvent(new CustomEvent('transparent:link', {link:link}));
1446
1481
 
@@ -1495,10 +1530,18 @@
1495
1530
  }
1496
1531
 
1497
1532
  // Specific page exception
1498
- for(i = 0; i < Settings.exceptions.length; i++) {
1499
-
1500
- exception = Settings.exceptions[i];
1501
- if (url.pathname.startsWith(exception)) return;
1533
+ for (let i = 0; i < Settings.exceptions.length; i++) {
1534
+ let exception = Settings.exceptions[i];
1535
+ if (exception instanceof RegExp) {
1536
+ if (exception.test(url.pathname)) return;
1537
+ } else {
1538
+ // Simple wildcard support: * matches any sequence of characters
1539
+ let pattern = exception.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
1540
+ let regex = new RegExp('^' + pattern + '$');
1541
+ if (regex.test(url.pathname)) {
1542
+ return;
1543
+ }
1544
+ }
1502
1545
  }
1503
1546
 
1504
1547
  // Ressources files rejected
@@ -1521,7 +1564,7 @@
1521
1564
  Transparent.scrollToHash(url.hash ?? "", {easing:Settings["smoothscroll_easing"], duration:Settings["smoothscroll_duration"], speed:Settings["smoothscroll_speed"]}, function() {
1522
1565
 
1523
1566
  if (e.target != undefined && $(e.target).data("skip-hash") != true)
1524
- window.replaceHash(url.hash);
1567
+ window.location.hash = url.hash;
1525
1568
 
1526
1569
  }, $(e.target).closestScrollable());
1527
1570
 
@@ -1532,8 +1575,9 @@
1532
1575
  if(e.metaKey && e.shiftKey) return window.open(url, '_blank').focus(); // Safari not focusing..
1533
1576
  if(e.metaKey || $(target).attr("target") == "_blank") return window.open(url, '_blank');
1534
1577
 
1535
- dispatchEvent(new Event('transparent:onbeforeunload'));
1536
- dispatchEvent(new Event('onbeforeunload'));
1578
+ // right (still limited by browser policy):
1579
+ dispatchEvent(new Event('transparent:beforeunload'));
1580
+ dispatchEvent(new Event('beforeunload', { cancelable: true }));
1537
1581
 
1538
1582
  $(Transparent.html).prop("user-scroll", true);
1539
1583
  $(Transparent.html).stop();
@@ -1772,6 +1816,8 @@
1772
1816
 
1773
1817
  window.onbeforeunload = function(e) {
1774
1818
 
1819
+ if(Settings.debug) console.log("Transparent onbeforeunload event called..");
1820
+
1775
1821
  if(formSubmission) return; // Do not display on form submission
1776
1822
  if(Settings.disable) return;
1777
1823
 
@@ -1802,8 +1848,6 @@
1802
1848
 
1803
1849
  var formDataBeforeKeys = Object.keys(formDataBefore);
1804
1850
  var formDataAfterKeys = Object.keys(formDataAfter);
1805
- var formDataBeforeEntries = Object.entries(formDataBefore);
1806
- var formDataAfterEntries = Object.entries(formDataAfter);
1807
1851
  function same(a, b) { return JSON.stringify(a) === JSON.stringify(b); }
1808
1852
  function sameKeys(a, b) {
1809
1853