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 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
+ ![footnote separator](footnote-separator.png "Footnote separator")
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
+ ![Footnotes without separator](footnote-without-separator.png "Footnotes without separators")
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: []