Version 2.1 #41
@ -9,19 +9,15 @@ open MyWebLog.ViewModels
|
|||||||
// GET /admin/pages/page/{pageNbr}
|
// GET /admin/pages/page/{pageNbr}
|
||||||
let all pageNbr : HttpHandler = requireAccess Author >=> fun next ctx -> task {
|
let all pageNbr : HttpHandler = requireAccess Author >=> fun next ctx -> task {
|
||||||
let! pages = ctx.Data.Page.FindPageOfPages ctx.WebLog.Id pageNbr
|
let! pages = ctx.Data.Page.FindPageOfPages ctx.WebLog.Id pageNbr
|
||||||
|
let displayPages =
|
||||||
|
pages
|
||||||
|
|> Seq.ofList
|
||||||
|
|> Seq.truncate 25
|
||||||
|
|> Seq.map (DisplayPage.FromPageMinimal ctx.WebLog)
|
||||||
|
|> List.ofSeq
|
||||||
return!
|
return!
|
||||||
hashForPage "Pages"
|
Views.Page.pageList displayPages pageNbr (pages.Length > 25)
|
||||||
|> withAntiCsrf ctx
|
|> adminPage "Pages" true next ctx
|
||||||
|> addToHash "pages" (pages
|
|
||||||
|> Seq.ofList
|
|
||||||
|> Seq.truncate 25
|
|
||||||
|> Seq.map (DisplayPage.FromPageMinimal ctx.WebLog)
|
|
||||||
|> List.ofSeq)
|
|
||||||
|> addToHash "page_nbr" pageNbr
|
|
||||||
|> addToHash "prev_page" (if pageNbr = 2 then "" else $"/page/{pageNbr - 1}")
|
|
||||||
|> addToHash "has_next" (List.length pages > 25)
|
|
||||||
|> addToHash "next_page" $"/page/{pageNbr + 1}"
|
|
||||||
|> adminView "page-list" next ctx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /admin/page/{id}/edit
|
// GET /admin/page/{id}/edit
|
||||||
@ -51,7 +47,7 @@ let edit pgId : HttpHandler = requireAccess Author >=> fun next ctx -> task {
|
|||||||
| None -> return! Error.notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /admin/page/{id}/delete
|
// DELETE /admin/page/{id}
|
||||||
let delete pgId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task {
|
let delete pgId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task {
|
||||||
match! ctx.Data.Page.Delete (PageId pgId) ctx.WebLog.Id with
|
match! ctx.Data.Page.Delete (PageId pgId) ctx.WebLog.Id with
|
||||||
| true ->
|
| true ->
|
||||||
|
@ -175,7 +175,6 @@ let router : HttpHandler = choose [
|
|||||||
subRoute "/page" (choose [
|
subRoute "/page" (choose [
|
||||||
route "/save" >=> Page.save
|
route "/save" >=> Page.save
|
||||||
route "/permalinks" >=> Page.savePermalinks
|
route "/permalinks" >=> Page.savePermalinks
|
||||||
routef "/%s/delete" Page.delete
|
|
||||||
routef "/%s/revision/%s/restore" Page.restoreRevision
|
routef "/%s/revision/%s/restore" Page.restoreRevision
|
||||||
])
|
])
|
||||||
subRoute "/post" (choose [
|
subRoute "/post" (choose [
|
||||||
@ -211,6 +210,7 @@ let router : HttpHandler = choose [
|
|||||||
]
|
]
|
||||||
DELETE >=> validateCsrf >=> choose [
|
DELETE >=> validateCsrf >=> choose [
|
||||||
subRoute "/page" (choose [
|
subRoute "/page" (choose [
|
||||||
|
routef "/%s" Page.delete
|
||||||
routef "/%s/revision/%s" Page.deleteRevision
|
routef "/%s/revision/%s" Page.deleteRevision
|
||||||
routef "/%s/revisions" Page.purgeRevisions
|
routef "/%s/revisions" Page.purgeRevisions
|
||||||
])
|
])
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<Compile Include="Caches.fs" />
|
<Compile Include="Caches.fs" />
|
||||||
<Compile Include="Views\Helpers.fs" />
|
<Compile Include="Views\Helpers.fs" />
|
||||||
<Compile Include="Views\Admin.fs" />
|
<Compile Include="Views\Admin.fs" />
|
||||||
|
<Compile Include="Views\Page.fs" />
|
||||||
<Compile Include="Views\Post.fs" />
|
<Compile Include="Views\Post.fs" />
|
||||||
<Compile Include="Views\User.fs" />
|
<Compile Include="Views\User.fs" />
|
||||||
<Compile Include="Handlers\Helpers.fs" />
|
<Compile Include="Handlers\Helpers.fs" />
|
||||||
|
84
src/MyWebLog/Views/Page.fs
Normal file
84
src/MyWebLog/Views/Page.fs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
module MyWebLog.Views.Page
|
||||||
|
|
||||||
|
open Giraffe.ViewEngine
|
||||||
|
open Giraffe.ViewEngine.Htmx
|
||||||
|
open MyWebLog
|
||||||
|
open MyWebLog.ViewModels
|
||||||
|
|
||||||
|
/// Display a list of pages for this web log
|
||||||
|
let pageList (pages: DisplayPage list) pageNbr hasNext app = [
|
||||||
|
h2 [ _class "my-3" ] [ raw app.PageTitle ]
|
||||||
|
article [] [
|
||||||
|
a [ _href (relUrl app "admin/page/new/edit"); _class "btn btn-primary btn-sm mb-3" ] [ raw "Create a New Page" ]
|
||||||
|
if pages.Length = 0 then
|
||||||
|
p [ _class "text-muted fst-italic text-center" ] [ raw "This web log has no pages" ]
|
||||||
|
else
|
||||||
|
let titleCol = "col-12 col-md-5"
|
||||||
|
let linkCol = "col-12 col-md-5"
|
||||||
|
let upd8Col = "col-12 col-md-2"
|
||||||
|
form [ _method "post"; _class "container mb-3"; _hxTarget "body" ] [
|
||||||
|
antiCsrf app
|
||||||
|
div [ _class "row mwl-table-heading" ] [
|
||||||
|
div [ _class titleCol ] [
|
||||||
|
span [ _class "d-none d-md-inline" ] [ raw "Title" ]; span [ _class "d-md-none" ] [ raw "Page" ]
|
||||||
|
]
|
||||||
|
div [ _class $"{linkCol} d-none d-md-inline-block" ] [ raw "Permalink" ]
|
||||||
|
div [ _class $"{upd8Col} d-none d-md-inline-block" ] [ raw "Updated" ]
|
||||||
|
]
|
||||||
|
for pg in pages do
|
||||||
|
let pageLink = if pg.IsDefault then "" else pg.Permalink
|
||||||
|
div [ _class "row mwl-table-detail" ] [
|
||||||
|
div [ _class titleCol ] [
|
||||||
|
txt pg.Title
|
||||||
|
if pg.IsDefault then
|
||||||
|
raw " "; span [ _class "badge bg-success" ] [ raw "HOME PAGE" ]
|
||||||
|
if pg.IsInPageList then
|
||||||
|
raw " "; span [ _class "badge bg-primary" ] [ raw "IN PAGE LIST" ]
|
||||||
|
br [] ; small [] [
|
||||||
|
let adminUrl = relUrl app $"admin/page/{pg.Id}"
|
||||||
|
a [ _href (relUrl app pageLink); _target "_blank" ] [ raw "View Page" ]
|
||||||
|
if app.IsEditor || (app.IsAuthor && app.UserId.Value = WebLogUserId pg.AuthorId) then
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _href $"{adminUrl}/edit" ] [ raw "Edit" ]
|
||||||
|
if app.IsWebLogAdmin then
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _href adminUrl; _hxDelete adminUrl; _class "text-danger"
|
||||||
|
_hxConfirm $"Are you sure you want to delete the page “{pg.Title}”? This action cannot be undone." ] [
|
||||||
|
raw "Delete"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class linkCol ] [
|
||||||
|
small [ _class "d-md-none" ] [ txt pageLink ]
|
||||||
|
span [ _class "d-none d-md-inline" ] [ txt pageLink ]
|
||||||
|
]
|
||||||
|
div [ _class upd8Col ] [
|
||||||
|
small [ _class "d-md-none text-muted" ] [
|
||||||
|
raw "Updated "; txt (pg.UpdatedOn.ToString "MMMM d, yyyy")
|
||||||
|
]
|
||||||
|
span [ _class "d-none d-md-inline" ] [ txt (pg.UpdatedOn.ToString "MMMM d, yyyy") ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
if pageNbr > 1 || hasNext then
|
||||||
|
div [ _class "d-flex justify-content-evenly mb-3" ] [
|
||||||
|
div [] [
|
||||||
|
if pageNbr > 1 then
|
||||||
|
let prevPage = if pageNbr = 2 then "" else $"/page/{pageNbr - 1}"
|
||||||
|
p [] [
|
||||||
|
a [ _class "btn btn-secondary"; _href (relUrl app $"admin/pages{prevPage}") ] [
|
||||||
|
raw "« Previous"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "text-right" ] [
|
||||||
|
if hasNext then
|
||||||
|
p [] [
|
||||||
|
a [ _class "btn btn-secondary"; _href (relUrl app $"admin/pages/page/{pageNbr + 1}") ] [
|
||||||
|
raw "Next »"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
@ -1,75 +0,0 @@
|
|||||||
<h2 class=my-3>{{ page_title }}</h2>
|
|
||||||
<article>
|
|
||||||
<a href="{{ "admin/page/new/edit" | relative_link }}" class="btn btn-primary btn-sm mb-3">Create a New Page</a>
|
|
||||||
{%- assign page_count = pages | size -%}
|
|
||||||
{% if page_count > 0 %}
|
|
||||||
{%- assign title_col = "col-12 col-md-5" -%}
|
|
||||||
{%- assign link_col = "col-12 col-md-5" -%}
|
|
||||||
{%- assign upd8_col = "col-12 col-md-2" -%}
|
|
||||||
<form method=post class="container mb-3" hx-target=body>
|
|
||||||
<input type=hidden name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
|
||||||
<div class="row mwl-table-heading">
|
|
||||||
<div class="{{ title_col }}">
|
|
||||||
<span class="d-none d-md-inline">Title</span><span class=d-md-none>Page</span>
|
|
||||||
</div>
|
|
||||||
<div class="{{ link_col }} d-none d-md-inline-block">Permalink</div>
|
|
||||||
<div class="{{ upd8_col }} d-none d-md-inline-block">Updated</div>
|
|
||||||
</div>
|
|
||||||
{% for pg in pages -%}
|
|
||||||
<div class="row mwl-table-detail">
|
|
||||||
<div class="{{ title_col }}">
|
|
||||||
{{ pg.title }}
|
|
||||||
{%- if pg.is_default %} <span class="badge bg-success">HOME PAGE</span>{% endif -%}
|
|
||||||
{%- if pg.is_in_page_list %} <span class="badge bg-primary">IN PAGE LIST</span> {% endif -%}<br>
|
|
||||||
<small>
|
|
||||||
{%- capture pg_link %}{% unless pg.is_default %}{{ pg.permalink }}{% endunless %}{% endcapture -%}
|
|
||||||
<a href="{{ pg_link | relative_link }}" target=_blank>View Page</a>
|
|
||||||
{% if is_editor or is_author and user_id == pg.author_id %}
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
<a href="{{ pg | edit_page_link }}">Edit</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if is_web_log_admin %}
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
{%- assign pg_del_link = "admin/page/" | append: pg.id | append: "/delete" | relative_link -%}
|
|
||||||
<a href="{{ pg_del_link }}" hx-post="{{ pg_del_link }}" class=text-danger
|
|
||||||
hx-confirm="Are you sure you want to delete the page “{{ pg.title | strip_html | escape }}”? This action cannot be undone.">
|
|
||||||
Delete
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
<div class="{{ link_col }}">
|
|
||||||
{%- capture pg_link %}/{% unless pg.is_default %}{{ pg.permalink }}{% endunless %}{% endcapture -%}
|
|
||||||
<small class=d-md-none>{{ pg_link }}</small><span class="d-none d-md-inline">{{ pg_link }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="{{ upd8_col }}">
|
|
||||||
<small class="d-md-none text-muted">Updated {{ pg.updated_on | date: "MMMM d, yyyy" }}</small>
|
|
||||||
<span class="d-none d-md-inline">{{ pg.updated_on | date: "MMMM d, yyyy" }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{%- endfor %}
|
|
||||||
</form>
|
|
||||||
{% if page_nbr > 1 or has_next %}
|
|
||||||
<div class="d-flex justify-content-evenly mb-3">
|
|
||||||
<div>
|
|
||||||
{% if page_nbr > 1 %}
|
|
||||||
<p>
|
|
||||||
<a class="btn btn-secondary" href="{{ "admin/pages" | append: prev_page | relative_link }}">
|
|
||||||
« Previous
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="text-right">
|
|
||||||
{% if has_next %}
|
|
||||||
<p>
|
|
||||||
<a class="btn btn-secondary" href="{{ "admin/pages" | append: next_page | relative_link }}">
|
|
||||||
Next »
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<p class="text-muted fst-italic text-center">This web log has no pages</p>
|
|
||||||
{% endif %}
|
|
||||||
</article>
|
|
@ -310,7 +310,7 @@ this.Admin = {
|
|||||||
*/
|
*/
|
||||||
checkChapterLocation() {
|
checkChapterLocation() {
|
||||||
const isDisabled = !document.getElementById("has_location").checked
|
const isDisabled = !document.getElementById("has_location").checked
|
||||||
;["location_name", "location_geo", "location_osm"].forEach(it => {
|
;["LocationName", "LocationGeo", "LocationOsm"].forEach(it => {
|
||||||
const elt = document.getElementById(it)
|
const elt = document.getElementById(it)
|
||||||
elt.disabled = isDisabled
|
elt.disabled = isDisabled
|
||||||
if (isDisabled) elt.value = ""
|
if (isDisabled) elt.value = ""
|
||||||
|
Loading…
Reference in New Issue
Block a user