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
This commit is contained in:
parent
38701c8a40
commit
1f7ff62c19
@ -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);
|
||||
|
@ -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
|
||||
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 ""
|
||||
|
@ -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 d’utilisateur 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…
Reference in New Issue
Block a user