Jump to…
snowfeat: given a new redesign and emulated terminal homepagerxkspqmsoknz1mo
Matt W1//! The in-browser file editor.
Matt W2//!
Matt W3//! A form with a `<textarea>` in it. That is the whole page, and it works with
Matt W4//! scripting disabled — CodeMirror replaces the textarea when `/assets/editor.js`
Matt W5//! loads and copies its content back on submit (spec §7: "Progressive
Matt W6//! enhancement is a hard requirement").
Matt W7//!
Matt W8//! Nothing here is conditional on JavaScript being available. There is no
Matt W9//! "loading" state and no hidden fallback: the fallback *is* the page.
Matt W10
Matt W11use maud::{html, Markup};
Matt W12
Matt W13use crate::repo_ctx::RepoContext;
Matt W14use crate::views::repo::breadcrumbs;
Matt W15
Matt W16pub struct Editor<'a> {
Matt W17 pub bookmark: &'a str,
Matt W18 /// The revision the edit is composed against, submitted back so a
Matt W19 /// concurrent edit is detected rather than overwritten.
Matt W20 pub tip: &'a str,
Matt W21 pub path: &'a str,
Matt W22 pub content: &'a str,
Matt W23 /// The grammar name CodeMirror should use, when we have one.
Matt W24 pub language: Option<&'a str>,
Matt W25 pub author: &'a str,
Matt W26 pub csrf: &'a str,
Matt W27 pub error: Option<&'a str>,
Matt W28}
Matt W29
Matt W30pub fn editor(ctx: &RepoContext, e: Editor<'_>) -> Markup {
Matt W31 let base = ctx.base();
Matt W32 let action = format!("{base}/edit/{}/{}", e.bookmark, e.path);
Matt W33 let cancel = format!("{base}/blob/{}/{}", e.bookmark, e.path);
Matt W34
Matt W35 html! {
Matt W36 div .tree-crumbs {
Matt W37 span .btn.btn-mono.is-static { (e.bookmark) }
Matt W38 (breadcrumbs(&base, e.bookmark, e.path))
Matt W39 span .spacer {}
Matt W40 a .btn.btn-mono href=(cancel) { "cancel" }
Matt W41 }
Matt W42
Matt W43 @if let Some(msg) = e.error {
Matt W44 div .banner.banner-error role="alert" { (msg) }
Matt W45 }
Matt W46
Matt W47 form method="post" action=(action) data-editor-form="1" {
Matt W48 input type="hidden" name="_csrf" value=(e.csrf);
Matt W49 // What the edit was composed against. The server refuses the save
Matt W50 // if the bookmark has moved since.
Matt W51 input type="hidden" name="tip" value=(e.tip);
Matt W52
Matt W53 div .editor-shell {
Matt W54 div .editor-bar {
Matt W55 span .mono { (e.path) }
Matt W56 @if let Some(l) = e.language {
Matt W57 span .label-condensed { (l) }
Matt W58 }
Matt W59 span .spacer {}
Matt W60 span .editor-status.mono { "editing on " (e.bookmark) }
Matt W61 }
Matt W62
Matt W63 label .sr-only for="content" { "Contents of " (e.path) }
Matt W64 div .editor-host {
Matt W65 textarea id="content" name="content" rows="24"
Matt W66 data-editor="1"
Matt W67 data-language=[e.language]
Matt W68 spellcheck="false"
Matt W69 autocapitalize="off" autocomplete="off"
Matt W70 wrap="off" { (e.content) }
Matt W71 }
Matt W72
Matt W73 div .editor-foot {
Matt W74 label .sr-only for="message" { "Commit message" }
Matt W75 input type="text" id="message" name="message" maxlength="500"
Matt W76 placeholder=(format!("Update {}", e.path));
Matt W77 button .btn.btn-primary type="submit" { "Commit changes" }
Matt W78 }
Matt W79 }
Matt W80 }
Matt W81
Matt W82 p .hint.measure {
Matt W83 "Committed to " code { (e.bookmark) } " as " (e.author)
Matt W84 ". Editing here writes a commit on top of the bookmark — it never rewrites \
Matt W85 history, so a protected bookmark accepts it, and it is indexed like any push."
Matt W86 }
Matt W87 }
Matt W88}

88 lines · Rust