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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3b8232a60a069137aa8a04c6611f0583877cf036ba6c62c82bef72584c5216d
4
- data.tar.gz: 975f2cb5e0fb8ce6eaa5ae8eb80e3135e1ff44126c102271dd318b148b40b47a
3
+ metadata.gz: 148f84007d3e1e31886f6be8297edfd19f5ddc13e29d1ff565d66a7c27261f85
4
+ data.tar.gz: 0e2794c6183a16940bdd62c62ff0f63e6b55c0e529adb025e596f93041de565f
5
5
  SHA512:
6
- metadata.gz: a012d400a6af140737018adb0187ce7e54be0614d1fd833492cebb35d4310aac91eeab2109ab8d08857333226624084d2ada8a567c21ff8ea43fff018ca17c0c
7
- data.tar.gz: 8df13bfa16acea6e9e65b22e20ff3e138791648c654090d1134140fa94b1bea7b8d439ef8544a73c9c7ac5ad8066539e9eca1842e8f152d86e3634b65bb71c73
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
- - [ ] Rich text formatting within footnote content
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 = @autolink_urls ? autolink_urls(footnote[:content]) : footnote[: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
- @footnote_registry = FootnoteRegistry.new(autolink_urls: autolink_urls)
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
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Panda
4
4
  module Editor
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
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.3.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