New editor (#458)
With this PR, when JS is activated and WASM supported, the article editor will be dynamically replaced with `contenteditable`s elements. This makes the editing interface simpler and less like a regular form. It will also allow us to easily add visual formatting with native browser APIs (and to insert images or videos directly). Here is a little demo:  There is still a lot to do, but it is a good first step. Fixes #255
This commit is contained in:
+26
-46
@@ -1,56 +1,36 @@
|
||||
#![recursion_limit="128"]
|
||||
#![feature(decl_macro, proc_macro_hygiene, try_trait)]
|
||||
|
||||
extern crate gettext;
|
||||
#[macro_use]
|
||||
extern crate gettext_macros;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate stdweb;
|
||||
|
||||
use stdweb::{unstable::{TryFrom, TryInto}, web::{*, event::*}};
|
||||
use stdweb::{web::{*, event::*}};
|
||||
|
||||
fn main() {
|
||||
editor_loop();
|
||||
menu();
|
||||
search();
|
||||
init_i18n!("plume-front", en, fr);
|
||||
|
||||
mod editor;
|
||||
|
||||
compile_i18n!();
|
||||
|
||||
lazy_static! {
|
||||
static ref CATALOG: gettext::Catalog = {
|
||||
let catalogs = include_i18n!();
|
||||
let lang = js!{ return navigator.language }.into_string().unwrap();
|
||||
let lang = lang.splitn(2, '-').next().unwrap_or("en");
|
||||
catalogs.iter().find(|(l, _)| l == &lang).unwrap_or(&catalogs[0]).clone().1
|
||||
};
|
||||
}
|
||||
|
||||
/// Auto expands the editor when adding text and count chars
|
||||
fn editor_loop() {
|
||||
match document().query_selector("#plume-editor") {
|
||||
Ok(Some(x)) => HtmlElement::try_from(x).map(|article_content| {
|
||||
let offset = article_content.offset_height() - (article_content.get_bounding_client_rect().get_height() as i32);
|
||||
article_content.add_event_listener(move |_: KeyDownEvent| {
|
||||
let article_content = document().query_selector("#plume-editor").ok();
|
||||
js! {
|
||||
@{&article_content}.style.height = "auto";
|
||||
@{&article_content}.style.height = @{&article_content}.scrollHeight - @{offset} + "px";
|
||||
};
|
||||
window().set_timeout(|| {match document().query_selector("#post-form") {
|
||||
Ok(Some(form)) => HtmlElement::try_from(form).map(|form| {
|
||||
if let Some(len) = form.get_attribute("content-size").and_then(|s| s.parse::<i32>().ok()) {
|
||||
let consumed: i32 = js!{
|
||||
var len = - 1;
|
||||
for(var i = 0; i < @{&form}.length; i++) {
|
||||
if(@{&form}[i].name != "") {
|
||||
len += @{&form}[i].name.length + encodeURIComponent(@{&form}[i].value)
|
||||
.replace(/%20/g, "+")
|
||||
.replace(/%0A/g, "%0D%0A")
|
||||
.replace(new RegExp("[!'*()]", "g"), "XXX") //replace exceptions of encodeURIComponent with placeholder
|
||||
.length + 2;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}.try_into().unwrap_or_default();
|
||||
match document().query_selector("#editor-left") {
|
||||
Ok(Some(e)) => HtmlElement::try_from(e).map(|e| {
|
||||
js!{@{e}.innerText = (@{len-consumed})};
|
||||
}).ok(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
}).ok(),
|
||||
_ => None,
|
||||
};}, 0);
|
||||
});
|
||||
}).ok(),
|
||||
_ => None
|
||||
};
|
||||
fn main() {
|
||||
menu();
|
||||
search();
|
||||
editor::init()
|
||||
.map_err(|e| console!(error, format!("Editor error: {:?}", e))).ok();
|
||||
}
|
||||
|
||||
/// Toggle menu on mobile device
|
||||
|
||||
Reference in New Issue
Block a user