mishig HF staff commited on
Commit
f9b076a
·
1 Parent(s): ad5b25a
Files changed (1) hide show
  1. src/syncHFSpacesURLHash.js +96 -62
src/syncHFSpacesURLHash.js CHANGED
@@ -1,90 +1,124 @@
1
  const queryArg = "section";
2
 
3
- function syncHFSpacesURLHash(){
4
- // Check for section parameter in URL
5
- const urlParams = new URLSearchParams(window.location.search);
6
- const sectionId = urlParams.get(queryArg);
7
-
8
- if (sectionId) {
9
- // Find the element with the specified ID
10
- const targetElement = document.getElementById(sectionId);
11
-
12
- // scroll if the element exists
13
- if (targetElement) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  targetElement.scrollIntoView();
15
  history.replaceState(null, null, `#${sectionId}`);
16
- }
17
  }
 
 
 
 
 
 
18
 
19
- updateHashBasedOnHashChange();
20
-
21
- // Variables to manage throttling
22
- let isScrolling = false;
23
- let lastKnownScrollPosition = 0;
 
 
 
 
24
 
25
- // Add the scroll event listener here
26
- window.addEventListener('scroll', function() {
27
- lastKnownScrollPosition = window.scrollY;
28
-
29
- if (!isScrolling) {
30
- window.requestAnimationFrame(function() {
 
31
  updateHashBasedOnScroll(lastKnownScrollPosition);
32
- isScrolling = false;
33
- });
34
- }
35
-
36
- isScrolling = true;
37
- });
38
 
39
- // Initial hash update on page load
40
- updateHashBasedOnScroll(window.scrollY);
41
  }
42
 
43
  // Function to update the URL hash based on scroll position
44
  function updateHashBasedOnScroll(scrollPosition) {
45
- // Get only heading elements with IDs that we want to track
46
- const elementsWithIds = Array.from(document.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- // Skip updating if there are no elements with IDs
49
- if (elementsWithIds.length === 0) return;
 
 
50
 
51
- // Find the element closest to the top of the viewport
52
- let closestElement = null;
53
- let closestDistance = Infinity;
54
- const viewportMiddle = scrollPosition + window.innerHeight / 2;
55
 
56
- // Iterate through all elements with IDs to find the closest one
57
- elementsWithIds.forEach(element => {
58
- const elementTop = element.getBoundingClientRect().top + scrollPosition;
59
- const distance = Math.abs(elementTop - viewportMiddle);
60
-
61
- if (distance < closestDistance) {
62
- closestDistance = distance;
63
- closestElement = element;
64
- }
65
- });
66
-
67
- // Update the URL hash if we found a closest element
68
- if (closestElement && closestElement.id) {
69
- // Only update if the hash is different to avoid unnecessary history entries
70
- if (window.location.hash !== `#${closestElement.id}`) {
71
- // Update the URL without adding a new history entry
72
- history.replaceState(null, null, `#${closestElement.id}`);
73
- postMessageToHFSpaces(closestElement.id);
74
- }
75
  }
 
 
 
 
 
 
 
 
76
  }
77
 
78
  function updateHashBasedOnHashChange() {
79
  window.addEventListener('hashchange', () => {
80
- const elementId = window.location.hash.slice(1);
81
- postMessageToHFSpaces(elementId);
82
  });
83
  }
84
 
85
- function postMessageToHFSpaces(elementId){
86
  const parentOrigin = "https://huggingface.co";
87
  window.parent.postMessage({ queryString: `${queryArg}=${elementId}` }, parentOrigin);
88
  }
89
 
90
- export { syncHFSpacesURLHash };
 
1
  const queryArg = "section";
2
 
3
+ function syncHFSpacesURLHash() {
4
+ // Handle explicit section requests (don't update hash automatically on load)
5
+ const hasExplicitRequest = handleExplicitSectionRequest();
6
+
7
+ // Set up hash change monitoring
8
+ updateHashBasedOnHashChange();
9
+
10
+ // Always set up scroll monitoring to update hash during scrolling
11
+ setupScrollMonitoring();
12
+
13
+ // If no explicit request, we don't update the hash on initial load
14
+ // The hash will only start updating when the user scrolls
15
+ }
16
+
17
+ function handleExplicitSectionRequest() {
18
+ // Check for section parameter in URL
19
+ const urlParams = new URLSearchParams(window.location.search);
20
+ const sectionId = urlParams.get(queryArg);
21
+
22
+ // If we have an explicit section request
23
+ if (sectionId) {
24
+ const targetElement = document.getElementById(sectionId);
25
+ if (targetElement) {
26
+ // Slight delay to ensure the browser doesn't try to do its own scrolling first
27
+ setTimeout(() => {
28
  targetElement.scrollIntoView();
29
  history.replaceState(null, null, `#${sectionId}`);
30
+ }, 100);
31
  }
32
+ return true;
33
+ }
34
+
35
+ // No explicit section parameter found
36
+ return false;
37
+ }
38
 
39
+ function setupScrollMonitoring() {
40
+ // Variables to manage throttling
41
+ let isScrolling = false;
42
+ let lastKnownScrollPosition = 0;
43
+ let initialScroll = true;
44
+
45
+ // Add the scroll event listener
46
+ window.addEventListener('scroll', function() {
47
+ lastKnownScrollPosition = window.scrollY;
48
 
49
+ if (!isScrolling) {
50
+ window.requestAnimationFrame(function() {
51
+ // Skip the first scroll event which might be browser's automatic scroll
52
+ // to a hash on page load
53
+ if (initialScroll) {
54
+ initialScroll = false;
55
+ } else {
56
  updateHashBasedOnScroll(lastKnownScrollPosition);
57
+ }
58
+ isScrolling = false;
59
+ });
60
+ }
 
 
61
 
62
+ isScrolling = true;
63
+ });
64
  }
65
 
66
  // Function to update the URL hash based on scroll position
67
  function updateHashBasedOnScroll(scrollPosition) {
68
+ const closestHeading = findClosestHeading(scrollPosition);
69
+
70
+ // Update the URL hash if we found a closest element
71
+ if (closestHeading && closestHeading.id) {
72
+ // Only update if the hash is different to avoid unnecessary operations
73
+ if (window.location.hash !== `#${closestHeading.id}`) {
74
+ silentlyUpdateHash(closestHeading.id);
75
+ postMessageToHFSpaces(closestHeading.id);
76
+ }
77
+ }
78
+ }
79
+
80
+ // Find the closest heading to the current scroll position
81
+ function findClosestHeading(scrollPosition) {
82
+ // Get only heading elements with IDs that we want to track
83
+ const headingsWithIds = Array.from(document.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]'));
84
+
85
+ // Skip if there are no headings with IDs
86
+ if (headingsWithIds.length === 0) return null;
87
 
88
+ // Find the element closest to the middle of the viewport
89
+ let closestHeading = null;
90
+ let closestDistance = Infinity;
91
+ const viewportMiddle = scrollPosition + window.innerHeight / 2;
92
 
93
+ // Iterate through all headings to find the closest one
94
+ headingsWithIds.forEach(heading => {
95
+ const headingTop = heading.getBoundingClientRect().top + scrollPosition;
96
+ const distance = Math.abs(headingTop - viewportMiddle);
97
 
98
+ if (distance < closestDistance) {
99
+ closestDistance = distance;
100
+ closestHeading = heading;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
102
+ });
103
+
104
+ return closestHeading;
105
+ }
106
+
107
+ // Update hash without triggering scroll or other side effects
108
+ function silentlyUpdateHash(id) {
109
+ history.replaceState(null, null, `#${id}`);
110
  }
111
 
112
  function updateHashBasedOnHashChange() {
113
  window.addEventListener('hashchange', () => {
114
+ const elementId = window.location.hash.slice(1);
115
+ postMessageToHFSpaces(elementId);
116
  });
117
  }
118
 
119
+ function postMessageToHFSpaces(elementId) {
120
  const parentOrigin = "https://huggingface.co";
121
  window.parent.postMessage({ queryString: `${queryArg}=${elementId}` }, parentOrigin);
122
  }
123
 
124
+ export { syncHFSpacesURLHash };