markdownr 0.3.1 → 0.3.2

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: 9d4082e717ca40db7ce0542b04d70550df3dfcba368f8e765d2ccee3139e280f
4
- data.tar.gz: b9caeb121bc3f2adf3e59ec353ba45fb8a59c851c49029a35387dfa2a555c6f9
3
+ metadata.gz: 18e8cbcc75e4fb58756514287b06b2824f56aafd336f9be4346d7846b8566b48
4
+ data.tar.gz: 2f1d715b1f94a943212a59da5ee992c7ef575c85e6059caa51579a4fd172eb69
5
5
  SHA512:
6
- metadata.gz: 1b8116a05668547942ad31702ae4b55b4f39de9806552414cd1f5d25e7213e150b24f3eed4098cf7f25b70013e4fc72358628fe8add35e08532cfd89938f9f5c
7
- data.tar.gz: 0acc8c5aa280ca7761f0a9da56f072a3a7cd81e0ce561598c08f6f29b0f5d2b40c92a1da2308cf843eff2447ed4093861c18a85144df1d94580556cebbcf0bbd
6
+ metadata.gz: 736446de4daffd8c1babdd82c307b3b0e46c3fb0fa5a08cf419429d7c119dc0763c6c9a0e95a7913abba6e0b291a5a085f8bb46258e614db102f8ff5c225494e
7
+ data.tar.gz: 2eb655f06a7380c7f4477735ae28e84afd454c68354b18fdd6d572cc01d4c5daccd3986ae3f4b368564042542c6fbb0ef7167f15b18f13bf5d0b9caa80e8e98c
@@ -114,6 +114,33 @@ module MarkdownServer
114
114
  end
115
115
 
116
116
  def render_markdown(text)
117
+ # Process wiki links BEFORE Kramdown so that | isn't consumed as
118
+ # a GFM table delimiter.
119
+ text = text.gsub(/\[\[([^\]]+)\]\]/) do
120
+ raw = $1
121
+ if raw.include?("|")
122
+ target, display = raw.split("|", 2)
123
+ else
124
+ target = raw
125
+ display = nil
126
+ end
127
+
128
+ if target.start_with?("#")
129
+ heading_text = target[1..]
130
+ anchor = heading_text.downcase.gsub(/\s+/, "-").gsub(/[^\w-]/, "")
131
+ label = display || heading_text
132
+ %(<a class="wiki-link" href="##{h(anchor)}">#{h(label)}</a>)
133
+ else
134
+ resolved = resolve_wiki_link(target)
135
+ label = display || target
136
+ if resolved
137
+ %(<a class="wiki-link" href="/browse/#{encode_path_component(resolved).gsub('%2F', '/')}">#{h(label)}</a>)
138
+ else
139
+ %(<span class="wiki-link broken">#{h(label)}</span>)
140
+ end
141
+ end
142
+ end
143
+
117
144
  html = Kramdown::Document.new(
118
145
  text,
119
146
  input: "GFM",
@@ -122,13 +149,22 @@ module MarkdownServer
122
149
  hard_wrap: false
123
150
  ).to_html
124
151
 
125
- html.gsub(/\[\[([^\]]+)\]\]/) do
126
- link_text = $1
127
- resolved = resolve_wiki_link(link_text)
128
- if resolved
129
- %(<a class="wiki-link" href="/browse/#{encode_path_component(resolved).gsub('%2F', '/')}">#{h(link_text)}</a>)
152
+ # Restore non-numeric footnote labels: Kramdown converts all footnote
153
+ # references to sequential numbers, but we want [^abc] to display "abc".
154
+ html = html.gsub(%r{<sup id="fnref:([^"]+)"[^>]*>\s*<a href="#fn:\1"[^>]*>\d+</a>\s*</sup>}m) do
155
+ name = $1
156
+ if name =~ /\A\d+\z/
157
+ $& # keep numeric footnotes as-is
158
+ else
159
+ %(<sup id="fnref:#{name}" role="doc-noteref"><a href="#fn:#{name}" class="footnote" rel="footnote">#{h(name)}</a></sup>)
160
+ end
161
+ end
162
+ html.gsub(%r{<li id="fn:([^"]+)"[^>]*role="doc-endnote"[^>]*>\s*<p>}m) do
163
+ name = $1
164
+ if name =~ /\A\d+\z/
165
+ $&
130
166
  else
131
- %(<span class="wiki-link broken">#{h(link_text)}</span>)
167
+ %(<li id="fn:#{name}" role="doc-endnote"><p><strong>#{h(name)}:</strong> )
132
168
  end
133
169
  end
134
170
  end
@@ -1,3 +1,3 @@
1
1
  module MarkdownServer
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
data/views/layout.erb CHANGED
@@ -713,6 +713,43 @@
713
713
  padding: 2rem 0;
714
714
  }
715
715
 
716
+ /* Footnote tooltips */
717
+ .footnote-tooltip {
718
+ position: absolute;
719
+ bottom: 100%;
720
+ left: 50%;
721
+ transform: translateX(-50%);
722
+ background: #2d2d2d;
723
+ color: #f0f0f0;
724
+ padding: 0.5rem 0.75rem;
725
+ border-radius: 5px;
726
+ font-size: 0.82rem;
727
+ line-height: 1.5;
728
+ max-width: 350px;
729
+ width: max-content;
730
+ z-index: 150;
731
+ pointer-events: none;
732
+ box-shadow: 0 2px 8px rgba(0,0,0,0.25);
733
+ margin-bottom: 6px;
734
+ }
735
+ .footnote-tooltip::after {
736
+ content: '';
737
+ position: absolute;
738
+ top: 100%;
739
+ left: 50%;
740
+ transform: translateX(-50%);
741
+ border: 5px solid transparent;
742
+ border-top-color: #2d2d2d;
743
+ }
744
+ .footnote-tooltip em, .footnote-tooltip i { font-style: italic; }
745
+ .footnote-tooltip strong, .footnote-tooltip b { font-weight: 700; }
746
+ .footnote-tooltip a { color: #d4b96a; }
747
+ .footnote-tooltip p { margin: 0; }
748
+ .footnote-tooltip p + p { margin-top: 0.3rem; }
749
+ sup[id^="fnref:"] {
750
+ position: relative;
751
+ }
752
+
716
753
  /* Responsive */
717
754
  @media (max-width: 768px) {
718
755
  .container { padding: 1rem; }
@@ -1020,6 +1057,49 @@
1020
1057
  }, { passive: true });
1021
1058
  })();
1022
1059
 
1060
+ // Footnote hover tooltips
1061
+ (function() {
1062
+ var refs = document.querySelectorAll('sup[id^="fnref:"]');
1063
+ refs.forEach(function(sup) {
1064
+ var link = sup.querySelector('a[href^="#fn:"]');
1065
+ if (!link) return;
1066
+ var fnId = link.getAttribute('href').slice(1); // "fn:name"
1067
+ var fnLi = document.getElementById(fnId);
1068
+ if (!fnLi) return;
1069
+
1070
+ // Clone the footnote content, strip the back-reference link
1071
+ var clone = fnLi.cloneNode(true);
1072
+ var backLinks = clone.querySelectorAll('a.reversefootnote, a[href^="#fnref:"]');
1073
+ backLinks.forEach(function(a) { a.remove(); });
1074
+ // Also remove the label prefix we add (e.g. "<strong>a:</strong> ")
1075
+ var firstStrong = clone.querySelector('p > strong:first-child');
1076
+ if (firstStrong && /:\s*$/.test(firstStrong.textContent)) {
1077
+ var nextSibling = firstStrong.nextSibling;
1078
+ if (nextSibling && nextSibling.nodeType === 3) {
1079
+ nextSibling.textContent = nextSibling.textContent.replace(/^\s+/, '');
1080
+ }
1081
+ firstStrong.remove();
1082
+ }
1083
+ var html = clone.innerHTML.trim();
1084
+ // Unwrap if it's just a single <p>
1085
+ var single = html.match(/^<p>([\s\S]*)<\/p>$/i);
1086
+ if (single && !/<p[\s>]/i.test(single[1])) {
1087
+ html = single[1];
1088
+ }
1089
+
1090
+ var tooltip = document.createElement('span');
1091
+ tooltip.className = 'footnote-tooltip';
1092
+ tooltip.innerHTML = html;
1093
+
1094
+ sup.addEventListener('mouseenter', function() {
1095
+ sup.appendChild(tooltip);
1096
+ });
1097
+ sup.addEventListener('mouseleave', function() {
1098
+ if (tooltip.parentNode === sup) sup.removeChild(tooltip);
1099
+ });
1100
+ });
1101
+ })();
1102
+
1023
1103
  // Jump to search match from _find query param
1024
1104
  (function() {
1025
1105
  var content = document.querySelector('.md-content');
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdownr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Dunn