-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathchooseForeign.ur
145 lines (122 loc) · 5.6 KB
/
chooseForeign.ur
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
open Bootstrap
functor Make(M : sig
con const :: {Type}
con given :: {Type}
con chosen :: {Type}
constraint const ~ given
constraint (const ++ given) ~ chosen
val const : $const
table choices : (const ++ given ++ chosen)
con optionsConst :: {Type}
con others :: {Type}
constraint others ~ chosen
constraint (others ++ chosen) ~ optionsConst
table options : (optionsConst ++ chosen ++ others)
val optionsConst : $optionsConst
val constFl : folder const
val givenFl : folder given
val chosenFl : folder chosen
val optionsConstFl : folder optionsConst
val constInj : $(map sql_injectable const)
val givenInj : $(map sql_injectable given)
val chosenInj : $(map sql_injectable chosen)
val optionsConstInj : $(map sql_injectable optionsConst)
val chosenShow : show $chosen
val chosenRead : read $chosen
val chosenEq : eq $chosen
val givenEq : eq $given
val buttonLabel : string
(* Authentication *)
val amGiven : transaction (option $given)
end) = struct
open M
type choiceSet = list $chosen
type input = _
type a = _
fun create gv =
opts <- queryL1 (SELECT options.{{chosen}}
FROM options
WHERE {@@Sql.easy_where [#Options] [optionsConst] [_] [_] [_] [_]
! ! optionsConstInj optionsConstFl optionsConst}
ORDER BY {{{@Sql.order_by chosenFl
(@Sql.some_fields [#Options] [chosen] ! ! chosenFl)
sql_asc}}});
prefs <- queryL1 (SELECT choices.{{chosen}}
FROM choices
WHERE {@@Sql.easy_where [#Choices] [const ++ given] [_] [_] [_] [_]
! ! (constInj ++ givenInj) (@Folder.concat ! constFl givenFl) (const ++ gv)}
ORDER BY {{{@Sql.order_by chosenFl
(@Sql.some_fields [#Choices] [chosen] ! ! chosenFl)
sql_asc}}});
prefs <- source prefs;
toAdd <- source "";
return {Given = gv, Options = opts, Prefs = prefs, ToAdd = toAdd}
fun ensure gv =
user <- amGiven;
case user of
None => error <xml>Must be authenticated to access this page</xml>
| Some user =>
if user = gv then
return ()
else
error <xml>Wrong user to be accessing this page</xml>
fun choose gv ch =
ensure gv;
@@Sql.easy_insert [const ++ given ++ chosen] [_] (constInj ++ givenInj ++ chosenInj)
(@Folder.concat ! constFl (@Folder.concat ! givenFl chosenFl))
choices (const ++ gv ++ ch)
fun unchoose gv ch =
ensure gv;
dml (DELETE FROM choices
WHERE {@@Sql.easy_where [#T] [const ++ given ++ chosen] [_] [_] [_] [_]
! ! (constInj ++ givenInj ++ chosenInj) (@Folder.concat ! constFl (@Folder.concat ! givenFl chosenFl)) (const ++ gv ++ ch)})
fun render t = <xml>
<table class="bs-table">
<dyn signal={chs <- signal t.Prefs;
return <xml>
{List.mapX (fn ch => <xml>
<tr><td>
{[ch]}
<button class="close"
onclick={fn _ =>
rpc (unchoose t.Given ch);
set t.Prefs (List.filter (fn ch' => ch' <> ch) chs)}>
×
</button>
</td></tr>
</xml>) chs}
<tr><td/></tr>
<tr>
<td>
<cselect class="form-select" source={t.ToAdd}>
{List.mapX (fn ch =>
if List.mem ch chs then
<xml/>
else
<xml><coption>{[ch]}</coption></xml>) t.Options}
</cselect>
<button class="btn btn-primary"
value={buttonLabel}
onclick={fn _ =>
ta <- get t.ToAdd;
case ta of
"" => return ()
| _ =>
ch <- return (readError ta);
rpc (choose t.Given ch);
set t.Prefs (List.sort (fn x y => show x > show y) (ch :: chs))}/>
</td>
</tr>
</xml>}/>
</table>
</xml>
fun notification _ _ = <xml></xml>
fun buttons _ _ = <xml></xml>
fun ui x = {
Create = create x,
Onload = fn _ => return (),
Render = fn _ => render,
Notification = notification,
Buttons = buttons
}
end