2 people like it.

Generate an inline editor for ascx

Somewhat implementation coupled, but the ideas are pretty neat. works in linqpad, not sure what's up with this editor

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
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 """<input type="hidden" name="%s"/>"""
    {
        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 """<span data-role="%s" class="fieldDisplay"><%%#%s%%></span>""" x.Role keys.DisplayAccessor
                    |EditLink -> sprintf """<i  data-role="%s" class="onHover fa fa-pencil-square-o" title="edit"></i>""" x.Role
                    |Editor -> sprintf """<input data-role="%s" type="text" disabled="disabled" name="%s<%%# Eval("ProjectQuotaId") %%>" 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 """ <asp:TemplateColumn HeaderText="%s">
                            <ItemTemplate>
                                 <span data-role="%s">
                                        %s
                                        %s
                                        %s
                                    </span>
                                
                            </ItemTemplate>
                        </asp:TemplateColumn>""" 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"
    ()
namespace System
type Keys =
  {Header: string;
   Pascal: string;
   Camel: string;
   Field: string;
   DisplayAccessor: string;
   HiddenDom: string;}

Full name: Script.Keys
Keys.Header: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
Keys.Pascal: string
Keys.Camel: string
Keys.Field: string
Keys.DisplayAccessor: string
Keys.HiddenDom: string
val toPascalCase : s:seq<char> -> string

Full name: Script.toPascalCase
val s : seq<char>
module Seq

from Microsoft.FSharp.Collections
val mapi : mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.mapi
val i : int
val l : char
type Char =
  struct
    member CompareTo : value:obj -> int + 1 overload
    member Equals : obj:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member GetTypeCode : unit -> TypeCode
    member ToString : unit -> string + 1 overload
    static val MaxValue : char
    static val MinValue : char
    static member ConvertFromUtf32 : utf32:int -> string
    static member ConvertToUtf32 : highSurrogate:char * lowSurrogate:char -> int + 1 overload
    static member GetNumericValue : c:char -> float + 1 overload
    ...
  end

Full name: System.Char
Char.IsLower(c: char) : bool
Char.IsLower(s: string, index: int) : bool
Char.ToUpper(c: char) : char
Char.ToUpper(c: char, culture: Globalization.CultureInfo) : char
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
String.Concat([<ParamArray>] values: string []) : string
   (+0 other overloads)
String.Concat(values: Collections.Generic.IEnumerable<string>) : string
   (+0 other overloads)
String.Concat<'T>(values: Collections.Generic.IEnumerable<'T>) : string
   (+0 other overloads)
String.Concat([<ParamArray>] args: obj []) : string
   (+0 other overloads)
String.Concat(arg0: obj) : string
   (+0 other overloads)
String.Concat(str0: string, str1: string) : string
   (+0 other overloads)
String.Concat(arg0: obj, arg1: obj) : string
   (+0 other overloads)
String.Concat(str0: string, str1: string, str2: string) : string
   (+0 other overloads)
String.Concat(arg0: obj, arg1: obj, arg2: obj) : string
   (+0 other overloads)
String.Concat(str0: string, str1: string, str2: string, str3: string) : string
   (+0 other overloads)
val humanize : camel:seq<char> -> string

Full name: Script.humanize
val camel : seq<char>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val pascalCased : string
val skip : count:int -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skip
Char.IsUpper(c: char) : bool
Char.IsUpper(s: string, index: int) : bool
val createKeys : camel:string -> field:string -> header:string -> accessor:(string -> string) -> Keys

Full name: Script.createKeys
val camel : string
val field : string
val header : string
val accessor : (string -> string)
val hidden : (string -> string)
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val AllKeys : seq<Keys>

Full name: Script.AllKeys
val formattedPositiveIntAccessor : (string -> string)
val defaultAccessor : (string -> string)
val reqMembersAccessor : (string -> string)
type InlineEditorComponent =
  | Display
  | Editor
  | EditLink
  | ItemChild

Full name: Script.InlineEditorComponent
union case InlineEditorComponent.Display: InlineEditorComponent
union case InlineEditorComponent.Editor: InlineEditorComponent
union case InlineEditorComponent.EditLink: InlineEditorComponent
union case InlineEditorComponent.ItemChild: InlineEditorComponent
Multiple items
type ClientSelector =
  new : inlineComponent:InlineEditorComponent * keys:Keys -> ClientSelector
  member DataRole : string
  member Dom : string
  member InlineComponent : InlineEditorComponent
  member Name : string
  member Role : string
  static member private dataRoleSelector : (string -> string -> string)
  static member private makeRole : c:InlineEditorComponent -> (string -> string)

Full name: Script.ClientSelector

--------------------
new : inlineComponent:InlineEditorComponent * keys:Keys -> ClientSelector
val inlineComponent : InlineEditorComponent
val keys : Keys
static member private ClientSelector.makeRole : c:InlineEditorComponent -> (string -> string)

Full name: Script.ClientSelector.makeRole
val c : InlineEditorComponent
static member private ClientSelector.dataRoleSelector : (string -> string -> string)

Full name: Script.ClientSelector.dataRoleSelector
val x : ClientSelector
member ClientSelector.InlineComponent : InlineEditorComponent

Full name: Script.ClientSelector.InlineComponent
member ClientSelector.Name : string

Full name: Script.ClientSelector.Name
static member private ClientSelector.makeRole : c:InlineEditorComponent -> (string -> string)
member ClientSelector.Role : string

Full name: Script.ClientSelector.Role
property ClientSelector.Name: string
member ClientSelector.DataRole : string

Full name: Script.ClientSelector.DataRole
property ClientSelector.dataRoleSelector: string -> string -> string
property ClientSelector.Role: string
member ClientSelector.Dom : string

Full name: Script.ClientSelector.Dom
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
type HandlerArgs =
  {StorageKey: string;
   HiddenName: string;
   EditorSelector: string;}

Full name: Script.HandlerArgs
HandlerArgs.StorageKey: string
HandlerArgs.HiddenName: string
HandlerArgs.EditorSelector: string
type InitializeHandlerArgs =
  {EditLinkSelector: string;
   ChildSelector: string;}

Full name: Script.InitializeHandlerArgs
InitializeHandlerArgs.EditLinkSelector: string
InitializeHandlerArgs.ChildSelector: string
Multiple items
type ClientSelectorCollection =
  new : keys:Keys -> ClientSelectorCollection
  member Asp : string
  member Display : ClientSelector
  member EditLink : ClientSelector
  member Editor : ClientSelector
  member HandlerArgs : HandlerArgs
  member ItemChild : ClientSelector
  member JsBeforeReq : string
  member JsClientSelectors : string
  member JsInitialize : string
  ...

Full name: Script.ClientSelectorCollection

--------------------
new : keys:Keys -> ClientSelectorCollection
val createClient : (InlineEditorComponent -> ClientSelector)
val com : InlineEditorComponent
val x : ClientSelectorCollection
Multiple items
member ClientSelectorCollection.Keys : Keys

Full name: Script.ClientSelectorCollection.Keys

--------------------
type Keys =
  {Header: string;
   Pascal: string;
   Camel: string;
   Field: string;
   DisplayAccessor: string;
   HiddenDom: string;}

Full name: Script.Keys
member ClientSelectorCollection.Display : ClientSelector

Full name: Script.ClientSelectorCollection.Display
member ClientSelectorCollection.Editor : ClientSelector

Full name: Script.ClientSelectorCollection.Editor
member ClientSelectorCollection.EditLink : ClientSelector

Full name: Script.ClientSelectorCollection.EditLink
member ClientSelectorCollection.ItemChild : ClientSelector

Full name: Script.ClientSelectorCollection.ItemChild
member ClientSelectorCollection.Asp : string

Full name: Script.ClientSelectorCollection.Asp
property ClientSelectorCollection.ItemChild: ClientSelector
property ClientSelectorCollection.EditLink: ClientSelector
property ClientSelector.Dom: string
property ClientSelectorCollection.Display: ClientSelector
property ClientSelectorCollection.Editor: ClientSelector
member ClientSelectorCollection.Selectors : ClientSelector list

Full name: Script.ClientSelectorCollection.Selectors
member ClientSelectorCollection.JsClientSelectors : string

Full name: Script.ClientSelectorCollection.JsClientSelectors
property ClientSelector.DataRole: string
Multiple items
member ClientSelectorCollection.HandlerArgs : HandlerArgs

Full name: Script.ClientSelectorCollection.HandlerArgs

--------------------
type HandlerArgs =
  {StorageKey: string;
   HiddenName: string;
   EditorSelector: string;}

Full name: Script.HandlerArgs
member ClientSelectorCollection.JsBeforeReq : string

Full name: Script.ClientSelectorCollection.JsBeforeReq
property ClientSelectorCollection.HandlerArgs: HandlerArgs
member ClientSelectorCollection.JsInitialize : string

Full name: Script.ClientSelectorCollection.JsInitialize
val k : Keys
val csColl : ClientSelectorCollection
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
property ClientSelectorCollection.Asp: string
property ClientSelectorCollection.Selectors: ClientSelector list
property ClientSelectorCollection.JsClientSelectors: string
property ClientSelectorCollection.JsBeforeReq: string
property ClientSelectorCollection.JsInitialize: string
val targetJs : string
val targetAspx : string
val targetAscx : string
val targetJsTextValidation : unit
val text : string
namespace System.IO
type File =
  static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
  static member AppendAllText : path:string * contents:string -> unit + 1 overload
  static member AppendText : path:string -> StreamWriter
  static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
  static member Create : path:string -> FileStream + 3 overloads
  static member CreateText : path:string -> StreamWriter
  static member Decrypt : path:string -> unit
  static member Delete : path:string -> unit
  static member Encrypt : path:string -> unit
  static member Exists : path:string -> bool
  ...

Full name: System.IO.File
IO.File.ReadAllText(path: string) : string
IO.File.ReadAllText(path: string, encoding: Text.Encoding) : string
val missingSelectors : seq<string>
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val x : string
String.Contains(value: string) : bool
val isEmpty : source:seq<'T> -> bool

Full name: Microsoft.FSharp.Collections.Seq.isEmpty
val targetAspxValidation : unit
property ClientSelectorCollection.Keys: Keys
val targetAscxValidation : unit
val s : ClientSelector
property ClientSelector.InlineComponent: InlineEditorComponent
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
Raw view Test code New version

More information

Link:http://fssnip.net/nz
Posted:10 years ago
Author:Brandon Dimperio (@MaslowJax)
Tags: webforms , javascript