Prototype for a WYSIWYG editor
We use pulldown-cmark in plume-front too now, but instead of using the provided HTML renderer, we use a custom DOM renderer, which let us use contenteditable only where we want, and which will allow us to add event listeners to provide a good contextual edition experience. Also removed the character counter, as the API limits are almost unreachable.
This commit is contained in:
parent
3669a0097d
commit
bce806ac63
40
Cargo.lock
generated
40
Cargo.lock
generated
@ -243,7 +243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.0.4"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -370,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -382,7 +382,7 @@ name = "cloudabi"
|
|||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -659,7 +659,7 @@ name = "devise_core"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -670,7 +670,7 @@ name = "diesel"
|
|||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -923,7 +923,7 @@ name = "fsevent"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -953,7 +953,7 @@ name = "fuchsia-zircon"
|
|||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1236,7 +1236,7 @@ name = "inotify"
|
|||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -1630,7 +1630,7 @@ name = "nix"
|
|||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1656,7 +1656,7 @@ name = "notify"
|
|||||||
version = "4.0.11"
|
version = "4.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"filetime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"filetime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1722,7 +1722,7 @@ name = "openssl"
|
|||||||
version = "0.10.22"
|
version = "0.10.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1966,6 +1966,7 @@ dependencies = [
|
|||||||
"gettext-utils 0.1.0 (git+https://github.com/Plume-org/gettext-macros/?rev=a7c605f7edd6bfbfbfe7778026bfefd88d82db10)",
|
"gettext-utils 0.1.0 (git+https://github.com/Plume-org/gettext-macros/?rev=a7c605f7edd6bfbfbfe7778026bfefd88d82db10)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"plume-api 0.3.0",
|
"plume-api 0.3.0",
|
||||||
|
"pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"stdweb 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"stdweb 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -2082,7 +2083,17 @@ name = "pulldown-cmark"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2686,7 +2697,7 @@ name = "shrinkwraprs"
|
|||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -3536,7 +3547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
||||||
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
|
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||||
"checksum bitpacking 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "667f3f518358b2cf64891b46a6dd2eb794e9f80d39f7eb5974f4784bcda9a61b"
|
"checksum bitpacking 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "667f3f518358b2cf64891b46a6dd2eb794e9f80d39f7eb5974f4784bcda9a61b"
|
||||||
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
||||||
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
|
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
|
||||||
@ -3730,6 +3741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||||
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
||||||
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
|
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
|
||||||
|
"checksum pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "77043da1282374688ee212dc44b3f37ff929431de9c9adc3053bd3cee5630357"
|
||||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||||
"checksum quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8065cbb01701c11cc195cde85cbf39d1c6a80705b67a157ebb3042e0e5777f"
|
"checksum quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8065cbb01701c11cc195cde85cbf39d1c6a80705b67a157ebb3042e0e5777f"
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
|
@ -12,3 +12,7 @@ gettext-utils = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a
|
|||||||
lazy_static = "1.3"
|
lazy_static = "1.3"
|
||||||
plume-api = { path = "../plume-api" }
|
plume-api = { path = "../plume-api" }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
[dependencies.pulldown-cmark]
|
||||||
|
default-features = false
|
||||||
|
version = "0.5"
|
||||||
|
@ -1,15 +1,180 @@
|
|||||||
|
use pulldown_cmark::{Event, Options, Parser, Tag};
|
||||||
use stdweb::{
|
use stdweb::{
|
||||||
unstable::{TryFrom, TryInto},
|
unstable::{TryFrom, TryInto},
|
||||||
web::{event::*, html_element::*, *},
|
web::{event::*, html_element::*, *},
|
||||||
};
|
};
|
||||||
use CATALOG;
|
use CATALOG;
|
||||||
|
|
||||||
macro_rules! mv {
|
fn from_md(md: &str) {
|
||||||
( $( $var:ident ),* => $exp:expr ) => {
|
let md_parser = Parser::new_ext(md, Options::all());
|
||||||
{
|
md_parser.fold(
|
||||||
$( let $var = $var.clone(); )*
|
document().get_element_by_id("editor-main").unwrap(),
|
||||||
$exp
|
|last_elt, event| {
|
||||||
|
match event {
|
||||||
|
Event::Start(tag) => {
|
||||||
|
let new = match tag {
|
||||||
|
Tag::Paragraph => document().create_element("p").unwrap(),
|
||||||
|
Tag::Rule => document().create_element("hr").unwrap(),
|
||||||
|
Tag::Header(level) => {
|
||||||
|
document().create_element(&format!("h{}", level)).unwrap()
|
||||||
|
}
|
||||||
|
Tag::BlockQuote => document().create_element("blockquote").unwrap(),
|
||||||
|
Tag::CodeBlock(code) => {
|
||||||
|
let pre = document().create_element("pre").unwrap();
|
||||||
|
let code_elt = document().create_element("code").unwrap();
|
||||||
|
code_elt.append_child(&document().create_text_node(&code));
|
||||||
|
pre.append_child(&code_elt);
|
||||||
|
pre
|
||||||
|
}
|
||||||
|
Tag::List(None) => document().create_element("ul").unwrap(),
|
||||||
|
Tag::List(Some(_start_index)) => document().create_element("ol").unwrap(), // TODO: handle start_index
|
||||||
|
Tag::Item => document().create_element("li").unwrap(),
|
||||||
|
Tag::FootnoteDefinition(def) => {
|
||||||
|
let note = document().create_element("div").unwrap();
|
||||||
|
note.class_list().add("footnote");
|
||||||
|
note.append_child(&document().create_text_node(&def));
|
||||||
|
note
|
||||||
|
}
|
||||||
|
Tag::HtmlBlock => document().create_element("div").unwrap(),
|
||||||
|
Tag::Table(_alignements) => document().create_element("table").unwrap(), // TODO: handle alignements
|
||||||
|
Tag::TableHead => document().create_element("th").unwrap(),
|
||||||
|
Tag::TableRow => document().create_element("tr").unwrap(),
|
||||||
|
Tag::TableCell => document().create_element("td").unwrap(),
|
||||||
|
Tag::Emphasis => document().create_element("em").unwrap(),
|
||||||
|
Tag::Strong => document().create_element("strong").unwrap(),
|
||||||
|
Tag::Strikethrough => document().create_element("s").unwrap(),
|
||||||
|
Tag::Link(_link_type, url, text) => {
|
||||||
|
let url: &str = &url;
|
||||||
|
let text: &str = &text;
|
||||||
|
let link = document().create_element("a").unwrap();
|
||||||
|
js! {
|
||||||
|
@{&link}.href = @{url};
|
||||||
|
@{&link}.title = @{text};
|
||||||
|
};
|
||||||
|
link
|
||||||
|
}
|
||||||
|
Tag::Image(_link_type, url, text) => {
|
||||||
|
let url: &str = &url;
|
||||||
|
let text: &str = &text;
|
||||||
|
let img = document().create_element("img").unwrap();
|
||||||
|
js! {
|
||||||
|
@{&img}.src = @{url};
|
||||||
|
@{&img}.title = @{text};
|
||||||
|
@{&img}.alt = @{text};
|
||||||
|
};
|
||||||
|
img
|
||||||
|
}
|
||||||
|
};
|
||||||
|
last_elt.append_child(&new);
|
||||||
|
new
|
||||||
|
}
|
||||||
|
Event::End(_) => last_elt.parent_element().unwrap(),
|
||||||
|
Event::Text(text) => {
|
||||||
|
let node = document().create_text_node(&text);
|
||||||
|
last_elt.append_child(&node);
|
||||||
|
last_elt
|
||||||
|
}
|
||||||
|
Event::Code(code) => {
|
||||||
|
let elt = document().create_element("code").unwrap();
|
||||||
|
let content = document().create_text_node(&code);
|
||||||
|
elt.append_child(&content);
|
||||||
|
last_elt.append_child(&elt);
|
||||||
|
last_elt
|
||||||
|
}
|
||||||
|
Event::Html(html) => {
|
||||||
|
// TODO: sanitize it?
|
||||||
|
last_elt.set_attribute("innerHtml", &html);
|
||||||
|
last_elt
|
||||||
|
}
|
||||||
|
Event::InlineHtml(html) => {
|
||||||
|
let elt = document().create_element("span").unwrap();
|
||||||
|
elt.set_attribute("innerHtml", &html);
|
||||||
|
last_elt.append_child(&elt);
|
||||||
|
last_elt
|
||||||
|
}
|
||||||
|
Event::FootnoteReference(reference) => {
|
||||||
|
last_elt // TODO
|
||||||
|
}
|
||||||
|
Event::SoftBreak => {
|
||||||
|
last_elt.append_child(&document().create_element("br").unwrap());
|
||||||
|
last_elt
|
||||||
|
}
|
||||||
|
Event::HardBreak => {
|
||||||
|
last_elt // TODO
|
||||||
|
}
|
||||||
|
Event::TaskListMarker(done) => {
|
||||||
|
last_elt // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_md() -> String {
|
||||||
|
let root = document().get_element_by_id("editor-main").unwrap();
|
||||||
|
fold_children(&root).join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_children(elt: &Element) -> Vec<String> {
|
||||||
|
elt.child_nodes().iter().fold(vec![], |mut blocks, node| {
|
||||||
|
blocks.push(html_to_md(&node));
|
||||||
|
blocks
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn html_to_md(node: &Node) -> String {
|
||||||
|
console!(log, node);
|
||||||
|
if let Ok(elt) = Element::try_from(node.clone()) {
|
||||||
|
console!(log, elt.node_name().to_lowercase());
|
||||||
|
match elt.node_name().to_lowercase().as_ref() {
|
||||||
|
"hr" => "---".into(),
|
||||||
|
"h1" => format!("# {}\n\n", fold_children(&elt).join("")),
|
||||||
|
"h2" => format!("## {}\n\n", fold_children(&elt).join("")),
|
||||||
|
"h3" => format!("### {}\n\n", fold_children(&elt).join("")),
|
||||||
|
"h4" => format!("#### {}\n\n", fold_children(&elt).join("")),
|
||||||
|
"h5" => format!("##### {}\n\n", fold_children(&elt).join("")),
|
||||||
|
"h6" => format!("###### {}\n\n", fold_children(&elt).join("")),
|
||||||
|
"blockquote" => format!("> {}\n\n", fold_children(&elt).join("> ")),
|
||||||
|
"pre" => format!("```\n{}\n```\n\n", node.text_content().unwrap_or_default()),
|
||||||
|
"li" => match elt
|
||||||
|
.parent_element()
|
||||||
|
.unwrap()
|
||||||
|
.node_name()
|
||||||
|
.to_lowercase()
|
||||||
|
.as_ref()
|
||||||
|
{
|
||||||
|
"ol" => format!(
|
||||||
|
"{}. {}\n",
|
||||||
|
elt.parent_element()
|
||||||
|
.unwrap()
|
||||||
|
.child_nodes()
|
||||||
|
.iter()
|
||||||
|
.position(|n| Element::try_from(n).unwrap() == elt)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
fold_children(&elt).join(""),
|
||||||
|
),
|
||||||
|
_ => format!("- {}\n", fold_children(&elt).join("")),
|
||||||
|
},
|
||||||
|
"em" => format!("_{}_", fold_children(&elt).join("")),
|
||||||
|
"strong" => format!("**{}**", fold_children(&elt).join("")),
|
||||||
|
"s" => format!("~~{}~~", fold_children(&elt).join("")),
|
||||||
|
"a" => format!(
|
||||||
|
"[{}]({})",
|
||||||
|
fold_children(&elt).join(""),
|
||||||
|
String::try_from(js! { return @{&elt}.href }).unwrap()
|
||||||
|
),
|
||||||
|
"img" => format!(
|
||||||
|
"![{}]({})",
|
||||||
|
String::try_from(js! { return @{&elt}.alt }).unwrap(),
|
||||||
|
String::try_from(js! { return @{&elt}.src }).unwrap()
|
||||||
|
),
|
||||||
|
other => {
|
||||||
|
console!(log, "Warning: unhandled element:", other);
|
||||||
|
String::new()
|
||||||
|
} // TODO: refs, tables, raw html
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
node.text_content().unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,27 +281,16 @@ fn init_editor() -> Result<(), EditorError> {
|
|||||||
// And pre-fill the new editor with this values
|
// And pre-fill the new editor with this values
|
||||||
let title = document().get_element_by_id("editor-title")?;
|
let title = document().get_element_by_id("editor-title")?;
|
||||||
let subtitle = document().get_element_by_id("editor-subtitle")?;
|
let subtitle = document().get_element_by_id("editor-subtitle")?;
|
||||||
let content = document().get_element_by_id("editor-default-paragraph")?;
|
let source = get_elt_value("editor-content");
|
||||||
|
|
||||||
|
from_md(&source);
|
||||||
|
|
||||||
title.add_event_listener(no_return);
|
title.add_event_listener(no_return);
|
||||||
subtitle.add_event_listener(no_return);
|
subtitle.add_event_listener(no_return);
|
||||||
|
|
||||||
filter_paste(&title);
|
filter_paste(&title);
|
||||||
filter_paste(&subtitle);
|
filter_paste(&subtitle);
|
||||||
filter_paste(&content);
|
// TODO: filter_paste(&content);
|
||||||
|
|
||||||
// character counter
|
|
||||||
content.add_event_listener(mv!(content => move |_: KeyDownEvent| {
|
|
||||||
window().set_timeout(mv!(content => move || {
|
|
||||||
if let Some(e) = document().get_element_by_id("char-count") {
|
|
||||||
let count = chars_left("#plume-fallback-editor", &content).unwrap_or_default();
|
|
||||||
let text = i18n!(CATALOG, "Around {} characters left"; count);
|
|
||||||
HtmlElement::try_from(e).map(|e| {
|
|
||||||
js!{@{e}.innerText = @{text}};
|
|
||||||
}).ok();
|
|
||||||
};
|
|
||||||
}), 0);
|
|
||||||
}));
|
|
||||||
|
|
||||||
document()
|
document()
|
||||||
.get_element_by_id("publish")?
|
.get_element_by_id("publish")?
|
||||||
@ -224,6 +378,7 @@ fn save(is_draft: bool) {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
console!(log, to_md());
|
||||||
let data = plume_api::posts::NewPostData {
|
let data = plume_api::posts::NewPostData {
|
||||||
title: HtmlElement::try_from(document().get_element_by_id("editor-title").unwrap())
|
title: HtmlElement::try_from(document().get_element_by_id("editor-title").unwrap())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -231,13 +386,7 @@ fn save(is_draft: bool) {
|
|||||||
subtitle: document()
|
subtitle: document()
|
||||||
.get_element_by_id("editor-subtitle")
|
.get_element_by_id("editor-subtitle")
|
||||||
.map(|s| HtmlElement::try_from(s).unwrap().inner_text()),
|
.map(|s| HtmlElement::try_from(s).unwrap().inner_text()),
|
||||||
source: HtmlElement::try_from(
|
source: to_md(),
|
||||||
document()
|
|
||||||
.get_element_by_id("editor-default-paragraph")
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.inner_text(),
|
|
||||||
author: String::new(), // it is ignored anyway (TODO: remove it ??)
|
author: String::new(), // it is ignored anyway (TODO: remove it ??)
|
||||||
blog_id: i32::try_from(js! { return window.blog_id }).ok(),
|
blog_id: i32::try_from(js! { return window.blog_id }).ok(),
|
||||||
published: Some(!is_draft),
|
published: Some(!is_draft),
|
||||||
@ -287,30 +436,3 @@ fn show_errors() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chars_left(selector: &str, content: &Element) -> Option<i32> {
|
|
||||||
match document().query_selector(selector) {
|
|
||||||
Ok(Some(form)) => HtmlElement::try_from(form).ok().and_then(|form| {
|
|
||||||
if let Some(len) = form
|
|
||||||
.get_attribute("content-size")
|
|
||||||
.and_then(|s| s.parse::<i32>().ok())
|
|
||||||
{
|
|
||||||
(js! {
|
|
||||||
let x = encodeURIComponent(@{content}.innerHTML)
|
|
||||||
.replace(/%20/g, "+")
|
|
||||||
.replace(/%0A/g, "%0D%0A")
|
|
||||||
.replace(new RegExp("[!'*()]", "g"), "XXX") // replace exceptions of encodeURIComponent with placeholder
|
|
||||||
.length + 2;
|
|
||||||
console.log(x);
|
|
||||||
return x;
|
|
||||||
})
|
|
||||||
.try_into()
|
|
||||||
.map(|c: i32| len - c)
|
|
||||||
.ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -6,6 +6,7 @@ extern crate gettext;
|
|||||||
extern crate gettext_macros;
|
extern crate gettext_macros;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
extern crate pulldown_cmark;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate stdweb;
|
extern crate stdweb;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
@ -411,7 +411,7 @@ main .article-meta {
|
|||||||
margin-top: 110px;
|
margin-top: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#edition-area > *[contenteditable] {
|
#editor-title, #editor-subtitle, #editor-main > * {
|
||||||
padding-left: 18px;
|
padding-left: 18px;
|
||||||
border-left: 2px solid transparent;
|
border-left: 2px solid transparent;
|
||||||
transition: border-left-color 0.1s ease-in;
|
transition: border-left-color 0.1s ease-in;
|
||||||
|
@ -25,12 +25,11 @@
|
|||||||
<div id="plume-editor" style="display: none;" dir="auto">
|
<div id="plume-editor" style="display: none;" dir="auto">
|
||||||
<header>
|
<header>
|
||||||
<a href="#" id="close-editor">@i18n!(ctx.1, "Classic editor (any changes will be lost)")</a>
|
<a href="#" id="close-editor">@i18n!(ctx.1, "Classic editor (any changes will be lost)")</a>
|
||||||
<p id="char-count">@content_len</p>
|
|
||||||
</header>
|
</header>
|
||||||
<article id="edition-area">
|
<article id="edition-area">
|
||||||
<h1 contenteditable id="editor-title" data-placeholder="@i18n!(ctx.1, "Type your title")">@form.title</h1>
|
<h1 contenteditable id="editor-title" data-placeholder="@i18n!(ctx.1, "Type your title")">@form.title</h1>
|
||||||
<h2 contenteditable id="editor-subtitle" data-placeholder="@i18n!(ctx.1, "Type a subtitle or a summary")">@form.subtitle</h2>
|
<h2 contenteditable id="editor-subtitle" data-placeholder="@i18n!(ctx.1, "Type a subtitle or a summary")">@form.subtitle</h2>
|
||||||
<p contenteditable id="editor-default-paragraph" data-placeholder="@i18n!(ctx.1, "Write your article. You can use Markdown.")">@form.content</p>
|
<article contenteditable id="editor-main" data-placeholder="@i18n!(ctx.1, "Write your article here. You can use markdown.")"></article>
|
||||||
</article>
|
</article>
|
||||||
<aside id="plume-editor-aside" style="display: none;">
|
<aside id="plume-editor-aside" style="display: none;">
|
||||||
<div id="options-page">
|
<div id="options-page">
|
||||||
|
Loading…
Reference in New Issue
Block a user