Skip to content

Commit

Permalink
Merge pull request #352 from pratikb64/page-routing
Browse files Browse the repository at this point in the history
feat: handle routing without page reload
  • Loading branch information
pratikb64 authored Feb 20, 2025
2 parents b83ceb2 + 8ce713d commit 481ed99
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 85 deletions.
54 changes: 0 additions & 54 deletions wiki/public/js/render_wiki.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,60 +151,6 @@ window.RenderWiki = class RenderWiki extends Wiki {
}
}

set_toc() {
$(document).ready(function () {
$(window).scroll(function () {
if (currentAnchor().not(".no-underline").hasClass("active")) return;
$(".page-toc a").removeClass("active");
currentAnchor().addClass("active");
});

const navbarHeight = $(".navbar").height();
$(".page-toc a").click(function (e) {
e.preventDefault();
var target = $(this).attr("href");
var offset = $(target).offset().top - navbarHeight - 50;
$("html, body").animate(
{
scrollTop: offset,
},
100
);
});
});

function tocItem(anchor) {
return $('[href="' + anchor + '"]');
}

function heading(anchor) {
return $("[id=" + anchor.substr(1) + "]");
}

var _anchors = null;
function anchors() {
if (!_anchors) {
_anchors = $(".page-toc .list-unstyled a").map(function () {
return $(this).attr("href");
});
}
return _anchors;
}

function currentAnchor() {
var winY = window.pageYOffset;
var currAnchor = null;
anchors().each(function () {
var y = heading(this).position().top;
if (y < winY + window.innerHeight * 0.23) {
currAnchor = this;
return;
}
});
return tocItem(currAnchor);
}
}

set_nav_buttons() {
var current_index = -1;
const sidebar_items = $(".sidebar-column").find("a").not(".navbar-brand");
Expand Down
205 changes: 174 additions & 31 deletions wiki/public/js/wiki.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,96 @@
function add_link_to_headings() {
$(".from-markdown")
.not(".revision-content")
.find("h1, h2, h3, h4, h5, h6")
.each((i, $heading) => {
const text = $heading.textContent.trim();
$heading.id = text
.replace(/[^\u00C0-\u1FFF\u2C00-\uD7FF\w\- ]/g, "")
.replace(/[ ]/g, "-")
.toLowerCase();

let id = $heading.id;
let $a = $('<a class="no-underline">')
.prop("href", "#" + id)
.attr("aria-hidden", "true").html(`
<svg xmlns="http://www.w3.org/2000/svg" style="width: 0.8em; height: 0.8em;" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
`);
$($heading).append($a);
});
}

function add_click_to_copy() {
$("pre code")
.parent("pre")
.prepend(
`<button title="Copy Code" class="btn copy-btn" data-toggle="tooltip"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-clipboard"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg></button>`
);

$(".copy-btn").on("click", function () {
frappe.utils.copy_to_clipboard($(this).siblings("code").text());
});
}

function set_toc() {
// Reset scroll event listener to avoid scroll jitterness
$(window).off("scroll");
$(document).ready(function () {
$(window).scroll(function () {
if (currentAnchor().not(".no-underline").hasClass("active")) return;
$(".page-toc a").removeClass("active");
currentAnchor().addClass("active");
});

const navbarHeight = $(".navbar").height();
$(".page-toc a").click(function (e) {
e.preventDefault();
var target = $(this).attr("href");
var offset = $(target).offset().top - navbarHeight - 50;
$("html, body").animate(
{
scrollTop: offset,
},
100
);
});
});

function tocItem(anchor) {
return $('[href="' + anchor + '"]');
}

function heading(anchor) {
return $("[id=" + anchor.substr(1) + "]");
}

var _anchors = null;
function anchors() {
if (!_anchors) {
_anchors = $(".page-toc .list-unstyled a").map(function () {
return $(this).attr("href");
});
}
return _anchors;
}

function currentAnchor() {
var winY = window.pageYOffset;
var currAnchor = null;
anchors().each(function () {
var y = heading(this).position()?.top;
if (y < winY + window.innerHeight * 0.23) {
currAnchor = this;
return;
}
});
return tocItem(currAnchor);
}
}

window.Wiki = class Wiki {
activate_sidebars() {
$(".sidebar-item").each(function (index) {
Expand All @@ -18,6 +111,20 @@ window.Wiki = class Wiki {
.scrollTo(0, topOffset - 200);
}, 50);
}

$($(this))
.find("a")
.on("click", (e) => {
e.preventDefault();
const href = $(e.currentTarget).attr("href");
loadWikiPage(href, e.currentTarget);
$("html, body").animate(
{
scrollTop: 0,
},
100
);
});
});
}

Expand Down Expand Up @@ -96,41 +203,16 @@ window.Wiki = class Wiki {
});
}

set_toc() {
set_toc();
}

add_link_to_headings() {
$(".from-markdown")
.not(".revision-content")
.find("h1, h2, h3, h4, h5, h6")
.each((i, $heading) => {
const text = $heading.textContent.trim();
$heading.id = text
.replace(/[^\u00C0-\u1FFF\u2C00-\uD7FF\w\- ]/g, "")
.replace(/[ ]/g, "-")
.toLowerCase();

let id = $heading.id;
let $a = $('<a class="no-underline">')
.prop("href", "#" + id)
.attr("aria-hidden", "true").html(`
<svg xmlns="http://www.w3.org/2000/svg" style="width: 0.8em; height: 0.8em;" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
`);
$($heading).append($a);
});
add_link_to_headings();
}

add_click_to_copy() {
$("pre code")
.parent("pre")
.prepend(
`<button title="Copy Code" class="btn copy-btn" data-toggle="tooltip"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-clipboard"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg></button>`
);

$(".copy-btn").on("click", function () {
frappe.utils.copy_to_clipboard($(this).siblings("code").text());
});
add_click_to_copy();
}
};

Expand All @@ -146,3 +228,64 @@ $(document).on("click", function (e) {
$("#navbar-dropdown-content").addClass("hide");
}
});

function loadWikiPage(url, pageElement, replaceState = false) {
// Update URL and history state
const historyMethod = replaceState ? "replaceState" : "pushState";
window[`history`][historyMethod](
{
pageName: $(pageElement).closest(".sidebar-item").data("name"),
url: url,
},
"",
url
);

// Get the wiki page name from the parent element's data attribute
const pageName = $(pageElement).closest(".sidebar-item").data("name");

frappe.call({
method: "wiki.wiki.doctype.wiki_page.wiki_page.get_page_content",
args: { wiki_page_name: pageName },
callback: (r) => {
if (r.message) {
$(".wiki-content").html(r.message.content);

$(".wiki-title").html(r.message.title);

if (r.message.toc_html) {
$(".page-toc .list-unstyled").html(r.message.toc_html);
}

// Update active sidebar item
$(".sidebar-item").removeClass("active");
$(".sidebar-item").find("a").removeClass("active");
$(pageElement).closest(".sidebar-item").addClass("active");
$(pageElement).addClass("active");

// Re-initialize necessary components
add_link_to_headings();
add_click_to_copy();
set_toc();
}
},
});
}

window.addEventListener("popstate", function (event) {
if (event.state && event.state.pageName) {
const sidebarItem = $(`.sidebar-item[data-name="${event.state.pageName}"]`);
if (sidebarItem.length) {
const pageElement = sidebarItem.find("a")[0];
loadWikiPage(event.state.url, pageElement, true);
}
} else {
// Fallback to path-based lookup
const path = window.location.pathname;
const sidebarItem = $(`.sidebar-item[data-route="${path.slice(1)}"]`);
if (sidebarItem.length) {
const pageElement = sidebarItem.find("a")[0];
loadWikiPage(path, pageElement, true);
}
}
});
15 changes: 15 additions & 0 deletions wiki/wiki/doctype/wiki_page/wiki_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,18 @@ def get_markdown_content(wikiPageName, wikiPagePatch):
new_code, new_title = frappe.db.get_value("Wiki Page Patch", wikiPagePatch, ["new_code", "new_title"])
return {"content": new_code, "title": new_title}
return frappe.db.get_value("Wiki Page", wikiPageName, ["content", "title"], as_dict=True)


@frappe.whitelist(allow_guest=True)
def get_page_content(wiki_page_name):
wiki_page = frappe.get_cached_doc("Wiki Page", wiki_page_name)
content = wiki_page.content

html = frappe.utils.md_to_html(content)
wiki_settings = frappe.get_single("Wiki Settings")

return {
"title": wiki_page.title,
"content": html,
"toc_html": (wiki_page.calculate_toc_html(html) if wiki_settings.enable_table_of_contents else None),
}

0 comments on commit 481ed99

Please sign in to comment.