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

Support for Pagination (issue #496) #589

Merged
merged 7 commits into from
Aug 16, 2020
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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Franklin"
uuid = "713c75ef-9fc9-4b05-94a9-213340da978e"
authors = ["Thibaut Lienart <tlienart@me.com>"]
version = "0.9.3"
version = "0.9.4"

[deps]
Crayons = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
Expand Down
4 changes: 3 additions & 1 deletion src/Franklin.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ const FD_ENV = LittleDict(
:SILENT_MODE => false,
:OFFSET_LXDEFS => -BIG_INT,
:CUR_PATH => "",
:STRUCTURE => v"0.2")
:STRUCTURE => v"0.2",
:QUIET_TEST => false,)

"""Dict to keep track of languages and how comments are indicated and their extensions. This is relevant to allow hiding lines of code. """
const CODE_LANG = LittleDict{String,NTuple{2,String}}(
Expand Down Expand Up @@ -173,6 +174,7 @@ include("converter/html/prerender.jl")

# FILE AND DIR MANAGEMENT
include("manager/rss_generator.jl")
include("manager/write_page.jl")
include("manager/dir_utils.jl")
include("manager/file_utils.jl")
include("manager/franklin.jl")
Expand Down
66 changes: 63 additions & 3 deletions src/converter/html/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function hfun_insert(params::Vector{String})::String
end
# apply
repl = ""
layout = path(ifelse(FD_ENV[:STRUCTURE] < v"0.2", :src_html, :layout))
layout = path(layout_key())
fpath = joinpath(layout, split(params[1], "/")...)
if isfile(fpath)
repl = convert_html(read(fpath, String))
Expand Down Expand Up @@ -228,8 +228,9 @@ H-Function of the form `{{redirect /addr/blah.html}}`.
"""
function hfun_redirect(params::Vector{String})::String
if length(params) != 1
throw(HTMLFunctionError("I found an {{redirect ...}} block and expected a single " *
"address but got $(length(params)). Verify."))
throw(HTMLFunctionError(
"I found an {{redirect ...}} block and expected a single " *
"address but got $(length(params)). Verify."))
end
addr = params[1]
if !endswith(addr, ".html")
Expand All @@ -255,3 +256,62 @@ function hfun_redirect(params::Vector{String})::String
""")
return ""
end


const PAGINATE = "%##PAGINATE##%"


"""
hfun_paginate

Called with `{{paginate iterable n_per_page}}`. It is assumed there is only
one such call per page.
Evaluation is actually delayed.
"""
function hfun_paginate(params::Vector{String})::String
# params[1] --> the iterable to paginate (locvar)
# params[2] --> a positive integer of items per page

# Check arguments
if length(params) != 2
throw(HTMLFunctionError(
"I found an {{paginate ...}} block and expected two args: " *
"the name of the iterable and the number of item per page. " *
"I see $(length(params)) arguments instead. Verify."))
end
iter = locvar(params[1])
if isnothing(iter)
@warn "In a {{paginate ...}} block, I couldn't recognise the " *
"name of the iterable. Nothing will get printed as a result."
return ""
end
npp = locvar(params[2])
if isnothing(npp)
try
npp = parse(Int, params[2])
catch
@warn "In a {{paginate ...}} block, I couldn't parse the number " *
"of items per page. Defaulting to 10."
npp = 10
end
end
if npp <= 0
@warn "In a {{paginate ...}} block, the number of items per page is " *
"non-positive, defaulting to 10."
npp = 10
end

# Was there already a pagination element on this page?
# if so warn and ignore
if !isnothing(locvar(:paginate_itr))
@warn "It looks like you have multiple calls to {{paginate ...}} on " *
"the page; only one is supported. Verify."
return ""
end
# we're just storing the name here, so we'll have to locvar(locvar(.))
set_var!(LOCAL_VARS, "paginate_itr", params[1])
set_var!(LOCAL_VARS, "paginate_npp", npp)

# return a token which will be processed at the convert_and_write stage.
return PAGINATE
end
4 changes: 3 additions & 1 deletion src/converter/html/link_fixer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ should eventually be pre-prended with `/project/`. This would happen just
before you publish the website.
"""
function fix_links(pg::String)::String
pp = strip(GLOBAL_VARS["prepath"].first, '/')
prepath = globvar(:prepath)
isempty(prepath) && return pg
pp = strip(prepath, '/')
ss = SubstitutionString("\\1=\"/$(pp)/")
return replace(pg, r"(src|href|formaction)\s*?=\s*?\"\/" => ss)
end
5 changes: 2 additions & 3 deletions src/converter/markdown/tags.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,8 @@ function write_tag_page(tag)::Nothing
# make `fd_tag` available to that page generation
set_var!(LOCAL_VARS, "fd_tag", tag)

layout_key = ifelse(FD_ENV[:STRUCTURE] < v"0.2", :src_html, :layout)
layout = path(layout_key)
content = read(joinpath(layout, "tag.html"), String)
layout = path(layout_key())
content = read(joinpath(layout, "tag.html"), String)

dir = joinpath(path(:tag), tag)
isdir(dir) || mkdir(dir)
Expand Down
103 changes: 2 additions & 101 deletions src/manager/file_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,81 +65,6 @@ function process_utils()
end


"""
$(SIGNATURES)

Take a path to an input markdown file (via `root` and `file`), then construct
the appropriate HTML page (inserting `head`, `pg_foot` and `foot`) and finally
write it at the appropriate place.
"""
function write_page(root::String, file::String, head::String,
pg_foot::String, foot::String, out_path::String;
prerender::Bool=false, isoptim::Bool=false,
on_write::Function=(_,_)->nothing)::Nothing
# 1. read the markdown into string, convert it and extract definitions
# 2. eval the definitions and update the variable dictionary, also retrieve
# document variables (time of creation, time of last modif) and add those
# to the dictionary.
fpath = joinpath(root, file)
# The curpath is the relative path starting after /src/ so for instance:
# f1/blah/page1.md or index.md etc... this is useful in the code evaluation
# and management of paths
set_cur_rpath(fpath)
# conversion
content = convert_md(read(fpath, String))

# Check if should add item
# should we generate ? otherwise no
# are we in the full pass ? otherwise no
# is there a `rss` or `rss_description` ? otherwise no
cond_add = GLOBAL_VARS["generate_rss"].first && # should we generate?
FD_ENV[:FULL_PASS] && # are we in the full pass?
!all(e -> isempty(locvar(e)), ("rss", "rss_description"))
# otherwise yes
cond_add && add_rss_item()

# adding document variables to the dictionary
# note that some won't change and so it's not necessary to do this every
# time but it takes negligible time to do this so ¯\_(ツ)_/¯
# (and it's less annoying than keeping tabs on which file has
# already been treated etc).
s = stat(fpath)
set_var!(LOCAL_VARS, "fd_ctime", fd_date(unix2datetime(s.ctime)))
set_var!(LOCAL_VARS, "fd_mtime", fd_date(unix2datetime(s.mtime)))

# 3. process blocks in the html infra elements based on `LOCAL_VARS`
# (e.g.: add the date in the footer)
content = convert_html(str(content))
head, pg_foot, foot = (e -> convert_html(e)).([head, pg_foot, foot])

# 4. construct the page proper & prerender if needed
pg = build_page(head, content, pg_foot, foot)
if prerender
# KATEX
pg = js_prerender_katex(pg)
# HIGHLIGHT
if FD_CAN_HIGHLIGHT
pg = js_prerender_highlight(pg)
# remove script
pg = replace(pg, r"<script.*?(?:highlight\.pack\.js|initHighlightingOnLoad).*?<\/script>"=>"")
end
# remove katex scripts
pg = replace(pg, r"<script.*?(?:katex\.min\.js|auto-render\.min\.js|renderMathInElement).*?<\/script>"=>"")
end
# append pre-path if required (see optimize)
if !isempty(GLOBAL_VARS["prepath"].first) && isoptim
pg = fix_links(pg)
end

# 5. write the html file where appropriate
write(out_path, pg)

# 6. possible post-processing via the "on-write" function.
on_write(pg, LOCAL_VARS)
return nothing
end


"""
$(SIGNATURES)

Expand All @@ -157,8 +82,7 @@ function process_file(case::Symbol, fpair::Pair{String,String}, args...;
catch err
rp = fpair.first
rp = rp[end-min(20, length(rp))+1 : end]
println("\n... encountered an issue processing '$(fpair.second)' " *
"in ...$rp. Verify, then start franklin again...\n")
FD_ENV[:QUIET_TEST] || println("\n... encountered an issue processing '$(fpair.second)' in ...$rp. Verify, then start franklin again...\n")
FD_ENV[:SUPPRESS_ERR] || throw(err)
return -1
end
Expand All @@ -185,7 +109,7 @@ function process_file_err(
inp = joinpath(fpair...)
outp = form_output_path(fpair.first, fpair.second, case)
if case == :md
write_page(fpair..., head, pgfoot, foot, outp;
convert_and_write(fpair..., head, pgfoot, foot, outp;
prerender=prerender, isoptim=isoptim, on_write=on_write)
elseif case == :html
set_cur_rpath(joinpath(fpair...))
Expand Down Expand Up @@ -225,29 +149,6 @@ Convenience function to replace the extension of a filename with another.
change_ext(fname::AS, ext=".html")::String = splitext(fname)[1] * ext


"""
$(SIGNATURES)

Convenience function to assemble the html out of its parts.
"""
function build_page(head, content, pgfoot, foot)
# (legacy support) if div_content is offered explicitly, it takes
# precedence
dc = globvar("div_content")
if isempty(dc)
content_tag = globvar("content_tag")
content_class = globvar("content_class")
content_id = globvar("content_id")
else
content_tag = "div"
content_class = dc
content_id = ""
end
return head * html_content(content_tag, content * pgfoot;
class=content_class, id=content_id) * foot
end


"""
get_rpath(fpath)

Expand Down
8 changes: 3 additions & 5 deletions src/manager/franklin.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Keyword arguments:
* `nomess=false`: suppresses all messages (internal use).
* `isoptim=false`: whether we're in an optimisation phase or not (if so,
links are fixed in case of a project website, see
[`write_page`](@ref).
[`convert_and_write`](@ref).
* `no_fail_prerender=true`: whether, in a prerendering phase, ignore errors and
try to produce an output
* `eval_all=false`: whether to force re-evaluation of all code blocks
Expand Down Expand Up @@ -224,9 +224,8 @@ function fd_fullpass(watched_files::NamedTuple; clear::Bool=false,

# form page segments
root_key = ifelse(FD_ENV[:STRUCTURE] < v"0.2", :src, :folder)
layout_key = ifelse(FD_ENV[:STRUCTURE] < v"0.2", :src_html, :layout)
root = path(root_key)
layout = path(layout_key)
layout = path(layout_key())

head = read(joinpath(layout, "head.html"), String)
pg_foot = read(joinpath(layout, "page_foot.html"), String)
Expand Down Expand Up @@ -308,8 +307,7 @@ function fd_loop(cycle_counter::Int, ::LiveServer.FileWatcher,
# update the dictionaries
scan_input_dir!(watched_files..., verb; in_loop=true)
else
layout_key = ifelse(FD_ENV[:STRUCTURE] < v"0.2", :src_html, :layout)
layout = path(layout_key)
layout = path(layout_key())
# do a pass over the files, check if one has changed and if so trigger
# the appropriate file processing mechanism
for (case, dict) ∈ pairs(watched_files), (fpair, t) ∈ dict
Expand Down
Loading