aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/format.rs40
-rw-r--r--src/server.rs79
-rw-r--r--static/style.css4
3 files changed, 102 insertions, 21 deletions
diff --git a/src/format.rs b/src/format.rs
index 801611d..b9da487 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -156,7 +156,22 @@ pub fn format_batch_to<'a>(
buf,
r#"<p><strong>Extra examples (reading practice)</strong></p>"#
)?;
- // TODO
+ writeln!(
+ buf,
+ r#"<form method="POST" action="gen.html">
+ <p>practice levels<p>
+ <p><select name="first_level" value="0">
+ "#
+ )?;
+ for val in 0..=i {
+ write!(buf, r#"<option value="{}">{:03}</option>"#, val, val)?;
+ }
+ writeln!(
+ buf,
+ r#"</select> - <input type="hidden" name="last_level" value="{}" />{:03}</p>
+ <p><input type="submit" value="practice random sentences" /></p></form>"#,
+ i, i
+ )?;
writeln!(buf, "<hr />")?;
writeln!(buf, "<p>\(≧▽≦)/</p>")?;
@@ -266,6 +281,29 @@ pub fn format_index_to(
writeln!(buf, "<hr />")?;
+ writeln!(buf, r#"<p><strong>Extra reading practice</strong></p>"#)?;
+ writeln!(
+ buf,
+ r#"<form method="POST" action="gen.html">
+ <p>practice levels<p>
+ <p><select name="first_level" value="0">
+ "#
+ )?;
+ for val in 0..batches.len() {
+ write!(buf, r#"<option value="{}">{:03}</option>"#, val, val)?;
+ }
+ writeln!(buf, r#"</select> - <select name="last_level" value="0">"#)?;
+ for val in 0..batches.len() {
+ write!(buf, r#"<option value="{}">{:03}</option>"#, val, val)?;
+ }
+ writeln!(
+ buf,
+ r#"</select></p>
+ <p><input type="submit" value="practice random sentences" /></p></form>"#
+ )?;
+
+ writeln!(buf, "<hr />")?;
+
let all_chars = Charset::from_iter(
batches
.iter()
diff --git a/src/server.rs b/src/server.rs
index c90ee40..774cff4 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,16 +1,16 @@
use std::fs;
-use std::io::Write;
-use futures::stream::TryStreamExt;
use anyhow::{anyhow, Result};
+use futures::stream::TryStreamExt;
use rand::prelude::*;
+use serde::Deserialize;
use http_types::mime;
use tide::Request;
use crate::datafiles::*;
-use crate::format::*;
use crate::example::*;
+use crate::format::*;
use crate::*;
pub async fn server_main() -> tide::Result<()> {
@@ -85,7 +85,7 @@ pub async fn server_main() -> tide::Result<()> {
app.at("/script.js").serve_file("static/script.js")?;
app.at("/jquery.js").serve_file("static/jquery.js")?;
app.at("/about.html").get(about_page);
- app.at("/ex/:start/:end").get(gen_examples_page);
+ app.at("/gen.html").post(gen_examples_page);
app.at("/:batch").get(batch_page);
// ---- serve actual http ----
@@ -152,9 +152,16 @@ async fn batch_page(req: Request<State>) -> tide::Result {
.build())
}
-async fn gen_examples_page(req: Request<State>) -> tide::Result {
- let first_level: usize = req.param("start")?.parse()?;
- let last_level: usize = req.param("end")?.parse()?;
+#[derive(Deserialize)]
+struct GenParam {
+ first_level: usize,
+ last_level: usize,
+}
+
+async fn gen_examples_page(mut req: Request<State>) -> tide::Result {
+ let param: GenParam = req.body_form().await?;
+ let first_level = std::cmp::min(param.first_level, param.last_level);
+ let last_level = std::cmp::max(param.first_level, param.last_level);
let allowed_chars = Charset::from_iter(
req.state()
@@ -179,15 +186,16 @@ async fn gen_examples_page(req: Request<State>) -> tide::Result {
let state: State = req.state();
std::thread::spawn(move || {
- tx.send_blocking(Ok(format!(r#"
+ tx.send_blocking(Ok(format!(
+ r#"
<!DOCTYPE html>
<html>
<head>
<meta charset=\"UTF-8\" />
<title>{:03} - {:03} practice</title>
- <link rel="stylesheet" type="text/css" href="/style.css" />
- <script src="/jquery.js"></script>
- <script src="/script.js"></script>
+ <link rel="stylesheet" type="text/css" href="style.css" />
+ <script src="jquery.js"></script>
+ <script src="script.js"></script>
</head>
<body>
<div class="batch_page">
@@ -206,7 +214,10 @@ async fn gen_examples_page(req: Request<State>) -> tide::Result {
</div>
</div>
</body>
- "#, first_level, last_level, first_level, last_level).into_bytes()))?;
+ "#,
+ first_level, last_level, first_level, last_level
+ )
+ .into_bytes()))?;
gen_examples(state, &allowed_chars, &needed_chars, 50, |mut ex| {
ex.gen_furigana(&req.state().jmdict_idx, &req.state().furigana_overrides);
@@ -221,12 +232,18 @@ async fn gen_examples_page(req: Request<State>) -> tide::Result {
if let Some(ents) = state.jmdict_idx.get(keb) {
for ent in ents.iter() {
let ent_r_ele = ent.children().find(|x| x.has_tag_name("r_ele")).unwrap();
- let ent_reb = ent_r_ele.children().find(|x| x.has_tag_name("reb")).unwrap();
+ let ent_reb = ent_r_ele
+ .children()
+ .find(|x| x.has_tag_name("reb"))
+ .unwrap();
let ent_reb = ent_reb.text().unwrap().trim();
if reb.map(|x| x != ent_reb).unwrap_or(false) {
continue;
}
- expl += &format!(r#"<tr><td style="word-break: keep-all">&nbsp;&nbsp;<span class="tab_large font_ja">{}</span>&nbsp;&nbsp;</td><td width="50%">"#, keb);
+ expl += &format!(
+ r#"<tr><td style="word-break: keep-all">&nbsp;&nbsp;<span class="tab_large font_ja">{}</span>&nbsp;&nbsp;</td><td width="50%">"#,
+ keb
+ );
for sense in ent.children().filter(|x| x.has_tag_name("sense")) {
if let Some(s) = sense.children().find(|x| x.has_tag_name("gloss")) {
@@ -236,7 +253,10 @@ async fn gen_examples_page(req: Request<State>) -> tide::Result {
expl += s.text().unwrap().trim();
}
}
- expl += &format!(r#"</td><td style="word-break: keep-all" class="tab_large font_ja">{}</td></tr>"#, ent_reb);
+ expl += &format!(
+ r#"</td><td style="word-break: keep-all" class="tab_large font_ja">{}</td></tr>"#,
+ ent_reb
+ );
}
}
}
@@ -247,20 +267,28 @@ async fn gen_examples_page(req: Request<State>) -> tide::Result {
"furi": ex.furigana_markup(),
"vocab": expl + "</table>",
});
- tx.send_blocking(Ok(format!("<script> add_example({}); </script>\n", serde_json::to_string(&item)?).into_bytes()))?;
+ tx.send_blocking(Ok(format!(
+ "<script> add_example({}); </script>\n",
+ serde_json::to_string(&item)?
+ )
+ .into_bytes()))?;
Ok(())
})?;
tx.send_blocking(Ok(br#"
</body>
</html>
- "#.to_vec()))?;
+ "#
+ .to_vec()))?;
Ok::<_, anyhow::Error>(())
});
Ok(tide::Response::builder(200)
- .body(tide::Body::from_reader(Box::pin(rx).into_async_read(), None))
+ .body(tide::Body::from_reader(
+ Box::pin(rx).into_async_read(),
+ None,
+ ))
.content_type(mime::HTML)
.build())
}
@@ -284,7 +312,9 @@ fn gen_examples<F>(
count: usize,
mut callback: F,
) -> Result<()>
-where F: FnMut(Example) -> Result<()> {
+where
+ F: FnMut(Example) -> Result<()>,
+{
let mut rng = thread_rng();
let mut generated = 0;
@@ -292,7 +322,16 @@ where F: FnMut(Example) -> Result<()> {
.examples
.iter()
.filter(|x| x.chars.diff(&allowed_chars).is_empty() && x.chars.intersects(&needed_chars))
- .map(|ex| (ex, *ex.chars.iter().filter_map(|x| data.example_freq.get(&x)).min().unwrap()))
+ .map(|ex| {
+ (
+ ex,
+ *ex.chars
+ .iter()
+ .filter_map(|x| data.example_freq.get(&x))
+ .min()
+ .unwrap(),
+ )
+ })
.collect::<Vec<_>>();
let mut remaining_needed = needed_chars.clone();
diff --git a/static/style.css b/static/style.css
index c09e15b..fbe8e7d 100644
--- a/static/style.css
+++ b/static/style.css
@@ -171,3 +171,7 @@ details .chars {
#gen_section.gen_hidden #gen_ex_display rt {
visibility: hidden;
}
+
+form p {
+ text-align: center;
+}