Easily insert citations in my Franklin Blog

Demands

Smoothly Insert a Citation I have made lots of functions to make batter experiences on writting Franklin Blogs. And yes, It is now more comfortable to write blogs (although the raw markdown texts was not so markdown and not so readable).

However, I still need an elegant way to insert citations to my blogs, there are several pain-points:

  1. The traditional way to add footnotes or Franklin's official bibliography functions all need two steps for add each citation:

  • add in situ indexes.

  • add references at the end of the doc.

  1. The traditional way to search and insert an academic citation would be too :

  • write manually: which is silly;

  • using research managers, such as EndNote or Zotero. But these are more friendly for MSOffice users, for plain-text based insertion, you have to copy-and-paste manually;

  • search on Google Scholar, and copy-and-paste manually;

Thus, I would like a solution to the above pain-points that:

  • A one step solution: insert in situ indexes and the References will generated automatically.

  • The indexes of the articles should be acquired easily, so that I don't have to spend lots of time searching.

Possible Solutions

Using DOI

The first thing pop out is using DOI as indexes, it is unique and can lead to the reference information through online api.

And there have been some implements on doi-based-citations functions in Franklin (see the functions of Leon Bilton's Blog HERE).

However, after a test on the DOI based solutions, I gave them up, for:

  • The online-API-based reference requests were not stable, it happens (a lot) that the references cannot be get;

  • The insertion gramma is too complex, consider if I would insert three articles in the same place, I'd write {{citedoi 10.1046/j.1365-294X.2002.01643.x 10.1159/000070664 10.1038/nature02168}}, infact I cannot remember which doi links to which article, it is painful if I would like to change one ref to another.

  • The build time for my blog would become too long, for HTTP connections (and it may finally fail)

I need a better solution.

Using Local CiteKey

Then I went back to my Zotero research manager. Zotero automatically generates Citation Key for each record, the key is informative with format of year-1stAuthor-ShortTitle (eg. 2020-Burgess-Guidelines-WOR), which is perfect for being my indexes. So I have decided to make my Citation Functions based on my Zotero BibTex Database. The pros are obvious:

  • A more readable/meaningful cite key;

  • Local parse, faster and more stable;

  • I can easily search for articles through Zotero and get the cite key;

  • The BibTex is informative, that I could DIY a lot: say I want the output index format be (Author1 et al. Year1, Author2 et al. Year2), and to show up to three authors in the reference list, and add urls to the article title of the reference list. All can do !

The implementation

The implementation codes were accessible HERE, and also as listed below:

julia

using BibParser
#=
Make Citation smoothly in My Franklin Blog
=#

#=
## Local bib db based citation:

1. parse all local bib, with citekey as key
2. get only first three authors
3. add urls to title
4. use (author et al., year) format citeindex
5. sort bibliography alphabetically
=#

function loadbib(db::String)
    # check = :error :warn :none
    return BibParser.parse_file(db, :BibTeX; check=:none)
end

# const CITEDB = loadbib(CITEDBFILE)
const CITEDB = loadbib("_assets/citedb/ref.bib")

function fmtidx(idx::String, name::String; format="normal")
    if !haskey(CITEDB, idx)
        @error "No ref information in the database for $k"
        name = "ERROR"
    end
    return """<a href="#$idx">$(name)</a>"""
end

function hfun_citebib(ks)
    rpath = Franklin.FD_ENV[:CUR_PATH]
    idxpath = replace(rpath, r"\.md$" => ".citedb")
    indexes = Vector{Any}()
    final_indexes = Vector{Any}()
    if isfile(idxpath)
        indexes = unique(readlines(idxpath))
    end
    open(idxpath, "a") do io
        for k in ks
            # @info "Parse citation $k for $rpath ..."
            curbib = CITEDB[k]
            curbib_year = curbib.date.year
            curbib_first_author = curbib.authors |> first
            curbib_etal = length(curbib.authors) > 1 ? " et al. " : " "
            outname = curbib_first_author.last * curbib_etal * curbib_year
            curidx = fmtidx(k, outname)
            push!(final_indexes, curidx)
            if !(k in indexes)
                push!(indexes, k)
                write(io, "$(k)\n")
            end
        end
    end
    final_index = join(final_indexes, ", ")
    return """
        <span>
            ($final_index)
        </span>
        """
end

function fmtreflist(idx::String)
    refstr = ""

    if !haskey(CITEDB, idx)
        @error "No ref information in the database for $k"
        refstr = "ERROR: No ref information in the database for $k"
    else
        curbib = CITEDB[idx]
        curbib_year = curbib.date.year
        etal = " et al. "
        if length(curbib.authors) < 3
            etal = " "
        end
        f3a_str = join([x.last * " " * x.first for x in first(curbib.authors,3)], ", ")
        curbib_first_three_authors = f3a_str * etal
        curbib_pubinfo = join(filter(!isempty,["<span style=\"color:#9970AB\"><i>" * curbib.in.journal * "</i></span>", curbib.in.pages, curbib.in.volume]),", ")
        curbib_title = replace(curbib.title, r"[\{\}]" => "")
        if !isempty(curbib.access.doi)
            url = startswith(curbib.access.doi, r"http(s)?://(dx\.)?doi.org/") ? curbib.access.doi : "https://doi.org/" * curbib.access.doi
            curbib_title = """<a href="$(url)" target="_blank">$(curbib_title)</a>"""
        else
            curbib_title = """<a><span style="color:#08519C">$(curbib_title)</span></a>"""
        end
        refstr = """
            <span>$(curbib_first_three_authors) ($(curbib_year)). $(curbib_title). $(curbib_pubinfo)</span>
            """
    end

    return """
        <li id="$(idx)">
            $refstr
        </li>
        """
end

function hfun_citebiblist()
    rpath = Franklin.FD_ENV[:CUR_PATH]
    idxpath = replace(rpath, r"\.md$" => ".citedb")
    reflist = "<h2>References</h2>"

    if !isfile(idxpath)
        @error "No indexes found in $idxpath !"
        reflist *= """
            <span style="color:#A50026">ERROR</span>
            """
        return reflist
    end

    for curidx in unique(readlines(idxpath))
        reflist *= fmtreflist(curidx)
    end

    return reflist
end # func hfun_citebiblist
a = ["a", "b", "c"]

julia

DEMO

By the implementation above, I could insert citation(s) through {{citebib CiteKey1 CiteKey2 ...}}, and add a {{citebiblist}} to the end of the file, then everything will work smoothly!

DEMO-CODE By writing Franklin markdown like this:

markdown

... has been well discussed in Pandey's work on evolution of unilateral incompatibility in flowering plants and Pla's work on ABA cis-regulators {{citebib pandeyEvolutionUnilateralIncompatibility1981 plaCisregulatoryElementCCACGTGG1993}}.

... Please refer to Bilinski's work on the adaptive evolution of genome size in maize {{citebib bilinskiParallelAltitudinalClines2018}}.

{{citebiblist}}

markdown

I'll get this:

DEMO-OUT ... has been well discussed in Pandey's work on evolution of unilateral incompatibility in flowering plants and Pla's work on ABA cis-regulators (Pandey 1981, Pla et al. 1993) .

... Please refer to Bilinski's work on the adaptive evolution of genome size in maize (Bilinski et al. 2018) .

References

  • Pandey K. (1981). Evolution of Unilateral Incompatibility in Flowering Plants: Further Evidence in Favour of Twin Specificities Controlling Intra- and Interspecific Incompatibility. New Phytologist, 705--728, 89
  • Pla Maria, Vilardell Josep, Guiltinan Mark et al. (1993). The cis-regulatory element CCACGTGG is involved in ABA and water-stress responses of the maize gene rab28. Plant Molecular Biology, 259--266, 21
  • Bilinski Paul, Albert Patrice, Berg Jeremy et al. (2018). Parallel altitudinal clines reveal trends in adaptive evolution of genome size in Zea mays. PLOS Genetics, e1007162, 14
  • Flaws

    There are several flaws for this primary implementation:

    • The BibTex should be strictly formated: the title, author, year information should be provided.

    • The Reference List is ordered as the first cited article get first, not by year or alphabetically.

    • The in situ indexes are not checked to make sure they are unique:

    say if you insert two articles published on 2022 by Wang Dabao and Wang Erbao respectively, the indexes would both be Wang 2022, which should be Wang 2022a and Wang 2022b, but the links are correct, so I'll live with it (after all, it's a blog, not a journal).

    That's It! For now!

    Feel free to use mine implementation on your blogs!
    And let me know if there are (there sure will be or already been) better solutions!