/// Logic to work with Fluid templates module MyWebLog.Template open System open System.Collections.Generic open System.IO open System.Text open Fluid open Fluid.Values open Microsoft.AspNetCore.Antiforgery open Microsoft.Extensions.FileProviders open MyWebLog open MyWebLog.ViewModels /// Alias for ValueTask type VTask<'T> = System.Threading.Tasks.ValueTask<'T> /// Extensions on Fluid's TemplateContext object type TemplateContext with /// Get the model of the context as an AppViewContext instance member this.App = this.Model.ToObjectValue() :?> AppViewContext /// Helper functions for filters and tags [] module private Helpers = /// Does an asset exist for the current theme? /// The name of the asset /// The current web log /// True if the theme has the requested asset name, false if not let assetExists fileName (webLog: WebLog) = ThemeAssetCache.get webLog.ThemeId |> List.exists (fun it -> it = fileName) /// Obtain the link from known types /// The FluidValue for the given parameter /// The function to extract the value of the link into a string /// The link as a string, or JavaScript to show an alert if a link cannot be determined let permalink (item: FluidValue) (linkFunc: Permalink -> string) = match item.Type with | FluidValues.String -> Some (item.ToStringValue()) | FluidValues.Object -> match item.ToObjectValue() with | :? DisplayPage as page -> Some page.Permalink | :? PostListItem as post -> Some post.Permalink | :? Permalink as link -> Some (string link) | _ -> None | _ -> None |> function | Some link -> linkFunc (Permalink link) | None -> $"alert('unknown item type {item.Type}')" /// Generate a link for theme asset (image, stylesheet, script, etc.) /// The name of the theme asset /// The template context for the current template rendering /// A relative URL for the given theme asset let themeAsset (input: FluidValue) (ctx: TemplateContext) = let app = ctx.App app.WebLog.RelativeUrl(Permalink $"themes/{app.WebLog.ThemeId}/{input.ToStringValue()}") /// Fluid template options customized with myWebLog filters /// A TemplateOptions instance with all myWebLog filters and types registered let options () = let sValue = StringValue >> VTask let it = TemplateOptions.Default it.MemberAccessStrategy.MemberNameStrategy <- MemberNameStrategies.SnakeCase [ // Domain types typeof; typeof; typeof; typeof; typeof; typeof typeof; typeof // View models typeof; typeof; typeof; typeof; typeof typeof; typeof // Framework types typeof; typeof; typeof; typeof typeof; typeof; typeof; typeof ] |> 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)) // A filter to generate a link with posts categorized under the given category it.Filters.AddFilter("category_link", fun input _ ctx -> match input.ToObjectValue() with | :? DisplayCategory as cat -> Some cat.Slug | :? string as slug -> Some slug | _ -> None |> function | Some slug -> ctx.App.WebLog.RelativeUrl(Permalink $"category/{slug}/") | None -> $"alert('unknown category object type {input.Type}')" |> sValue) // A filter to generate a link that will edit a page it.Filters.AddFilter("edit_page_link", fun input _ ctx -> match input.ToObjectValue() with | :? DisplayPage as page -> Some page.Id | :? string as theId -> Some theId | _ -> None |> function | Some pageId -> ctx.App.WebLog.RelativeUrl(Permalink $"admin/page/{pageId}/edit") | None -> $"alert('unknown page object type {input.Type}')" |> sValue) // A filter to generate a link that will edit a post it.Filters.AddFilter("edit_post_link", fun input _ ctx -> match input.ToObjectValue() with | :? PostListItem as post -> Some post.Id | :? string as theId -> Some theId | _ -> None |> function | Some postId -> ctx.App.WebLog.RelativeUrl(Permalink $"admin/post/{postId}/edit") | None -> $"alert('unknown post object type {input.Type}')" |> sValue) // A filter to generate nav links, highlighting the active link (starts-with match) it.Filters.AddFilter("nav_link", fun input args ctx -> let app = ctx.App let extraPath = app.WebLog.ExtraPath let path = if extraPath = "" then "" else $"{extraPath[1..]}/" let url = input.ToStringValue() seq { "