WIP on Fluid model/filters
This commit is contained in:
+62
-10
@@ -1,8 +1,14 @@
|
||||
module MyWebLog.Template
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.IO
|
||||
open System.Text
|
||||
open Fluid
|
||||
open Fluid.Values
|
||||
open Giraffe.ViewEngine
|
||||
open Microsoft.AspNetCore.Antiforgery
|
||||
open Microsoft.Extensions.FileProviders
|
||||
open MyWebLog
|
||||
open MyWebLog.ViewModels
|
||||
|
||||
@@ -48,10 +54,21 @@ module private Helpers =
|
||||
|
||||
|
||||
/// Fluid template options customized with myWebLog filters
|
||||
let options =
|
||||
let options () =
|
||||
let sValue = StringValue >> VTask<FluidValue>
|
||||
|
||||
let it = TemplateOptions.Default
|
||||
it.MemberAccessStrategy.MemberNameStrategy <- MemberNameStrategies.SnakeCase
|
||||
[ // Domain types
|
||||
typeof<CustomFeed>; typeof<Episode>; typeof<Episode option>; typeof<MetaItem>; typeof<Page>; typeof<RssOptions>
|
||||
typeof<TagMap>; typeof<WebLog>
|
||||
// View models
|
||||
typeof<AppViewContext>; typeof<DisplayCategory>; typeof<DisplayPage>; typeof<EditPageModel>; typeof<PostDisplay>
|
||||
typeof<PostListItem>; typeof<UserMessage>
|
||||
// Framework types
|
||||
typeof<AntiforgeryTokenSet>; typeof<DateTime option>; typeof<int option>; typeof<KeyValuePair>
|
||||
typeof<MetaItem list>; typeof<string list>; typeof<string option>; typeof<TagMap list> ]
|
||||
|> List.iter it.MemberAccessStrategy.Register
|
||||
|
||||
// A filter to generate an absolute link
|
||||
it.Filters.AddFilter("absolute_link", fun input _ ctx -> sValue (permalink input ctx.App.WebLog.AbsoluteUrl))
|
||||
@@ -132,12 +149,14 @@ let options =
|
||||
// A filter to retrieve the value of a meta item from a list
|
||||
// (shorter than `{% assign item = list | where: "Name", [name] | first %}{{ item.value }}`)
|
||||
it.Filters.AddFilter("value",
|
||||
fun input args _ ->
|
||||
let items = input.ToObjectValue() :?> MetaItem list
|
||||
let name = args.At(0).ToStringValue()
|
||||
match items |> List.tryFind (fun it -> it.Name = name) with
|
||||
| Some item -> item.Value
|
||||
| None -> $"-- {name} not found --"
|
||||
fun input args ctx ->
|
||||
let name = args.At(0).ToStringValue()
|
||||
let picker (value: FluidValue) =
|
||||
let item = value.ToObjectValue() :?> MetaItem
|
||||
if item.Name = name then Some item.Value else None
|
||||
(input :?> ArrayValue).Values
|
||||
|> Seq.tryPick picker
|
||||
|> Option.defaultValue $"-- {name} not found --"
|
||||
|> sValue)
|
||||
|
||||
it
|
||||
@@ -234,11 +253,13 @@ let parser =
|
||||
|
||||
it
|
||||
|
||||
|
||||
open MyWebLog.Data
|
||||
|
||||
/// Cache for parsed templates
|
||||
module Cache =
|
||||
|
||||
open System.Collections.Concurrent
|
||||
open MyWebLog.Data
|
||||
|
||||
/// Cache of parsed templates
|
||||
let private _cache = ConcurrentDictionary<string, IFluidTemplate> ()
|
||||
@@ -277,6 +298,37 @@ module Cache =
|
||||
_cache.Clear()
|
||||
|
||||
|
||||
/// A file provider to retrieve files by theme
|
||||
type ThemeFileProvider(themeId: ThemeId, data: IData) =
|
||||
|
||||
interface IFileProvider with
|
||||
|
||||
member _.GetDirectoryContents _ =
|
||||
raise <| NotImplementedException "The theme file provider does not support directory listings"
|
||||
|
||||
member _.GetFileInfo path =
|
||||
match data.Theme.FindById themeId |> Async.AwaitTask |> Async.RunSynchronously with
|
||||
| Some theme ->
|
||||
match theme.Templates |> List.tryFind (fun t -> t.Name = path) with
|
||||
| Some template ->
|
||||
{ new IFileInfo with
|
||||
member _.Exists = true
|
||||
member _.IsDirectory = false
|
||||
member _.LastModified = DateTimeOffset.Now
|
||||
member _.Length = int64 template.Text.Length
|
||||
member _.Name = template.Name.Split '/' |> Array.last
|
||||
member _.PhysicalPath = null
|
||||
member _.CreateReadStream() =
|
||||
new MemoryStream(Encoding.UTF8.GetBytes template.Text) }
|
||||
| None -> NotFoundFileInfo path
|
||||
| None -> NotFoundFileInfo path
|
||||
|
||||
member _.Watch _ =
|
||||
raise <| NotImplementedException "The theme file provider does not support watching for changes"
|
||||
|
||||
|
||||
/// Render a template to a string
|
||||
let render (template: IFluidTemplate) (viewCtx: AppViewContext) =
|
||||
template.Render(TemplateContext(viewCtx, options, true))
|
||||
let render (template: IFluidTemplate) (viewCtx: AppViewContext) data =
|
||||
let opts = options ()
|
||||
opts.FileProvider <- ThemeFileProvider(viewCtx.WebLog.ThemeId, data)
|
||||
template.Render(TemplateContext(viewCtx, opts, true))
|
||||
|
||||
Reference in New Issue
Block a user