open System type Keys = {Header:string;Pascal:string;Camel:string;Field:string;DisplayAccessor:string;HiddenDom:string} let toPascalCase s = s |> Seq.mapi (fun i l -> if i=0 && Char.IsLower(l) then Char.ToUpper(l) else l) |> String.Concat let humanize camel :string = seq { let pascalCased = toPascalCase camel yield pascalCased.[0] for l in pascalCased |> Seq.skip(1) do if System.Char.IsUpper(l) then yield ' ' yield l else yield l } |> String.Concat let createKeys camel field header accessor = let hidden = sprintf """""" { Keys.Header=header Field=field DisplayAccessor = accessor field Camel=camel HiddenDom= hidden field Pascal= toPascalCase camel //FromCamel } let AllKeys = let formattedPositiveIntAccessor = sprintf """GetFormattedPositiveInt(Eval("%s"))""" let defaultAccessor = sprintf """Eval("%s")""" let reqMembersAccessor = sprintf """GetRequestedMembers(Eval("%s")) + (Convert.ToBoolean(Eval("IsQuotaCap")) ? "*" : "")""" seq { yield(createKeys "overQuotaCap" "OverQuotaCap" "OverQuota Cap" formattedPositiveIntAccessor) yield(createKeys "reqCompletes" "RequestedMembers" "Requested Completes" reqMembersAccessor) } // type InlineEditorComponent = |Display |Editor |EditLink |ItemChild type ClientSelector(inlineComponent:InlineEditorComponent,keys) = //let roles = { InlineEditorRole.Display = sprintf "%sDisplay" keys.Pascal; Editor=sprintf "%sEditor" keys.Pascal;EditLink=sprintf "%sEditLink" keys.Pascal;ItemChild=sprintf "%sItemChild" keys.Pascal} static member private makeRole c = match c with |Display -> sprintf "%sDisplay" |Editor -> sprintf "%sEditor" |EditLink -> sprintf "%sEditLink" |ItemChild -> sprintf "%sItemChild" static member private dataRoleSelector = sprintf "%s: '[data-role=%s]'" member x.InlineComponent = inlineComponent member x.Name = ClientSelector.makeRole inlineComponent keys.Pascal member x.Role = x.Name member x.DataRole = ClientSelector.dataRoleSelector x.Name x.Role member x.Dom = match inlineComponent with |Display -> sprintf """<%%#%s%%>""" x.Role keys.DisplayAccessor |EditLink -> sprintf """""" x.Role |Editor -> sprintf """" style="display:none;width:90px" value="" data-original-value="" data-quotaGroupId="<%%# Eval("ProjectQuotaId") %%>"/>""" x.Role keys.Pascal |ItemChild-> failwithf "Can't generate dom for itemChild directly" type HandlerArgs = {StorageKey:string; HiddenName:string; EditorSelector:string} type InitializeHandlerArgs = {EditLinkSelector:string;ChildSelector:string;} type ClientSelectorCollection(keys) = let createClient com = ClientSelector(com,keys) member x.Keys = keys member x.Display = createClient InlineEditorComponent.Display member x.Editor = createClient InlineEditorComponent.Editor member x.EditLink = createClient InlineEditorComponent.EditLink member x.ItemChild = createClient InlineEditorComponent.ItemChild member x.Asp = sprintf """ %s %s %s """ keys.Header x.ItemChild.Role x.EditLink.Dom x.Display.Dom x.Editor.Dom member x.Selectors = [ x.Display x.Editor x.EditLink x.ItemChild ] member x.JsClientSelectors = sprintf """ %s, %s, %s, %s""" x.Display.DataRole x.Editor.DataRole x.EditLink.DataRole x.ItemChild.DataRole member x.HandlerArgs = {HandlerArgs.StorageKey=keys.Camel+"Edits"; HiddenName=keys.Camel+"Edits";EditorSelector = sprintf "%sEditor" keys.Camel} member x.JsBeforeReq = //before save or updatePanel request starts sprintf """beforeSavePostHandler(currentTabIsQuotaGroups, quotaGroupTabStorage, '%s', '%s', clientSelectors.%s, $qgGrid);""" x.HandlerArgs.StorageKey x.HandlerArgs.HiddenName x.HandlerArgs.EditorSelector member x.JsInitialize = sprintf """quotaGridInlineEditsInitializeHandler(clientSelectors.%s, clientSelectors.%s, clientSelectors.%s, clientSelectors.quotaGroupIdAttr, clientSelectors.%s, quotaGroupTabStorage, '%s');""" x.EditLink.Name x.ItemChild.Name x.Editor.Name x.Display.Name x.HandlerArgs.StorageKey for k in AllKeys do let csColl = ClientSelectorCollection(k) printfn "%A" (k,csColl.Asp,csColl.Selectors,csColl.JsClientSelectors,csColl.JsBeforeReq,csColl.JsInitialize) //validation let targetJs = """c:\development\products\app\web\lib\javascript\editproject.js""" let targetAspx = """c:\development\products\app\web\pages\projects\editproject.aspx""" let targetAscx = """c:\development\products\app\web\pages\projects\usercontrols\quotagroups.ascx""" let targetJsTextValidation = let text = System.IO.File.ReadAllText(targetJs) let missingSelectors = csColl.Selectors |>Seq.map (fun x->x.DataRole) |>Seq.filter(fun x->text.Contains(x)=false) if Seq.isEmpty(missingSelectors)=false then failwithf "some expected .js lines were missing %A" missingSelectors if text.Contains(csColl.JsBeforeReq)=false then failwithf ".js: missing call(s) to beforeSavePostHandler %A" csColl.JsBeforeReq if text.Contains(csColl.JsInitialize)= false then failwithf ".js: missing call(s) to InitializeHandler %A" csColl.JsInitialize printfn "js tests passed" let targetAspxValidation = let text = System.IO.File.ReadAllText(targetAspx) if text.Contains(csColl.Keys.HiddenDom)=false then failwithf ".aspx: missing %A" csColl.Keys.HiddenDom printfn "aspx tests passed" let targetAscxValidation = let text = System.IO.File.ReadAllText(targetAscx) csColl.Selectors |> Seq.filter (fun s-> s.InlineComponent <> InlineEditorComponent.ItemChild) |> Seq.iter (fun s -> if text.Contains(s.Dom) = false then failwithf ".ascx: missing %A" s.Dom ) printfn "ascx tests passed" ()