2021-02-10 15:51:09 +01:00
|
|
|
#![recursion_limit = "128"]
|
2021-11-28 00:36:27 +01:00
|
|
|
#![feature(decl_macro, proc_macro_hygiene)]
|
2021-02-10 15:51:09 +01:00
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
extern crate gettext_macros;
|
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
|
|
|
|
|
|
|
use wasm_bindgen::{prelude::*, JsCast};
|
2021-02-12 10:12:32 +01:00
|
|
|
use web_sys::{console, window, Document, Element, Event, HtmlInputElement, TouchEvent};
|
2021-02-10 15:51:09 +01:00
|
|
|
|
|
|
|
init_i18n!(
|
|
|
|
"plume-front",
|
|
|
|
af,
|
|
|
|
ar,
|
|
|
|
bg,
|
|
|
|
ca,
|
|
|
|
cs,
|
|
|
|
cy,
|
|
|
|
da,
|
|
|
|
de,
|
|
|
|
el,
|
|
|
|
en,
|
|
|
|
eo,
|
|
|
|
es,
|
2022-01-26 14:15:35 +01:00
|
|
|
eu,
|
2021-02-10 15:51:09 +01:00
|
|
|
fa,
|
|
|
|
fi,
|
|
|
|
fr,
|
|
|
|
gl,
|
|
|
|
he,
|
|
|
|
hi,
|
|
|
|
hr,
|
|
|
|
hu,
|
|
|
|
it,
|
|
|
|
ja,
|
|
|
|
ko,
|
|
|
|
nb,
|
|
|
|
nl,
|
|
|
|
no,
|
|
|
|
pl,
|
|
|
|
pt,
|
|
|
|
ro,
|
|
|
|
ru,
|
|
|
|
sat,
|
|
|
|
si,
|
|
|
|
sk,
|
|
|
|
sl,
|
|
|
|
sr,
|
|
|
|
sv,
|
|
|
|
tr,
|
|
|
|
uk,
|
|
|
|
vi,
|
|
|
|
zh
|
|
|
|
);
|
|
|
|
|
2021-02-11 19:19:46 +01:00
|
|
|
mod editor;
|
2021-02-10 17:24:41 +01:00
|
|
|
|
2021-02-10 15:51:09 +01:00
|
|
|
compile_i18n!();
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref CATALOG: gettext::Catalog = {
|
|
|
|
let catalogs = include_i18n!();
|
|
|
|
let lang = window().unwrap().navigator().language().unwrap();
|
2021-11-28 00:36:27 +01:00
|
|
|
let lang = lang.split_once('-').map_or("en", |x| x.0);
|
2021-02-10 15:51:09 +01:00
|
|
|
|
|
|
|
let english_position = catalogs
|
|
|
|
.iter()
|
|
|
|
.position(|(language_code, _)| *language_code == "en")
|
|
|
|
.unwrap();
|
|
|
|
catalogs
|
|
|
|
.iter()
|
|
|
|
.find(|(l, _)| l == &lang)
|
|
|
|
.unwrap_or(&catalogs[english_position])
|
|
|
|
.clone()
|
|
|
|
.1
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[wasm_bindgen(start)]
|
|
|
|
pub fn main() -> Result<(), JsValue> {
|
2021-02-11 19:19:46 +01:00
|
|
|
extern crate console_error_panic_hook;
|
|
|
|
use std::panic;
|
|
|
|
panic::set_hook(Box::new(console_error_panic_hook::hook));
|
|
|
|
|
2021-02-10 15:51:09 +01:00
|
|
|
menu();
|
2021-02-10 17:19:42 +01:00
|
|
|
search();
|
2021-02-11 19:19:46 +01:00
|
|
|
editor::init()
|
2021-11-28 00:36:27 +01:00
|
|
|
.map_err(|e| console::error_1(&format!("Editor error: {:?}", e).into()))
|
2021-02-11 19:19:46 +01:00
|
|
|
.ok();
|
2021-02-10 15:51:09 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Toggle menu on mobile devices
|
|
|
|
///
|
|
|
|
/// It should normally be working fine even without this code
|
|
|
|
/// But :focus-within is not yet supported by Webkit/Blink
|
|
|
|
fn menu() {
|
2021-02-12 10:48:33 +01:00
|
|
|
let document = document();
|
2021-02-12 10:26:05 +01:00
|
|
|
if let Ok(Some(button)) = document.query_selector("#menu a") {
|
2021-02-10 15:51:09 +01:00
|
|
|
if let Some(menu) = document.get_element_by_id("content") {
|
2021-02-10 17:24:41 +01:00
|
|
|
let show_menu = Closure::wrap(Box::new(|_: TouchEvent| {
|
2021-02-12 10:48:33 +01:00
|
|
|
self::document()
|
2021-02-10 15:51:09 +01:00
|
|
|
.get_element_by_id("menu")
|
2021-02-12 10:54:42 +01:00
|
|
|
.map(|menu| {
|
|
|
|
menu.set_attribute("aria-expanded", "true")
|
|
|
|
.map(|_| menu.class_list().add_1("show"))
|
|
|
|
})
|
|
|
|
.unwrap()
|
2021-02-10 15:51:09 +01:00
|
|
|
.unwrap()
|
|
|
|
.unwrap();
|
2021-02-10 17:24:41 +01:00
|
|
|
}) as Box<dyn FnMut(TouchEvent)>);
|
2021-02-10 15:51:09 +01:00
|
|
|
button
|
|
|
|
.add_event_listener_with_callback("touchend", show_menu.as_ref().unchecked_ref())
|
|
|
|
.unwrap();
|
|
|
|
show_menu.forget();
|
|
|
|
|
2021-02-13 15:40:18 +01:00
|
|
|
let close_menu = Closure::wrap(Box::new(|evt: TouchEvent| {
|
|
|
|
if evt
|
|
|
|
.target()
|
|
|
|
.unwrap()
|
|
|
|
.dyn_ref::<Element>()
|
|
|
|
.unwrap()
|
|
|
|
.closest("a")
|
|
|
|
.unwrap()
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2021-02-12 10:48:33 +01:00
|
|
|
self::document()
|
2021-02-10 15:51:09 +01:00
|
|
|
.get_element_by_id("menu")
|
2021-02-12 10:54:42 +01:00
|
|
|
.map(|menu| {
|
|
|
|
menu.set_attribute("aria-expanded", "false")
|
|
|
|
.map(|_| menu.class_list().remove_1("show"))
|
|
|
|
})
|
|
|
|
.unwrap()
|
2021-02-10 15:51:09 +01:00
|
|
|
.unwrap()
|
|
|
|
.unwrap()
|
2021-02-10 17:24:41 +01:00
|
|
|
}) as Box<dyn FnMut(TouchEvent)>);
|
2021-02-10 15:51:09 +01:00
|
|
|
menu.add_event_listener_with_callback("touchend", close_menu.as_ref().unchecked_ref())
|
|
|
|
.unwrap();
|
|
|
|
close_menu.forget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-10 17:19:42 +01:00
|
|
|
|
|
|
|
/// Clear the URL of the search page before submitting request
|
|
|
|
fn search() {
|
2021-02-12 10:48:33 +01:00
|
|
|
if let Some(form) = document().get_element_by_id("form") {
|
2021-02-10 17:24:41 +01:00
|
|
|
let normalize_query = Closure::wrap(Box::new(|_: Event| {
|
2021-02-12 10:48:33 +01:00
|
|
|
document()
|
2021-02-10 17:19:42 +01:00
|
|
|
.query_selector_all("#form input")
|
|
|
|
.map(|inputs| {
|
|
|
|
for i in 0..inputs.length() {
|
|
|
|
let input = inputs.get(i).unwrap();
|
2021-02-10 17:24:41 +01:00
|
|
|
let input = input.dyn_ref::<HtmlInputElement>().unwrap();
|
2021-02-10 17:19:42 +01:00
|
|
|
if input.name().is_empty() {
|
2021-02-10 17:24:41 +01:00
|
|
|
input.set_name(&input.dyn_ref::<Element>().unwrap().id());
|
2021-02-10 17:19:42 +01:00
|
|
|
}
|
|
|
|
if !input.name().is_empty() && input.value().is_empty() {
|
|
|
|
input.set_name("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-02-10 17:24:41 +01:00
|
|
|
}) as Box<dyn FnMut(Event)>);
|
2021-02-10 17:19:42 +01:00
|
|
|
form.add_event_listener_with_callback("submit", normalize_query.as_ref().unchecked_ref())
|
|
|
|
.unwrap();
|
|
|
|
normalize_query.forget();
|
|
|
|
}
|
|
|
|
}
|
2021-02-12 10:12:32 +01:00
|
|
|
|
|
|
|
fn document() -> Document {
|
|
|
|
window().unwrap().document().unwrap()
|
|
|
|
}
|