markdownr 0.5.6 → 0.5.7
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 +136 -2
- data/lib/markdown_server/version.rb +1 -1
- data/views/layout.erb +16 -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: e9a74b1e181f0fd5361c73e64a6e00659451cf075e1e41ec4f45c0cee9167e9d
|
|
4
|
+
data.tar.gz: 44b5d07121159a9efadac6ee85bd4528d2490ec419b0752dbe15e1336e94eea2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 866416e07423170e5ec3c84e60da99682bfabb07b09cf1eb74f29e7e74f509c9982ec292641721ec0d054f5361bd6012fc00a34755ab46987c4462e63569926e
|
|
7
|
+
data.tar.gz: 1a18c15a57094d2a5d72670d760d82d1eeca80ab1c694cc550a7ff69e352c6dd9e889840e515b0a40c9e59a9b48e9aa85744d6983f37f33c572b90cdd39c28a8
|
data/lib/markdown_server/app.rb
CHANGED
|
@@ -580,6 +580,133 @@ module MarkdownServer
|
|
|
580
580
|
out.length > 10_000 ? out[0, 10_000] : out
|
|
581
581
|
end
|
|
582
582
|
|
|
583
|
+
def blueletterbible_html(html, url)
|
|
584
|
+
base = "https://www.blueletterbible.org"
|
|
585
|
+
|
|
586
|
+
# ── Word ──────────────────────────────────────────────────────────────
|
|
587
|
+
word = html[/<h6[^>]+class="lexTitle(?:Gk|Hb)"[^>]*>(.*?)<\/h6>/im, 1]
|
|
588
|
+
&.gsub(/<[^>]+>/, "")&.strip || ""
|
|
589
|
+
|
|
590
|
+
# ── Transliteration ───────────────────────────────────────────────────
|
|
591
|
+
transliteration = html[/<div[^>]+id="lexTrans".*?<em>(.*?)<\/em>/im, 1]&.strip || ""
|
|
592
|
+
|
|
593
|
+
# ── Pronunciation + audio ─────────────────────────────────────────────
|
|
594
|
+
pronunciation = html[/class="[^"]*lexicon-pronunc[^"]*"[^>]*>\s*([^\n<]{1,50})/i, 1]&.strip || ""
|
|
595
|
+
data_pronunc = html[/data-pronunc="([a-fA-F0-9]{20,})"/i, 1] || ""
|
|
596
|
+
audio_btn = if data_pronunc.length > 10
|
|
597
|
+
au = "#{base}/lang/lexicon/lexPronouncePlayer.cfm?skin=#{data_pronunc}"
|
|
598
|
+
%(<button onclick="var a=this._a||(this._a=new Audio('#{h(au)}'));a.currentTime=0;a.play();" ) +
|
|
599
|
+
%(style="background:none;border:none;cursor:pointer;padding:0 0 0 4px;font-size:1.1em;vertical-align:middle;" title="Play pronunciation">🔊</button>)
|
|
600
|
+
else
|
|
601
|
+
""
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# ── Part of speech ────────────────────────────────────────────────────
|
|
605
|
+
pos = html[/<div[^>]+id="lexPart".*?small-text-right"[^>]*>(.*?)<\/div>/im, 1]
|
|
606
|
+
&.gsub(/<[^>]+>/, "")&.strip || ""
|
|
607
|
+
|
|
608
|
+
# ── Info table ────────────────────────────────────────────────────────
|
|
609
|
+
info_rows = [
|
|
610
|
+
["Word", h(word)],
|
|
611
|
+
["Transliteration", "<em>#{h(transliteration)}</em>"],
|
|
612
|
+
["Pronunciation", "#{h(pronunciation)}#{audio_btn}"],
|
|
613
|
+
["Part of Speech", h(pos)],
|
|
614
|
+
]
|
|
615
|
+
info_html = %(<table class="blb-table">) +
|
|
616
|
+
info_rows.map { |label, v|
|
|
617
|
+
%(<tr><th class="blb-th">#{h(label)}</th><td>#{v}</td></tr>)
|
|
618
|
+
}.join + "</table>"
|
|
619
|
+
|
|
620
|
+
# ── Inflections ───────────────────────────────────────────────────────
|
|
621
|
+
infl_html = ""
|
|
622
|
+
if (m = html.match(/<div\s[^>]*id="greek-tr-inflections"[^>]*>/im))
|
|
623
|
+
after_infl = html[m.end(0)..]
|
|
624
|
+
stop = after_infl.index(/<div\s[^>]*id="greek-(?:mgnt|lxx)-inflections"/i) || after_infl.length
|
|
625
|
+
infl_section = after_infl[0...stop]
|
|
626
|
+
inflections = []
|
|
627
|
+
infl_section.scan(/<div\s[^>]*class="greekInflection"[^>]*>(.*?)<\/div>\s*<\/div>/im) do |mv|
|
|
628
|
+
chunk = mv[0]
|
|
629
|
+
href = chunk[/href="([^"]+)"/i, 1]
|
|
630
|
+
gk = chunk[/<span[^>]+class="Gk"[^>]*>(.*?)<\/span>/im, 1]&.gsub(/<[^>]+>/, "")&.strip || ""
|
|
631
|
+
freq = chunk[/—\s*(\d+)x<\/a>/i, 1]&.to_i || 0
|
|
632
|
+
next if gk.empty? || freq.zero?
|
|
633
|
+
inflections << { word: gk, freq: freq,
|
|
634
|
+
href: href ? base + href.gsub("&", "&") : nil }
|
|
635
|
+
end
|
|
636
|
+
inflections.sort_by! { |i| -i[:freq] }
|
|
637
|
+
if inflections.any?
|
|
638
|
+
rows = inflections.map { |i|
|
|
639
|
+
link = i[:href] ? %(<a href="#{h(i[:href])}" target="_blank" rel="noopener">#{h(i[:word])}</a>) : h(i[:word])
|
|
640
|
+
%(<tr><td>#{link}</td><td class="blb-right">#{i[:freq]}x</td></tr>)
|
|
641
|
+
}.join
|
|
642
|
+
infl_html = %(<h4 class="blb-heading">Inflections</h4>) +
|
|
643
|
+
%(<table class="blb-table"><thead><tr><th class="blb-th">Form</th>) +
|
|
644
|
+
%(<th class="blb-th blb-right">Count</th></tr></thead><tbody>#{rows}</tbody></table>)
|
|
645
|
+
end
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# ── Biblical Usage ────────────────────────────────────────────────────
|
|
649
|
+
usage_html = ""
|
|
650
|
+
if (um = html.match(/<div[^>]+id="outlineBiblical"[^>]*>/im))
|
|
651
|
+
after_usage = html[um.end(0)..]
|
|
652
|
+
if (inner = after_usage.match(/\A\s*<div>([\s\S]*?)<\/div>\s*<\/div>/im))
|
|
653
|
+
cleaned = inner[1]
|
|
654
|
+
.gsub(/<(\/?)(\w+)[^>]*>/) { "<#{$1}#{$2.downcase}>" }
|
|
655
|
+
.gsub(/[ \t]+/, " ")
|
|
656
|
+
.strip
|
|
657
|
+
usage_html = %(<h4 class="blb-heading">Biblical Usage</h4><div class="blb-usage">#{cleaned}</div>)
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
# ── Concordance ───────────────────────────────────────────────────────
|
|
662
|
+
conc_html = ""
|
|
663
|
+
trans_name = html[/id="bibleTable"[^>]+data-translation="([^"]+)"/i, 1] || ""
|
|
664
|
+
verses = []
|
|
665
|
+
html.split(/<div\s[^>]*id="bVerse_\d+"[^>]*>/).drop(1).each do |chunk|
|
|
666
|
+
cite_href = chunk[/tablet-order-2[^>]*>[\s\S]{0,400}?href="([^"]+)"/im, 1] || ""
|
|
667
|
+
cite = chunk[/tablet-order-2[^>]*>[\s\S]{0,400}?<a[^>]*>(.*?)<\/a>/im, 1]
|
|
668
|
+
&.gsub(/<[^>]+>/, "")&.strip || ""
|
|
669
|
+
|
|
670
|
+
# Process verse HTML: highlight the matched word, strip all Strong's refs
|
|
671
|
+
raw_html = chunk[/class="EngBibleText[^"]*"[^>]*>([\s\S]*?)<\/div>/im, 1] || ""
|
|
672
|
+
raw_html.gsub!(/<img[^>]*>/, "")
|
|
673
|
+
raw_html.gsub!(/<a[^>]*class="hide-for-tablet"[^>]*>[\s\S]*?<\/a>/im, "")
|
|
674
|
+
raw_html.gsub!(/<span[^>]*class="hide-for-tablet"[^>]*>[\s\S]*?<\/span>/im, "")
|
|
675
|
+
verse_html = raw_html.gsub(/<span\s[^>]*class="word-phrase"[^>]*>([\s\S]*?)<\/span>/im) do
|
|
676
|
+
inner = $1
|
|
677
|
+
word = inner.sub(/<sup[\s\S]*/im, "").gsub(/<[^>]+>/, "")
|
|
678
|
+
.gsub(/ /i, " ").strip
|
|
679
|
+
inner.match?(/<sup[^>]*class="[^"]*strongs criteria[^"]*"/i) ?
|
|
680
|
+
%(<span class="blb-match">#{h(word)}</span>) : h(word)
|
|
681
|
+
end
|
|
682
|
+
verse_html.gsub!(/<sup[^>]*>[\s\S]*?<\/sup>/im, "")
|
|
683
|
+
verse_html.gsub!(/<[^>]+>/, "")
|
|
684
|
+
verse_html.gsub!(/ /i, " ")
|
|
685
|
+
verse_html.gsub!(/&#(\d+);/) { [$1.to_i].pack("U") rescue " " }
|
|
686
|
+
verse_html.gsub!(/&#x([\da-f]+);/i) { [$1.to_i(16)].pack("U") rescue " " }
|
|
687
|
+
verse_html.gsub!(/&/, "&").gsub!(/</, "<").gsub!(/>/, ">")
|
|
688
|
+
verse_html.gsub!(/\s+/, " ")
|
|
689
|
+
verse_html.strip!
|
|
690
|
+
# Strip the mobile citation prefix ("Mat 5:17 - ") left by hide-for-tablet removal
|
|
691
|
+
verse_html.sub!(/\A#{Regexp.escape(cite)}\s*-\s*/i, "")
|
|
692
|
+
|
|
693
|
+
next if cite.empty? || verse_html.empty?
|
|
694
|
+
full_href = cite_href.empty? ? nil : (cite_href.start_with?("http") ? cite_href : base + cite_href)
|
|
695
|
+
verses << { cite: cite, verse_html: verse_html, href: full_href }
|
|
696
|
+
end
|
|
697
|
+
if verses.any?
|
|
698
|
+
heading = trans_name.empty? ? "Concordance" : "Concordance (#{h(trans_name)})"
|
|
699
|
+
rows = verses.map { |v|
|
|
700
|
+
link = v[:href] ? %(<a href="#{h(v[:href])}" target="_blank" rel="noopener">#{h(v[:cite])}</a>) : h(v[:cite])
|
|
701
|
+
%(<tr><td class="blb-nowrap">#{link}</td><td>#{v[:verse_html]}</td></tr>)
|
|
702
|
+
}.join
|
|
703
|
+
conc_html = %(<h4 class="blb-heading">#{heading}</h4>) +
|
|
704
|
+
%(<table class="blb-table"><tbody>#{rows}</tbody></table>)
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
info_html + infl_html + usage_html + conc_html
|
|
708
|
+
end
|
|
709
|
+
|
|
583
710
|
def compile_regexes(query)
|
|
584
711
|
words = query.split(/\s+/).reject(&:empty?)
|
|
585
712
|
return nil if words.empty?
|
|
@@ -680,8 +807,15 @@ module MarkdownServer
|
|
|
680
807
|
html = fetch_external_page(url)
|
|
681
808
|
halt 502, '{"error":"fetch failed"}' unless html
|
|
682
809
|
|
|
683
|
-
|
|
684
|
-
|
|
810
|
+
if url.match?(/blueletterbible\.org\/lexicon\//i)
|
|
811
|
+
raw = page_title(html)
|
|
812
|
+
title = raw.match(/^([GH]\d+ - \w+)/i)&.[](1)&.sub(" - ", " – ") ||
|
|
813
|
+
raw.sub(/ [-–] .*/, "").strip
|
|
814
|
+
JSON.dump({ title: title, html: blueletterbible_html(html, url) })
|
|
815
|
+
else
|
|
816
|
+
title = page_title(html).sub(/ [-–] .*/, "").strip
|
|
817
|
+
JSON.dump({ title: title, html: page_html(html, url) })
|
|
818
|
+
end
|
|
685
819
|
end
|
|
686
820
|
|
|
687
821
|
get "/search/?*" do
|
data/views/layout.erb
CHANGED
|
@@ -909,6 +909,22 @@
|
|
|
909
909
|
.link-preview-popup th, .link-preview-popup td { border: 1px solid #ddd; padding: 0.3rem 0.5rem; }
|
|
910
910
|
.link-ctx-popup-body th, .link-preview-popup th { background: #f5f0e4; }
|
|
911
911
|
|
|
912
|
+
/* Blue Letter Bible popup tables */
|
|
913
|
+
.blb-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; margin-bottom: 0.6rem; }
|
|
914
|
+
.blb-table th, .blb-table td { padding: 3px 7px; border: 1px solid #ddd; }
|
|
915
|
+
.blb-th { text-align: left; font-weight: normal; background: #f5f0e4; color: #555; width: 38%; }
|
|
916
|
+
.blb-right { text-align: right; }
|
|
917
|
+
.blb-nowrap { white-space: nowrap; vertical-align: top; }
|
|
918
|
+
.blb-match { color: #b33; font-weight: 600; }
|
|
919
|
+
.blb-heading { font-size: 0.82rem; font-weight: 600; margin: 0.7rem 0 0.25rem; color: #555; text-transform: uppercase; letter-spacing: 0.04em; }
|
|
920
|
+
.blb-usage { font-size: 0.85rem; }
|
|
921
|
+
.blb-usage ol { margin: 0.1rem 0 0.1rem 1.3rem; padding: 0; list-style-type: decimal; }
|
|
922
|
+
.blb-usage ol ol { list-style-type: lower-alpha; }
|
|
923
|
+
.blb-usage ol ol ol { list-style-type: lower-roman; }
|
|
924
|
+
.blb-usage ol ol ol ol { list-style-type: lower-alpha; }
|
|
925
|
+
.blb-usage li { margin-bottom: 0.15rem; }
|
|
926
|
+
.blb-usage p { margin: 0; }
|
|
927
|
+
|
|
912
928
|
/* Footnote tooltips */
|
|
913
929
|
.footnote-tooltip {
|
|
914
930
|
position: absolute;
|