Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On-hover footnote preview #2080

Open
mortenpi opened this issue Mar 20, 2023 · 9 comments · May be fixed by #2522
Open

On-hover footnote preview #2080

mortenpi opened this issue Mar 20, 2023 · 9 comments · May be fixed by #2522
Assignees
Labels
Format: HTML Related to the default HTML output good first issue Indicates a good issue for first-time contributors help wanted

Comments

@mortenpi
Copy link
Member

I.e. something like this

image

Example is from a Quarto document: https://mixtape.scunning.com/02-probability_and_regression#fnref1

Would be really handy, and a nice self-contained front-end feature for someone to take on.

@mortenpi mortenpi added help wanted Format: HTML Related to the default HTML output good first issue Indicates a good issue for first-time contributors labels Mar 20, 2023
@shravanngoswamii
Copy link
Contributor

I would like to work on this issue and this also come under my expertise, Can I have some details like in which part of Julia Codebase should I do this? And I am really sorry to ask this newbie question as I am new to Julia and I am still trying to understand Julia Codebase and Documenter.jl!!

@mortenpi
Copy link
Member Author

On the Julia side, the HTML for the footnotes is generated here:

function domify(dctx::DCtx, node::Node, f::MarkdownAST.FootnoteLink)
@tags sup a
sup[".footnote-reference"](a["#citeref-$(f.id)", :href => "#footnote-$(f.id)"]("[$(f.id)]"))
end
function domify(dctx::DCtx, node::Node, f::MarkdownAST.FootnoteDefinition)
# As we run through the document to generate the document, we won't render the footnote
# definitions right away, and instead store them on dctx.footnotes. They get printed
# a little later, at the very end of the page.
#
# It does mean that we call domify() again later on the actual footnote bodies, and in that
# case dctx.footnotes = nothing. In case we then still end up here, it means we have footnote
# definitions nested inside footnote definition. We just ignore those and print a warning.
#
# TODO: this could be rearranged such that we push!() the DOM here into .footnotes, rather
# than the Node objects.
if isnothing(dctx.footnotes)
@error "Invalid nested footnote definition in $(Documenter.locrepr(dctx.navnode.page))" f.id
else
push!(dctx.footnotes, node)
end
return DOM.Node[]
end

In the rendering phase, Documenter essentially gets a big object representing the Markdown and then runs over that, generating the HTML. The entry point into HTMLWriter is here:

function render(doc::Documenter.Document, settings::HTML=HTML())
@info "HTMLWriter: rendering HTML pages."
!isempty(doc.user.sitename) || error("HTML output requires `sitename`.")
if isempty(doc.blueprint.pages)
error("Aborting HTML build: no pages under src/")
elseif !haskey(doc.blueprint.pages, "index.md")
@warn "Can't generate landing page (index.html): src/index.md missing" keys(doc.blueprint.pages)
end
if isa(settings.repolink, Default) && (isnothing(doc.user.remote) || Remotes.repourl(doc.user.remote) === nothing)
@warn """
Unable to determine the repository root URL for the navbar link.
This can happen when a string is passed to the `repo` keyword of `makedocs`.
To remove this warning, either pass a Remotes.Remote object to `repo` to completely
specify the remote repository, or explicitly set the remote URL by setting `repolink`
via `makedocs(format = HTML(repolink = "..."), ...)`.
"""
end
ctx = HTMLContext(doc, settings)
ctx.search_index_js = "search_index.js"
ctx.themeswap_js = copy_asset("themeswap.js", doc)
ctx.warner_js = copy_asset("warner.js", doc)
# Generate documenter.js file with all the JS dependencies
ctx.documenter_js = "assets/documenter.js"
if isfile(joinpath(doc.user.source, "assets", "documenter.js"))
@warn "not creating 'documenter.js', provided by the user."
else
r = JSDependencies.RequireJS([
RD.jquery, RD.jqueryui, RD.headroom, RD.headroom_jquery,
])
RD.mathengine!(r, settings.mathengine)
if !settings.prerender
RD.highlightjs!(r, settings.highlights)
end
for filename in readdir(joinpath(ASSETS, "js"))
path = joinpath(ASSETS, "js", filename)
endswith(filename, ".js") && isfile(path) || continue
push!(r, JSDependencies.parse_snippet(path))
end
JSDependencies.verify(r; verbose=true) || error("RequireJS declaration is invalid")
JSDependencies.writejs(joinpath(doc.user.build, "assets", "documenter.js"), r)
end
# Generate search.js file with all the JS dependencies
ctx.search_js = "assets/search.js"
if isfile(joinpath(doc.user.source, "assets", "search.js"))
@warn "not creating 'search.js', provided by the user."
else
r = JSDependencies.RequireJS([RD.jquery, RD.lunr, RD.lodash])
push!(r, JSDependencies.parse_snippet(joinpath(ASSETS, "search.js")))
JSDependencies.verify(r; verbose=true) || error("RequireJS declaration is invalid")
JSDependencies.writejs(joinpath(doc.user.build, "assets", "search.js"), r)
end
for theme in THEMES
copy_asset("themes/$(theme).css", doc)
end
for page in keys(doc.blueprint.pages)
idx = findfirst(nn -> nn.page == page, doc.internal.navlist)
nn = (idx === nothing) ? Documenter.NavNode(page, nothing, nothing) : doc.internal.navlist[idx]
@debug "Rendering $(page) [$(repr(idx))]"
render_page(ctx, nn)
end
render_search(ctx)
open(joinpath(doc.user.build, ctx.search_index_js), "w") do io
println(io, "var documenterSearchIndex = {\"docs\":")
# convert Vector{SearchRecord} to a JSON string + do additional JS escaping
println(io, json_jsescape(ctx.search_index), "\n}")
end
end

The Markdown elements are represented with MarkdownAST objects.

However, what could be a good first step is to take just the generated HTML, probably tidy it up, and then create a HTML/CSS/JS proof-of-concept directly in the HTML. Once we know what the HTML needs to look like, we can think about how to incorporate it into Julia.

@shravanngoswamii
Copy link
Contributor

As you said, I created a HTML/CSS/JS proof-of-concept directly in HTML, Please let me know if i should change something or there is any mistake and if it is correct than what should be my next step in STEP.
This is HTML code :- https://github.com/shravanngoswamii/Documenter-PR-Test
Its Output :- https://shravanngoswamii.github.io/Documenter-PR-Test/

@mortenpi
Copy link
Member Author

Yeah, that's a good start. I guess there is no good way to do this via pure CSS with a :hover? I guess it would be hard to control the positioning?

If we're going to do it via JS, I wonder if we can re-use the generated HTML for the footnote definitions (i.e. copy the DOM to the preview span as the JS triggers)? But we could also just duplicate the generated HTML, if that's easier.

For integration:

@goerz
Copy link
Member

goerz commented Jan 8, 2024

I strongly feel that this feature should be primarily implemented via JS, primarily for usability and accessibility reasons. Ideally, a Documenter page should be useable in a browser without JS script (e.g., a terminal browser like w3m), or a screenreader. See also my comment at #2394 (comment)

Showing footnotes on hover is exactly the kind of UI sugar you'd want in a full browser. At least arguably, though, you wouldn't want footnotes inserted into the basic non-JS rendering of the page, and then appear multiple times.

This applies even more so to JuliaDocs/DocumenterCitations.jl#67

Since I'd be reluctant to add JS to DocumenterCitations (at least not until we implement a way for plugins to automatically inject CSS/JS), I'd want to reuse any implementation of this footnote-hover for the citation-hover.

@mortenpi
Copy link
Member Author

It seems like we could just have a single hidden-by-default div that renders the footnote, and we copy the DOM from the real footnote into that div whenever we trigger a hover event over the footnote reference. This way we'd keep the original footnotes around on the bottom of the page.

@shravanngoswamii
Copy link
Contributor

I added a span (hidden by default) for footnote preview and also added styling for its appropriate positioning but I am not able to get the footnote definitions in that span!
Can you please just have a look at these changes and see if it's fine this way: master...shravanngoswamii:Documenter.jl:footnote-preview

https://github.com/shravanngoswamii/Documenter.jl/blob/2dc0a6124be6fc02a09d61f52199f17c5d72ea27/src/html/HTMLWriter.jl#L2273C1-L2280C4

It's looking like this:
Screenshot 2024-06-04 003938

@mortenpi

@mortenpi
Copy link
Member Author

mortenpi commented Jun 3, 2024

Would have to test that on a live site, but HTML/CSS-wise I think it looks quite fine.

For getting the definitions, you'd have to modify HTMLWriter some more. Currently, I think we just gather them up as we go through the tree, since we only need them at the end:

https://github.com/shravanngoswamii/Documenter.jl/blob/2dc0a6124be6fc02a09d61f52199f17c5d72ea27/src/html/HTMLWriter.jl#L2281-L2298

It's a bit tricky, since for rendering them inline, we need to know the definitions when we encounter the reference. I'd be okay if we'd do another pre-pass through the tree before actually rendering, to gather up the definitions. That seems to be the simplest solution.

@shravanngoswamii shravanngoswamii linked a pull request Jun 5, 2024 that will close this issue
@shravanngoswamii
Copy link
Contributor

For getting the definitions, you'd have to modify HTMLWriter some more. Currently, I think we just gather them up as we go through the tree, since we only need them at the end:

https://github.com/shravanngoswamii/Documenter.jl/blob/2dc0a6124be6fc02a09d61f52199f17c5d72ea27/src/html/HTMLWriter.jl#L2281-L2298

It's a bit tricky, since for rendering them inline, we need to know the definitions when we encounter the reference. I'd be okay if we'd do another pre-pass through the tree before actually rendering, to gather up the definitions. That seems to be the simplest solution.

I used JQuery instead for fetching footnote definitions from the end of page and its working fine! I opened a PR for it, let me know if any changes are required!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Format: HTML Related to the default HTML output good first issue Indicates a good issue for first-time contributors help wanted
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants