package jsoo-react
Bindings to ReactJS for js_of_ocaml, including JSX ppx
Install
Dune Dependency
Authors
Maintainers
Sources
0.1.tar.gz
sha256=93d5751c01016f5aa018b80259df0c65ac12f25152cef1dbcff024ddfc1f07b5
md5=240fd3b58cb002ff7eaa6ddddb7eba87
doc/src/jsoo-react.lib/router.ml.html
Source file router.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
(* Adapted from reason-react: https://reasonml.github.io/reason-react/docs/en/router *) module Browser = [%js: type history type window val window_to_js : window -> Ojs.t type location val history : history option [@@js.global "history"] val window : window option [@@js.global "window"] val location : window -> location [@@js.get] val pathname : location -> string [@@js.get] val hash : location -> string [@@js.get] val search : location -> string [@@js.get] val push_state : history -> Ojs.t -> string -> href:string -> unit [@@js.call "pushState"] val replace_state : history -> Ojs.t -> string -> href:string -> unit [@@js.call "replaceState"]] module Event = [%js: type t val event : t [@@js.global "Event"] val make_event_ie11_compatible : string -> t [@@js.new "Event"] val create_event_non_ie8 : string -> t [@@js.global "document.createEvent"] val init_event_non_ie8 : t -> string -> bool -> bool -> unit [@@js.call "initEvent"] (* The cb is t => unit, but access is restricted for now *) val add_event_listener : Browser.window -> string -> (unit -> unit) -> unit [@@js.call "addEventListener"] val remove_event_listener : Browser.window -> string -> (unit -> unit) -> unit [@@js.call "removeEventListener"] val dispatch_event : Browser.window -> t -> unit [@@js.call "dispatchEvent"]] let safe_make_event eventName = if let open Js_of_ocaml in Js.typeof (Js.Unsafe.inject Event.event) = Js.string "function" then Event.make_event_ie11_compatible eventName else let event = Event.create_event_non_ie8 "Event" in Event.init_event_non_ie8 event eventName true true; Event.event let slice_to_end s = match s = "" with true -> "" | false -> String.sub s 1 (String.length s - 1) (* if we ever roll our own parser in the future, make sure you test all url combinations e.g. foo.com/?#bar *) (* URLSearchParams doesn't work on IE11, edge16, etc. *) (* The library doesn't provide search for now. Users can roll their own solution/data structure.*) let path () = match Browser.window with | None -> [] | Some w -> ( match let open Browser in w |> location |> pathname with | "" | "/" -> [] | raw -> let raw = slice_to_end raw in let raw = let n = String.length raw in match n > 0 && raw.[n - 1] = '/' with | true -> String.sub raw 0 (n - 1) | false -> raw in raw |> String.split_on_char '/') let hash () = match Browser.window with | None -> "" | Some w -> ( match let open Browser in w |> location |> hash with | "" | "#" -> "" | raw -> (* remove the preceeding #, which every hash seems to have. *) slice_to_end raw) let search () = match Browser.window with | None -> "" | Some w -> ( match let open Browser in w |> location |> search with | "" | "?" -> "" | raw -> (* remove the preceeding ?, which every search seems to have. *) slice_to_end raw) let push path = match let open Browser in (history, window) with | None, _ | _, None -> () | Some history, Some window -> Browser.push_state history Ojs.null "" ~href:path; Event.dispatch_event window (safe_make_event "popstate") let replace path = match let open Browser in (history, window) with | None, _ | _, None -> () | Some history, Some window -> Browser.replace_state history Ojs.null "" ~href:path; Event.dispatch_event window (safe_make_event "popstate") type url = { path : string list ; hash : string ; search : string } let url_not_equal a b = let rec list_not_equal xs ys = match (xs, ys) with | [], [] -> false | [], _ :: _ | _ :: _, [] -> true | x :: xs, y :: ys -> if x != y then true else list_not_equal xs ys in a.hash != b.hash || a.search != b.search || list_not_equal a.path b.path type watcher_id = unit -> unit let url () = { path = path (); hash = hash (); search = search () } (* alias exposed publicly *) let dangerously_get_initial_url = url let watch_url callback = match Browser.window with | None -> fun () -> () | Some window -> let watcher_id () = callback (url ()) in Event.add_event_listener window "popstate" watcher_id; watcher_id let unwatch_url watcher_id = match Browser.window with | None -> () | Some window -> Event.remove_event_listener window "popstate" watcher_id let use_url ?server_url () = let url, set_url = Core.use_state (fun () -> match server_url with | Some url -> url | None -> dangerously_get_initial_url ()) in Core.use_effect_once (fun () -> let watcher_id = watch_url (fun url -> set_url (fun _ -> url)) in (* check for updates that may have occured between the initial state and the subscribe above *) let new_url = dangerously_get_initial_url () in if url_not_equal new_url url then set_url (fun _ -> new_url); Some (fun () -> unwatch_url watcher_id)); url
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>