From 9076dbaadcde9388d2377a877f0a74d65e6d94ab Mon Sep 17 00:00:00 2001 From: Baptiste Gelez Date: Fri, 15 Mar 2019 16:06:10 +0100 Subject: [PATCH] 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: ![peek 05-03-2019 16-12](https://user-images.githubusercontent.com/16254623/53815536-1dc05680-3f62-11e9-94d3-b363ed84eb97.gif) There is still a lot to do, but it is a good first step. Fixes #255 --- .gitignore | 3 +- Cargo.lock | 148 +++++++++--------- Cargo.toml | 2 +- build.rs | 1 + plume-front/Cargo.toml | 4 + plume-front/src/editor.rs | 269 +++++++++++++++++++++++++++++++++ plume-front/src/main.rs | 72 ++++----- po/plume-front/en.po | 45 ++++++ po/plume-front/fr.po | 45 ++++++ po/plume-front/plume-front.pot | 45 ++++++ po/plume/ar.po | 6 +- po/plume/de.po | 6 +- po/plume/en.po | 3 + po/plume/es.po | 6 +- po/plume/fr.po | 6 +- po/plume/gl.po | 6 +- po/plume/it.po | 6 +- po/plume/ja.po | 6 +- po/plume/nb.po | 3 + po/plume/pl.po | 6 +- po/plume/plume.pot | 3 + po/plume/pt.po | 6 +- po/plume/ru.po | 6 +- static/css/_article.scss | 55 +++++++ templates/posts/new.rs.html | 16 +- 25 files changed, 618 insertions(+), 156 deletions(-) create mode 100644 plume-front/src/editor.rs create mode 100644 po/plume-front/en.po create mode 100644 po/plume-front/fr.po create mode 100644 po/plume-front/plume-front.pot diff --git a/.gitignore b/.gitignore index 9cc32270..e0d6ad46 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,7 @@ rls **/*.rs.bk rls translations -po/*.po~ -po/plume/*.po~ +*.po~ .env Rocket.toml !.gitkeep diff --git a/Cargo.lock b/Cargo.lock index 5d088062..18f6a9ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "MacTypes-sys" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -145,7 +145,7 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -161,11 +161,11 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "debug-builders 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -176,8 +176,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -188,7 +188,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -332,7 +332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -424,7 +424,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -432,15 +432,15 @@ name = "core-foundation-sys" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crc32fast" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -453,7 +453,7 @@ name = "crossbeam" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -496,7 +496,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -509,7 +509,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -529,7 +529,7 @@ name = "crossbeam-utils" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -771,7 +771,7 @@ name = "encoding_rs" version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -825,8 +825,8 @@ name = "filetime" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -855,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -863,7 +863,7 @@ name = "fsevent-sys" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -946,7 +946,7 @@ dependencies = [ [[package]] name = "gettext-macros" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gettext 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1050,7 +1050,7 @@ name = "hostname" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1171,7 +1171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (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.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1179,7 +1179,7 @@ name = "inotify-sys" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1187,7 +1187,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1196,8 +1196,8 @@ name = "isatty" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1288,7 +1288,7 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.49" +version = "0.2.50" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1298,7 +1298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1332,7 +1332,7 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1380,7 +1380,7 @@ name = "memmap" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1455,7 +1455,7 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1516,7 +1516,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1532,8 +1532,8 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1549,8 +1549,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1579,7 +1579,7 @@ dependencies = [ "fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1613,7 +1613,7 @@ name = "num_cpus" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1627,10 +1627,10 @@ version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1645,7 +1645,7 @@ version = "0.9.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1691,7 +1691,7 @@ name = "parking_lot_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1703,7 +1703,7 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1790,7 +1790,7 @@ dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "gettext 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gettext-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gettext-macros 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "gettext-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "guid-create 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1854,7 +1854,7 @@ dependencies = [ "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1865,6 +1865,10 @@ dependencies = [ name = "plume-front" version = "0.1.0" dependencies = [ + "gettext 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gettext-macros 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gettext-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1887,7 +1891,7 @@ dependencies = [ "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)", "plume-api 0.2.0", "plume-common 0.2.0", - "reqwest 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2016,7 +2020,7 @@ name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2026,7 +2030,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2039,7 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2050,13 +2054,13 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2105,19 +2109,19 @@ name = "rand_jitter" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_os" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2215,7 +2219,7 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2249,7 +2253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2341,7 +2345,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2459,7 +2463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2470,7 +2474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "MacTypes-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2777,8 +2781,8 @@ name = "tempfile" version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2800,7 +2804,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2826,7 +2830,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3156,7 +3160,7 @@ name = "webfinger" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "reqwest 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3277,7 +3281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum canapi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aab4d6d1edcef8bf19b851b7730d3d1a90373c06321a49a984baebe0989c962c" "checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92" "checksum census 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e5c044df9888597e4e96610c916ce9d58c653b67c01b5eac5b7abd7405f4fee4" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum chomp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f74ad218e66339b11fd23f693fb8f1d621e80ba6ac218297be26073365d163d" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" @@ -3288,7 +3292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" -"checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" "checksum crossbeam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d1c92ff2d7a202d592f5a412d75cf421495c913817781c1cb383bf12a77e185f" "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" @@ -3349,7 +3353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum gettext 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4378b8e09fd51cfdb0d48f40929a5c358efeeb62feb458c7d6eab979fae231f4" -"checksum gettext-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e977a8090ecd681d1c54f49ced1fa7cea8edca94e16e597642845c66e4b48aa8" +"checksum gettext-macros 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdeb4255ca6caddbe341fb22fdbe654abb0b797358dfc2c569ed0d5d832ab8e" "checksum gettext-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46dd079379f756f6a1ae74b051813e242893f84fbf6ac898bce827fc77958d70" "checksum guid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e691c64d9b226c7597e29aeb46be753beb8c9eeef96d8c78dfd4d306338a38da" "checksum guid-create 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fcea207bf7a6092166ab590f98fe5dde5a7deed1f1920d98dcac31f80814c40d" @@ -3384,7 +3388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lettre 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)" = "" "checksum lettre_email 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)" = "" "checksum levenshtein_automata 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73a004f877f468548d8d0ac4977456a249d8fabbdb8416c36db163dfc8f2e8ca" -"checksum libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)" = "413f3dfc802c5dc91dc570b05125b6cda9855edfaa9825c9849807876376e70e" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" "checksum libflate 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "54d1ddf9c52870243c5689d7638d888331c1116aa5b398f3ba1acfa7d8758ca1" "checksum libsqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd6457c70bbff456d9fe49deaba35ec47c3e598bf8d7950ff0575ceb7a8a6ad1" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" @@ -3463,7 +3467,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" -"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -3475,7 +3479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rental 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ca24bf9b98e3df0bb359f1bbb8ef993a0093d8432500c5eaf3ae724f30b5f754" "checksum rental-impl 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a269533a9b93bbaa4848260e51b64564cc445d46185979f31974ec703374803a" -"checksum reqwest 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f205a95638627fc0d21c53901671b06f439dc2830311ff11ecdff34ae2d839a8" +"checksum reqwest 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e542d9f077c126af32536b6aacc75bb7325400eab8cd0743543be5d91660780d" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "242154377a85c2a9e036fc31ffc8c200b9e1f22a196e47baa3b57716606ca89d" "checksum rocket_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d907d6d458c859651c1cf4c8fa99b77685082bde0561db6a4600b365058f710" diff --git a/Cargo.toml b/Cargo.toml index 7be8872f..7392b31a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ colored = "1.7" dotenv = "0.13" failure = "0.1" gettext = "0.3" -gettext-macros = "0.3" +gettext-macros = "0.4" gettext-utils = "0.1" guid-create = "0.1" heck = "0.3.0" diff --git a/build.rs b/build.rs index 0d12b7ca..e9ff3876 100644 --- a/build.rs +++ b/build.rs @@ -16,6 +16,7 @@ fn main() { .expect("Error during SCSS compilation") ).expect("Couldn't write CSS output"); + println!("cargo:rerun-if-changed=target/deploy/plume-front.wasm"); copy("target/deploy/plume-front.wasm", "static/plume-front.wasm") .and_then(|_| read_to_string("target/deploy/plume-front.js")) .and_then(|js| write("static/plume-front.js", js.replace("\"plume-front.wasm\"", "\"/static/plume-front.wasm\""))).ok(); diff --git a/plume-front/Cargo.toml b/plume-front/Cargo.toml index ef464ce3..bde4e040 100644 --- a/plume-front/Cargo.toml +++ b/plume-front/Cargo.toml @@ -5,3 +5,7 @@ authors = ["Plume contributors"] [dependencies] stdweb = "0.4" +gettext = "0.3" +gettext-macros = "0.4" +gettext-utils = "0.1" +lazy_static = "1.3" \ No newline at end of file diff --git a/plume-front/src/editor.rs b/plume-front/src/editor.rs new file mode 100644 index 00000000..b3ab5cea --- /dev/null +++ b/plume-front/src/editor.rs @@ -0,0 +1,269 @@ +use stdweb::{unstable::{TryInto, TryFrom}, web::{*, html_element::*, event::*}}; +use CATALOG; + +macro_rules! mv { + ( $( $var:ident ),* => $exp:expr ) => { + { + $( let $var = $var.clone(); )* + $exp + } + } +} + +fn get_elt_value(id: &'static str) -> String { + let elt = document().get_element_by_id(id).unwrap(); + let inp: Result = elt.clone().try_into(); + let textarea: Result = elt.try_into(); + inp.map(|i| i.raw_value()).unwrap_or_else(|_| textarea.unwrap().value()) +} + +fn set_value>(id: &'static str, val: S) { + let elt = document().get_element_by_id(id).unwrap(); + let inp: Result = elt.clone().try_into(); + let textarea: Result = elt.try_into(); + inp.map(|i| i.set_raw_value(val.as_ref())) + .unwrap_or_else(|_| textarea.unwrap().set_value(val.as_ref())) +} + +fn no_return(evt: KeyDownEvent) { + if evt.key() == "Enter" { + evt.prevent_default(); + } +} + +#[derive(Debug)] +pub enum EditorError { + NoneError, + DOMError, + TypeError, +} + +impl From for EditorError { + fn from(_: std::option::NoneError) -> Self { + EditorError::NoneError + } +} +impl From for EditorError { + fn from(_: stdweb::web::error::InvalidCharacterError) -> Self { + EditorError::DOMError + } +} +impl From for EditorError { + fn from(_: stdweb::private::TODO) -> Self { + EditorError::DOMError + } +} +impl From for EditorError { + fn from(_: stdweb::private::ConversionError) -> Self { + EditorError::TypeError + } +} + +fn init_widget( + parent: &Element, + tag: &'static str, + placeholder_text: String, + content: String, + disable_return: bool +) -> Result { + let widget = placeholder(make_editable(tag).try_into()?, &placeholder_text); + if !content.is_empty() { + widget.dataset().insert("edited", "true")?; + } + widget.append_child(&document().create_text_node(&content)); + if disable_return { + widget.add_event_listener(no_return); + } + + parent.append_child(&widget); + // We need to do that to make sure the placeholder is correctly rendered + widget.focus(); + widget.blur(); + + Ok(widget) +} + +pub fn init() -> Result<(), EditorError> { + if let Some(ed) = document().get_element_by_id("plume-editor") { + // Show the editor + js!{ @{&ed}.style.display = "block"; }; + // And hide the HTML-only fallback + let old_ed = document().get_element_by_id("plume-fallback-editor")?; + let old_title = document().get_element_by_id("plume-editor-title")?; + js! { + @{&old_ed}.style.display = "none"; + @{&old_title}.style.display = "none"; + }; + + // Get content from the old editor (when editing an article for instance) + let title_val = get_elt_value("title"); + let subtitle_val = get_elt_value("subtitle"); + let content_val = get_elt_value("editor-content"); + // And pre-fill the new editor with this values + let title = init_widget(&ed, "h1", i18n!(CATALOG, "Title"), title_val, true)?; + let subtitle = init_widget(&ed, "h2", i18n!(CATALOG, "Subtitle or summary"), subtitle_val, true)?; + let content = init_widget(&ed, "article", i18n!(CATALOG, "Write your article here. Markdown is supported."), content_val.clone(), true)?; + js! { @{&content}.innerHTML = @{content_val}; }; + + // 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().get_element_by_id("publish")?.add_event_listener(mv!(title, subtitle, content, old_ed => move |_: ClickEvent| { + let popup = document().get_element_by_id("publish-popup").or_else(|| + init_popup(&title, &subtitle, &content, &old_ed).ok() + ).unwrap(); + let bg = document().get_element_by_id("popup-bg").or_else(|| + init_popup_bg().ok() + ).unwrap(); + + popup.class_list().add("show").unwrap(); + bg.class_list().add("show").unwrap(); + })); + } + Ok(()) +} + +fn init_popup(title: &HtmlElement, subtitle: &HtmlElement, content: &HtmlElement, old_ed: &Element) -> Result { + let popup = document().create_element("div")?; + popup.class_list().add("popup")?; + popup.set_attribute("id", "publish-popup")?; + + let tags = get_elt_value("tags").split(',').map(str::trim).map(str::to_string).collect::>(); + let license = get_elt_value("license"); + make_input(&i18n!(CATALOG, "Tags"), "popup-tags", &popup).set_raw_value(&tags.join(", ")); + make_input(&i18n!(CATALOG, "License"), "popup-license", &popup).set_raw_value(&license); + + let cover_label = document().create_element("label")?; + cover_label.append_child(&document().create_text_node(&i18n!(CATALOG, "Cover"))); + cover_label.set_attribute("for", "cover")?; + let cover = document().get_element_by_id("cover")?; + cover.parent_element()?.remove_child(&cover).ok(); + popup.append_child(&cover_label); + popup.append_child(&cover); + + let button = document().create_element("input")?; + js!{ + @{&button}.type = "submit"; + @{&button}.value = @{i18n!(CATALOG, "Publish")}; + }; + button.append_child(&document().create_text_node(&i18n!(CATALOG, "Publish"))); + button.add_event_listener(mv!(title, subtitle, content, old_ed => move |_: ClickEvent| { + set_value("title", title.inner_text()); + set_value("subtitle", subtitle.inner_text()); + set_value("editor-content", js!{ return @{&content}.innerHTML }.as_str().unwrap_or_default()); + set_value("tags", get_elt_value("popup-tags")); + let cover = document().get_element_by_id("cover").unwrap(); + cover.parent_element().unwrap().remove_child(&cover).ok(); + old_ed.append_child(&cover); + set_value("license", get_elt_value("popup-license")); + js! { + @{&old_ed}.submit(); + }; + })); + popup.append_child(&button); + + document().body()?.append_child(&popup); + Ok(popup) +} + +fn init_popup_bg() -> Result { + let bg = document().create_element("div")?; + bg.class_list().add("popup-bg")?; + bg.set_attribute("id", "popup-bg")?; + + document().body()?.append_child(&bg); + bg.add_event_listener(|_: ClickEvent| close_popup()); + Ok(bg) +} + +fn chars_left(selector: &str, content: &HtmlElement) -> Option { + 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::().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, + } +} + +fn close_popup() { + let hide = |x: Element| x.class_list().remove("show"); + document().get_element_by_id("publish-popup").map(hide); + document().get_element_by_id("popup-bg").map(hide); +} + +fn make_input(label_text: &str, name: &'static str, form: &Element) -> InputElement { + let label = document().create_element("label").unwrap(); + label.append_child(&document().create_text_node(label_text)); + label.set_attribute("for", name).unwrap(); + + let inp: InputElement = document().create_element("input").unwrap().try_into().unwrap(); + inp.set_attribute("name", name).unwrap(); + inp.set_attribute("id", name).unwrap(); + + form.append_child(&label); + form.append_child(&inp); + inp +} + +fn make_editable(tag: &'static str) -> Element { + let elt = document().create_element(tag).expect("Couldn't create editable element"); + elt.set_attribute("contenteditable", "true").expect("Couldn't make element editable"); + elt +} + +fn placeholder<'a>(elt: HtmlElement, text: &'a str) -> HtmlElement { + elt.dataset().insert("placeholder", text).unwrap(); + elt.dataset().insert("edited", "false").unwrap(); + + elt.add_event_listener(mv!(elt => move |_: FocusEvent| { + if elt.dataset().get("edited").unwrap().as_str() != "true" { + clear_children(&elt); + } + })); + elt.add_event_listener(mv!(elt => move |_: BlurEvent| { + if elt.dataset().get("edited").unwrap().as_str() != "true" { + clear_children(&elt); + + let ph = document().create_element("span").expect("Couldn't create placeholder"); + ph.class_list().add("placeholder").expect("Couldn't add class"); + ph.append_child(&document().create_text_node(&elt.dataset().get("placeholder").unwrap_or(String::new()))); + elt.append_child(&ph); + } + })); + elt.add_event_listener(mv!(elt => move |_: KeyUpEvent| { + elt.dataset().insert("edited", if elt.inner_text().trim_matches('\n').is_empty() { + "false" + } else { + "true" + }).expect("Couldn't update edition state"); + })); + elt +} + +fn clear_children(elt: &HtmlElement) { + for child in elt.child_nodes() { + elt.remove_child(&child).unwrap(); + } +} diff --git a/plume-front/src/main.rs b/plume-front/src/main.rs index be33e279..30999957 100644 --- a/plume-front/src/main.rs +++ b/plume-front/src/main.rs @@ -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::().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 diff --git a/po/plume-front/en.po b/po/plume-front/en.po new file mode 100644 index 00000000..80912b63 --- /dev/null +++ b/po/plume-front/en.po @@ -0,0 +1,45 @@ +msgid "" +msgstr "" +"Project-Id-Version: plume-front\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-15 16:33-0700\n" +"PO-Revision-Date: 2018-06-15 16:33-0700\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +# plume-front/src/editor.rs:57 +msgid "Title" +msgstr "Title" + +# plume-front/src/editor.rs:61 +msgid "Subtitle or summary" +msgstr "" + +# plume-front/src/editor.rs:68 +msgid "Write your article here. Markdown is supported." +msgstr "" + +# plume-front/src/editor.rs:46 +msgid "Around {} characters left" +msgstr "" + +# plume-front/src/editor.rs:96 +msgid "Tags" +msgstr "" + +# plume-front/src/editor.rs:97 +msgid "License" +msgstr "" + +# plume-front/src/editor.rs:100 +msgid "Cover" +msgstr "" + +# plume-front/src/editor.rs:111 +msgid "Publish" +msgstr "" diff --git a/po/plume-front/fr.po b/po/plume-front/fr.po new file mode 100644 index 00000000..0f8198ce --- /dev/null +++ b/po/plume-front/fr.po @@ -0,0 +1,45 @@ +msgid "" +msgstr "" +"Project-Id-Version: plume-front\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-15 16:33-0700\n" +"PO-Revision-Date: 2018-06-15 16:33-0700\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +# plume-front/src/editor.rs:57 +msgid "Title" +msgstr "Titre" + +# plume-front/src/editor.rs:61 +msgid "Subtitle or summary" +msgstr "Sous-titre ou résumé" + +# plume-front/src/editor.rs:68 +msgid "Write your article here. Markdown is supported." +msgstr "Écrivez votre article ici. Vous pouvez utiliser du Markdown." + +# plume-front/src/editor.rs:46 +msgid "Around {} characters left" +msgstr "" + +# plume-front/src/editor.rs:96 +msgid "Tags" +msgstr "" + +# plume-front/src/editor.rs:97 +msgid "License" +msgstr "" + +# plume-front/src/editor.rs:100 +msgid "Cover" +msgstr "" + +# plume-front/src/editor.rs:111 +msgid "Publish" +msgstr "Publier" diff --git a/po/plume-front/plume-front.pot b/po/plume-front/plume-front.pot new file mode 100644 index 00000000..93cecd7f --- /dev/null +++ b/po/plume-front/plume-front.pot @@ -0,0 +1,45 @@ +msgid "" +msgstr "" +"Project-Id-Version: plume-front\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-15 16:33-0700\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +# plume-front/src/editor.rs:103 +msgid "Title" +msgstr "" + +# plume-front/src/editor.rs:104 +msgid "Subtitle or summary" +msgstr "" + +# plume-front/src/editor.rs:105 +msgid "Write your article here. Markdown is supported." +msgstr "" + +# plume-front/src/editor.rs:113 +msgid "Around {} characters left" +msgstr "" + +# plume-front/src/editor.rs:143 +msgid "Tags" +msgstr "" + +# plume-front/src/editor.rs:144 +msgid "License" +msgstr "" + +# plume-front/src/editor.rs:147 +msgid "Cover" +msgstr "" + +# plume-front/src/editor.rs:157 +msgid "Publish" +msgstr "" diff --git a/po/plume/ar.po b/po/plume/ar.po index 0dd994a9..78450ecc 100644 --- a/po/plume/ar.po +++ b/po/plume/ar.po @@ -528,6 +528,9 @@ msgstr "تسجيل الدخول" msgid "Username or email" msgstr "اسم المستخدم أو عنوان البريد الالكتروني" +msgid "Publish" +msgstr "انشر" + msgid "Subtitle" msgstr "العنوان الثانوي" @@ -819,9 +822,6 @@ msgstr "استخدمها كصورة رمزية" #~ msgid "Create a post" #~ msgstr "انشئ منشورا" -#~ msgid "Publish" -#~ msgstr "انشر" - #~ msgid "One follower" #~ msgid_plural "{0} followers" #~ msgstr[0] "دون متابِع" diff --git a/po/plume/de.po b/po/plume/de.po index bcc9b7d3..39774b23 100644 --- a/po/plume/de.po +++ b/po/plume/de.po @@ -542,6 +542,9 @@ msgstr "" msgid "Username or email" msgstr "Nutzername oder E-Mail" +msgid "Publish" +msgstr "Veröffentlichen" + msgid "Subtitle" msgstr "Untertitel" @@ -901,9 +904,6 @@ msgstr "Als Avatar verwenden" #~ msgid "Let's go!" #~ msgstr "Los geht's!" -#~ msgid "Publish" -#~ msgstr "Veröffentlichen" - #~ msgid "One follower" #~ msgid_plural "{0} followers" #~ msgstr[0] "Ein Follower" diff --git a/po/plume/en.po b/po/plume/en.po index 556c410a..1a8fcaca 100644 --- a/po/plume/en.po +++ b/po/plume/en.po @@ -517,6 +517,9 @@ msgstr "" msgid "Username or email" msgstr "" +msgid "Publish" +msgstr "" + # src/template_utils.rs:144 msgid "Subtitle" msgstr "" diff --git a/po/plume/es.po b/po/plume/es.po index 2da53ffe..2e171eaf 100644 --- a/po/plume/es.po +++ b/po/plume/es.po @@ -504,6 +504,9 @@ msgstr "Iniciar Sesión" msgid "Username or email" msgstr "Nombre de usuario o correo electrónico" +msgid "Publish" +msgstr "Publicar" + msgid "Subtitle" msgstr "" @@ -744,9 +747,6 @@ msgstr "" #~ msgid "Create a post" #~ msgstr "Crear una publicación" -#~ msgid "Publish" -#~ msgstr "Publicar" - #~ msgid "Follow" #~ msgstr "Seguir" diff --git a/po/plume/fr.po b/po/plume/fr.po index 9d41b56b..c45e8ee0 100644 --- a/po/plume/fr.po +++ b/po/plume/fr.po @@ -538,6 +538,9 @@ msgstr "" msgid "Username or email" msgstr "Nom d’utilisateur ou adresse électronique" +msgid "Publish" +msgstr "Publier" + msgid "Subtitle" msgstr "Sous-titre" @@ -898,9 +901,6 @@ msgstr "Utiliser comme avatar" #~ msgid "Let's go!" #~ msgstr "C’est parti !" -#~ msgid "Publish" -#~ msgstr "Publier" - #~ msgid "New Account" #~ msgstr "Nouveau compte" diff --git a/po/plume/gl.po b/po/plume/gl.po index f6fa3693..a62bf728 100644 --- a/po/plume/gl.po +++ b/po/plume/gl.po @@ -538,6 +538,9 @@ msgstr "" msgid "Username or email" msgstr "Usuaria ou correo-e" +msgid "Publish" +msgstr "Publicar" + msgid "Subtitle" msgstr "Subtítulo" @@ -901,9 +904,6 @@ msgstr "Utilizar como avatar" #~ msgid "Let's go!" #~ msgstr "Imos!" -#~ msgid "Publish" -#~ msgstr "Publicar" - #~ msgid "New Account" #~ msgstr "Nova conta" diff --git a/po/plume/it.po b/po/plume/it.po index 08d36819..f965a51d 100644 --- a/po/plume/it.po +++ b/po/plume/it.po @@ -541,6 +541,9 @@ msgstr "" msgid "Username or email" msgstr "Nome utente o email" +msgid "Publish" +msgstr "Pubblica" + msgid "Subtitle" msgstr "Sottotitolo" @@ -904,9 +907,6 @@ msgstr "Usa come avatar" #~ msgid "Let's go!" #~ msgstr "Andiamo!" -#~ msgid "Publish" -#~ msgstr "Pubblica" - #~ msgid "New Account" #~ msgstr "Nuovo Account" diff --git a/po/plume/ja.po b/po/plume/ja.po index 3451d531..74b7d410 100644 --- a/po/plume/ja.po +++ b/po/plume/ja.po @@ -533,6 +533,9 @@ msgstr "ログイン" msgid "Username or email" msgstr "ユーザー名またはメールアドレス" +msgid "Publish" +msgstr "公開" + msgid "Subtitle" msgstr "サブタイトル" @@ -814,9 +817,6 @@ msgstr "アバターとして使う" #~ msgid "Create a post" #~ msgstr "記事を作成" -#~ msgid "Publish" -#~ msgstr "公開" - #~ msgid "One follower" #~ msgid_plural "{0} followers" #~ msgstr[0] "{0} フォロワー" diff --git a/po/plume/nb.po b/po/plume/nb.po index 24877dae..b963e9b4 100644 --- a/po/plume/nb.po +++ b/po/plume/nb.po @@ -565,6 +565,9 @@ msgstr "Logg inn" msgid "Username or email" msgstr "Brukernavn eller epost" +msgid "Publish" +msgstr "" + #, fuzzy msgid "Subtitle" msgstr "Tittel" diff --git a/po/plume/pl.po b/po/plume/pl.po index 93f23f7c..73a3f5b9 100644 --- a/po/plume/pl.po +++ b/po/plume/pl.po @@ -507,6 +507,9 @@ msgstr "Zaloguj się" msgid "Username or email" msgstr "Nazwa użytkownika lub adres e-mail" +msgid "Publish" +msgstr "Opublikuj" + msgid "Subtitle" msgstr "Podtytuł" @@ -847,9 +850,6 @@ msgstr "Użyj jako awataru" #~ msgid "Let's go!" #~ msgstr "Przejdźmy dalej!" -#~ msgid "Publish" -#~ msgstr "Opublikuj" - #~ msgid "New Account" #~ msgstr "Nowe konto" diff --git a/po/plume/plume.pot b/po/plume/plume.pot index 730fadbb..9bce11fb 100644 --- a/po/plume/plume.pot +++ b/po/plume/plume.pot @@ -509,6 +509,9 @@ msgstr "" msgid "Username or email" msgstr "" +msgid "Publish" +msgstr "" + # src/template_utils.rs:144 msgid "Subtitle" msgstr "" diff --git a/po/plume/pt.po b/po/plume/pt.po index 503ec614..36864c24 100644 --- a/po/plume/pt.po +++ b/po/plume/pt.po @@ -528,6 +528,9 @@ msgstr "Entrar" msgid "Username or email" msgstr "Nome de usuário ou e-mail" +msgid "Publish" +msgstr "Publicar" + msgid "Subtitle" msgstr "Subtítulo" @@ -800,9 +803,6 @@ msgstr "Utilizar como avatar" #~ msgid "Create a post" #~ msgstr "Criar um artigo" -#~ msgid "Publish" -#~ msgstr "Publicar" - #~ msgid "One follower" #~ msgid_plural "{0} followers" #~ msgstr[0] "Um seguidor" diff --git a/po/plume/ru.po b/po/plume/ru.po index a4769479..2295cb8e 100644 --- a/po/plume/ru.po +++ b/po/plume/ru.po @@ -545,6 +545,9 @@ msgstr "" msgid "Username or email" msgstr "Имя пользователя или адрес электронной почты" +msgid "Publish" +msgstr "Опубликовать" + msgid "Subtitle" msgstr "Подзаголовок" @@ -914,9 +917,6 @@ msgstr "Использовать как аватар" #~ msgid "Let's go!" #~ msgstr "Поехали!" -#~ msgid "Publish" -#~ msgstr "Опубликовать" - #~ msgid "One follower" #~ msgid_plural "{0} followers" #~ msgstr[0] "Один подписчик" diff --git a/static/css/_article.scss b/static/css/_article.scss index dd268aaf..742f1ffa 100644 --- a/static/css/_article.scss +++ b/static/css/_article.scss @@ -266,3 +266,58 @@ main .article-meta { } } } + +#plume-editor { + header { + display: flex; + flex-direction: row-reverse; + background: transparent; + align-items: center; + button { + flex: 0 0 10em; + font-size: 1.25em; + margin: .5em 0em .5em 1em; + } + } + + & > * { + min-height: 1em; + outline: none; + margin-bottom: 0.5em; + } + + .placeholder { + color: transparentize($black, 0.6); + } + + article { + max-width: none; + min-height: 80vh; + } +} + +.popup { + position: fixed; + top: 15vh; + bottom: 20vh; + left: 20vw; + right: 20vw; + background: $lightgray; + border: 1px solid $purple; + z-index: 2; + padding: 2em; + overflow-y: auto; +} + +.popup:not(.show), .popup-bg:not(.show) { + display: none; +} + +.popup-bg { + background: rgba(0, 0, 0, 0.1); + position: fixed; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; +} diff --git a/templates/posts/new.rs.html b/templates/posts/new.rs.html index 0e472075..d4706072 100644 --- a/templates/posts/new.rs.html +++ b/templates/posts/new.rs.html @@ -11,11 +11,17 @@ @(ctx: BaseContext, title: String, blog: Blog, editing: bool, form: &NewPostForm, is_draft: bool, article: Option, errors: ValidationErrors, medias: Vec, content_len: u64) @:base(ctx, title.clone(), {}, {}, { -

@title

+

@title

+ @if let Some(article) = article { -
+ } else { - + } @input!(ctx.1, title (text), "Title", form, errors.clone(), "required") @input!(ctx.1, subtitle (optional text), "Subtitle", form, errors.clone(), "") @@ -24,8 +30,8 @@ @format!(r#"

{}

"#, errs[0].message.clone().unwrap_or(Cow::from("Unknown error"))) } - - + + @content_len

@i18n!(ctx.1, "You can upload medias to your gallery, and copy their Markdown code in your articles to insert them.")