From 1f7ff62c196d8ae2b3927f8926d08c1f77a80942 Mon Sep 17 00:00:00 2001 From: Baptiste Gelez Date: Sat, 6 Apr 2019 14:20:12 +0100 Subject: [PATCH] Editor improvements (#486) - Make it possible to insert new paragraphs in the article body - Make it impossible to copy formatted HTML (to make media insertion from markdown code work correctly) TODO: - [x] make it possible to escape draft mode - [x] display errors from the server - [x] button to go back to the "normal" editor - [x] Avoid publishing placeholders --- plume-front/src/editor.rs | 124 +++++++++++++++++++++++++++++---- po/plume-front/en.po | 8 +++ po/plume-front/fr.po | 8 +++ po/plume-front/plume-front.pot | 48 +++++++------ po/plume/ar.po | 3 + po/plume/de.po | 3 + po/plume/en.po | 3 + po/plume/es.po | 3 + po/plume/fr.po | 3 + po/plume/gl.po | 3 + po/plume/it.po | 3 + po/plume/ja.po | 3 + po/plume/nb.po | 3 + po/plume/pl.po | 3 + po/plume/plume.pot | 3 + po/plume/pt.po | 3 + po/plume/ru.po | 3 + static/css/_article.scss | 1 + static/css/_header.scss | 13 ++++ templates/posts/new.rs.html | 1 + 20 files changed, 208 insertions(+), 34 deletions(-) diff --git a/plume-front/src/editor.rs b/plume-front/src/editor.rs index 160d4c6..2ebecdd 100644 --- a/plume-front/src/editor.rs +++ b/plume-front/src/editor.rs @@ -84,10 +84,46 @@ fn init_widget( widget.focus(); widget.blur(); + filter_paste(&widget); + Ok(widget) } +fn filter_paste(elt: &HtmlElement) { + // Only insert text when pasting something + js! { + @{&elt}.addEventListener("paste", function (evt) { + evt.preventDefault(); + document.execCommand("insertText", false, evt.clipboardData.getData("text")); + }); + }; +} + pub fn init() -> Result<(), EditorError> { + // Check if the user wants to use the basic editor + if let Some(basic_editor) = window().local_storage().get("basic-editor") { + if basic_editor == "true" { + if let Some(editor) = document().get_element_by_id("plume-fallback-editor") { + if let Ok(Some(title_label)) = document().query_selector("label[for=title]") { + let editor_button = document().create_element("a")?; + js!{ @{&editor_button}.href = "#"; } + editor_button.add_event_listener(|_: ClickEvent| { + window().local_storage().remove("basic-editor"); + window().history().go(0).ok(); // refresh + }); + editor_button.append_child(&document().create_text_node(&i18n!(CATALOG, "Open the rich text editor"))); + editor.insert_before(&editor_button, &title_label).ok(); + return Ok(()); + } + } + } + } + + // If we didn't returned above + init_editor() +} + +fn init_editor() -> Result<(), EditorError> { if let Some(ed) = document().get_element_by_id("plume-editor") { // Show the editor js! { @{&ed}.style.display = "block"; }; @@ -117,7 +153,7 @@ pub fn init() -> Result<(), EditorError> { "article", i18n!(CATALOG, "Write your article here. Markdown is supported."), content_val.clone(), - true, + false, )?; js! { @{&content}.innerHTML = @{content_val}; }; @@ -134,23 +170,45 @@ pub fn init() -> Result<(), EditorError> { }), 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(); + 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(); - }), - ); + popup.class_list().add("show").unwrap(); + bg.class_list().add("show").unwrap(); + })); + + show_errors(); + setup_close_button(); } Ok(()) } +fn setup_close_button() { + if let Some(button) = document().get_element_by_id("close-editor") { + button.add_event_listener(|_: ClickEvent| { + window().local_storage().insert("basic-editor", "true").unwrap(); + window().history().go(0).unwrap(); // Refresh the page + }); + } +} + +fn show_errors() { + if let Ok(Some(header)) = document().query_selector("header") { + let list = document().create_element("header").unwrap(); + list.class_list().add("messages").unwrap(); + for error in document().query_selector_all("p.error").unwrap() { + error.parent_element().unwrap().remove_child(&error).unwrap(); + list.append_child(&error); + } + header.parent_element().unwrap().insert_before(&list, &header.next_sibling().unwrap()).unwrap(); + } +} + fn init_popup( title: &HtmlElement, subtitle: &HtmlElement, @@ -178,6 +236,23 @@ fn init_popup( popup.append_child(&cover_label); popup.append_child(&cover); + if let Some(draft_checkbox) = document().get_element_by_id("draft") { + let draft_label = document().create_element("label")?; + draft_label.set_attribute("for", "popup-draft")?; + + let draft = document().create_element("input").unwrap(); + js!{ + @{&draft}.id = "popup-draft"; + @{&draft}.name = "popup-draft"; + @{&draft}.type = "checkbox"; + @{&draft}.checked = @{&draft_checkbox}.checked; + }; + + draft_label.append_child(&draft); + draft_label.append_child(&document().create_text_node(&i18n!(CATALOG, "This is a draft"))); + popup.append_child(&draft_label); + } + let button = document().create_element("input")?; js! { @{&button}.type = "submit"; @@ -185,10 +260,31 @@ fn init_popup( }; button.append_child(&document().create_text_node(&i18n!(CATALOG, "Publish"))); button.add_event_listener(mv!(title, subtitle, content, old_ed => move |_: ClickEvent| { + title.focus(); // Remove the placeholder before publishing set_value("title", title.inner_text()); + subtitle.focus(); set_value("subtitle", subtitle.inner_text()); - set_value("editor-content", js!{ return @{&content}.innerHTML }.as_str().unwrap_or_default()); + content.focus(); + set_value("editor-content", content.child_nodes().iter().fold(String::new(), |md, ch| { + let to_append = match ch.node_type() { + NodeType::Element => { + if js!{ return @{&ch}.tagName; } == "DIV" { + (js!{ return @{&ch}.innerHTML; }).try_into().unwrap_or_default() + } else { + (js!{ return @{&ch}.outerHTML; }).try_into().unwrap_or_default() + } + }, + NodeType::Text => ch.node_value().unwrap_or_default(), + _ => unreachable!(), + }; + format!("{}\n\n{}", md, to_append) + })); set_value("tags", get_elt_value("popup-tags")); + if let Some(draft) = document().get_element_by_id("popup-draft") { + js!{ + document.getElementById("draft").checked = @{draft}.checked; + }; + } let cover = document().get_element_by_id("cover").unwrap(); cover.parent_element().unwrap().remove_child(&cover).ok(); old_ed.append_child(&cover); diff --git a/po/plume-front/en.po b/po/plume-front/en.po index 80912b6..1e80dcf 100644 --- a/po/plume-front/en.po +++ b/po/plume-front/en.po @@ -12,6 +12,10 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +# plume-front/src/editor.rs:110 +msgid "Open the rich text editor" +msgstr "" + # plume-front/src/editor.rs:57 msgid "Title" msgstr "Title" @@ -40,6 +44,10 @@ msgstr "" msgid "Cover" msgstr "" +# plume-front/src/editor.rs:167 +msgid "This is a draft" +msgstr "" + # plume-front/src/editor.rs:111 msgid "Publish" msgstr "" diff --git a/po/plume-front/fr.po b/po/plume-front/fr.po index 0f8198c..237845b 100644 --- a/po/plume-front/fr.po +++ b/po/plume-front/fr.po @@ -12,6 +12,10 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +# plume-front/src/editor.rs:110 +msgid "Open the rich text editor" +msgstr "" + # plume-front/src/editor.rs:57 msgid "Title" msgstr "Titre" @@ -40,6 +44,10 @@ msgstr "" msgid "Cover" msgstr "" +# plume-front/src/editor.rs:167 +msgid "This is a draft" +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 index 93cecd7..6866575 100644 --- a/po/plume-front/plume-front.pot +++ b/po/plume-front/plume-front.pot @@ -12,34 +12,42 @@ msgstr "" "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" +# plume-front/src/editor.rs:114 +msgid "Open the rich text editor" msgstr "" # plume-front/src/editor.rs:143 -msgid "Tags" -msgstr "" - -# plume-front/src/editor.rs:144 -msgid "License" +msgid "Title" msgstr "" # plume-front/src/editor.rs:147 +msgid "Subtitle or summary" +msgstr "" + +# plume-front/src/editor.rs:154 +msgid "Write your article here. Markdown is supported." +msgstr "" + +# plume-front/src/editor.rs:165 +msgid "Around {} characters left" +msgstr "" + +# plume-front/src/editor.rs:228 +msgid "Tags" +msgstr "" + +# plume-front/src/editor.rs:229 +msgid "License" +msgstr "" + +# plume-front/src/editor.rs:232 msgid "Cover" msgstr "" -# plume-front/src/editor.rs:157 +# plume-front/src/editor.rs:252 +msgid "This is a draft" +msgstr "" + +# plume-front/src/editor.rs:259 msgid "Publish" msgstr "" diff --git a/po/plume/ar.po b/po/plume/ar.po index 0ac9812..241918e 100644 --- a/po/plume/ar.po +++ b/po/plume/ar.po @@ -568,6 +568,9 @@ msgstr "اسم المستخدم أو عنوان البريد الالكترون msgid "Publish" msgstr "انشر" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "العنوان الثانوي" diff --git a/po/plume/de.po b/po/plume/de.po index 25e660f..2c45a8e 100644 --- a/po/plume/de.po +++ b/po/plume/de.po @@ -571,6 +571,9 @@ msgstr "Nutzername oder E-Mail" msgid "Publish" msgstr "Veröffentlichen" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "Untertitel" diff --git a/po/plume/en.po b/po/plume/en.po index 797e402..fbaf12c 100644 --- a/po/plume/en.po +++ b/po/plume/en.po @@ -542,6 +542,9 @@ msgstr "" msgid "Publish" msgstr "" +msgid "Classic editor (any changes will be lost)" +msgstr "" + # src/template_utils.rs:144 msgid "Subtitle" msgstr "" diff --git a/po/plume/es.po b/po/plume/es.po index 39339fb..71f789a 100644 --- a/po/plume/es.po +++ b/po/plume/es.po @@ -539,6 +539,9 @@ msgstr "Nombre de usuario o correo electrónico" msgid "Publish" msgstr "Publicar" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "" diff --git a/po/plume/fr.po b/po/plume/fr.po index a9bbdc6..7cff9a0 100644 --- a/po/plume/fr.po +++ b/po/plume/fr.po @@ -567,6 +567,9 @@ msgstr "Nom d’utilisateur ou adresse électronique" msgid "Publish" msgstr "Publier" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "Sous-titre" diff --git a/po/plume/gl.po b/po/plume/gl.po index b2dfb99..98fa9fc 100644 --- a/po/plume/gl.po +++ b/po/plume/gl.po @@ -567,6 +567,9 @@ msgstr "Usuaria ou correo-e" msgid "Publish" msgstr "Publicar" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "Subtítulo" diff --git a/po/plume/it.po b/po/plume/it.po index 703a94e..59b215c 100644 --- a/po/plume/it.po +++ b/po/plume/it.po @@ -570,6 +570,9 @@ msgstr "Nome utente o email" msgid "Publish" msgstr "Pubblica" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "Sottotitolo" diff --git a/po/plume/ja.po b/po/plume/ja.po index 1dce9a0..1eb603b 100644 --- a/po/plume/ja.po +++ b/po/plume/ja.po @@ -574,6 +574,9 @@ msgstr "ユーザー名またはメールアドレス" msgid "Publish" msgstr "公開" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "サブタイトル" diff --git a/po/plume/nb.po b/po/plume/nb.po index d338a3f..90c46dd 100644 --- a/po/plume/nb.po +++ b/po/plume/nb.po @@ -594,6 +594,9 @@ msgstr "Brukernavn eller epost" msgid "Publish" msgstr "" +msgid "Classic editor (any changes will be lost)" +msgstr "" + #, fuzzy msgid "Subtitle" msgstr "Tittel" diff --git a/po/plume/pl.po b/po/plume/pl.po index b06b60d..4d1209f 100644 --- a/po/plume/pl.po +++ b/po/plume/pl.po @@ -549,6 +549,9 @@ msgstr "Nazwa użytkownika lub adres e-mail" msgid "Publish" msgstr "Opublikuj" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "Podtytuł" diff --git a/po/plume/plume.pot b/po/plume/plume.pot index b31bb68..0830db4 100644 --- a/po/plume/plume.pot +++ b/po/plume/plume.pot @@ -532,6 +532,9 @@ msgstr "" msgid "Publish" msgstr "" +msgid "Classic editor (any changes will be lost)" +msgstr "" + # src/template_utils.rs:217 msgid "Subtitle" msgstr "" diff --git a/po/plume/pt.po b/po/plume/pt.po index 4101f15..b8b159c 100644 --- a/po/plume/pt.po +++ b/po/plume/pt.po @@ -568,6 +568,9 @@ msgstr "Nome de usuário ou e-mail" msgid "Publish" msgstr "Publicar" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "Subtítulo" diff --git a/po/plume/ru.po b/po/plume/ru.po index 2c972ea..72b2b7e 100644 --- a/po/plume/ru.po +++ b/po/plume/ru.po @@ -574,6 +574,9 @@ msgstr "Имя пользователя или адрес электронной msgid "Publish" msgstr "Опубликовать" +msgid "Classic editor (any changes will be lost)" +msgstr "" + msgid "Subtitle" msgstr "Подзаголовок" diff --git a/static/css/_article.scss b/static/css/_article.scss index 742f1ff..bcb253a 100644 --- a/static/css/_article.scss +++ b/static/css/_article.scss @@ -273,6 +273,7 @@ main .article-meta { flex-direction: row-reverse; background: transparent; align-items: center; + justify-content: space-between; button { flex: 0 0 10em; font-size: 1.25em; diff --git a/static/css/_header.scss b/static/css/_header.scss index 6ea4069..35368e8 100644 --- a/static/css/_header.scss +++ b/static/css/_header.scss @@ -74,6 +74,19 @@ header { } } +.messages { + & > * { + padding: 1em 20%; + } + + p.error { + color: $red; + background: lighten($red, 40%); + margin: 0; + max-width: initial; + } +} + // Only enable label animations on normal screens @media screen and (min-width: 900px) { header nav a { diff --git a/templates/posts/new.rs.html b/templates/posts/new.rs.html index a387177..5c6e041 100644 --- a/templates/posts/new.rs.html +++ b/templates/posts/new.rs.html @@ -17,6 +17,7 @@

@content_len

+ @i18n!(ctx.1, "Classic editor (any changes will be lost)")
@if let Some(article) = article {