diff --git a/src/JobsJobsJobs/Server/App.fs b/src/JobsJobsJobs/Server/App.fs index 977515c..e6236f4 100644 --- a/src/JobsJobsJobs/Server/App.fs +++ b/src/JobsJobsJobs/Server/App.fs @@ -17,6 +17,15 @@ open Microsoft.Extensions.Hosting open NodaTime +/// Enable buffering on the request body +type BufferedBodyMiddleware (next : RequestDelegate) = + + member _.InvokeAsync (ctx : HttpContext) = task { + ctx.Request.EnableBuffering () + return! next.Invoke ctx + } + + [] let main args = @@ -54,6 +63,7 @@ let main args = let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict)) let _ = app.UseStaticFiles () let _ = app.UseRouting () + let _ = app.UseMiddleware () let _ = app.UseAuthentication () let _ = app.UseAuthorization () let _ = app.UseSession () diff --git a/src/JobsJobsJobs/Server/Handlers.fs b/src/JobsJobsJobs/Server/Handlers.fs index 762c5f1..9dbb1ac 100644 --- a/src/JobsJobsJobs/Server/Handlers.fs +++ b/src/JobsJobsJobs/Server/Handlers.fs @@ -226,9 +226,10 @@ module Api = // POST: /api/markdown-preview let markdownPreview : HttpHandler = requireUser >=> fun next ctx -> task { + let _ = ctx.Request.Body.Seek(0L, SeekOrigin.Begin) use reader = new StreamReader (ctx.Request.Body) let! preview = reader.ReadToEndAsync () - return! htmlString (MarkdownString.toHtml (Text (defaultArg (Option.ofObj preview) "--"))) next ctx + return! htmlString (MarkdownString.toHtml (Text preview)) next ctx } diff --git a/src/JobsJobsJobs/Server/ViewModels.fs b/src/JobsJobsJobs/Server/ViewModels.fs index d789dc0..f710a5e 100644 --- a/src/JobsJobsJobs/Server/ViewModels.fs +++ b/src/JobsJobsJobs/Server/ViewModels.fs @@ -60,11 +60,7 @@ module EditProfileViewModel = FullTime = false Biography = "" Experience = None - Skills = [| - { Id = "1"; Description = "test 1"; Notes = None } - { Id = "3"; Description = "test 2"; Notes = Some "noted" } - { Id = "4"; Description = "asfasdfa"; Notes = None } - |] + Skills = [||] } /// Create an instance of this form from the given profile diff --git a/src/JobsJobsJobs/Server/Views/Common.fs b/src/JobsJobsJobs/Server/Views/Common.fs index 0c32d13..5760bb0 100644 --- a/src/JobsJobsJobs/Server/Views/Common.fs +++ b/src/JobsJobsJobs/Server/Views/Common.fs @@ -37,12 +37,13 @@ let markdownEditor attrs name value editorLabel = rawText "Markdown" ] rawText "   " - button [ _type "button"; _id $"{name}PreviewButton"; _class "btn btn-outline-secondary btn-sm rounded-pill" - _onclick $"jjj.showPreview('{name}')" ] [ + button [ _type "button"; _id $"{name}PreviewButton" + _class "btn btn-outline-secondary btn-sm rounded-pill" ] [ rawText "Preview" ] ] - section [ _id $"{name}Preview"; _class "jjj-not-shown"; _ariaLabel "Rendered Markdown preview" ] [] + section [ _id $"{name}Preview"; _class "jjj-not-shown jjj-markdown-preview px-2 pt-2" + _ariaLabel "Rendered Markdown preview" ] [] div [ _id $"{name}Edit"; _class "form-floating jjj-shown" ] [ textarea (List.append attrs [ _id name; _name name; _class "form-control jjj-markdown-editor"; _rows "10" ]) [ @@ -50,4 +51,9 @@ let markdownEditor attrs name value editorLabel = ] label [ _for name ] [ rawText editorLabel ] ] + script [] [ + rawText """document.addEventListener("DOMContentLoaded", function () {""" + rawText $" jjj.markdownOnLoad('{name}') " + rawText "})" + ] ] diff --git a/src/JobsJobsJobs/Server/wwwroot/script.js b/src/JobsJobsJobs/Server/wwwroot/script.js index d31d6b9..6d295a7 100644 --- a/src/JobsJobsJobs/Server/wwwroot/script.js +++ b/src/JobsJobsJobs/Server/wwwroot/script.js @@ -53,6 +53,14 @@ this.jjj = { } catch (_) { } }, + /** + * Set up the onClick event for the preview button + * @param {string} editorId The ID of the editor to wire up + */ + markdownOnLoad(editorId) { + document.getElementById(`${editorId}PreviewButton`).addEventListener("click", () => { this.showPreview(editorId) }) + }, + /** * Show a preview of the Markdown in the given editor * @param {string} editorId The ID of the Markdown editor whose preview should be shown @@ -62,6 +70,8 @@ this.jjj = { const editBtn = document.getElementById(`${editorId}EditButton`) /** @type {HTMLDivElement} */ const editDiv = document.getElementById(`${editorId}Edit`) + /** @type {HTMLTextAreaElement} */ + const editor = document.getElementById(editorId) /** @type {HTMLButtonElement} */ const previewBtn = document.getElementById(`${editorId}PreviewButton`) /** @type {HTMLDivElement} */ @@ -69,20 +79,12 @@ this.jjj = { editBtn.classList.remove("btn-primary") editBtn.classList.add("btn-outline-secondary") - editBtn.addAttribute("onclick", `jjj.showEditor('{editorId}')`) + editBtn.addEventListener("click", () => { this.showEditor(editorId) }) previewBtn.classList.remove("btn-outline-secondary") previewBtn.classList.add("btn-primary") - previewBtn.removeAttribute("onclick") + previewBtn.removeEventListener("click", () => { this.showPreview(editorId) }) - editDiv.classList.remove("jjj-shown") - editDiv.classList.add("jjj-not-shown") - previewDiv.innerHTML = "

Loading preview...

" - previewtDiv.classList.remove("jjj-not-shown") - previewDiv.classList.add("jjj-shown") - - const preview = await fetch("/api/markdown-preview", - { method: "POST", body: document.getElementById(editorId).textContent }) - + const preview = await fetch("/api/markdown-preview", { method: "POST", body: editor.value }) let text if (preview.ok) { text = await preview.text() @@ -90,6 +92,12 @@ this.jjj = { text = `

ERROR ${preview.status} – ${preview.statusText}` } previewDiv.innerHTML = text + + editDiv.classList.remove("jjj-shown") + editDiv.classList.add("jjj-not-shown") + previewDiv.classList.remove("jjj-not-shown") + previewDiv.classList.add("jjj-shown") + }, /** @@ -101,17 +109,19 @@ this.jjj = { const editBtn = document.getElementById(`${editorId}EditButton`) /** @type {HTMLDivElement} */ const editDiv = document.getElementById(`${editorId}Edit`) + /** @type {HTMLTextAreaElement} */ + const editor = document.getElementById(editorId) /** @type {HTMLButtonElement} */ const previewBtn = document.getElementById(`${editorId}PreviewButton`) /** @type {HTMLDivElement} */ const previewDiv = document.getElementById(`${editorId}Preview`) - previewtBtn.classList.remove("btn-primary") + previewBtn.classList.remove("btn-primary") previewBtn.classList.add("btn-outline-secondary") - previewtBtn.addAttribute("onclick", `jjj.showPreview('{editorId}')`) + this.markdownOnLoad(editorId) editBtn.classList.remove("btn-outline-secondary") editBtn.classList.add("btn-primary") - editBtn.removeAttribute("onclick") + editBtn.removeEventListener("click", () => { this.showEditor(editorId) }) previewDiv.classList.remove("jjj-shown") previewDiv.classList.add("jjj-not-shown") diff --git a/src/JobsJobsJobs/Server/wwwroot/style.css b/src/JobsJobsJobs/Server/wwwroot/style.css index 24822a7..8fcb873 100644 --- a/src/JobsJobsJobs/Server/wwwroot/style.css +++ b/src/JobsJobsJobs/Server/wwwroot/style.css @@ -212,6 +212,10 @@ span.jjj-audio-clip:hover { would be; this overrides that for this textarea specifically */ height: inherit !important; } +.jjj-markdown-preview { + border: solid 1px lightgray; + border-radius: .5rem; +} /* Footer styling */ footer { display: flex;