markdownr 0.3.2 → 0.3.4
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 +3 -3
- data/lib/markdown_server/version.rb +1 -1
- data/views/layout.erb +71 -5
- 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: 22318ff27259abe3a66849439a50b48103e0a7d2bea077290fd9b8d4a6329716
|
|
4
|
+
data.tar.gz: ce38b5daf5f53c9cf56ae41e1f343bd1db39a1af25a7d04f3fdd1205538ac0bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9996ded48092a440241e924b914a0ad12c054fd02b68e06debaf21cdfbfce6cd74f5f4f5e4657357aff00ae8f3824fc1eb8dc8fb62efdea9153c5ff55ac9b5e0
|
|
7
|
+
data.tar.gz: d9bca1a6f76dd9f578af6b135cfac6d0a12626a4a4720661ef2c46bfdd1c06b7228c73a1ee0f008b29f1ce32709e0ecdd5f060435044b17ee1c79c6f55a51044
|
data/lib/markdown_server/app.rb
CHANGED
|
@@ -159,12 +159,12 @@ module MarkdownServer
|
|
|
159
159
|
%(<sup id="fnref:#{name}" role="doc-noteref"><a href="#fn:#{name}" class="footnote" rel="footnote">#{h(name)}</a></sup>)
|
|
160
160
|
end
|
|
161
161
|
end
|
|
162
|
-
html.gsub(%r{<li id="fn:([^"]+)"[^>]
|
|
162
|
+
html.gsub(%r{<li id="fn:([^"]+)"[^>]*>\s*<p>}m) do
|
|
163
163
|
name = $1
|
|
164
164
|
if name =~ /\A\d+\z/
|
|
165
165
|
$&
|
|
166
166
|
else
|
|
167
|
-
%(<li id="fn:#{name}"
|
|
167
|
+
%(<li id="fn:#{name}"><p><strong>#{h(name)}:</strong> )
|
|
168
168
|
end
|
|
169
169
|
end
|
|
170
170
|
end
|
|
@@ -219,7 +219,7 @@ module MarkdownServer
|
|
|
219
219
|
def extract_toc(html)
|
|
220
220
|
headings = []
|
|
221
221
|
html.scan(/<h([1-6])\s[^>]*id="([^"]*)"[^>]*>(.*?)<\/h\1>/mi) do |level, id, text|
|
|
222
|
-
clean_text = text.gsub(/<[^>]+>/, "").strip
|
|
222
|
+
clean_text = text.gsub(/<sup[^>]*id="fnref:[^"]*"[^>]*>.*?<\/sup>/i, "").gsub(/<[^>]+>/, "").strip
|
|
223
223
|
headings << { level: level.to_i, id: id, text: clean_text }
|
|
224
224
|
end
|
|
225
225
|
headings
|
data/views/layout.erb
CHANGED
|
@@ -713,6 +713,9 @@
|
|
|
713
713
|
padding: 2rem 0;
|
|
714
714
|
}
|
|
715
715
|
|
|
716
|
+
/* Footnote list — hide numeric markers; labels are inline via <strong> */
|
|
717
|
+
.footnotes ol { list-style: none; padding-left: 1.2em; }
|
|
718
|
+
|
|
716
719
|
/* Footnote tooltips */
|
|
717
720
|
.footnote-tooltip {
|
|
718
721
|
position: absolute;
|
|
@@ -728,15 +731,15 @@
|
|
|
728
731
|
max-width: 350px;
|
|
729
732
|
width: max-content;
|
|
730
733
|
z-index: 150;
|
|
731
|
-
pointer-events: none;
|
|
732
734
|
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
|
|
733
735
|
margin-bottom: 6px;
|
|
734
736
|
}
|
|
737
|
+
.footnote-tooltip { cursor: pointer; }
|
|
735
738
|
.footnote-tooltip::after {
|
|
736
739
|
content: '';
|
|
737
740
|
position: absolute;
|
|
738
741
|
top: 100%;
|
|
739
|
-
left: 50
|
|
742
|
+
left: calc(50% + var(--arrow-offset, 0px));
|
|
740
743
|
transform: translateX(-50%);
|
|
741
744
|
border: 5px solid transparent;
|
|
742
745
|
border-top-color: #2d2d2d;
|
|
@@ -1090,12 +1093,75 @@
|
|
|
1090
1093
|
var tooltip = document.createElement('span');
|
|
1091
1094
|
tooltip.className = 'footnote-tooltip';
|
|
1092
1095
|
tooltip.innerHTML = html;
|
|
1096
|
+
var fnHref = link.getAttribute('href');
|
|
1093
1097
|
|
|
1094
|
-
|
|
1098
|
+
function showTooltip() {
|
|
1095
1099
|
sup.appendChild(tooltip);
|
|
1096
|
-
|
|
1097
|
-
|
|
1100
|
+
// Reset any previous adjustment
|
|
1101
|
+
tooltip.style.left = '50%';
|
|
1102
|
+
tooltip.style.transform = 'translateX(-50%)';
|
|
1103
|
+
tooltip.style.removeProperty('--arrow-offset');
|
|
1104
|
+
// Clamp tooltip to viewport.
|
|
1105
|
+
// document.documentElement.clientWidth is more reliable than window.innerWidth
|
|
1106
|
+
// on Android browsers (e.g. EinkBro) which may return a pre-scaled layout
|
|
1107
|
+
// viewport width for window.innerWidth rather than the CSS viewport width.
|
|
1108
|
+
var viewportWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
|
|
1109
|
+
var rect = tooltip.getBoundingClientRect();
|
|
1110
|
+
var shift = 0;
|
|
1111
|
+
if (rect.left < 8) {
|
|
1112
|
+
shift = 8 - rect.left;
|
|
1113
|
+
} else if (rect.right > viewportWidth - 8) {
|
|
1114
|
+
shift = (viewportWidth - 8) - rect.right;
|
|
1115
|
+
}
|
|
1116
|
+
if (shift !== 0) {
|
|
1117
|
+
tooltip.style.transform = 'translateX(calc(-50% + ' + shift + 'px))';
|
|
1118
|
+
tooltip.style.setProperty('--arrow-offset', (-shift) + 'px');
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
function hideTooltip() {
|
|
1098
1123
|
if (tooltip.parentNode === sup) sup.removeChild(tooltip);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// Hover devices: show/hide on mouseenter/mouseleave
|
|
1127
|
+
sup.addEventListener('mouseenter', showTooltip);
|
|
1128
|
+
sup.addEventListener('mouseleave', hideTooltip);
|
|
1129
|
+
|
|
1130
|
+
// Touch: first tap shows tooltip, second tap navigates
|
|
1131
|
+
// Using touchend instead of click so no hover media query check is needed —
|
|
1132
|
+
// touchend only fires on real touch, regardless of what (hover:none) reports.
|
|
1133
|
+
var linkTouchMoved = false;
|
|
1134
|
+
link.addEventListener('touchstart', function() { linkTouchMoved = false; }, { passive: true });
|
|
1135
|
+
link.addEventListener('touchmove', function() { linkTouchMoved = true; }, { passive: true });
|
|
1136
|
+
link.addEventListener('touchend', function(e) {
|
|
1137
|
+
if (linkTouchMoved) return; // scroll, not a tap
|
|
1138
|
+
if (tooltip.parentNode === sup) {
|
|
1139
|
+
// Tooltip already showing — let the link navigate
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
e.preventDefault();
|
|
1143
|
+
// Dismiss any other open tooltip
|
|
1144
|
+
document.querySelectorAll('.footnote-tooltip').forEach(function(t) {
|
|
1145
|
+
if (t.parentNode) t.parentNode.removeChild(t);
|
|
1146
|
+
});
|
|
1147
|
+
showTooltip();
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
var tooltipTouchMoved = false;
|
|
1151
|
+
tooltip.addEventListener('touchstart', function() { tooltipTouchMoved = false; }, { passive: true });
|
|
1152
|
+
tooltip.addEventListener('touchmove', function() { tooltipTouchMoved = true; }, { passive: true });
|
|
1153
|
+
tooltip.addEventListener('touchend', function(e) {
|
|
1154
|
+
if (tooltipTouchMoved) return;
|
|
1155
|
+
e.stopPropagation();
|
|
1156
|
+
hideTooltip();
|
|
1157
|
+
window.location.hash = fnHref;
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1160
|
+
// Dismiss tooltip when tapping elsewhere
|
|
1161
|
+
document.addEventListener('click', function(e) {
|
|
1162
|
+
if (tooltip.parentNode === sup && !sup.contains(e.target)) {
|
|
1163
|
+
hideTooltip();
|
|
1164
|
+
}
|
|
1099
1165
|
});
|
|
1100
1166
|
});
|
|
1101
1167
|
})();
|