|
47 | 47 | }); |
48 | 48 | // Ensure search results stay on developers.procore.com under /documentation |
49 | 49 | var basePath = "/documentation"; |
50 | | - |
51 | | - // Function to rewrite search result links for iframe display |
52 | | - function rewriteSearchResultLinks() { |
53 | | - if (window.self !== window.top) { |
54 | | - try { |
55 | | - var parentOrigin = window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0 |
56 | | - ? window.location.ancestorOrigins[0] |
57 | | - : document.referrer ? new URL(document.referrer).origin : null; |
58 | | - |
59 | | - if (parentOrigin) { |
60 | | - $("#results-container a").each(function() { |
61 | | - var $link = $(this); |
62 | | - var originalHref = $link.attr("href"); |
63 | | - |
64 | | - // Skip if already processed or special links |
65 | | - if ($link.data("original-href") || !originalHref || originalHref.startsWith("#") || originalHref.startsWith("mailto:") || originalHref.startsWith("javascript:") || originalHref.startsWith("data:") || originalHref.startsWith("vbscript:")) { |
66 | | - return; |
67 | | - } |
68 | | - |
69 | | - // Get the path from the href |
70 | | - var path = originalHref; |
71 | | - if (!path.startsWith("/")) { |
72 | | - path = "/" + path; |
73 | | - } |
74 | | - |
75 | | - // Store original and set to parent origin for hover display |
76 | | - $link.data("original-href", originalHref); |
77 | | - $link.attr("href", parentOrigin + path); |
78 | | - }); |
79 | | - } |
80 | | - } catch (err) { |
81 | | - console.warn("Could not rewrite search result links:", err); |
82 | | - } |
83 | | - } |
84 | | - } |
85 | | - |
86 | 50 | var sjs = SimpleJekyllSearch({ |
87 | 51 | searchInput: document.getElementById("search-input"), |
88 | 52 | resultsContainer: document.getElementById("results-container"), |
|
101 | 65 | return path + (u.search || "") + (u.hash || ""); |
102 | 66 | } catch (e) { |
103 | 67 | // Fallback for odd values (e.g., "page.html" or "#anchor") |
104 | | - console.error("Error parsing URL in templateMiddleware:", e, "value:", value); |
105 | 68 | if (value.charAt(0) === "#") return value; |
106 | 69 | return basePath.replace(/\/$/, "") + "/" + value.replace(/^\//, ""); |
107 | 70 | } |
108 | 71 | } |
109 | 72 | return value; |
110 | 73 | }, |
111 | | - noResultsText: "No results found", |
112 | | - limit: 10, |
113 | | - fuzzy: false |
114 | 74 | }); |
115 | | - |
116 | | - // Use MutationObserver to rewrite search result links when they're added |
117 | | - if (window.self !== window.top) { |
118 | | - var resultsContainer = document.getElementById("results-container"); |
119 | | - if (resultsContainer) { |
120 | | - var observer = new MutationObserver(function(mutations) { |
121 | | - rewriteSearchResultLinks(); |
122 | | - }); |
123 | | - observer.observe(resultsContainer, { |
124 | | - childList: true, |
125 | | - subtree: true |
126 | | - }); |
127 | | - } |
128 | | - } |
129 | | - // Handle clicks on search result links - navigate within iframe if in one |
| 75 | + // Defensive: if a result link is absolute and points off-site, rewrite it to this host |
130 | 76 | $("#results-container").on("click", "a", function (e) { |
131 | | - var $link = $(this); |
132 | | - var currentHref = $link.attr("href"); |
133 | | - var originalHref = $link.data("original-href"); |
134 | | - |
135 | | - if (!currentHref) return; |
136 | | - |
137 | | - // If in iframe and link points to parent origin, navigate within iframe |
138 | | - if (window.self !== window.top) { |
139 | | - try { |
140 | | - var parentOrigin = window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0 |
141 | | - ? window.location.ancestorOrigins[0] |
142 | | - : document.referrer ? new URL(document.referrer).origin : null; |
143 | | - |
144 | | - if (parentOrigin && currentHref.startsWith(parentOrigin)) { |
145 | | - e.preventDefault(); |
146 | | - var path = new URL(currentHref).pathname + new URL(currentHref).search + new URL(currentHref).hash; |
147 | | - // Update iframe location |
148 | | - window.location.href = path; |
149 | | - // Update parent window URL via postMessage (cross-origin safe) |
150 | | - try { |
151 | | - window.parent.postMessage({ |
152 | | - type: 'documentationNavigation', |
153 | | - path: path, |
154 | | - fullUrl: parentOrigin + path |
155 | | - }, parentOrigin); |
156 | | - } catch (e) { |
157 | | - console.warn("Could not send navigation message to parent:", e); |
158 | | - } |
159 | | - return false; |
160 | | - } |
161 | | - } catch (err) { |
162 | | - console.error("Error handling search result link click:", err); |
163 | | - } |
164 | | - } |
165 | | - |
166 | | - // Fallback: handle absolute URLs pointing off-site |
167 | | - if (/^https?:\/\//i.test(currentHref)) { |
| 77 | + var href = $(this).attr("href"); |
| 78 | + if (!href) return; |
| 79 | + // Only act on absolute URLs |
| 80 | + if (/^https?:\/\//i.test(href)) { |
168 | 81 | try { |
169 | | - var u = new URL(currentHref); |
| 82 | + var u = new URL(href); |
170 | 83 | if (u.origin !== window.location.origin) { |
171 | 84 | e.preventDefault(); |
172 | 85 | var path = u.pathname; |
173 | 86 | if (!path.startsWith(basePath)) { |
174 | 87 | path = basePath.replace(/\/$/, "") + "/" + path.replace(/^\//, ""); |
175 | 88 | } |
176 | | - var newUrl = path + (u.search || "") + (u.hash || ""); |
177 | | - window.location.href = newUrl; |
178 | | - return false; |
| 89 | + window.location.href = path + (u.search || "") + (u.hash || ""); |
179 | 90 | } |
180 | 91 | } catch (err) { |
181 | | - console.error("Error handling absolute URL in search result click:", err, "href:", currentHref); |
| 92 | + // ignore malformed URLs |
182 | 93 | } |
183 | 94 | } |
184 | 95 | }); |
185 | | - |
186 | | - // If in an iframe, rewrite link hrefs for hover display but intercept clicks to navigate within iframe |
187 | | - if (window.self !== window.top) { |
188 | | - try { |
189 | | - var parentOrigin = window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0 |
190 | | - ? window.location.ancestorOrigins[0] |
191 | | - : document.referrer ? new URL(document.referrer).origin : null; |
192 | | - |
193 | | - if (parentOrigin) { |
194 | | - // Function to get the actual path from a href |
195 | | - function getPathFromHref(href) { |
196 | | - if (!href || href.startsWith("#") || href.startsWith("mailto:") || href.startsWith("javascript:") || href.startsWith("data:") || href.startsWith("vbscript:")) { |
197 | | - return null; |
198 | | - } |
199 | | - try { |
200 | | - if (href.match(/^https?:\/\//)) { |
201 | | - return new URL(href).pathname + new URL(href).search + new URL(href).hash; |
202 | | - } else { |
203 | | - // Relative URL |
204 | | - return href.startsWith("/") ? href : "/" + href; |
205 | | - } |
206 | | - } catch (e) { |
207 | | - console.error("Error parsing href in getPathFromHref:", e, "href:", href); |
208 | | - return href.startsWith("/") ? href : "/" + href; |
209 | | - } |
210 | | - } |
211 | | - |
212 | | - // Rewrite navigation links for hover display |
213 | | - $("nav a").each(function() { |
214 | | - var $link = $(this); |
215 | | - var originalHref = $link.attr("href"); |
216 | | - var path = getPathFromHref(originalHref); |
217 | | - |
218 | | - if (path && !path.startsWith("#") && !path.startsWith("mailto:") && !path.startsWith("javascript:") && !path.startsWith("data:") && !path.startsWith("vbscript:")) { |
219 | | - // Store original href in data attribute |
220 | | - $link.data("original-href", originalHref); |
221 | | - // Set href to parent origin for hover display |
222 | | - $link.attr("href", parentOrigin + path); |
223 | | - } |
224 | | - }); |
225 | | - |
226 | | - // Rewrite links in main content area for hover display |
227 | | - $("main a").each(function() { |
228 | | - var $link = $(this); |
229 | | - var originalHref = $link.attr("href"); |
230 | | - var path = getPathFromHref(originalHref); |
231 | | - |
232 | | - if (path && !path.startsWith("#") && !path.startsWith("mailto:") && !path.startsWith("javascript:") && !path.startsWith("data:") && !path.startsWith("vbscript:")) { |
233 | | - // Store original href in data attribute |
234 | | - $link.data("original-href", originalHref); |
235 | | - // Set href to parent origin for hover display |
236 | | - $link.attr("href", parentOrigin + path); |
237 | | - } |
238 | | - }); |
239 | | - |
240 | | - // Intercept clicks on navigation and content links to navigate within iframe |
241 | | - $(document).on("click", "nav a, main a", function(e) { |
242 | | - var $link = $(this); |
243 | | - var originalHref = $link.data("original-href"); |
244 | | - var currentHref = $link.attr("href"); |
245 | | - |
246 | | - // If we have a stored original href, use it; otherwise check current href |
247 | | - var hrefToUse = originalHref || currentHref; |
248 | | - |
249 | | - // Skip external links, anchors, and special protocols |
250 | | - if (!hrefToUse || hrefToUse.startsWith("#") || hrefToUse.startsWith("mailto:") || hrefToUse.startsWith("javascript:") || hrefToUse.startsWith("data:") || hrefToUse.startsWith("vbscript:")) { |
251 | | - return; // Let default behavior handle these |
252 | | - } |
253 | | - |
254 | | - // If current href points to parent origin (for display), navigate using the path within iframe |
255 | | - if (currentHref && currentHref.startsWith(parentOrigin)) { |
256 | | - e.preventDefault(); |
257 | | - var path = new URL(currentHref).pathname + new URL(currentHref).search + new URL(currentHref).hash; |
258 | | - // Update iframe location |
259 | | - window.location.href = path; |
260 | | - // Update parent window URL via postMessage (cross-origin safe) |
261 | | - try { |
262 | | - window.parent.postMessage({ |
263 | | - type: 'documentationNavigation', |
264 | | - path: path, |
265 | | - fullUrl: parentOrigin + path |
266 | | - }, parentOrigin); |
267 | | - } catch (e) { |
268 | | - console.warn("Could not send navigation message to parent:", e); |
269 | | - } |
270 | | - return false; |
271 | | - } else if (hrefToUse.match(/^https?:\/\//) && !hrefToUse.startsWith(window.location.origin) && !hrefToUse.startsWith(parentOrigin)) { |
272 | | - // External link (not parent origin, not current origin) - let it open normally |
273 | | - return; |
274 | | - } else if (originalHref && originalHref.startsWith(parentOrigin)) { |
275 | | - // Original href was parent origin - navigate within iframe |
276 | | - e.preventDefault(); |
277 | | - var path = new URL(originalHref).pathname + new URL(originalHref).search + new URL(originalHref).hash; |
278 | | - // Update iframe location |
279 | | - window.location.href = path; |
280 | | - // Update parent window URL via postMessage (cross-origin safe) |
281 | | - try { |
282 | | - window.parent.postMessage({ |
283 | | - type: 'documentationNavigation', |
284 | | - path: path, |
285 | | - fullUrl: parentOrigin + path |
286 | | - }, parentOrigin); |
287 | | - } catch (e) { |
288 | | - console.warn("Could not send navigation message to parent:", e); |
289 | | - } |
290 | | - return false; |
291 | | - } else if (hrefToUse && !hrefToUse.match(/^https?:\/\//)) { |
292 | | - // Relative link - navigate within iframe and update parent URL |
293 | | - e.preventDefault(); |
294 | | - var path = hrefToUse.startsWith("/") ? hrefToUse : "/" + hrefToUse; |
295 | | - // Update iframe location |
296 | | - window.location.href = path; |
297 | | - // Update parent window URL via postMessage (cross-origin safe) |
298 | | - try { |
299 | | - window.parent.postMessage({ |
300 | | - type: 'documentationNavigation', |
301 | | - path: path, |
302 | | - fullUrl: parentOrigin + path |
303 | | - }, parentOrigin); |
304 | | - } catch (e) { |
305 | | - console.warn("Could not send navigation message to parent:", e); |
306 | | - } |
307 | | - return false; |
308 | | - } |
309 | | - // For other cases, let default behavior work |
310 | | - }); |
311 | | - } |
312 | | - } catch (err) { |
313 | | - console.warn("Could not rewrite links for parent origin:", err); |
314 | | - } |
315 | | - } |
316 | 96 | })(); |
0 commit comments