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
80 changes: 67 additions & 13 deletions scribble-doc/scriblib/scribblings/footnote.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,39 @@

@defproc[(note [pre-content pre-content?] ...) element?]{

Creates a margin note for HTML and a footnote for Latex/PDF output.}
Creates a margin note for HTML and a footnote for Latex/PDF output.

@defform[(define-footnote footnote-id footnote-part-id)]{
To produce a numbered note for HTML (which can useful if a CSS
specialization changes how ``margin notes'' are rendered), use
@racket[define-footnote] with @racket[#:margin], instead.

Binds @racket[footnote-id] to a form like @racket[note] that registers a
footnote.
Binds @racket[footnote-part-id] to a function that generates a section to
display the registered footnotes.
(The section generated by @racket[footnote-part-id] will not show a title or
appear in a table of contents; it will look like a footnote area.)
The element generated by @racket[note] uses the style
@racket["NoteBox"] wrapped around an element using the style
@racket["NoteContent"]. CSS and Latex macros configure rendering for
HTML and Latex/PDF to create a margin note or footnote, but those CSS
classes or Latex macros can be redefined or overridden to produce a
different result.

Beware that any content passed to @racket[footnote-id] will occur
twice in at least an intermediate form of the document, and perhaps
also in the rendered form of the document. Consequently, the content
passed to @racket[footnote-id] should not bind link targets or include
other one-time declarations.}
}

@defform*[((define-footnote footnote-id footnote-part-id)
(define-footnote footnote-id #:margin))]{

Binds @racket[footnote-id] to a form like @racket[note] that registers
a footnote. For Latex/PDF output, this is the same result as using
@racket[note].

If @racket[footnote-part-id] is provided, it is bound to a function
that generates a section to display the registered footnotes in HTML.
The section generated by @racket[footnote-part-id] will not show a title or
appear in a table of contents; it will look like a footnote area.
If @racket[#:margin] is supplied instead, then each footnote is
rendered as an immediate margin note, and no separate footnote section
is needed.

Using @racket[footnote-id] within the argument to a
@racket[footnote-id] will not always work, but it can work in
@racket[#:margin] mode for HTML output.

Example:
@codeblock|{
Expand All @@ -48,3 +65,40 @@ Example:
@section{March}
March has 30 days.
}|


The elements and parts generated by @racket[footnote-id] and
@racket[footnote-part-id] use the following style names, which can be
redefined as CSS classes or Latex macros to adjust the result:

@itemlist[

@item{@racket["Footnote"]: Style for the result of
@racket[footnote-id], which is mapped to @tt{\footnote} for Latex.}

@item{@racket["FootnoteRef"]: Wrapped around the reference to a
footnote that is rendered by @racket[footnote-part-id] or as a margin
note. For Latex, this name is mapped to a macro that returns nothing,
leaving the reference managment to @tt{\footnote}.}

@item{@racket["FootnoteTarget"]: Wrapped around the footnote that is
rendered by @racket[footnote-part-id] or as a margin note. For Latex,
this name is mapped to a macro that returns nothing, leaving the
reference managment to @tt{\footnote}.}

@item{@racket["FootnoteContent"]: For Latex, wrapped around the
content of a footnote as rendered by @racket[footnote-part-id].}

@item{@racket["FootnoteMarginContent"]: Wrapped around the content of
a footnote as rendered as a margin note. By default, CSS styling for
this name floats the note into the right margin.}

@item{@racket["FootnoteBlock"]: Wrapped around the output of
@racket[footnote-part-id].}

@item{@racket["FootnoteBlockContent"]: Also wrapped around the output of
@racket[footnote-part-id], inside the @racket["FootnoteBlock"] wrapper.}

]

}
2 changes: 1 addition & 1 deletion scribble-lib/info.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

(define pkg-authors '(mflatt eli))

(define version "1.61")
(define version "1.62")

(define license
'((Apache-2.0 OR MIT)
Expand Down
3 changes: 2 additions & 1 deletion scribble-lib/scribble/core.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,8 @@
(define (tag-key tg ri)
(if (generated-tag? (cadr tg))
(list (car tg)
(hash-ref (collect-info-tags (resolve-info-ci ri)) (cadr tg)))
(hash-ref (collect-info-tags (resolve-info-ci ri)) (cadr tg)
'unknown))
tg))

(define current-tag-prefixes (make-parameter null))
Expand Down
2 changes: 1 addition & 1 deletion scribble-lib/scriblib/footnote.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

.NoteBox {
.NoteBox, .FootnoteMarginContent {
position: relative;
float: right;
left: 2em;
Expand Down
62 changes: 46 additions & 16 deletions scribble-lib/scriblib/footnote.rkt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#lang racket/base

(require scribble/core
(require (for-syntax racket/base)
scribble/core
scribble/decode
scribble/html-properties
scribble/latex-properties
racket/promise
setup/main-collects
scriblib/render-cond
"private/counter.rkt")

(provide note
Expand All @@ -32,31 +34,56 @@
(define footnote-style (make-style "Footnote" footnote-style-extras))
(define footnote-ref-style (make-style "FootnoteRef" footnote-style-extras))
(define footnote-content-style (make-style "FootnoteContent" footnote-style-extras))
(define footnote-margin-content-style (make-style "FootnoteMarginContent" footnote-style-extras))
(define footnote-target-style (make-style "FootnoteTarget" footnote-style-extras))
(define footnote-block-style (make-style "FootnoteBlock" footnote-style-extras))
(define footnote-block-content-style (make-style "FootnoteBlockContent" footnote-style-extras))

(define-syntax-rule (define-footnote footnote footnote-part)
(begin
(define footnotes (new-counter "footnote"))
(define id (gensym))
(define (footnote . text) (do-footnote footnotes id text))
(define (footnote-part . text) (do-footnote-part footnotes id))))
(define-syntax (define-footnote stx)
(define (check-identifier id)
(unless (identifier? id)
(raise-syntax-error #f "expected an identifier" stx id)))
(define (generate-footnote footnote-id margin?)
#`(begin
(define footnotes (new-counter "footnote"))
(define id (gensym))
(define (#,footnote-id . text) (do-footnote footnotes id text #,margin?))))
(syntax-case stx ()
[(_ footnote #:margin)
(begin
(check-identifier #'footnote)
(generate-footnote #'footnote #t))]
[(_ footnote footnote-part)
(begin
(check-identifier #'footnote)
(check-identifier #'footnote-part)
#`(begin
#,(generate-footnote #'footnote #f)
(define (footnote-part . text) (do-footnote-part footnotes id))))]))

(define (do-footnote footnotes id text)
(define (do-footnote footnotes id text margin?)
(define tag (generated-tag))
(define content (decode-content text))
(define target (cons (make-element footnote-target-style
(make-element 'superscript
(counter-target footnotes tag #f
#:use-ref? #t)))
content))
(make-traverse-element
(lambda (get set)
(set id
(cons (cons (make-element footnote-target-style
(make-element 'superscript (counter-target footnotes tag #f)))
content)
(get id null)))
(unless margin?
(set id (cons target (get id null))))
(make-element footnote-style
(list (make-element footnote-ref-style
(make-element 'superscript (counter-ref footnotes tag #f)))
(make-element footnote-content-style content))))))
(make-element 'superscript (counter-ref footnotes tag #f
#:use-target? #t)))
(if margin?
(make-element footnote-margin-content-style target)
(cond-element
[latex
(make-element footnote-content-style content)]
[else
null])))))))

(define (do-footnote-part footnotes id)
(make-part
Expand All @@ -71,5 +98,8 @@
(make-compound-paragraph
footnote-block-style
(for/list ([content (in-list (reverse (get id null)))])
(make-paragraph footnote-block-content-style content))))))
(make-paragraph footnote-block-content-style
(cond-element
[latex null]
[else content])))))))
null))
1 change: 1 addition & 0 deletions scribble-lib/scriblib/footnote.tex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
\newcommand{\FootnoteRef}[1]{}
\newcommand{\FootnoteTarget}[1]{}
\newcommand{\FootnoteContent}[1]{#1}
\newcommand{\FootnoteMarginContent}[1]{#1}

% Redefine \noindent to avoid generating any output at all:
\newenvironment{FootnoteBlock}{\renewcommand{\noindent}{}}{}
Expand Down
69 changes: 40 additions & 29 deletions scribble-lib/scriblib/private/counter.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@
#:label-style [label-style #f]
#:label-suffix [label-suffix '()]
#:continue? [continue? #f]
#:use-ref? [use-ref? #f]
. content)
(define (wrap-ref e)
(if use-ref?
(make-link-element #f e (tag->counter-tag counter tag "use"))
e))
(let ([content (decode-content content)])
(define c
(make-target-element
target-style
(list
(wrap-ref
(make-collect-element
#f
(list
Expand Down Expand Up @@ -79,35 +84,41 @@
[else (format "x~x" (char->integer c))]))))

(define (counter-ref counter tag label
#:use-target? [use-target? #f]
#:link-render-style [link-style #f])
(make-delayed-element
(lambda (renderer part ri)
(define n (resolve-get part ri (tag->counter-tag counter tag "value")))
(let ([n (if (counter-ref-wrap counter)
((counter-ref-wrap counter)
(format "~a" n)
;; Don't use this argument:
(format "t:~a" (t-encode (list 'counter (list (counter-name counter) tag)))))
(list (format "~a" n)))]
[link-number-only?
(eq? (link-render-style-mode (or link-style (current-link-render-style))) 'number)])
(cond
[(and label link-number-only?)
(make-element
#f
(list label 'nbsp (make-link-element #f (list n) (tag->counter-tag counter tag))))]
[else
(make-link-element #f
(if label
(list label 'nbsp n)
n)
(tag->counter-tag counter tag))])))
(lambda () (if label
(list label 'nbsp "N")
(list "N")))
(lambda () (if label
(list label 'nbsp "N")
(list "N")))))
(define (wrap-target e)
(if use-target?
(make-target-element #f e (tag->counter-tag counter tag "use"))
e))
(wrap-target
(make-delayed-element
(lambda (renderer part ri)
(define n (resolve-get part ri (tag->counter-tag counter tag "value")))
(let ([n (if (counter-ref-wrap counter)
((counter-ref-wrap counter)
(format "~a" n)
;; Don't use this argument:
(format "t:~a" (t-encode (list 'counter (list (counter-name counter) tag)))))
(list (format "~a" n)))]
[link-number-only?
(eq? (link-render-style-mode (or link-style (current-link-render-style))) 'number)])
(cond
[(and label link-number-only?)
(make-element
#f
(list label 'nbsp (make-link-element #f (list n) (tag->counter-tag counter tag))))]
[else
(make-link-element #f
(if label
(list label 'nbsp n)
n)
(tag->counter-tag counter tag))])))
(lambda () (if label
(list label 'nbsp "N")
(list "N")))
(lambda () (if label
(list label 'nbsp "N")
(list "N"))))))

(define (counter-collect-value counter)
(counter-n counter))
Loading
Loading