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 +4 -4
- data/lib/markdown_server/app.rb +42 -6
- data/lib/markdown_server/version.rb +1 -1
- data/views/layout.erb +80 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 18e8cbcc75e4fb58756514287b06b2824f56aafd336f9be4346d7846b8566b48
|
|
4
|
+
data.tar.gz: 2f1d715b1f94a943212a59da5ee992c7ef575c85e6059caa51579a4fd172eb69
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 736446de4daffd8c1babdd82c307b3b0e46c3fb0fa5a08cf419429d7c119dc0763c6c9a0e95a7913abba6e0b291a5a085f8bb46258e614db102f8ff5c225494e
|
|
7
|
+
data.tar.gz: 2eb655f06a7380c7f4477735ae28e84afd454c68354b18fdd6d572cc01d4c5daccd3986ae3f4b368564042542c6fbb0ef7167f15b18f13bf5d0b9caa80e8e98c
|
data/lib/markdown_server/app.rb
CHANGED
|
@@ -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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
%(<
|
|
167
|
+
%(<li id="fn:#{name}" role="doc-endnote"><p><strong>#{h(name)}:</strong> )
|
|
132
168
|
end
|
|
133
169
|
end
|
|
134
170
|
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');
|