|
@@ -14,7 +14,7 @@ use kuchiki::NodeRef;
|
|
|
|
|
|
fn header(title: &str, css_path: &str) -> String {
|
|
|
format!(
|
|
|
- r#"<!DOCTYPE html>
|
|
|
+ r##"<!DOCTYPE html>
|
|
|
<html>
|
|
|
<head>
|
|
|
<title>{title}</title>
|
|
@@ -23,14 +23,260 @@ fn header(title: &str, css_path: &str) -> String {
|
|
|
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0' />
|
|
|
<link rel='icon' href='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📧</text></svg>'>
|
|
|
<meta name="description" content="{title}"/>
|
|
|
+ <script>
|
|
|
+ let numberingVisible = true;
|
|
|
+ let blankLinesVisible = false;
|
|
|
+
|
|
|
+ function applyNumberingVisibility() {{
|
|
|
+ const purplenumbers = document.querySelectorAll('.purplenumber');
|
|
|
+ purplenumbers.forEach(element => {{
|
|
|
+ element.classList.toggle('transparent', !numberingVisible);
|
|
|
+ }});
|
|
|
+ }}
|
|
|
+
|
|
|
+ function applyBlankLinesVisibility() {{
|
|
|
+ const content = document.getElementById('content');
|
|
|
+
|
|
|
+ if (blankLinesVisible) {{
|
|
|
+ if (window.originalBrElements) {{
|
|
|
+ window.originalBrElements.forEach(br => {{
|
|
|
+ const parent = br.parent;
|
|
|
+ if (parent) {{
|
|
|
+ parent.insertBefore(br.element, parent.children[br.index]);
|
|
|
+ }}
|
|
|
+ }});
|
|
|
+ window.originalBrElements = [];
|
|
|
+ }}
|
|
|
+
|
|
|
+ if (window.originalStyles) {{
|
|
|
+ window.originalStyles.forEach(item => {{
|
|
|
+ item.element.style.marginTop = item.styles.marginTop;
|
|
|
+ item.element.style.marginBottom = item.styles.marginBottom;
|
|
|
+ }});
|
|
|
+ window.originalStyles = [];
|
|
|
+ }}
|
|
|
+ }} else {{
|
|
|
+ const brElements = content.querySelectorAll('br');
|
|
|
+ window.originalBrElements = [];
|
|
|
+ brElements.forEach(br => {{
|
|
|
+ const parent = br.parentNode;
|
|
|
+ const index = Array.prototype.indexOf.call(parent.children, br);
|
|
|
+ window.originalBrElements.push({{element: br, parent, index}});
|
|
|
+ parent.removeChild(br);
|
|
|
+ }});
|
|
|
+
|
|
|
+ const allElements = document.querySelectorAll('*');
|
|
|
+ window.originalStyles = [];
|
|
|
+ allElements.forEach(element => {{
|
|
|
+ window.originalStyles.push({{
|
|
|
+ element: element,
|
|
|
+ styles: {{
|
|
|
+ marginTop: element.style.marginTop,
|
|
|
+ marginBottom: element.style.marginBottom
|
|
|
+ }}
|
|
|
+ }});
|
|
|
+ element.style.marginTop = '0';
|
|
|
+ element.style.marginBottom = '0';
|
|
|
+ }});
|
|
|
+ }}
|
|
|
+ }}
|
|
|
+
|
|
|
+ function showElement(body_id, summary_id) {{
|
|
|
+ const summaries = document.querySelectorAll('.message-meta');
|
|
|
+ const innerElements = document.querySelectorAll('.email-body');
|
|
|
+ const zoom_ins = document.querySelectorAll('.zoom_in');
|
|
|
+ const zoom_outs = document.querySelectorAll('.zoom_out');
|
|
|
+
|
|
|
+ summaries.forEach(summary => {{
|
|
|
+ summary.style.display = 'none';
|
|
|
+ }});
|
|
|
+ innerElements.forEach(element => {{
|
|
|
+ element.style.display = 'none';
|
|
|
+ }});
|
|
|
+
|
|
|
+ zoom_ins.forEach(element => {{
|
|
|
+ element.style.display = 'none';
|
|
|
+ }});
|
|
|
+
|
|
|
+ zoom_outs.forEach(element => {{
|
|
|
+ element.style.display = 'block';
|
|
|
+ }});
|
|
|
+
|
|
|
+ document.getElementById(body_id).style.display = 'block';
|
|
|
+ document.getElementById(summary_id).style.display = 'block';
|
|
|
+
|
|
|
+ window.scrollTo(0, 0);
|
|
|
+ }}
|
|
|
+
|
|
|
+ function showSummaries() {{
|
|
|
+ const summaries = document.querySelectorAll('.message-meta');
|
|
|
+ const innerElements = document.querySelectorAll('.email-body');
|
|
|
+ const zoom_ins = document.querySelectorAll('.zoom_in');
|
|
|
+ const zoom_outs = document.querySelectorAll('.zoom_out');
|
|
|
+
|
|
|
+ summaries.forEach(summary => {{
|
|
|
+ summary.style.display = 'block';
|
|
|
+ }});
|
|
|
+
|
|
|
+ innerElements.forEach(element => {{
|
|
|
+ element.style.display = 'none';
|
|
|
+ }});
|
|
|
+
|
|
|
+ zoom_ins.forEach(element => {{
|
|
|
+ element.style.display = 'block';
|
|
|
+ }});
|
|
|
+
|
|
|
+ zoom_outs.forEach(element => {{
|
|
|
+ element.style.display = 'none';
|
|
|
+ }});
|
|
|
+
|
|
|
+ window.scrollTo(0, 0);
|
|
|
+ }}
|
|
|
+
|
|
|
+ function jumpToItem() {{
|
|
|
+ const id = document.getElementById('textfield').value;
|
|
|
+ if (id) {{
|
|
|
+ window.location.href = '#' + id;
|
|
|
+ }}
|
|
|
+ }}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ function openNewWindow() {{
|
|
|
+ const newWindow = window.open('', '', 'width=250,height=200');
|
|
|
+ const popupContent = `
|
|
|
+ <!DOCTYPE html>
|
|
|
+ <html>
|
|
|
+ <head>
|
|
|
+ <title>Viewspecs</title>
|
|
|
+ <style>
|
|
|
+ .popup-content {{
|
|
|
+ font-family: Arial, sans-serif;
|
|
|
+ font-size: 14px;
|
|
|
+ margin: 20px;
|
|
|
+ }}
|
|
|
+ .popup-content fieldset {{
|
|
|
+ border: 1px solid #000;
|
|
|
+ padding: 10px;
|
|
|
+ }}
|
|
|
+ .popup-content legend {{
|
|
|
+ padding: 0 10px;
|
|
|
+ font-weight: bold;
|
|
|
+ }}
|
|
|
+ .popup-content label {{
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ }}
|
|
|
+ .popup-content input {{
|
|
|
+ margin-right: 5px;
|
|
|
+ }}
|
|
|
+ .accept-button {{
|
|
|
+ margin-top: 10px;
|
|
|
+ padding: 5px 10px;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ }}
|
|
|
+ </style>
|
|
|
+ </head>
|
|
|
+ <body>
|
|
|
+ <div class="popup-content">
|
|
|
+ <fieldset>
|
|
|
+ <legend>Show</legend>
|
|
|
+ <label> Blank lines (y/z)</label>
|
|
|
+ <label> Numbering (m/n)</label>
|
|
|
+ </fieldset>
|
|
|
+ <button class="accept-button" onclick="window.close()">Accept</button>
|
|
|
+ </div>
|
|
|
+ </body>
|
|
|
+ </html>
|
|
|
+ `;
|
|
|
+ newWindow.document.open();
|
|
|
+ newWindow.document.write(popupContent);
|
|
|
+ newWindow.document.close();
|
|
|
+ }}
|
|
|
+
|
|
|
+ document.addEventListener('DOMContentLoaded', function() {{
|
|
|
+ const textfield = document.getElementById('textfield');
|
|
|
+ textfield.addEventListener('keydown', function(event) {{
|
|
|
+ if (event.key === 'Enter') {{
|
|
|
+ jumpToItem();
|
|
|
+ }}
|
|
|
+ }});
|
|
|
+
|
|
|
+ const jumpButton = document.querySelector('input[type="button"][value="Jump Item:"]');
|
|
|
+ jumpButton.addEventListener('click', jumpToItem);
|
|
|
+
|
|
|
+ // Apply stored states on load
|
|
|
+ blankLinesVisible = JSON.parse(localStorage.getItem('blankLinesVisible') || 'true');
|
|
|
+ numberingVisible = JSON.parse(localStorage.getItem('numberingVisible') || 'true');
|
|
|
+ applyBlankLinesVisibility();
|
|
|
+ applyNumberingVisibility();
|
|
|
+
|
|
|
+ document.getElementById('numbering').addEventListener('change', function() {{
|
|
|
+ numberingVisible = this.checked;
|
|
|
+ applyNumberingVisibility();
|
|
|
+ }});
|
|
|
+
|
|
|
+ document.getElementById('blankLines').addEventListener('change', function() {{
|
|
|
+ blankLinesVisible = this.checked;
|
|
|
+ applyBlankLinesVisibility();
|
|
|
+ }});
|
|
|
+ }});
|
|
|
+
|
|
|
+ // Keyboard shortcuts
|
|
|
+ document.addEventListener('keydown', function(event) {{
|
|
|
+ const numberingCheckbox = document.getElementById('numbering');
|
|
|
+ const blankLinesCheckbox = document.getElementById('blankLines');
|
|
|
+
|
|
|
+ if (event.key === 'm') {{
|
|
|
+ numberingVisible = true;
|
|
|
+ if (numberingCheckbox) numberingCheckbox.checked = true;
|
|
|
+ applyNumberingVisibility();
|
|
|
+ }}
|
|
|
+ if (event.key === 'n') {{
|
|
|
+ numberingVisible = false;
|
|
|
+ if (numberingCheckbox) numberingCheckbox.checked = false;
|
|
|
+ applyNumberingVisibility();
|
|
|
+ }}
|
|
|
+ if (event.key === 'y') {{
|
|
|
+ blankLinesVisible = true;
|
|
|
+ if (blankLinesCheckbox) blankLinesCheckbox.checked = true;
|
|
|
+ applyBlankLinesVisibility();
|
|
|
+ }}
|
|
|
+ if (event.key === 'z') {{
|
|
|
+ blankLinesVisible = false;
|
|
|
+ if (blankLinesCheckbox) blankLinesCheckbox.checked = false;
|
|
|
+ applyBlankLinesVisibility();
|
|
|
+ }}
|
|
|
+ }});
|
|
|
+ </script>
|
|
|
</head>
|
|
|
<body>
|
|
|
+ <div id="button-container">
|
|
|
+ <!-- class 2 buttons will appear here -->
|
|
|
+ </div>
|
|
|
+ <button onclick="window.location.href='../../index.html'">Home</button>
|
|
|
+ <input name="" type="button" value="Jump Item:">
|
|
|
+ <input type="text" name="textfield" id="textfield" />
|
|
|
+ <!--dropdown for options-->
|
|
|
+ <div class="dropdown">
|
|
|
+ <button>Options</button>
|
|
|
+ <div class="dropdown-content">
|
|
|
+ <a href="#option1">Class 1</a>
|
|
|
+ <a href="#option2">Class 2</a>
|
|
|
+ <a href="#option3">Turbo Augment</a>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- Viewspecs button -->
|
|
|
+ <button class="viewspecs-button" onclick="openNewWindow()">Viewspecs</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<div>
|
|
|
<b>sort by</b> [<a href='../../authors.html'>author</a>] [<a href='../../dates.html'>dates</a>] [<a href='../../subjects.html'>subjects</a>]
|
|
|
- <button onclick="window.location.href='../../index.html'">Home</button>
|
|
|
</div>
|
|
|
<hr>
|
|
|
- "#
|
|
|
+ "##
|
|
|
)
|
|
|
}
|
|
|
|
|
@@ -39,61 +285,6 @@ const FOOTER: &str = r#"
|
|
|
</html>
|
|
|
"#;
|
|
|
|
|
|
-const JS_SCRIPT_VIEWSPECS: &str = r#"
|
|
|
-<script>
|
|
|
- function showElement(body_id, summary_id){
|
|
|
- const summaries = document.querySelectorAll('.message-meta');
|
|
|
- const innerElements = document.querySelectorAll('.email-body');
|
|
|
- const zoom_ins = document.querySelectorAll('.zoom_in');
|
|
|
- const zoom_outs = document.querySelectorAll('.zoom_out');
|
|
|
-
|
|
|
- summaries.forEach(summary => {
|
|
|
- summary.style.display = 'none';
|
|
|
- });
|
|
|
- innerElements.forEach(element => {
|
|
|
- element.style.display = 'none';
|
|
|
- });
|
|
|
-
|
|
|
- zoom_ins.forEach(element => {
|
|
|
- element.style.display = 'none';
|
|
|
- });
|
|
|
-
|
|
|
- zoom_outs.forEach(element => {
|
|
|
- element.style.display = 'block';
|
|
|
- });
|
|
|
-
|
|
|
- document.getElementById(body_id).style.display = 'block';
|
|
|
- document.getElementById(summary_id).style.display = 'block';
|
|
|
-
|
|
|
- window.scrollTo(0, 0);
|
|
|
- }
|
|
|
-
|
|
|
- function showSummaries() {
|
|
|
- const summaries = document.querySelectorAll('.message-meta');
|
|
|
- const innerElements = document.querySelectorAll('.email-body');
|
|
|
- const zoom_ins = document.querySelectorAll('.zoom_in');
|
|
|
- const zoom_outs = document.querySelectorAll('.zoom_out');
|
|
|
-
|
|
|
- summaries.forEach(summary => {
|
|
|
- summary.style.display = 'block';
|
|
|
- });
|
|
|
-
|
|
|
- innerElements.forEach(element => {
|
|
|
- element.style.display = 'none';
|
|
|
- });
|
|
|
-
|
|
|
- zoom_ins.forEach(element => {
|
|
|
- element.style.display = 'block';
|
|
|
- });
|
|
|
-
|
|
|
- zoom_outs.forEach(element => {
|
|
|
- element.style.display = 'none';
|
|
|
- });
|
|
|
-
|
|
|
- window.scrollTo(0, 0);
|
|
|
- }
|
|
|
-</script>
|
|
|
-"#;
|
|
|
|
|
|
impl Lists {
|
|
|
pub fn to_html(&self) -> String {
|
|
@@ -443,8 +634,7 @@ impl Thread {
|
|
|
message_id_css += 1;
|
|
|
}
|
|
|
|
|
|
- body.push_str(&*format!(r#"</div><hr>{}</body></html>"#, JS_SCRIPT_VIEWSPECS));
|
|
|
- remove_inline_styles_from_body(&body)
|
|
|
+ remove_inline_styles_from_body(&body)
|
|
|
}
|
|
|
}
|
|
|
|