Commit 3b8704e1 authored by Laurent Wouters's avatar Laurent Wouters
Browse files

Removed old content

parent 8548c00c6eb5
ReactDOMRe.renderToElementWithId(<App />, "app");
\ No newline at end of file
type state = Framework.appState;
type action = Framework.appAction;
let component = ReasonReact.reducerComponent("Page");
let make = _children => {
...component,
didMount: self => {
let watcherID =
ReasonReact.Router.watchUrl(url =>
self.send(Framework.GoTo(Framework.path_to_str(url.path)))
);
self.onUnmount(() => ReasonReact.Router.unwatchUrl(watcherID));
let url = ReasonReact.Router.dangerouslyGetInitialUrl();
self.send(Framework.GoTo(Framework.path_to_str(url.path)));
},
initialState: () => {
let registry = Defaults.defaultRegistry;
Framework.States.initial_state(registry);
},
reducer: Framework.States.reduce,
didUpdate: oldNewSelf => Framework.States.on_updated(oldNewSelf),
render: self =>
Framework.DefaultRenderer.render(self, Defaults.defaultRenderer),
};
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>
\ No newline at end of file
let renderLoading =
(
_self: ReasonReact.self(Framework.appState, _, Framework.appAction),
_state: Framework.appState,
) =>
<div> (ReasonReact.string("Loading")) </div>;
let renderFailed =
(
_self: ReasonReact.self(Framework.appState, _, Framework.appAction),
_state: Framework.appState,
) =>
<div> (ReasonReact.string("Failed")) </div>;
let renderRoot =
(
self: ReasonReact.self(Framework.appState, _, Framework.appAction),
state: Framework.appState,
) => {
let resource = Framework.States.root_resource(state);
let schema = Hypermedia.Schema.as_root(Framework.schema_of(resource));
<div>
<h1> (ReasonReact.string(schema.title)) </h1>
(
schema.links
|> List.map((link: Hypermedia.schemaLink) => {
let link_href =
switch (link.href) {
| Some(x) => x
| None => ""
};
let title =
switch (link.title) {
| Some(x) => x
| None => ""
};
<li>
<a
href=link_href
onClick=(
self.handle((_event, _self) =>
Framework.follow_link(link_href)
)
)>
(ReasonReact.string(title))
</a>
</li>;
})
|> Array.of_list
|> ReasonReact.array
)
</div>;
};
let renderCollectionComplete =
(
self: ReasonReact.self(Framework.appState, _, Framework.appAction),
state: Framework.appState,
) => {
let resource = Framework.States.root_resource(state);
let schema = Hypermedia.Schema.as_array(Framework.schema_of(resource));
let data = Hypermedia.Entity.as_array(Framework.data_of(resource));
let schema_title =
switch (schema.title) {
| Some(x) => x
| None => ""
};
let schema_items =
switch (schema.items) {
| ObjectType(t) => t
| _ => {links: [], properties: [], title: None}
};
let link_href =
switch (List.nth(schema_items.links, 0).href) {
| Some(x) => x
| None => "{id}"
};
<div>
<h1> (ReasonReact.string(schema_title)) </h1>
(
data
|> List.map((entity: Hypermedia.entityValue) => {
let obj = Hypermedia.Entity.as_object(entity);
let link_target = Hypermedia.Utils.produce(link_href, obj);
let title =
Hypermedia.Entity.as_string(
Hypermedia.Entity.get(obj, "title"),
);
<li>
<a
href=link_target
onClick=(
self.handle((_event, _self) =>
Framework.follow_link(link_target)
)
)>
(ReasonReact.string(title))
</a>
</li>;
})
|> Array.of_list
|> ReasonReact.array
)
</div>;
};
let renderCollection =
(
self: ReasonReact.self(Framework.appState, _, Framework.appAction),
state: Framework.appState,
) => {
let resource = Framework.States.root_resource(state);
switch (resource.data) {
| None => renderLoading(self, state)
| Some(_) => renderCollectionComplete(self, state)
};
};
let renderEntityComplete =
(
_self: ReasonReact.self(Framework.appState, _, Framework.appAction),
state: Framework.appState,
) => {
let resource = Framework.States.root_resource(state);
let schema = Hypermedia.Schema.as_object(Framework.schema_of(resource));
let data = Hypermedia.Entity.as_object(Framework.data_of(resource));
let schema_title =
switch (schema.title) {
| Some(x) => x
| None => ""
};
<div>
<h1> (ReasonReact.string(schema_title)) </h1>
<div>
(
data.properties
|> List.map((property: Hypermedia.entityProperty) => {
let value = Hypermedia.Entity.as_string(property.value);
<div>
<div> (ReasonReact.string(property.name)) </div>
<div> (ReasonReact.string(value)) </div>
</div>;
})
|> Array.of_list
|> ReasonReact.array
)
</div>
</div>;
};
let renderEntity =
(
self: ReasonReact.self(Framework.appState, _, Framework.appAction),
state: Framework.appState,
) => {
let resource = Framework.States.root_resource(state);
switch (resource.data) {
| None => renderLoading(self, state)
| Some(_) => renderEntityComplete(self, state)
};
};
let defaultRegistry =
Framework.Create.registry([
Framework.Create.view(
"::defaults::Loading",
"Default loading view",
Framework.LoadingView,
0,
"::defaults::Loading",
"::defaults::Loading",
),
Framework.Create.view(
"::defaults::Failed",
"Default failed view",
Framework.FailedView,
0,
"::defaults::Failed",
"::defaults::Failed",
),
Framework.Create.view(
"::defaults::Root",
"Default root view",
Framework.RootView,
0,
"::defaults::Root",
"::defaults::Root",
),
Framework.Create.view(
"::defaults::Collection",
"Default collection view",
Framework.CollectionView(None),
0,
"::defaults::Collection",
"::defaults::Collection",
),
Framework.Create.view(
"::defaults::Entity",
"Default entity view",
Framework.EntityView(None),
0,
"::defaults::Entity",
"::defaults::Entity",
),
]);
let defaultRenderer =
Framework.DefaultRenderer.empty
|> Framework.DefaultRenderer.register(
"::defaults::Loading",
(
self:
ReasonReact.self(
Framework.appState,
ReasonReact.noRetainedProps,
Framework.appAction,
),
state: Framework.appState,
) =>
renderLoading(self, state)
)
|> Framework.DefaultRenderer.register(
"::defaults::Failed",
(
self:
ReasonReact.self(
Framework.appState,
ReasonReact.noRetainedProps,
Framework.appAction,
),
state: Framework.appState,
) =>
renderFailed(self, state)
)
|> Framework.DefaultRenderer.register(
"::defaults::Root",
(
self:
ReasonReact.self(
Framework.appState,
ReasonReact.noRetainedProps,
Framework.appAction,
),
state: Framework.appState,
) =>
renderRoot(self, state)
)
|> Framework.DefaultRenderer.register(
"::defaults::Collection",
(
self:
ReasonReact.self(
Framework.appState,
ReasonReact.noRetainedProps,
Framework.appAction,
),
state: Framework.appState,
) =>
renderCollection(self, state)
)
|> Framework.DefaultRenderer.register(
"::defaults::Entity",
(
self:
ReasonReact.self(
Framework.appState,
ReasonReact.noRetainedProps,
Framework.appAction,
),
state: Framework.appState,
) =>
renderEntity(self, state)
);
\ No newline at end of file
module StringMap = Map.Make(String);;
(* Exception when the application is in a bad state *)
exception BadState of string
(* A piece of data that has to be fetched *)
type requestedData =
(* A schema that has to be fetched *)
| RequestedSchema of string
(* A piece of resource that has to be fetched *)
| RequestedData of string
(* The definition of a view has to be fetched *)
| RequestedViewDefinition of string
(* The specification of views has to be fetched *)
| RequestedViewSpecifications of string
(* Get a descriptor for requested data *)
let describe_requested data = match data with
| RequestedData(target) -> ("data", target)
| RequestedSchema(target) -> ("schema", target)
| RequestedViewDefinition(target) -> ("view", target)
| RequestedViewSpecifications(target) -> ("view specifications", target)
(* Possible kind of views *)
type viewKind =
(* The view when loading *)
| LoadingView
(* The view when loading failed *)
| FailedView
(* A view for an application root *)
| RootView
(* A view for a collection of items *)
| CollectionView of string option
(* A view for a kind of entity *)
| EntityView of string option
(* A specification *)
type viewSpecification = {
(* The unique identifier for this view *)
identifier: string;
(* The view's human readable name *)
name: string;
(* The kind of view *)
kind: viewKind;
(* The priority given to the view *)
priority: int;
(* The location where to load the view from *)
location: string;
}
(* A piece of fetched data *)
type fetchedData =
(* A fetched schema *)
| FetchedSchema of string * Hypermedia.schemaType
(* A fetched piece of data *)
| FetchedData of (string * Hypermedia.entityValue)
(* A fetched collection of view specifications *)
| FetchedSpecifications of viewSpecification list
(* An resource to be rendered *)
type resource = {
(* The path to the resource *)
path: string;
(* The schema for this resource *)
schema: Hypermedia.schemaType option;
(* The data for this resource, if applicable *)
data: Hypermedia.entityValue option;
}
let schema_of resource = match resource.schema with
| None -> raise (BadState "Expected a schema for the resource")
| Some(schema) -> schema
let data_of resource = match resource.data with
| None -> raise (BadState "Expected data for the resource")
| Some(data) -> data
(* The definition of a view *)
type view = {
(* The specification of this view *)
specification: viewSpecification;
(* The view rendering function *)
renderer: string;
}
(* A registry of views *)
and viewRegistry = {
(* The known specifications *)
specifications: viewSpecification StringMap.t;
(* The known definitions *)
definitions: view StringMap.t;
}
(* The state of an app while loading *)
and appStateLoading = {
(* the location of the current resource *)
location: string;
(* The already loaded resources *)
loaded: resource StringMap.t;
(* The data remaining to be fetched *)
requested: requestedData list;
(* The view registry for the app *)
registry: viewRegistry;
}
(* The state of an app while loading *)
and appStateLoaded = {
(* the location of the current resource *)
location: string;
(* The already loaded resources *)
resources: resource StringMap.t;
(* The view registry for the app *)
registry: viewRegistry;
}
(* The possible states of an app *)
and appState =
(* The app failed with a message *)
| Failed of string * viewRegistry
(* Initial state *)
| Init of viewRegistry
(* The app is loading *)
| Loading of appStateLoading
(* The completed state of an app *)
| Ready of appStateLoaded
(* The possible actions of an app *)
and appAction =
(* Some fetching is being requested *)
| Request of requestedData
(* Some request has been launched *)
| LaunchedRequest of requestedData
(* The loading of a resource failed *)
| LoadingFailed of requestedData
(* The loading of a resource has been completed *)
| LoadingCompleted of fetchedData
(* The user requested going to another location *)
| GoTo of string
(* Follow a link *)
let follow_link link =
ReasonReact.Router.push link
(* Take a path as a list of segments and convert it to a string *)
let rec path_to_str path =
match path with
| [] -> ""
| [first] -> "/" ^ first
| first :: others -> "/" ^ first ^ (path_to_str others)
(* Module for state management *)
module States : sig
(* Get the initial state for the application *)
val initial_state: viewRegistry -> appState
(* Default reduction function *)
val reduce: appAction -> appState -> (appState, 'retainedProps, appAction) ReasonReact.update
(* When the state has changed *)
val on_updated: (appState, 'retainedProps, appAction) ReasonReact.oldNewSelf -> unit
(* Gets the root resource from an application state *)
val root_resource: appState -> resource
end = struct
(* Fold fetched data into a map of resources *)
let append_resource fetchedData (resources: resource StringMap.t) =
match fetchedData with
| FetchedSchema(target, schema) ->
if StringMap.exists (fun k _ -> target = k) resources then
let old = StringMap.find target resources in
StringMap.add target {path=target; schema=Some(schema); data=old.data} resources
else
StringMap.add target {path=target; schema=Some(schema); data=None} resources
| FetchedData(target, data) ->
if StringMap.exists (fun k _ -> target = k) resources then
let old = StringMap.find target resources in
StringMap.add target {path=target; schema=old.schema; data=Some(data)} resources
else
StringMap.add target {path=target; schema=None; data=Some(data)} resources
| _ -> resources
(* Gets the root resource from an application state *)
let root_resource (state: appState) = match state with
| Init(_)
| Failed(_) -> raise (BadState "Expected state Loading or Ready")
| Loading({
location = location;
loaded = resources;
requested = _;
registry = _;
})
| Ready({
location = location;
resources = resources;
registry = _;
}) -> StringMap.find location resources
(* Get the initial state for the application *)
let initial_state viewRegistry = Init(viewRegistry)
(* Apply the reduction on a GoTo action *)
let reduce_on_goto state target = match state with
| Loading({
location = _;
loaded = _;
requested = _;
registry = registry;
})
| Ready({
location = _;
resources = _;
registry = registry;
})
| Failed(_, registry)-> ReasonReact.Update(Loading({
location = target;
loaded = StringMap.empty;
requested = [RequestedSchema(target)];
registry = registry;
}))
| Init(registry) -> ReasonReact.Update(Loading({
location = target;
loaded = StringMap.empty;
requested = [RequestedSchema(target)];
registry = registry;
}))
(* Apply the reduction on a Request action *)
let reduce_on_requested state requestedData = match state with
| Loading({
location = location;
loaded = loaded;
requested = requested;
registry = registry
}) -> ReasonReact.Update(Loading({
location = location;
loaded = loaded;
requested = requested @ [requestedData];
registry = registry;
}))
| Ready({
location = location;
resources = resources;
registry = registry;
}) -> ReasonReact.Update(Loading({
location = location;
loaded = resources;
requested = [requestedData];
registry = registry;
}))
| Failed(_, _)
| Init(_) -> ReasonReact.NoUpdate
let reduce_on_request_launched state _ = match state with
| Loading({
location = location;
loaded = loaded;
requested = requested;
registry = registry
}) -> ReasonReact.Update(Loading({
location = location;
loaded = loaded;
requested = List.tl requested;
registry = registry;
}))
| Ready(_)
| Failed(_, _)
| Init(_) -> ReasonReact.NoUpdate
(* Apply the reduction on a Loading Failed action *)
let reduce_on_failed state requestedData =
let what, target = describe_requested requestedData in
match state with
| Loading({
location = _;
loaded = _;
requested = _;
registry = registry;
})
| Ready({
location = _;
resources = _;
registry = registry;
})
| Failed(_, registry)-> ReasonReact.Update(Failed("Failed to fetch " ^ what ^ " at " ^ target, registry))