Version 3 #40
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
[<EntryPoint>]
|
||||
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<BufferedBodyMiddleware> ()
|
||||
let _ = app.UseAuthentication ()
|
||||
let _ = app.UseAuthorization ()
|
||||
let _ = app.UseSession ()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "})"
|
||||
]
|
||||
]
|
||||
|
|
|
@ -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 = "<p><strong><em>Loading preview...</em></strong></p>"
|
||||
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 = `<p class="text-danger"><strong> ERROR ${preview.status}</strong> – ${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")
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user