markdownr 0.6.3 → 0.6.5

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: 722e15f2df1b9be481803fab089a9cbcd03feca4074066af6e9c1fd32172eb95
4
- data.tar.gz: 7a35e644b28724d93e14147688ed34f3a824d8eec1f2e972eb8dd2f599a94b8e
3
+ metadata.gz: af0a41eadcbe996f7165b92a56174857657a21698308b515a35a67ec81a9a3e0
4
+ data.tar.gz: 12f87ff3043049997f895f4dc0bde07d6d7e41c0195286b1abe29c91eada81e2
5
5
  SHA512:
6
- metadata.gz: 689bdd5757bec61a6284b63b3ab6b1a67dfa9e160b7343e63787962f9ed2cbf2c4b2ad677ec482d4e7712c445a17a94e068b80b551392f737eb1ec7546b55754
7
- data.tar.gz: 74cfee882d280839673ee560c3dded04c6cc3ca7f605766f037ea531538c5a8a04b697928081a74480a8830cca07192cd5389629949a96cc16b8c6565390eb58
6
+ metadata.gz: cc617683848f464907a1f8d4e17986a80842e631b9e68dcd6d3eb340bb0b658d080a9849c8f1a6ec952f8ceaa23cb95fda4760e44dc02b36a6620a7b30dcbf53
7
+ data.tar.gz: 73bbfe99e65f7c50b4c4ffca35b4ab98d9a706f3c8367451b115e61919391ec95d987396cb75f5cbf7890822f4ec4b0456255a47a9872af5745b2dc90737e92b
@@ -750,7 +750,7 @@ module MarkdownServer
750
750
 
751
751
  def scrip_html(html)
752
752
  # Extract the passage content block
753
- content = html[/<div\s+class="passage-text[^"]*"[^>]*>([\s\S]*?)<\/div>\s*(?:<nav|$)/im, 1] || ""
753
+ content = html[/<div\s+class="passage-text[^"]*"[^>]*>([\s\S]*?)<\/div>\s*(?:<nav|\z)/im, 1] || ""
754
754
  return page_html(html) if content.empty?
755
755
 
756
756
  # Add data-verse attributes to verse spans for popup scrolling.
@@ -1,3 +1,3 @@
1
1
  module MarkdownServer
2
- VERSION = "0.6.3"
2
+ VERSION = "0.6.5"
3
3
  end
data/views/layout.erb CHANGED
@@ -883,6 +883,12 @@
883
883
  margin-bottom: 0.5rem;
884
884
  }
885
885
 
886
+ /* Verse range highlighting */
887
+ .verse-selected {
888
+ background: #e5eefb;
889
+ border-radius: 2px;
890
+ }
891
+
886
892
  /* Mermaid diagrams */
887
893
  .mermaid { text-align: center; margin: 1.2rem 0; overflow-x: auto; }
888
894
  .mermaid svg { max-width: 100%; height: auto; }
@@ -2017,30 +2023,57 @@
2017
2023
  historyStack = [];
2018
2024
  }
2019
2025
 
2026
+ function findVerseSpans(root, verseNum) {
2027
+ var num = String(verseNum);
2028
+ // Prefer .verse spans (full verse text) with exact verse number match
2029
+ var all = root.querySelectorAll('.verse[data-verse]');
2030
+ var matches = [];
2031
+ for (var i = 0; i < all.length; i++) {
2032
+ var dv = all[i].getAttribute('data-verse');
2033
+ var after = dv.split(':').pop();
2034
+ if (after === num) matches.push(all[i]);
2035
+ }
2036
+ if (matches.length) return matches;
2037
+ // Fallback: bare data-verse="N" (e.g. sup elements from scrip_html)
2038
+ var span = root.querySelector('[data-verse="' + num + '"]');
2039
+ return span ? [span] : [];
2040
+ }
2041
+
2020
2042
  function applyPopupAnchor(hash) {
2021
2043
  if (!hash || !popup) return;
2022
2044
  var id = hash.replace(/^#/, '');
2023
2045
  try {
2024
- var eid = id.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
2025
- var target = popup.querySelector('[id="' + eid + '"]');
2026
- // For scrip verse anchors like #v15, find by data-verse attribute
2027
- if (!target) {
2028
- var vm = id.match(/^v(\d+)$/);
2029
- if (vm) {
2030
- target = popup.querySelector('[data-verse="' + vm[1] + '"]');
2031
- // Also match "Book Ch:Verse" format like data-verse="Acts 17:25"
2032
- if (!target) target = popup.querySelector('[data-verse$=":' + vm[1] + '"]');
2046
+ var body = popup.querySelector('.link-ctx-popup-body');
2047
+ if (!body) return;
2048
+
2049
+ // Verse range: #vN or #vN-M
2050
+ var vm = id.match(/^v(\d+)(?:-(\d+))?$/);
2051
+ if (vm) {
2052
+ var start = parseInt(vm[1], 10);
2053
+ var end = vm[2] ? parseInt(vm[2], 10) : start;
2054
+ var first = null;
2055
+ for (var v = start; v <= end; v++) {
2056
+ var spans = findVerseSpans(body, v);
2057
+ for (var i = 0; i < spans.length; i++) {
2058
+ spans[i].classList.add('verse-selected');
2059
+ if (!first) first = spans[i];
2060
+ }
2061
+ }
2062
+ if (first) {
2063
+ var bodyTop = body.getBoundingClientRect().top;
2064
+ var targetTop = first.getBoundingClientRect().top;
2065
+ body.scrollTop += targetTop - bodyTop - 8;
2033
2066
  }
2067
+ return;
2034
2068
  }
2069
+
2070
+ // Standard anchor by ID
2071
+ var eid = id.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
2072
+ var target = popup.querySelector('[id="' + eid + '"]');
2035
2073
  if (!target) return;
2036
- // Scroll the body container (which has overflow-y:auto) to the target,
2037
- // accounting for the sticky header so the heading lands just below it
2038
- var body = popup.querySelector('.link-ctx-popup-body');
2039
- if (!body) return;
2040
2074
  var bodyTop = body.getBoundingClientRect().top;
2041
2075
  var targetTop = target.getBoundingClientRect().top;
2042
2076
  body.scrollTop += targetTop - bodyTop - 8;
2043
- // Append section heading text to the popup title
2044
2077
  if (/^H[1-6]$/.test(target.tagName)) {
2045
2078
  var titleEl = popup.querySelector('.link-ctx-popup-title span');
2046
2079
  if (titleEl) titleEl.textContent = titleEl.textContent + ' \u203a ' + target.textContent;
@@ -142,6 +142,12 @@
142
142
  margin-bottom: 0.5rem;
143
143
  }
144
144
 
145
+ /* Verse range highlighting */
146
+ .verse-selected {
147
+ background: #e5eefb;
148
+ border-radius: 2px;
149
+ }
150
+
145
151
  /* Shared popup content styles */
146
152
  .link-ctx-popup-body {
147
153
  font-family: Georgia, "Times New Roman", serif;
@@ -589,24 +595,54 @@
589
595
  historyStack = [];
590
596
  }
591
597
 
598
+ function findVerseSpans(root, verseNum) {
599
+ var num = String(verseNum);
600
+ // Prefer .verse spans (full verse text) with exact verse number match
601
+ var all = root.querySelectorAll('.verse[data-verse]');
602
+ var matches = [];
603
+ for (var i = 0; i < all.length; i++) {
604
+ var dv = all[i].getAttribute('data-verse');
605
+ var after = dv.split(':').pop();
606
+ if (after === num) matches.push(all[i]);
607
+ }
608
+ if (matches.length) return matches;
609
+ // Fallback: bare data-verse="N" (e.g. sup elements from scrip_html)
610
+ var span = root.querySelector('[data-verse="' + num + '"]');
611
+ return span ? [span] : [];
612
+ }
613
+
592
614
  function applyPopupAnchor(hash) {
593
615
  if (!hash || !popup) return;
594
616
  var id = hash.replace(/^#/, '');
595
617
  try {
596
- var eid = id.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
597
- var target = popup.querySelector('[id="' + eid + '"]');
598
- // For scrip verse anchors like #v15, find by data-verse attribute
599
- if (!target) {
600
- var vm = id.match(/^v(\d+)$/);
601
- if (vm) {
602
- target = popup.querySelector('[data-verse="' + vm[1] + '"]');
603
- // Also match "Book Ch:Verse" format like data-verse="Acts 17:25"
604
- if (!target) target = popup.querySelector('[data-verse$=":' + vm[1] + '"]');
618
+ var body = popup.querySelector('.link-ctx-popup-body');
619
+ if (!body) return;
620
+
621
+ // Verse range: #vN or #vN-M
622
+ var vm = id.match(/^v(\d+)(?:-(\d+))?$/);
623
+ if (vm) {
624
+ var start = parseInt(vm[1], 10);
625
+ var end = vm[2] ? parseInt(vm[2], 10) : start;
626
+ var first = null;
627
+ for (var v = start; v <= end; v++) {
628
+ var spans = findVerseSpans(body, v);
629
+ for (var i = 0; i < spans.length; i++) {
630
+ spans[i].classList.add('verse-selected');
631
+ if (!first) first = spans[i];
632
+ }
633
+ }
634
+ if (first) {
635
+ var bodyTop = body.getBoundingClientRect().top;
636
+ var targetTop = first.getBoundingClientRect().top;
637
+ body.scrollTop += targetTop - bodyTop - 8;
605
638
  }
639
+ return;
606
640
  }
641
+
642
+ // Standard anchor by ID
643
+ var eid = id.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
644
+ var target = popup.querySelector('[id="' + eid + '"]');
607
645
  if (!target) return;
608
- var body = popup.querySelector('.link-ctx-popup-body');
609
- if (!body) return;
610
646
  var bodyTop = body.getBoundingClientRect().top;
611
647
  var targetTop = target.getBoundingClientRect().top;
612
648
  body.scrollTop += targetTop - bodyTop - 8;
@@ -847,4 +883,39 @@
847
883
  })();
848
884
 
849
885
  })();
886
+
887
+ // Full-page verse highlighting from URL hash (#vN or #vN-M)
888
+ (function() {
889
+ var m = window.location.hash.match(/^#v(\d+)(?:-(\d+))?$/);
890
+ if (!m) return;
891
+ var start = parseInt(m[1], 10);
892
+ var end = m[2] ? parseInt(m[2], 10) : start;
893
+ var bookMeta = document.querySelector('meta[name="book"]');
894
+ var chMeta = document.querySelector('meta[name="chapter"]');
895
+ var book = bookMeta && bookMeta.content;
896
+ var ch = chMeta && chMeta.content;
897
+ var first = null;
898
+ for (var v = start; v <= end; v++) {
899
+ var spans;
900
+ if (book && ch) {
901
+ spans = document.querySelectorAll('.verse[data-verse="' + book + ' ' + ch + ':' + v + '"]');
902
+ } else {
903
+ // No meta tags — filter all .verse spans by exact verse number
904
+ var all = document.querySelectorAll('.verse[data-verse]');
905
+ spans = [];
906
+ for (var i = 0; i < all.length; i++) {
907
+ if (all[i].getAttribute('data-verse').split(':').pop() === String(v)) spans.push(all[i]);
908
+ }
909
+ }
910
+ for (var j = 0; j < spans.length; j++) {
911
+ spans[j].classList.add('verse-selected');
912
+ if (!first) first = spans[j];
913
+ }
914
+ }
915
+ if (!first) return;
916
+ var top = first.getBoundingClientRect().top + window.pageYOffset;
917
+ var toolbar = document.querySelector('.toolbar');
918
+ if (toolbar) top -= toolbar.offsetHeight + 4;
919
+ window.scrollTo({ top: top, behavior: 'instant' });
920
+ })();
850
921
  </script>
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.6.3
4
+ version: 0.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Dunn