File size: 6,480 Bytes
f0b6424 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
from .utils import GParse_Paper, Get_Bibliography
from bs4 import BeautifulSoup
import solara
from pathlib import Path
HERE = Path(__file__).parent
app_style = (HERE / "style.css").read_text()
def Get_HTMLTop(title):
# Top part of HTML
html_top = f"""
<h1>{title}</h1>
<span typeof="schema:Person" resource="http://orcid.org/0000-0003-1279-3709">
</span>
"""
return html_top
def Get_Controls():
controls="""
<label for="textSize">Text Size: </label>
<select id="textSize" name="textSize" onchange="adjustTextSize(this.value)">
<option value="10">10px</option>
<option value="12">12px</option>
<option value="14">14px</option>
<option value="16" selected>16px</option>
<option value="18">18px</option>
<option value="20">20px</option>
<option value="24">24px</option>
<option value="28">28px</option>
<option value="32">32px</option>
<option value="36">36px</option>
<option value="40">40px</option>
<option value="44">44px</option>
<option value="48">48px</option>
<option value="50">50px</option>
</select>
<script>
function adjustTextSize(size) {
const baseSize = parseInt(size);
document.body.style.fontSize = baseSize + 'px';
}
</script>
<script>
function openDialog(event, dialogId) {
var dialog = document.getElementById(dialogId);
var rect = event.target.getBoundingClientRect();
dialog.style.top = rect.top + window.scrollY + 'px';
dialog.style.left = rect.left + window.scrollX + 'px';
dialog.style.display = 'block';
// Add an event listener to close the dialog when clicking outside of it
document.addEventListener('click', function(event) {
var isClickInside = dialog.contains(event.target);
var isClickOnText = event.target.classList.contains('text-area');
if (!isClickInside && !isClickOnText) {
closeDialog(dialogId);
}
}, { once: true });
}
function closeDialog(dialogId) {
document.getElementById(dialogId).style.display = 'none';
}
</script>
"""
return Controls
def Get_Sections(soup):
# Generate sections from divs
sections_content = ""
sections_list = []
raw_text=""
bib = Get_Bibliography(soup)
citation_modals = []
for div in soup.find_all("div"):
header = div.find("head")
if header is not None:
section_number = header.get('n', "")
section_id = header.text.replace(" ", "_")
sections_list.append({'num': normalize_section(section_number), 'text': section_id})
sections_content += f"<section id='{section_id}'>"
sections_content += f"<h2>{section_number} {header.text}</h2>"
else:
sections_content += f"<section id=''>"
for i,paragraph in enumerate(div.find_all("p")):
new_paragraph = ""
for ii,element in enumerate(paragraph.contents):
if isinstance(element, NavigableString):
new_paragraph += element
elif isinstance(element, Tag) and element.name == "ref" and element.get("target")!=None:
ref_id = element.get("target").lstrip("#")
if ref_id in bib.keys():
citation = f"""<span class="text-area" onclick="openDialog(event, '{ref_id}')">{element.text}</span>"""
new_paragraph += citation
cit_info = bib[ref_id]
citation_modals.append(f"""<div id="{ref_id}" class="dialog">
<b>{element.text}</b><br>
<b>Title:</b> {cit_info['title']}<br>
<b>Authors:</b> {", ".join(cit_info['authors'])}<br>
<b>Year:</b> {cit_info['year']}<br>
<b>Journal:</b> {cit_info['journal']}<br>
<b>DOI:</b> <a href="https://doi.org/{cit_info['doi']}">{cit_info['doi']} </a><br>
<button class="close-button" onclick="closeDialog('{ref_id}')">Close</button>
</div>""")
else:
new_paragraph += element.text
sections_content += f"<p>{new_paragraph}</p>"
raw_text += "\n" + paragraph.text
sections_content += "</section>"
return sections_list, sections_content
def Get_Navigation(controls,):
# Generate navigation for sections
navigation = "<div class='sticky-content' style='max-height: 100%; overflow-y: auto;'>" + controls + " <h2> Navigation </h2>"
for section in sections_list:
no_tabs = section['num'].count(".")
if no_tabs>0:
left = str(20*no_tabs)+"px" # Adjust the multiplier for desired tab width
else:
left= "0px"
navigation += f'<p style="margin-left: {left}; font-size: 10px;"><a href="#{section["text"]}">{section["num"]} {section["text"]}</a></p>'
navigation += "</div>"
def Get_Article_HTML(pdf):
article = GParse_Paper(pdf)
soup = BeautifulSoup(article, "xml")
html = Get_Article_HTML(soup)
try:
document_title = soup.find("fileDesc").find("title").text
except:
document_title = ""
html_top = Get_HTMLTop(document_title)
sections_list, sections_content = Get_Sections(soup)
controls = Get_Controls()
navigation = Get_Navigation(controls, sections_list)
# Combine all parts into final HTML
html = style + "<body><article>" + html_top + sections_content + navigation + "n".join(citation_modals)+"</body></article>"
with open("article_demo.html","w") as f:
f.write(html)
return html
html = solara.reactive("")
@solara.component
def Page():
solara.Style(app_style)
def on_file():
html.value = Get_Article_HTML(f["file_obj"].read())
dropzone = solara.FileDrop(label="Drag and drop article pdf", on_file=on_file, lazy=True)
solara.HTML(html)
|