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
fix-mobile-margin
Baptiste Gelez 5 years ago committed by GitHub
parent 38701c8a40
commit 1f7ff62c19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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();
popup.class_list().add("show").unwrap();
bg.class_list().add("show").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();
}));
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);

@ -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 ""

@ -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"

@ -12,34 +12,42 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
# plume-front/src/editor.rs:103
# plume-front/src/editor.rs:114
msgid "Open the rich text editor"
msgstr ""
# plume-front/src/editor.rs:143
msgid "Title"
msgstr ""
# plume-front/src/editor.rs:104
# plume-front/src/editor.rs:147
msgid "Subtitle or summary"
msgstr ""
# plume-front/src/editor.rs:105
# plume-front/src/editor.rs:154
msgid "Write your article here. Markdown is supported."
msgstr ""
# plume-front/src/editor.rs:113
# plume-front/src/editor.rs:165
msgid "Around {} characters left"
msgstr ""
# plume-front/src/editor.rs:143
# plume-front/src/editor.rs:228
msgid "Tags"
msgstr ""
# plume-front/src/editor.rs:144
# plume-front/src/editor.rs:229
msgid "License"
msgstr ""
# plume-front/src/editor.rs:147
# 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 ""

@ -568,6 +568,9 @@ msgstr "اسم المستخدم أو عنوان البريد الالكترون
msgid "Publish"
msgstr "انشر"
msgid "Classic editor (any changes will be lost)"
msgstr ""
msgid "Subtitle"
msgstr "العنوان الثانوي"

@ -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"

@ -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 ""

@ -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 ""

@ -567,6 +567,9 @@ msgstr "Nom dutilisateur ou adresse électronique"
msgid "Publish"
msgstr "Publier"
msgid "Classic editor (any changes will be lost)"
msgstr ""
msgid "Subtitle"
msgstr "Sous-titre"

@ -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"

@ -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"

@ -574,6 +574,9 @@ msgstr "ユーザー名またはメールアドレス"
msgid "Publish"
msgstr "公開"
msgid "Classic editor (any changes will be lost)"
msgstr ""
msgid "Subtitle"
msgstr "サブタイトル"

@ -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"

@ -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ł"

@ -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 ""

@ -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"

@ -574,6 +574,9 @@ msgstr "Имя пользователя или адрес электронной
msgid "Publish"
msgstr "Опубликовать"
msgid "Classic editor (any changes will be lost)"
msgstr ""
msgid "Subtitle"
msgstr "Подзаголовок"

@ -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;

@ -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 {

@ -17,6 +17,7 @@
<header>
<button id="publish" class="button">@i18n!(ctx.1, "Publish")</button>
<p id="char-count">@content_len</p>
<a href="#" id="close-editor">@i18n!(ctx.1, "Classic editor (any changes will be lost)")</a>
</header>
</div>
@if let Some(article) = article {

Loading…
Cancel
Save