Page / Post edit pages work
Category in work
This commit is contained in:
parent
0d54fc2ec3
commit
458b8308ae
|
@ -53,22 +53,26 @@ type PageModule (data : IMyWebLogData, clock : IClock) as this =
|
|||
let pageId = parameters.["id"].ToString ()
|
||||
let form = this.Bind<EditPageForm> ()
|
||||
let now = clock.GetCurrentInstant().ToUnixTimeTicks ()
|
||||
match pageId with "new" -> Some Page.Empty | _ -> tryFindPage data this.WebLog.Id pageId
|
||||
match pageId with "new" -> Some Page.Empty | _ -> tryFindPage data this.WebLog.Id pageId
|
||||
|> function
|
||||
| Some p ->
|
||||
let page = match pageId with "new" -> { p with WebLogId = this.WebLog.Id } | _ -> p
|
||||
let pId = { p with
|
||||
Title = form.Title
|
||||
Permalink = form.Permalink
|
||||
PublishedOn = match pageId with "new" -> now | _ -> page.PublishedOn
|
||||
UpdatedOn = now
|
||||
Text = match form.Source with
|
||||
| RevisionSource.Markdown -> (* Markdown.TransformHtml *) form.Text
|
||||
| _ -> form.Text
|
||||
Revisions = { AsOf = now
|
||||
SourceType = form.Source
|
||||
Text = form.Text } :: page.Revisions }
|
||||
|> savePage data
|
||||
let pId =
|
||||
{ p with
|
||||
Title = form.Title
|
||||
Permalink = form.Permalink
|
||||
PublishedOn = match pageId with "new" -> now | _ -> page.PublishedOn
|
||||
UpdatedOn = now
|
||||
ShowInPageList = form.ShowInPageList
|
||||
Text = match form.Source with
|
||||
| RevisionSource.Markdown -> (* Markdown.TransformHtml *) form.Text
|
||||
| _ -> form.Text
|
||||
Revisions = { AsOf = now
|
||||
SourceType = form.Source
|
||||
Text = form.Text
|
||||
} :: page.Revisions
|
||||
}
|
||||
|> savePage data
|
||||
let model = MyWebLogModel (this.Context, this.WebLog)
|
||||
{ UserMessage.Empty with
|
||||
Level = Level.Info
|
||||
|
|
|
@ -269,7 +269,7 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
|
|||
match postId with "new" -> Some Post.Empty | _ -> tryFindPost data this.WebLog.Id postId
|
||||
|> function
|
||||
| Some p ->
|
||||
let justPublished = p.PublishedOn = int64 0 && form.PublishNow
|
||||
let justPublished = p.PublishedOn = 0L && form.PublishNow
|
||||
let post = match postId with
|
||||
| "new" -> { p with
|
||||
WebLogId = this.WebLog.Id
|
||||
|
@ -281,7 +281,7 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
|
|||
Status = match form.PublishNow with true -> PostStatus.Published | _ -> PostStatus.Draft
|
||||
Title = form.Title
|
||||
Permalink = form.Permalink
|
||||
PublishedOn = match justPublished with true -> now | _ -> int64 0
|
||||
PublishedOn = match justPublished with true -> now | _ -> post.PublishedOn
|
||||
UpdatedOn = now
|
||||
Text = match form.Source with
|
||||
| RevisionSource.Markdown -> (* Markdown.TransformHtml *) form.Text
|
||||
|
@ -289,6 +289,7 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
|
|||
CategoryIds = Array.toList form.Categories
|
||||
Tags = form.Tags.Split ','
|
||||
|> Seq.map (fun t -> t.Trim().ToLowerInvariant ())
|
||||
|> Seq.sort
|
||||
|> Seq.toList
|
||||
Revisions = { AsOf = now
|
||||
SourceType = form.Source
|
||||
|
|
|
@ -220,6 +220,8 @@ type CategoryEditModel (ctx, webLog, category) =
|
|||
inherit MyWebLogModel (ctx, webLog)
|
||||
/// The form with the category information
|
||||
member val Form = CategoryForm (category) with get, set
|
||||
/// The category being edited
|
||||
member val Category = category
|
||||
/// The categories
|
||||
member val Categories : IndentedCategory list = [] with get, set
|
||||
|
||||
|
@ -336,9 +338,15 @@ type PostForDisplay (webLog : WebLog, post : Post) =
|
|||
/// The time zone for the web log to which this post belongs
|
||||
member this.TimeZone = webLog.TimeZone
|
||||
/// The date the post was published
|
||||
member this.PublishedDate = FormatDateTime.longDate this.TimeZone this.Post.PublishedOn
|
||||
member this.PublishedDate =
|
||||
match this.Post.Status with
|
||||
| PostStatus.Published -> FormatDateTime.longDate this.TimeZone this.Post.PublishedOn
|
||||
| _ -> FormatDateTime.longDate this.TimeZone this.Post.UpdatedOn
|
||||
/// The time the post was published
|
||||
member this.PublishedTime = FormatDateTime.time this.TimeZone this.Post.PublishedOn
|
||||
member this.PublishedTime =
|
||||
match this.Post.Status with
|
||||
| PostStatus.Published -> FormatDateTime.time this.TimeZone this.Post.PublishedOn
|
||||
| _ -> FormatDateTime.time this.TimeZone this.Post.UpdatedOn
|
||||
/// Tags
|
||||
member this.Tags =
|
||||
match List.length this.Post.Tags with
|
||||
|
@ -389,14 +397,17 @@ type EditPostForm () =
|
|||
/// The selected category Ids for the post
|
||||
member val Categories : string[] = [||] with get, set
|
||||
/// Whether the post should be published
|
||||
member val PublishNow = true with get, set
|
||||
member val PublishNow = false with get, set
|
||||
|
||||
/// Fill the form with applicable values from a post
|
||||
member this.ForPost (post : Post) =
|
||||
this.Title <- post.Title
|
||||
this.Permalink <- post.Permalink
|
||||
this.Tags <- List.reduce (fun acc x -> sprintf "%s, %s" acc x) post.Tags
|
||||
this.Tags <- match List.isEmpty post.Tags with
|
||||
| true -> ""
|
||||
| _ -> List.reduce (fun acc x -> sprintf "%s, %s" acc x) post.Tags
|
||||
this.Categories <- List.toArray post.CategoryIds
|
||||
this.PublishNow <- post.Status = PostStatus.Published || "new" = post.Id
|
||||
this
|
||||
|
||||
/// Fill the form with applicable values from a revision
|
||||
|
@ -412,7 +423,7 @@ type DisplayCategory = {
|
|||
Name : string
|
||||
Description : string
|
||||
IsChecked : bool
|
||||
}
|
||||
}
|
||||
with
|
||||
/// Create a display category
|
||||
static member Create (cat : Category, indent) isChecked =
|
||||
|
@ -442,6 +453,8 @@ type EditPostModel (ctx, webLog, post, revision) =
|
|||
member this.PublishedDate = this.DisplayLongDate this.Post.PublishedOn
|
||||
/// The published time
|
||||
member this.PublishedTime = this.DisplayTime this.Post.PublishedOn
|
||||
/// The "checked" attribute for the Publish Now box
|
||||
member this.PublishNowCheckedAttr = match this.Form.PublishNow with true -> "checked=\"checked\"" | _ -> ""
|
||||
|
||||
|
||||
// ---- User models ----
|
||||
|
|
|
@ -5,12 +5,6 @@ open RethinkDb.Driver.Ast
|
|||
|
||||
let private r = RethinkDb.Driver.RethinkDB.R
|
||||
|
||||
/// Shorthand to get a category by Id and filter by web log Id
|
||||
let private category (webLogId : string) (catId : string) =
|
||||
r.Table(Table.Category)
|
||||
.Get(catId)
|
||||
.Filter(ReqlFunction1 (fun c -> upcast c.["WebLogId"].Eq webLogId))
|
||||
|
||||
/// Get all categories for a web log
|
||||
let getAllCategories conn (webLogId : string) =
|
||||
async {
|
||||
|
@ -24,10 +18,16 @@ let getAllCategories conn (webLogId : string) =
|
|||
/// Get a specific category by its Id
|
||||
let tryFindCategory conn webLogId catId : Category option =
|
||||
async {
|
||||
let! catt = (category webLogId catId).RunResultAsync<Category> conn
|
||||
return catt
|
||||
|> box
|
||||
|> function null -> None | cat -> Some <| unbox cat
|
||||
let! c =
|
||||
r.Table(Table.Category)
|
||||
.Get(catId)
|
||||
.RunResultAsync<Category> conn
|
||||
return
|
||||
match box c with
|
||||
| null -> None
|
||||
| catt ->
|
||||
let cat : Category = unbox catt
|
||||
match cat.WebLogId = webLogId with true -> Some cat | _ -> None
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
|
@ -48,53 +48,63 @@ type CategoryUpdateRecord =
|
|||
}
|
||||
/// Update a category
|
||||
let updateCategory conn (cat : Category) =
|
||||
async {
|
||||
do! (category cat.WebLogId cat.Id)
|
||||
.Update({ CategoryUpdateRecord.Name = cat.Name
|
||||
match tryFindCategory conn cat.WebLogId cat.Id with
|
||||
| Some _ ->
|
||||
async {
|
||||
do! r.Table(Table.Category)
|
||||
.Get(cat.Id)
|
||||
.Update(
|
||||
{ CategoryUpdateRecord.Name = cat.Name
|
||||
Slug = cat.Slug
|
||||
Description = cat.Description
|
||||
ParentId = cat.ParentId
|
||||
})
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
| _ -> ()
|
||||
|
||||
type CategoryChildrenUpdateRecord =
|
||||
{ Children : string list }
|
||||
/// Update a category's children
|
||||
let updateChildren conn webLogId parentId (children : string list) =
|
||||
async {
|
||||
do! (category webLogId parentId)
|
||||
.Update({ CategoryChildrenUpdateRecord.Children = children })
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
match tryFindCategory conn webLogId parentId with
|
||||
| Some _ ->
|
||||
async {
|
||||
do! r.Table(Table.Category)
|
||||
.Get(parentId)
|
||||
.Update(dict [ "Children", children ])
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
| _ -> ()
|
||||
|
||||
type CategoryParentUpdateRecord =
|
||||
{ ParentId : string option }
|
||||
type PostCategoriesUpdateRecord =
|
||||
{ CategoryIds : string list }
|
||||
/// Delete a category
|
||||
let deleteCategory conn (cat : Category) =
|
||||
async {
|
||||
// Remove the category from its parent
|
||||
match cat.ParentId with
|
||||
| Some parentId -> match tryFindCategory conn cat.WebLogId parentId with
|
||||
| Some parent -> parent.Children
|
||||
|> List.filter (fun childId -> childId <> cat.Id)
|
||||
|> updateChildren conn cat.WebLogId parentId
|
||||
| _ -> ()
|
||||
| Some parentId ->
|
||||
match tryFindCategory conn cat.WebLogId parentId with
|
||||
| Some parent -> parent.Children
|
||||
|> List.filter (fun childId -> childId <> cat.Id)
|
||||
|> updateChildren conn cat.WebLogId parentId
|
||||
| _ -> ()
|
||||
| _ -> ()
|
||||
// Move this category's children to its parent
|
||||
let newParent = { CategoryParentUpdateRecord.ParentId = cat.ParentId }
|
||||
cat.Children
|
||||
|> List.map (fun childId ->
|
||||
async {
|
||||
do! (category cat.WebLogId childId)
|
||||
.Update(newParent)
|
||||
.RunResultAsync conn
|
||||
})
|
||||
|> List.iter Async.RunSynchronously
|
||||
match tryFindCategory conn cat.WebLogId childId with
|
||||
| Some _ ->
|
||||
async {
|
||||
do! r.Table(Table.Category)
|
||||
.Get(childId)
|
||||
.Update(dict [ "ParentId", cat.ParentId ])
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> Some
|
||||
| _ -> None)
|
||||
|> List.filter Option.isSome
|
||||
|> List.map Option.get
|
||||
|> List.iter Async.RunSynchronously
|
||||
// Remove the category from posts where it is assigned
|
||||
let! posts =
|
||||
r.Table(Table.Post)
|
||||
|
@ -105,13 +115,9 @@ let deleteCategory conn (cat : Category) =
|
|||
posts
|
||||
|> List.map (fun post ->
|
||||
async {
|
||||
let newCats =
|
||||
{ PostCategoriesUpdateRecord.CategoryIds = post.CategoryIds
|
||||
|> List.filter (fun c -> c <> cat.Id)
|
||||
}
|
||||
do! r.Table(Table.Post)
|
||||
.Get(post.Id)
|
||||
.Update(newCats)
|
||||
.Update(dict [ "CategoryIds", post.CategoryIds |> List.filter (fun c -> c <> cat.Id) ])
|
||||
.RunResultAsync conn
|
||||
})
|
||||
|> List.iter Async.RunSynchronously
|
||||
|
|
|
@ -62,6 +62,7 @@ type PageUpdateRecord =
|
|||
Permalink : string
|
||||
PublishedOn : int64
|
||||
UpdatedOn : int64
|
||||
ShowInPageList : bool
|
||||
Text : string
|
||||
Revisions : Revision list }
|
||||
/// Update a page
|
||||
|
@ -75,6 +76,7 @@ let updatePage conn (page : Page) =
|
|||
Permalink = page.Permalink
|
||||
PublishedOn = page.PublishedOn
|
||||
UpdatedOn = page.UpdatedOn
|
||||
ShowInPageList = page.ShowInPageList
|
||||
Text = page.Text
|
||||
Revisions = page.Revisions })
|
||||
.RunResultAsync conn
|
||||
|
|
|
@ -85,10 +85,12 @@ let tryFindOlderTaggedPost conn (tag : string) post =
|
|||
let findPageOfAllPosts conn (webLogId : string) pageNbr nbrPerPage =
|
||||
// FIXME: sort unpublished posts by their last updated date
|
||||
async {
|
||||
// .orderBy(r.desc(r.branch(r.row("Status").eq("Published"), r.row("PublishedOn"), r.row("UpdatedOn"))))
|
||||
return!
|
||||
r.Table(Table.Post)
|
||||
.GetAll(webLogId).OptArg("index", "WebLogId")
|
||||
.OrderBy(r.Desc "PublishedOn")
|
||||
.OrderBy(r.Desc (ReqlFunction1 (fun p ->
|
||||
upcast r.Branch (p.["Status"].Eq("Published"), p.["PublishedOn"], p.["UpdatedOn"]))))
|
||||
.Slice((pageNbr - 1) * nbrPerPage, pageNbr * nbrPerPage)
|
||||
.RunResultAsync<Post list> conn
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"AndPublished": " and Published",
|
||||
"andXMore": "and {0} more...",
|
||||
"at": "at",
|
||||
"BackToCategoryList": "Back to Category List",
|
||||
"BackToPageList": "Back to Page List",
|
||||
"BackToPostList": "Back to Post List",
|
||||
"Categories": "Categories",
|
||||
"Category": "Category",
|
||||
"CategoryDeleteWarning": "Are you sure you wish to delete the category",
|
||||
|
@ -36,7 +39,7 @@
|
|||
"MsgLogOffSuccess": "Log off successful | Have a nice day!",
|
||||
"MsgLogOnSuccess": "Log on successful | Welcome to myWebLog!",
|
||||
"MsgPageDeleted": "Deleted page successfully",
|
||||
"MsgPageEditSuccess": "{0} edited successfully",
|
||||
"MsgPageEditSuccess": "{0} page successfully",
|
||||
"MsgPostEditSuccess": "{0}{1} post successfully",
|
||||
"Name": "Name",
|
||||
"NewerPosts": "Newer Posts",
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
@AntiForgeryToken
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<a href="/categories" class="btn btn-default">
|
||||
<i class="fa fa-list-ul"></i> @Translate.BackToCategoryList
|
||||
</a>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="Name">@Translate.Name</label>
|
||||
<input type="text" class="form-control" id="Name" name="Name" value="@Model.Form.Name" />
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
@AntiForgeryToken
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<a href="/pages" class="btn btn-default">
|
||||
<i class="fa fa-list-ul"></i> @Translate.BackToPageList
|
||||
</a>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="Title">@Translate.Title</label>
|
||||
<input type="text" name="Title" id="Title" class="form-control" value="@Model.Form.Title" />
|
||||
|
@ -12,10 +15,11 @@
|
|||
<div class="form-group">
|
||||
<label class="control-label" for="Permalink">@Translate.Permalink</label>
|
||||
<input type="text" name="Permalink" id="Permalink" class="form-control" value="@Model.Form.Permalink" />
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.WebLog.UrlBase/ </p>
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> //@Model.WebLog.UrlBase/</p>
|
||||
</div>
|
||||
<!-- // TODO: Markdown / HTML choice -->
|
||||
<div class="form-group">
|
||||
<input type="hidden" name="Source" value="html" />
|
||||
<div class="form-group">
|
||||
<textarea name="Text" id="Text" rows="15" class="form-control">@Model.Form.Text</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,7 +38,7 @@
|
|||
</div>
|
||||
@EndIf
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="ShowInPageList" id="ShowInPageList" @Model.PageListChecked />
|
||||
<input type="checkbox" name="ShowInPageList" id="ShowInPageList" value="true" @Model.PageListChecked />
|
||||
<label for="ShowInPageList">@Translate.ShowInPageList</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
@AntiForgeryToken
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<a href="/posts/list" class="btn btn-default">
|
||||
<i class="fa fa-list-ul"></i> @Translate.BackToPostList
|
||||
</a>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="Title">@Translate.Title</label>
|
||||
<input type="text" name="Title" id="Title" class="form-control" value="@Model.Form.Title" />
|
||||
|
@ -12,10 +15,10 @@
|
|||
<div class="form-group">
|
||||
<label class="control-label" for="Permalink">@Translate.Permalink</label>
|
||||
<input type="text" name="Permalink" id="Permalink" class="form-control" value="@Model.Form.Permalink" />
|
||||
<!-- // FIXME: hard-coded "http" -->
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.WebLog.UrlBase/ </p>
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> //@Model.WebLog.UrlBase/ </p>
|
||||
</div>
|
||||
<!-- // TODO: Markdown / HTML choice -->
|
||||
<input type="hidden" name="Source" value="html" />
|
||||
<div class="form-group">
|
||||
<textarea name="Text" id="Text" rows="15">@Model.Form.Text</textarea>
|
||||
</div>
|
||||
|
@ -49,7 +52,7 @@
|
|||
<div class="panel-body" style="max-height:350px;overflow:scroll;">
|
||||
@Each.Categories
|
||||
@Current.Indent
|
||||
<input type="checkbox" id="Category-@Current.Id" name="Category" value="@Current.Id" @Current.CheckedAttr />
|
||||
<input type="checkbox" id="Category-@Current.Id" name="Categories" value="@Current.Id" @Current.CheckedAttr />
|
||||
|
||||
<label for="Category-@Current.Id" title="@Current.Description">@Current.Name</label>
|
||||
<br/>
|
||||
|
@ -62,7 +65,7 @@
|
|||
@EndIf
|
||||
@IfNot.IsPublished
|
||||
<div>
|
||||
<input type="checkbox" name="PublishNow" id="PublishNow" value="true" checked="checked" />
|
||||
<input type="checkbox" name="PublishNow" id="PublishNow" value="true" @Model.PublishNowCheckedAttr />
|
||||
<label for="PublishNow">@Translate.PublishThisPost</label>
|
||||
</div>
|
||||
@EndIf
|
||||
|
|
Loading…
Reference in New Issue
Block a user