panda-editor 0.3.0 → 0.4.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +24 -0
- data/docs/FOOTNOTES.md +51 -2
- data/lib/panda/editor/footnote_registry.rb +44 -2
- data/lib/panda/editor/renderer.rb +2 -1
- data/lib/panda/editor/version.rb +1 -1
- data/panda-editor.gemspec +1 -0
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 148f84007d3e1e31886f6be8297edfd19f5ddc13e29d1ff565d66a7c27261f85
|
|
4
|
+
data.tar.gz: 0e2794c6183a16940bdd62c62ff0f63e6b55c0e529adb025e596f93041de565f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 06cef5d5517ef1211bcfc1b0b5c0c63dba5c8bfd9d189b1074e1174d261d14de5d15c522734cdc69fca71c3ef3cfbbed88fe741de6e739a4c9b49a4a7960219d
|
|
7
|
+
data.tar.gz: c169a830348145a9b9f24a62d15333a02fb9b27cc0bdc2356a383ade82010af16369e2279034bae78607ff751844c52a417d872a0146023445bcf7c4d7dc29b8
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.0] - 2025-10-30
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Markdown support for rich text formatting in footnotes
|
|
12
|
+
- **Bold**, *italic*, `code`, ~~strikethrough~~, and [link](url) support
|
|
13
|
+
- Automatic URL linking in markdown content
|
|
14
|
+
- Security-hardened Redcarpet configuration (no images, safe links only)
|
|
15
|
+
- Works alongside existing autolink_urls option
|
|
16
|
+
- Comprehensive test coverage for markdown features
|
|
17
|
+
- Updated documentation with markdown examples
|
|
18
|
+
|
|
8
19
|
## [0.3.0] - 2025-10-30
|
|
9
20
|
|
|
10
21
|
### Added
|
data/README.md
CHANGED
|
@@ -168,6 +168,27 @@ The sources section includes data attributes for integration with JavaScript fra
|
|
|
168
168
|
|
|
169
169
|
See [docs/FOOTNOTES.md](docs/FOOTNOTES.md) for detailed implementation examples.
|
|
170
170
|
|
|
171
|
+
### Markdown Support
|
|
172
|
+
|
|
173
|
+
Enable markdown formatting in footnote content for rich text citations:
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
renderer = Panda::Editor::Renderer.new(@content, markdown: true)
|
|
177
|
+
html = renderer.render
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Supports **bold**, *italic*, `code`, ~~strikethrough~~, and [links](url):
|
|
181
|
+
|
|
182
|
+
**Input:**
|
|
183
|
+
```
|
|
184
|
+
Smith, J. (2023). **Important study** on *ADHD treatment*. See https://example.com for details.
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Output:**
|
|
188
|
+
```html
|
|
189
|
+
Smith, J. (2023). <strong>Important study</strong> on <em>ADHD treatment</em>. See <a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a> for details.
|
|
190
|
+
```
|
|
191
|
+
|
|
171
192
|
### Auto-linking URLs
|
|
172
193
|
|
|
173
194
|
Enable automatic URL linking in footnote content:
|
|
@@ -195,6 +216,9 @@ Features:
|
|
|
195
216
|
- Won't double-link URLs already in `<a>` tags
|
|
196
217
|
- Supports `http://`, `https://`, `ftp://`, and `www.` URLs
|
|
197
218
|
- Handles multiple URLs in the same footnote
|
|
219
|
+
- Can be combined with `markdown: true` (markdown's autolink runs first, then custom autolink for any remaining URLs)
|
|
220
|
+
|
|
221
|
+
**Note:** When using `markdown: true`, you typically don't need `autolink_urls: true` as markdown includes built-in autolinking. However, both options can work together safely.
|
|
198
222
|
|
|
199
223
|
To enable globally for all content using the `Panda::Editor::Content` concern, pass the option in `generate_cached_content`.
|
|
200
224
|
|
data/docs/FOOTNOTES.md
CHANGED
|
@@ -308,9 +308,58 @@ insert at position 11: "Hello world<sup>2</sup>"
|
|
|
308
308
|
insert at position 5: "Hello<sup>1</sup> world<sup>2</sup>"
|
|
309
309
|
```
|
|
310
310
|
|
|
311
|
+
### Markdown Support
|
|
312
|
+
|
|
313
|
+
The footnote system supports markdown formatting, allowing you to use rich text formatting in your citations.
|
|
314
|
+
|
|
315
|
+
**Enable markdown:**
|
|
316
|
+
|
|
317
|
+
```ruby
|
|
318
|
+
renderer = Panda::Editor::Renderer.new(content, markdown: true)
|
|
319
|
+
output = renderer.render
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Supported markdown features:**
|
|
323
|
+
|
|
324
|
+
- **Bold text** (`**bold**` or `__bold__`)
|
|
325
|
+
- *Italic text* (`*italic*` or `_italic_`)
|
|
326
|
+
- `Inline code` (`` `code` ``)
|
|
327
|
+
- ~~Strikethrough~~ (`~~text~~`)
|
|
328
|
+
- [Links](url) (`[text](url)`)
|
|
329
|
+
- Automatic URL linking
|
|
330
|
+
|
|
331
|
+
**Example:**
|
|
332
|
+
|
|
333
|
+
```ruby
|
|
334
|
+
content = {
|
|
335
|
+
"blocks" => [{
|
|
336
|
+
"type" => "paragraph",
|
|
337
|
+
"data" => {
|
|
338
|
+
"text" => "Research findings",
|
|
339
|
+
"footnotes" => [{
|
|
340
|
+
"id" => "fn-1",
|
|
341
|
+
"content" => "Smith, J. (2023). **Important study** on *ADHD treatment*. See https://example.com for details.",
|
|
342
|
+
"position" => 17
|
|
343
|
+
}]
|
|
344
|
+
}
|
|
345
|
+
}]
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
renderer = Panda::Editor::Renderer.new(content, markdown: true)
|
|
349
|
+
# Output will include: Smith, J. (2023). <strong>Important study</strong> on <em>ADHD treatment</em>. See <a href="https://example.com">https://example.com</a> for details.
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Important notes:**
|
|
353
|
+
|
|
354
|
+
- Markdown includes built-in URL autolinking, so you typically don't need `autolink_urls: true` when using markdown
|
|
355
|
+
- However, both options can be used together if needed - the custom autolink_urls will skip URLs that markdown already linked
|
|
356
|
+
- Markdown links are rendered with `target="_blank"` and `rel="noopener noreferrer"` for security
|
|
357
|
+
- Images are disabled in markdown footnotes for security
|
|
358
|
+
- HTML styles are stripped from markdown output
|
|
359
|
+
|
|
311
360
|
### Auto-linking URLs
|
|
312
361
|
|
|
313
|
-
The footnote system can automatically convert plain URLs in footnote content into clickable links.
|
|
362
|
+
The footnote system can automatically convert plain URLs in footnote content into clickable links when markdown is not enabled.
|
|
314
363
|
|
|
315
364
|
**Enable auto-linking:**
|
|
316
365
|
|
|
@@ -575,7 +624,7 @@ bundle exec rspec spec/lib/panda/editor/renderer_spec.rb
|
|
|
575
624
|
Potential improvements for future versions:
|
|
576
625
|
|
|
577
626
|
- [ ] Support for footnotes in other block types (headers, quotes, etc.)
|
|
578
|
-
- [
|
|
627
|
+
- [x] Rich text formatting within footnote content (implemented via markdown support)
|
|
579
628
|
- [ ] Footnote tooltips on hover
|
|
580
629
|
- [ ] Customizable footnote markers (*, †, ‡, etc.)
|
|
581
630
|
- [ ] Export footnotes to bibliography formats (BibTeX, etc.)
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "redcarpet"
|
|
4
|
+
|
|
3
5
|
module Panda
|
|
4
6
|
module Editor
|
|
5
7
|
class FootnoteRegistry
|
|
6
8
|
attr_reader :footnotes
|
|
7
9
|
|
|
8
|
-
def initialize(autolink_urls: false)
|
|
10
|
+
def initialize(autolink_urls: false, markdown: false)
|
|
9
11
|
@footnotes = []
|
|
10
12
|
@footnote_ids = {}
|
|
11
13
|
@autolink_urls = autolink_urls
|
|
14
|
+
@markdown = markdown
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
def add(id:, content:)
|
|
@@ -30,7 +33,7 @@ module Panda
|
|
|
30
33
|
|
|
31
34
|
footnote_items = @footnotes.map.with_index do |footnote, index|
|
|
32
35
|
number = index + 1
|
|
33
|
-
content =
|
|
36
|
+
content = process_content(footnote[:content])
|
|
34
37
|
<<~HTML.strip
|
|
35
38
|
<li id="fn:#{number}">
|
|
36
39
|
<p>
|
|
@@ -66,6 +69,45 @@ module Panda
|
|
|
66
69
|
|
|
67
70
|
private
|
|
68
71
|
|
|
72
|
+
def process_content(content)
|
|
73
|
+
# Apply markdown processing if enabled
|
|
74
|
+
content = render_markdown(content) if @markdown
|
|
75
|
+
|
|
76
|
+
# Apply URL autolinking if enabled
|
|
77
|
+
# Note: Markdown already includes autolink, but custom autolink_urls can still be used
|
|
78
|
+
# if needed for additional URL patterns. The autolink_urls method skips already-linked URLs.
|
|
79
|
+
content = autolink_urls(content) if @autolink_urls
|
|
80
|
+
|
|
81
|
+
content
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def render_markdown(text)
|
|
85
|
+
# Configure Redcarpet with safe options for footnotes
|
|
86
|
+
renderer = Redcarpet::Render::HTML.new(
|
|
87
|
+
filter_html: false,
|
|
88
|
+
no_images: true,
|
|
89
|
+
no_styles: true,
|
|
90
|
+
safe_links_only: true,
|
|
91
|
+
link_attributes: {target: "_blank", rel: "noopener noreferrer"}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
markdown = Redcarpet::Markdown.new(
|
|
95
|
+
renderer,
|
|
96
|
+
autolink: true,
|
|
97
|
+
space_after_headers: true,
|
|
98
|
+
fenced_code_blocks: false,
|
|
99
|
+
no_intra_emphasis: true,
|
|
100
|
+
strikethrough: true,
|
|
101
|
+
superscript: false,
|
|
102
|
+
underline: false
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Render markdown and strip the wrapping <p> tags if present
|
|
106
|
+
# since we're already wrapping in <p> tags in the template
|
|
107
|
+
html = markdown.render(text).strip
|
|
108
|
+
html.gsub(%r{^<p>(.*)</p>$}m, '\1')
|
|
109
|
+
end
|
|
110
|
+
|
|
69
111
|
def autolink_urls(text)
|
|
70
112
|
# Regex to match URLs that aren't already in <a> tags
|
|
71
113
|
# Matches http://, https://, and other common protocols
|
|
@@ -14,7 +14,8 @@ module Panda
|
|
|
14
14
|
@cache_store = options.delete(:cache_store) || Rails.cache
|
|
15
15
|
@validate_html = options.delete(:validate_html) || false
|
|
16
16
|
autolink_urls = options.delete(:autolink_urls) || false
|
|
17
|
-
|
|
17
|
+
markdown = options.delete(:markdown) || false
|
|
18
|
+
@footnote_registry = FootnoteRegistry.new(autolink_urls: autolink_urls, markdown: markdown)
|
|
18
19
|
@options[:footnote_registry] = @footnote_registry
|
|
19
20
|
end
|
|
20
21
|
|
data/lib/panda/editor/version.rb
CHANGED
data/panda-editor.gemspec
CHANGED
|
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_dependency "rails", ">= 7.1"
|
|
35
35
|
spec.add_dependency "sanitize", "~> 6.0"
|
|
36
36
|
spec.add_dependency "dry-configurable", "~> 1.0"
|
|
37
|
+
spec.add_dependency "redcarpet", "~> 3.6"
|
|
37
38
|
|
|
38
39
|
# Development dependencies
|
|
39
40
|
spec.add_development_dependency "rspec-rails", "~> 6.0"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: panda-editor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Otaina Limited
|
|
@@ -53,6 +53,20 @@ dependencies:
|
|
|
53
53
|
- - "~>"
|
|
54
54
|
- !ruby/object:Gem::Version
|
|
55
55
|
version: '1.0'
|
|
56
|
+
- !ruby/object:Gem::Dependency
|
|
57
|
+
name: redcarpet
|
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - "~>"
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '3.6'
|
|
63
|
+
type: :runtime
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - "~>"
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '3.6'
|
|
56
70
|
- !ruby/object:Gem::Dependency
|
|
57
71
|
name: rspec-rails
|
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|