Source file vue_js.ml

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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
open Js_of_ocaml
open Js
open Mjs

type 'all vue = 'all t

class type ['data, 'all, 'state] vue_arg = object
  method el : js_string t readonly_prop
  method data : 'data t readonly_prop
  method computed : ('all t, unit -> any optdef) meth_callback table optdef readonly_prop
  method watch : ('all t, any -> any -> any) meth_callback table optdef readonly_prop
  method methods : any table optdef readonly_prop
  method components : (top, top) Vue_component.Internal.component_arg table optdef readonly_prop
  method router : Vue_router.router optdef readonly_prop
  method store : 'state Vuex.store optdef readonly_prop
end

type ('data, 'all, 'state) vue_cs = (('data, 'all, 'state) vue_arg t -> 'all t) constr

let make ?computed ?watch ?methods ?data ?components ?router ?store id =
  let data : 'data t = match data with None -> Unsafe.obj [||] | Some d -> d in
  let v : ('data, 'all, 'state) vue_arg t = object%js
    val el = string ("#" ^ id)
    val data = data
    val computed = optdef (to_tablef (fun c -> wrap_meth_callback (fun this () -> c this))) computed
    val watch = optdef (to_tablef wrap_meth_callback) watch
    val methods = optdef to_table methods
    val components = optdef to_table components
    val router = Optdef.option router
    val store = Optdef.option store
  end in
  let cs : ('data, 'all, 'state) vue_cs = Unsafe.global##._Vue in
  new%js cs v

let get_prop vm s = Unsafe.get vm @@ "$" ^ s
let get_ref vm id =
  let refs = get_prop vm "refs" in
  Unsafe.get refs id

let get_router vm = get_prop vm "router"
let get_store vm = get_prop vm "store"
let get_route vm = get_prop vm "route"

let unhide ?(suffix="loading") id =
  (match Dom_html.getElementById_opt id with
   | None -> ()
   | Some app -> app##.style##.display := string "block");
  match Dom_html.getElementById_opt (id ^ "-" ^ suffix) with
  | None -> ()
  | Some loading -> loading##.style##.display := string "none"

module Make(S : sig
    type data
    type all
    val id : string
  end) = struct

  include Vue_component.Tables(struct type all = S.all end)

  let app : all t ref = ref (Unsafe.obj [||])

  let init ?(export=true) ?(data : S.data t option) ?(show=false) ?suffix
      ?router ?store () =
    app :=
      make
        ?data
        ~methods:(T methods_t)
        ~watch:(T watch_t)
        ~computed:(T computed_t)
        ~components:(T components_t)
        ?router
        ?store
        S.id;
    if show then unhide ?suffix S.id;
    if export then Js.export S.id !app;
    !app

  let app () = !app

end

module SPA(S : sig
    type data
    type all
    type state
    val name : string
    val template : string
    val props : string list
  end) = struct

  type data = S.data
  include Vuex.Module(struct type state = S.state end)
  include Vue_component.Tables(struct type all = S.all end)
  include Vue_router.Tables

  let store : state Vuex.module_obj ref = ref (Unsafe.obj [||])
  let route : (data, all) Vue_router.Internal.route t ref = ref (Unsafe.obj [||])

  let init ?getters ?mutations ?actions ?modules ?computed ?methods ?watch ?components
      ?children ?hook ?path ~data ~state () =
    merge_lists_component ?computed ?methods ?watch ?components ();
    merge_routes ?routes:children ();
    let st = get ?getters ?mutations ?actions ?modules ~namespaced:true state in
    let computed = Table.merge [
        computed_t;
        Vuex.Map.state ~namespace:S.name (to_listf to_string @@ object_keys state);
        Vuex.Map.getters ~namespace:S.name (Table.keys getters_t) ] in
    let methods = Table.merge [
        methods_t;
        Vuex.Map.mutations ~namespace:S.name (Table.keys mutations_t);
        Vuex.Map.actions ~namespace:S.name (Table.keys actions_t);
      ] in
    let component = Some {
        Vue_component.empty with
        Vue_component.template = Some S.template;
        props = Some (Vue_component.PrsArray S.props);
        data = Some (fun _ -> data);
        computed = Some (T computed);
        methods = Some (T methods);
        watch = Some (T watch_t);
        components = T components_t;
        name = Some S.name } in
    let path = match path with None -> "/" ^ S.name | Some path -> path in
    let r = Vue_router.Internal.make_route_base {
        (Vue_router.empty path) with
        Vue_router.component;
        props = (match S.props with [] -> None | _ -> Some (Vue_router.PrBool true));
        children = Some !routes_t;
        hook
      } in
    store := st;
    route := r;
    S.name, st, r

  let store () = !store
  let route () = !route

end

module Root(S : sig
    type data
    type all
    type state
    val id : string
  end) = struct

  type data = S.data
  include Vuex.Make(struct type state = S.state end)
  include Vue_component.Tables(struct type all = S.all end)
  include Vue_router.Tables

  let app : all vue ref = ref (Unsafe.obj [||])
  let router : Vue_router.router ref = ref (Unsafe.obj [||])

  let init ?getters ?mutations ?actions ?modules ?computed ?methods ?watch
      ?components ?routes ?strict ?devtools ?plugins ?mode
      ?(show=false) ?(export=true) ?suffix ~(data: data t) ~state () =
    merge_lists_component ?computed ?methods ?watch ?components ();
    merge_routes ?routes ();
    let store = init ?plugins ?getters ?mutations ?actions ?modules ?strict ?devtools state in
    let computed = Table.merge [
        computed_t;
        Vuex.Map.state (to_listf to_string @@ object_keys state);
        Vuex.Map.getters (Table.keys getters_t);
      ] in
    let methods = Table.merge [
        methods_t;
        Vuex.Map.mutations (Table.keys mutations_t);
        Vuex.Map.actions (Table.keys actions_t);
      ] in
    let rt = new%js Vue_router.Internal.vue_router_cs
      (Vue_router.Internal.make_args_base ?mode !routes_t) in
    router := rt;
    app :=
      make
        ~data
        ~methods:(T methods)
        ~watch:(T watch_t)
        ~computed:(T computed)
        ~components:(T components_t)
        ~router:rt
        ~store
        S.id;
    if show then unhide ?suffix S.id;
    if export then Js.export S.id !app;
    !app

  let router () = !router
  let app () = !app

end