asciidoctor-anywhere-footnote 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +7 -0
- data/README.md +209 -0
- data/asciidoctor-anywhere-footnote.gemspec +34 -0
- data/lib/asciidoctor/anywhere_footnote_processor.rb +245 -0
- metadata +133 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 460bfe36b3fb2aa22460bc048a5c75bd381e29e6497a20fed19961aa87f95078
|
|
4
|
+
data.tar.gz: 523ef6f8922a038e95d8f1ff41ce71a9046b04521efd51ff87ee87ecdf8d8504
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 154194eeae784ea2b8522e6d5590afc9e22aaf277be7adbd82936e52f4a17d8b5ce135096e75e69b0aaa829df6d04aab5520f05bc393454d94d3f654337cb558
|
|
7
|
+
data.tar.gz: dd9cab18382358f98eb2fb25889d25d5e0178e11b4c088e3f8ad154d57f8797dd6e962dd4a8909b8effec8433e82fd8767c4a49715695667a88a29f6aafffe70
|
data/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright <2025> <Ray Offiah>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Asciidoctor Anywhere Footnote
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
We've all been there: you're out in the pouring rain with a flat battery.
|
|
6
|
+
What's worse, when you pop the boot, you realize that you've left the spare charging in the garage.
|
|
7
|
+
And to top it all, you still have that AsciiDoc table that's going to need a lot of footnotes.
|
|
8
|
+
|
|
9
|
+
That's going to be a real bind if you want them to show up near the table, instead of right at the end of the page.
|
|
10
|
+
|
|
11
|
+
Well, there's little you can do about the rain and the flat battery, but there may be something you can do about the footnotes. …
|
|
12
|
+
|
|
13
|
+
## Anywhere Footnote
|
|
14
|
+
|
|
15
|
+
This is an inline macro that you can use in most places that you'd be able to use `footnote`.
|
|
16
|
+
The main difference is that it includes a parameter that it uses to reference the location of the footnote block:
|
|
17
|
+
|
|
18
|
+
```asciidoc
|
|
19
|
+
This is a piece of text{empty}afnote:footnote-block[This is the text of the footnote.]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
The macro parameter (`footnote-block`) points to the `afnote` block where the footnote will be rendered:
|
|
24
|
+
|
|
25
|
+
```asciidoc
|
|
26
|
+
This is where the footnote block goes:
|
|
27
|
+
|
|
28
|
+
afnote::footnote-block[]
|
|
29
|
+
```
|
|
30
|
+
> **Note**: Block macros must appear on their own line with no other characters.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
> **Tip** You can also use a single colon for the footnote block macro. (`afnote:footnote-block[]`)
|
|
34
|
+
|
|
35
|
+
All the footnotes with the same identifier will be rendered in the same block,
|
|
36
|
+
so you can have multiple footnote blocks on your page.
|
|
37
|
+
|
|
38
|
+
The inline tag (single colon) supports extra parameters, as well as the text for the footnote.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
afnote:my-block[Footnote text] // (1)
|
|
42
|
+
afnote:my-block[reftext="Footnote text", refid="footnote-id"] // (2)
|
|
43
|
+
afnote:my-block[refid="footnote-id"] (3)
|
|
44
|
+
afnote:my-block[reftext="Footnote text", marker="*"] (4)
|
|
45
|
+
afnote:my-block[reftext="Footnote text", lbrace="(" rbrace=")"] (5)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
1. The standard pattern. The text in brackets will be used as the footnote.
|
|
50
|
+
2. You can also set the footnote text using the `reftext` parameter. In this case we’re also using the `refid` to set a reusable reference identifier.
|
|
51
|
+
3. The `refid` is used to reference an existing footnote so that multiple footnote references can point to the same footnote.
|
|
52
|
+
4. Normally, the footnotes are numbered per block, but if you wish, you can assign your own marker for any footnote.
|
|
53
|
+
5. As a default, the footnote markers are encased in square brackets. You can change this (to parentheses, for example)
|
|
54
|
+
by using the `lbrace` and/or `rbrace` parameters.
|
|
55
|
+
|
|
56
|
+
> **Tip** If you don't want any kind of bracket encasing the footnote,
|
|
57
|
+
> then set both `lbrace` and `rbrace` to `{empty} or empty strings.`
|
|
58
|
+
>
|
|
59
|
+
> You don't have to use both parameters. If you set `lbrace={empyty}` and `rbrace=")"`, for example, you can footnote marked like this: `1)`
|
|
60
|
+
|
|
61
|
+
## The Stylesheet
|
|
62
|
+
|
|
63
|
+
The footnotes and the footnote block are rendered in HTML with an attached style (`anywhere-footnote`).
|
|
64
|
+
It's included here for reference:
|
|
65
|
+
|
|
66
|
+
```css
|
|
67
|
+
.afnote-marker {
|
|
68
|
+
vertical-align: super;
|
|
69
|
+
font-size: 100%;
|
|
70
|
+
text-decoration: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.afnote-marker::before {
|
|
74
|
+
content: "[";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.afnote-marker::after {
|
|
78
|
+
content: "]";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.afnote-block {
|
|
82
|
+
text-decoration: none;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.afnote-hr-divider {
|
|
86
|
+
height: 1px;
|
|
87
|
+
background-color: #ccc; /* Standard gray color similar to default HR */
|
|
88
|
+
border: none;
|
|
89
|
+
margin: 0.5em 0; /* Standard HR margin */
|
|
90
|
+
width: 20%;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
div.afnote-horizontal dl {
|
|
94
|
+
display: grid;
|
|
95
|
+
grid-template-columns: 30px auto;
|
|
96
|
+
grid-column-gap: 1px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Force each dt and dd to be on the same line */
|
|
100
|
+
div.afnote-horizontal dl > dt,
|
|
101
|
+
div.afnote-horizontal dl > dd {
|
|
102
|
+
display: inline !important;
|
|
103
|
+
vertical-align: top !important;
|
|
104
|
+
margin: 0 !important;
|
|
105
|
+
padding: 0 !important;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Remove margins from paragraphs inside dd */
|
|
109
|
+
div.afnote-horizontal dl > dd p {
|
|
110
|
+
display: inline;
|
|
111
|
+
margin: 0;
|
|
112
|
+
padding: 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Omitting the separator
|
|
118
|
+
|
|
119
|
+
Normally, the footnote block is rendered with a short horizontal line above the footnotes:
|
|
120
|
+
|
|
121
|
+

|
|
122
|
+
|
|
123
|
+
To omit the separator, add the `omit-separator` attribute to the block tag.
|
|
124
|
+
|
|
125
|
+
```asciidoc
|
|
126
|
+
afnote:footnote-block[omit-separator="true"]
|
|
127
|
+
```
|
|
128
|
+

|
|
129
|
+
|
|
130
|
+
## Alternative counting formats
|
|
131
|
+
|
|
132
|
+
By default, the footnotes will be counted using the standard Arabic notion (1, 2, 3, …).
|
|
133
|
+
But other forms can be used by adding an attribute selector to your page:
|
|
134
|
+
|
|
135
|
+
```asciidoc
|
|
136
|
+
:afnote-format: alpha
|
|
137
|
+
```
|
|
138
|
+
The footnotes will use a single letter as a footnote marker.
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
> ** Warning** Do not use this format if you have more than 26 footnotes on your page.
|
|
142
|
+
|
|
143
|
+
You can also use roman numerals.
|
|
144
|
+
|
|
145
|
+
```asciidoc
|
|
146
|
+
:afnote-format: roman
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
> ** Warning** Do not use this format if you have more than 3999 footnotes on your page.
|
|
150
|
+
> (Though if you did then I suspect footnote formatting would be the least of your problems)
|
|
151
|
+
|
|
152
|
+
Omit the `afnote-format` attribute for standard arabic, or use:
|
|
153
|
+
|
|
154
|
+
```asciidoc
|
|
155
|
+
:afnote-format: arabic
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
> ** Note ** Bear in mind that the roman format will take up more space
|
|
159
|
+
## Controlling the Count
|
|
160
|
+
|
|
161
|
+
Normally, the footnotes are numbered page-wide: starting at 1 then continuing to the end of the page.
|
|
162
|
+
If you prefer the count reset to be reset to 1 each time a new block is encountered,
|
|
163
|
+
then put this near the top of the page (before the first footnote):
|
|
164
|
+
|
|
165
|
+
```asciidoc
|
|
166
|
+
:afnote-block-reset: true
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Suppressing the separators globally
|
|
170
|
+
|
|
171
|
+
There is also the option of suppressing the separators for the entire page
|
|
172
|
+
by declaring the following variable near the top of the page (before the first footnote):
|
|
173
|
+
|
|
174
|
+
```asciidoc
|
|
175
|
+
:afnote-omit-separators: true
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Running the Extension
|
|
179
|
+
|
|
180
|
+
Add the extension to your Node installation:
|
|
181
|
+
|
|
182
|
+
```shell
|
|
183
|
+
npm i asciidoctor-anywhere-footnote
|
|
184
|
+
```
|
|
185
|
+
Then extension can be used with an AsciiDoctor ``convert()`` call:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
|
|
189
|
+
registry = asciidoctor.Extensions.create();
|
|
190
|
+
require('../anywhere-footnote-processor')(registry);
|
|
191
|
+
|
|
192
|
+
let converted_doc = asciidoctor.convert(input_document,{safe: 'safe', standalone: true,
|
|
193
|
+
extension_registry: registry})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Or as part of your Antora installation:
|
|
197
|
+
|
|
198
|
+
```yaml
|
|
199
|
+
extensions:
|
|
200
|
+
- asciidoctor-kroki
|
|
201
|
+
- asciidoctor-external-callout
|
|
202
|
+
- '@asciidoctor/tabs'
|
|
203
|
+
- asciidoctor-anywhere-footnote
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# asciidoctor-anywhere-footnote.gemspec
|
|
2
|
+
Gem::Specification.new do |spec|
|
|
3
|
+
spec.name = "asciidoctor-anywhere-footnote"
|
|
4
|
+
spec.version = "1.0.0"
|
|
5
|
+
spec.authors = ["Ray Offiah"]
|
|
6
|
+
spec.email = ["ray.offiah@couchbase.com"]
|
|
7
|
+
|
|
8
|
+
spec.summary = "An Asciidoctor extension for placing footnotes anywhere in the document"
|
|
9
|
+
spec.description = "This extension allows you to place footnotes near their referenced content rather than at the end of the document, with support for multiple footnote blocks, custom formatting, and reference management."
|
|
10
|
+
spec.homepage = "https://github.com/yourusername/asciidoctor-anywhere-footnote"
|
|
11
|
+
spec.license = "MIT"
|
|
12
|
+
|
|
13
|
+
spec.required_ruby_version = ">= 2.5.0"
|
|
14
|
+
|
|
15
|
+
# Specify which files should be added to the gem when it is released
|
|
16
|
+
spec.files = Dir[
|
|
17
|
+
"lib/**/*",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE",
|
|
20
|
+
"*.gemspec"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
spec.require_paths = ["lib"]
|
|
24
|
+
|
|
25
|
+
# Runtime dependencies
|
|
26
|
+
spec.add_runtime_dependency "asciidoctor", "~> 2.0"
|
|
27
|
+
spec.add_runtime_dependency "ruby-enum", "~> 1.0"
|
|
28
|
+
spec.add_runtime_dependency "roman-numerals", "~> 0.3"
|
|
29
|
+
|
|
30
|
+
# Development dependencies
|
|
31
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
|
32
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
33
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
34
|
+
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
require 'asciidoctor'
|
|
2
|
+
require 'ruby-enum'
|
|
3
|
+
require 'roman-numerals'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Asciidoctor::Extensions.register do
|
|
8
|
+
|
|
9
|
+
$footnote_list = []
|
|
10
|
+
|
|
11
|
+
inline_macro AnywhereFootnoteProcessor
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Format
|
|
16
|
+
include Ruby::Enum
|
|
17
|
+
|
|
18
|
+
define :ARABIC, 'arabic'
|
|
19
|
+
define :ROMAN, 'roman'
|
|
20
|
+
define :ALPHA, 'alpha'
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AnywhereFootnote
|
|
26
|
+
attr_accessor :block_id, :ref_id, :text_parameter, :footnote_marker, :lbrace, :rbrace
|
|
27
|
+
|
|
28
|
+
def initialize
|
|
29
|
+
|
|
30
|
+
@block_id = ""
|
|
31
|
+
@ref_id = ""
|
|
32
|
+
@text_parameter = ""
|
|
33
|
+
@footnote_marker = ""
|
|
34
|
+
@lbrace = ""
|
|
35
|
+
@rbrace = ""
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class AnywhereFootnoteProcessor < Asciidoctor::Extensions::InlineMacroProcessor
|
|
40
|
+
|
|
41
|
+
use_dsl
|
|
42
|
+
|
|
43
|
+
named :afnote
|
|
44
|
+
|
|
45
|
+
AFNOTE_FORMAT = 'afnote-format'
|
|
46
|
+
AFNOTE_BLOCK_RESET = 'afnote-block-reset'
|
|
47
|
+
AFNOTE_OMIT_SEPARATORS ="afnote-omit-separators"
|
|
48
|
+
OMIT_SEPARATOR = 'omit-separator'
|
|
49
|
+
|
|
50
|
+
AFNOTE_ID_PREFIX = 'afnote-id-prefix'
|
|
51
|
+
AFNOTE_CSS_PREFIX = 'afnote-css-prefix'
|
|
52
|
+
|
|
53
|
+
AFNOTE_ID_DEFAULT_PREFIX = 'afnote-'
|
|
54
|
+
AFNOTE_CSS_DEFAULT_PREFIX = 'afnote-'
|
|
55
|
+
|
|
56
|
+
$afnote_id_prefix = AFNOTE_ID_DEFAULT_PREFIX
|
|
57
|
+
$afnote_css_prefix = AFNOTE_CSS_DEFAULT_PREFIX
|
|
58
|
+
|
|
59
|
+
def initialize(backend, document)
|
|
60
|
+
super
|
|
61
|
+
@name = 'afnote'
|
|
62
|
+
@document = document
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def process(parent, target, attrs)
|
|
68
|
+
|
|
69
|
+
document = parent.document
|
|
70
|
+
|
|
71
|
+
afnote_format = Format.key(document.attr(AFNOTE_FORMAT) || 'arabic')
|
|
72
|
+
|
|
73
|
+
omit_separators_page_wide = document.attr? AFNOTE_OMIT_SEPARATORS, "true"
|
|
74
|
+
|
|
75
|
+
$afnote_id_prefix = document.attr(AFNOTE_ID_PREFIX) || AFNOTE_ID_DEFAULT_PREFIX
|
|
76
|
+
$afnote_css_prefix = document.attr(AFNOTE_CSS_PREFIX) || AFNOTE_CSS_DEFAULT_PREFIX
|
|
77
|
+
|
|
78
|
+
footnote = AnywhereFootnote.new
|
|
79
|
+
|
|
80
|
+
if target[0] == ':' or attrs.empty? or attrs.has_key? OMIT_SEPARATOR
|
|
81
|
+
|
|
82
|
+
omit_separator = attrs[OMIT_SEPARATOR] == 'true'
|
|
83
|
+
|
|
84
|
+
block_id = target[0] == ':' ? target[1..-1] : target
|
|
85
|
+
return process_footnote_block(parent, block_id, (omit_separator or omit_separators_page_wide))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
block_reset = document.attr? AFNOTE_BLOCK_RESET, "true"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
footnote.block_id = target
|
|
94
|
+
|
|
95
|
+
# This means we have at least a single text parameter
|
|
96
|
+
footnote.text_parameter = attrs[1] || attrs['reftext'] || ""
|
|
97
|
+
|
|
98
|
+
footnote.ref_id = attrs['refid'] || (number_of_footnotes_in_block(footnote.block_id, false) + 1).to_s
|
|
99
|
+
|
|
100
|
+
footnote.footnote_marker = attrs['marker'] if attrs.has_key? 'marker'
|
|
101
|
+
|
|
102
|
+
footnote.lbrace = attrs['lbrace'] || ''
|
|
103
|
+
footnote.rbrace = attrs['rbrace'] || ''
|
|
104
|
+
|
|
105
|
+
add_footnote_reference(footnote, block_reset, afnote_format)
|
|
106
|
+
|
|
107
|
+
# This odd bit of code is to ensure that we don't end up setting duplicate anchor ids
|
|
108
|
+
# for footnotes that reference other footnotes. In this case, the second footnote
|
|
109
|
+
# is assigned another random string, which means we won't be able to click to it
|
|
110
|
+
# from the footnote block.
|
|
111
|
+
|
|
112
|
+
id_string = if $footnote_list.any? { |f| f.ref_id == footnote.ref_id }
|
|
113
|
+
""
|
|
114
|
+
else
|
|
115
|
+
"#{$afnote_id_prefix}#{footnote.block_id}-#{footnote.ref_id}"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
inline = create_footnote_reference(footnote, id_string)
|
|
119
|
+
|
|
120
|
+
$footnote_list << footnote
|
|
121
|
+
|
|
122
|
+
self.create_inline parent, :quoted, inline, :attributes => { 'role' => "#{$afnote_css_prefix}marker" }
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def add_footnote_reference(footnote, block_reset = false, format = :ARABIC)
|
|
127
|
+
|
|
128
|
+
# First, find the highest footnote number.
|
|
129
|
+
# The easiest thing to do is
|
|
130
|
+
# count the number of footnotes in each block
|
|
131
|
+
counter = number_of_footnotes_in_block(footnote.block_id, block_reset) + 1
|
|
132
|
+
|
|
133
|
+
if footnote.ref_id and footnote.text_parameter.empty?
|
|
134
|
+
|
|
135
|
+
referenced_footnote = get_existing_footnote_marker($footnote_list, footnote.ref_id)
|
|
136
|
+
# Add nil checking.
|
|
137
|
+
footnote.footnote_marker = referenced_footnote&.footnote_marker
|
|
138
|
+
footnote.ref_id = referenced_footnote&.ref_id
|
|
139
|
+
|
|
140
|
+
else
|
|
141
|
+
if footnote.footnote_marker.empty?
|
|
142
|
+
footnote.footnote_marker = formatted_number(counter, format)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def get_existing_footnote_marker(footnote_list, ref_id)
|
|
149
|
+
|
|
150
|
+
footnote_list.find { |f| f.ref_id == ref_id and not f.text_parameter.empty?}
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def process_footnote_block(parent, target, omit_separator)
|
|
155
|
+
|
|
156
|
+
block_id = target
|
|
157
|
+
|
|
158
|
+
grouped_footnotes = $footnote_list.group_by { |f| f.block_id }
|
|
159
|
+
selected_block = grouped_footnotes[block_id]
|
|
160
|
+
|
|
161
|
+
unless selected_block
|
|
162
|
+
throw "No footnotes found for block #{block_id}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Add an ID marker
|
|
166
|
+
footnote_block_id_text = "[[#{$afnote_id_prefix}#{block_id}]]\n"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
separator_text = if omit_separator
|
|
170
|
+
""
|
|
171
|
+
else
|
|
172
|
+
self.create_block(parent, :paragraph, "", {"role" => "#{$afnote_css_prefix}hr-divider"}).convert
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
footnote_block_list = self.create_list(parent, :dlist, {"role" => "#{$afnote_css_prefix}horizontal"})
|
|
176
|
+
|
|
177
|
+
selected_block.each do |footnote|
|
|
178
|
+
|
|
179
|
+
unless footnote.text_parameter.empty?
|
|
180
|
+
|
|
181
|
+
# Some footnotes in the list are pointers to other footnotes.
|
|
182
|
+
# If you have duplicate markers, then you will not be able to
|
|
183
|
+
# point back to the original footnote. (Which one would you point back to?)
|
|
184
|
+
# Instead, just use a fake reference when the block is rendered.
|
|
185
|
+
|
|
186
|
+
xref_text = $footnote_list.count { |f| f.ref_id == footnote.ref_id } <= 1 ? "xref:#{$afnote_id_prefix}#{footnote.block_id}-#{footnote.ref_id}-ref" : "xref:#"
|
|
187
|
+
|
|
188
|
+
term = "[[#{$afnote_id_prefix}#{footnote.block_id}-#{footnote.ref_id}-def]]#{xref_text}[#{footnote.lbrace}#{footnote.footnote_marker}#{footnote.rbrace}, role=\"#{$afnote_css_prefix}marker\"]"
|
|
189
|
+
|
|
190
|
+
description = "#{footnote.text_parameter}"
|
|
191
|
+
|
|
192
|
+
dlist_term = self.create_list_item(footnote_block_list, term)
|
|
193
|
+
dlist_description = self.create_list_item(footnote_block_list, description)
|
|
194
|
+
|
|
195
|
+
dlist_item = [[dlist_term], dlist_description]
|
|
196
|
+
|
|
197
|
+
footnote_block_list.items << dlist_item
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
self.create_inline parent, :quoted, "#{footnote_block_id_text}\n#{separator_text}\n#{footnote_block_list.convert}", :attributes => { 'role' => "#{$afnote_css_prefix}block" }
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def create_footnote_reference(footnote, id_string)
|
|
208
|
+
|
|
209
|
+
base_xref = "xref:#{$afnote_id_prefix}#{footnote.block_id}-#{footnote.ref_id}-def[#{footnote.lbrace}#{footnote.footnote_marker}#{footnote.rbrace}]"
|
|
210
|
+
|
|
211
|
+
(not id_string.empty?) ? "[[#{id_string}-ref]]#{base_xref}" : base_xref
|
|
212
|
+
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def number_of_footnotes_in_block(block_id, block_reset = false)
|
|
216
|
+
|
|
217
|
+
if block_reset
|
|
218
|
+
$footnote_list.find_all { |f| f.block_id == block_id and not f.text_parameter.empty? }.size
|
|
219
|
+
else
|
|
220
|
+
$footnote_list.find_all { |f| not f.text_parameter.empty? }.size
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def formatted_number(number, format = :ARABIC)
|
|
226
|
+
case format
|
|
227
|
+
when :ARABIC
|
|
228
|
+
number.to_s
|
|
229
|
+
when :ROMAN
|
|
230
|
+
RomanNumerals.to_roman(number).downcase
|
|
231
|
+
when :ALPHA
|
|
232
|
+
number_to_letter(number)
|
|
233
|
+
else
|
|
234
|
+
throw "Unknown format"
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def number_to_letter(num)
|
|
239
|
+
(num + 96).chr
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
metadata
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: asciidoctor-anywhere-footnote
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ray Offiah
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-07-27 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: asciidoctor
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: ruby-enum
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: roman-numerals
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.3'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.3'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: bundler
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '2.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rake
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '13.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '13.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: minitest
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '5.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '5.0'
|
|
97
|
+
description: This extension allows you to place footnotes near their referenced content
|
|
98
|
+
rather than at the end of the document, with support for multiple footnote blocks,
|
|
99
|
+
custom formatting, and reference management.
|
|
100
|
+
email:
|
|
101
|
+
- ray.offiah@couchbase.com
|
|
102
|
+
executables: []
|
|
103
|
+
extensions: []
|
|
104
|
+
extra_rdoc_files: []
|
|
105
|
+
files:
|
|
106
|
+
- LICENSE
|
|
107
|
+
- README.md
|
|
108
|
+
- asciidoctor-anywhere-footnote.gemspec
|
|
109
|
+
- lib/asciidoctor/anywhere_footnote_processor.rb
|
|
110
|
+
homepage: https://github.com/yourusername/asciidoctor-anywhere-footnote
|
|
111
|
+
licenses:
|
|
112
|
+
- MIT
|
|
113
|
+
metadata: {}
|
|
114
|
+
post_install_message:
|
|
115
|
+
rdoc_options: []
|
|
116
|
+
require_paths:
|
|
117
|
+
- lib
|
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: 2.5.0
|
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
|
+
requirements:
|
|
125
|
+
- - ">="
|
|
126
|
+
- !ruby/object:Gem::Version
|
|
127
|
+
version: '0'
|
|
128
|
+
requirements: []
|
|
129
|
+
rubygems_version: 3.4.10
|
|
130
|
+
signing_key:
|
|
131
|
+
specification_version: 4
|
|
132
|
+
summary: An Asciidoctor extension for placing footnotes anywhere in the document
|
|
133
|
+
test_files: []
|