30
31:- module(http_settings,
32 [ http_show_settings/3, 33 http_apply_settings/4 34 ]). 35:- use_module(library('http/html_write')). 36:- use_module(library('http/html_head')). 37:- use_module(library('http/http_parameters')). 38:- use_module(library(option)). 39:- use_module(library(lists)). 40:- use_module(library(pairs)). 41:- use_module(library(debug)). 42:- use_module(library(settings)).
56http_show_settings(Options) -->
57 { findall(M-N, current_setting(M:N), List),
58 keysort(List, Sorted),
59 group_pairs_by_key(Sorted, ByModule)
60 },
61 ( { option(edit(true), Options, false),
62 option(action(Action), Options, '/http/settings')
63 }
64 -> html(form([ action(Action),
65 method('GET')
66 ],
67 table(class(block),
68 \settings_table(ByModule, Options))))
69 ; html([ table(class(block),
70 \settings_table(ByModule, Options))
71 ])
72 ).
73
74settings_table(ByModule, Options) -->
75 ( {ByModule = [M-List],
76 \+ option(hide_module(_), Options)
77 }
78 -> show_module(M, List, [hide_module(true)|Options])
79 ; show_modules(ByModule, Options)
80 ),
81 ( { option(edit(true), Options, true) }
82 -> html(tr(class(buttons),
83 td([ colspan(2),
84 align(right)
85 ],
86 [ input([ type(reset) ]),
87 input([ type(submit), value('Apply') ])
88 ])))
89 ; []
90 ).
91
92
93show_modules([], _) -->
94 [].
95show_modules([M-List|T], Options) -->
96 show_module(M, List, Options),
97 show_modules(T, Options).
98
99show_module(Module, _Settings, Options) -->
100 { option(modules(ListOfModules), Options),
101 \+ memberchk(Module,ListOfModules)
102 }, !.
103show_module(Module, Settings, Options) -->
104 show_module_header(Module, Options),
105 show_settings(Settings, Module, odd, Options).
106
(_Module, Options) -->
108 { option(hide_module(true), Options, false)}, !.
109show_module_header(Module, _Options) -->
110 html(tr(th([colspan(2), class(group)], Module))).
111
112show_settings([], _, _, _) -->
113 [].
114show_settings([H|T], Module, EO, Options) -->
115 show_setting(H, Module, EO, Options),
116 { negate_odd_even(EO, EO2) },
117 show_settings(T, Module, EO2, Options).
118
119show_setting(H, Module, EO, Options) -->
120 { setting_property(Module:H, comment(Comment)),
121 setting_property(Module:H, type(Type)),
122 setting_title(Module:H, Title),
123 setting(Module:H, Value),
124 debug(settings, '~w: type=~w', [H, Type])
125 },
126 html(tr(class(EO),
127 [ td([class(comment), title(Title)], Comment),
128 td(class(value),
129 \show_value(Type, Value, Module:H, Options))
130 ])).
131
132setting_title(Setting, Title) :-
133 setting_property(Setting, File:Line),
134 integer(Line), !,
135 file_base_name(File, Base),
136 format(atom(Title), '~q from ~w:~d', [Setting, Base, Line]).
137setting_title(Setting, Title) :-
138 format(atom(Title), '~q', [Setting]).
139
140
141show_value(Type, Value, Id, Options) -->
142 { option(edit(true), Options, true) }, !,
143 input_value(Type, Value, Id).
144show_value(Type, Value, _, _Options) -->
145 show_value(Type, Value).
151show_value(list(Type), Values) --> !,
152 html(div(class(list), \show_list(Values, Type, odd))).
153show_value(_, Value) -->
154 html('~w'-[Value]).
155
156show_list([], _, _) -->
157 [].
158show_list([H|T], Type, Class) -->
159 html(div(class(elem_+Class), \show_value(Type, H))),
160 { negate_odd_even(Class, NextClass) },
161 show_list(T, Type, NextClass).
168:- multifile
169 input_item/5. 170
171input_value(Type, Value, Id) -->
172 { html_name(Id, Name) },
173 ( input_item(Type, Value, Name)
174 -> []
175 ; builtin_input_item(Type, Value, Name)
176 ).
177
178builtin_input_item(boolean, Value, Name) --> !,
179 builtin_input_item(oneof([true,false]), Value, Name).
180builtin_input_item(between(L,U), Value, Name) --> !,
181 html(input([ type(range),
182 name(Name),
183 min(L), max(U), value(Value)
184 ])).
185builtin_input_item(oneof(List), Value, Name) --> !,
186 html(select([name(Name)], \oneof(List, Value))).
187builtin_input_item(atom, Value, Name) --> !,
188 html(input([name(Name), size(40), value(Value)])).
189builtin_input_item(_, Value, Name) -->
190 { format(string(S), '~q', [Value])
191 },
192 html(input([name(Name), size(40), value(S)])).
193
194oneof([], _) -->
195 [].
196oneof([H|T], Value) -->
197 ( {H == Value}
198 -> html([ option([selected(selected),value(H)], H) ])
199 ; html([ option([ value(H)], H) ])
200 ),
201 oneof(T, Value).
202
203
204
222http_apply_settings(Request, Options) -->
223 { http_parameters(Request, [],
224 [ form_data(Data)
225 ]),
226 debug(settings, 'Form data: ~p', [Data]),
227 phrase(process_settings_form(Data), Changes)
228 },
229 report_changed(Changes, Options).
230
231
232report_changed([], _) -->
233 html(div(class(msg_informational), 'No changes')).
234report_changed(L, _) -->
235 { memberchk(error(_), L) },
236 report_errors(L).
237report_changed(L, Options) -->
238 { length(L, N),
239 forall(member(change(Id, _, Value), L),
240 set_setting(Id, Value)),
241 ( option(save_as(File), Options)
242 -> save_settings(File)
243 ; option(save(true), Options, true)
244 -> save_settings
245 ; true
246 )
247 },
248 html(div(class(msg_informational), ['Changed ', N, ' settings'])).
249
250report_errors([]) -->
251 [].
252report_errors([error(Error)|T]) -->
253 report_error(Error),
254 report_errors(T).
255report_errors([_|T]) -->
256 report_errors(T).
257
258report_error(no_setting(Id)) -->
259 { format(string(Name), '~w', [Id]) },
260 html(div(class(msg_error),
261 ['Setting ', Name, ' does not exist.'])).
262report_error(bad_value(Id, RawValue)) -->
263 { format(string(Name), '~w', [Id]) },
264 html(div(class(msg_error),
265 ['Wrong value for ', Name, ': ', RawValue])).
277process_settings_form([]) -->
278 [].
279process_settings_form([Name = Value|T]) -->
280 ( { html_name(Setting, Name) }
281 -> process_form_field(Setting, Value)
282 ; [ error(no_setting(Name)) ]
283 ),
284 process_settings_form(T).
285
286process_form_field(Id, RawValue) -->
287 ( { setting_property(Id, type(Type)) }
288 -> ( { catch(convert_setting_text(Type, RawValue, Value), _, fail) }
289 -> { setting(Id, OldValue) },
290 ( { Value == OldValue }
291 -> []
292 ; [change(Id, OldValue, Value)]
293 )
294 ; [ error(bad_value(Id, RawValue))]
295 )
296 ; [ error(no_setting(Id)) ]
297 ).
298
299
300
301
310html_name(Module:Setting, Name) :-
311 atomic_list_concat([Module, Setting], ':', Name).
316negate_odd_even(odd, even).
317negate_odd_even(even, odd)