Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions _layouts/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@
<meta name="description" content="Documentation for Procore developers" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">

<title>{{ page.title }}</title>
<base target="_parent">
<script>
// Only set base target="_parent" if NOT in an iframe
// This allows iframed pages to navigate within the iframe
if (window.self === window.top) {
var base = document.createElement('base');
base.target = '_parent';
document.head.appendChild(base);
}
</script>
<link rel="stylesheet" href="{{ 'assets/css/main.css' | relative_url }}">
<link rel="stylesheet" href="{{ site.baseurl }}/assets/css/nav.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
Expand All @@ -23,7 +32,7 @@
<dl class="col_content">
{% for item in section.items %}
<dd{% if item.url == page.url %} class="active"{% endif %}>
<a href="{% if item.absolute != true %}{{ site.url }}{{ site.baseurl }}{% endif %}{{ item.url }}">
<a href="{% if item.absolute == true %}{{ site.url }}{{ site.baseurl }}{{ item.url }}{% else %}{{ item.url | relative_url }}{% endif %}">
<!-- <a href="https://b601-208-127-107-52.ngrok-free.app/documentation{{ item.url }}"> -->
{{ item.title }}
</a>
Expand Down
236 changes: 228 additions & 8 deletions assets/js/nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,42 @@
});
// Ensure search results stay on developers.procore.com under /documentation
var basePath = "/documentation";

// Function to rewrite search result links for iframe display
function rewriteSearchResultLinks() {
if (window.self !== window.top) {
try {
var parentOrigin = window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0
? window.location.ancestorOrigins[0]
: document.referrer ? new URL(document.referrer).origin : null;

if (parentOrigin) {
$("#results-container a").each(function() {
var $link = $(this);
var originalHref = $link.attr("href");

// Skip if already processed or special links
if ($link.data("original-href") || !originalHref || originalHref.startsWith("#") || originalHref.startsWith("mailto:") || originalHref.startsWith("javascript:") || originalHref.startsWith("data:") || originalHref.startsWith("vbscript:")) {
return;
}

// Get the path from the href
var path = originalHref;
if (!path.startsWith("/")) {
path = "/" + path;
}

// Store original and set to parent origin for hover display
$link.data("original-href", originalHref);
$link.attr("href", parentOrigin + path);
});
}
} catch (err) {
console.warn("Could not rewrite search result links:", err);
}
}
}

var sjs = SimpleJekyllSearch({
searchInput: document.getElementById("search-input"),
resultsContainer: document.getElementById("results-container"),
Expand All @@ -65,32 +101,216 @@
return path + (u.search || "") + (u.hash || "");
} catch (e) {
// Fallback for odd values (e.g., "page.html" or "#anchor")
console.error("Error parsing URL in templateMiddleware:", e, "value:", value);
if (value.charAt(0) === "#") return value;
return basePath.replace(/\/$/, "") + "/" + value.replace(/^\//, "");
}
}
return value;
},
noResultsText: "No results found",
limit: 10,
fuzzy: false
});
// Defensive: if a result link is absolute and points off-site, rewrite it to this host

// Use MutationObserver to rewrite search result links when they're added
if (window.self !== window.top) {
var resultsContainer = document.getElementById("results-container");
if (resultsContainer) {
var observer = new MutationObserver(function(mutations) {
rewriteSearchResultLinks();
});
observer.observe(resultsContainer, {
childList: true,
subtree: true
});
}
}
// Handle clicks on search result links - navigate within iframe if in one
$("#results-container").on("click", "a", function (e) {
var href = $(this).attr("href");
if (!href) return;
// Only act on absolute URLs
if (/^https?:\/\//i.test(href)) {
var $link = $(this);
var currentHref = $link.attr("href");
var originalHref = $link.data("original-href");

if (!currentHref) return;

// If in iframe and link points to parent origin, navigate within iframe
if (window.self !== window.top) {
try {
var parentOrigin = window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0
? window.location.ancestorOrigins[0]
: document.referrer ? new URL(document.referrer).origin : null;

if (parentOrigin && currentHref.startsWith(parentOrigin)) {
e.preventDefault();
var path = new URL(currentHref).pathname + new URL(currentHref).search + new URL(currentHref).hash;
// Update iframe location
window.location.href = path;
// Update parent window URL via postMessage (cross-origin safe)
try {
window.parent.postMessage({
type: 'documentationNavigation',
path: path,
fullUrl: parentOrigin + path
}, parentOrigin);
} catch (e) {
console.warn("Could not send navigation message to parent:", e);
}
return false;
}
} catch (err) {
console.error("Error handling search result link click:", err);
}
}

// Fallback: handle absolute URLs pointing off-site
if (/^https?:\/\//i.test(currentHref)) {
try {
var u = new URL(href);
var u = new URL(currentHref);
if (u.origin !== window.location.origin) {
e.preventDefault();
var path = u.pathname;
if (!path.startsWith(basePath)) {
path = basePath.replace(/\/$/, "") + "/" + path.replace(/^\//, "");
}
window.location.href = path + (u.search || "") + (u.hash || "");
var newUrl = path + (u.search || "") + (u.hash || "");
window.location.href = newUrl;
return false;
}
} catch (err) {
// ignore malformed URLs
console.error("Error handling absolute URL in search result click:", err, "href:", currentHref);
}
}
});

// If in an iframe, rewrite link hrefs for hover display but intercept clicks to navigate within iframe
if (window.self !== window.top) {
try {
var parentOrigin = window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0
? window.location.ancestorOrigins[0]
: document.referrer ? new URL(document.referrer).origin : null;

if (parentOrigin) {
// Function to get the actual path from a href
function getPathFromHref(href) {
if (!href || href.startsWith("#") || href.startsWith("mailto:") || href.startsWith("javascript:") || href.startsWith("data:") || href.startsWith("vbscript:")) {
return null;
}
try {
if (href.match(/^https?:\/\//)) {
return new URL(href).pathname + new URL(href).search + new URL(href).hash;
} else {
// Relative URL
return href.startsWith("/") ? href : "/" + href;
}
} catch (e) {
console.error("Error parsing href in getPathFromHref:", e, "href:", href);
return href.startsWith("/") ? href : "/" + href;
}
}

// Rewrite navigation links for hover display
$("nav a").each(function() {
var $link = $(this);
var originalHref = $link.attr("href");
var path = getPathFromHref(originalHref);

if (path && !path.startsWith("#") && !path.startsWith("mailto:") && !path.startsWith("javascript:") && !path.startsWith("data:") && !path.startsWith("vbscript:")) {
// Store original href in data attribute
$link.data("original-href", originalHref);
// Set href to parent origin for hover display
$link.attr("href", parentOrigin + path);
}
});

// Rewrite links in main content area for hover display
$("main a").each(function() {
var $link = $(this);
var originalHref = $link.attr("href");
var path = getPathFromHref(originalHref);

if (path && !path.startsWith("#") && !path.startsWith("mailto:") && !path.startsWith("javascript:") && !path.startsWith("data:") && !path.startsWith("vbscript:")) {
// Store original href in data attribute
$link.data("original-href", originalHref);
// Set href to parent origin for hover display
$link.attr("href", parentOrigin + path);
}
});

// Intercept clicks on navigation and content links to navigate within iframe
$(document).on("click", "nav a, main a", function(e) {
var $link = $(this);
var originalHref = $link.data("original-href");
var currentHref = $link.attr("href");

// If we have a stored original href, use it; otherwise check current href
var hrefToUse = originalHref || currentHref;

// Skip external links, anchors, and special protocols
if (!hrefToUse || hrefToUse.startsWith("#") || hrefToUse.startsWith("mailto:") || hrefToUse.startsWith("javascript:") || hrefToUse.startsWith("data:") || hrefToUse.startsWith("vbscript:")) {
return; // Let default behavior handle these
}

// If current href points to parent origin (for display), navigate using the path within iframe
if (currentHref && currentHref.startsWith(parentOrigin)) {
e.preventDefault();
var path = new URL(currentHref).pathname + new URL(currentHref).search + new URL(currentHref).hash;
// Update iframe location
window.location.href = path;
// Update parent window URL via postMessage (cross-origin safe)
try {
window.parent.postMessage({
type: 'documentationNavigation',
path: path,
fullUrl: parentOrigin + path
}, parentOrigin);
} catch (e) {
console.warn("Could not send navigation message to parent:", e);
}
return false;
} else if (hrefToUse.match(/^https?:\/\//) && !hrefToUse.startsWith(window.location.origin) && !hrefToUse.startsWith(parentOrigin)) {
// External link (not parent origin, not current origin) - let it open normally
return;
} else if (originalHref && originalHref.startsWith(parentOrigin)) {
// Original href was parent origin - navigate within iframe
e.preventDefault();
var path = new URL(originalHref).pathname + new URL(originalHref).search + new URL(originalHref).hash;
// Update iframe location
window.location.href = path;
// Update parent window URL via postMessage (cross-origin safe)
try {
window.parent.postMessage({
type: 'documentationNavigation',
path: path,
fullUrl: parentOrigin + path
}, parentOrigin);
} catch (e) {
console.warn("Could not send navigation message to parent:", e);
}
return false;
} else if (hrefToUse && !hrefToUse.match(/^https?:\/\//)) {
// Relative link - navigate within iframe and update parent URL
e.preventDefault();
var path = hrefToUse.startsWith("/") ? hrefToUse : "/" + hrefToUse;
// Update iframe location
window.location.href = path;
// Update parent window URL via postMessage (cross-origin safe)
try {
window.parent.postMessage({
type: 'documentationNavigation',
path: path,
fullUrl: parentOrigin + path
}, parentOrigin);
} catch (e) {
console.warn("Could not send navigation message to parent:", e);
}
return false;
}
// For other cases, let default behavior work
});
}
} catch (err) {
console.warn("Could not rewrite links for parent origin:", err);
}
}
})();
Loading