(* The TodoMVC page, rendered from shared/reference.html. The no-JS controls carry the class "nojs"; app.css hides them once app.js has loaded. *) type filter = All | Active | Completed let filter_of_string = function "active" -> Active | "completed" -> Completed | _ -> All let filter_name = function All -> "all" | Active -> "active" | Completed -> "completed" let filter_path = function All -> "/" | Active -> "/active" | Completed -> "/completed" let shows filter (t : Store.todo) = match filter with All -> true | Active -> not t.completed | Completed -> t.completed let escape s = let b = Buffer.create (String.length s + 16) in String.iter (function | '&' -> Buffer.add_string b "&" | '<' -> Buffer.add_string b "<" | '>' -> Buffer.add_string b ">" | '"' -> Buffer.add_string b """ | '\'' -> Buffer.add_string b "'" | c -> Buffer.add_char b c) s; Buffer.contents b (* A hidden form that a control elsewhere submits with form="". *) let action_form b ~id ~action filter = Printf.bprintf b {||} id action (filter_name filter) let item b filter ~editing (t : Store.todo) = let title = escape t.title in let classes = List.filter_map Fun.id [ (if t.completed then Some "completed" else None); (if editing then Some "editing" else None) ] in Printf.bprintf b {|
  • |} t.id (if classes = [] then "" else Printf.sprintf {| class="%s"|} (String.concat " " classes)); Printf.bprintf b {||} t.id (if t.completed then " checked" else "") title; Printf.bprintf b {||} t.id; Printf.bprintf b {||} t.id (if t.completed then "Mark as active" else "Mark as completed"); Printf.bprintf b {|Edit
    |} (filter_path filter) t.id; Printf.bprintf b {|
    |} t.id (filter_name filter) title (if editing then " autofocus" else ""); action_form b ~id:(Printf.sprintf "toggle-%d" t.id) ~action:(Printf.sprintf "/todos/%d/toggle" t.id) filter; action_form b ~id:(Printf.sprintf "destroy-%d" t.id) ~action:(Printf.sprintf "/todos/%d/destroy" t.id) filter; Buffer.add_string b "
  • " (* section.todoapp: the part app.js swaps after each action. *) let todoapp b ~filter ?editing (todos : Store.todo list) = let left = List.length (List.filter (fun (t : Store.todo) -> not t.completed) todos) in let done_ = List.length todos - left in Printf.bprintf b {|

    todos

    |} (filter_name filter) (if editing = None then " autofocus" else ""); if todos <> [] then begin Buffer.add_string b {|
    |}; action_form b ~id:"toggle-all-form" ~action:"/todos/toggle-all" filter; Printf.bprintf b {||} (if left = 0 then " checked" else ""); Buffer.add_string b {|
      |}; List.iter (fun (t : Store.todo) -> if shows filter t then item b filter ~editing:(editing = Some t.id) t) todos; Buffer.add_string b {|
    |}; Printf.bprintf b {|%d %s left
      |} left (if left = 1 then "item" else "items"); List.iter (fun (f, label) -> Printf.bprintf b {|
    • %s
    • |} (if f = filter then {| class="selected"|} else "") (filter_path f) label) [ (All, "All"); (Active, "Active"); (Completed, "Completed") ]; Buffer.add_string b "
    "; if done_ > 0 then begin action_form b ~id:"clear-completed-form" ~action:"/todos/clear-completed" filter; Buffer.add_string b {||} end; Buffer.add_string b "
    " end; Buffer.add_string b "
    " let fragment ~filter todos = let b = Buffer.create 4096 in todoapp b ~filter todos; Buffer.contents b let page ~version ~filter ?editing todos = let b = Buffer.create 8192 in Printf.bprintf b {| TodoMVC |} version version version version; todoapp b ~filter ?editing todos; Buffer.add_string b {| |}; Buffer.contents b