docs: update js api docs
[project/luci.git] / docs / jsapi / ui.js.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>Source: ui.js</title>
6
7
8 <script src="scripts/prettify/prettify.js"></script>
9 <script src="scripts/prettify/lang-css.js"></script>
10 <script src="scripts/jquery.min.js"></script>
11 <!--[if lt IE 9]>
12 <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13 <![endif]-->
14 <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
15 <link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
16 <link type="text/css" rel="stylesheet" href="styles/jaguar.css">
17
18
19 <script>
20 var config = {"monospaceLinks":true,"cleverLinks":true,"default":{"outputSourceFiles":true}};
21 </script>
22
23
24
25 </head>
26 <body>
27 <div id="wrap" class="clearfix">
28
29 <div class="navigation">
30 <h3 class="applicationName"><a href="index.html"></a></h3>
31
32 <div class="search">
33 <input id="search" type="text" class="form-control input-sm" placeholder="Search Documentations">
34 </div>
35 <ul class="list">
36
37 <li class="item" data-name="LuCI">
38 <span class="title">
39 <a href="LuCI.html">LuCI</a>
40
41 </span>
42 <ul class="members itemMembers">
43
44 <span class="subtitle">Members</span>
45
46 <li data-name="LuCI#Class"><a href="LuCI.html#Class">Class</a></li>
47
48 <li data-name="LuCI#dom"><a href="LuCI.html#dom">dom</a></li>
49
50 <li data-name="LuCI#env"><a href="LuCI.html#env">env</a></li>
51
52 <li data-name="LuCI#Poll"><a href="LuCI.html#Poll">Poll</a></li>
53
54 <li data-name="LuCI#Request"><a href="LuCI.html#Request">Request</a></li>
55
56 <li data-name="LuCI#view"><a href="LuCI.html#view">view</a></li>
57
58 </ul>
59 <ul class="typedefs itemMembers">
60
61 <span class="subtitle">Typedefs</span>
62
63 <li data-name="LuCI.requestCallbackFn"><a href="LuCI.html#.requestCallbackFn">requestCallbackFn</a></li>
64
65 </ul>
66 <ul class="typedefs itemMembers">
67
68 </ul>
69 <ul class="methods itemMembers">
70
71 <span class="subtitle">Methods</span>
72
73 <li data-name="LuCI#bind"><a href="LuCI.html#bind">bind</a></li>
74
75 <li data-name="LuCI#error"><a href="LuCI.html#error">error</a></li>
76
77 <li data-name="LuCI#fspath"><a href="LuCI.html#fspath">fspath</a></li>
78
79 <li data-name="LuCI#get"><a href="LuCI.html#get">get</a></li>
80
81 <li data-name="LuCI#halt"><a href="LuCI.html#halt">halt</a></li>
82
83 <li data-name="LuCI#hasSystemFeature"><a href="LuCI.html#hasSystemFeature">hasSystemFeature</a></li>
84
85 <li data-name="LuCI#hasViewPermission"><a href="LuCI.html#hasViewPermission">hasViewPermission</a></li>
86
87 <li data-name="LuCI#isObject"><a href="LuCI.html#isObject">isObject</a></li>
88
89 <li data-name="LuCI#location"><a href="LuCI.html#location">location</a></li>
90
91 <li data-name="LuCI#media"><a href="LuCI.html#media">media</a></li>
92
93 <li data-name="LuCI#path"><a href="LuCI.html#path">path</a></li>
94
95 <li data-name="LuCI#poll"><a href="LuCI.html#poll">poll</a></li>
96
97 <li data-name="LuCI#post"><a href="LuCI.html#post">post</a></li>
98
99 <li data-name="LuCI#raise"><a href="LuCI.html#raise">raise</a></li>
100
101 <li data-name="LuCI#require"><a href="LuCI.html#require">require</a></li>
102
103 <li data-name="LuCI#resolveDefault"><a href="LuCI.html#resolveDefault">resolveDefault</a></li>
104
105 <li data-name="LuCI#resource"><a href="LuCI.html#resource">resource</a></li>
106
107 <li data-name="LuCI#run"><a href="LuCI.html#run">run</a></li>
108
109 <li data-name="LuCI#sortedKeys"><a href="LuCI.html#sortedKeys">sortedKeys</a></li>
110
111 <li data-name="LuCI#stop"><a href="LuCI.html#stop">stop</a></li>
112
113 <li data-name="LuCI#toArray"><a href="LuCI.html#toArray">toArray</a></li>
114
115 <li data-name="LuCI#url"><a href="LuCI.html#url">url</a></li>
116
117 </ul>
118 <ul class="events itemMembers">
119
120 </ul>
121 </li>
122
123 <li class="item" data-name="LuCI.baseclass">
124 <span class="title">
125 <a href="LuCI.baseclass.html">LuCI.baseclass</a>
126
127 </span>
128 <ul class="members itemMembers">
129
130 </ul>
131 <ul class="typedefs itemMembers">
132
133 </ul>
134 <ul class="typedefs itemMembers">
135
136 </ul>
137 <ul class="methods itemMembers">
138
139 <span class="subtitle">Methods</span>
140
141 <li data-name="LuCI.baseclass.extend"><a href="LuCI.baseclass.html#.extend">extend</a></li>
142
143 <li data-name="LuCI.baseclass.instantiate"><a href="LuCI.baseclass.html#.instantiate">instantiate</a></li>
144
145 <li data-name="LuCI.baseclass.isSubclass"><a href="LuCI.baseclass.html#.isSubclass">isSubclass</a></li>
146
147 <li data-name="LuCI.baseclass.singleton"><a href="LuCI.baseclass.html#.singleton">singleton</a></li>
148
149 <li data-name="LuCI.baseclass#super"><a href="LuCI.baseclass.html#super">super</a></li>
150
151 <li data-name="LuCI.baseclass#varargs"><a href="LuCI.baseclass.html#varargs">varargs</a></li>
152
153 </ul>
154 <ul class="events itemMembers">
155
156 </ul>
157 </li>
158
159 <li class="item" data-name="LuCI.dom">
160 <span class="title">
161 <a href="LuCI.dom.html">LuCI.dom</a>
162
163 </span>
164 <ul class="members itemMembers">
165
166 </ul>
167 <ul class="typedefs itemMembers">
168
169 <span class="subtitle">Typedefs</span>
170
171 <li data-name="LuCI.dom~ignoreCallbackFn"><a href="LuCI.dom.html#~ignoreCallbackFn">ignoreCallbackFn</a></li>
172
173 </ul>
174 <ul class="typedefs itemMembers">
175
176 </ul>
177 <ul class="methods itemMembers">
178
179 <span class="subtitle">Methods</span>
180
181 <li data-name="LuCI.dom#append"><a href="LuCI.dom.html#append">append</a></li>
182
183 <li data-name="LuCI.dom#attr"><a href="LuCI.dom.html#attr">attr</a></li>
184
185 <li data-name="LuCI.dom#bindClassInstance"><a href="LuCI.dom.html#bindClassInstance">bindClassInstance</a></li>
186
187 <li data-name="LuCI.dom#callClassMethod"><a href="LuCI.dom.html#callClassMethod">callClassMethod</a></li>
188
189 <li data-name="LuCI.dom#content"><a href="LuCI.dom.html#content">content</a></li>
190
191 <li data-name="LuCI.dom#create"><a href="LuCI.dom.html#create">create</a></li>
192
193 <li data-name="LuCI.dom#data"><a href="LuCI.dom.html#data">data</a></li>
194
195 <li data-name="LuCI.dom#elem"><a href="LuCI.dom.html#elem">elem</a></li>
196
197 <li data-name="LuCI.dom#findClassInstance"><a href="LuCI.dom.html#findClassInstance">findClassInstance</a></li>
198
199 <li data-name="LuCI.dom#isEmpty"><a href="LuCI.dom.html#isEmpty">isEmpty</a></li>
200
201 <li data-name="LuCI.dom#matches"><a href="LuCI.dom.html#matches">matches</a></li>
202
203 <li data-name="LuCI.dom#parent"><a href="LuCI.dom.html#parent">parent</a></li>
204
205 <li data-name="LuCI.dom#parse"><a href="LuCI.dom.html#parse">parse</a></li>
206
207 </ul>
208 <ul class="events itemMembers">
209
210 </ul>
211 </li>
212
213 <li class="item" data-name="LuCI.form">
214 <span class="title">
215 <a href="LuCI.form.html">LuCI.form</a>
216
217 </span>
218 <ul class="members itemMembers">
219
220 </ul>
221 <ul class="typedefs itemMembers">
222
223 </ul>
224 <ul class="typedefs itemMembers">
225
226 </ul>
227 <ul class="methods itemMembers">
228
229 </ul>
230 <ul class="events itemMembers">
231
232 </ul>
233 </li>
234
235 <li class="item" data-name="LuCI.form.AbstractElement">
236 <span class="title">
237 <a href="LuCI.form.AbstractElement.html">LuCI.form.AbstractElement</a>
238
239 </span>
240 <ul class="members itemMembers">
241
242 </ul>
243 <ul class="typedefs itemMembers">
244
245 </ul>
246 <ul class="typedefs itemMembers">
247
248 </ul>
249 <ul class="methods itemMembers">
250
251 <span class="subtitle">Methods</span>
252
253 <li data-name="LuCI.form.AbstractElement#append"><a href="LuCI.form.AbstractElement.html#append">append</a></li>
254
255 <li data-name="LuCI.form.AbstractElement#parse"><a href="LuCI.form.AbstractElement.html#parse">parse</a></li>
256
257 <li data-name="LuCI.form.AbstractElement#render"><a href="LuCI.form.AbstractElement.html#render">render</a></li>
258
259 <li data-name="LuCI.form.AbstractElement#stripTags"><a href="LuCI.form.AbstractElement.html#stripTags">stripTags</a></li>
260
261 <li data-name="LuCI.form.AbstractElement#titleFn"><a href="LuCI.form.AbstractElement.html#titleFn">titleFn</a></li>
262
263 </ul>
264 <ul class="events itemMembers">
265
266 </ul>
267 </li>
268
269 <li class="item" data-name="LuCI.form.AbstractSection">
270 <span class="title">
271 <a href="LuCI.form.AbstractSection.html">LuCI.form.AbstractSection</a>
272
273 </span>
274 <ul class="members itemMembers">
275
276 <span class="subtitle">Members</span>
277
278 <li data-name="LuCI.form.AbstractSection##parentoption"><a href="LuCI.form.AbstractSection.html#parentoption">parentoption</a></li>
279
280 </ul>
281 <ul class="typedefs itemMembers">
282
283 </ul>
284 <ul class="typedefs itemMembers">
285
286 </ul>
287 <ul class="methods itemMembers">
288
289 <span class="subtitle">Methods</span>
290
291 <li data-name="LuCI.form.AbstractSection#append"><a href="LuCI.form.AbstractSection.html#append">append</a></li>
292
293 <li data-name="LuCI.form.AbstractSection#cfgsections"><a href="LuCI.form.AbstractSection.html#cfgsections">cfgsections</a></li>
294
295 <li data-name="LuCI.form.AbstractSection#cfgvalue"><a href="LuCI.form.AbstractSection.html#cfgvalue">cfgvalue</a></li>
296
297 <li data-name="LuCI.form.AbstractSection#filter"><a href="LuCI.form.AbstractSection.html#filter">filter</a></li>
298
299 <li data-name="LuCI.form.AbstractSection#formvalue"><a href="LuCI.form.AbstractSection.html#formvalue">formvalue</a></li>
300
301 <li data-name="LuCI.form.AbstractSection#getOption"><a href="LuCI.form.AbstractSection.html#getOption">getOption</a></li>
302
303 <li data-name="LuCI.form.AbstractSection#getUIElement"><a href="LuCI.form.AbstractSection.html#getUIElement">getUIElement</a></li>
304
305 <li data-name="LuCI.form.AbstractSection#load"><a href="LuCI.form.AbstractSection.html#load">load</a></li>
306
307 <li data-name="LuCI.form.AbstractSection#option"><a href="LuCI.form.AbstractSection.html#option">option</a></li>
308
309 <li data-name="LuCI.form.AbstractSection#parse"><a href="LuCI.form.AbstractSection.html#parse">parse</a></li>
310
311 <li data-name="LuCI.form.AbstractSection#render"><a href="LuCI.form.AbstractSection.html#render">render</a></li>
312
313 <li data-name="LuCI.form.AbstractSection#stripTags"><a href="LuCI.form.AbstractSection.html#stripTags">stripTags</a></li>
314
315 <li data-name="LuCI.form.AbstractSection#tab"><a href="LuCI.form.AbstractSection.html#tab">tab</a></li>
316
317 <li data-name="LuCI.form.AbstractSection#taboption"><a href="LuCI.form.AbstractSection.html#taboption">taboption</a></li>
318
319 <li data-name="LuCI.form.AbstractSection#titleFn"><a href="LuCI.form.AbstractSection.html#titleFn">titleFn</a></li>
320
321 </ul>
322 <ul class="events itemMembers">
323
324 </ul>
325 </li>
326
327 <li class="item" data-name="LuCI.form.AbstractValue">
328 <span class="title">
329 <a href="LuCI.form.AbstractValue.html">LuCI.form.AbstractValue</a>
330
331 </span>
332 <ul class="members itemMembers">
333
334 <span class="subtitle">Members</span>
335
336 <li data-name="LuCI.form.AbstractValue##datatype"><a href="LuCI.form.AbstractValue.html#datatype">datatype</a></li>
337
338 <li data-name="LuCI.form.AbstractValue##default"><a href="LuCI.form.AbstractValue.html#default">default</a></li>
339
340 <li data-name="LuCI.form.AbstractValue##editable"><a href="LuCI.form.AbstractValue.html#editable">editable</a></li>
341
342 <li data-name="LuCI.form.AbstractValue##modalonly"><a href="LuCI.form.AbstractValue.html#modalonly">modalonly</a></li>
343
344 <li data-name="LuCI.form.AbstractValue##onchange"><a href="LuCI.form.AbstractValue.html#onchange">onchange</a></li>
345
346 <li data-name="LuCI.form.AbstractValue##optional"><a href="LuCI.form.AbstractValue.html#optional">optional</a></li>
347
348 <li data-name="LuCI.form.AbstractValue##readonly"><a href="LuCI.form.AbstractValue.html#readonly">readonly</a></li>
349
350 <li data-name="LuCI.form.AbstractValue##rmempty"><a href="LuCI.form.AbstractValue.html#rmempty">rmempty</a></li>
351
352 <li data-name="LuCI.form.AbstractValue##uciconfig"><a href="LuCI.form.AbstractValue.html#uciconfig">uciconfig</a></li>
353
354 <li data-name="LuCI.form.AbstractValue##ucioption"><a href="LuCI.form.AbstractValue.html#ucioption">ucioption</a></li>
355
356 <li data-name="LuCI.form.AbstractValue##ucisection"><a href="LuCI.form.AbstractValue.html#ucisection">ucisection</a></li>
357
358 <li data-name="LuCI.form.AbstractValue##validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
359
360 <li data-name="LuCI.form.AbstractValue##width"><a href="LuCI.form.AbstractValue.html#width">width</a></li>
361
362 </ul>
363 <ul class="typedefs itemMembers">
364
365 </ul>
366 <ul class="typedefs itemMembers">
367
368 </ul>
369 <ul class="methods itemMembers">
370
371 <span class="subtitle">Methods</span>
372
373 <li data-name="LuCI.form.AbstractValue#append"><a href="LuCI.form.AbstractValue.html#append">append</a></li>
374
375 <li data-name="LuCI.form.AbstractValue#cbid"><a href="LuCI.form.AbstractValue.html#cbid">cbid</a></li>
376
377 <li data-name="LuCI.form.AbstractValue#cfgvalue"><a href="LuCI.form.AbstractValue.html#cfgvalue">cfgvalue</a></li>
378
379 <li data-name="LuCI.form.AbstractValue#depends"><a href="LuCI.form.AbstractValue.html#depends">depends</a></li>
380
381 <li data-name="LuCI.form.AbstractValue#formvalue"><a href="LuCI.form.AbstractValue.html#formvalue">formvalue</a></li>
382
383 <li data-name="LuCI.form.AbstractValue#getUIElement"><a href="LuCI.form.AbstractValue.html#getUIElement">getUIElement</a></li>
384
385 <li data-name="LuCI.form.AbstractValue#isActive"><a href="LuCI.form.AbstractValue.html#isActive">isActive</a></li>
386
387 <li data-name="LuCI.form.AbstractValue#isValid"><a href="LuCI.form.AbstractValue.html#isValid">isValid</a></li>
388
389 <li data-name="LuCI.form.AbstractValue#load"><a href="LuCI.form.AbstractValue.html#load">load</a></li>
390
391 <li data-name="LuCI.form.AbstractValue#parse"><a href="LuCI.form.AbstractValue.html#parse">parse</a></li>
392
393 <li data-name="LuCI.form.AbstractValue#remove"><a href="LuCI.form.AbstractValue.html#remove">remove</a></li>
394
395 <li data-name="LuCI.form.AbstractValue#render"><a href="LuCI.form.AbstractValue.html#render">render</a></li>
396
397 <li data-name="LuCI.form.AbstractValue#stripTags"><a href="LuCI.form.AbstractValue.html#stripTags">stripTags</a></li>
398
399 <li data-name="LuCI.form.AbstractValue#textvalue"><a href="LuCI.form.AbstractValue.html#textvalue">textvalue</a></li>
400
401 <li data-name="LuCI.form.AbstractValue#titleFn"><a href="LuCI.form.AbstractValue.html#titleFn">titleFn</a></li>
402
403 <li data-name="LuCI.form.AbstractValue#validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
404
405 <li data-name="LuCI.form.AbstractValue#write"><a href="LuCI.form.AbstractValue.html#write">write</a></li>
406
407 </ul>
408 <ul class="events itemMembers">
409
410 </ul>
411 </li>
412
413 <li class="item" data-name="LuCI.form.ButtonValue">
414 <span class="title">
415 <a href="LuCI.form.ButtonValue.html">LuCI.form.ButtonValue</a>
416
417 </span>
418 <ul class="members itemMembers">
419
420 <span class="subtitle">Members</span>
421
422 <li data-name="LuCI.form.ButtonValue##inputstyle"><a href="LuCI.form.ButtonValue.html#inputstyle">inputstyle</a></li>
423
424 <li data-name="LuCI.form.ButtonValue##inputtitle"><a href="LuCI.form.ButtonValue.html#inputtitle">inputtitle</a></li>
425
426 <li data-name="LuCI.form.ButtonValue##onclick"><a href="LuCI.form.ButtonValue.html#onclick">onclick</a></li>
427
428 <li data-name="LuCI.form.ButtonValue#datatype"><a href="LuCI.form.ButtonValue.html#datatype">datatype</a></li>
429
430 <li data-name="LuCI.form.ButtonValue#default"><a href="LuCI.form.ButtonValue.html#default">default</a></li>
431
432 <li data-name="LuCI.form.ButtonValue#editable"><a href="LuCI.form.ButtonValue.html#editable">editable</a></li>
433
434 <li data-name="LuCI.form.ButtonValue#modalonly"><a href="LuCI.form.ButtonValue.html#modalonly">modalonly</a></li>
435
436 <li data-name="LuCI.form.ButtonValue#onchange"><a href="LuCI.form.ButtonValue.html#onchange">onchange</a></li>
437
438 <li data-name="LuCI.form.ButtonValue#optional"><a href="LuCI.form.ButtonValue.html#optional">optional</a></li>
439
440 <li data-name="LuCI.form.ButtonValue#password"><a href="LuCI.form.ButtonValue.html#password">password</a></li>
441
442 <li data-name="LuCI.form.ButtonValue#placeholder"><a href="LuCI.form.ButtonValue.html#placeholder">placeholder</a></li>
443
444 <li data-name="LuCI.form.ButtonValue#readonly"><a href="LuCI.form.ButtonValue.html#readonly">readonly</a></li>
445
446 <li data-name="LuCI.form.ButtonValue#rmempty"><a href="LuCI.form.ButtonValue.html#rmempty">rmempty</a></li>
447
448 <li data-name="LuCI.form.ButtonValue#uciconfig"><a href="LuCI.form.ButtonValue.html#uciconfig">uciconfig</a></li>
449
450 <li data-name="LuCI.form.ButtonValue#ucioption"><a href="LuCI.form.ButtonValue.html#ucioption">ucioption</a></li>
451
452 <li data-name="LuCI.form.ButtonValue#ucisection"><a href="LuCI.form.ButtonValue.html#ucisection">ucisection</a></li>
453
454 <li data-name="LuCI.form.ButtonValue#validate"><a href="LuCI.form.ButtonValue.html#validate">validate</a></li>
455
456 <li data-name="LuCI.form.ButtonValue#width"><a href="LuCI.form.ButtonValue.html#width">width</a></li>
457
458 </ul>
459 <ul class="typedefs itemMembers">
460
461 </ul>
462 <ul class="typedefs itemMembers">
463
464 </ul>
465 <ul class="methods itemMembers">
466
467 <span class="subtitle">Methods</span>
468
469 <li data-name="LuCI.form.ButtonValue#append"><a href="LuCI.form.ButtonValue.html#append">append</a></li>
470
471 <li data-name="LuCI.form.ButtonValue#cbid"><a href="LuCI.form.ButtonValue.html#cbid">cbid</a></li>
472
473 <li data-name="LuCI.form.ButtonValue#cfgvalue"><a href="LuCI.form.ButtonValue.html#cfgvalue">cfgvalue</a></li>
474
475 <li data-name="LuCI.form.ButtonValue#depends"><a href="LuCI.form.ButtonValue.html#depends">depends</a></li>
476
477 <li data-name="LuCI.form.ButtonValue#formvalue"><a href="LuCI.form.ButtonValue.html#formvalue">formvalue</a></li>
478
479 <li data-name="LuCI.form.ButtonValue#getUIElement"><a href="LuCI.form.ButtonValue.html#getUIElement">getUIElement</a></li>
480
481 <li data-name="LuCI.form.ButtonValue#isActive"><a href="LuCI.form.ButtonValue.html#isActive">isActive</a></li>
482
483 <li data-name="LuCI.form.ButtonValue#isValid"><a href="LuCI.form.ButtonValue.html#isValid">isValid</a></li>
484
485 <li data-name="LuCI.form.ButtonValue#load"><a href="LuCI.form.ButtonValue.html#load">load</a></li>
486
487 <li data-name="LuCI.form.ButtonValue#parse"><a href="LuCI.form.ButtonValue.html#parse">parse</a></li>
488
489 <li data-name="LuCI.form.ButtonValue#remove"><a href="LuCI.form.ButtonValue.html#remove">remove</a></li>
490
491 <li data-name="LuCI.form.ButtonValue#stripTags"><a href="LuCI.form.ButtonValue.html#stripTags">stripTags</a></li>
492
493 <li data-name="LuCI.form.ButtonValue#textvalue"><a href="LuCI.form.ButtonValue.html#textvalue">textvalue</a></li>
494
495 <li data-name="LuCI.form.ButtonValue#titleFn"><a href="LuCI.form.ButtonValue.html#titleFn">titleFn</a></li>
496
497 <li data-name="LuCI.form.ButtonValue#value"><a href="LuCI.form.ButtonValue.html#value">value</a></li>
498
499 <li data-name="LuCI.form.ButtonValue#write"><a href="LuCI.form.ButtonValue.html#write">write</a></li>
500
501 </ul>
502 <ul class="events itemMembers">
503
504 </ul>
505 </li>
506
507 <li class="item" data-name="LuCI.form.DummyValue">
508 <span class="title">
509 <a href="LuCI.form.DummyValue.html">LuCI.form.DummyValue</a>
510
511 </span>
512 <ul class="members itemMembers">
513
514 <span class="subtitle">Members</span>
515
516 <li data-name="LuCI.form.DummyValue##href"><a href="LuCI.form.DummyValue.html#href">href</a></li>
517
518 <li data-name="LuCI.form.DummyValue##rawhtml"><a href="LuCI.form.DummyValue.html#rawhtml">rawhtml</a></li>
519
520 <li data-name="LuCI.form.DummyValue#datatype"><a href="LuCI.form.DummyValue.html#datatype">datatype</a></li>
521
522 <li data-name="LuCI.form.DummyValue#default"><a href="LuCI.form.DummyValue.html#default">default</a></li>
523
524 <li data-name="LuCI.form.DummyValue#editable"><a href="LuCI.form.DummyValue.html#editable">editable</a></li>
525
526 <li data-name="LuCI.form.DummyValue#modalonly"><a href="LuCI.form.DummyValue.html#modalonly">modalonly</a></li>
527
528 <li data-name="LuCI.form.DummyValue#onchange"><a href="LuCI.form.DummyValue.html#onchange">onchange</a></li>
529
530 <li data-name="LuCI.form.DummyValue#optional"><a href="LuCI.form.DummyValue.html#optional">optional</a></li>
531
532 <li data-name="LuCI.form.DummyValue#password"><a href="LuCI.form.DummyValue.html#password">password</a></li>
533
534 <li data-name="LuCI.form.DummyValue#placeholder"><a href="LuCI.form.DummyValue.html#placeholder">placeholder</a></li>
535
536 <li data-name="LuCI.form.DummyValue#readonly"><a href="LuCI.form.DummyValue.html#readonly">readonly</a></li>
537
538 <li data-name="LuCI.form.DummyValue#rmempty"><a href="LuCI.form.DummyValue.html#rmempty">rmempty</a></li>
539
540 <li data-name="LuCI.form.DummyValue#uciconfig"><a href="LuCI.form.DummyValue.html#uciconfig">uciconfig</a></li>
541
542 <li data-name="LuCI.form.DummyValue#ucioption"><a href="LuCI.form.DummyValue.html#ucioption">ucioption</a></li>
543
544 <li data-name="LuCI.form.DummyValue#ucisection"><a href="LuCI.form.DummyValue.html#ucisection">ucisection</a></li>
545
546 <li data-name="LuCI.form.DummyValue#validate"><a href="LuCI.form.DummyValue.html#validate">validate</a></li>
547
548 <li data-name="LuCI.form.DummyValue#width"><a href="LuCI.form.DummyValue.html#width">width</a></li>
549
550 </ul>
551 <ul class="typedefs itemMembers">
552
553 </ul>
554 <ul class="typedefs itemMembers">
555
556 </ul>
557 <ul class="methods itemMembers">
558
559 <span class="subtitle">Methods</span>
560
561 <li data-name="LuCI.form.DummyValue#append"><a href="LuCI.form.DummyValue.html#append">append</a></li>
562
563 <li data-name="LuCI.form.DummyValue#cbid"><a href="LuCI.form.DummyValue.html#cbid">cbid</a></li>
564
565 <li data-name="LuCI.form.DummyValue#cfgvalue"><a href="LuCI.form.DummyValue.html#cfgvalue">cfgvalue</a></li>
566
567 <li data-name="LuCI.form.DummyValue#depends"><a href="LuCI.form.DummyValue.html#depends">depends</a></li>
568
569 <li data-name="LuCI.form.DummyValue#formvalue"><a href="LuCI.form.DummyValue.html#formvalue">formvalue</a></li>
570
571 <li data-name="LuCI.form.DummyValue#getUIElement"><a href="LuCI.form.DummyValue.html#getUIElement">getUIElement</a></li>
572
573 <li data-name="LuCI.form.DummyValue#isActive"><a href="LuCI.form.DummyValue.html#isActive">isActive</a></li>
574
575 <li data-name="LuCI.form.DummyValue#isValid"><a href="LuCI.form.DummyValue.html#isValid">isValid</a></li>
576
577 <li data-name="LuCI.form.DummyValue#load"><a href="LuCI.form.DummyValue.html#load">load</a></li>
578
579 <li data-name="LuCI.form.DummyValue#parse"><a href="LuCI.form.DummyValue.html#parse">parse</a></li>
580
581 <li data-name="LuCI.form.DummyValue#remove"><a href="LuCI.form.DummyValue.html#remove">remove</a></li>
582
583 <li data-name="LuCI.form.DummyValue#stripTags"><a href="LuCI.form.DummyValue.html#stripTags">stripTags</a></li>
584
585 <li data-name="LuCI.form.DummyValue#textvalue"><a href="LuCI.form.DummyValue.html#textvalue">textvalue</a></li>
586
587 <li data-name="LuCI.form.DummyValue#titleFn"><a href="LuCI.form.DummyValue.html#titleFn">titleFn</a></li>
588
589 <li data-name="LuCI.form.DummyValue#value"><a href="LuCI.form.DummyValue.html#value">value</a></li>
590
591 <li data-name="LuCI.form.DummyValue#write"><a href="LuCI.form.DummyValue.html#write">write</a></li>
592
593 </ul>
594 <ul class="events itemMembers">
595
596 </ul>
597 </li>
598
599 <li class="item" data-name="LuCI.form.DynamicList">
600 <span class="title">
601 <a href="LuCI.form.DynamicList.html">LuCI.form.DynamicList</a>
602
603 </span>
604 <ul class="members itemMembers">
605
606 <span class="subtitle">Members</span>
607
608 <li data-name="LuCI.form.DynamicList#datatype"><a href="LuCI.form.DynamicList.html#datatype">datatype</a></li>
609
610 <li data-name="LuCI.form.DynamicList#default"><a href="LuCI.form.DynamicList.html#default">default</a></li>
611
612 <li data-name="LuCI.form.DynamicList#editable"><a href="LuCI.form.DynamicList.html#editable">editable</a></li>
613
614 <li data-name="LuCI.form.DynamicList#modalonly"><a href="LuCI.form.DynamicList.html#modalonly">modalonly</a></li>
615
616 <li data-name="LuCI.form.DynamicList#onchange"><a href="LuCI.form.DynamicList.html#onchange">onchange</a></li>
617
618 <li data-name="LuCI.form.DynamicList#optional"><a href="LuCI.form.DynamicList.html#optional">optional</a></li>
619
620 <li data-name="LuCI.form.DynamicList#password"><a href="LuCI.form.DynamicList.html#password">password</a></li>
621
622 <li data-name="LuCI.form.DynamicList#placeholder"><a href="LuCI.form.DynamicList.html#placeholder">placeholder</a></li>
623
624 <li data-name="LuCI.form.DynamicList#readonly"><a href="LuCI.form.DynamicList.html#readonly">readonly</a></li>
625
626 <li data-name="LuCI.form.DynamicList#rmempty"><a href="LuCI.form.DynamicList.html#rmempty">rmempty</a></li>
627
628 <li data-name="LuCI.form.DynamicList#uciconfig"><a href="LuCI.form.DynamicList.html#uciconfig">uciconfig</a></li>
629
630 <li data-name="LuCI.form.DynamicList#ucioption"><a href="LuCI.form.DynamicList.html#ucioption">ucioption</a></li>
631
632 <li data-name="LuCI.form.DynamicList#ucisection"><a href="LuCI.form.DynamicList.html#ucisection">ucisection</a></li>
633
634 <li data-name="LuCI.form.DynamicList#validate"><a href="LuCI.form.DynamicList.html#validate">validate</a></li>
635
636 <li data-name="LuCI.form.DynamicList#width"><a href="LuCI.form.DynamicList.html#width">width</a></li>
637
638 </ul>
639 <ul class="typedefs itemMembers">
640
641 </ul>
642 <ul class="typedefs itemMembers">
643
644 </ul>
645 <ul class="methods itemMembers">
646
647 <span class="subtitle">Methods</span>
648
649 <li data-name="LuCI.form.DynamicList#append"><a href="LuCI.form.DynamicList.html#append">append</a></li>
650
651 <li data-name="LuCI.form.DynamicList#cbid"><a href="LuCI.form.DynamicList.html#cbid">cbid</a></li>
652
653 <li data-name="LuCI.form.DynamicList#cfgvalue"><a href="LuCI.form.DynamicList.html#cfgvalue">cfgvalue</a></li>
654
655 <li data-name="LuCI.form.DynamicList#depends"><a href="LuCI.form.DynamicList.html#depends">depends</a></li>
656
657 <li data-name="LuCI.form.DynamicList#formvalue"><a href="LuCI.form.DynamicList.html#formvalue">formvalue</a></li>
658
659 <li data-name="LuCI.form.DynamicList#getUIElement"><a href="LuCI.form.DynamicList.html#getUIElement">getUIElement</a></li>
660
661 <li data-name="LuCI.form.DynamicList#isActive"><a href="LuCI.form.DynamicList.html#isActive">isActive</a></li>
662
663 <li data-name="LuCI.form.DynamicList#isValid"><a href="LuCI.form.DynamicList.html#isValid">isValid</a></li>
664
665 <li data-name="LuCI.form.DynamicList#load"><a href="LuCI.form.DynamicList.html#load">load</a></li>
666
667 <li data-name="LuCI.form.DynamicList#parse"><a href="LuCI.form.DynamicList.html#parse">parse</a></li>
668
669 <li data-name="LuCI.form.DynamicList#remove"><a href="LuCI.form.DynamicList.html#remove">remove</a></li>
670
671 <li data-name="LuCI.form.DynamicList#stripTags"><a href="LuCI.form.DynamicList.html#stripTags">stripTags</a></li>
672
673 <li data-name="LuCI.form.DynamicList#textvalue"><a href="LuCI.form.DynamicList.html#textvalue">textvalue</a></li>
674
675 <li data-name="LuCI.form.DynamicList#titleFn"><a href="LuCI.form.DynamicList.html#titleFn">titleFn</a></li>
676
677 <li data-name="LuCI.form.DynamicList#value"><a href="LuCI.form.DynamicList.html#value">value</a></li>
678
679 <li data-name="LuCI.form.DynamicList#write"><a href="LuCI.form.DynamicList.html#write">write</a></li>
680
681 </ul>
682 <ul class="events itemMembers">
683
684 </ul>
685 </li>
686
687 <li class="item" data-name="LuCI.form.FileUpload">
688 <span class="title">
689 <a href="LuCI.form.FileUpload.html">LuCI.form.FileUpload</a>
690
691 </span>
692 <ul class="members itemMembers">
693
694 <span class="subtitle">Members</span>
695
696 <li data-name="LuCI.form.FileUpload##enable_remove"><a href="LuCI.form.FileUpload.html#enable_remove">enable_remove</a></li>
697
698 <li data-name="LuCI.form.FileUpload##enable_upload"><a href="LuCI.form.FileUpload.html#enable_upload">enable_upload</a></li>
699
700 <li data-name="LuCI.form.FileUpload##root_directory"><a href="LuCI.form.FileUpload.html#root_directory">root_directory</a></li>
701
702 <li data-name="LuCI.form.FileUpload##show_hidden"><a href="LuCI.form.FileUpload.html#show_hidden">show_hidden</a></li>
703
704 <li data-name="LuCI.form.FileUpload#datatype"><a href="LuCI.form.FileUpload.html#datatype">datatype</a></li>
705
706 <li data-name="LuCI.form.FileUpload#default"><a href="LuCI.form.FileUpload.html#default">default</a></li>
707
708 <li data-name="LuCI.form.FileUpload#editable"><a href="LuCI.form.FileUpload.html#editable">editable</a></li>
709
710 <li data-name="LuCI.form.FileUpload#modalonly"><a href="LuCI.form.FileUpload.html#modalonly">modalonly</a></li>
711
712 <li data-name="LuCI.form.FileUpload#onchange"><a href="LuCI.form.FileUpload.html#onchange">onchange</a></li>
713
714 <li data-name="LuCI.form.FileUpload#optional"><a href="LuCI.form.FileUpload.html#optional">optional</a></li>
715
716 <li data-name="LuCI.form.FileUpload#password"><a href="LuCI.form.FileUpload.html#password">password</a></li>
717
718 <li data-name="LuCI.form.FileUpload#placeholder"><a href="LuCI.form.FileUpload.html#placeholder">placeholder</a></li>
719
720 <li data-name="LuCI.form.FileUpload#readonly"><a href="LuCI.form.FileUpload.html#readonly">readonly</a></li>
721
722 <li data-name="LuCI.form.FileUpload#rmempty"><a href="LuCI.form.FileUpload.html#rmempty">rmempty</a></li>
723
724 <li data-name="LuCI.form.FileUpload#uciconfig"><a href="LuCI.form.FileUpload.html#uciconfig">uciconfig</a></li>
725
726 <li data-name="LuCI.form.FileUpload#ucioption"><a href="LuCI.form.FileUpload.html#ucioption">ucioption</a></li>
727
728 <li data-name="LuCI.form.FileUpload#ucisection"><a href="LuCI.form.FileUpload.html#ucisection">ucisection</a></li>
729
730 <li data-name="LuCI.form.FileUpload#validate"><a href="LuCI.form.FileUpload.html#validate">validate</a></li>
731
732 <li data-name="LuCI.form.FileUpload#width"><a href="LuCI.form.FileUpload.html#width">width</a></li>
733
734 </ul>
735 <ul class="typedefs itemMembers">
736
737 </ul>
738 <ul class="typedefs itemMembers">
739
740 </ul>
741 <ul class="methods itemMembers">
742
743 <span class="subtitle">Methods</span>
744
745 <li data-name="LuCI.form.FileUpload#append"><a href="LuCI.form.FileUpload.html#append">append</a></li>
746
747 <li data-name="LuCI.form.FileUpload#cbid"><a href="LuCI.form.FileUpload.html#cbid">cbid</a></li>
748
749 <li data-name="LuCI.form.FileUpload#cfgvalue"><a href="LuCI.form.FileUpload.html#cfgvalue">cfgvalue</a></li>
750
751 <li data-name="LuCI.form.FileUpload#depends"><a href="LuCI.form.FileUpload.html#depends">depends</a></li>
752
753 <li data-name="LuCI.form.FileUpload#formvalue"><a href="LuCI.form.FileUpload.html#formvalue">formvalue</a></li>
754
755 <li data-name="LuCI.form.FileUpload#getUIElement"><a href="LuCI.form.FileUpload.html#getUIElement">getUIElement</a></li>
756
757 <li data-name="LuCI.form.FileUpload#isActive"><a href="LuCI.form.FileUpload.html#isActive">isActive</a></li>
758
759 <li data-name="LuCI.form.FileUpload#isValid"><a href="LuCI.form.FileUpload.html#isValid">isValid</a></li>
760
761 <li data-name="LuCI.form.FileUpload#load"><a href="LuCI.form.FileUpload.html#load">load</a></li>
762
763 <li data-name="LuCI.form.FileUpload#parse"><a href="LuCI.form.FileUpload.html#parse">parse</a></li>
764
765 <li data-name="LuCI.form.FileUpload#remove"><a href="LuCI.form.FileUpload.html#remove">remove</a></li>
766
767 <li data-name="LuCI.form.FileUpload#stripTags"><a href="LuCI.form.FileUpload.html#stripTags">stripTags</a></li>
768
769 <li data-name="LuCI.form.FileUpload#textvalue"><a href="LuCI.form.FileUpload.html#textvalue">textvalue</a></li>
770
771 <li data-name="LuCI.form.FileUpload#titleFn"><a href="LuCI.form.FileUpload.html#titleFn">titleFn</a></li>
772
773 <li data-name="LuCI.form.FileUpload#value"><a href="LuCI.form.FileUpload.html#value">value</a></li>
774
775 <li data-name="LuCI.form.FileUpload#write"><a href="LuCI.form.FileUpload.html#write">write</a></li>
776
777 </ul>
778 <ul class="events itemMembers">
779
780 </ul>
781 </li>
782
783 <li class="item" data-name="LuCI.form.FlagValue">
784 <span class="title">
785 <a href="LuCI.form.FlagValue.html">LuCI.form.FlagValue</a>
786
787 </span>
788 <ul class="members itemMembers">
789
790 <span class="subtitle">Members</span>
791
792 <li data-name="LuCI.form.FlagValue##disabled"><a href="LuCI.form.FlagValue.html#disabled">disabled</a></li>
793
794 <li data-name="LuCI.form.FlagValue##enabled"><a href="LuCI.form.FlagValue.html#enabled">enabled</a></li>
795
796 <li data-name="LuCI.form.FlagValue#datatype"><a href="LuCI.form.FlagValue.html#datatype">datatype</a></li>
797
798 <li data-name="LuCI.form.FlagValue#default"><a href="LuCI.form.FlagValue.html#default">default</a></li>
799
800 <li data-name="LuCI.form.FlagValue#editable"><a href="LuCI.form.FlagValue.html#editable">editable</a></li>
801
802 <li data-name="LuCI.form.FlagValue#modalonly"><a href="LuCI.form.FlagValue.html#modalonly">modalonly</a></li>
803
804 <li data-name="LuCI.form.FlagValue#onchange"><a href="LuCI.form.FlagValue.html#onchange">onchange</a></li>
805
806 <li data-name="LuCI.form.FlagValue#optional"><a href="LuCI.form.FlagValue.html#optional">optional</a></li>
807
808 <li data-name="LuCI.form.FlagValue#password"><a href="LuCI.form.FlagValue.html#password">password</a></li>
809
810 <li data-name="LuCI.form.FlagValue#placeholder"><a href="LuCI.form.FlagValue.html#placeholder">placeholder</a></li>
811
812 <li data-name="LuCI.form.FlagValue#readonly"><a href="LuCI.form.FlagValue.html#readonly">readonly</a></li>
813
814 <li data-name="LuCI.form.FlagValue#rmempty"><a href="LuCI.form.FlagValue.html#rmempty">rmempty</a></li>
815
816 <li data-name="LuCI.form.FlagValue#uciconfig"><a href="LuCI.form.FlagValue.html#uciconfig">uciconfig</a></li>
817
818 <li data-name="LuCI.form.FlagValue#ucioption"><a href="LuCI.form.FlagValue.html#ucioption">ucioption</a></li>
819
820 <li data-name="LuCI.form.FlagValue#ucisection"><a href="LuCI.form.FlagValue.html#ucisection">ucisection</a></li>
821
822 <li data-name="LuCI.form.FlagValue#validate"><a href="LuCI.form.FlagValue.html#validate">validate</a></li>
823
824 <li data-name="LuCI.form.FlagValue#width"><a href="LuCI.form.FlagValue.html#width">width</a></li>
825
826 </ul>
827 <ul class="typedefs itemMembers">
828
829 </ul>
830 <ul class="typedefs itemMembers">
831
832 </ul>
833 <ul class="methods itemMembers">
834
835 <span class="subtitle">Methods</span>
836
837 <li data-name="LuCI.form.FlagValue#append"><a href="LuCI.form.FlagValue.html#append">append</a></li>
838
839 <li data-name="LuCI.form.FlagValue#cbid"><a href="LuCI.form.FlagValue.html#cbid">cbid</a></li>
840
841 <li data-name="LuCI.form.FlagValue#cfgvalue"><a href="LuCI.form.FlagValue.html#cfgvalue">cfgvalue</a></li>
842
843 <li data-name="LuCI.form.FlagValue#depends"><a href="LuCI.form.FlagValue.html#depends">depends</a></li>
844
845 <li data-name="LuCI.form.FlagValue#formvalue"><a href="LuCI.form.FlagValue.html#formvalue">formvalue</a></li>
846
847 <li data-name="LuCI.form.FlagValue#getUIElement"><a href="LuCI.form.FlagValue.html#getUIElement">getUIElement</a></li>
848
849 <li data-name="LuCI.form.FlagValue#isActive"><a href="LuCI.form.FlagValue.html#isActive">isActive</a></li>
850
851 <li data-name="LuCI.form.FlagValue#isValid"><a href="LuCI.form.FlagValue.html#isValid">isValid</a></li>
852
853 <li data-name="LuCI.form.FlagValue#load"><a href="LuCI.form.FlagValue.html#load">load</a></li>
854
855 <li data-name="LuCI.form.FlagValue#parse"><a href="LuCI.form.FlagValue.html#parse">parse</a></li>
856
857 <li data-name="LuCI.form.FlagValue#remove"><a href="LuCI.form.FlagValue.html#remove">remove</a></li>
858
859 <li data-name="LuCI.form.FlagValue#stripTags"><a href="LuCI.form.FlagValue.html#stripTags">stripTags</a></li>
860
861 <li data-name="LuCI.form.FlagValue#textvalue"><a href="LuCI.form.FlagValue.html#textvalue">textvalue</a></li>
862
863 <li data-name="LuCI.form.FlagValue#titleFn"><a href="LuCI.form.FlagValue.html#titleFn">titleFn</a></li>
864
865 <li data-name="LuCI.form.FlagValue#value"><a href="LuCI.form.FlagValue.html#value">value</a></li>
866
867 <li data-name="LuCI.form.FlagValue#write"><a href="LuCI.form.FlagValue.html#write">write</a></li>
868
869 </ul>
870 <ul class="events itemMembers">
871
872 </ul>
873 </li>
874
875 <li class="item" data-name="LuCI.form.GridSection">
876 <span class="title">
877 <a href="LuCI.form.GridSection.html">LuCI.form.GridSection</a>
878
879 </span>
880 <ul class="members itemMembers">
881
882 <span class="subtitle">Members</span>
883
884 <li data-name="LuCI.form.GridSection#addbtntitle"><a href="LuCI.form.GridSection.html#addbtntitle">addbtntitle</a></li>
885
886 <li data-name="LuCI.form.GridSection#addremove"><a href="LuCI.form.GridSection.html#addremove">addremove</a></li>
887
888 <li data-name="LuCI.form.GridSection#anonymous"><a href="LuCI.form.GridSection.html#anonymous">anonymous</a></li>
889
890 <li data-name="LuCI.form.GridSection#extedit"><a href="LuCI.form.GridSection.html#extedit">extedit</a></li>
891
892 <li data-name="LuCI.form.GridSection#max_cols"><a href="LuCI.form.GridSection.html#max_cols">max_cols</a></li>
893
894 <li data-name="LuCI.form.GridSection#modaltitle"><a href="LuCI.form.GridSection.html#modaltitle">modaltitle</a></li>
895
896 <li data-name="LuCI.form.GridSection#nodescriptions"><a href="LuCI.form.GridSection.html#nodescriptions">nodescriptions</a></li>
897
898 <li data-name="LuCI.form.GridSection#parentoption"><a href="LuCI.form.GridSection.html#parentoption">parentoption</a></li>
899
900 <li data-name="LuCI.form.GridSection#rowcolors"><a href="LuCI.form.GridSection.html#rowcolors">rowcolors</a></li>
901
902 <li data-name="LuCI.form.GridSection#sectiontitle"><a href="LuCI.form.GridSection.html#sectiontitle">sectiontitle</a></li>
903
904 <li data-name="LuCI.form.GridSection#sortable"><a href="LuCI.form.GridSection.html#sortable">sortable</a></li>
905
906 <li data-name="LuCI.form.GridSection#tabbed"><a href="LuCI.form.GridSection.html#tabbed">tabbed</a></li>
907
908 <li data-name="LuCI.form.GridSection#uciconfig"><a href="LuCI.form.GridSection.html#uciconfig">uciconfig</a></li>
909
910 </ul>
911 <ul class="typedefs itemMembers">
912
913 </ul>
914 <ul class="typedefs itemMembers">
915
916 </ul>
917 <ul class="methods itemMembers">
918
919 <span class="subtitle">Methods</span>
920
921 <li data-name="LuCI.form.GridSection#addModalOptions"><a href="LuCI.form.GridSection.html#addModalOptions">addModalOptions</a></li>
922
923 <li data-name="LuCI.form.GridSection#append"><a href="LuCI.form.GridSection.html#append">append</a></li>
924
925 <li data-name="LuCI.form.GridSection#cfgvalue"><a href="LuCI.form.GridSection.html#cfgvalue">cfgvalue</a></li>
926
927 <li data-name="LuCI.form.GridSection#filter"><a href="LuCI.form.GridSection.html#filter">filter</a></li>
928
929 <li data-name="LuCI.form.GridSection#formvalue"><a href="LuCI.form.GridSection.html#formvalue">formvalue</a></li>
930
931 <li data-name="LuCI.form.GridSection#getOption"><a href="LuCI.form.GridSection.html#getOption">getOption</a></li>
932
933 <li data-name="LuCI.form.GridSection#getUIElement"><a href="LuCI.form.GridSection.html#getUIElement">getUIElement</a></li>
934
935 <li data-name="LuCI.form.GridSection#load"><a href="LuCI.form.GridSection.html#load">load</a></li>
936
937 <li data-name="LuCI.form.GridSection#option"><a href="LuCI.form.GridSection.html#option">option</a></li>
938
939 <li data-name="LuCI.form.GridSection#parse"><a href="LuCI.form.GridSection.html#parse">parse</a></li>
940
941 <li data-name="LuCI.form.GridSection#stripTags"><a href="LuCI.form.GridSection.html#stripTags">stripTags</a></li>
942
943 <li data-name="LuCI.form.GridSection#tab"><a href="LuCI.form.GridSection.html#tab">tab</a></li>
944
945 <li data-name="LuCI.form.GridSection#taboption"><a href="LuCI.form.GridSection.html#taboption">taboption</a></li>
946
947 <li data-name="LuCI.form.GridSection#titleFn"><a href="LuCI.form.GridSection.html#titleFn">titleFn</a></li>
948
949 </ul>
950 <ul class="events itemMembers">
951
952 </ul>
953 </li>
954
955 <li class="item" data-name="LuCI.form.HiddenValue">
956 <span class="title">
957 <a href="LuCI.form.HiddenValue.html">LuCI.form.HiddenValue</a>
958
959 </span>
960 <ul class="members itemMembers">
961
962 <span class="subtitle">Members</span>
963
964 <li data-name="LuCI.form.HiddenValue#datatype"><a href="LuCI.form.HiddenValue.html#datatype">datatype</a></li>
965
966 <li data-name="LuCI.form.HiddenValue#default"><a href="LuCI.form.HiddenValue.html#default">default</a></li>
967
968 <li data-name="LuCI.form.HiddenValue#editable"><a href="LuCI.form.HiddenValue.html#editable">editable</a></li>
969
970 <li data-name="LuCI.form.HiddenValue#modalonly"><a href="LuCI.form.HiddenValue.html#modalonly">modalonly</a></li>
971
972 <li data-name="LuCI.form.HiddenValue#onchange"><a href="LuCI.form.HiddenValue.html#onchange">onchange</a></li>
973
974 <li data-name="LuCI.form.HiddenValue#optional"><a href="LuCI.form.HiddenValue.html#optional">optional</a></li>
975
976 <li data-name="LuCI.form.HiddenValue#password"><a href="LuCI.form.HiddenValue.html#password">password</a></li>
977
978 <li data-name="LuCI.form.HiddenValue#placeholder"><a href="LuCI.form.HiddenValue.html#placeholder">placeholder</a></li>
979
980 <li data-name="LuCI.form.HiddenValue#readonly"><a href="LuCI.form.HiddenValue.html#readonly">readonly</a></li>
981
982 <li data-name="LuCI.form.HiddenValue#rmempty"><a href="LuCI.form.HiddenValue.html#rmempty">rmempty</a></li>
983
984 <li data-name="LuCI.form.HiddenValue#uciconfig"><a href="LuCI.form.HiddenValue.html#uciconfig">uciconfig</a></li>
985
986 <li data-name="LuCI.form.HiddenValue#ucioption"><a href="LuCI.form.HiddenValue.html#ucioption">ucioption</a></li>
987
988 <li data-name="LuCI.form.HiddenValue#ucisection"><a href="LuCI.form.HiddenValue.html#ucisection">ucisection</a></li>
989
990 <li data-name="LuCI.form.HiddenValue#validate"><a href="LuCI.form.HiddenValue.html#validate">validate</a></li>
991
992 <li data-name="LuCI.form.HiddenValue#width"><a href="LuCI.form.HiddenValue.html#width">width</a></li>
993
994 </ul>
995 <ul class="typedefs itemMembers">
996
997 </ul>
998 <ul class="typedefs itemMembers">
999
1000 </ul>
1001 <ul class="methods itemMembers">
1002
1003 <span class="subtitle">Methods</span>
1004
1005 <li data-name="LuCI.form.HiddenValue#append"><a href="LuCI.form.HiddenValue.html#append">append</a></li>
1006
1007 <li data-name="LuCI.form.HiddenValue#cbid"><a href="LuCI.form.HiddenValue.html#cbid">cbid</a></li>
1008
1009 <li data-name="LuCI.form.HiddenValue#cfgvalue"><a href="LuCI.form.HiddenValue.html#cfgvalue">cfgvalue</a></li>
1010
1011 <li data-name="LuCI.form.HiddenValue#depends"><a href="LuCI.form.HiddenValue.html#depends">depends</a></li>
1012
1013 <li data-name="LuCI.form.HiddenValue#formvalue"><a href="LuCI.form.HiddenValue.html#formvalue">formvalue</a></li>
1014
1015 <li data-name="LuCI.form.HiddenValue#getUIElement"><a href="LuCI.form.HiddenValue.html#getUIElement">getUIElement</a></li>
1016
1017 <li data-name="LuCI.form.HiddenValue#isActive"><a href="LuCI.form.HiddenValue.html#isActive">isActive</a></li>
1018
1019 <li data-name="LuCI.form.HiddenValue#isValid"><a href="LuCI.form.HiddenValue.html#isValid">isValid</a></li>
1020
1021 <li data-name="LuCI.form.HiddenValue#load"><a href="LuCI.form.HiddenValue.html#load">load</a></li>
1022
1023 <li data-name="LuCI.form.HiddenValue#parse"><a href="LuCI.form.HiddenValue.html#parse">parse</a></li>
1024
1025 <li data-name="LuCI.form.HiddenValue#remove"><a href="LuCI.form.HiddenValue.html#remove">remove</a></li>
1026
1027 <li data-name="LuCI.form.HiddenValue#stripTags"><a href="LuCI.form.HiddenValue.html#stripTags">stripTags</a></li>
1028
1029 <li data-name="LuCI.form.HiddenValue#textvalue"><a href="LuCI.form.HiddenValue.html#textvalue">textvalue</a></li>
1030
1031 <li data-name="LuCI.form.HiddenValue#titleFn"><a href="LuCI.form.HiddenValue.html#titleFn">titleFn</a></li>
1032
1033 <li data-name="LuCI.form.HiddenValue#value"><a href="LuCI.form.HiddenValue.html#value">value</a></li>
1034
1035 <li data-name="LuCI.form.HiddenValue#write"><a href="LuCI.form.HiddenValue.html#write">write</a></li>
1036
1037 </ul>
1038 <ul class="events itemMembers">
1039
1040 </ul>
1041 </li>
1042
1043 <li class="item" data-name="LuCI.form.JSONMap">
1044 <span class="title">
1045 <a href="LuCI.form.JSONMap.html">LuCI.form.JSONMap</a>
1046
1047 </span>
1048 <ul class="members itemMembers">
1049
1050 <span class="subtitle">Members</span>
1051
1052 <li data-name="LuCI.form.JSONMap#readonly"><a href="LuCI.form.JSONMap.html#readonly">readonly</a></li>
1053
1054 </ul>
1055 <ul class="typedefs itemMembers">
1056
1057 </ul>
1058 <ul class="typedefs itemMembers">
1059
1060 </ul>
1061 <ul class="methods itemMembers">
1062
1063 <span class="subtitle">Methods</span>
1064
1065 <li data-name="LuCI.form.JSONMap#append"><a href="LuCI.form.JSONMap.html#append">append</a></li>
1066
1067 <li data-name="LuCI.form.JSONMap#chain"><a href="LuCI.form.JSONMap.html#chain">chain</a></li>
1068
1069 <li data-name="LuCI.form.JSONMap#findElement"><a href="LuCI.form.JSONMap.html#findElement">findElement</a></li>
1070
1071 <li data-name="LuCI.form.JSONMap#findElements"><a href="LuCI.form.JSONMap.html#findElements">findElements</a></li>
1072
1073 <li data-name="LuCI.form.JSONMap#load"><a href="LuCI.form.JSONMap.html#load">load</a></li>
1074
1075 <li data-name="LuCI.form.JSONMap#lookupOption"><a href="LuCI.form.JSONMap.html#lookupOption">lookupOption</a></li>
1076
1077 <li data-name="LuCI.form.JSONMap#parse"><a href="LuCI.form.JSONMap.html#parse">parse</a></li>
1078
1079 <li data-name="LuCI.form.JSONMap#render"><a href="LuCI.form.JSONMap.html#render">render</a></li>
1080
1081 <li data-name="LuCI.form.JSONMap#reset"><a href="LuCI.form.JSONMap.html#reset">reset</a></li>
1082
1083 <li data-name="LuCI.form.JSONMap#save"><a href="LuCI.form.JSONMap.html#save">save</a></li>
1084
1085 <li data-name="LuCI.form.JSONMap#section"><a href="LuCI.form.JSONMap.html#section">section</a></li>
1086
1087 <li data-name="LuCI.form.JSONMap#stripTags"><a href="LuCI.form.JSONMap.html#stripTags">stripTags</a></li>
1088
1089 <li data-name="LuCI.form.JSONMap#titleFn"><a href="LuCI.form.JSONMap.html#titleFn">titleFn</a></li>
1090
1091 </ul>
1092 <ul class="events itemMembers">
1093
1094 </ul>
1095 </li>
1096
1097 <li class="item" data-name="LuCI.form.ListValue">
1098 <span class="title">
1099 <a href="LuCI.form.ListValue.html">LuCI.form.ListValue</a>
1100
1101 </span>
1102 <ul class="members itemMembers">
1103
1104 <span class="subtitle">Members</span>
1105
1106 <li data-name="LuCI.form.ListValue##orientation"><a href="LuCI.form.ListValue.html#orientation">orientation</a></li>
1107
1108 <li data-name="LuCI.form.ListValue##size"><a href="LuCI.form.ListValue.html#size">size</a></li>
1109
1110 <li data-name="LuCI.form.ListValue##widget"><a href="LuCI.form.ListValue.html#widget">widget</a></li>
1111
1112 <li data-name="LuCI.form.ListValue#datatype"><a href="LuCI.form.ListValue.html#datatype">datatype</a></li>
1113
1114 <li data-name="LuCI.form.ListValue#default"><a href="LuCI.form.ListValue.html#default">default</a></li>
1115
1116 <li data-name="LuCI.form.ListValue#editable"><a href="LuCI.form.ListValue.html#editable">editable</a></li>
1117
1118 <li data-name="LuCI.form.ListValue#modalonly"><a href="LuCI.form.ListValue.html#modalonly">modalonly</a></li>
1119
1120 <li data-name="LuCI.form.ListValue#onchange"><a href="LuCI.form.ListValue.html#onchange">onchange</a></li>
1121
1122 <li data-name="LuCI.form.ListValue#optional"><a href="LuCI.form.ListValue.html#optional">optional</a></li>
1123
1124 <li data-name="LuCI.form.ListValue#password"><a href="LuCI.form.ListValue.html#password">password</a></li>
1125
1126 <li data-name="LuCI.form.ListValue#placeholder"><a href="LuCI.form.ListValue.html#placeholder">placeholder</a></li>
1127
1128 <li data-name="LuCI.form.ListValue#readonly"><a href="LuCI.form.ListValue.html#readonly">readonly</a></li>
1129
1130 <li data-name="LuCI.form.ListValue#rmempty"><a href="LuCI.form.ListValue.html#rmempty">rmempty</a></li>
1131
1132 <li data-name="LuCI.form.ListValue#uciconfig"><a href="LuCI.form.ListValue.html#uciconfig">uciconfig</a></li>
1133
1134 <li data-name="LuCI.form.ListValue#ucioption"><a href="LuCI.form.ListValue.html#ucioption">ucioption</a></li>
1135
1136 <li data-name="LuCI.form.ListValue#ucisection"><a href="LuCI.form.ListValue.html#ucisection">ucisection</a></li>
1137
1138 <li data-name="LuCI.form.ListValue#validate"><a href="LuCI.form.ListValue.html#validate">validate</a></li>
1139
1140 <li data-name="LuCI.form.ListValue#width"><a href="LuCI.form.ListValue.html#width">width</a></li>
1141
1142 </ul>
1143 <ul class="typedefs itemMembers">
1144
1145 </ul>
1146 <ul class="typedefs itemMembers">
1147
1148 </ul>
1149 <ul class="methods itemMembers">
1150
1151 <span class="subtitle">Methods</span>
1152
1153 <li data-name="LuCI.form.ListValue#append"><a href="LuCI.form.ListValue.html#append">append</a></li>
1154
1155 <li data-name="LuCI.form.ListValue#cbid"><a href="LuCI.form.ListValue.html#cbid">cbid</a></li>
1156
1157 <li data-name="LuCI.form.ListValue#cfgvalue"><a href="LuCI.form.ListValue.html#cfgvalue">cfgvalue</a></li>
1158
1159 <li data-name="LuCI.form.ListValue#depends"><a href="LuCI.form.ListValue.html#depends">depends</a></li>
1160
1161 <li data-name="LuCI.form.ListValue#formvalue"><a href="LuCI.form.ListValue.html#formvalue">formvalue</a></li>
1162
1163 <li data-name="LuCI.form.ListValue#getUIElement"><a href="LuCI.form.ListValue.html#getUIElement">getUIElement</a></li>
1164
1165 <li data-name="LuCI.form.ListValue#isActive"><a href="LuCI.form.ListValue.html#isActive">isActive</a></li>
1166
1167 <li data-name="LuCI.form.ListValue#isValid"><a href="LuCI.form.ListValue.html#isValid">isValid</a></li>
1168
1169 <li data-name="LuCI.form.ListValue#load"><a href="LuCI.form.ListValue.html#load">load</a></li>
1170
1171 <li data-name="LuCI.form.ListValue#parse"><a href="LuCI.form.ListValue.html#parse">parse</a></li>
1172
1173 <li data-name="LuCI.form.ListValue#remove"><a href="LuCI.form.ListValue.html#remove">remove</a></li>
1174
1175 <li data-name="LuCI.form.ListValue#stripTags"><a href="LuCI.form.ListValue.html#stripTags">stripTags</a></li>
1176
1177 <li data-name="LuCI.form.ListValue#textvalue"><a href="LuCI.form.ListValue.html#textvalue">textvalue</a></li>
1178
1179 <li data-name="LuCI.form.ListValue#titleFn"><a href="LuCI.form.ListValue.html#titleFn">titleFn</a></li>
1180
1181 <li data-name="LuCI.form.ListValue#value"><a href="LuCI.form.ListValue.html#value">value</a></li>
1182
1183 <li data-name="LuCI.form.ListValue#write"><a href="LuCI.form.ListValue.html#write">write</a></li>
1184
1185 </ul>
1186 <ul class="events itemMembers">
1187
1188 </ul>
1189 </li>
1190
1191 <li class="item" data-name="LuCI.form.Map">
1192 <span class="title">
1193 <a href="LuCI.form.Map.html">LuCI.form.Map</a>
1194
1195 </span>
1196 <ul class="members itemMembers">
1197
1198 <span class="subtitle">Members</span>
1199
1200 <li data-name="LuCI.form.Map##readonly"><a href="LuCI.form.Map.html#readonly">readonly</a></li>
1201
1202 </ul>
1203 <ul class="typedefs itemMembers">
1204
1205 </ul>
1206 <ul class="typedefs itemMembers">
1207
1208 </ul>
1209 <ul class="methods itemMembers">
1210
1211 <span class="subtitle">Methods</span>
1212
1213 <li data-name="LuCI.form.Map#append"><a href="LuCI.form.Map.html#append">append</a></li>
1214
1215 <li data-name="LuCI.form.Map#chain"><a href="LuCI.form.Map.html#chain">chain</a></li>
1216
1217 <li data-name="LuCI.form.Map#findElement"><a href="LuCI.form.Map.html#findElement">findElement</a></li>
1218
1219 <li data-name="LuCI.form.Map#findElements"><a href="LuCI.form.Map.html#findElements">findElements</a></li>
1220
1221 <li data-name="LuCI.form.Map#load"><a href="LuCI.form.Map.html#load">load</a></li>
1222
1223 <li data-name="LuCI.form.Map#lookupOption"><a href="LuCI.form.Map.html#lookupOption">lookupOption</a></li>
1224
1225 <li data-name="LuCI.form.Map#parse"><a href="LuCI.form.Map.html#parse">parse</a></li>
1226
1227 <li data-name="LuCI.form.Map#render"><a href="LuCI.form.Map.html#render">render</a></li>
1228
1229 <li data-name="LuCI.form.Map#reset"><a href="LuCI.form.Map.html#reset">reset</a></li>
1230
1231 <li data-name="LuCI.form.Map#save"><a href="LuCI.form.Map.html#save">save</a></li>
1232
1233 <li data-name="LuCI.form.Map#section"><a href="LuCI.form.Map.html#section">section</a></li>
1234
1235 <li data-name="LuCI.form.Map#stripTags"><a href="LuCI.form.Map.html#stripTags">stripTags</a></li>
1236
1237 <li data-name="LuCI.form.Map#titleFn"><a href="LuCI.form.Map.html#titleFn">titleFn</a></li>
1238
1239 </ul>
1240 <ul class="events itemMembers">
1241
1242 </ul>
1243 </li>
1244
1245 <li class="item" data-name="LuCI.form.MultiValue">
1246 <span class="title">
1247 <a href="LuCI.form.MultiValue.html">LuCI.form.MultiValue</a>
1248
1249 </span>
1250 <ul class="members itemMembers">
1251
1252 <span class="subtitle">Members</span>
1253
1254 <li data-name="LuCI.form.MultiValue##display_size"><a href="LuCI.form.MultiValue.html#display_size">display_size</a></li>
1255
1256 <li data-name="LuCI.form.MultiValue##dropdown_size"><a href="LuCI.form.MultiValue.html#dropdown_size">dropdown_size</a></li>
1257
1258 <li data-name="LuCI.form.MultiValue#datatype"><a href="LuCI.form.MultiValue.html#datatype">datatype</a></li>
1259
1260 <li data-name="LuCI.form.MultiValue#default"><a href="LuCI.form.MultiValue.html#default">default</a></li>
1261
1262 <li data-name="LuCI.form.MultiValue#editable"><a href="LuCI.form.MultiValue.html#editable">editable</a></li>
1263
1264 <li data-name="LuCI.form.MultiValue#modalonly"><a href="LuCI.form.MultiValue.html#modalonly">modalonly</a></li>
1265
1266 <li data-name="LuCI.form.MultiValue#onchange"><a href="LuCI.form.MultiValue.html#onchange">onchange</a></li>
1267
1268 <li data-name="LuCI.form.MultiValue#optional"><a href="LuCI.form.MultiValue.html#optional">optional</a></li>
1269
1270 <li data-name="LuCI.form.MultiValue#password"><a href="LuCI.form.MultiValue.html#password">password</a></li>
1271
1272 <li data-name="LuCI.form.MultiValue#placeholder"><a href="LuCI.form.MultiValue.html#placeholder">placeholder</a></li>
1273
1274 <li data-name="LuCI.form.MultiValue#readonly"><a href="LuCI.form.MultiValue.html#readonly">readonly</a></li>
1275
1276 <li data-name="LuCI.form.MultiValue#rmempty"><a href="LuCI.form.MultiValue.html#rmempty">rmempty</a></li>
1277
1278 <li data-name="LuCI.form.MultiValue#uciconfig"><a href="LuCI.form.MultiValue.html#uciconfig">uciconfig</a></li>
1279
1280 <li data-name="LuCI.form.MultiValue#ucioption"><a href="LuCI.form.MultiValue.html#ucioption">ucioption</a></li>
1281
1282 <li data-name="LuCI.form.MultiValue#ucisection"><a href="LuCI.form.MultiValue.html#ucisection">ucisection</a></li>
1283
1284 <li data-name="LuCI.form.MultiValue#validate"><a href="LuCI.form.MultiValue.html#validate">validate</a></li>
1285
1286 <li data-name="LuCI.form.MultiValue#width"><a href="LuCI.form.MultiValue.html#width">width</a></li>
1287
1288 </ul>
1289 <ul class="typedefs itemMembers">
1290
1291 </ul>
1292 <ul class="typedefs itemMembers">
1293
1294 </ul>
1295 <ul class="methods itemMembers">
1296
1297 <span class="subtitle">Methods</span>
1298
1299 <li data-name="LuCI.form.MultiValue#append"><a href="LuCI.form.MultiValue.html#append">append</a></li>
1300
1301 <li data-name="LuCI.form.MultiValue#cbid"><a href="LuCI.form.MultiValue.html#cbid">cbid</a></li>
1302
1303 <li data-name="LuCI.form.MultiValue#cfgvalue"><a href="LuCI.form.MultiValue.html#cfgvalue">cfgvalue</a></li>
1304
1305 <li data-name="LuCI.form.MultiValue#depends"><a href="LuCI.form.MultiValue.html#depends">depends</a></li>
1306
1307 <li data-name="LuCI.form.MultiValue#formvalue"><a href="LuCI.form.MultiValue.html#formvalue">formvalue</a></li>
1308
1309 <li data-name="LuCI.form.MultiValue#getUIElement"><a href="LuCI.form.MultiValue.html#getUIElement">getUIElement</a></li>
1310
1311 <li data-name="LuCI.form.MultiValue#isActive"><a href="LuCI.form.MultiValue.html#isActive">isActive</a></li>
1312
1313 <li data-name="LuCI.form.MultiValue#isValid"><a href="LuCI.form.MultiValue.html#isValid">isValid</a></li>
1314
1315 <li data-name="LuCI.form.MultiValue#load"><a href="LuCI.form.MultiValue.html#load">load</a></li>
1316
1317 <li data-name="LuCI.form.MultiValue#parse"><a href="LuCI.form.MultiValue.html#parse">parse</a></li>
1318
1319 <li data-name="LuCI.form.MultiValue#remove"><a href="LuCI.form.MultiValue.html#remove">remove</a></li>
1320
1321 <li data-name="LuCI.form.MultiValue#stripTags"><a href="LuCI.form.MultiValue.html#stripTags">stripTags</a></li>
1322
1323 <li data-name="LuCI.form.MultiValue#textvalue"><a href="LuCI.form.MultiValue.html#textvalue">textvalue</a></li>
1324
1325 <li data-name="LuCI.form.MultiValue#titleFn"><a href="LuCI.form.MultiValue.html#titleFn">titleFn</a></li>
1326
1327 <li data-name="LuCI.form.MultiValue#value"><a href="LuCI.form.MultiValue.html#value">value</a></li>
1328
1329 <li data-name="LuCI.form.MultiValue#write"><a href="LuCI.form.MultiValue.html#write">write</a></li>
1330
1331 </ul>
1332 <ul class="events itemMembers">
1333
1334 </ul>
1335 </li>
1336
1337 <li class="item" data-name="LuCI.form.NamedSection">
1338 <span class="title">
1339 <a href="LuCI.form.NamedSection.html">LuCI.form.NamedSection</a>
1340
1341 </span>
1342 <ul class="members itemMembers">
1343
1344 <span class="subtitle">Members</span>
1345
1346 <li data-name="LuCI.form.NamedSection##addremove"><a href="LuCI.form.NamedSection.html#addremove">addremove</a></li>
1347
1348 <li data-name="LuCI.form.NamedSection##uciconfig"><a href="LuCI.form.NamedSection.html#uciconfig">uciconfig</a></li>
1349
1350 <li data-name="LuCI.form.NamedSection#parentoption"><a href="LuCI.form.NamedSection.html#parentoption">parentoption</a></li>
1351
1352 </ul>
1353 <ul class="typedefs itemMembers">
1354
1355 </ul>
1356 <ul class="typedefs itemMembers">
1357
1358 </ul>
1359 <ul class="methods itemMembers">
1360
1361 <span class="subtitle">Methods</span>
1362
1363 <li data-name="LuCI.form.NamedSection#append"><a href="LuCI.form.NamedSection.html#append">append</a></li>
1364
1365 <li data-name="LuCI.form.NamedSection#cfgsections"><a href="LuCI.form.NamedSection.html#cfgsections">cfgsections</a></li>
1366
1367 <li data-name="LuCI.form.NamedSection#cfgvalue"><a href="LuCI.form.NamedSection.html#cfgvalue">cfgvalue</a></li>
1368
1369 <li data-name="LuCI.form.NamedSection#filter"><a href="LuCI.form.NamedSection.html#filter">filter</a></li>
1370
1371 <li data-name="LuCI.form.NamedSection#formvalue"><a href="LuCI.form.NamedSection.html#formvalue">formvalue</a></li>
1372
1373 <li data-name="LuCI.form.NamedSection#getOption"><a href="LuCI.form.NamedSection.html#getOption">getOption</a></li>
1374
1375 <li data-name="LuCI.form.NamedSection#getUIElement"><a href="LuCI.form.NamedSection.html#getUIElement">getUIElement</a></li>
1376
1377 <li data-name="LuCI.form.NamedSection#load"><a href="LuCI.form.NamedSection.html#load">load</a></li>
1378
1379 <li data-name="LuCI.form.NamedSection#option"><a href="LuCI.form.NamedSection.html#option">option</a></li>
1380
1381 <li data-name="LuCI.form.NamedSection#parse"><a href="LuCI.form.NamedSection.html#parse">parse</a></li>
1382
1383 <li data-name="LuCI.form.NamedSection#render"><a href="LuCI.form.NamedSection.html#render">render</a></li>
1384
1385 <li data-name="LuCI.form.NamedSection#stripTags"><a href="LuCI.form.NamedSection.html#stripTags">stripTags</a></li>
1386
1387 <li data-name="LuCI.form.NamedSection#tab"><a href="LuCI.form.NamedSection.html#tab">tab</a></li>
1388
1389 <li data-name="LuCI.form.NamedSection#taboption"><a href="LuCI.form.NamedSection.html#taboption">taboption</a></li>
1390
1391 <li data-name="LuCI.form.NamedSection#titleFn"><a href="LuCI.form.NamedSection.html#titleFn">titleFn</a></li>
1392
1393 </ul>
1394 <ul class="events itemMembers">
1395
1396 </ul>
1397 </li>
1398
1399 <li class="item" data-name="LuCI.form.SectionValue">
1400 <span class="title">
1401 <a href="LuCI.form.SectionValue.html">LuCI.form.SectionValue</a>
1402
1403 </span>
1404 <ul class="members itemMembers">
1405
1406 <span class="subtitle">Members</span>
1407
1408 <li data-name="LuCI.form.SectionValue##subsection"><a href="LuCI.form.SectionValue.html#subsection">subsection</a></li>
1409
1410 <li data-name="LuCI.form.SectionValue#datatype"><a href="LuCI.form.SectionValue.html#datatype">datatype</a></li>
1411
1412 <li data-name="LuCI.form.SectionValue#default"><a href="LuCI.form.SectionValue.html#default">default</a></li>
1413
1414 <li data-name="LuCI.form.SectionValue#editable"><a href="LuCI.form.SectionValue.html#editable">editable</a></li>
1415
1416 <li data-name="LuCI.form.SectionValue#modalonly"><a href="LuCI.form.SectionValue.html#modalonly">modalonly</a></li>
1417
1418 <li data-name="LuCI.form.SectionValue#onchange"><a href="LuCI.form.SectionValue.html#onchange">onchange</a></li>
1419
1420 <li data-name="LuCI.form.SectionValue#optional"><a href="LuCI.form.SectionValue.html#optional">optional</a></li>
1421
1422 <li data-name="LuCI.form.SectionValue#password"><a href="LuCI.form.SectionValue.html#password">password</a></li>
1423
1424 <li data-name="LuCI.form.SectionValue#placeholder"><a href="LuCI.form.SectionValue.html#placeholder">placeholder</a></li>
1425
1426 <li data-name="LuCI.form.SectionValue#readonly"><a href="LuCI.form.SectionValue.html#readonly">readonly</a></li>
1427
1428 <li data-name="LuCI.form.SectionValue#rmempty"><a href="LuCI.form.SectionValue.html#rmempty">rmempty</a></li>
1429
1430 <li data-name="LuCI.form.SectionValue#uciconfig"><a href="LuCI.form.SectionValue.html#uciconfig">uciconfig</a></li>
1431
1432 <li data-name="LuCI.form.SectionValue#ucioption"><a href="LuCI.form.SectionValue.html#ucioption">ucioption</a></li>
1433
1434 <li data-name="LuCI.form.SectionValue#ucisection"><a href="LuCI.form.SectionValue.html#ucisection">ucisection</a></li>
1435
1436 <li data-name="LuCI.form.SectionValue#validate"><a href="LuCI.form.SectionValue.html#validate">validate</a></li>
1437
1438 <li data-name="LuCI.form.SectionValue#width"><a href="LuCI.form.SectionValue.html#width">width</a></li>
1439
1440 </ul>
1441 <ul class="typedefs itemMembers">
1442
1443 </ul>
1444 <ul class="typedefs itemMembers">
1445
1446 </ul>
1447 <ul class="methods itemMembers">
1448
1449 <span class="subtitle">Methods</span>
1450
1451 <li data-name="LuCI.form.SectionValue#append"><a href="LuCI.form.SectionValue.html#append">append</a></li>
1452
1453 <li data-name="LuCI.form.SectionValue#cbid"><a href="LuCI.form.SectionValue.html#cbid">cbid</a></li>
1454
1455 <li data-name="LuCI.form.SectionValue#cfgvalue"><a href="LuCI.form.SectionValue.html#cfgvalue">cfgvalue</a></li>
1456
1457 <li data-name="LuCI.form.SectionValue#depends"><a href="LuCI.form.SectionValue.html#depends">depends</a></li>
1458
1459 <li data-name="LuCI.form.SectionValue#formvalue"><a href="LuCI.form.SectionValue.html#formvalue">formvalue</a></li>
1460
1461 <li data-name="LuCI.form.SectionValue#getUIElement"><a href="LuCI.form.SectionValue.html#getUIElement">getUIElement</a></li>
1462
1463 <li data-name="LuCI.form.SectionValue#isActive"><a href="LuCI.form.SectionValue.html#isActive">isActive</a></li>
1464
1465 <li data-name="LuCI.form.SectionValue#isValid"><a href="LuCI.form.SectionValue.html#isValid">isValid</a></li>
1466
1467 <li data-name="LuCI.form.SectionValue#load"><a href="LuCI.form.SectionValue.html#load">load</a></li>
1468
1469 <li data-name="LuCI.form.SectionValue#parse"><a href="LuCI.form.SectionValue.html#parse">parse</a></li>
1470
1471 <li data-name="LuCI.form.SectionValue#remove"><a href="LuCI.form.SectionValue.html#remove">remove</a></li>
1472
1473 <li data-name="LuCI.form.SectionValue#stripTags"><a href="LuCI.form.SectionValue.html#stripTags">stripTags</a></li>
1474
1475 <li data-name="LuCI.form.SectionValue#textvalue"><a href="LuCI.form.SectionValue.html#textvalue">textvalue</a></li>
1476
1477 <li data-name="LuCI.form.SectionValue#titleFn"><a href="LuCI.form.SectionValue.html#titleFn">titleFn</a></li>
1478
1479 <li data-name="LuCI.form.SectionValue#value"><a href="LuCI.form.SectionValue.html#value">value</a></li>
1480
1481 <li data-name="LuCI.form.SectionValue#write"><a href="LuCI.form.SectionValue.html#write">write</a></li>
1482
1483 </ul>
1484 <ul class="events itemMembers">
1485
1486 </ul>
1487 </li>
1488
1489 <li class="item" data-name="LuCI.form.TableSection">
1490 <span class="title">
1491 <a href="LuCI.form.TableSection.html">LuCI.form.TableSection</a>
1492
1493 </span>
1494 <ul class="members itemMembers">
1495
1496 <span class="subtitle">Members</span>
1497
1498 <li data-name="LuCI.form.TableSection##addbtntitle"><a href="LuCI.form.TableSection.html#addbtntitle">addbtntitle</a></li>
1499
1500 <li data-name="LuCI.form.TableSection##addremove"><a href="LuCI.form.TableSection.html#addremove">addremove</a></li>
1501
1502 <li data-name="LuCI.form.TableSection##anonymous"><a href="LuCI.form.TableSection.html#anonymous">anonymous</a></li>
1503
1504 <li data-name="LuCI.form.TableSection##extedit"><a href="LuCI.form.TableSection.html#extedit">extedit</a></li>
1505
1506 <li data-name="LuCI.form.TableSection##max_cols"><a href="LuCI.form.TableSection.html#max_cols">max_cols</a></li>
1507
1508 <li data-name="LuCI.form.TableSection##modaltitle"><a href="LuCI.form.TableSection.html#modaltitle">modaltitle</a></li>
1509
1510 <li data-name="LuCI.form.TableSection##nodescriptions"><a href="LuCI.form.TableSection.html#nodescriptions">nodescriptions</a></li>
1511
1512 <li data-name="LuCI.form.TableSection##rowcolors"><a href="LuCI.form.TableSection.html#rowcolors">rowcolors</a></li>
1513
1514 <li data-name="LuCI.form.TableSection##sectiontitle"><a href="LuCI.form.TableSection.html#sectiontitle">sectiontitle</a></li>
1515
1516 <li data-name="LuCI.form.TableSection##sortable"><a href="LuCI.form.TableSection.html#sortable">sortable</a></li>
1517
1518 <li data-name="LuCI.form.TableSection##uciconfig"><a href="LuCI.form.TableSection.html#uciconfig">uciconfig</a></li>
1519
1520 <li data-name="LuCI.form.TableSection#addbtntitle"><a href="LuCI.form.TableSection.html#addbtntitle">addbtntitle</a></li>
1521
1522 <li data-name="LuCI.form.TableSection#addremove"><a href="LuCI.form.TableSection.html#addremove">addremove</a></li>
1523
1524 <li data-name="LuCI.form.TableSection#anonymous"><a href="LuCI.form.TableSection.html#anonymous">anonymous</a></li>
1525
1526 <li data-name="LuCI.form.TableSection#parentoption"><a href="LuCI.form.TableSection.html#parentoption">parentoption</a></li>
1527
1528 <li data-name="LuCI.form.TableSection#tabbed"><a href="LuCI.form.TableSection.html#tabbed">tabbed</a></li>
1529
1530 <li data-name="LuCI.form.TableSection#uciconfig"><a href="LuCI.form.TableSection.html#uciconfig">uciconfig</a></li>
1531
1532 </ul>
1533 <ul class="typedefs itemMembers">
1534
1535 </ul>
1536 <ul class="typedefs itemMembers">
1537
1538 </ul>
1539 <ul class="methods itemMembers">
1540
1541 <span class="subtitle">Methods</span>
1542
1543 <li data-name="LuCI.form.TableSection#addModalOptions"><a href="LuCI.form.TableSection.html#addModalOptions">addModalOptions</a></li>
1544
1545 <li data-name="LuCI.form.TableSection#append"><a href="LuCI.form.TableSection.html#append">append</a></li>
1546
1547 <li data-name="LuCI.form.TableSection#cfgvalue"><a href="LuCI.form.TableSection.html#cfgvalue">cfgvalue</a></li>
1548
1549 <li data-name="LuCI.form.TableSection#filter"><a href="LuCI.form.TableSection.html#filter">filter</a></li>
1550
1551 <li data-name="LuCI.form.TableSection#formvalue"><a href="LuCI.form.TableSection.html#formvalue">formvalue</a></li>
1552
1553 <li data-name="LuCI.form.TableSection#getOption"><a href="LuCI.form.TableSection.html#getOption">getOption</a></li>
1554
1555 <li data-name="LuCI.form.TableSection#getUIElement"><a href="LuCI.form.TableSection.html#getUIElement">getUIElement</a></li>
1556
1557 <li data-name="LuCI.form.TableSection#load"><a href="LuCI.form.TableSection.html#load">load</a></li>
1558
1559 <li data-name="LuCI.form.TableSection#option"><a href="LuCI.form.TableSection.html#option">option</a></li>
1560
1561 <li data-name="LuCI.form.TableSection#parse"><a href="LuCI.form.TableSection.html#parse">parse</a></li>
1562
1563 <li data-name="LuCI.form.TableSection#stripTags"><a href="LuCI.form.TableSection.html#stripTags">stripTags</a></li>
1564
1565 <li data-name="LuCI.form.TableSection#tab"><a href="LuCI.form.TableSection.html#tab">tab</a></li>
1566
1567 <li data-name="LuCI.form.TableSection#taboption"><a href="LuCI.form.TableSection.html#taboption">taboption</a></li>
1568
1569 <li data-name="LuCI.form.TableSection#titleFn"><a href="LuCI.form.TableSection.html#titleFn">titleFn</a></li>
1570
1571 </ul>
1572 <ul class="events itemMembers">
1573
1574 </ul>
1575 </li>
1576
1577 <li class="item" data-name="LuCI.form.TextValue">
1578 <span class="title">
1579 <a href="LuCI.form.TextValue.html">LuCI.form.TextValue</a>
1580
1581 </span>
1582 <ul class="members itemMembers">
1583
1584 <span class="subtitle">Members</span>
1585
1586 <li data-name="LuCI.form.TextValue##cols"><a href="LuCI.form.TextValue.html#cols">cols</a></li>
1587
1588 <li data-name="LuCI.form.TextValue##monospace"><a href="LuCI.form.TextValue.html#monospace">monospace</a></li>
1589
1590 <li data-name="LuCI.form.TextValue##rows"><a href="LuCI.form.TextValue.html#rows">rows</a></li>
1591
1592 <li data-name="LuCI.form.TextValue##wrap"><a href="LuCI.form.TextValue.html#wrap">wrap</a></li>
1593
1594 <li data-name="LuCI.form.TextValue#datatype"><a href="LuCI.form.TextValue.html#datatype">datatype</a></li>
1595
1596 <li data-name="LuCI.form.TextValue#default"><a href="LuCI.form.TextValue.html#default">default</a></li>
1597
1598 <li data-name="LuCI.form.TextValue#editable"><a href="LuCI.form.TextValue.html#editable">editable</a></li>
1599
1600 <li data-name="LuCI.form.TextValue#modalonly"><a href="LuCI.form.TextValue.html#modalonly">modalonly</a></li>
1601
1602 <li data-name="LuCI.form.TextValue#onchange"><a href="LuCI.form.TextValue.html#onchange">onchange</a></li>
1603
1604 <li data-name="LuCI.form.TextValue#optional"><a href="LuCI.form.TextValue.html#optional">optional</a></li>
1605
1606 <li data-name="LuCI.form.TextValue#password"><a href="LuCI.form.TextValue.html#password">password</a></li>
1607
1608 <li data-name="LuCI.form.TextValue#placeholder"><a href="LuCI.form.TextValue.html#placeholder">placeholder</a></li>
1609
1610 <li data-name="LuCI.form.TextValue#readonly"><a href="LuCI.form.TextValue.html#readonly">readonly</a></li>
1611
1612 <li data-name="LuCI.form.TextValue#rmempty"><a href="LuCI.form.TextValue.html#rmempty">rmempty</a></li>
1613
1614 <li data-name="LuCI.form.TextValue#uciconfig"><a href="LuCI.form.TextValue.html#uciconfig">uciconfig</a></li>
1615
1616 <li data-name="LuCI.form.TextValue#ucioption"><a href="LuCI.form.TextValue.html#ucioption">ucioption</a></li>
1617
1618 <li data-name="LuCI.form.TextValue#ucisection"><a href="LuCI.form.TextValue.html#ucisection">ucisection</a></li>
1619
1620 <li data-name="LuCI.form.TextValue#validate"><a href="LuCI.form.TextValue.html#validate">validate</a></li>
1621
1622 <li data-name="LuCI.form.TextValue#width"><a href="LuCI.form.TextValue.html#width">width</a></li>
1623
1624 </ul>
1625 <ul class="typedefs itemMembers">
1626
1627 </ul>
1628 <ul class="typedefs itemMembers">
1629
1630 </ul>
1631 <ul class="methods itemMembers">
1632
1633 <span class="subtitle">Methods</span>
1634
1635 <li data-name="LuCI.form.TextValue#append"><a href="LuCI.form.TextValue.html#append">append</a></li>
1636
1637 <li data-name="LuCI.form.TextValue#cbid"><a href="LuCI.form.TextValue.html#cbid">cbid</a></li>
1638
1639 <li data-name="LuCI.form.TextValue#cfgvalue"><a href="LuCI.form.TextValue.html#cfgvalue">cfgvalue</a></li>
1640
1641 <li data-name="LuCI.form.TextValue#depends"><a href="LuCI.form.TextValue.html#depends">depends</a></li>
1642
1643 <li data-name="LuCI.form.TextValue#formvalue"><a href="LuCI.form.TextValue.html#formvalue">formvalue</a></li>
1644
1645 <li data-name="LuCI.form.TextValue#getUIElement"><a href="LuCI.form.TextValue.html#getUIElement">getUIElement</a></li>
1646
1647 <li data-name="LuCI.form.TextValue#isActive"><a href="LuCI.form.TextValue.html#isActive">isActive</a></li>
1648
1649 <li data-name="LuCI.form.TextValue#isValid"><a href="LuCI.form.TextValue.html#isValid">isValid</a></li>
1650
1651 <li data-name="LuCI.form.TextValue#load"><a href="LuCI.form.TextValue.html#load">load</a></li>
1652
1653 <li data-name="LuCI.form.TextValue#parse"><a href="LuCI.form.TextValue.html#parse">parse</a></li>
1654
1655 <li data-name="LuCI.form.TextValue#remove"><a href="LuCI.form.TextValue.html#remove">remove</a></li>
1656
1657 <li data-name="LuCI.form.TextValue#stripTags"><a href="LuCI.form.TextValue.html#stripTags">stripTags</a></li>
1658
1659 <li data-name="LuCI.form.TextValue#textvalue"><a href="LuCI.form.TextValue.html#textvalue">textvalue</a></li>
1660
1661 <li data-name="LuCI.form.TextValue#titleFn"><a href="LuCI.form.TextValue.html#titleFn">titleFn</a></li>
1662
1663 <li data-name="LuCI.form.TextValue#write"><a href="LuCI.form.TextValue.html#write">write</a></li>
1664
1665 </ul>
1666 <ul class="events itemMembers">
1667
1668 </ul>
1669 </li>
1670
1671 <li class="item" data-name="LuCI.form.TypedSection">
1672 <span class="title">
1673 <a href="LuCI.form.TypedSection.html">LuCI.form.TypedSection</a>
1674
1675 </span>
1676 <ul class="members itemMembers">
1677
1678 <span class="subtitle">Members</span>
1679
1680 <li data-name="LuCI.form.TypedSection##addbtntitle"><a href="LuCI.form.TypedSection.html#addbtntitle">addbtntitle</a></li>
1681
1682 <li data-name="LuCI.form.TypedSection##addremove"><a href="LuCI.form.TypedSection.html#addremove">addremove</a></li>
1683
1684 <li data-name="LuCI.form.TypedSection##anonymous"><a href="LuCI.form.TypedSection.html#anonymous">anonymous</a></li>
1685
1686 <li data-name="LuCI.form.TypedSection##tabbed"><a href="LuCI.form.TypedSection.html#tabbed">tabbed</a></li>
1687
1688 <li data-name="LuCI.form.TypedSection##uciconfig"><a href="LuCI.form.TypedSection.html#uciconfig">uciconfig</a></li>
1689
1690 <li data-name="LuCI.form.TypedSection#parentoption"><a href="LuCI.form.TypedSection.html#parentoption">parentoption</a></li>
1691
1692 </ul>
1693 <ul class="typedefs itemMembers">
1694
1695 </ul>
1696 <ul class="typedefs itemMembers">
1697
1698 </ul>
1699 <ul class="methods itemMembers">
1700
1701 <span class="subtitle">Methods</span>
1702
1703 <li data-name="LuCI.form.TypedSection#append"><a href="LuCI.form.TypedSection.html#append">append</a></li>
1704
1705 <li data-name="LuCI.form.TypedSection#cfgsections"><a href="LuCI.form.TypedSection.html#cfgsections">cfgsections</a></li>
1706
1707 <li data-name="LuCI.form.TypedSection#cfgvalue"><a href="LuCI.form.TypedSection.html#cfgvalue">cfgvalue</a></li>
1708
1709 <li data-name="LuCI.form.TypedSection#filter"><a href="LuCI.form.TypedSection.html#filter">filter</a></li>
1710
1711 <li data-name="LuCI.form.TypedSection#formvalue"><a href="LuCI.form.TypedSection.html#formvalue">formvalue</a></li>
1712
1713 <li data-name="LuCI.form.TypedSection#getOption"><a href="LuCI.form.TypedSection.html#getOption">getOption</a></li>
1714
1715 <li data-name="LuCI.form.TypedSection#getUIElement"><a href="LuCI.form.TypedSection.html#getUIElement">getUIElement</a></li>
1716
1717 <li data-name="LuCI.form.TypedSection#load"><a href="LuCI.form.TypedSection.html#load">load</a></li>
1718
1719 <li data-name="LuCI.form.TypedSection#option"><a href="LuCI.form.TypedSection.html#option">option</a></li>
1720
1721 <li data-name="LuCI.form.TypedSection#parse"><a href="LuCI.form.TypedSection.html#parse">parse</a></li>
1722
1723 <li data-name="LuCI.form.TypedSection#render"><a href="LuCI.form.TypedSection.html#render">render</a></li>
1724
1725 <li data-name="LuCI.form.TypedSection#stripTags"><a href="LuCI.form.TypedSection.html#stripTags">stripTags</a></li>
1726
1727 <li data-name="LuCI.form.TypedSection#tab"><a href="LuCI.form.TypedSection.html#tab">tab</a></li>
1728
1729 <li data-name="LuCI.form.TypedSection#taboption"><a href="LuCI.form.TypedSection.html#taboption">taboption</a></li>
1730
1731 <li data-name="LuCI.form.TypedSection#titleFn"><a href="LuCI.form.TypedSection.html#titleFn">titleFn</a></li>
1732
1733 </ul>
1734 <ul class="events itemMembers">
1735
1736 </ul>
1737 </li>
1738
1739 <li class="item" data-name="LuCI.form.Value">
1740 <span class="title">
1741 <a href="LuCI.form.Value.html">LuCI.form.Value</a>
1742
1743 </span>
1744 <ul class="members itemMembers">
1745
1746 <span class="subtitle">Members</span>
1747
1748 <li data-name="LuCI.form.Value##password"><a href="LuCI.form.Value.html#password">password</a></li>
1749
1750 <li data-name="LuCI.form.Value##placeholder"><a href="LuCI.form.Value.html#placeholder">placeholder</a></li>
1751
1752 <li data-name="LuCI.form.Value#datatype"><a href="LuCI.form.Value.html#datatype">datatype</a></li>
1753
1754 <li data-name="LuCI.form.Value#default"><a href="LuCI.form.Value.html#default">default</a></li>
1755
1756 <li data-name="LuCI.form.Value#editable"><a href="LuCI.form.Value.html#editable">editable</a></li>
1757
1758 <li data-name="LuCI.form.Value#modalonly"><a href="LuCI.form.Value.html#modalonly">modalonly</a></li>
1759
1760 <li data-name="LuCI.form.Value#onchange"><a href="LuCI.form.Value.html#onchange">onchange</a></li>
1761
1762 <li data-name="LuCI.form.Value#optional"><a href="LuCI.form.Value.html#optional">optional</a></li>
1763
1764 <li data-name="LuCI.form.Value#readonly"><a href="LuCI.form.Value.html#readonly">readonly</a></li>
1765
1766 <li data-name="LuCI.form.Value#rmempty"><a href="LuCI.form.Value.html#rmempty">rmempty</a></li>
1767
1768 <li data-name="LuCI.form.Value#uciconfig"><a href="LuCI.form.Value.html#uciconfig">uciconfig</a></li>
1769
1770 <li data-name="LuCI.form.Value#ucioption"><a href="LuCI.form.Value.html#ucioption">ucioption</a></li>
1771
1772 <li data-name="LuCI.form.Value#ucisection"><a href="LuCI.form.Value.html#ucisection">ucisection</a></li>
1773
1774 <li data-name="LuCI.form.Value#validate"><a href="LuCI.form.Value.html#validate">validate</a></li>
1775
1776 <li data-name="LuCI.form.Value#width"><a href="LuCI.form.Value.html#width">width</a></li>
1777
1778 </ul>
1779 <ul class="typedefs itemMembers">
1780
1781 </ul>
1782 <ul class="typedefs itemMembers">
1783
1784 </ul>
1785 <ul class="methods itemMembers">
1786
1787 <span class="subtitle">Methods</span>
1788
1789 <li data-name="LuCI.form.Value#append"><a href="LuCI.form.Value.html#append">append</a></li>
1790
1791 <li data-name="LuCI.form.Value#cbid"><a href="LuCI.form.Value.html#cbid">cbid</a></li>
1792
1793 <li data-name="LuCI.form.Value#cfgvalue"><a href="LuCI.form.Value.html#cfgvalue">cfgvalue</a></li>
1794
1795 <li data-name="LuCI.form.Value#depends"><a href="LuCI.form.Value.html#depends">depends</a></li>
1796
1797 <li data-name="LuCI.form.Value#formvalue"><a href="LuCI.form.Value.html#formvalue">formvalue</a></li>
1798
1799 <li data-name="LuCI.form.Value#getUIElement"><a href="LuCI.form.Value.html#getUIElement">getUIElement</a></li>
1800
1801 <li data-name="LuCI.form.Value#isActive"><a href="LuCI.form.Value.html#isActive">isActive</a></li>
1802
1803 <li data-name="LuCI.form.Value#isValid"><a href="LuCI.form.Value.html#isValid">isValid</a></li>
1804
1805 <li data-name="LuCI.form.Value#load"><a href="LuCI.form.Value.html#load">load</a></li>
1806
1807 <li data-name="LuCI.form.Value#parse"><a href="LuCI.form.Value.html#parse">parse</a></li>
1808
1809 <li data-name="LuCI.form.Value#remove"><a href="LuCI.form.Value.html#remove">remove</a></li>
1810
1811 <li data-name="LuCI.form.Value#render"><a href="LuCI.form.Value.html#render">render</a></li>
1812
1813 <li data-name="LuCI.form.Value#stripTags"><a href="LuCI.form.Value.html#stripTags">stripTags</a></li>
1814
1815 <li data-name="LuCI.form.Value#textvalue"><a href="LuCI.form.Value.html#textvalue">textvalue</a></li>
1816
1817 <li data-name="LuCI.form.Value#titleFn"><a href="LuCI.form.Value.html#titleFn">titleFn</a></li>
1818
1819 <li data-name="LuCI.form.Value#value"><a href="LuCI.form.Value.html#value">value</a></li>
1820
1821 <li data-name="LuCI.form.Value#write"><a href="LuCI.form.Value.html#write">write</a></li>
1822
1823 </ul>
1824 <ul class="events itemMembers">
1825
1826 </ul>
1827 </li>
1828
1829 <li class="item" data-name="LuCI.fs">
1830 <span class="title">
1831 <a href="LuCI.fs.html">LuCI.fs</a>
1832
1833 </span>
1834 <ul class="members itemMembers">
1835
1836 </ul>
1837 <ul class="typedefs itemMembers">
1838
1839 <span class="subtitle">Typedefs</span>
1840
1841 <li data-name="LuCI.fs.FileExecResult"><a href="LuCI.fs.html#.FileExecResult">FileExecResult</a></li>
1842
1843 <li data-name="LuCI.fs.FileStatEntry"><a href="LuCI.fs.html#.FileStatEntry">FileStatEntry</a></li>
1844
1845 </ul>
1846 <ul class="typedefs itemMembers">
1847
1848 </ul>
1849 <ul class="methods itemMembers">
1850
1851 <span class="subtitle">Methods</span>
1852
1853 <li data-name="LuCI.fs#exec"><a href="LuCI.fs.html#exec">exec</a></li>
1854
1855 <li data-name="LuCI.fs#exec_direct"><a href="LuCI.fs.html#exec_direct">exec_direct</a></li>
1856
1857 <li data-name="LuCI.fs#lines"><a href="LuCI.fs.html#lines">lines</a></li>
1858
1859 <li data-name="LuCI.fs#list"><a href="LuCI.fs.html#list">list</a></li>
1860
1861 <li data-name="LuCI.fs#read"><a href="LuCI.fs.html#read">read</a></li>
1862
1863 <li data-name="LuCI.fs#read_direct"><a href="LuCI.fs.html#read_direct">read_direct</a></li>
1864
1865 <li data-name="LuCI.fs#remove"><a href="LuCI.fs.html#remove">remove</a></li>
1866
1867 <li data-name="LuCI.fs#stat"><a href="LuCI.fs.html#stat">stat</a></li>
1868
1869 <li data-name="LuCI.fs#trimmed"><a href="LuCI.fs.html#trimmed">trimmed</a></li>
1870
1871 <li data-name="LuCI.fs#write"><a href="LuCI.fs.html#write">write</a></li>
1872
1873 </ul>
1874 <ul class="events itemMembers">
1875
1876 </ul>
1877 </li>
1878
1879 <li class="item" data-name="LuCI.headers">
1880 <span class="title">
1881 <a href="LuCI.headers.html">LuCI.headers</a>
1882
1883 </span>
1884 <ul class="members itemMembers">
1885
1886 </ul>
1887 <ul class="typedefs itemMembers">
1888
1889 </ul>
1890 <ul class="typedefs itemMembers">
1891
1892 </ul>
1893 <ul class="methods itemMembers">
1894
1895 <span class="subtitle">Methods</span>
1896
1897 <li data-name="LuCI.headers#get"><a href="LuCI.headers.html#get">get</a></li>
1898
1899 <li data-name="LuCI.headers#has"><a href="LuCI.headers.html#has">has</a></li>
1900
1901 </ul>
1902 <ul class="events itemMembers">
1903
1904 </ul>
1905 </li>
1906
1907 <li class="item" data-name="LuCI.network">
1908 <span class="title">
1909 <a href="LuCI.network.html">LuCI.network</a>
1910
1911 </span>
1912 <ul class="members itemMembers">
1913
1914 </ul>
1915 <ul class="typedefs itemMembers">
1916
1917 <span class="subtitle">Typedefs</span>
1918
1919 <li data-name="LuCI.network.SwitchTopology"><a href="LuCI.network.html#.SwitchTopology">SwitchTopology</a></li>
1920
1921 <li data-name="LuCI.network.WifiEncryption"><a href="LuCI.network.html#.WifiEncryption">WifiEncryption</a></li>
1922
1923 <li data-name="LuCI.network.WifiPeerEntry"><a href="LuCI.network.html#.WifiPeerEntry">WifiPeerEntry</a></li>
1924
1925 <li data-name="LuCI.network.WifiRateEntry"><a href="LuCI.network.html#.WifiRateEntry">WifiRateEntry</a></li>
1926
1927 <li data-name="LuCI.network.WifiScanResult"><a href="LuCI.network.html#.WifiScanResult">WifiScanResult</a></li>
1928
1929 </ul>
1930 <ul class="typedefs itemMembers">
1931
1932 </ul>
1933 <ul class="methods itemMembers">
1934
1935 <span class="subtitle">Methods</span>
1936
1937 <li data-name="LuCI.network#addNetwork"><a href="LuCI.network.html#addNetwork">addNetwork</a></li>
1938
1939 <li data-name="LuCI.network#addWifiNetwork"><a href="LuCI.network.html#addWifiNetwork">addWifiNetwork</a></li>
1940
1941 <li data-name="LuCI.network#deleteNetwork"><a href="LuCI.network.html#deleteNetwork">deleteNetwork</a></li>
1942
1943 <li data-name="LuCI.network#deleteWifiNetwork"><a href="LuCI.network.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
1944
1945 <li data-name="LuCI.network#flushCache"><a href="LuCI.network.html#flushCache">flushCache</a></li>
1946
1947 <li data-name="LuCI.network#formatWifiEncryption"><a href="LuCI.network.html#formatWifiEncryption">formatWifiEncryption</a></li>
1948
1949 <li data-name="LuCI.network#getDevice"><a href="LuCI.network.html#getDevice">getDevice</a></li>
1950
1951 <li data-name="LuCI.network#getDevices"><a href="LuCI.network.html#getDevices">getDevices</a></li>
1952
1953 <li data-name="LuCI.network#getDSLModemType"><a href="LuCI.network.html#getDSLModemType">getDSLModemType</a></li>
1954
1955 <li data-name="LuCI.network#getHostHints"><a href="LuCI.network.html#getHostHints">getHostHints</a></li>
1956
1957 <li data-name="LuCI.network#getIfnameOf"><a href="LuCI.network.html#getIfnameOf">getIfnameOf</a></li>
1958
1959 <li data-name="LuCI.network#getNetwork"><a href="LuCI.network.html#getNetwork">getNetwork</a></li>
1960
1961 <li data-name="LuCI.network#getNetworks"><a href="LuCI.network.html#getNetworks">getNetworks</a></li>
1962
1963 <li data-name="LuCI.network#getProtocol"><a href="LuCI.network.html#getProtocol">getProtocol</a></li>
1964
1965 <li data-name="LuCI.network#getProtocols"><a href="LuCI.network.html#getProtocols">getProtocols</a></li>
1966
1967 <li data-name="LuCI.network#getSwitchTopologies"><a href="LuCI.network.html#getSwitchTopologies">getSwitchTopologies</a></li>
1968
1969 <li data-name="LuCI.network#getWAN6Networks"><a href="LuCI.network.html#getWAN6Networks">getWAN6Networks</a></li>
1970
1971 <li data-name="LuCI.network#getWANNetworks"><a href="LuCI.network.html#getWANNetworks">getWANNetworks</a></li>
1972
1973 <li data-name="LuCI.network#getWifiDevice"><a href="LuCI.network.html#getWifiDevice">getWifiDevice</a></li>
1974
1975 <li data-name="LuCI.network#getWifiDevices"><a href="LuCI.network.html#getWifiDevices">getWifiDevices</a></li>
1976
1977 <li data-name="LuCI.network#getWifiNetwork"><a href="LuCI.network.html#getWifiNetwork">getWifiNetwork</a></li>
1978
1979 <li data-name="LuCI.network#getWifiNetworks"><a href="LuCI.network.html#getWifiNetworks">getWifiNetworks</a></li>
1980
1981 <li data-name="LuCI.network#isIgnoredDevice"><a href="LuCI.network.html#isIgnoredDevice">isIgnoredDevice</a></li>
1982
1983 <li data-name="LuCI.network#maskToPrefix"><a href="LuCI.network.html#maskToPrefix">maskToPrefix</a></li>
1984
1985 <li data-name="LuCI.network#prefixToMask"><a href="LuCI.network.html#prefixToMask">prefixToMask</a></li>
1986
1987 <li data-name="LuCI.network#registerErrorCode"><a href="LuCI.network.html#registerErrorCode">registerErrorCode</a></li>
1988
1989 <li data-name="LuCI.network#registerPatternVirtual"><a href="LuCI.network.html#registerPatternVirtual">registerPatternVirtual</a></li>
1990
1991 <li data-name="LuCI.network#registerProtocol"><a href="LuCI.network.html#registerProtocol">registerProtocol</a></li>
1992
1993 <li data-name="LuCI.network#renameNetwork"><a href="LuCI.network.html#renameNetwork">renameNetwork</a></li>
1994
1995 </ul>
1996 <ul class="events itemMembers">
1997
1998 </ul>
1999 </li>
2000
2001 <li class="item" data-name="LuCI.network.Device">
2002 <span class="title">
2003 <a href="LuCI.network.Device.html">LuCI.network.Device</a>
2004
2005 </span>
2006 <ul class="members itemMembers">
2007
2008 </ul>
2009 <ul class="typedefs itemMembers">
2010
2011 </ul>
2012 <ul class="typedefs itemMembers">
2013
2014 </ul>
2015 <ul class="methods itemMembers">
2016
2017 <span class="subtitle">Methods</span>
2018
2019 <li data-name="LuCI.network.Device#getBridgeID"><a href="LuCI.network.Device.html#getBridgeID">getBridgeID</a></li>
2020
2021 <li data-name="LuCI.network.Device#getBridgeSTP"><a href="LuCI.network.Device.html#getBridgeSTP">getBridgeSTP</a></li>
2022
2023 <li data-name="LuCI.network.Device#getI18n"><a href="LuCI.network.Device.html#getI18n">getI18n</a></li>
2024
2025 <li data-name="LuCI.network.Device#getIP6Addrs"><a href="LuCI.network.Device.html#getIP6Addrs">getIP6Addrs</a></li>
2026
2027 <li data-name="LuCI.network.Device#getIPAddrs"><a href="LuCI.network.Device.html#getIPAddrs">getIPAddrs</a></li>
2028
2029 <li data-name="LuCI.network.Device#getMAC"><a href="LuCI.network.Device.html#getMAC">getMAC</a></li>
2030
2031 <li data-name="LuCI.network.Device#getMTU"><a href="LuCI.network.Device.html#getMTU">getMTU</a></li>
2032
2033 <li data-name="LuCI.network.Device#getName"><a href="LuCI.network.Device.html#getName">getName</a></li>
2034
2035 <li data-name="LuCI.network.Device#getNetwork"><a href="LuCI.network.Device.html#getNetwork">getNetwork</a></li>
2036
2037 <li data-name="LuCI.network.Device#getNetworks"><a href="LuCI.network.Device.html#getNetworks">getNetworks</a></li>
2038
2039 <li data-name="LuCI.network.Device#getPorts"><a href="LuCI.network.Device.html#getPorts">getPorts</a></li>
2040
2041 <li data-name="LuCI.network.Device#getRXBytes"><a href="LuCI.network.Device.html#getRXBytes">getRXBytes</a></li>
2042
2043 <li data-name="LuCI.network.Device#getRXPackets"><a href="LuCI.network.Device.html#getRXPackets">getRXPackets</a></li>
2044
2045 <li data-name="LuCI.network.Device#getShortName"><a href="LuCI.network.Device.html#getShortName">getShortName</a></li>
2046
2047 <li data-name="LuCI.network.Device#getTXBytes"><a href="LuCI.network.Device.html#getTXBytes">getTXBytes</a></li>
2048
2049 <li data-name="LuCI.network.Device#getTXPackets"><a href="LuCI.network.Device.html#getTXPackets">getTXPackets</a></li>
2050
2051 <li data-name="LuCI.network.Device#getType"><a href="LuCI.network.Device.html#getType">getType</a></li>
2052
2053 <li data-name="LuCI.network.Device#getTypeI18n"><a href="LuCI.network.Device.html#getTypeI18n">getTypeI18n</a></li>
2054
2055 <li data-name="LuCI.network.Device#getWifiNetwork"><a href="LuCI.network.Device.html#getWifiNetwork">getWifiNetwork</a></li>
2056
2057 <li data-name="LuCI.network.Device#isBridge"><a href="LuCI.network.Device.html#isBridge">isBridge</a></li>
2058
2059 <li data-name="LuCI.network.Device#isBridgePort"><a href="LuCI.network.Device.html#isBridgePort">isBridgePort</a></li>
2060
2061 <li data-name="LuCI.network.Device#isUp"><a href="LuCI.network.Device.html#isUp">isUp</a></li>
2062
2063 </ul>
2064 <ul class="events itemMembers">
2065
2066 </ul>
2067 </li>
2068
2069 <li class="item" data-name="LuCI.network.Hosts">
2070 <span class="title">
2071 <a href="LuCI.network.Hosts.html">LuCI.network.Hosts</a>
2072
2073 </span>
2074 <ul class="members itemMembers">
2075
2076 </ul>
2077 <ul class="typedefs itemMembers">
2078
2079 </ul>
2080 <ul class="typedefs itemMembers">
2081
2082 </ul>
2083 <ul class="methods itemMembers">
2084
2085 <span class="subtitle">Methods</span>
2086
2087 <li data-name="LuCI.network.Hosts#getHostnameByIP6Addr"><a href="LuCI.network.Hosts.html#getHostnameByIP6Addr">getHostnameByIP6Addr</a></li>
2088
2089 <li data-name="LuCI.network.Hosts#getHostnameByIPAddr"><a href="LuCI.network.Hosts.html#getHostnameByIPAddr">getHostnameByIPAddr</a></li>
2090
2091 <li data-name="LuCI.network.Hosts#getHostnameByMACAddr"><a href="LuCI.network.Hosts.html#getHostnameByMACAddr">getHostnameByMACAddr</a></li>
2092
2093 <li data-name="LuCI.network.Hosts#getIP6AddrByMACAddr"><a href="LuCI.network.Hosts.html#getIP6AddrByMACAddr">getIP6AddrByMACAddr</a></li>
2094
2095 <li data-name="LuCI.network.Hosts#getIPAddrByMACAddr"><a href="LuCI.network.Hosts.html#getIPAddrByMACAddr">getIPAddrByMACAddr</a></li>
2096
2097 <li data-name="LuCI.network.Hosts#getMACAddrByIP6Addr"><a href="LuCI.network.Hosts.html#getMACAddrByIP6Addr">getMACAddrByIP6Addr</a></li>
2098
2099 <li data-name="LuCI.network.Hosts#getMACAddrByIPAddr"><a href="LuCI.network.Hosts.html#getMACAddrByIPAddr">getMACAddrByIPAddr</a></li>
2100
2101 <li data-name="LuCI.network.Hosts#getMACHints"><a href="LuCI.network.Hosts.html#getMACHints">getMACHints</a></li>
2102
2103 </ul>
2104 <ul class="events itemMembers">
2105
2106 </ul>
2107 </li>
2108
2109 <li class="item" data-name="LuCI.network.Protocol">
2110 <span class="title">
2111 <a href="LuCI.network.Protocol.html">LuCI.network.Protocol</a>
2112
2113 </span>
2114 <ul class="members itemMembers">
2115
2116 </ul>
2117 <ul class="typedefs itemMembers">
2118
2119 </ul>
2120 <ul class="typedefs itemMembers">
2121
2122 </ul>
2123 <ul class="methods itemMembers">
2124
2125 <span class="subtitle">Methods</span>
2126
2127 <li data-name="LuCI.network.Protocol#addDevice"><a href="LuCI.network.Protocol.html#addDevice">addDevice</a></li>
2128
2129 <li data-name="LuCI.network.Protocol#containsDevice"><a href="LuCI.network.Protocol.html#containsDevice">containsDevice</a></li>
2130
2131 <li data-name="LuCI.network.Protocol#deleteConfiguration"><a href="LuCI.network.Protocol.html#deleteConfiguration">deleteConfiguration</a></li>
2132
2133 <li data-name="LuCI.network.Protocol#deleteDevice"><a href="LuCI.network.Protocol.html#deleteDevice">deleteDevice</a></li>
2134
2135 <li data-name="LuCI.network.Protocol#get"><a href="LuCI.network.Protocol.html#get">get</a></li>
2136
2137 <li data-name="LuCI.network.Protocol#getDevice"><a href="LuCI.network.Protocol.html#getDevice">getDevice</a></li>
2138
2139 <li data-name="LuCI.network.Protocol#getDevices"><a href="LuCI.network.Protocol.html#getDevices">getDevices</a></li>
2140
2141 <li data-name="LuCI.network.Protocol#getDNS6Addrs"><a href="LuCI.network.Protocol.html#getDNS6Addrs">getDNS6Addrs</a></li>
2142
2143 <li data-name="LuCI.network.Protocol#getDNSAddrs"><a href="LuCI.network.Protocol.html#getDNSAddrs">getDNSAddrs</a></li>
2144
2145 <li data-name="LuCI.network.Protocol#getErrors"><a href="LuCI.network.Protocol.html#getErrors">getErrors</a></li>
2146
2147 <li data-name="LuCI.network.Protocol#getExpiry"><a href="LuCI.network.Protocol.html#getExpiry">getExpiry</a></li>
2148
2149 <li data-name="LuCI.network.Protocol#getGateway6Addr"><a href="LuCI.network.Protocol.html#getGateway6Addr">getGateway6Addr</a></li>
2150
2151 <li data-name="LuCI.network.Protocol#getGatewayAddr"><a href="LuCI.network.Protocol.html#getGatewayAddr">getGatewayAddr</a></li>
2152
2153 <li data-name="LuCI.network.Protocol#getI18n"><a href="LuCI.network.Protocol.html#getI18n">getI18n</a></li>
2154
2155 <li data-name="LuCI.network.Protocol#getIfname"><a href="LuCI.network.Protocol.html#getIfname">getIfname</a></li>
2156
2157 <li data-name="LuCI.network.Protocol#getIP6Addr"><a href="LuCI.network.Protocol.html#getIP6Addr">getIP6Addr</a></li>
2158
2159 <li data-name="LuCI.network.Protocol#getIP6Addrs"><a href="LuCI.network.Protocol.html#getIP6Addrs">getIP6Addrs</a></li>
2160
2161 <li data-name="LuCI.network.Protocol#getIP6Prefix"><a href="LuCI.network.Protocol.html#getIP6Prefix">getIP6Prefix</a></li>
2162
2163 <li data-name="LuCI.network.Protocol#getIPAddr"><a href="LuCI.network.Protocol.html#getIPAddr">getIPAddr</a></li>
2164
2165 <li data-name="LuCI.network.Protocol#getIPAddrs"><a href="LuCI.network.Protocol.html#getIPAddrs">getIPAddrs</a></li>
2166
2167 <li data-name="LuCI.network.Protocol#getL2Device"><a href="LuCI.network.Protocol.html#getL2Device">getL2Device</a></li>
2168
2169 <li data-name="LuCI.network.Protocol#getL3Device"><a href="LuCI.network.Protocol.html#getL3Device">getL3Device</a></li>
2170
2171 <li data-name="LuCI.network.Protocol#getMetric"><a href="LuCI.network.Protocol.html#getMetric">getMetric</a></li>
2172
2173 <li data-name="LuCI.network.Protocol#getName"><a href="LuCI.network.Protocol.html#getName">getName</a></li>
2174
2175 <li data-name="LuCI.network.Protocol#getNetmask"><a href="LuCI.network.Protocol.html#getNetmask">getNetmask</a></li>
2176
2177 <li data-name="LuCI.network.Protocol#getOpkgPackage"><a href="LuCI.network.Protocol.html#getOpkgPackage">getOpkgPackage</a></li>
2178
2179 <li data-name="LuCI.network.Protocol#getProtocol"><a href="LuCI.network.Protocol.html#getProtocol">getProtocol</a></li>
2180
2181 <li data-name="LuCI.network.Protocol#getType"><a href="LuCI.network.Protocol.html#getType">getType</a></li>
2182
2183 <li data-name="LuCI.network.Protocol#getUptime"><a href="LuCI.network.Protocol.html#getUptime">getUptime</a></li>
2184
2185 <li data-name="LuCI.network.Protocol#getZoneName"><a href="LuCI.network.Protocol.html#getZoneName">getZoneName</a></li>
2186
2187 <li data-name="LuCI.network.Protocol#isAlias"><a href="LuCI.network.Protocol.html#isAlias">isAlias</a></li>
2188
2189 <li data-name="LuCI.network.Protocol#isBridge"><a href="LuCI.network.Protocol.html#isBridge">isBridge</a></li>
2190
2191 <li data-name="LuCI.network.Protocol#isCreateable"><a href="LuCI.network.Protocol.html#isCreateable">isCreateable</a></li>
2192
2193 <li data-name="LuCI.network.Protocol#isDynamic"><a href="LuCI.network.Protocol.html#isDynamic">isDynamic</a></li>
2194
2195 <li data-name="LuCI.network.Protocol#isEmpty"><a href="LuCI.network.Protocol.html#isEmpty">isEmpty</a></li>
2196
2197 <li data-name="LuCI.network.Protocol#isFloating"><a href="LuCI.network.Protocol.html#isFloating">isFloating</a></li>
2198
2199 <li data-name="LuCI.network.Protocol#isInstalled"><a href="LuCI.network.Protocol.html#isInstalled">isInstalled</a></li>
2200
2201 <li data-name="LuCI.network.Protocol#isUp"><a href="LuCI.network.Protocol.html#isUp">isUp</a></li>
2202
2203 <li data-name="LuCI.network.Protocol#isVirtual"><a href="LuCI.network.Protocol.html#isVirtual">isVirtual</a></li>
2204
2205 <li data-name="LuCI.network.Protocol#set"><a href="LuCI.network.Protocol.html#set">set</a></li>
2206
2207 </ul>
2208 <ul class="events itemMembers">
2209
2210 </ul>
2211 </li>
2212
2213 <li class="item" data-name="LuCI.network.WifiDevice">
2214 <span class="title">
2215 <a href="LuCI.network.WifiDevice.html">LuCI.network.WifiDevice</a>
2216
2217 </span>
2218 <ul class="members itemMembers">
2219
2220 </ul>
2221 <ul class="typedefs itemMembers">
2222
2223 </ul>
2224 <ul class="typedefs itemMembers">
2225
2226 </ul>
2227 <ul class="methods itemMembers">
2228
2229 <span class="subtitle">Methods</span>
2230
2231 <li data-name="LuCI.network.WifiDevice#addWifiNetwork"><a href="LuCI.network.WifiDevice.html#addWifiNetwork">addWifiNetwork</a></li>
2232
2233 <li data-name="LuCI.network.WifiDevice#deleteWifiNetwork"><a href="LuCI.network.WifiDevice.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
2234
2235 <li data-name="LuCI.network.WifiDevice#get"><a href="LuCI.network.WifiDevice.html#get">get</a></li>
2236
2237 <li data-name="LuCI.network.WifiDevice#getHTModes"><a href="LuCI.network.WifiDevice.html#getHTModes">getHTModes</a></li>
2238
2239 <li data-name="LuCI.network.WifiDevice#getHWModes"><a href="LuCI.network.WifiDevice.html#getHWModes">getHWModes</a></li>
2240
2241 <li data-name="LuCI.network.WifiDevice#getI18n"><a href="LuCI.network.WifiDevice.html#getI18n">getI18n</a></li>
2242
2243 <li data-name="LuCI.network.WifiDevice#getName"><a href="LuCI.network.WifiDevice.html#getName">getName</a></li>
2244
2245 <li data-name="LuCI.network.WifiDevice#getScanList"><a href="LuCI.network.WifiDevice.html#getScanList">getScanList</a></li>
2246
2247 <li data-name="LuCI.network.WifiDevice#getWifiNetwork"><a href="LuCI.network.WifiDevice.html#getWifiNetwork">getWifiNetwork</a></li>
2248
2249 <li data-name="LuCI.network.WifiDevice#getWifiNetworks"><a href="LuCI.network.WifiDevice.html#getWifiNetworks">getWifiNetworks</a></li>
2250
2251 <li data-name="LuCI.network.WifiDevice#isDisabled"><a href="LuCI.network.WifiDevice.html#isDisabled">isDisabled</a></li>
2252
2253 <li data-name="LuCI.network.WifiDevice#isUp"><a href="LuCI.network.WifiDevice.html#isUp">isUp</a></li>
2254
2255 <li data-name="LuCI.network.WifiDevice#set"><a href="LuCI.network.WifiDevice.html#set">set</a></li>
2256
2257 </ul>
2258 <ul class="events itemMembers">
2259
2260 </ul>
2261 </li>
2262
2263 <li class="item" data-name="LuCI.network.WifiNetwork">
2264 <span class="title">
2265 <a href="LuCI.network.WifiNetwork.html">LuCI.network.WifiNetwork</a>
2266
2267 </span>
2268 <ul class="members itemMembers">
2269
2270 </ul>
2271 <ul class="typedefs itemMembers">
2272
2273 </ul>
2274 <ul class="typedefs itemMembers">
2275
2276 </ul>
2277 <ul class="methods itemMembers">
2278
2279 <span class="subtitle">Methods</span>
2280
2281 <li data-name="LuCI.network.WifiNetwork#disconnectClient"><a href="LuCI.network.WifiNetwork.html#disconnectClient">disconnectClient</a></li>
2282
2283 <li data-name="LuCI.network.WifiNetwork#get"><a href="LuCI.network.WifiNetwork.html#get">get</a></li>
2284
2285 <li data-name="LuCI.network.WifiNetwork#getActiveBSSID"><a href="LuCI.network.WifiNetwork.html#getActiveBSSID">getActiveBSSID</a></li>
2286
2287 <li data-name="LuCI.network.WifiNetwork#getActiveEncryption"><a href="LuCI.network.WifiNetwork.html#getActiveEncryption">getActiveEncryption</a></li>
2288
2289 <li data-name="LuCI.network.WifiNetwork#getActiveMode"><a href="LuCI.network.WifiNetwork.html#getActiveMode">getActiveMode</a></li>
2290
2291 <li data-name="LuCI.network.WifiNetwork#getActiveModeI18n"><a href="LuCI.network.WifiNetwork.html#getActiveModeI18n">getActiveModeI18n</a></li>
2292
2293 <li data-name="LuCI.network.WifiNetwork#getActiveSSID"><a href="LuCI.network.WifiNetwork.html#getActiveSSID">getActiveSSID</a></li>
2294
2295 <li data-name="LuCI.network.WifiNetwork#getAssocList"><a href="LuCI.network.WifiNetwork.html#getAssocList">getAssocList</a></li>
2296
2297 <li data-name="LuCI.network.WifiNetwork#getBitRate"><a href="LuCI.network.WifiNetwork.html#getBitRate">getBitRate</a></li>
2298
2299 <li data-name="LuCI.network.WifiNetwork#getBSSID"><a href="LuCI.network.WifiNetwork.html#getBSSID">getBSSID</a></li>
2300
2301 <li data-name="LuCI.network.WifiNetwork#getChannel"><a href="LuCI.network.WifiNetwork.html#getChannel">getChannel</a></li>
2302
2303 <li data-name="LuCI.network.WifiNetwork#getCountryCode"><a href="LuCI.network.WifiNetwork.html#getCountryCode">getCountryCode</a></li>
2304
2305 <li data-name="LuCI.network.WifiNetwork#getDevice"><a href="LuCI.network.WifiNetwork.html#getDevice">getDevice</a></li>
2306
2307 <li data-name="LuCI.network.WifiNetwork#getFrequency"><a href="LuCI.network.WifiNetwork.html#getFrequency">getFrequency</a></li>
2308
2309 <li data-name="LuCI.network.WifiNetwork#getI18n"><a href="LuCI.network.WifiNetwork.html#getI18n">getI18n</a></li>
2310
2311 <li data-name="LuCI.network.WifiNetwork#getID"><a href="LuCI.network.WifiNetwork.html#getID">getID</a></li>
2312
2313 <li data-name="LuCI.network.WifiNetwork#getIfname"><a href="LuCI.network.WifiNetwork.html#getIfname">getIfname</a></li>
2314
2315 <li data-name="LuCI.network.WifiNetwork#getMeshID"><a href="LuCI.network.WifiNetwork.html#getMeshID">getMeshID</a></li>
2316
2317 <li data-name="LuCI.network.WifiNetwork#getMode"><a href="LuCI.network.WifiNetwork.html#getMode">getMode</a></li>
2318
2319 <li data-name="LuCI.network.WifiNetwork#getName"><a href="LuCI.network.WifiNetwork.html#getName">getName</a></li>
2320
2321 <li data-name="LuCI.network.WifiNetwork#getNetwork"><a href="LuCI.network.WifiNetwork.html#getNetwork">getNetwork</a></li>
2322
2323 <li data-name="LuCI.network.WifiNetwork#getNetworkNames"><a href="LuCI.network.WifiNetwork.html#getNetworkNames">getNetworkNames</a></li>
2324
2325 <li data-name="LuCI.network.WifiNetwork#getNetworks"><a href="LuCI.network.WifiNetwork.html#getNetworks">getNetworks</a></li>
2326
2327 <li data-name="LuCI.network.WifiNetwork#getNoise"><a href="LuCI.network.WifiNetwork.html#getNoise">getNoise</a></li>
2328
2329 <li data-name="LuCI.network.WifiNetwork#getShortName"><a href="LuCI.network.WifiNetwork.html#getShortName">getShortName</a></li>
2330
2331 <li data-name="LuCI.network.WifiNetwork#getSignal"><a href="LuCI.network.WifiNetwork.html#getSignal">getSignal</a></li>
2332
2333 <li data-name="LuCI.network.WifiNetwork#getSignalLevel"><a href="LuCI.network.WifiNetwork.html#getSignalLevel">getSignalLevel</a></li>
2334
2335 <li data-name="LuCI.network.WifiNetwork#getSignalPercent"><a href="LuCI.network.WifiNetwork.html#getSignalPercent">getSignalPercent</a></li>
2336
2337 <li data-name="LuCI.network.WifiNetwork#getSSID"><a href="LuCI.network.WifiNetwork.html#getSSID">getSSID</a></li>
2338
2339 <li data-name="LuCI.network.WifiNetwork#getTXPower"><a href="LuCI.network.WifiNetwork.html#getTXPower">getTXPower</a></li>
2340
2341 <li data-name="LuCI.network.WifiNetwork#getTXPowerOffset"><a href="LuCI.network.WifiNetwork.html#getTXPowerOffset">getTXPowerOffset</a></li>
2342
2343 <li data-name="LuCI.network.WifiNetwork#getWifiDevice"><a href="LuCI.network.WifiNetwork.html#getWifiDevice">getWifiDevice</a></li>
2344
2345 <li data-name="LuCI.network.WifiNetwork#getWifiDeviceName"><a href="LuCI.network.WifiNetwork.html#getWifiDeviceName">getWifiDeviceName</a></li>
2346
2347 <li data-name="LuCI.network.WifiNetwork#isClientDisconnectSupported"><a href="LuCI.network.WifiNetwork.html#isClientDisconnectSupported">isClientDisconnectSupported</a></li>
2348
2349 <li data-name="LuCI.network.WifiNetwork#isDisabled"><a href="LuCI.network.WifiNetwork.html#isDisabled">isDisabled</a></li>
2350
2351 <li data-name="LuCI.network.WifiNetwork#isUp"><a href="LuCI.network.WifiNetwork.html#isUp">isUp</a></li>
2352
2353 <li data-name="LuCI.network.WifiNetwork#set"><a href="LuCI.network.WifiNetwork.html#set">set</a></li>
2354
2355 </ul>
2356 <ul class="events itemMembers">
2357
2358 </ul>
2359 </li>
2360
2361 <li class="item" data-name="LuCI.poll">
2362 <span class="title">
2363 <a href="LuCI.poll.html">LuCI.poll</a>
2364
2365 </span>
2366 <ul class="members itemMembers">
2367
2368 </ul>
2369 <ul class="typedefs itemMembers">
2370
2371 </ul>
2372 <ul class="typedefs itemMembers">
2373
2374 </ul>
2375 <ul class="methods itemMembers">
2376
2377 <span class="subtitle">Methods</span>
2378
2379 <li data-name="LuCI.poll#active"><a href="LuCI.poll.html#active">active</a></li>
2380
2381 <li data-name="LuCI.poll#add"><a href="LuCI.poll.html#add">add</a></li>
2382
2383 <li data-name="LuCI.poll#remove"><a href="LuCI.poll.html#remove">remove</a></li>
2384
2385 <li data-name="LuCI.poll#start"><a href="LuCI.poll.html#start">start</a></li>
2386
2387 <li data-name="LuCI.poll#stop"><a href="LuCI.poll.html#stop">stop</a></li>
2388
2389 </ul>
2390 <ul class="events itemMembers">
2391
2392 </ul>
2393 </li>
2394
2395 <li class="item" data-name="LuCI.request">
2396 <span class="title">
2397 <a href="LuCI.request.html">LuCI.request</a>
2398
2399 </span>
2400 <ul class="members itemMembers">
2401
2402 </ul>
2403 <ul class="typedefs itemMembers">
2404
2405 <span class="subtitle">Typedefs</span>
2406
2407 <li data-name="LuCI.request.interceptorFn"><a href="LuCI.request.html#.interceptorFn">interceptorFn</a></li>
2408
2409 <li data-name="LuCI.request.RequestOptions"><a href="LuCI.request.html#.RequestOptions">RequestOptions</a></li>
2410
2411 </ul>
2412 <ul class="typedefs itemMembers">
2413
2414 </ul>
2415 <ul class="methods itemMembers">
2416
2417 <span class="subtitle">Methods</span>
2418
2419 <li data-name="LuCI.request#addInterceptor"><a href="LuCI.request.html#addInterceptor">addInterceptor</a></li>
2420
2421 <li data-name="LuCI.request#expandURL"><a href="LuCI.request.html#expandURL">expandURL</a></li>
2422
2423 <li data-name="LuCI.request#get"><a href="LuCI.request.html#get">get</a></li>
2424
2425 <li data-name="LuCI.request#post"><a href="LuCI.request.html#post">post</a></li>
2426
2427 <li data-name="LuCI.request#removeInterceptor"><a href="LuCI.request.html#removeInterceptor">removeInterceptor</a></li>
2428
2429 <li data-name="LuCI.request#request"><a href="LuCI.request.html#request">request</a></li>
2430
2431 </ul>
2432 <ul class="events itemMembers">
2433
2434 </ul>
2435 </li>
2436
2437 <li class="item" data-name="LuCI.request.poll">
2438 <span class="title">
2439 <a href="LuCI.request.poll.html">LuCI.request.poll</a>
2440
2441 </span>
2442 <ul class="members itemMembers">
2443
2444 </ul>
2445 <ul class="typedefs itemMembers">
2446
2447 <span class="subtitle">Typedefs</span>
2448
2449 <li data-name="LuCI.request.poll~callbackFn"><a href="LuCI.request.poll.html#~callbackFn">callbackFn</a></li>
2450
2451 </ul>
2452 <ul class="typedefs itemMembers">
2453
2454 </ul>
2455 <ul class="methods itemMembers">
2456
2457 <span class="subtitle">Methods</span>
2458
2459 <li data-name="LuCI.request.poll#active"><a href="LuCI.request.poll.html#active">active</a></li>
2460
2461 <li data-name="LuCI.request.poll#add"><a href="LuCI.request.poll.html#add">add</a></li>
2462
2463 <li data-name="LuCI.request.poll#remove"><a href="LuCI.request.poll.html#remove">remove</a></li>
2464
2465 <li data-name="LuCI.request.poll#start"><a href="LuCI.request.poll.html#start">start</a></li>
2466
2467 <li data-name="LuCI.request.poll#stop"><a href="LuCI.request.poll.html#stop">stop</a></li>
2468
2469 </ul>
2470 <ul class="events itemMembers">
2471
2472 </ul>
2473 </li>
2474
2475 <li class="item" data-name="LuCI.response">
2476 <span class="title">
2477 <a href="LuCI.response.html">LuCI.response</a>
2478
2479 </span>
2480 <ul class="members itemMembers">
2481
2482 <span class="subtitle">Members</span>
2483
2484 <li data-name="LuCI.response#duration"><a href="LuCI.response.html#duration">duration</a></li>
2485
2486 <li data-name="LuCI.response#headers"><a href="LuCI.response.html#headers">headers</a></li>
2487
2488 <li data-name="LuCI.response#ok"><a href="LuCI.response.html#ok">ok</a></li>
2489
2490 <li data-name="LuCI.response#status"><a href="LuCI.response.html#status">status</a></li>
2491
2492 <li data-name="LuCI.response#statusText"><a href="LuCI.response.html#statusText">statusText</a></li>
2493
2494 <li data-name="LuCI.response#url"><a href="LuCI.response.html#url">url</a></li>
2495
2496 </ul>
2497 <ul class="typedefs itemMembers">
2498
2499 </ul>
2500 <ul class="typedefs itemMembers">
2501
2502 </ul>
2503 <ul class="methods itemMembers">
2504
2505 <span class="subtitle">Methods</span>
2506
2507 <li data-name="LuCI.response#blob"><a href="LuCI.response.html#blob">blob</a></li>
2508
2509 <li data-name="LuCI.response#clone"><a href="LuCI.response.html#clone">clone</a></li>
2510
2511 <li data-name="LuCI.response#json"><a href="LuCI.response.html#json">json</a></li>
2512
2513 <li data-name="LuCI.response#text"><a href="LuCI.response.html#text">text</a></li>
2514
2515 </ul>
2516 <ul class="events itemMembers">
2517
2518 </ul>
2519 </li>
2520
2521 <li class="item" data-name="LuCI.rpc">
2522 <span class="title">
2523 <a href="LuCI.rpc.html">LuCI.rpc</a>
2524
2525 </span>
2526 <ul class="members itemMembers">
2527
2528 </ul>
2529 <ul class="typedefs itemMembers">
2530
2531 <span class="subtitle">Typedefs</span>
2532
2533 <li data-name="LuCI.rpc.DeclareOptions"><a href="LuCI.rpc.html#.DeclareOptions">DeclareOptions</a></li>
2534
2535 <li data-name="LuCI.rpc~filterFn"><a href="LuCI.rpc.html#~filterFn">filterFn</a></li>
2536
2537 <li data-name="LuCI.rpc~interceptorFn"><a href="LuCI.rpc.html#~interceptorFn">interceptorFn</a></li>
2538
2539 <li data-name="LuCI.rpc~invokeFn"><a href="LuCI.rpc.html#~invokeFn">invokeFn</a></li>
2540
2541 </ul>
2542 <ul class="typedefs itemMembers">
2543
2544 </ul>
2545 <ul class="methods itemMembers">
2546
2547 <span class="subtitle">Methods</span>
2548
2549 <li data-name="LuCI.rpc#addInterceptor"><a href="LuCI.rpc.html#addInterceptor">addInterceptor</a></li>
2550
2551 <li data-name="LuCI.rpc#declare"><a href="LuCI.rpc.html#declare">declare</a></li>
2552
2553 <li data-name="LuCI.rpc#getBaseURL"><a href="LuCI.rpc.html#getBaseURL">getBaseURL</a></li>
2554
2555 <li data-name="LuCI.rpc#getSessionID"><a href="LuCI.rpc.html#getSessionID">getSessionID</a></li>
2556
2557 <li data-name="LuCI.rpc#getStatusText"><a href="LuCI.rpc.html#getStatusText">getStatusText</a></li>
2558
2559 <li data-name="LuCI.rpc#list"><a href="LuCI.rpc.html#list">list</a></li>
2560
2561 <li data-name="LuCI.rpc#removeInterceptor"><a href="LuCI.rpc.html#removeInterceptor">removeInterceptor</a></li>
2562
2563 <li data-name="LuCI.rpc#setBaseURL"><a href="LuCI.rpc.html#setBaseURL">setBaseURL</a></li>
2564
2565 <li data-name="LuCI.rpc#setSessionID"><a href="LuCI.rpc.html#setSessionID">setSessionID</a></li>
2566
2567 </ul>
2568 <ul class="events itemMembers">
2569
2570 </ul>
2571 </li>
2572
2573 <li class="item" data-name="LuCI.session">
2574 <span class="title">
2575 <a href="LuCI.session.html">LuCI.session</a>
2576
2577 </span>
2578 <ul class="members itemMembers">
2579
2580 </ul>
2581 <ul class="typedefs itemMembers">
2582
2583 </ul>
2584 <ul class="typedefs itemMembers">
2585
2586 </ul>
2587 <ul class="methods itemMembers">
2588
2589 <span class="subtitle">Methods</span>
2590
2591 <li data-name="LuCI.session#getID"><a href="LuCI.session.html#getID">getID</a></li>
2592
2593 <li data-name="LuCI.session#getLocalData"><a href="LuCI.session.html#getLocalData">getLocalData</a></li>
2594
2595 <li data-name="LuCI.session#getToken"><a href="LuCI.session.html#getToken">getToken</a></li>
2596
2597 <li data-name="LuCI.session#setLocalData"><a href="LuCI.session.html#setLocalData">setLocalData</a></li>
2598
2599 </ul>
2600 <ul class="events itemMembers">
2601
2602 </ul>
2603 </li>
2604
2605 <li class="item" data-name="LuCI.uci">
2606 <span class="title">
2607 <a href="LuCI.uci.html">LuCI.uci</a>
2608
2609 </span>
2610 <ul class="members itemMembers">
2611
2612 </ul>
2613 <ul class="typedefs itemMembers">
2614
2615 <span class="subtitle">Typedefs</span>
2616
2617 <li data-name="LuCI.uci.ChangeRecord"><a href="LuCI.uci.html#.ChangeRecord">ChangeRecord</a></li>
2618
2619 <li data-name="LuCI.uci.SectionObject"><a href="LuCI.uci.html#.SectionObject">SectionObject</a></li>
2620
2621 <li data-name="LuCI.uci~sectionsFn"><a href="LuCI.uci.html#~sectionsFn">sectionsFn</a></li>
2622
2623 </ul>
2624 <ul class="typedefs itemMembers">
2625
2626 </ul>
2627 <ul class="methods itemMembers">
2628
2629 <span class="subtitle">Methods</span>
2630
2631 <li data-name="LuCI.uci#add"><a href="LuCI.uci.html#add">add</a></li>
2632
2633 <li data-name="LuCI.uci#apply"><a href="LuCI.uci.html#apply">apply</a></li>
2634
2635 <li data-name="LuCI.uci#changes"><a href="LuCI.uci.html#changes">changes</a></li>
2636
2637 <li data-name="LuCI.uci#createSID"><a href="LuCI.uci.html#createSID">createSID</a></li>
2638
2639 <li data-name="LuCI.uci#get"><a href="LuCI.uci.html#get">get</a></li>
2640
2641 <li data-name="LuCI.uci#get_first"><a href="LuCI.uci.html#get_first">get_first</a></li>
2642
2643 <li data-name="LuCI.uci#load"><a href="LuCI.uci.html#load">load</a></li>
2644
2645 <li data-name="LuCI.uci#move"><a href="LuCI.uci.html#move">move</a></li>
2646
2647 <li data-name="LuCI.uci#remove"><a href="LuCI.uci.html#remove">remove</a></li>
2648
2649 <li data-name="LuCI.uci#resolveSID"><a href="LuCI.uci.html#resolveSID">resolveSID</a></li>
2650
2651 <li data-name="LuCI.uci#save"><a href="LuCI.uci.html#save">save</a></li>
2652
2653 <li data-name="LuCI.uci#sections"><a href="LuCI.uci.html#sections">sections</a></li>
2654
2655 <li data-name="LuCI.uci#set"><a href="LuCI.uci.html#set">set</a></li>
2656
2657 <li data-name="LuCI.uci#set_first"><a href="LuCI.uci.html#set_first">set_first</a></li>
2658
2659 <li data-name="LuCI.uci#unload"><a href="LuCI.uci.html#unload">unload</a></li>
2660
2661 <li data-name="LuCI.uci#unset"><a href="LuCI.uci.html#unset">unset</a></li>
2662
2663 <li data-name="LuCI.uci#unset_first"><a href="LuCI.uci.html#unset_first">unset_first</a></li>
2664
2665 </ul>
2666 <ul class="events itemMembers">
2667
2668 </ul>
2669 </li>
2670
2671 <li class="item" data-name="LuCI.ui">
2672 <span class="title">
2673 <a href="LuCI.ui.html">LuCI.ui</a>
2674
2675 </span>
2676 <ul class="members itemMembers">
2677
2678 </ul>
2679 <ul class="typedefs itemMembers">
2680
2681 <span class="subtitle">Typedefs</span>
2682
2683 <li data-name="LuCI.ui.FileUploadReply"><a href="LuCI.ui.html#.FileUploadReply">FileUploadReply</a></li>
2684
2685 </ul>
2686 <ul class="typedefs itemMembers">
2687
2688 </ul>
2689 <ul class="methods itemMembers">
2690
2691 <span class="subtitle">Methods</span>
2692
2693 <li data-name="LuCI.ui#addNotification"><a href="LuCI.ui.html#addNotification">addNotification</a></li>
2694
2695 <li data-name="LuCI.ui#addValidator"><a href="LuCI.ui.html#addValidator">addValidator</a></li>
2696
2697 <li data-name="LuCI.ui#awaitReconnect"><a href="LuCI.ui.html#awaitReconnect">awaitReconnect</a></li>
2698
2699 <li data-name="LuCI.ui#createHandlerFn"><a href="LuCI.ui.html#createHandlerFn">createHandlerFn</a></li>
2700
2701 <li data-name="LuCI.ui#hideIndicator"><a href="LuCI.ui.html#hideIndicator">hideIndicator</a></li>
2702
2703 <li data-name="LuCI.ui#hideModal"><a href="LuCI.ui.html#hideModal">hideModal</a></li>
2704
2705 <li data-name="LuCI.ui#instantiateView"><a href="LuCI.ui.html#instantiateView">instantiateView</a></li>
2706
2707 <li data-name="LuCI.ui#itemlist"><a href="LuCI.ui.html#itemlist">itemlist</a></li>
2708
2709 <li data-name="LuCI.ui#pingDevice"><a href="LuCI.ui.html#pingDevice">pingDevice</a></li>
2710
2711 <li data-name="LuCI.ui#showIndicator"><a href="LuCI.ui.html#showIndicator">showIndicator</a></li>
2712
2713 <li data-name="LuCI.ui#showModal"><a href="LuCI.ui.html#showModal">showModal</a></li>
2714
2715 <li data-name="LuCI.ui#uploadFile"><a href="LuCI.ui.html#uploadFile">uploadFile</a></li>
2716
2717 </ul>
2718 <ul class="events itemMembers">
2719
2720 </ul>
2721 </li>
2722
2723 <li class="item" data-name="LuCI.ui.AbstractElement">
2724 <span class="title">
2725 <a href="LuCI.ui.AbstractElement.html">LuCI.ui.AbstractElement</a>
2726
2727 </span>
2728 <ul class="members itemMembers">
2729
2730 </ul>
2731 <ul class="typedefs itemMembers">
2732
2733 <span class="subtitle">Typedefs</span>
2734
2735 <li data-name="LuCI.ui.AbstractElement.InitOptions"><a href="LuCI.ui.AbstractElement.html#.InitOptions">InitOptions</a></li>
2736
2737 </ul>
2738 <ul class="typedefs itemMembers">
2739
2740 </ul>
2741 <ul class="methods itemMembers">
2742
2743 <span class="subtitle">Methods</span>
2744
2745 <li data-name="LuCI.ui.AbstractElement#getValue"><a href="LuCI.ui.AbstractElement.html#getValue">getValue</a></li>
2746
2747 <li data-name="LuCI.ui.AbstractElement#isChanged"><a href="LuCI.ui.AbstractElement.html#isChanged">isChanged</a></li>
2748
2749 <li data-name="LuCI.ui.AbstractElement#isValid"><a href="LuCI.ui.AbstractElement.html#isValid">isValid</a></li>
2750
2751 <li data-name="LuCI.ui.AbstractElement#registerEvents"><a href="LuCI.ui.AbstractElement.html#registerEvents">registerEvents</a></li>
2752
2753 <li data-name="LuCI.ui.AbstractElement#render"><a href="LuCI.ui.AbstractElement.html#render">render</a></li>
2754
2755 <li data-name="LuCI.ui.AbstractElement#setChangeEvents"><a href="LuCI.ui.AbstractElement.html#setChangeEvents">setChangeEvents</a></li>
2756
2757 <li data-name="LuCI.ui.AbstractElement#setPlaceholder"><a href="LuCI.ui.AbstractElement.html#setPlaceholder">setPlaceholder</a></li>
2758
2759 <li data-name="LuCI.ui.AbstractElement#setUpdateEvents"><a href="LuCI.ui.AbstractElement.html#setUpdateEvents">setUpdateEvents</a></li>
2760
2761 <li data-name="LuCI.ui.AbstractElement#setValue"><a href="LuCI.ui.AbstractElement.html#setValue">setValue</a></li>
2762
2763 <li data-name="LuCI.ui.AbstractElement#triggerValidation"><a href="LuCI.ui.AbstractElement.html#triggerValidation">triggerValidation</a></li>
2764
2765 </ul>
2766 <ul class="events itemMembers">
2767
2768 </ul>
2769 </li>
2770
2771 <li class="item" data-name="LuCI.ui.changes">
2772 <span class="title">
2773 <a href="LuCI.ui.changes.html">LuCI.ui.changes</a>
2774
2775 </span>
2776 <ul class="members itemMembers">
2777
2778 </ul>
2779 <ul class="typedefs itemMembers">
2780
2781 </ul>
2782 <ul class="typedefs itemMembers">
2783
2784 </ul>
2785 <ul class="methods itemMembers">
2786
2787 <span class="subtitle">Methods</span>
2788
2789 <li data-name="LuCI.ui.changes#apply"><a href="LuCI.ui.changes.html#apply">apply</a></li>
2790
2791 <li data-name="LuCI.ui.changes#displayChanges"><a href="LuCI.ui.changes.html#displayChanges">displayChanges</a></li>
2792
2793 <li data-name="LuCI.ui.changes#renderChangeIndicator"><a href="LuCI.ui.changes.html#renderChangeIndicator">renderChangeIndicator</a></li>
2794
2795 <li data-name="LuCI.ui.changes#revert"><a href="LuCI.ui.changes.html#revert">revert</a></li>
2796
2797 <li data-name="LuCI.ui.changes#setIndicator"><a href="LuCI.ui.changes.html#setIndicator">setIndicator</a></li>
2798
2799 </ul>
2800 <ul class="events itemMembers">
2801
2802 </ul>
2803 </li>
2804
2805 <li class="item" data-name="LuCI.ui.Checkbox">
2806 <span class="title">
2807 <a href="LuCI.ui.Checkbox.html">LuCI.ui.Checkbox</a>
2808
2809 </span>
2810 <ul class="members itemMembers">
2811
2812 </ul>
2813 <ul class="typedefs itemMembers">
2814
2815 <span class="subtitle">Typedefs</span>
2816
2817 <li data-name="LuCI.ui.Checkbox.InitOptions"><a href="LuCI.ui.Checkbox.html#.InitOptions">InitOptions</a></li>
2818
2819 </ul>
2820 <ul class="typedefs itemMembers">
2821
2822 </ul>
2823 <ul class="methods itemMembers">
2824
2825 <span class="subtitle">Methods</span>
2826
2827 <li data-name="LuCI.ui.Checkbox#getValue"><a href="LuCI.ui.Checkbox.html#getValue">getValue</a></li>
2828
2829 <li data-name="LuCI.ui.Checkbox#isChanged"><a href="LuCI.ui.Checkbox.html#isChanged">isChanged</a></li>
2830
2831 <li data-name="LuCI.ui.Checkbox#isChecked"><a href="LuCI.ui.Checkbox.html#isChecked">isChecked</a></li>
2832
2833 <li data-name="LuCI.ui.Checkbox#isValid"><a href="LuCI.ui.Checkbox.html#isValid">isValid</a></li>
2834
2835 <li data-name="LuCI.ui.Checkbox#registerEvents"><a href="LuCI.ui.Checkbox.html#registerEvents">registerEvents</a></li>
2836
2837 <li data-name="LuCI.ui.Checkbox#render"><a href="LuCI.ui.Checkbox.html#render">render</a></li>
2838
2839 <li data-name="LuCI.ui.Checkbox#setChangeEvents"><a href="LuCI.ui.Checkbox.html#setChangeEvents">setChangeEvents</a></li>
2840
2841 <li data-name="LuCI.ui.Checkbox#setPlaceholder"><a href="LuCI.ui.Checkbox.html#setPlaceholder">setPlaceholder</a></li>
2842
2843 <li data-name="LuCI.ui.Checkbox#setUpdateEvents"><a href="LuCI.ui.Checkbox.html#setUpdateEvents">setUpdateEvents</a></li>
2844
2845 <li data-name="LuCI.ui.Checkbox#setValue"><a href="LuCI.ui.Checkbox.html#setValue">setValue</a></li>
2846
2847 <li data-name="LuCI.ui.Checkbox#triggerValidation"><a href="LuCI.ui.Checkbox.html#triggerValidation">triggerValidation</a></li>
2848
2849 </ul>
2850 <ul class="events itemMembers">
2851
2852 </ul>
2853 </li>
2854
2855 <li class="item" data-name="LuCI.ui.Combobox">
2856 <span class="title">
2857 <a href="LuCI.ui.Combobox.html">LuCI.ui.Combobox</a>
2858
2859 </span>
2860 <ul class="members itemMembers">
2861
2862 </ul>
2863 <ul class="typedefs itemMembers">
2864
2865 <span class="subtitle">Typedefs</span>
2866
2867 <li data-name="LuCI.ui.Combobox.InitOptions"><a href="LuCI.ui.Combobox.html#.InitOptions">InitOptions</a></li>
2868
2869 </ul>
2870 <ul class="typedefs itemMembers">
2871
2872 </ul>
2873 <ul class="methods itemMembers">
2874
2875 <span class="subtitle">Methods</span>
2876
2877 <li data-name="LuCI.ui.Combobox#addChoices"><a href="LuCI.ui.Combobox.html#addChoices">addChoices</a></li>
2878
2879 <li data-name="LuCI.ui.Combobox#clearChoices"><a href="LuCI.ui.Combobox.html#clearChoices">clearChoices</a></li>
2880
2881 <li data-name="LuCI.ui.Combobox#closeAllDropdowns"><a href="LuCI.ui.Combobox.html#closeAllDropdowns">closeAllDropdowns</a></li>
2882
2883 <li data-name="LuCI.ui.Combobox#isChanged"><a href="LuCI.ui.Combobox.html#isChanged">isChanged</a></li>
2884
2885 <li data-name="LuCI.ui.Combobox#isValid"><a href="LuCI.ui.Combobox.html#isValid">isValid</a></li>
2886
2887 <li data-name="LuCI.ui.Combobox#registerEvents"><a href="LuCI.ui.Combobox.html#registerEvents">registerEvents</a></li>
2888
2889 <li data-name="LuCI.ui.Combobox#setChangeEvents"><a href="LuCI.ui.Combobox.html#setChangeEvents">setChangeEvents</a></li>
2890
2891 <li data-name="LuCI.ui.Combobox#setPlaceholder"><a href="LuCI.ui.Combobox.html#setPlaceholder">setPlaceholder</a></li>
2892
2893 <li data-name="LuCI.ui.Combobox#setUpdateEvents"><a href="LuCI.ui.Combobox.html#setUpdateEvents">setUpdateEvents</a></li>
2894
2895 <li data-name="LuCI.ui.Combobox#triggerValidation"><a href="LuCI.ui.Combobox.html#triggerValidation">triggerValidation</a></li>
2896
2897 </ul>
2898 <ul class="events itemMembers">
2899
2900 </ul>
2901 </li>
2902
2903 <li class="item" data-name="LuCI.ui.ComboButton">
2904 <span class="title">
2905 <a href="LuCI.ui.ComboButton.html">LuCI.ui.ComboButton</a>
2906
2907 </span>
2908 <ul class="members itemMembers">
2909
2910 </ul>
2911 <ul class="typedefs itemMembers">
2912
2913 <span class="subtitle">Typedefs</span>
2914
2915 <li data-name="LuCI.ui.ComboButton.InitOptions"><a href="LuCI.ui.ComboButton.html#.InitOptions">InitOptions</a></li>
2916
2917 </ul>
2918 <ul class="typedefs itemMembers">
2919
2920 </ul>
2921 <ul class="methods itemMembers">
2922
2923 <span class="subtitle">Methods</span>
2924
2925 <li data-name="LuCI.ui.ComboButton#addChoices"><a href="LuCI.ui.ComboButton.html#addChoices">addChoices</a></li>
2926
2927 <li data-name="LuCI.ui.ComboButton#clearChoices"><a href="LuCI.ui.ComboButton.html#clearChoices">clearChoices</a></li>
2928
2929 <li data-name="LuCI.ui.ComboButton#closeAllDropdowns"><a href="LuCI.ui.ComboButton.html#closeAllDropdowns">closeAllDropdowns</a></li>
2930
2931 <li data-name="LuCI.ui.ComboButton#isChanged"><a href="LuCI.ui.ComboButton.html#isChanged">isChanged</a></li>
2932
2933 <li data-name="LuCI.ui.ComboButton#isValid"><a href="LuCI.ui.ComboButton.html#isValid">isValid</a></li>
2934
2935 <li data-name="LuCI.ui.ComboButton#registerEvents"><a href="LuCI.ui.ComboButton.html#registerEvents">registerEvents</a></li>
2936
2937 <li data-name="LuCI.ui.ComboButton#setChangeEvents"><a href="LuCI.ui.ComboButton.html#setChangeEvents">setChangeEvents</a></li>
2938
2939 <li data-name="LuCI.ui.ComboButton#setPlaceholder"><a href="LuCI.ui.ComboButton.html#setPlaceholder">setPlaceholder</a></li>
2940
2941 <li data-name="LuCI.ui.ComboButton#setUpdateEvents"><a href="LuCI.ui.ComboButton.html#setUpdateEvents">setUpdateEvents</a></li>
2942
2943 <li data-name="LuCI.ui.ComboButton#triggerValidation"><a href="LuCI.ui.ComboButton.html#triggerValidation">triggerValidation</a></li>
2944
2945 </ul>
2946 <ul class="events itemMembers">
2947
2948 </ul>
2949 </li>
2950
2951 <li class="item" data-name="LuCI.ui.Dropdown">
2952 <span class="title">
2953 <a href="LuCI.ui.Dropdown.html">LuCI.ui.Dropdown</a>
2954
2955 </span>
2956 <ul class="members itemMembers">
2957
2958 </ul>
2959 <ul class="typedefs itemMembers">
2960
2961 <span class="subtitle">Typedefs</span>
2962
2963 <li data-name="LuCI.ui.Dropdown.InitOptions"><a href="LuCI.ui.Dropdown.html#.InitOptions">InitOptions</a></li>
2964
2965 </ul>
2966 <ul class="typedefs itemMembers">
2967
2968 </ul>
2969 <ul class="methods itemMembers">
2970
2971 <span class="subtitle">Methods</span>
2972
2973 <li data-name="LuCI.ui.Dropdown#addChoices"><a href="LuCI.ui.Dropdown.html#addChoices">addChoices</a></li>
2974
2975 <li data-name="LuCI.ui.Dropdown#clearChoices"><a href="LuCI.ui.Dropdown.html#clearChoices">clearChoices</a></li>
2976
2977 <li data-name="LuCI.ui.Dropdown#closeAllDropdowns"><a href="LuCI.ui.Dropdown.html#closeAllDropdowns">closeAllDropdowns</a></li>
2978
2979 <li data-name="LuCI.ui.Dropdown#getValue"><a href="LuCI.ui.Dropdown.html#getValue">getValue</a></li>
2980
2981 <li data-name="LuCI.ui.Dropdown#isChanged"><a href="LuCI.ui.Dropdown.html#isChanged">isChanged</a></li>
2982
2983 <li data-name="LuCI.ui.Dropdown#isValid"><a href="LuCI.ui.Dropdown.html#isValid">isValid</a></li>
2984
2985 <li data-name="LuCI.ui.Dropdown#registerEvents"><a href="LuCI.ui.Dropdown.html#registerEvents">registerEvents</a></li>
2986
2987 <li data-name="LuCI.ui.Dropdown#render"><a href="LuCI.ui.Dropdown.html#render">render</a></li>
2988
2989 <li data-name="LuCI.ui.Dropdown#setChangeEvents"><a href="LuCI.ui.Dropdown.html#setChangeEvents">setChangeEvents</a></li>
2990
2991 <li data-name="LuCI.ui.Dropdown#setPlaceholder"><a href="LuCI.ui.Dropdown.html#setPlaceholder">setPlaceholder</a></li>
2992
2993 <li data-name="LuCI.ui.Dropdown#setUpdateEvents"><a href="LuCI.ui.Dropdown.html#setUpdateEvents">setUpdateEvents</a></li>
2994
2995 <li data-name="LuCI.ui.Dropdown#setValue"><a href="LuCI.ui.Dropdown.html#setValue">setValue</a></li>
2996
2997 <li data-name="LuCI.ui.Dropdown#triggerValidation"><a href="LuCI.ui.Dropdown.html#triggerValidation">triggerValidation</a></li>
2998
2999 </ul>
3000 <ul class="events itemMembers">
3001
3002 </ul>
3003 </li>
3004
3005 <li class="item" data-name="LuCI.ui.DynamicList">
3006 <span class="title">
3007 <a href="LuCI.ui.DynamicList.html">LuCI.ui.DynamicList</a>
3008
3009 </span>
3010 <ul class="members itemMembers">
3011
3012 </ul>
3013 <ul class="typedefs itemMembers">
3014
3015 <span class="subtitle">Typedefs</span>
3016
3017 <li data-name="LuCI.ui.DynamicList.InitOptions"><a href="LuCI.ui.DynamicList.html#.InitOptions">InitOptions</a></li>
3018
3019 </ul>
3020 <ul class="typedefs itemMembers">
3021
3022 </ul>
3023 <ul class="methods itemMembers">
3024
3025 <span class="subtitle">Methods</span>
3026
3027 <li data-name="LuCI.ui.DynamicList#addChoices"><a href="LuCI.ui.DynamicList.html#addChoices">addChoices</a></li>
3028
3029 <li data-name="LuCI.ui.DynamicList#clearChoices"><a href="LuCI.ui.DynamicList.html#clearChoices">clearChoices</a></li>
3030
3031 <li data-name="LuCI.ui.DynamicList#getValue"><a href="LuCI.ui.DynamicList.html#getValue">getValue</a></li>
3032
3033 <li data-name="LuCI.ui.DynamicList#isChanged"><a href="LuCI.ui.DynamicList.html#isChanged">isChanged</a></li>
3034
3035 <li data-name="LuCI.ui.DynamicList#isValid"><a href="LuCI.ui.DynamicList.html#isValid">isValid</a></li>
3036
3037 <li data-name="LuCI.ui.DynamicList#registerEvents"><a href="LuCI.ui.DynamicList.html#registerEvents">registerEvents</a></li>
3038
3039 <li data-name="LuCI.ui.DynamicList#render"><a href="LuCI.ui.DynamicList.html#render">render</a></li>
3040
3041 <li data-name="LuCI.ui.DynamicList#setChangeEvents"><a href="LuCI.ui.DynamicList.html#setChangeEvents">setChangeEvents</a></li>
3042
3043 <li data-name="LuCI.ui.DynamicList#setPlaceholder"><a href="LuCI.ui.DynamicList.html#setPlaceholder">setPlaceholder</a></li>
3044
3045 <li data-name="LuCI.ui.DynamicList#setUpdateEvents"><a href="LuCI.ui.DynamicList.html#setUpdateEvents">setUpdateEvents</a></li>
3046
3047 <li data-name="LuCI.ui.DynamicList#setValue"><a href="LuCI.ui.DynamicList.html#setValue">setValue</a></li>
3048
3049 <li data-name="LuCI.ui.DynamicList#triggerValidation"><a href="LuCI.ui.DynamicList.html#triggerValidation">triggerValidation</a></li>
3050
3051 </ul>
3052 <ul class="events itemMembers">
3053
3054 </ul>
3055 </li>
3056
3057 <li class="item" data-name="LuCI.ui.FileUpload">
3058 <span class="title">
3059 <a href="LuCI.ui.FileUpload.html">LuCI.ui.FileUpload</a>
3060
3061 </span>
3062 <ul class="members itemMembers">
3063
3064 </ul>
3065 <ul class="typedefs itemMembers">
3066
3067 <span class="subtitle">Typedefs</span>
3068
3069 <li data-name="LuCI.ui.FileUpload.InitOptions"><a href="LuCI.ui.FileUpload.html#.InitOptions">InitOptions</a></li>
3070
3071 </ul>
3072 <ul class="typedefs itemMembers">
3073
3074 </ul>
3075 <ul class="methods itemMembers">
3076
3077 <span class="subtitle">Methods</span>
3078
3079 <li data-name="LuCI.ui.FileUpload#getValue"><a href="LuCI.ui.FileUpload.html#getValue">getValue</a></li>
3080
3081 <li data-name="LuCI.ui.FileUpload#isChanged"><a href="LuCI.ui.FileUpload.html#isChanged">isChanged</a></li>
3082
3083 <li data-name="LuCI.ui.FileUpload#isValid"><a href="LuCI.ui.FileUpload.html#isValid">isValid</a></li>
3084
3085 <li data-name="LuCI.ui.FileUpload#registerEvents"><a href="LuCI.ui.FileUpload.html#registerEvents">registerEvents</a></li>
3086
3087 <li data-name="LuCI.ui.FileUpload#render"><a href="LuCI.ui.FileUpload.html#render">render</a></li>
3088
3089 <li data-name="LuCI.ui.FileUpload#setChangeEvents"><a href="LuCI.ui.FileUpload.html#setChangeEvents">setChangeEvents</a></li>
3090
3091 <li data-name="LuCI.ui.FileUpload#setPlaceholder"><a href="LuCI.ui.FileUpload.html#setPlaceholder">setPlaceholder</a></li>
3092
3093 <li data-name="LuCI.ui.FileUpload#setUpdateEvents"><a href="LuCI.ui.FileUpload.html#setUpdateEvents">setUpdateEvents</a></li>
3094
3095 <li data-name="LuCI.ui.FileUpload#setValue"><a href="LuCI.ui.FileUpload.html#setValue">setValue</a></li>
3096
3097 <li data-name="LuCI.ui.FileUpload#triggerValidation"><a href="LuCI.ui.FileUpload.html#triggerValidation">triggerValidation</a></li>
3098
3099 </ul>
3100 <ul class="events itemMembers">
3101
3102 </ul>
3103 </li>
3104
3105 <li class="item" data-name="LuCI.ui.Hiddenfield">
3106 <span class="title">
3107 <a href="LuCI.ui.Hiddenfield.html">LuCI.ui.Hiddenfield</a>
3108
3109 </span>
3110 <ul class="members itemMembers">
3111
3112 </ul>
3113 <ul class="typedefs itemMembers">
3114
3115 </ul>
3116 <ul class="typedefs itemMembers">
3117
3118 </ul>
3119 <ul class="methods itemMembers">
3120
3121 <span class="subtitle">Methods</span>
3122
3123 <li data-name="LuCI.ui.Hiddenfield#getValue"><a href="LuCI.ui.Hiddenfield.html#getValue">getValue</a></li>
3124
3125 <li data-name="LuCI.ui.Hiddenfield#isChanged"><a href="LuCI.ui.Hiddenfield.html#isChanged">isChanged</a></li>
3126
3127 <li data-name="LuCI.ui.Hiddenfield#isValid"><a href="LuCI.ui.Hiddenfield.html#isValid">isValid</a></li>
3128
3129 <li data-name="LuCI.ui.Hiddenfield#registerEvents"><a href="LuCI.ui.Hiddenfield.html#registerEvents">registerEvents</a></li>
3130
3131 <li data-name="LuCI.ui.Hiddenfield#render"><a href="LuCI.ui.Hiddenfield.html#render">render</a></li>
3132
3133 <li data-name="LuCI.ui.Hiddenfield#setChangeEvents"><a href="LuCI.ui.Hiddenfield.html#setChangeEvents">setChangeEvents</a></li>
3134
3135 <li data-name="LuCI.ui.Hiddenfield#setPlaceholder"><a href="LuCI.ui.Hiddenfield.html#setPlaceholder">setPlaceholder</a></li>
3136
3137 <li data-name="LuCI.ui.Hiddenfield#setUpdateEvents"><a href="LuCI.ui.Hiddenfield.html#setUpdateEvents">setUpdateEvents</a></li>
3138
3139 <li data-name="LuCI.ui.Hiddenfield#setValue"><a href="LuCI.ui.Hiddenfield.html#setValue">setValue</a></li>
3140
3141 <li data-name="LuCI.ui.Hiddenfield#triggerValidation"><a href="LuCI.ui.Hiddenfield.html#triggerValidation">triggerValidation</a></li>
3142
3143 </ul>
3144 <ul class="events itemMembers">
3145
3146 </ul>
3147 </li>
3148
3149 <li class="item" data-name="LuCI.ui.menu">
3150 <span class="title">
3151 <a href="LuCI.ui.menu.html">LuCI.ui.menu</a>
3152
3153 </span>
3154 <ul class="members itemMembers">
3155
3156 </ul>
3157 <ul class="typedefs itemMembers">
3158
3159 <span class="subtitle">Typedefs</span>
3160
3161 <li data-name="LuCI.ui.menu.MenuNode"><a href="LuCI.ui.menu.html#.MenuNode">MenuNode</a></li>
3162
3163 </ul>
3164 <ul class="typedefs itemMembers">
3165
3166 </ul>
3167 <ul class="methods itemMembers">
3168
3169 <span class="subtitle">Methods</span>
3170
3171 <li data-name="LuCI.ui.menu#flushCache"><a href="LuCI.ui.menu.html#flushCache">flushCache</a></li>
3172
3173 <li data-name="LuCI.ui.menu#getChildren"><a href="LuCI.ui.menu.html#getChildren">getChildren</a></li>
3174
3175 <li data-name="LuCI.ui.menu#load"><a href="LuCI.ui.menu.html#load">load</a></li>
3176
3177 </ul>
3178 <ul class="events itemMembers">
3179
3180 </ul>
3181 </li>
3182
3183 <li class="item" data-name="LuCI.ui.Select">
3184 <span class="title">
3185 <a href="LuCI.ui.Select.html">LuCI.ui.Select</a>
3186
3187 </span>
3188 <ul class="members itemMembers">
3189
3190 </ul>
3191 <ul class="typedefs itemMembers">
3192
3193 <span class="subtitle">Typedefs</span>
3194
3195 <li data-name="LuCI.ui.Select.InitOptions"><a href="LuCI.ui.Select.html#.InitOptions">InitOptions</a></li>
3196
3197 </ul>
3198 <ul class="typedefs itemMembers">
3199
3200 </ul>
3201 <ul class="methods itemMembers">
3202
3203 <span class="subtitle">Methods</span>
3204
3205 <li data-name="LuCI.ui.Select#getValue"><a href="LuCI.ui.Select.html#getValue">getValue</a></li>
3206
3207 <li data-name="LuCI.ui.Select#isChanged"><a href="LuCI.ui.Select.html#isChanged">isChanged</a></li>
3208
3209 <li data-name="LuCI.ui.Select#isValid"><a href="LuCI.ui.Select.html#isValid">isValid</a></li>
3210
3211 <li data-name="LuCI.ui.Select#registerEvents"><a href="LuCI.ui.Select.html#registerEvents">registerEvents</a></li>
3212
3213 <li data-name="LuCI.ui.Select#render"><a href="LuCI.ui.Select.html#render">render</a></li>
3214
3215 <li data-name="LuCI.ui.Select#setChangeEvents"><a href="LuCI.ui.Select.html#setChangeEvents">setChangeEvents</a></li>
3216
3217 <li data-name="LuCI.ui.Select#setPlaceholder"><a href="LuCI.ui.Select.html#setPlaceholder">setPlaceholder</a></li>
3218
3219 <li data-name="LuCI.ui.Select#setUpdateEvents"><a href="LuCI.ui.Select.html#setUpdateEvents">setUpdateEvents</a></li>
3220
3221 <li data-name="LuCI.ui.Select#setValue"><a href="LuCI.ui.Select.html#setValue">setValue</a></li>
3222
3223 <li data-name="LuCI.ui.Select#triggerValidation"><a href="LuCI.ui.Select.html#triggerValidation">triggerValidation</a></li>
3224
3225 </ul>
3226 <ul class="events itemMembers">
3227
3228 </ul>
3229 </li>
3230
3231 <li class="item" data-name="LuCI.ui.tabs">
3232 <span class="title">
3233 <a href="LuCI.ui.tabs.html">LuCI.ui.tabs</a>
3234
3235 </span>
3236 <ul class="members itemMembers">
3237
3238 </ul>
3239 <ul class="typedefs itemMembers">
3240
3241 </ul>
3242 <ul class="typedefs itemMembers">
3243
3244 </ul>
3245 <ul class="methods itemMembers">
3246
3247 <span class="subtitle">Methods</span>
3248
3249 <li data-name="LuCI.ui.tabs#initTabGroup"><a href="LuCI.ui.tabs.html#initTabGroup">initTabGroup</a></li>
3250
3251 <li data-name="LuCI.ui.tabs#isEmptyPane"><a href="LuCI.ui.tabs.html#isEmptyPane">isEmptyPane</a></li>
3252
3253 </ul>
3254 <ul class="events itemMembers">
3255
3256 </ul>
3257 </li>
3258
3259 <li class="item" data-name="LuCI.ui.Textarea">
3260 <span class="title">
3261 <a href="LuCI.ui.Textarea.html">LuCI.ui.Textarea</a>
3262
3263 </span>
3264 <ul class="members itemMembers">
3265
3266 </ul>
3267 <ul class="typedefs itemMembers">
3268
3269 <span class="subtitle">Typedefs</span>
3270
3271 <li data-name="LuCI.ui.Textarea.InitOptions"><a href="LuCI.ui.Textarea.html#.InitOptions">InitOptions</a></li>
3272
3273 </ul>
3274 <ul class="typedefs itemMembers">
3275
3276 </ul>
3277 <ul class="methods itemMembers">
3278
3279 <span class="subtitle">Methods</span>
3280
3281 <li data-name="LuCI.ui.Textarea#getValue"><a href="LuCI.ui.Textarea.html#getValue">getValue</a></li>
3282
3283 <li data-name="LuCI.ui.Textarea#isChanged"><a href="LuCI.ui.Textarea.html#isChanged">isChanged</a></li>
3284
3285 <li data-name="LuCI.ui.Textarea#isValid"><a href="LuCI.ui.Textarea.html#isValid">isValid</a></li>
3286
3287 <li data-name="LuCI.ui.Textarea#registerEvents"><a href="LuCI.ui.Textarea.html#registerEvents">registerEvents</a></li>
3288
3289 <li data-name="LuCI.ui.Textarea#render"><a href="LuCI.ui.Textarea.html#render">render</a></li>
3290
3291 <li data-name="LuCI.ui.Textarea#setChangeEvents"><a href="LuCI.ui.Textarea.html#setChangeEvents">setChangeEvents</a></li>
3292
3293 <li data-name="LuCI.ui.Textarea#setPlaceholder"><a href="LuCI.ui.Textarea.html#setPlaceholder">setPlaceholder</a></li>
3294
3295 <li data-name="LuCI.ui.Textarea#setUpdateEvents"><a href="LuCI.ui.Textarea.html#setUpdateEvents">setUpdateEvents</a></li>
3296
3297 <li data-name="LuCI.ui.Textarea#setValue"><a href="LuCI.ui.Textarea.html#setValue">setValue</a></li>
3298
3299 <li data-name="LuCI.ui.Textarea#triggerValidation"><a href="LuCI.ui.Textarea.html#triggerValidation">triggerValidation</a></li>
3300
3301 </ul>
3302 <ul class="events itemMembers">
3303
3304 </ul>
3305 </li>
3306
3307 <li class="item" data-name="LuCI.ui.Textfield">
3308 <span class="title">
3309 <a href="LuCI.ui.Textfield.html">LuCI.ui.Textfield</a>
3310
3311 </span>
3312 <ul class="members itemMembers">
3313
3314 </ul>
3315 <ul class="typedefs itemMembers">
3316
3317 <span class="subtitle">Typedefs</span>
3318
3319 <li data-name="LuCI.ui.Textfield.InitOptions"><a href="LuCI.ui.Textfield.html#.InitOptions">InitOptions</a></li>
3320
3321 </ul>
3322 <ul class="typedefs itemMembers">
3323
3324 </ul>
3325 <ul class="methods itemMembers">
3326
3327 <span class="subtitle">Methods</span>
3328
3329 <li data-name="LuCI.ui.Textfield#getValue"><a href="LuCI.ui.Textfield.html#getValue">getValue</a></li>
3330
3331 <li data-name="LuCI.ui.Textfield#isChanged"><a href="LuCI.ui.Textfield.html#isChanged">isChanged</a></li>
3332
3333 <li data-name="LuCI.ui.Textfield#isValid"><a href="LuCI.ui.Textfield.html#isValid">isValid</a></li>
3334
3335 <li data-name="LuCI.ui.Textfield#registerEvents"><a href="LuCI.ui.Textfield.html#registerEvents">registerEvents</a></li>
3336
3337 <li data-name="LuCI.ui.Textfield#render"><a href="LuCI.ui.Textfield.html#render">render</a></li>
3338
3339 <li data-name="LuCI.ui.Textfield#setChangeEvents"><a href="LuCI.ui.Textfield.html#setChangeEvents">setChangeEvents</a></li>
3340
3341 <li data-name="LuCI.ui.Textfield#setPlaceholder"><a href="LuCI.ui.Textfield.html#setPlaceholder">setPlaceholder</a></li>
3342
3343 <li data-name="LuCI.ui.Textfield#setUpdateEvents"><a href="LuCI.ui.Textfield.html#setUpdateEvents">setUpdateEvents</a></li>
3344
3345 <li data-name="LuCI.ui.Textfield#setValue"><a href="LuCI.ui.Textfield.html#setValue">setValue</a></li>
3346
3347 <li data-name="LuCI.ui.Textfield#triggerValidation"><a href="LuCI.ui.Textfield.html#triggerValidation">triggerValidation</a></li>
3348
3349 </ul>
3350 <ul class="events itemMembers">
3351
3352 </ul>
3353 </li>
3354
3355 <li class="item" data-name="LuCI.view">
3356 <span class="title">
3357 <a href="LuCI.view.html">LuCI.view</a>
3358
3359 </span>
3360 <ul class="members itemMembers">
3361
3362 </ul>
3363 <ul class="typedefs itemMembers">
3364
3365 </ul>
3366 <ul class="typedefs itemMembers">
3367
3368 </ul>
3369 <ul class="methods itemMembers">
3370
3371 <span class="subtitle">Methods</span>
3372
3373 <li data-name="LuCI.view#addFooter"><a href="LuCI.view.html#addFooter">addFooter</a></li>
3374
3375 <li data-name="LuCI.view#handleReset"><a href="LuCI.view.html#handleReset">handleReset</a></li>
3376
3377 <li data-name="LuCI.view#handleSave"><a href="LuCI.view.html#handleSave">handleSave</a></li>
3378
3379 <li data-name="LuCI.view#handleSaveApply"><a href="LuCI.view.html#handleSaveApply">handleSaveApply</a></li>
3380
3381 <li data-name="LuCI.view#load"><a href="LuCI.view.html#load">load</a></li>
3382
3383 <li data-name="LuCI.view#render"><a href="LuCI.view.html#render">render</a></li>
3384
3385 </ul>
3386 <ul class="events itemMembers">
3387
3388 </ul>
3389 </li>
3390
3391 <li class="item" data-name="LuCI.xhr">
3392 <span class="title">
3393 <a href="LuCI.xhr.html">LuCI.xhr</a>
3394
3395 </span>
3396 <ul class="members itemMembers">
3397
3398 </ul>
3399 <ul class="typedefs itemMembers">
3400
3401 </ul>
3402 <ul class="typedefs itemMembers">
3403
3404 </ul>
3405 <ul class="methods itemMembers">
3406
3407 <span class="subtitle">Methods</span>
3408
3409 <li data-name="LuCI.xhr#abort"><a href="LuCI.xhr.html#abort">abort</a></li>
3410
3411 <li data-name="LuCI.xhr#busy"><a href="LuCI.xhr.html#busy">busy</a></li>
3412
3413 <li data-name="LuCI.xhr#cancel"><a href="LuCI.xhr.html#cancel">cancel</a></li>
3414
3415 <li data-name="LuCI.xhr#get"><a href="LuCI.xhr.html#get">get</a></li>
3416
3417 <li data-name="LuCI.xhr#post"><a href="LuCI.xhr.html#post">post</a></li>
3418
3419 <li data-name="LuCI.xhr#send_form"><a href="LuCI.xhr.html#send_form">send_form</a></li>
3420
3421 </ul>
3422 <ul class="events itemMembers">
3423
3424 </ul>
3425 </li>
3426
3427 </ul>
3428 </div>
3429 <div class="main">
3430 <h1 class="page-title" data-filename="ui.js.html">Source: ui.js</h1>
3431
3432
3433
3434
3435 <section>
3436 <article>
3437 <pre id="source-code" class="prettyprint source "><code>'use strict';
3438 'require validation';
3439 'require baseclass';
3440 'require request';
3441 'require session';
3442 'require poll';
3443 'require dom';
3444 'require rpc';
3445 'require uci';
3446 'require fs';
3447
3448 var modalDiv = null,
3449 tooltipDiv = null,
3450 indicatorDiv = null,
3451 tooltipTimeout = null;
3452
3453 /**
3454 * @class AbstractElement
3455 * @memberof LuCI.ui
3456 * @hideconstructor
3457 * @classdesc
3458 *
3459 * The `AbstractElement` class serves as abstract base for the different widgets
3460 * implemented by `LuCI.ui`. It provides the common logic for getting and
3461 * setting values, for checking the validity state and for wiring up required
3462 * events.
3463 *
3464 * UI widget instances are usually not supposed to be created by view code
3465 * directly, instead they're implicitely created by `LuCI.form` when
3466 * instantiating CBI forms.
3467 *
3468 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3469 * in views, use `'require ui'` and refer to `ui.AbstractElement`. To import
3470 * it in external JavaScript, use `L.require("ui").then(...)` and access the
3471 * `AbstractElement` property of the class instance value.
3472 */
3473 var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ {
3474 /**
3475 * @typedef {Object} InitOptions
3476 * @memberof LuCI.ui.AbstractElement
3477 *
3478 * @property {string} [id]
3479 * Specifies the widget ID to use. It will be used as HTML `id` attribute
3480 * on the toplevel widget DOM node.
3481 *
3482 * @property {string} [name]
3483 * Specifies the widget name which is set as HTML `name` attribute on the
3484 * corresponding `&lt;input>` element.
3485 *
3486 * @property {boolean} [optional=true]
3487 * Specifies whether the input field allows empty values.
3488 *
3489 * @property {string} [datatype=string]
3490 * An expression describing the input data validation constraints.
3491 * It defaults to `string` which will allow any value.
3492 * See {@link LuCI.validation} for details on the expression format.
3493 *
3494 * @property {function} [validator]
3495 * Specifies a custom validator function which is invoked after the
3496 * standard validation constraints are checked. The function should return
3497 * `true` to accept the given input value. Any other return value type is
3498 * converted to a string and treated as validation error message.
3499 *
3500 * @property {boolean} [disabled=false]
3501 * Specifies whether the widget should be rendered in disabled state
3502 * (`true`) or not (`false`). Disabled widgets cannot be interacted with
3503 * and are displayed in a slightly faded style.
3504 */
3505
3506 /**
3507 * Read the current value of the input widget.
3508 *
3509 * @instance
3510 * @memberof LuCI.ui.AbstractElement
3511 * @returns {string|string[]|null}
3512 * The current value of the input element. For simple inputs like text
3513 * fields or selects, the return value type will be a - possibly empty -
3514 * string. Complex widgets such as `DynamicList` instances may result in
3515 * an array of strings or `null` for unset values.
3516 */
3517 getValue: function() {
3518 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3519 return this.node.value;
3520
3521 return null;
3522 },
3523
3524 /**
3525 * Set the current value of the input widget.
3526 *
3527 * @instance
3528 * @memberof LuCI.ui.AbstractElement
3529 * @param {string|string[]|null} value
3530 * The value to set the input element to. For simple inputs like text
3531 * fields or selects, the value should be a - possibly empty - string.
3532 * Complex widgets such as `DynamicList` instances may accept string array
3533 * or `null` values.
3534 */
3535 setValue: function(value) {
3536 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3537 this.node.value = value;
3538 },
3539
3540 /**
3541 * Set the current placeholder value of the input widget.
3542 *
3543 * @instance
3544 * @memberof LuCI.ui.AbstractElement
3545 * @param {string|string[]|null} value
3546 * The placeholder to set for the input element. Only applicable to text
3547 * inputs, not to radio buttons, selects or similar.
3548 */
3549 setPlaceholder: function(value) {
3550 var node = this.node ? this.node.querySelector('input,textarea') : null;
3551 if (node) {
3552 switch (node.getAttribute('type') || 'text') {
3553 case 'password':
3554 case 'search':
3555 case 'tel':
3556 case 'text':
3557 case 'url':
3558 if (value != null &amp;&amp; value != '')
3559 node.setAttribute('placeholder', value);
3560 else
3561 node.removeAttribute('placeholder');
3562 }
3563 }
3564 },
3565
3566 /**
3567 * Check whether the input value was altered by the user.
3568 *
3569 * @instance
3570 * @memberof LuCI.ui.AbstractElement
3571 * @returns {boolean}
3572 * Returns `true` if the input value has been altered by the user or
3573 * `false` if it is unchaged. Note that if the user modifies the initial
3574 * value and changes it back to the original state, it is still reported
3575 * as changed.
3576 */
3577 isChanged: function() {
3578 return (this.node ? this.node.getAttribute('data-changed') : null) == 'true';
3579 },
3580
3581 /**
3582 * Check whether the current input value is valid.
3583 *
3584 * @instance
3585 * @memberof LuCI.ui.AbstractElement
3586 * @returns {boolean}
3587 * Returns `true` if the current input value is valid or `false` if it does
3588 * not meet the validation constraints.
3589 */
3590 isValid: function() {
3591 return (this.validState !== false);
3592 },
3593
3594 /**
3595 * Force validation of the current input value.
3596 *
3597 * Usually input validation is automatically triggered by various DOM events
3598 * bound to the input widget. In some cases it is required though to manually
3599 * trigger validation runs, e.g. when programmatically altering values.
3600 *
3601 * @instance
3602 * @memberof LuCI.ui.AbstractElement
3603 */
3604 triggerValidation: function() {
3605 if (typeof(this.vfunc) != 'function')
3606 return false;
3607
3608 var wasValid = this.isValid();
3609
3610 this.vfunc();
3611
3612 return (wasValid != this.isValid());
3613 },
3614
3615 /**
3616 * Dispatch a custom (synthetic) event in response to received events.
3617 *
3618 * Sets up event handlers on the given target DOM node for the given event
3619 * names that dispatch a custom event of the given type to the widget root
3620 * DOM node.
3621 *
3622 * The primary purpose of this function is to set up a series of custom
3623 * uniform standard events such as `widget-update`, `validation-success`,
3624 * `validation-failure` etc. which are triggered by various different
3625 * widget specific native DOM events.
3626 *
3627 * @instance
3628 * @memberof LuCI.ui.AbstractElement
3629 * @param {Node} targetNode
3630 * Specifies the DOM node on which the native event listeners should be
3631 * registered.
3632 *
3633 * @param {string} synevent
3634 * The name of the custom event to dispatch to the widget root DOM node.
3635 *
3636 * @param {string[]} events
3637 * The native DOM events for which event handlers should be registered.
3638 */
3639 registerEvents: function(targetNode, synevent, events) {
3640 var dispatchFn = L.bind(function(ev) {
3641 this.node.dispatchEvent(new CustomEvent(synevent, { bubbles: true }));
3642 }, this);
3643
3644 for (var i = 0; i &lt; events.length; i++)
3645 targetNode.addEventListener(events[i], dispatchFn);
3646 },
3647
3648 /**
3649 * Setup listeners for native DOM events that may update the widget value.
3650 *
3651 * Sets up event handlers on the given target DOM node for the given event
3652 * names which may cause the input value to update, such as `keyup` or
3653 * `onclick` events. In contrast to change events, such update events will
3654 * trigger input value validation.
3655 *
3656 * @instance
3657 * @memberof LuCI.ui.AbstractElement
3658 * @param {Node} targetNode
3659 * Specifies the DOM node on which the event listeners should be registered.
3660 *
3661 * @param {...string} events
3662 * The DOM events for which event handlers should be registered.
3663 */
3664 setUpdateEvents: function(targetNode /*, ... */) {
3665 var datatype = this.options.datatype,
3666 optional = this.options.hasOwnProperty('optional') ? this.options.optional : true,
3667 validate = this.options.validate,
3668 events = this.varargs(arguments, 1);
3669
3670 this.registerEvents(targetNode, 'widget-update', events);
3671
3672 if (!datatype &amp;&amp; !validate)
3673 return;
3674
3675 this.vfunc = UI.prototype.addValidator.apply(UI.prototype, [
3676 targetNode, datatype || 'string',
3677 optional, validate
3678 ].concat(events));
3679
3680 this.node.addEventListener('validation-success', L.bind(function(ev) {
3681 this.validState = true;
3682 }, this));
3683
3684 this.node.addEventListener('validation-failure', L.bind(function(ev) {
3685 this.validState = false;
3686 }, this));
3687 },
3688
3689 /**
3690 * Setup listeners for native DOM events that may change the widget value.
3691 *
3692 * Sets up event handlers on the given target DOM node for the given event
3693 * names which may cause the input value to change completely, such as
3694 * `change` events in a select menu. In contrast to update events, such
3695 * change events will not trigger input value validation but they may cause
3696 * field dependencies to get re-evaluated and will mark the input widget
3697 * as dirty.
3698 *
3699 * @instance
3700 * @memberof LuCI.ui.AbstractElement
3701 * @param {Node} targetNode
3702 * Specifies the DOM node on which the event listeners should be registered.
3703 *
3704 * @param {...string} events
3705 * The DOM events for which event handlers should be registered.
3706 */
3707 setChangeEvents: function(targetNode /*, ... */) {
3708 var tag_changed = L.bind(function(ev) { this.setAttribute('data-changed', true) }, this.node);
3709
3710 for (var i = 1; i &lt; arguments.length; i++)
3711 targetNode.addEventListener(arguments[i], tag_changed);
3712
3713 this.registerEvents(targetNode, 'widget-change', this.varargs(arguments, 1));
3714 },
3715
3716 /**
3717 * Render the widget, setup event listeners and return resulting markup.
3718 *
3719 * @instance
3720 * @memberof LuCI.ui.AbstractElement
3721 *
3722 * @returns {Node}
3723 * Returns a DOM Node or DocumentFragment containing the rendered
3724 * widget markup.
3725 */
3726 render: function() {}
3727 });
3728
3729 /**
3730 * Instantiate a text input widget.
3731 *
3732 * @constructor Textfield
3733 * @memberof LuCI.ui
3734 * @augments LuCI.ui.AbstractElement
3735 *
3736 * @classdesc
3737 *
3738 * The `Textfield` class implements a standard single line text input field.
3739 *
3740 * UI widget instances are usually not supposed to be created by view code
3741 * directly, instead they're implicitely created by `LuCI.form` when
3742 * instantiating CBI forms.
3743 *
3744 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3745 * in views, use `'require ui'` and refer to `ui.Textfield`. To import it in
3746 * external JavaScript, use `L.require("ui").then(...)` and access the
3747 * `Textfield` property of the class instance value.
3748 *
3749 * @param {string} [value=null]
3750 * The initial input value.
3751 *
3752 * @param {LuCI.ui.Textfield.InitOptions} [options]
3753 * Object describing the widget specific options to initialize the input.
3754 */
3755 var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ {
3756 /**
3757 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3758 * the following properties are recognized:
3759 *
3760 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3761 * @memberof LuCI.ui.Textfield
3762 *
3763 * @property {boolean} [password=false]
3764 * Specifies whether the input should be rendered as concealed password field.
3765 *
3766 * @property {boolean} [readonly=false]
3767 * Specifies whether the input widget should be rendered readonly.
3768 *
3769 * @property {number} [maxlength]
3770 * Specifies the HTML `maxlength` attribute to set on the corresponding
3771 * `&lt;input>` element. Note that this a legacy property that exists for
3772 * compatibility reasons. It is usually better to `maxlength(N)` validation
3773 * expression.
3774 *
3775 * @property {string} [placeholder]
3776 * Specifies the HTML `placeholder` attribute which is displayed when the
3777 * corresponding `&lt;input>` element is empty.
3778 */
3779 __init__: function(value, options) {
3780 this.value = value;
3781 this.options = Object.assign({
3782 optional: true,
3783 password: false
3784 }, options);
3785 },
3786
3787 /** @override */
3788 render: function() {
3789 var frameEl = E('div', { 'id': this.options.id });
3790 var inputEl = E('input', {
3791 'id': this.options.id ? 'widget.' + this.options.id : null,
3792 'name': this.options.name,
3793 'type': 'text',
3794 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text',
3795 'readonly': this.options.readonly ? '' : null,
3796 'disabled': this.options.disabled ? '' : null,
3797 'maxlength': this.options.maxlength,
3798 'placeholder': this.options.placeholder,
3799 'value': this.value,
3800 });
3801
3802 if (this.options.password) {
3803 frameEl.appendChild(E('div', { 'class': 'control-group' }, [
3804 inputEl,
3805 E('button', {
3806 'class': 'cbi-button cbi-button-neutral',
3807 'title': _('Reveal/hide password'),
3808 'aria-label': _('Reveal/hide password'),
3809 'click': function(ev) {
3810 var e = this.previousElementSibling;
3811 e.type = (e.type === 'password') ? 'text' : 'password';
3812 ev.preventDefault();
3813 }
3814 }, '∗')
3815 ]));
3816
3817 window.requestAnimationFrame(function() { inputEl.type = 'password' });
3818 }
3819 else {
3820 frameEl.appendChild(inputEl);
3821 }
3822
3823 return this.bind(frameEl);
3824 },
3825
3826 /** @private */
3827 bind: function(frameEl) {
3828 var inputEl = frameEl.querySelector('input');
3829
3830 this.node = frameEl;
3831
3832 this.setUpdateEvents(inputEl, 'keyup', 'blur');
3833 this.setChangeEvents(inputEl, 'change');
3834
3835 dom.bindClassInstance(frameEl, this);
3836
3837 return frameEl;
3838 },
3839
3840 /** @override */
3841 getValue: function() {
3842 var inputEl = this.node.querySelector('input');
3843 return inputEl.value;
3844 },
3845
3846 /** @override */
3847 setValue: function(value) {
3848 var inputEl = this.node.querySelector('input');
3849 inputEl.value = value;
3850 }
3851 });
3852
3853 /**
3854 * Instantiate a textarea widget.
3855 *
3856 * @constructor Textarea
3857 * @memberof LuCI.ui
3858 * @augments LuCI.ui.AbstractElement
3859 *
3860 * @classdesc
3861 *
3862 * The `Textarea` class implements a multiline text area input field.
3863 *
3864 * UI widget instances are usually not supposed to be created by view code
3865 * directly, instead they're implicitely created by `LuCI.form` when
3866 * instantiating CBI forms.
3867 *
3868 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3869 * in views, use `'require ui'` and refer to `ui.Textarea`. To import it in
3870 * external JavaScript, use `L.require("ui").then(...)` and access the
3871 * `Textarea` property of the class instance value.
3872 *
3873 * @param {string} [value=null]
3874 * The initial input value.
3875 *
3876 * @param {LuCI.ui.Textarea.InitOptions} [options]
3877 * Object describing the widget specific options to initialize the input.
3878 */
3879 var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ {
3880 /**
3881 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3882 * the following properties are recognized:
3883 *
3884 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3885 * @memberof LuCI.ui.Textarea
3886 *
3887 * @property {boolean} [readonly=false]
3888 * Specifies whether the input widget should be rendered readonly.
3889 *
3890 * @property {string} [placeholder]
3891 * Specifies the HTML `placeholder` attribute which is displayed when the
3892 * corresponding `&lt;textarea>` element is empty.
3893 *
3894 * @property {boolean} [monospace=false]
3895 * Specifies whether a monospace font should be forced for the textarea
3896 * contents.
3897 *
3898 * @property {number} [cols]
3899 * Specifies the HTML `cols` attribute to set on the corresponding
3900 * `&lt;textarea>` element.
3901 *
3902 * @property {number} [rows]
3903 * Specifies the HTML `rows` attribute to set on the corresponding
3904 * `&lt;textarea>` element.
3905 *
3906 * @property {boolean} [wrap=false]
3907 * Specifies whether the HTML `wrap` attribute should be set.
3908 */
3909 __init__: function(value, options) {
3910 this.value = value;
3911 this.options = Object.assign({
3912 optional: true,
3913 wrap: false,
3914 cols: null,
3915 rows: null
3916 }, options);
3917 },
3918
3919 /** @override */
3920 render: function() {
3921 var style = !this.options.cols ? 'width:100%' : null,
3922 frameEl = E('div', { 'id': this.options.id, 'style': style }),
3923 value = (this.value != null) ? String(this.value) : '';
3924
3925 frameEl.appendChild(E('textarea', {
3926 'id': this.options.id ? 'widget.' + this.options.id : null,
3927 'name': this.options.name,
3928 'class': 'cbi-input-textarea',
3929 'readonly': this.options.readonly ? '' : null,
3930 'disabled': this.options.disabled ? '' : null,
3931 'placeholder': this.options.placeholder,
3932 'style': style,
3933 'cols': this.options.cols,
3934 'rows': this.options.rows,
3935 'wrap': this.options.wrap ? '' : null
3936 }, [ value ]));
3937
3938 if (this.options.monospace)
3939 frameEl.firstElementChild.style.fontFamily = 'monospace';
3940
3941 return this.bind(frameEl);
3942 },
3943
3944 /** @private */
3945 bind: function(frameEl) {
3946 var inputEl = frameEl.firstElementChild;
3947
3948 this.node = frameEl;
3949
3950 this.setUpdateEvents(inputEl, 'keyup', 'blur');
3951 this.setChangeEvents(inputEl, 'change');
3952
3953 dom.bindClassInstance(frameEl, this);
3954
3955 return frameEl;
3956 },
3957
3958 /** @override */
3959 getValue: function() {
3960 return this.node.firstElementChild.value;
3961 },
3962
3963 /** @override */
3964 setValue: function(value) {
3965 this.node.firstElementChild.value = value;
3966 }
3967 });
3968
3969 /**
3970 * Instantiate a checkbox widget.
3971 *
3972 * @constructor Checkbox
3973 * @memberof LuCI.ui
3974 * @augments LuCI.ui.AbstractElement
3975 *
3976 * @classdesc
3977 *
3978 * The `Checkbox` class implements a simple checkbox input field.
3979 *
3980 * UI widget instances are usually not supposed to be created by view code
3981 * directly, instead they're implicitely created by `LuCI.form` when
3982 * instantiating CBI forms.
3983 *
3984 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3985 * in views, use `'require ui'` and refer to `ui.Checkbox`. To import it in
3986 * external JavaScript, use `L.require("ui").then(...)` and access the
3987 * `Checkbox` property of the class instance value.
3988 *
3989 * @param {string} [value=null]
3990 * The initial input value.
3991 *
3992 * @param {LuCI.ui.Checkbox.InitOptions} [options]
3993 * Object describing the widget specific options to initialize the input.
3994 */
3995 var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ {
3996 /**
3997 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3998 * the following properties are recognized:
3999 *
4000 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4001 * @memberof LuCI.ui.Checkbox
4002 *
4003 * @property {string} [value_enabled=1]
4004 * Specifies the value corresponding to a checked checkbox.
4005 *
4006 * @property {string} [value_disabled=0]
4007 * Specifies the value corresponding to an unchecked checkbox.
4008 *
4009 * @property {string} [hiddenname]
4010 * Specifies the HTML `name` attribute of the hidden input backing the
4011 * checkbox. This is a legacy property existing for compatibility reasons,
4012 * it is required for HTML based form submissions.
4013 */
4014 __init__: function(value, options) {
4015 this.value = value;
4016 this.options = Object.assign({
4017 value_enabled: '1',
4018 value_disabled: '0'
4019 }, options);
4020 },
4021
4022 /** @override */
4023 render: function() {
4024 var id = 'cb%08x'.format(Math.random() * 0xffffffff);
4025 var frameEl = E('div', {
4026 'id': this.options.id,
4027 'class': 'cbi-checkbox'
4028 });
4029
4030 if (this.options.hiddenname)
4031 frameEl.appendChild(E('input', {
4032 'type': 'hidden',
4033 'name': this.options.hiddenname,
4034 'value': 1
4035 }));
4036
4037 frameEl.appendChild(E('input', {
4038 'id': id,
4039 'name': this.options.name,
4040 'type': 'checkbox',
4041 'value': this.options.value_enabled,
4042 'checked': (this.value == this.options.value_enabled) ? '' : null,
4043 'disabled': this.options.disabled ? '' : null,
4044 'data-widget-id': this.options.id ? 'widget.' + this.options.id : null
4045 }));
4046
4047 frameEl.appendChild(E('label', { 'for': id }));
4048
4049 return this.bind(frameEl);
4050 },
4051
4052 /** @private */
4053 bind: function(frameEl) {
4054 this.node = frameEl;
4055
4056 this.setUpdateEvents(frameEl.lastElementChild.previousElementSibling, 'click', 'blur');
4057 this.setChangeEvents(frameEl.lastElementChild.previousElementSibling, 'change');
4058
4059 dom.bindClassInstance(frameEl, this);
4060
4061 return frameEl;
4062 },
4063
4064 /**
4065 * Test whether the checkbox is currently checked.
4066 *
4067 * @instance
4068 * @memberof LuCI.ui.Checkbox
4069 * @returns {boolean}
4070 * Returns `true` when the checkbox is currently checked, otherwise `false`.
4071 */
4072 isChecked: function() {
4073 return this.node.lastElementChild.previousElementSibling.checked;
4074 },
4075
4076 /** @override */
4077 getValue: function() {
4078 return this.isChecked()
4079 ? this.options.value_enabled
4080 : this.options.value_disabled;
4081 },
4082
4083 /** @override */
4084 setValue: function(value) {
4085 this.node.lastElementChild.previousElementSibling.checked = (value == this.options.value_enabled);
4086 }
4087 });
4088
4089 /**
4090 * Instantiate a select dropdown or checkbox/radiobutton group.
4091 *
4092 * @constructor Select
4093 * @memberof LuCI.ui
4094 * @augments LuCI.ui.AbstractElement
4095 *
4096 * @classdesc
4097 *
4098 * The `Select` class implements either a traditional HTML `&lt;select>` element
4099 * or a group of checkboxes or radio buttons, depending on whether multiple
4100 * values are enabled or not.
4101 *
4102 * UI widget instances are usually not supposed to be created by view code
4103 * directly, instead they're implicitely created by `LuCI.form` when
4104 * instantiating CBI forms.
4105 *
4106 * This class is automatically instantiated as part of `LuCI.ui`. To use it
4107 * in views, use `'require ui'` and refer to `ui.Select`. To import it in
4108 * external JavaScript, use `L.require("ui").then(...)` and access the
4109 * `Select` property of the class instance value.
4110 *
4111 * @param {string|string[]} [value=null]
4112 * The initial input value(s).
4113 *
4114 * @param {Object&lt;string, string>} choices
4115 * Object containing the selectable choices of the widget. The object keys
4116 * serve as values for the different choices while the values are used as
4117 * choice labels.
4118 *
4119 * @param {LuCI.ui.Select.InitOptions} [options]
4120 * Object describing the widget specific options to initialize the inputs.
4121 */
4122 var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ {
4123 /**
4124 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
4125 * the following properties are recognized:
4126 *
4127 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4128 * @memberof LuCI.ui.Select
4129 *
4130 * @property {boolean} [multiple=false]
4131 * Specifies whether multiple choice values may be selected.
4132 *
4133 * @property {string} [widget=select]
4134 * Specifies the kind of widget to render. May be either `select` or
4135 * `individual`. When set to `select` an HTML `&lt;select>` element will be
4136 * used, otherwise a group of checkbox or radio button elements is created,
4137 * depending on the value of the `multiple` option.
4138 *
4139 * @property {string} [orientation=horizontal]
4140 * Specifies whether checkbox / radio button groups should be rendered
4141 * in a `horizontal` or `vertical` manner. Does not apply to the `select`
4142 * widget type.
4143 *
4144 * @property {boolean|string[]} [sort=false]
4145 * Specifies if and how to sort choice values. If set to `true`, the choice
4146 * values will be sorted alphabetically. If set to an array of strings, the
4147 * choice sort order is derived from the array.
4148 *
4149 * @property {number} [size]
4150 * Specifies the HTML `size` attribute to set on the `&lt;select>` element.
4151 * Only applicable to the `select` widget type.
4152 *
4153 * @property {string} [placeholder=-- Please choose --]
4154 * Specifies a placeholder text which is displayed when no choice is
4155 * selected yet. Only applicable to the `select` widget type.
4156 */
4157 __init__: function(value, choices, options) {
4158 if (!L.isObject(choices))
4159 choices = {};
4160
4161 if (!Array.isArray(value))
4162 value = (value != null &amp;&amp; value != '') ? [ value ] : [];
4163
4164 if (!options.multiple &amp;&amp; value.length > 1)
4165 value.length = 1;
4166
4167 this.values = value;
4168 this.choices = choices;
4169 this.options = Object.assign({
4170 multiple: false,
4171 widget: 'select',
4172 orientation: 'horizontal'
4173 }, options);
4174
4175 if (this.choices.hasOwnProperty(''))
4176 this.options.optional = true;
4177 },
4178
4179 /** @override */
4180 render: function() {
4181 var frameEl = E('div', { 'id': this.options.id }),
4182 keys = Object.keys(this.choices);
4183
4184 if (this.options.sort === true)
4185 keys.sort();
4186 else if (Array.isArray(this.options.sort))
4187 keys = this.options.sort;
4188
4189 if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox') {
4190 frameEl.appendChild(E('select', {
4191 'id': this.options.id ? 'widget.' + this.options.id : null,
4192 'name': this.options.name,
4193 'size': this.options.size,
4194 'class': 'cbi-input-select',
4195 'multiple': this.options.multiple ? '' : null,
4196 'disabled': this.options.disabled ? '' : null
4197 }));
4198
4199 if (this.options.optional)
4200 frameEl.lastChild.appendChild(E('option', {
4201 'value': '',
4202 'selected': (this.values.length == 0 || this.values[0] == '') ? '' : null
4203 }, [ this.choices[''] || this.options.placeholder || _('-- Please choose --') ]));
4204
4205 for (var i = 0; i &lt; keys.length; i++) {
4206 if (keys[i] == null || keys[i] == '')
4207 continue;
4208
4209 frameEl.lastChild.appendChild(E('option', {
4210 'value': keys[i],
4211 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
4212 }, [ this.choices[keys[i]] || keys[i] ]));
4213 }
4214 }
4215 else {
4216 var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' \xa0 ') : E('br');
4217
4218 for (var i = 0; i &lt; keys.length; i++) {
4219 frameEl.appendChild(E('span', {
4220 'class': 'cbi-%s'.format(this.options.multiple ? 'checkbox' : 'radio')
4221 }, [
4222 E('input', {
4223 'id': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null,
4224 'name': this.options.id || this.options.name,
4225 'type': this.options.multiple ? 'checkbox' : 'radio',
4226 'class': this.options.multiple ? 'cbi-input-checkbox' : 'cbi-input-radio',
4227 'value': keys[i],
4228 'checked': (this.values.indexOf(keys[i]) > -1) ? '' : null,
4229 'disabled': this.options.disabled ? '' : null
4230 }),
4231 E('label', { 'for': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null }),
4232 E('span', {
4233 'click': function(ev) {
4234 ev.currentTarget.previousElementSibling.previousElementSibling.click();
4235 }
4236 }, [ this.choices[keys[i]] || keys[i] ])
4237 ]));
4238
4239 frameEl.appendChild(brEl.cloneNode());
4240 }
4241 }
4242
4243 return this.bind(frameEl);
4244 },
4245
4246 /** @private */
4247 bind: function(frameEl) {
4248 this.node = frameEl;
4249
4250 if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox') {
4251 this.setUpdateEvents(frameEl.firstChild, 'change', 'click', 'blur');
4252 this.setChangeEvents(frameEl.firstChild, 'change');
4253 }
4254 else {
4255 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
4256 for (var i = 0; i &lt; radioEls.length; i++) {
4257 this.setUpdateEvents(radioEls[i], 'change', 'click', 'blur');
4258 this.setChangeEvents(radioEls[i], 'change', 'click', 'blur');
4259 }
4260 }
4261
4262 dom.bindClassInstance(frameEl, this);
4263
4264 return frameEl;
4265 },
4266
4267 /** @override */
4268 getValue: function() {
4269 if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox')
4270 return this.node.firstChild.value;
4271
4272 var radioEls = this.node.querySelectorAll('input[type="radio"]');
4273 for (var i = 0; i &lt; radioEls.length; i++)
4274 if (radioEls[i].checked)
4275 return radioEls[i].value;
4276
4277 return null;
4278 },
4279
4280 /** @override */
4281 setValue: function(value) {
4282 if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox') {
4283 if (value == null)
4284 value = '';
4285
4286 for (var i = 0; i &lt; this.node.firstChild.options.length; i++)
4287 this.node.firstChild.options[i].selected = (this.node.firstChild.options[i].value == value);
4288
4289 return;
4290 }
4291
4292 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
4293 for (var i = 0; i &lt; radioEls.length; i++)
4294 radioEls[i].checked = (radioEls[i].value == value);
4295 }
4296 });
4297
4298 /**
4299 * Instantiate a rich dropdown choice widget.
4300 *
4301 * @constructor Dropdown
4302 * @memberof LuCI.ui
4303 * @augments LuCI.ui.AbstractElement
4304 *
4305 * @classdesc
4306 *
4307 * The `Dropdown` class implements a rich, stylable dropdown menu which
4308 * supports non-text choice labels.
4309 *
4310 * UI widget instances are usually not supposed to be created by view code
4311 * directly, instead they're implicitely created by `LuCI.form` when
4312 * instantiating CBI forms.
4313 *
4314 * This class is automatically instantiated as part of `LuCI.ui`. To use it
4315 * in views, use `'require ui'` and refer to `ui.Dropdown`. To import it in
4316 * external JavaScript, use `L.require("ui").then(...)` and access the
4317 * `Dropdown` property of the class instance value.
4318 *
4319 * @param {string|string[]} [value=null]
4320 * The initial input value(s).
4321 *
4322 * @param {Object&lt;string, *>} choices
4323 * Object containing the selectable choices of the widget. The object keys
4324 * serve as values for the different choices while the values are used as
4325 * choice labels.
4326 *
4327 * @param {LuCI.ui.Dropdown.InitOptions} [options]
4328 * Object describing the widget specific options to initialize the dropdown.
4329 */
4330 var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
4331 /**
4332 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
4333 * the following properties are recognized:
4334 *
4335 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4336 * @memberof LuCI.ui.Dropdown
4337 *
4338 * @property {boolean} [optional=true]
4339 * Specifies whether the dropdown selection is optional. In contrast to
4340 * other widgets, the `optional` constraint of dropdowns works differently;
4341 * instead of marking the widget invalid on empty values when set to `false`,
4342 * the user is not allowed to deselect all choices.
4343 *
4344 * For single value dropdowns that means that no empty "please select"
4345 * choice is offered and for multi value dropdowns, the last selected choice
4346 * may not be deselected without selecting another choice first.
4347 *
4348 * @property {boolean} [multiple]
4349 * Specifies whether multiple choice values may be selected. It defaults
4350 * to `true` when an array is passed as input value to the constructor.
4351 *
4352 * @property {boolean|string[]} [sort=false]
4353 * Specifies if and how to sort choice values. If set to `true`, the choice
4354 * values will be sorted alphabetically. If set to an array of strings, the
4355 * choice sort order is derived from the array.
4356 *
4357 * @property {string} [select_placeholder=-- Please choose --]
4358 * Specifies a placeholder text which is displayed when no choice is
4359 * selected yet.
4360 *
4361 * @property {string} [custom_placeholder=-- custom --]
4362 * Specifies a placeholder text which is displayed in the text input
4363 * field allowing to enter custom choice values. Only applicable if the
4364 * `create` option is set to `true`.
4365 *
4366 * @property {boolean} [create=false]
4367 * Specifies whether custom choices may be entered into the dropdown
4368 * widget.
4369 *
4370 * @property {string} [create_query=.create-item-input]
4371 * Specifies a CSS selector expression used to find the input element
4372 * which is used to enter custom choice values. This should not normally
4373 * be used except by widgets derived from the Dropdown class.
4374 *
4375 * @property {string} [create_template=script[type="item-template"]]
4376 * Specifies a CSS selector expression used to find an HTML element
4377 * serving as template for newly added custom choice values.
4378 *
4379 * Any `{{value}}` placeholder string within the template elements text
4380 * content will be replaced by the user supplied choice value, the
4381 * resulting string is parsed as HTML and appended to the end of the
4382 * choice list. The template markup may specify one HTML element with a
4383 * `data-label-placeholder` attribute which is replaced by a matching
4384 * label value from the `choices` object or with the user supplied value
4385 * itself in case `choices` contains no matching choice label.
4386 *
4387 * If the template element is not found or if no `create_template` selector
4388 * expression is specified, the default markup for newly created elements is
4389 * `&lt;li data-value="{{value}}">&lt;span data-label-placeholder="true" />&lt;/li>`.
4390 *
4391 * @property {string} [create_markup]
4392 * This property allows specifying the markup for custom choices directly
4393 * instead of referring to a template element through CSS selectors.
4394 *
4395 * Apart from that it works exactly like `create_template`.
4396 *
4397 * @property {number} [display_items=3]
4398 * Specifies the maximum amount of choice labels that should be shown in
4399 * collapsed dropdown state before further selected choices are cut off.
4400 *
4401 * Only applicable when `multiple` is `true`.
4402 *
4403 * @property {number} [dropdown_items=-1]
4404 * Specifies the maximum amount of choices that should be shown when the
4405 * dropdown is open. If the amount of available choices exceeds this number,
4406 * the dropdown area must be scrolled to reach further items.
4407 *
4408 * If set to `-1`, the dropdown menu will attempt to show all choice values
4409 * and only resort to scrolling if the amount of choices exceeds the available
4410 * screen space above and below the dropdown widget.
4411 *
4412 * @property {string} [placeholder]
4413 * This property serves as a shortcut to set both `select_placeholder` and
4414 * `custom_placeholder`. Either of these properties will fallback to
4415 * `placeholder` if not specified.
4416 *
4417 * @property {boolean} [readonly=false]
4418 * Specifies whether the custom choice input field should be rendered
4419 * readonly. Only applicable when `create` is `true`.
4420 *
4421 * @property {number} [maxlength]
4422 * Specifies the HTML `maxlength` attribute to set on the custom choice
4423 * `&lt;input>` element. Note that this a legacy property that exists for
4424 * compatibility reasons. It is usually better to `maxlength(N)` validation
4425 * expression. Only applicable when `create` is `true`.
4426 */
4427 __init__: function(value, choices, options) {
4428 if (typeof(choices) != 'object')
4429 choices = {};
4430
4431 if (!Array.isArray(value))
4432 this.values = (value != null &amp;&amp; value != '') ? [ value ] : [];
4433 else
4434 this.values = value;
4435
4436 this.choices = choices;
4437 this.options = Object.assign({
4438 sort: true,
4439 multiple: Array.isArray(value),
4440 optional: true,
4441 select_placeholder: _('-- Please choose --'),
4442 custom_placeholder: _('-- custom --'),
4443 display_items: 3,
4444 dropdown_items: -1,
4445 create: false,
4446 create_query: '.create-item-input',
4447 create_template: 'script[type="item-template"]'
4448 }, options);
4449 },
4450
4451 /** @override */
4452 render: function() {
4453 var sb = E('div', {
4454 'id': this.options.id,
4455 'class': 'cbi-dropdown',
4456 'multiple': this.options.multiple ? '' : null,
4457 'optional': this.options.optional ? '' : null,
4458 'disabled': this.options.disabled ? '' : null
4459 }, E('ul'));
4460
4461 var keys = Object.keys(this.choices);
4462
4463 if (this.options.sort === true)
4464 keys.sort();
4465 else if (Array.isArray(this.options.sort))
4466 keys = this.options.sort;
4467
4468 if (this.options.create)
4469 for (var i = 0; i &lt; this.values.length; i++)
4470 if (!this.choices.hasOwnProperty(this.values[i]))
4471 keys.push(this.values[i]);
4472
4473 for (var i = 0; i &lt; keys.length; i++) {
4474 var label = this.choices[keys[i]];
4475
4476 if (dom.elem(label))
4477 label = label.cloneNode(true);
4478
4479 sb.lastElementChild.appendChild(E('li', {
4480 'data-value': keys[i],
4481 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
4482 }, [ label || keys[i] ]));
4483 }
4484
4485 if (this.options.create) {
4486 var createEl = E('input', {
4487 'type': 'text',
4488 'class': 'create-item-input',
4489 'readonly': this.options.readonly ? '' : null,
4490 'maxlength': this.options.maxlength,
4491 'placeholder': this.options.custom_placeholder || this.options.placeholder
4492 });
4493
4494 if (this.options.datatype || this.options.validate)
4495 UI.prototype.addValidator(createEl, this.options.datatype || 'string',
4496 true, this.options.validate, 'blur', 'keyup');
4497
4498 sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl));
4499 }
4500
4501 if (this.options.create_markup)
4502 sb.appendChild(E('script', { type: 'item-template' },
4503 this.options.create_markup));
4504
4505 return this.bind(sb);
4506 },
4507
4508 /** @private */
4509 bind: function(sb) {
4510 var o = this.options;
4511
4512 o.multiple = sb.hasAttribute('multiple');
4513 o.optional = sb.hasAttribute('optional');
4514 o.placeholder = sb.getAttribute('placeholder') || o.placeholder;
4515 o.display_items = parseInt(sb.getAttribute('display-items') || o.display_items);
4516 o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') || o.dropdown_items);
4517 o.create_query = sb.getAttribute('item-create') || o.create_query;
4518 o.create_template = sb.getAttribute('item-template') || o.create_template;
4519
4520 var ul = sb.querySelector('ul'),
4521 more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')),
4522 open = sb.appendChild(E('span', { class: 'open', tabindex: -1 }, '▾')),
4523 canary = sb.appendChild(E('div')),
4524 create = sb.querySelector(this.options.create_query),
4525 ndisplay = this.options.display_items,
4526 n = 0;
4527
4528 if (this.options.multiple) {
4529 var items = ul.querySelectorAll('li');
4530
4531 for (var i = 0; i &lt; items.length; i++) {
4532 this.transformItem(sb, items[i]);
4533
4534 if (items[i].hasAttribute('selected') &amp;&amp; ndisplay-- > 0)
4535 items[i].setAttribute('display', n++);
4536 }
4537 }
4538 else {
4539 if (this.options.optional &amp;&amp; !ul.querySelector('li[data-value=""]')) {
4540 var placeholder = E('li', { placeholder: '' },
4541 this.options.select_placeholder || this.options.placeholder);
4542
4543 ul.firstChild
4544 ? ul.insertBefore(placeholder, ul.firstChild)
4545 : ul.appendChild(placeholder);
4546 }
4547
4548 var items = ul.querySelectorAll('li'),
4549 sel = sb.querySelectorAll('[selected]');
4550
4551 sel.forEach(function(s) {
4552 s.removeAttribute('selected');
4553 });
4554
4555 var s = sel[0] || items[0];
4556 if (s) {
4557 s.setAttribute('selected', '');
4558 s.setAttribute('display', n++);
4559 }
4560
4561 ndisplay--;
4562 }
4563
4564 this.saveValues(sb, ul);
4565
4566 ul.setAttribute('tabindex', -1);
4567 sb.setAttribute('tabindex', 0);
4568
4569 if (ndisplay &lt; 0)
4570 sb.setAttribute('more', '')
4571 else
4572 sb.removeAttribute('more');
4573
4574 if (ndisplay == this.options.display_items)
4575 sb.setAttribute('empty', '')
4576 else
4577 sb.removeAttribute('empty');
4578
4579 dom.content(more, (ndisplay == this.options.display_items)
4580 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4581
4582
4583 sb.addEventListener('click', this.handleClick.bind(this));
4584 sb.addEventListener('keydown', this.handleKeydown.bind(this));
4585 sb.addEventListener('cbi-dropdown-close', this.handleDropdownClose.bind(this));
4586 sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this));
4587
4588 if ('ontouchstart' in window) {
4589 sb.addEventListener('touchstart', function(ev) { ev.stopPropagation(); });
4590 window.addEventListener('touchstart', this.closeAllDropdowns);
4591 }
4592 else {
4593 sb.addEventListener('mouseover', this.handleMouseover.bind(this));
4594 sb.addEventListener('focus', this.handleFocus.bind(this));
4595
4596 canary.addEventListener('focus', this.handleCanaryFocus.bind(this));
4597
4598 window.addEventListener('mouseover', this.setFocus);
4599 window.addEventListener('click', this.closeAllDropdowns);
4600 }
4601
4602 if (create) {
4603 create.addEventListener('keydown', this.handleCreateKeydown.bind(this));
4604 create.addEventListener('focus', this.handleCreateFocus.bind(this));
4605 create.addEventListener('blur', this.handleCreateBlur.bind(this));
4606
4607 var li = findParent(create, 'li');
4608
4609 li.setAttribute('unselectable', '');
4610 li.addEventListener('click', this.handleCreateClick.bind(this));
4611 }
4612
4613 this.node = sb;
4614
4615 this.setUpdateEvents(sb, 'cbi-dropdown-open', 'cbi-dropdown-close');
4616 this.setChangeEvents(sb, 'cbi-dropdown-change', 'cbi-dropdown-close');
4617
4618 dom.bindClassInstance(sb, this);
4619
4620 return sb;
4621 },
4622
4623 /** @private */
4624 openDropdown: function(sb) {
4625 var st = window.getComputedStyle(sb, null),
4626 ul = sb.querySelector('ul'),
4627 li = ul.querySelectorAll('li'),
4628 fl = findParent(sb, '.cbi-value-field'),
4629 sel = ul.querySelector('[selected]'),
4630 rect = sb.getBoundingClientRect(),
4631 items = Math.min(this.options.dropdown_items, li.length);
4632
4633 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
4634 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
4635 });
4636
4637 sb.setAttribute('open', '');
4638
4639 var pv = ul.cloneNode(true);
4640 pv.classList.add('preview');
4641
4642 if (fl)
4643 fl.classList.add('cbi-dropdown-open');
4644
4645 if ('ontouchstart' in window) {
4646 var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
4647 vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
4648 start = null;
4649
4650 ul.style.top = sb.offsetHeight + 'px';
4651 ul.style.left = -rect.left + 'px';
4652 ul.style.right = (rect.right - vpWidth) + 'px';
4653 ul.style.maxHeight = (vpHeight * 0.5) + 'px';
4654 ul.style.WebkitOverflowScrolling = 'touch';
4655
4656 var getScrollParent = function(element) {
4657 var parent = element,
4658 style = getComputedStyle(element),
4659 excludeStaticParent = (style.position === 'absolute');
4660
4661 if (style.position === 'fixed')
4662 return document.body;
4663
4664 while ((parent = parent.parentElement) != null) {
4665 style = getComputedStyle(parent);
4666
4667 if (excludeStaticParent &amp;&amp; style.position === 'static')
4668 continue;
4669
4670 if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX))
4671 return parent;
4672 }
4673
4674 return document.body;
4675 }
4676
4677 var scrollParent = getScrollParent(sb),
4678 scrollFrom = scrollParent.scrollTop,
4679 scrollTo = scrollFrom + rect.top - vpHeight * 0.5;
4680
4681 var scrollStep = function(timestamp) {
4682 if (!start) {
4683 start = timestamp;
4684 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
4685 }
4686
4687 var duration = Math.max(timestamp - start, 1);
4688 if (duration &lt; 100) {
4689 scrollParent.scrollTop = scrollFrom + (scrollTo - scrollFrom) * (duration / 100);
4690 window.requestAnimationFrame(scrollStep);
4691 }
4692 else {
4693 scrollParent.scrollTop = scrollTo;
4694 }
4695 };
4696
4697 window.requestAnimationFrame(scrollStep);
4698 }
4699 else {
4700 ul.style.maxHeight = '1px';
4701 ul.style.top = ul.style.bottom = '';
4702
4703 window.requestAnimationFrame(function() {
4704 var itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height,
4705 fullHeight = 0,
4706 spaceAbove = rect.top,
4707 spaceBelow = window.innerHeight - rect.height - rect.top;
4708
4709 for (var i = 0; i &lt; (items == -1 ? li.length : items); i++)
4710 fullHeight += li[i].getBoundingClientRect().height;
4711
4712 if (fullHeight &lt;= spaceBelow) {
4713 ul.style.top = rect.height + 'px';
4714 ul.style.maxHeight = spaceBelow + 'px';
4715 }
4716 else if (fullHeight &lt;= spaceAbove) {
4717 ul.style.bottom = rect.height + 'px';
4718 ul.style.maxHeight = spaceAbove + 'px';
4719 }
4720 else if (spaceBelow >= spaceAbove) {
4721 ul.style.top = rect.height + 'px';
4722 ul.style.maxHeight = (spaceBelow - (spaceBelow % itemHeight)) + 'px';
4723 }
4724 else {
4725 ul.style.bottom = rect.height + 'px';
4726 ul.style.maxHeight = (spaceAbove - (spaceAbove % itemHeight)) + 'px';
4727 }
4728
4729 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
4730 });
4731 }
4732
4733 var cboxes = ul.querySelectorAll('[selected] input[type="checkbox"]');
4734 for (var i = 0; i &lt; cboxes.length; i++) {
4735 cboxes[i].checked = true;
4736 cboxes[i].disabled = (cboxes.length == 1 &amp;&amp; !this.options.optional);
4737 };
4738
4739 ul.classList.add('dropdown');
4740
4741 sb.insertBefore(pv, ul.nextElementSibling);
4742
4743 li.forEach(function(l) {
4744 l.setAttribute('tabindex', 0);
4745 });
4746
4747 sb.lastElementChild.setAttribute('tabindex', 0);
4748
4749 this.setFocus(sb, sel || li[0], true);
4750 },
4751
4752 /** @private */
4753 closeDropdown: function(sb, no_focus) {
4754 if (!sb.hasAttribute('open'))
4755 return;
4756
4757 var pv = sb.querySelector('ul.preview'),
4758 ul = sb.querySelector('ul.dropdown'),
4759 li = ul.querySelectorAll('li'),
4760 fl = findParent(sb, '.cbi-value-field');
4761
4762 li.forEach(function(l) { l.removeAttribute('tabindex'); });
4763 sb.lastElementChild.removeAttribute('tabindex');
4764
4765 sb.removeChild(pv);
4766 sb.removeAttribute('open');
4767 sb.style.width = sb.style.height = '';
4768
4769 ul.classList.remove('dropdown');
4770 ul.style.top = ul.style.bottom = ul.style.maxHeight = '';
4771
4772 if (fl)
4773 fl.classList.remove('cbi-dropdown-open');
4774
4775 if (!no_focus)
4776 this.setFocus(sb, sb);
4777
4778 this.saveValues(sb, ul);
4779 },
4780
4781 /** @private */
4782 toggleItem: function(sb, li, force_state) {
4783 if (li.hasAttribute('unselectable'))
4784 return;
4785
4786 if (this.options.multiple) {
4787 var cbox = li.querySelector('input[type="checkbox"]'),
4788 items = li.parentNode.querySelectorAll('li'),
4789 label = sb.querySelector('ul.preview'),
4790 sel = li.parentNode.querySelectorAll('[selected]').length,
4791 more = sb.querySelector('.more'),
4792 ndisplay = this.options.display_items,
4793 n = 0;
4794
4795 if (li.hasAttribute('selected')) {
4796 if (force_state !== true) {
4797 if (sel > 1 || this.options.optional) {
4798 li.removeAttribute('selected');
4799 cbox.checked = cbox.disabled = false;
4800 sel--;
4801 }
4802 else {
4803 cbox.disabled = true;
4804 }
4805 }
4806 }
4807 else {
4808 if (force_state !== false) {
4809 li.setAttribute('selected', '');
4810 cbox.checked = true;
4811 cbox.disabled = false;
4812 sel++;
4813 }
4814 }
4815
4816 while (label &amp;&amp; label.firstElementChild)
4817 label.removeChild(label.firstElementChild);
4818
4819 for (var i = 0; i &lt; items.length; i++) {
4820 items[i].removeAttribute('display');
4821 if (items[i].hasAttribute('selected')) {
4822 if (ndisplay-- > 0) {
4823 items[i].setAttribute('display', n++);
4824 if (label)
4825 label.appendChild(items[i].cloneNode(true));
4826 }
4827 var c = items[i].querySelector('input[type="checkbox"]');
4828 if (c)
4829 c.disabled = (sel == 1 &amp;&amp; !this.options.optional);
4830 }
4831 }
4832
4833 if (ndisplay &lt; 0)
4834 sb.setAttribute('more', '');
4835 else
4836 sb.removeAttribute('more');
4837
4838 if (ndisplay === this.options.display_items)
4839 sb.setAttribute('empty', '');
4840 else
4841 sb.removeAttribute('empty');
4842
4843 dom.content(more, (ndisplay === this.options.display_items)
4844 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4845 }
4846 else {
4847 var sel = li.parentNode.querySelector('[selected]');
4848 if (sel) {
4849 sel.removeAttribute('display');
4850 sel.removeAttribute('selected');
4851 }
4852
4853 li.setAttribute('display', 0);
4854 li.setAttribute('selected', '');
4855
4856 this.closeDropdown(sb, true);
4857 }
4858
4859 this.saveValues(sb, li.parentNode);
4860 },
4861
4862 /** @private */
4863 transformItem: function(sb, li) {
4864 var cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -1, onclick: 'event.preventDefault()' })),
4865 label = E('label');
4866
4867 while (li.firstChild)
4868 label.appendChild(li.firstChild);
4869
4870 li.appendChild(cbox);
4871 li.appendChild(label);
4872 },
4873
4874 /** @private */
4875 saveValues: function(sb, ul) {
4876 var sel = ul.querySelectorAll('li[selected]'),
4877 div = sb.lastElementChild,
4878 name = this.options.name,
4879 strval = '',
4880 values = [];
4881
4882 while (div.lastElementChild)
4883 div.removeChild(div.lastElementChild);
4884
4885 sel.forEach(function (s) {
4886 if (s.hasAttribute('placeholder'))
4887 return;
4888
4889 var v = {
4890 text: s.innerText,
4891 value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText,
4892 element: s
4893 };
4894
4895 div.appendChild(E('input', {
4896 type: 'hidden',
4897 name: name,
4898 value: v.value
4899 }));
4900
4901 values.push(v);
4902
4903 strval += strval.length ? ' ' + v.value : v.value;
4904 });
4905
4906 var detail = {
4907 instance: this,
4908 element: sb
4909 };
4910
4911 if (this.options.multiple)
4912 detail.values = values;
4913 else
4914 detail.value = values.length ? values[0] : null;
4915
4916 sb.value = strval;
4917
4918 sb.dispatchEvent(new CustomEvent('cbi-dropdown-change', {
4919 bubbles: true,
4920 detail: detail
4921 }));
4922 },
4923
4924 /** @private */
4925 setValues: function(sb, values) {
4926 var ul = sb.querySelector('ul');
4927
4928 if (this.options.create) {
4929 for (var value in values) {
4930 this.createItems(sb, value);
4931
4932 if (!this.options.multiple)
4933 break;
4934 }
4935 }
4936
4937 if (this.options.multiple) {
4938 var lis = ul.querySelectorAll('li[data-value]');
4939 for (var i = 0; i &lt; lis.length; i++) {
4940 var value = lis[i].getAttribute('data-value');
4941 if (values === null || !(value in values))
4942 this.toggleItem(sb, lis[i], false);
4943 else
4944 this.toggleItem(sb, lis[i], true);
4945 }
4946 }
4947 else {
4948 var ph = ul.querySelector('li[placeholder]');
4949 if (ph)
4950 this.toggleItem(sb, ph);
4951
4952 var lis = ul.querySelectorAll('li[data-value]');
4953 for (var i = 0; i &lt; lis.length; i++) {
4954 var value = lis[i].getAttribute('data-value');
4955 if (values !== null &amp;&amp; (value in values))
4956 this.toggleItem(sb, lis[i]);
4957 }
4958 }
4959 },
4960
4961 /** @private */
4962 setFocus: function(sb, elem, scroll) {
4963 if (sb &amp;&amp; sb.hasAttribute &amp;&amp; sb.hasAttribute('locked-in'))
4964 return;
4965
4966 if (sb.target &amp;&amp; findParent(sb.target, 'ul.dropdown'))
4967 return;
4968
4969 document.querySelectorAll('.focus').forEach(function(e) {
4970 if (!matchesElem(e, 'input')) {
4971 e.classList.remove('focus');
4972 e.blur();
4973 }
4974 });
4975
4976 if (elem) {
4977 elem.focus();
4978 elem.classList.add('focus');
4979
4980 if (scroll)
4981 elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop;
4982 }
4983 },
4984
4985 /** @private */
4986 createChoiceElement: function(sb, value, label) {
4987 var tpl = sb.querySelector(this.options.create_template),
4988 markup = null;
4989
4990 if (tpl)
4991 markup = (tpl.textContent || tpl.innerHTML || tpl.firstChild.data).replace(/^&lt;!--|-->$/, '').trim();
4992 else
4993 markup = '&lt;li data-value="{{value}}">&lt;span data-label-placeholder="true" />&lt;/li>';
4994
4995 var new_item = E(markup.replace(/{{value}}/g, '%h'.format(value))),
4996 placeholder = new_item.querySelector('[data-label-placeholder]');
4997
4998 if (placeholder) {
4999 var content = E('span', {}, label || this.choices[value] || [ value ]);
5000
5001 while (content.firstChild)
5002 placeholder.parentNode.insertBefore(content.firstChild, placeholder);
5003
5004 placeholder.parentNode.removeChild(placeholder);
5005 }
5006
5007 if (this.options.multiple)
5008 this.transformItem(sb, new_item);
5009
5010 return new_item;
5011 },
5012
5013 /** @private */
5014 createItems: function(sb, value) {
5015 var sbox = this,
5016 val = (value || '').trim(),
5017 ul = sb.querySelector('ul');
5018
5019 if (!sbox.options.multiple)
5020 val = val.length ? [ val ] : [];
5021 else
5022 val = val.length ? val.split(/\s+/) : [];
5023
5024 val.forEach(function(item) {
5025 var new_item = null;
5026
5027 ul.childNodes.forEach(function(li) {
5028 if (li.getAttribute &amp;&amp; li.getAttribute('data-value') === item)
5029 new_item = li;
5030 });
5031
5032 if (!new_item) {
5033 new_item = sbox.createChoiceElement(sb, item);
5034
5035 if (!sbox.options.multiple) {
5036 var old = ul.querySelector('li[created]');
5037 if (old)
5038 ul.removeChild(old);
5039
5040 new_item.setAttribute('created', '');
5041 }
5042
5043 new_item = ul.insertBefore(new_item, ul.lastElementChild);
5044 }
5045
5046 sbox.toggleItem(sb, new_item, true);
5047 sbox.setFocus(sb, new_item, true);
5048 });
5049 },
5050
5051 /**
5052 * Remove all existing choices from the dropdown menu.
5053 *
5054 * This function removes all preexisting dropdown choices from the widget,
5055 * keeping only choices currently being selected unless `reset_values` is
5056 * given, in which case all choices and deselected and removed.
5057 *
5058 * @instance
5059 * @memberof LuCI.ui.Dropdown
5060 * @param {boolean} [reset_value=false]
5061 * If set to `true`, deselect and remove selected choices as well instead
5062 * of keeping them.
5063 */
5064 clearChoices: function(reset_value) {
5065 var ul = this.node.querySelector('ul'),
5066 lis = ul ? ul.querySelectorAll('li[data-value]') : [],
5067 len = lis.length - (this.options.create ? 1 : 0),
5068 val = reset_value ? null : this.getValue();
5069
5070 for (var i = 0; i &lt; len; i++) {
5071 var lival = lis[i].getAttribute('data-value');
5072 if (val == null ||
5073 (!this.options.multiple &amp;&amp; val != lival) ||
5074 (this.options.multiple &amp;&amp; val.indexOf(lival) == -1))
5075 ul.removeChild(lis[i]);
5076 }
5077
5078 if (reset_value)
5079 this.setValues(this.node, {});
5080 },
5081
5082 /**
5083 * Add new choices to the dropdown menu.
5084 *
5085 * This function adds further choices to an existing dropdown menu,
5086 * ignoring choice values which are already present.
5087 *
5088 * @instance
5089 * @memberof LuCI.ui.Dropdown
5090 * @param {string[]} values
5091 * The choice values to add to the dropdown widget.
5092 *
5093 * @param {Object&lt;string, *>} labels
5094 * The choice label values to use when adding dropdown choices. If no
5095 * label is found for a particular choice value, the value itself is used
5096 * as label text. Choice labels may be any valid value accepted by
5097 * {@link LuCI.dom#content}.
5098 */
5099 addChoices: function(values, labels) {
5100 var sb = this.node,
5101 ul = sb.querySelector('ul'),
5102 lis = ul ? ul.querySelectorAll('li[data-value]') : [];
5103
5104 if (!Array.isArray(values))
5105 values = L.toArray(values);
5106
5107 if (!L.isObject(labels))
5108 labels = {};
5109
5110 for (var i = 0; i &lt; values.length; i++) {
5111 var found = false;
5112
5113 for (var j = 0; j &lt; lis.length; j++) {
5114 if (lis[j].getAttribute('data-value') === values[i]) {
5115 found = true;
5116 break;
5117 }
5118 }
5119
5120 if (found)
5121 continue;
5122
5123 ul.insertBefore(
5124 this.createChoiceElement(sb, values[i], labels[values[i]]),
5125 ul.lastElementChild);
5126 }
5127 },
5128
5129 /**
5130 * Close all open dropdown widgets in the current document.
5131 */
5132 closeAllDropdowns: function() {
5133 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
5134 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
5135 });
5136 },
5137
5138 /** @private */
5139 handleClick: function(ev) {
5140 var sb = ev.currentTarget;
5141
5142 if (!sb.hasAttribute('open')) {
5143 if (!matchesElem(ev.target, 'input'))
5144 this.openDropdown(sb);
5145 }
5146 else {
5147 var li = findParent(ev.target, 'li');
5148 if (li &amp;&amp; li.parentNode.classList.contains('dropdown'))
5149 this.toggleItem(sb, li);
5150 else if (li &amp;&amp; li.parentNode.classList.contains('preview'))
5151 this.closeDropdown(sb);
5152 else if (matchesElem(ev.target, 'span.open, span.more'))
5153 this.closeDropdown(sb);
5154 }
5155
5156 ev.preventDefault();
5157 ev.stopPropagation();
5158 },
5159
5160 /** @private */
5161 handleKeydown: function(ev) {
5162 var sb = ev.currentTarget;
5163
5164 if (matchesElem(ev.target, 'input'))
5165 return;
5166
5167 if (!sb.hasAttribute('open')) {
5168 switch (ev.keyCode) {
5169 case 37:
5170 case 38:
5171 case 39:
5172 case 40:
5173 this.openDropdown(sb);
5174 ev.preventDefault();
5175 }
5176 }
5177 else {
5178 var active = findParent(document.activeElement, 'li');
5179
5180 switch (ev.keyCode) {
5181 case 27:
5182 this.closeDropdown(sb);
5183 break;
5184
5185 case 13:
5186 if (active) {
5187 if (!active.hasAttribute('selected'))
5188 this.toggleItem(sb, active);
5189 this.closeDropdown(sb);
5190 ev.preventDefault();
5191 }
5192 break;
5193
5194 case 32:
5195 if (active) {
5196 this.toggleItem(sb, active);
5197 ev.preventDefault();
5198 }
5199 break;
5200
5201 case 38:
5202 if (active &amp;&amp; active.previousElementSibling) {
5203 this.setFocus(sb, active.previousElementSibling);
5204 ev.preventDefault();
5205 }
5206 break;
5207
5208 case 40:
5209 if (active &amp;&amp; active.nextElementSibling) {
5210 this.setFocus(sb, active.nextElementSibling);
5211 ev.preventDefault();
5212 }
5213 break;
5214 }
5215 }
5216 },
5217
5218 /** @private */
5219 handleDropdownClose: function(ev) {
5220 var sb = ev.currentTarget;
5221
5222 this.closeDropdown(sb, true);
5223 },
5224
5225 /** @private */
5226 handleDropdownSelect: function(ev) {
5227 var sb = ev.currentTarget,
5228 li = findParent(ev.target, 'li');
5229
5230 if (!li)
5231 return;
5232
5233 this.toggleItem(sb, li);
5234 this.closeDropdown(sb, true);
5235 },
5236
5237 /** @private */
5238 handleMouseover: function(ev) {
5239 var sb = ev.currentTarget;
5240
5241 if (!sb.hasAttribute('open'))
5242 return;
5243
5244 var li = findParent(ev.target, 'li');
5245
5246 if (li &amp;&amp; li.parentNode.classList.contains('dropdown'))
5247 this.setFocus(sb, li);
5248 },
5249
5250 /** @private */
5251 handleFocus: function(ev) {
5252 var sb = ev.currentTarget;
5253
5254 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
5255 if (s !== sb || sb.hasAttribute('open'))
5256 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
5257 });
5258 },
5259
5260 /** @private */
5261 handleCanaryFocus: function(ev) {
5262 this.closeDropdown(ev.currentTarget.parentNode);
5263 },
5264
5265 /** @private */
5266 handleCreateKeydown: function(ev) {
5267 var input = ev.currentTarget,
5268 sb = findParent(input, '.cbi-dropdown');
5269
5270 switch (ev.keyCode) {
5271 case 13:
5272 ev.preventDefault();
5273
5274 if (input.classList.contains('cbi-input-invalid'))
5275 return;
5276
5277 this.createItems(sb, input.value);
5278 input.value = '';
5279 input.blur();
5280 break;
5281 }
5282 },
5283
5284 /** @private */
5285 handleCreateFocus: function(ev) {
5286 var input = ev.currentTarget,
5287 cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'),
5288 sb = findParent(input, '.cbi-dropdown');
5289
5290 if (cbox)
5291 cbox.checked = true;
5292
5293 sb.setAttribute('locked-in', '');
5294 },
5295
5296 /** @private */
5297 handleCreateBlur: function(ev) {
5298 var input = ev.currentTarget,
5299 cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'),
5300 sb = findParent(input, '.cbi-dropdown');
5301
5302 if (cbox)
5303 cbox.checked = false;
5304
5305 sb.removeAttribute('locked-in');
5306 },
5307
5308 /** @private */
5309 handleCreateClick: function(ev) {
5310 ev.currentTarget.querySelector(this.options.create_query).focus();
5311 },
5312
5313 /** @override */
5314 setValue: function(values) {
5315 if (this.options.multiple) {
5316 if (!Array.isArray(values))
5317 values = (values != null &amp;&amp; values != '') ? [ values ] : [];
5318
5319 var v = {};
5320
5321 for (var i = 0; i &lt; values.length; i++)
5322 v[values[i]] = true;
5323
5324 this.setValues(this.node, v);
5325 }
5326 else {
5327 var v = {};
5328
5329 if (values != null) {
5330 if (Array.isArray(values))
5331 v[values[0]] = true;
5332 else
5333 v[values] = true;
5334 }
5335
5336 this.setValues(this.node, v);
5337 }
5338 },
5339
5340 /** @override */
5341 getValue: function() {
5342 var div = this.node.lastElementChild,
5343 h = div.querySelectorAll('input[type="hidden"]'),
5344 v = [];
5345
5346 for (var i = 0; i &lt; h.length; i++)
5347 v.push(h[i].value);
5348
5349 return this.options.multiple ? v : v[0];
5350 }
5351 });
5352
5353 /**
5354 * Instantiate a rich dropdown choice widget allowing custom values.
5355 *
5356 * @constructor Combobox
5357 * @memberof LuCI.ui
5358 * @augments LuCI.ui.Dropdown
5359 *
5360 * @classdesc
5361 *
5362 * The `Combobox` class implements a rich, stylable dropdown menu which allows
5363 * to enter custom values. Historically, comboboxes used to be a dedicated
5364 * widget type in LuCI but nowadays they are direct aliases of dropdown widgets
5365 * with a set of enforced default properties for easier instantiation.
5366 *
5367 * UI widget instances are usually not supposed to be created by view code
5368 * directly, instead they're implicitely created by `LuCI.form` when
5369 * instantiating CBI forms.
5370 *
5371 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5372 * in views, use `'require ui'` and refer to `ui.Combobox`. To import it in
5373 * external JavaScript, use `L.require("ui").then(...)` and access the
5374 * `Combobox` property of the class instance value.
5375 *
5376 * @param {string|string[]} [value=null]
5377 * The initial input value(s).
5378 *
5379 * @param {Object&lt;string, *>} choices
5380 * Object containing the selectable choices of the widget. The object keys
5381 * serve as values for the different choices while the values are used as
5382 * choice labels.
5383 *
5384 * @param {LuCI.ui.Combobox.InitOptions} [options]
5385 * Object describing the widget specific options to initialize the dropdown.
5386 */
5387 var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ {
5388 /**
5389 * Comboboxes support the same properties as
5390 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5391 * specific values for the following properties:
5392 *
5393 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5394 * @memberof LuCI.ui.Combobox
5395 *
5396 * @property {boolean} multiple=false
5397 * Since Comboboxes never allow selecting multiple values, this property
5398 * is forcibly set to `false`.
5399 *
5400 * @property {boolean} create=true
5401 * Since Comboboxes always allow custom choice values, this property is
5402 * forcibly set to `true`.
5403 *
5404 * @property {boolean} optional=true
5405 * Since Comboboxes are always optional, this property is forcibly set to
5406 * `true`.
5407 */
5408 __init__: function(value, choices, options) {
5409 this.super('__init__', [ value, choices, Object.assign({
5410 select_placeholder: _('-- Please choose --'),
5411 custom_placeholder: _('-- custom --'),
5412 dropdown_items: -1,
5413 sort: true
5414 }, options, {
5415 multiple: false,
5416 create: true,
5417 optional: true
5418 }) ]);
5419 }
5420 });
5421
5422 /**
5423 * Instantiate a combo button widget offering multiple action choices.
5424 *
5425 * @constructor ComboButton
5426 * @memberof LuCI.ui
5427 * @augments LuCI.ui.Dropdown
5428 *
5429 * @classdesc
5430 *
5431 * The `ComboButton` class implements a button element which can be expanded
5432 * into a dropdown to chose from a set of different action choices.
5433 *
5434 * UI widget instances are usually not supposed to be created by view code
5435 * directly, instead they're implicitely created by `LuCI.form` when
5436 * instantiating CBI forms.
5437 *
5438 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5439 * in views, use `'require ui'` and refer to `ui.ComboButton`. To import it in
5440 * external JavaScript, use `L.require("ui").then(...)` and access the
5441 * `ComboButton` property of the class instance value.
5442 *
5443 * @param {string|string[]} [value=null]
5444 * The initial input value(s).
5445 *
5446 * @param {Object&lt;string, *>} choices
5447 * Object containing the selectable choices of the widget. The object keys
5448 * serve as values for the different choices while the values are used as
5449 * choice labels.
5450 *
5451 * @param {LuCI.ui.ComboButton.InitOptions} [options]
5452 * Object describing the widget specific options to initialize the button.
5453 */
5454 var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype */ {
5455 /**
5456 * ComboButtons support the same properties as
5457 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5458 * specific values for some properties and add aditional button specific
5459 * properties.
5460 *
5461 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5462 * @memberof LuCI.ui.ComboButton
5463 *
5464 * @property {boolean} multiple=false
5465 * Since ComboButtons never allow selecting multiple actions, this property
5466 * is forcibly set to `false`.
5467 *
5468 * @property {boolean} create=false
5469 * Since ComboButtons never allow creating custom choices, this property
5470 * is forcibly set to `false`.
5471 *
5472 * @property {boolean} optional=false
5473 * Since ComboButtons must always select one action, this property is
5474 * forcibly set to `false`.
5475 *
5476 * @property {Object&lt;string, string>} [classes]
5477 * Specifies a mapping of choice values to CSS class names. If an action
5478 * choice is selected by the user and if a corresponding entry exists in
5479 * the `classes` object, the class names corresponding to the selected
5480 * value are set on the button element.
5481 *
5482 * This is useful to apply different button styles, such as colors, to the
5483 * combined button depending on the selected action.
5484 *
5485 * @property {function} [click]
5486 * Specifies a handler function to invoke when the user clicks the button.
5487 * This function will be called with the button DOM node as `this` context
5488 * and receive the DOM click event as first as well as the selected action
5489 * choice value as second argument.
5490 */
5491 __init__: function(value, choices, options) {
5492 this.super('__init__', [ value, choices, Object.assign({
5493 sort: true
5494 }, options, {
5495 multiple: false,
5496 create: false,
5497 optional: false
5498 }) ]);
5499 },
5500
5501 /** @override */
5502 render: function(/* ... */) {
5503 var node = UIDropdown.prototype.render.apply(this, arguments),
5504 val = this.getValue();
5505
5506 if (L.isObject(this.options.classes) &amp;&amp; this.options.classes.hasOwnProperty(val))
5507 node.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5508
5509 return node;
5510 },
5511
5512 /** @private */
5513 handleClick: function(ev) {
5514 var sb = ev.currentTarget,
5515 t = ev.target;
5516
5517 if (sb.hasAttribute('open') || dom.matches(t, '.cbi-dropdown > span.open'))
5518 return UIDropdown.prototype.handleClick.apply(this, arguments);
5519
5520 if (this.options.click)
5521 return this.options.click.call(sb, ev, this.getValue());
5522 },
5523
5524 /** @private */
5525 toggleItem: function(sb /*, ... */) {
5526 var rv = UIDropdown.prototype.toggleItem.apply(this, arguments),
5527 val = this.getValue();
5528
5529 if (L.isObject(this.options.classes) &amp;&amp; this.options.classes.hasOwnProperty(val))
5530 sb.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5531 else
5532 sb.setAttribute('class', 'cbi-dropdown');
5533
5534 return rv;
5535 }
5536 });
5537
5538 /**
5539 * Instantiate a dynamic list widget.
5540 *
5541 * @constructor DynamicList
5542 * @memberof LuCI.ui
5543 * @augments LuCI.ui.AbstractElement
5544 *
5545 * @classdesc
5546 *
5547 * The `DynamicList` class implements a widget which allows the user to specify
5548 * an arbitrary amount of input values, either from free formed text input or
5549 * from a set of predefined choices.
5550 *
5551 * UI widget instances are usually not supposed to be created by view code
5552 * directly, instead they're implicitely created by `LuCI.form` when
5553 * instantiating CBI forms.
5554 *
5555 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5556 * in views, use `'require ui'` and refer to `ui.DynamicList`. To import it in
5557 * external JavaScript, use `L.require("ui").then(...)` and access the
5558 * `DynamicList` property of the class instance value.
5559 *
5560 * @param {string|string[]} [value=null]
5561 * The initial input value(s).
5562 *
5563 * @param {Object&lt;string, *>} [choices]
5564 * Object containing the selectable choices of the widget. The object keys
5565 * serve as values for the different choices while the values are used as
5566 * choice labels. If omitted, no default choices are presented to the user,
5567 * instead a plain text input field is rendered allowing the user to add
5568 * arbitrary values to the dynamic list.
5569 *
5570 * @param {LuCI.ui.DynamicList.InitOptions} [options]
5571 * Object describing the widget specific options to initialize the dynamic list.
5572 */
5573 var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ {
5574 /**
5575 * In case choices are passed to the dynamic list contructor, the widget
5576 * supports the same properties as [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions}
5577 * but enforces specific values for some dropdown properties.
5578 *
5579 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5580 * @memberof LuCI.ui.DynamicList
5581 *
5582 * @property {boolean} multiple=false
5583 * Since dynamic lists never allow selecting multiple choices when adding
5584 * another list item, this property is forcibly set to `false`.
5585 *
5586 * @property {boolean} optional=true
5587 * Since dynamic lists use an embedded dropdown to present a list of
5588 * predefined choice values, the dropdown must be made optional to allow
5589 * it to remain unselected.
5590 */
5591 __init__: function(values, choices, options) {
5592 if (!Array.isArray(values))
5593 values = (values != null &amp;&amp; values != '') ? [ values ] : [];
5594
5595 if (typeof(choices) != 'object')
5596 choices = null;
5597
5598 this.values = values;
5599 this.choices = choices;
5600 this.options = Object.assign({}, options, {
5601 multiple: false,
5602 optional: true
5603 });
5604 },
5605
5606 /** @override */
5607 render: function() {
5608 var dl = E('div', {
5609 'id': this.options.id,
5610 'class': 'cbi-dynlist',
5611 'disabled': this.options.disabled ? '' : null
5612 }, E('div', { 'class': 'add-item' }));
5613
5614 if (this.choices) {
5615 if (this.options.placeholder != null)
5616 this.options.select_placeholder = this.options.placeholder;
5617
5618 var cbox = new UICombobox(null, this.choices, this.options);
5619
5620 dl.lastElementChild.appendChild(cbox.render());
5621 }
5622 else {
5623 var inputEl = E('input', {
5624 'id': this.options.id ? 'widget.' + this.options.id : null,
5625 'type': 'text',
5626 'class': 'cbi-input-text',
5627 'placeholder': this.options.placeholder,
5628 'disabled': this.options.disabled ? '' : null
5629 });
5630
5631 dl.lastElementChild.appendChild(inputEl);
5632 dl.lastElementChild.appendChild(E('div', { 'class': 'btn cbi-button cbi-button-add' }, '+'));
5633
5634 if (this.options.datatype || this.options.validate)
5635 UI.prototype.addValidator(inputEl, this.options.datatype || 'string',
5636 true, this.options.validate, 'blur', 'keyup');
5637 }
5638
5639 for (var i = 0; i &lt; this.values.length; i++) {
5640 var label = this.choices ? this.choices[this.values[i]] : null;
5641
5642 if (dom.elem(label))
5643 label = label.cloneNode(true);
5644
5645 this.addItem(dl, this.values[i], label);
5646 }
5647
5648 return this.bind(dl);
5649 },
5650
5651 /** @private */
5652 bind: function(dl) {
5653 dl.addEventListener('click', L.bind(this.handleClick, this));
5654 dl.addEventListener('keydown', L.bind(this.handleKeydown, this));
5655 dl.addEventListener('cbi-dropdown-change', L.bind(this.handleDropdownChange, this));
5656
5657 this.node = dl;
5658
5659 this.setUpdateEvents(dl, 'cbi-dynlist-change');
5660 this.setChangeEvents(dl, 'cbi-dynlist-change');
5661
5662 dom.bindClassInstance(dl, this);
5663
5664 return dl;
5665 },
5666
5667 /** @private */
5668 addItem: function(dl, value, text, flash) {
5669 var exists = false,
5670 new_item = E('div', { 'class': flash ? 'item flash' : 'item', 'tabindex': 0 }, [
5671 E('span', {}, [ text || value ]),
5672 E('input', {
5673 'type': 'hidden',
5674 'name': this.options.name,
5675 'value': value })]);
5676
5677 dl.querySelectorAll('.item').forEach(function(item) {
5678 if (exists)
5679 return;
5680
5681 var hidden = item.querySelector('input[type="hidden"]');
5682
5683 if (hidden &amp;&amp; hidden.parentNode !== item)
5684 hidden = null;
5685
5686 if (hidden &amp;&amp; hidden.value === value)
5687 exists = true;
5688 });
5689
5690 if (!exists) {
5691 var ai = dl.querySelector('.add-item');
5692 ai.parentNode.insertBefore(new_item, ai);
5693 }
5694
5695 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5696 bubbles: true,
5697 detail: {
5698 instance: this,
5699 element: dl,
5700 value: value,
5701 add: true
5702 }
5703 }));
5704 },
5705
5706 /** @private */
5707 removeItem: function(dl, item) {
5708 var value = item.querySelector('input[type="hidden"]').value;
5709 var sb = dl.querySelector('.cbi-dropdown');
5710 if (sb)
5711 sb.querySelectorAll('ul > li').forEach(function(li) {
5712 if (li.getAttribute('data-value') === value) {
5713 if (li.hasAttribute('dynlistcustom'))
5714 li.parentNode.removeChild(li);
5715 else
5716 li.removeAttribute('unselectable');
5717 }
5718 });
5719
5720 item.parentNode.removeChild(item);
5721
5722 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5723 bubbles: true,
5724 detail: {
5725 instance: this,
5726 element: dl,
5727 value: value,
5728 remove: true
5729 }
5730 }));
5731 },
5732
5733 /** @private */
5734 handleClick: function(ev) {
5735 var dl = ev.currentTarget,
5736 item = findParent(ev.target, '.item');
5737
5738 if (this.options.disabled)
5739 return;
5740
5741 if (item) {
5742 this.removeItem(dl, item);
5743 }
5744 else if (matchesElem(ev.target, '.cbi-button-add')) {
5745 var input = ev.target.previousElementSibling;
5746 if (input.value.length &amp;&amp; !input.classList.contains('cbi-input-invalid')) {
5747 this.addItem(dl, input.value, null, true);
5748 input.value = '';
5749 }
5750 }
5751 },
5752
5753 /** @private */
5754 handleDropdownChange: function(ev) {
5755 var dl = ev.currentTarget,
5756 sbIn = ev.detail.instance,
5757 sbEl = ev.detail.element,
5758 sbVal = ev.detail.value;
5759
5760 if (sbVal === null)
5761 return;
5762
5763 sbIn.setValues(sbEl, null);
5764 sbVal.element.setAttribute('unselectable', '');
5765
5766 if (sbVal.element.hasAttribute('created')) {
5767 sbVal.element.removeAttribute('created');
5768 sbVal.element.setAttribute('dynlistcustom', '');
5769 }
5770
5771 var label = sbVal.text;
5772
5773 if (sbVal.element) {
5774 label = E([]);
5775
5776 for (var i = 0; i &lt; sbVal.element.childNodes.length; i++)
5777 label.appendChild(sbVal.element.childNodes[i].cloneNode(true));
5778 }
5779
5780 this.addItem(dl, sbVal.value, label, true);
5781 },
5782
5783 /** @private */
5784 handleKeydown: function(ev) {
5785 var dl = ev.currentTarget,
5786 item = findParent(ev.target, '.item');
5787
5788 if (item) {
5789 switch (ev.keyCode) {
5790 case 8: /* backspace */
5791 if (item.previousElementSibling)
5792 item.previousElementSibling.focus();
5793
5794 this.removeItem(dl, item);
5795 break;
5796
5797 case 46: /* delete */
5798 if (item.nextElementSibling) {
5799 if (item.nextElementSibling.classList.contains('item'))
5800 item.nextElementSibling.focus();
5801 else
5802 item.nextElementSibling.firstElementChild.focus();
5803 }
5804
5805 this.removeItem(dl, item);
5806 break;
5807 }
5808 }
5809 else if (matchesElem(ev.target, '.cbi-input-text')) {
5810 switch (ev.keyCode) {
5811 case 13: /* enter */
5812 if (ev.target.value.length &amp;&amp; !ev.target.classList.contains('cbi-input-invalid')) {
5813 this.addItem(dl, ev.target.value, null, true);
5814 ev.target.value = '';
5815 ev.target.blur();
5816 ev.target.focus();
5817 }
5818
5819 ev.preventDefault();
5820 break;
5821 }
5822 }
5823 },
5824
5825 /** @override */
5826 getValue: function() {
5827 var items = this.node.querySelectorAll('.item > input[type="hidden"]'),
5828 input = this.node.querySelector('.add-item > input[type="text"]'),
5829 v = [];
5830
5831 for (var i = 0; i &lt; items.length; i++)
5832 v.push(items[i].value);
5833
5834 if (input &amp;&amp; input.value != null &amp;&amp; input.value.match(/\S/) &amp;&amp;
5835 input.classList.contains('cbi-input-invalid') == false &amp;&amp;
5836 v.filter(function(s) { return s == input.value }).length == 0)
5837 v.push(input.value);
5838
5839 return v;
5840 },
5841
5842 /** @override */
5843 setValue: function(values) {
5844 if (!Array.isArray(values))
5845 values = (values != null &amp;&amp; values != '') ? [ values ] : [];
5846
5847 var items = this.node.querySelectorAll('.item');
5848
5849 for (var i = 0; i &lt; items.length; i++)
5850 if (items[i].parentNode === this.node)
5851 this.removeItem(this.node, items[i]);
5852
5853 for (var i = 0; i &lt; values.length; i++)
5854 this.addItem(this.node, values[i],
5855 this.choices ? this.choices[values[i]] : null);
5856 },
5857
5858 /**
5859 * Add new suggested choices to the dynamic list.
5860 *
5861 * This function adds further choices to an existing dynamic list,
5862 * ignoring choice values which are already present.
5863 *
5864 * @instance
5865 * @memberof LuCI.ui.DynamicList
5866 * @param {string[]} values
5867 * The choice values to add to the dynamic lists suggestion dropdown.
5868 *
5869 * @param {Object&lt;string, *>} labels
5870 * The choice label values to use when adding suggested choices. If no
5871 * label is found for a particular choice value, the value itself is used
5872 * as label text. Choice labels may be any valid value accepted by
5873 * {@link LuCI.dom#content}.
5874 */
5875 addChoices: function(values, labels) {
5876 var dl = this.node.lastElementChild.firstElementChild;
5877 dom.callClassMethod(dl, 'addChoices', values, labels);
5878 },
5879
5880 /**
5881 * Remove all existing choices from the dynamic list.
5882 *
5883 * This function removes all preexisting suggested choices from the widget.
5884 *
5885 * @instance
5886 * @memberof LuCI.ui.DynamicList
5887 */
5888 clearChoices: function() {
5889 var dl = this.node.lastElementChild.firstElementChild;
5890 dom.callClassMethod(dl, 'clearChoices');
5891 }
5892 });
5893
5894 /**
5895 * Instantiate a hidden input field widget.
5896 *
5897 * @constructor Hiddenfield
5898 * @memberof LuCI.ui
5899 * @augments LuCI.ui.AbstractElement
5900 *
5901 * @classdesc
5902 *
5903 * The `Hiddenfield` class implements an HTML `&lt;input type="hidden">` field
5904 * which allows to store form data without exposing it to the user.
5905 *
5906 * UI widget instances are usually not supposed to be created by view code
5907 * directly, instead they're implicitely created by `LuCI.form` when
5908 * instantiating CBI forms.
5909 *
5910 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5911 * in views, use `'require ui'` and refer to `ui.Hiddenfield`. To import it in
5912 * external JavaScript, use `L.require("ui").then(...)` and access the
5913 * `Hiddenfield` property of the class instance value.
5914 *
5915 * @param {string|string[]} [value=null]
5916 * The initial input value.
5917 *
5918 * @param {LuCI.ui.AbstractElement.InitOptions} [options]
5919 * Object describing the widget specific options to initialize the hidden input.
5920 */
5921 var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ {
5922 __init__: function(value, options) {
5923 this.value = value;
5924 this.options = Object.assign({
5925
5926 }, options);
5927 },
5928
5929 /** @override */
5930 render: function() {
5931 var hiddenEl = E('input', {
5932 'id': this.options.id,
5933 'type': 'hidden',
5934 'value': this.value
5935 });
5936
5937 return this.bind(hiddenEl);
5938 },
5939
5940 /** @private */
5941 bind: function(hiddenEl) {
5942 this.node = hiddenEl;
5943
5944 dom.bindClassInstance(hiddenEl, this);
5945
5946 return hiddenEl;
5947 },
5948
5949 /** @override */
5950 getValue: function() {
5951 return this.node.value;
5952 },
5953
5954 /** @override */
5955 setValue: function(value) {
5956 this.node.value = value;
5957 }
5958 });
5959
5960 /**
5961 * Instantiate a file upload widget.
5962 *
5963 * @constructor FileUpload
5964 * @memberof LuCI.ui
5965 * @augments LuCI.ui.AbstractElement
5966 *
5967 * @classdesc
5968 *
5969 * The `FileUpload` class implements a widget which allows the user to upload,
5970 * browse, select and delete files beneath a predefined remote directory.
5971 *
5972 * UI widget instances are usually not supposed to be created by view code
5973 * directly, instead they're implicitely created by `LuCI.form` when
5974 * instantiating CBI forms.
5975 *
5976 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5977 * in views, use `'require ui'` and refer to `ui.FileUpload`. To import it in
5978 * external JavaScript, use `L.require("ui").then(...)` and access the
5979 * `FileUpload` property of the class instance value.
5980 *
5981 * @param {string|string[]} [value=null]
5982 * The initial input value.
5983 *
5984 * @param {LuCI.ui.DynamicList.InitOptions} [options]
5985 * Object describing the widget specific options to initialize the file
5986 * upload control.
5987 */
5988 var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
5989 /**
5990 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
5991 * the following properties are recognized:
5992 *
5993 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
5994 * @memberof LuCI.ui.FileUpload
5995 *
5996 * @property {boolean} [show_hidden=false]
5997 * Specifies whether hidden files should be displayed when browsing remote
5998 * files. Note that this is not a security feature, hidden files are always
5999 * present in the remote file listings received, this option merely controls
6000 * whether they're displayed or not.
6001 *
6002 * @property {boolean} [enable_upload=true]
6003 * Specifies whether the widget allows the user to upload files. If set to
6004 * `false`, only existing files may be selected. Note that this is not a
6005 * security feature. Whether file upload requests are accepted remotely
6006 * depends on the ACL setup for the current session. This option merely
6007 * controls whether the upload controls are rendered or not.
6008 *
6009 * @property {boolean} [enable_remove=true]
6010 * Specifies whether the widget allows the user to delete remove files.
6011 * If set to `false`, existing files may not be removed. Note that this is
6012 * not a security feature. Whether file delete requests are accepted
6013 * remotely depends on the ACL setup for the current session. This option
6014 * merely controls whether the file remove controls are rendered or not.
6015 *
6016 * @property {string} [root_directory=/etc/luci-uploads]
6017 * Specifies the remote directory the upload and file browsing actions take
6018 * place in. Browsing to directories outside of the root directory is
6019 * prevented by the widget. Note that this is not a security feature.
6020 * Whether remote directories are browseable or not solely depends on the
6021 * ACL setup for the current session.
6022 */
6023 __init__: function(value, options) {
6024 this.value = value;
6025 this.options = Object.assign({
6026 show_hidden: false,
6027 enable_upload: true,
6028 enable_remove: true,
6029 root_directory: '/etc/luci-uploads'
6030 }, options);
6031 },
6032
6033 /** @private */
6034 bind: function(browserEl) {
6035 this.node = browserEl;
6036
6037 this.setUpdateEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
6038 this.setChangeEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
6039
6040 dom.bindClassInstance(browserEl, this);
6041
6042 return browserEl;
6043 },
6044
6045 /** @override */
6046 render: function() {
6047 return L.resolveDefault(this.value != null ? fs.stat(this.value) : null).then(L.bind(function(stat) {
6048 var label;
6049
6050 if (L.isObject(stat) &amp;&amp; stat.type != 'directory')
6051 this.stat = stat;
6052
6053 if (this.stat != null)
6054 label = [ this.iconForType(this.stat.type), ' %s (%1000mB)'.format(this.truncatePath(this.stat.path), this.stat.size) ];
6055 else if (this.value != null)
6056 label = [ this.iconForType('file'), ' %s (%s)'.format(this.truncatePath(this.value), _('File not accessible')) ];
6057 else
6058 label = [ _('Select file…') ];
6059
6060 return this.bind(E('div', { 'id': this.options.id }, [
6061 E('button', {
6062 'class': 'btn',
6063 'click': UI.prototype.createHandlerFn(this, 'handleFileBrowser'),
6064 'disabled': this.options.disabled ? '' : null
6065 }, label),
6066 E('div', {
6067 'class': 'cbi-filebrowser'
6068 }),
6069 E('input', {
6070 'type': 'hidden',
6071 'name': this.options.name,
6072 'value': this.value
6073 })
6074 ]));
6075 }, this));
6076 },
6077
6078 /** @private */
6079 truncatePath: function(path) {
6080 if (path.length > 50)
6081 path = path.substring(0, 25) + '…' + path.substring(path.length - 25);
6082
6083 return path;
6084 },
6085
6086 /** @private */
6087 iconForType: function(type) {
6088 switch (type) {
6089 case 'symlink':
6090 return E('img', {
6091 'src': L.resource('cbi/link.svg'),
6092 'width': 16,
6093 'title': _('Symbolic link'),
6094 'class': 'middle'
6095 });
6096
6097 case 'directory':
6098 return E('img', {
6099 'src': L.resource('cbi/folder.svg'),
6100 'width': 16,
6101 'title': _('Directory'),
6102 'class': 'middle'
6103 });
6104
6105 default:
6106 return E('img', {
6107 'src': L.resource('cbi/file.svg'),
6108 'width': 16,
6109 'title': _('File'),
6110 'class': 'middle'
6111 });
6112 }
6113 },
6114
6115 /** @private */
6116 canonicalizePath: function(path) {
6117 return path.replace(/\/{2,}/, '/')
6118 .replace(/\/\.(\/|$)/g, '/')
6119 .replace(/[^\/]+\/\.\.(\/|$)/g, '/')
6120 .replace(/\/$/, '');
6121 },
6122
6123 /** @private */
6124 splitPath: function(path) {
6125 var croot = this.canonicalizePath(this.options.root_directory || '/'),
6126 cpath = this.canonicalizePath(path || '/');
6127
6128 if (cpath.length &lt;= croot.length)
6129 return [ croot ];
6130
6131 if (cpath.charAt(croot.length) != '/')
6132 return [ croot ];
6133
6134 var parts = cpath.substring(croot.length + 1).split(/\//);
6135
6136 parts.unshift(croot);
6137
6138 return parts;
6139 },
6140
6141 /** @private */
6142 handleUpload: function(path, list, ev) {
6143 var form = ev.target.parentNode,
6144 fileinput = form.querySelector('input[type="file"]'),
6145 nameinput = form.querySelector('input[type="text"]'),
6146 filename = (nameinput.value != null ? nameinput.value : '').trim();
6147
6148 ev.preventDefault();
6149
6150 if (filename == '' || filename.match(/\//) || fileinput.files[0] == null)
6151 return;
6152
6153 var existing = list.filter(function(e) { return e.name == filename })[0];
6154
6155 if (existing != null &amp;&amp; existing.type == 'directory')
6156 return alert(_('A directory with the same name already exists.'));
6157 else if (existing != null &amp;&amp; !confirm(_('Overwrite existing file "%s" ?').format(filename)))
6158 return;
6159
6160 var data = new FormData();
6161
6162 data.append('sessionid', L.env.sessionid);
6163 data.append('filename', path + '/' + filename);
6164 data.append('filedata', fileinput.files[0]);
6165
6166 return request.post(L.env.cgi_base + '/cgi-upload', data, {
6167 progress: L.bind(function(btn, ev) {
6168 btn.firstChild.data = '%.2f%%'.format((ev.loaded / ev.total) * 100);
6169 }, this, ev.target)
6170 }).then(L.bind(function(path, ev, res) {
6171 var reply = res.json();
6172
6173 if (L.isObject(reply) &amp;&amp; reply.failure)
6174 alert(_('Upload request failed: %s').format(reply.message));
6175
6176 return this.handleSelect(path, null, ev);
6177 }, this, path, ev));
6178 },
6179
6180 /** @private */
6181 handleDelete: function(path, fileStat, ev) {
6182 var parent = path.replace(/\/[^\/]+$/, '') || '/',
6183 name = path.replace(/^.+\//, ''),
6184 msg;
6185
6186 ev.preventDefault();
6187
6188 if (fileStat.type == 'directory')
6189 msg = _('Do you really want to recursively delete the directory "%s" ?').format(name);
6190 else
6191 msg = _('Do you really want to delete "%s" ?').format(name);
6192
6193 if (confirm(msg)) {
6194 var button = this.node.firstElementChild,
6195 hidden = this.node.lastElementChild;
6196
6197 if (path == hidden.value) {
6198 dom.content(button, _('Select file…'));
6199 hidden.value = '';
6200 }
6201
6202 return fs.remove(path).then(L.bind(function(parent, ev) {
6203 return this.handleSelect(parent, null, ev);
6204 }, this, parent, ev)).catch(function(err) {
6205 alert(_('Delete request failed: %s').format(err.message));
6206 });
6207 }
6208 },
6209
6210 /** @private */
6211 renderUpload: function(path, list) {
6212 if (!this.options.enable_upload)
6213 return E([]);
6214
6215 return E([
6216 E('a', {
6217 'href': '#',
6218 'class': 'btn cbi-button-positive',
6219 'click': function(ev) {
6220 var uploadForm = ev.target.nextElementSibling,
6221 fileInput = uploadForm.querySelector('input[type="file"]');
6222
6223 ev.target.style.display = 'none';
6224 uploadForm.style.display = '';
6225 fileInput.click();
6226 }
6227 }, _('Upload file…')),
6228 E('div', { 'class': 'upload', 'style': 'display:none' }, [
6229 E('input', {
6230 'type': 'file',
6231 'style': 'display:none',
6232 'change': function(ev) {
6233 var nameinput = ev.target.parentNode.querySelector('input[type="text"]'),
6234 uploadbtn = ev.target.parentNode.querySelector('button.cbi-button-save');
6235
6236 nameinput.value = ev.target.value.replace(/^.+[\/\\]/, '');
6237 uploadbtn.disabled = false;
6238 }
6239 }),
6240 E('button', {
6241 'class': 'btn',
6242 'click': function(ev) {
6243 ev.preventDefault();
6244 ev.target.previousElementSibling.click();
6245 }
6246 }, [ _('Browse…') ]),
6247 E('div', {}, E('input', { 'type': 'text', 'placeholder': _('Filename') })),
6248 E('button', {
6249 'class': 'btn cbi-button-save',
6250 'click': UI.prototype.createHandlerFn(this, 'handleUpload', path, list),
6251 'disabled': true
6252 }, [ _('Upload file') ])
6253 ])
6254 ]);
6255 },
6256
6257 /** @private */
6258 renderListing: function(container, path, list) {
6259 var breadcrumb = E('p'),
6260 rows = E('ul');
6261
6262 list.sort(function(a, b) {
6263 var isDirA = (a.type == 'directory'),
6264 isDirB = (b.type == 'directory');
6265
6266 if (isDirA != isDirB)
6267 return isDirA &lt; isDirB;
6268
6269 return a.name > b.name;
6270 });
6271
6272 for (var i = 0; i &lt; list.length; i++) {
6273 if (!this.options.show_hidden &amp;&amp; list[i].name.charAt(0) == '.')
6274 continue;
6275
6276 var entrypath = this.canonicalizePath(path + '/' + list[i].name),
6277 selected = (entrypath == this.node.lastElementChild.value),
6278 mtime = new Date(list[i].mtime * 1000);
6279
6280 rows.appendChild(E('li', [
6281 E('div', { 'class': 'name' }, [
6282 this.iconForType(list[i].type),
6283 ' ',
6284 E('a', {
6285 'href': '#',
6286 'style': selected ? 'font-weight:bold' : null,
6287 'click': UI.prototype.createHandlerFn(this, 'handleSelect',
6288 entrypath, list[i].type != 'directory' ? list[i] : null)
6289 }, '%h'.format(list[i].name))
6290 ]),
6291 E('div', { 'class': 'mtime hide-xs' }, [
6292 ' %04d-%02d-%02d %02d:%02d:%02d '.format(
6293 mtime.getFullYear(),
6294 mtime.getMonth() + 1,
6295 mtime.getDate(),
6296 mtime.getHours(),
6297 mtime.getMinutes(),
6298 mtime.getSeconds())
6299 ]),
6300 E('div', [
6301 selected ? E('button', {
6302 'class': 'btn',
6303 'click': UI.prototype.createHandlerFn(this, 'handleReset')
6304 }, [ _('Deselect') ]) : '',
6305 this.options.enable_remove ? E('button', {
6306 'class': 'btn cbi-button-negative',
6307 'click': UI.prototype.createHandlerFn(this, 'handleDelete', entrypath, list[i])
6308 }, [ _('Delete') ]) : ''
6309 ])
6310 ]));
6311 }
6312
6313 if (!rows.firstElementChild)
6314 rows.appendChild(E('em', _('No entries in this directory')));
6315
6316 var dirs = this.splitPath(path),
6317 cur = '';
6318
6319 for (var i = 0; i &lt; dirs.length; i++) {
6320 cur = cur ? cur + '/' + dirs[i] : dirs[i];
6321 dom.append(breadcrumb, [
6322 i ? ' » ' : '',
6323 E('a', {
6324 'href': '#',
6325 'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur || '/', null)
6326 }, dirs[i] != '' ? '%h'.format(dirs[i]) : E('em', '(root)')),
6327 ]);
6328 }
6329
6330 dom.content(container, [
6331 breadcrumb,
6332 rows,
6333 E('div', { 'class': 'right' }, [
6334 this.renderUpload(path, list),
6335 E('a', {
6336 'href': '#',
6337 'class': 'btn',
6338 'click': UI.prototype.createHandlerFn(this, 'handleCancel')
6339 }, _('Cancel'))
6340 ]),
6341 ]);
6342 },
6343
6344 /** @private */
6345 handleCancel: function(ev) {
6346 var button = this.node.firstElementChild,
6347 browser = button.nextElementSibling;
6348
6349 browser.classList.remove('open');
6350 button.style.display = '';
6351
6352 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-cancel', {}));
6353
6354 ev.preventDefault();
6355 },
6356
6357 /** @private */
6358 handleReset: function(ev) {
6359 var button = this.node.firstElementChild,
6360 hidden = this.node.lastElementChild;
6361
6362 hidden.value = '';
6363 dom.content(button, _('Select file…'));
6364
6365 this.handleCancel(ev);
6366 },
6367
6368 /** @private */
6369 handleSelect: function(path, fileStat, ev) {
6370 var browser = dom.parent(ev.target, '.cbi-filebrowser'),
6371 ul = browser.querySelector('ul');
6372
6373 if (fileStat == null) {
6374 dom.content(ul, E('em', { 'class': 'spinning' }, _('Loading directory contents…')));
6375 L.resolveDefault(fs.list(path), []).then(L.bind(this.renderListing, this, browser, path));
6376 }
6377 else {
6378 var button = this.node.firstElementChild,
6379 hidden = this.node.lastElementChild;
6380
6381 path = this.canonicalizePath(path);
6382
6383 dom.content(button, [
6384 this.iconForType(fileStat.type),
6385 ' %s (%1000mB)'.format(this.truncatePath(path), fileStat.size)
6386 ]);
6387
6388 browser.classList.remove('open');
6389 button.style.display = '';
6390 hidden.value = path;
6391
6392 this.stat = Object.assign({ path: path }, fileStat);
6393 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-select', { detail: this.stat }));
6394 }
6395 },
6396
6397 /** @private */
6398 handleFileBrowser: function(ev) {
6399 var button = ev.target,
6400 browser = button.nextElementSibling,
6401 path = this.stat ? this.stat.path.replace(/\/[^\/]+$/, '') : (this.options.initial_directory || this.options.root_directory);
6402
6403 if (path.indexOf(this.options.root_directory) != 0)
6404 path = this.options.root_directory;
6405
6406 ev.preventDefault();
6407
6408 return L.resolveDefault(fs.list(path), []).then(L.bind(function(button, browser, path, list) {
6409 document.querySelectorAll('.cbi-filebrowser.open').forEach(function(browserEl) {
6410 dom.findClassInstance(browserEl).handleCancel(ev);
6411 });
6412
6413 button.style.display = 'none';
6414 browser.classList.add('open');
6415
6416 return this.renderListing(browser, path, list);
6417 }, this, button, browser, path));
6418 },
6419
6420 /** @override */
6421 getValue: function() {
6422 return this.node.lastElementChild.value;
6423 },
6424
6425 /** @override */
6426 setValue: function(value) {
6427 this.node.lastElementChild.value = value;
6428 }
6429 });
6430
6431
6432 function scrubMenu(node) {
6433 var hasSatisfiedChild = false;
6434
6435 if (L.isObject(node.children)) {
6436 for (var k in node.children) {
6437 var child = scrubMenu(node.children[k]);
6438
6439 if (child.title)
6440 hasSatisfiedChild = hasSatisfiedChild || child.satisfied;
6441 }
6442 }
6443
6444 if (L.isObject(node.action) &amp;&amp;
6445 node.action.type == 'firstchild' &amp;&amp;
6446 hasSatisfiedChild == false)
6447 node.satisfied = false;
6448
6449 return node;
6450 };
6451
6452 /**
6453 * Handle menu.
6454 *
6455 * @constructor menu
6456 * @memberof LuCI.ui
6457 *
6458 * @classdesc
6459 *
6460 * Handles menus.
6461 */
6462 var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ {
6463 /**
6464 * @typedef {Object} MenuNode
6465 * @memberof LuCI.ui.menu
6466
6467 * @property {string} name - The internal name of the node, as used in the URL
6468 * @property {number} order - The sort index of the menu node
6469 * @property {string} [title] - The title of the menu node, `null` if the node should be hidden
6470 * @property {satisified} boolean - Boolean indicating whether the menu enries dependencies are satisfied
6471 * @property {readonly} [boolean] - Boolean indicating whether the menu entries underlying ACLs are readonly
6472 * @property {LuCI.ui.menu.MenuNode[]} [children] - Array of child menu nodes.
6473 */
6474
6475 /**
6476 * Load and cache current menu tree.
6477 *
6478 * @returns {Promise&lt;LuCI.ui.menu.MenuNode>}
6479 * Returns a promise resolving to the root element of the menu tree.
6480 */
6481 load: function() {
6482 if (this.menu == null)
6483 this.menu = session.getLocalData('menu');
6484
6485 if (!L.isObject(this.menu)) {
6486 this.menu = request.get(L.url('admin/menu')).then(L.bind(function(menu) {
6487 this.menu = scrubMenu(menu.json());
6488 session.setLocalData('menu', this.menu);
6489
6490 return this.menu;
6491 }, this));
6492 }
6493
6494 return Promise.resolve(this.menu);
6495 },
6496
6497 /**
6498 * Flush the internal menu cache to force loading a new structure on the
6499 * next page load.
6500 */
6501 flushCache: function() {
6502 session.setLocalData('menu', null);
6503 },
6504
6505 /**
6506 * @param {LuCI.ui.menu.MenuNode} [node]
6507 * The menu node to retrieve the children for. Defaults to the menu's
6508 * internal root node if omitted.
6509 *
6510 * @returns {LuCI.ui.menu.MenuNode[]}
6511 * Returns an array of child menu nodes.
6512 */
6513 getChildren: function(node) {
6514 var children = [];
6515
6516 if (node == null)
6517 node = this.menu;
6518
6519 for (var k in node.children) {
6520 if (!node.children.hasOwnProperty(k))
6521 continue;
6522
6523 if (!node.children[k].satisfied)
6524 continue;
6525
6526 if (!node.children[k].hasOwnProperty('title'))
6527 continue;
6528
6529 children.push(Object.assign(node.children[k], { name: k }));
6530 }
6531
6532 return children.sort(function(a, b) {
6533 var wA = a.order || 1000,
6534 wB = b.order || 1000;
6535
6536 if (wA != wB)
6537 return wA - wB;
6538
6539 return a.name > b.name;
6540 });
6541 }
6542 });
6543
6544 /**
6545 * @class ui
6546 * @memberof LuCI
6547 * @hideconstructor
6548 * @classdesc
6549 *
6550 * Provides high level UI helper functionality.
6551 * To import the class in views, use `'require ui'`, to import it in
6552 * external JavaScript, use `L.require("ui").then(...)`.
6553 */
6554 var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
6555 __init__: function() {
6556 modalDiv = document.body.appendChild(
6557 dom.create('div', { id: 'modal_overlay' },
6558 dom.create('div', { class: 'modal', role: 'dialog', 'aria-modal': true })));
6559
6560 tooltipDiv = document.body.appendChild(
6561 dom.create('div', { class: 'cbi-tooltip' }));
6562
6563 /* setup old aliases */
6564 L.showModal = this.showModal;
6565 L.hideModal = this.hideModal;
6566 L.showTooltip = this.showTooltip;
6567 L.hideTooltip = this.hideTooltip;
6568 L.itemlist = this.itemlist;
6569
6570 document.addEventListener('mouseover', this.showTooltip.bind(this), true);
6571 document.addEventListener('mouseout', this.hideTooltip.bind(this), true);
6572 document.addEventListener('focus', this.showTooltip.bind(this), true);
6573 document.addEventListener('blur', this.hideTooltip.bind(this), true);
6574
6575 document.addEventListener('luci-loaded', this.tabs.init.bind(this.tabs));
6576 document.addEventListener('luci-loaded', this.changes.init.bind(this.changes));
6577 document.addEventListener('uci-loaded', this.changes.init.bind(this.changes));
6578 },
6579
6580 /**
6581 * Display a modal overlay dialog with the specified contents.
6582 *
6583 * The modal overlay dialog covers the current view preventing interaction
6584 * with the underlying view contents. Only one modal dialog instance can
6585 * be opened. Invoking showModal() while a modal dialog is already open will
6586 * replace the open dialog with a new one having the specified contents.
6587 *
6588 * Additional CSS class names may be passed to influence the appearence of
6589 * the dialog. Valid values for the classes depend on the underlying theme.
6590 *
6591 * @see LuCI.dom.content
6592 *
6593 * @param {string} [title]
6594 * The title of the dialog. If `null`, no title element will be rendered.
6595 *
6596 * @param {*} contents
6597 * The contents to add to the modal dialog. This should be a DOM node or
6598 * a document fragment in most cases. The value is passed as-is to the
6599 * `dom.content()` function - refer to its documentation for applicable
6600 * values.
6601 *
6602 * @param {...string} [classes]
6603 * A number of extra CSS class names which are set on the modal dialog
6604 * element.
6605 *
6606 * @returns {Node}
6607 * Returns a DOM Node representing the modal dialog element.
6608 */
6609 showModal: function(title, children /* , ... */) {
6610 var dlg = modalDiv.firstElementChild;
6611
6612 dlg.setAttribute('class', 'modal');
6613
6614 for (var i = 2; i &lt; arguments.length; i++)
6615 dlg.classList.add(arguments[i]);
6616
6617 dom.content(dlg, dom.create('h4', {}, title));
6618 dom.append(dlg, children);
6619
6620 document.body.classList.add('modal-overlay-active');
6621 modalDiv.scrollTop = 0;
6622
6623 return dlg;
6624 },
6625
6626 /**
6627 * Close the open modal overlay dialog.
6628 *
6629 * This function will close an open modal dialog and restore the normal view
6630 * behaviour. It has no effect if no modal dialog is currently open.
6631 *
6632 * Note that this function is stand-alone, it does not rely on `this` and
6633 * will not invoke other class functions so it suitable to be used as event
6634 * handler as-is without the need to bind it first.
6635 */
6636 hideModal: function() {
6637 document.body.classList.remove('modal-overlay-active');
6638 },
6639
6640 /** @private */
6641 showTooltip: function(ev) {
6642 var target = findParent(ev.target, '[data-tooltip]');
6643
6644 if (!target)
6645 return;
6646
6647 if (tooltipTimeout !== null) {
6648 window.clearTimeout(tooltipTimeout);
6649 tooltipTimeout = null;
6650 }
6651
6652 var rect = target.getBoundingClientRect(),
6653 x = rect.left + window.pageXOffset,
6654 y = rect.top + rect.height + window.pageYOffset;
6655
6656 tooltipDiv.className = 'cbi-tooltip';
6657 tooltipDiv.innerHTML = '▲ ';
6658 tooltipDiv.firstChild.data += target.getAttribute('data-tooltip');
6659
6660 if (target.hasAttribute('data-tooltip-style'))
6661 tooltipDiv.classList.add(target.getAttribute('data-tooltip-style'));
6662
6663 if ((y + tooltipDiv.offsetHeight) > (window.innerHeight + window.pageYOffset)) {
6664 y -= (tooltipDiv.offsetHeight + target.offsetHeight);
6665 tooltipDiv.firstChild.data = '▼ ' + tooltipDiv.firstChild.data.substr(2);
6666 }
6667
6668 tooltipDiv.style.top = y + 'px';
6669 tooltipDiv.style.left = x + 'px';
6670 tooltipDiv.style.opacity = 1;
6671
6672 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-open', {
6673 bubbles: true,
6674 detail: { target: target }
6675 }));
6676 },
6677
6678 /** @private */
6679 hideTooltip: function(ev) {
6680 if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv ||
6681 tooltipDiv.contains(ev.target) || tooltipDiv.contains(ev.relatedTarget))
6682 return;
6683
6684 if (tooltipTimeout !== null) {
6685 window.clearTimeout(tooltipTimeout);
6686 tooltipTimeout = null;
6687 }
6688
6689 tooltipDiv.style.opacity = 0;
6690 tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250);
6691
6692 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-close', { bubbles: true }));
6693 },
6694
6695 /**
6696 * Add a notification banner at the top of the current view.
6697 *
6698 * A notification banner is an alert message usually displayed at the
6699 * top of the current view, spanning the entire availibe width.
6700 * Notification banners will stay in place until dismissed by the user.
6701 * Multiple banners may be shown at the same time.
6702 *
6703 * Additional CSS class names may be passed to influence the appearence of
6704 * the banner. Valid values for the classes depend on the underlying theme.
6705 *
6706 * @see LuCI.dom.content
6707 *
6708 * @param {string} [title]
6709 * The title of the notification banner. If `null`, no title element
6710 * will be rendered.
6711 *
6712 * @param {*} contents
6713 * The contents to add to the notification banner. This should be a DOM
6714 * node or a document fragment in most cases. The value is passed as-is
6715 * to the `dom.content()` function - refer to its documentation for
6716 * applicable values.
6717 *
6718 * @param {...string} [classes]
6719 * A number of extra CSS class names which are set on the notification
6720 * banner element.
6721 *
6722 * @returns {Node}
6723 * Returns a DOM Node representing the notification banner element.
6724 */
6725 addNotification: function(title, children /*, ... */) {
6726 var mc = document.querySelector('#maincontent') || document.body;
6727 var msg = E('div', {
6728 'class': 'alert-message fade-in',
6729 'style': 'display:flex',
6730 'transitionend': function(ev) {
6731 var node = ev.currentTarget;
6732 if (node.parentNode &amp;&amp; node.classList.contains('fade-out'))
6733 node.parentNode.removeChild(node);
6734 }
6735 }, [
6736 E('div', { 'style': 'flex:10' }),
6737 E('div', { 'style': 'flex:1 1 auto; display:flex' }, [
6738 E('button', {
6739 'class': 'btn',
6740 'style': 'margin-left:auto; margin-top:auto',
6741 'click': function(ev) {
6742 dom.parent(ev.target, '.alert-message').classList.add('fade-out');
6743 },
6744
6745 }, [ _('Dismiss') ])
6746 ])
6747 ]);
6748
6749 if (title != null)
6750 dom.append(msg.firstElementChild, E('h4', {}, title));
6751
6752 dom.append(msg.firstElementChild, children);
6753
6754 for (var i = 2; i &lt; arguments.length; i++)
6755 msg.classList.add(arguments[i]);
6756
6757 mc.insertBefore(msg, mc.firstElementChild);
6758
6759 return msg;
6760 },
6761
6762 /**
6763 * Display or update an header area indicator.
6764 *
6765 * An indicator is a small label displayed in the header area of the screen
6766 * providing few amounts of status information such as item counts or state
6767 * toggle indicators.
6768 *
6769 * Multiple indicators may be shown at the same time and indicator labels
6770 * may be made clickable to display extended information or to initiate
6771 * further actions.
6772 *
6773 * Indicators can either use a default `active` or a less accented `inactive`
6774 * style which is useful for indicators representing state toggles.
6775 *
6776 * @param {string} id
6777 * The ID of the indicator. If an indicator with the given ID already exists,
6778 * it is updated with the given label and style.
6779 *
6780 * @param {string} label
6781 * The text to display in the indicator label.
6782 *
6783 * @param {function} [handler]
6784 * A handler function to invoke when the indicator label is clicked/touched
6785 * by the user. If omitted, the indicator is not clickable/touchable.
6786 *
6787 * Note that this parameter only applies to new indicators, when updating
6788 * existing labels it is ignored.
6789 *
6790 * @param {string} [style=active]
6791 * The indicator style to use. May be either `active` or `inactive`.
6792 *
6793 * @returns {boolean}
6794 * Returns `true` when the indicator has been updated or `false` when no
6795 * changes were made.
6796 */
6797 showIndicator: function(id, label, handler, style) {
6798 if (indicatorDiv == null) {
6799 indicatorDiv = document.body.querySelector('#indicators');
6800
6801 if (indicatorDiv == null)
6802 return false;
6803 }
6804
6805 var handlerFn = (typeof(handler) == 'function') ? handler : null,
6806 indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id));
6807
6808 if (indicatorElem == null) {
6809 var beforeElem = null;
6810
6811 for (beforeElem = indicatorDiv.firstElementChild;
6812 beforeElem != null;
6813 beforeElem = beforeElem.nextElementSibling)
6814 if (beforeElem.getAttribute('data-indicator') > id)
6815 break;
6816
6817 indicatorElem = indicatorDiv.insertBefore(E('span', {
6818 'data-indicator': id,
6819 'data-clickable': handlerFn ? true : null,
6820 'click': handlerFn
6821 }, ['']), beforeElem);
6822 }
6823
6824 if (label == indicatorElem.firstChild.data &amp;&amp; style == indicatorElem.getAttribute('data-style'))
6825 return false;
6826
6827 indicatorElem.firstChild.data = label;
6828 indicatorElem.setAttribute('data-style', (style == 'inactive') ? 'inactive' : 'active');
6829 return true;
6830 },
6831
6832 /**
6833 * Remove an header area indicator.
6834 *
6835 * This function removes the given indicator label from the header indicator
6836 * area. When the given indicator is not found, this function does nothing.
6837 *
6838 * @param {string} id
6839 * The ID of the indicator to remove.
6840 *
6841 * @returns {boolean}
6842 * Returns `true` when the indicator has been removed or `false` when the
6843 * requested indicator was not found.
6844 */
6845 hideIndicator: function(id) {
6846 var indicatorElem = indicatorDiv ? indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) : null;
6847
6848 if (indicatorElem == null)
6849 return false;
6850
6851 indicatorDiv.removeChild(indicatorElem);
6852 return true;
6853 },
6854
6855 /**
6856 * Formats a series of label/value pairs into list-like markup.
6857 *
6858 * This function transforms a flat array of alternating label and value
6859 * elements into a list-like markup, using the values in `separators` as
6860 * separators and appends the resulting nodes to the given parent DOM node.
6861 *
6862 * Each label is suffixed with `: ` and wrapped into a `&lt;strong>` tag, the
6863 * `&lt;strong>` element and the value corresponding to the label are
6864 * subsequently wrapped into a `&lt;span class="nowrap">` element.
6865 *
6866 * The resulting `&lt;span>` element tuples are joined by the given separators
6867 * to form the final markup which is appened to the given parent DOM node.
6868 *
6869 * @param {Node} node
6870 * The parent DOM node to append the markup to. Any previous child elements
6871 * will be removed.
6872 *
6873 * @param {Array&lt;*>} items
6874 * An alternating array of labels and values. The label values will be
6875 * converted to plain strings, the values are used as-is and may be of
6876 * any type accepted by `LuCI.dom.content()`.
6877 *
6878 * @param {*|Array&lt;*>} [separators=[E('br')]]
6879 * A single value or an array of separator values to separate each
6880 * label/value pair with. The function will cycle through the separators
6881 * when joining the pairs. If omitted, the default separator is a sole HTML
6882 * `&lt;br>` element. Separator values are used as-is and may be of any type
6883 * accepted by `LuCI.dom.content()`.
6884 *
6885 * @returns {Node}
6886 * Returns the parent DOM node the formatted markup has been added to.
6887 */
6888 itemlist: function(node, items, separators) {
6889 var children = [];
6890
6891 if (!Array.isArray(separators))
6892 separators = [ separators || E('br') ];
6893
6894 for (var i = 0; i &lt; items.length; i += 2) {
6895 if (items[i+1] !== null &amp;&amp; items[i+1] !== undefined) {
6896 var sep = separators[(i/2) % separators.length],
6897 cld = [];
6898
6899 children.push(E('span', { class: 'nowrap' }, [
6900 items[i] ? E('strong', items[i] + ': ') : '',
6901 items[i+1]
6902 ]));
6903
6904 if ((i+2) &lt; items.length)
6905 children.push(dom.elem(sep) ? sep.cloneNode(true) : sep);
6906 }
6907 }
6908
6909 dom.content(node, children);
6910
6911 return node;
6912 },
6913
6914 /**
6915 * @class
6916 * @memberof LuCI.ui
6917 * @hideconstructor
6918 * @classdesc
6919 *
6920 * The `tabs` class handles tab menu groups used throughout the view area.
6921 * It takes care of setting up tab groups, tracking their state and handling
6922 * related events.
6923 *
6924 * This class is automatically instantiated as part of `LuCI.ui`. To use it
6925 * in views, use `'require ui'` and refer to `ui.tabs`. To import it in
6926 * external JavaScript, use `L.require("ui").then(...)` and access the
6927 * `tabs` property of the class instance value.
6928 */
6929 tabs: baseclass.singleton(/* @lends LuCI.ui.tabs.prototype */ {
6930 /** @private */
6931 init: function() {
6932 var groups = [], prevGroup = null, currGroup = null;
6933
6934 document.querySelectorAll('[data-tab]').forEach(function(tab) {
6935 var parent = tab.parentNode;
6936
6937 if (dom.matches(tab, 'li') &amp;&amp; dom.matches(parent, 'ul.cbi-tabmenu'))
6938 return;
6939
6940 if (!parent.hasAttribute('data-tab-group'))
6941 parent.setAttribute('data-tab-group', groups.length);
6942
6943 currGroup = +parent.getAttribute('data-tab-group');
6944
6945 if (currGroup !== prevGroup) {
6946 prevGroup = currGroup;
6947
6948 if (!groups[currGroup])
6949 groups[currGroup] = [];
6950 }
6951
6952 groups[currGroup].push(tab);
6953 });
6954
6955 for (var i = 0; i &lt; groups.length; i++)
6956 this.initTabGroup(groups[i]);
6957
6958 document.addEventListener('dependency-update', this.updateTabs.bind(this));
6959
6960 this.updateTabs();
6961 },
6962
6963 /**
6964 * Initializes a new tab group from the given tab pane collection.
6965 *
6966 * This function cycles through the given tab pane DOM nodes, extracts
6967 * their tab IDs, titles and active states, renders a corresponding
6968 * tab menu and prepends it to the tab panes common parent DOM node.
6969 *
6970 * The tab menu labels will be set to the value of the `data-tab-title`
6971 * attribute of each corresponding pane. The last pane with the
6972 * `data-tab-active` attribute set to `true` will be selected by default.
6973 *
6974 * If no pane is marked as active, the first one will be preselected.
6975 *
6976 * @instance
6977 * @memberof LuCI.ui.tabs
6978 * @param {Array&lt;Node>|NodeList} panes
6979 * A collection of tab panes to build a tab group menu for. May be a
6980 * plain array of DOM nodes or a NodeList collection, such as the result
6981 * of a `querySelectorAll()` call or the `.childNodes` property of a
6982 * DOM node.
6983 */
6984 initTabGroup: function(panes) {
6985 if (typeof(panes) != 'object' || !('length' in panes) || panes.length === 0)
6986 return;
6987
6988 var menu = E('ul', { 'class': 'cbi-tabmenu' }),
6989 group = panes[0].parentNode,
6990 groupId = +group.getAttribute('data-tab-group'),
6991 selected = null;
6992
6993 if (group.getAttribute('data-initialized') === 'true')
6994 return;
6995
6996 for (var i = 0, pane; pane = panes[i]; i++) {
6997 var name = pane.getAttribute('data-tab'),
6998 title = pane.getAttribute('data-tab-title'),
6999 active = pane.getAttribute('data-tab-active') === 'true';
7000
7001 menu.appendChild(E('li', {
7002 'style': this.isEmptyPane(pane) ? 'display:none' : null,
7003 'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
7004 'data-tab': name
7005 }, E('a', {
7006 'href': '#',
7007 'click': this.switchTab.bind(this)
7008 }, title)));
7009
7010 if (active)
7011 selected = i;
7012 }
7013
7014 group.parentNode.insertBefore(menu, group);
7015 group.setAttribute('data-initialized', true);
7016
7017 if (selected === null) {
7018 selected = this.getActiveTabId(panes[0]);
7019
7020 if (selected &lt; 0 || selected >= panes.length || this.isEmptyPane(panes[selected])) {
7021 for (var i = 0; i &lt; panes.length; i++) {
7022 if (!this.isEmptyPane(panes[i])) {
7023 selected = i;
7024 break;
7025 }
7026 }
7027 }
7028
7029 menu.childNodes[selected].classList.add('cbi-tab');
7030 menu.childNodes[selected].classList.remove('cbi-tab-disabled');
7031 panes[selected].setAttribute('data-tab-active', 'true');
7032
7033 this.setActiveTabId(panes[selected], selected);
7034 }
7035
7036 panes[selected].dispatchEvent(new CustomEvent('cbi-tab-active', {
7037 detail: { tab: panes[selected].getAttribute('data-tab') }
7038 }));
7039
7040 this.updateTabs(group);
7041 },
7042
7043 /**
7044 * Checks whether the given tab pane node is empty.
7045 *
7046 * @instance
7047 * @memberof LuCI.ui.tabs
7048 * @param {Node} pane
7049 * The tab pane to check.
7050 *
7051 * @returns {boolean}
7052 * Returns `true` if the pane is empty, else `false`.
7053 */
7054 isEmptyPane: function(pane) {
7055 return dom.isEmpty(pane, function(n) { return n.classList.contains('cbi-tab-descr') });
7056 },
7057
7058 /** @private */
7059 getPathForPane: function(pane) {
7060 var path = [], node = null;
7061
7062 for (node = pane ? pane.parentNode : null;
7063 node != null &amp;&amp; node.hasAttribute != null;
7064 node = node.parentNode)
7065 {
7066 if (node.hasAttribute('data-tab'))
7067 path.unshift(node.getAttribute('data-tab'));
7068 else if (node.hasAttribute('data-section-id'))
7069 path.unshift(node.getAttribute('data-section-id'));
7070 }
7071
7072 return path.join('/');
7073 },
7074
7075 /** @private */
7076 getActiveTabState: function() {
7077 var page = document.body.getAttribute('data-page'),
7078 state = session.getLocalData('tab');
7079
7080 if (L.isObject(state) &amp;&amp; state.page === page &amp;&amp; L.isObject(state.paths))
7081 return state;
7082
7083 session.setLocalData('tab', null);
7084
7085 return { page: page, paths: {} };
7086 },
7087
7088 /** @private */
7089 getActiveTabId: function(pane) {
7090 var path = this.getPathForPane(pane);
7091 return +this.getActiveTabState().paths[path] || 0;
7092 },
7093
7094 /** @private */
7095 setActiveTabId: function(pane, tabIndex) {
7096 var path = this.getPathForPane(pane),
7097 state = this.getActiveTabState();
7098
7099 state.paths[path] = tabIndex;
7100
7101 return session.setLocalData('tab', state);
7102 },
7103
7104 /** @private */
7105 updateTabs: function(ev, root) {
7106 (root || document).querySelectorAll('[data-tab-title]').forEach(L.bind(function(pane) {
7107 var menu = pane.parentNode.previousElementSibling,
7108 tab = menu ? menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))) : null,
7109 n_errors = pane.querySelectorAll('.cbi-input-invalid').length;
7110
7111 if (!menu || !tab)
7112 return;
7113
7114 if (this.isEmptyPane(pane)) {
7115 tab.style.display = 'none';
7116 tab.classList.remove('flash');
7117 }
7118 else if (tab.style.display === 'none') {
7119 tab.style.display = '';
7120 requestAnimationFrame(function() { tab.classList.add('flash') });
7121 }
7122
7123 if (n_errors) {
7124 tab.setAttribute('data-errors', n_errors);
7125 tab.setAttribute('data-tooltip', _('%d invalid field(s)').format(n_errors));
7126 tab.setAttribute('data-tooltip-style', 'error');
7127 }
7128 else {
7129 tab.removeAttribute('data-errors');
7130 tab.removeAttribute('data-tooltip');
7131 }
7132 }, this));
7133 },
7134
7135 /** @private */
7136 switchTab: function(ev) {
7137 var tab = ev.target.parentNode,
7138 name = tab.getAttribute('data-tab'),
7139 menu = tab.parentNode,
7140 group = menu.nextElementSibling,
7141 groupId = +group.getAttribute('data-tab-group'),
7142 index = 0;
7143
7144 ev.preventDefault();
7145
7146 if (!tab.classList.contains('cbi-tab-disabled'))
7147 return;
7148
7149 menu.querySelectorAll('[data-tab]').forEach(function(tab) {
7150 tab.classList.remove('cbi-tab');
7151 tab.classList.remove('cbi-tab-disabled');
7152 tab.classList.add(
7153 tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled');
7154 });
7155
7156 group.childNodes.forEach(function(pane) {
7157 if (dom.matches(pane, '[data-tab]')) {
7158 if (pane.getAttribute('data-tab') === name) {
7159 pane.setAttribute('data-tab-active', 'true');
7160 pane.dispatchEvent(new CustomEvent('cbi-tab-active', { detail: { tab: name } }));
7161 UI.prototype.tabs.setActiveTabId(pane, index);
7162 }
7163 else {
7164 pane.setAttribute('data-tab-active', 'false');
7165 }
7166
7167 index++;
7168 }
7169 });
7170 }
7171 }),
7172
7173 /**
7174 * @typedef {Object} FileUploadReply
7175 * @memberof LuCI.ui
7176
7177 * @property {string} name - Name of the uploaded file without directory components
7178 * @property {number} size - Size of the uploaded file in bytes
7179 * @property {string} checksum - The MD5 checksum of the received file data
7180 * @property {string} sha256sum - The SHA256 checksum of the received file data
7181 */
7182
7183 /**
7184 * Display a modal file upload prompt.
7185 *
7186 * This function opens a modal dialog prompting the user to select and
7187 * upload a file to a predefined remote destination path.
7188 *
7189 * @param {string} path
7190 * The remote file path to upload the local file to.
7191 *
7192 * @param {Node} [progessStatusNode]
7193 * An optional DOM text node whose content text is set to the progress
7194 * percentage value during file upload.
7195 *
7196 * @returns {Promise&lt;LuCI.ui.FileUploadReply>}
7197 * Returns a promise resolving to a file upload status object on success
7198 * or rejecting with an error in case the upload failed or has been
7199 * cancelled by the user.
7200 */
7201 uploadFile: function(path, progressStatusNode) {
7202 return new Promise(function(resolveFn, rejectFn) {
7203 UI.prototype.showModal(_('Uploading file…'), [
7204 E('p', _('Please select the file to upload.')),
7205 E('div', { 'style': 'display:flex' }, [
7206 E('div', { 'class': 'left', 'style': 'flex:1' }, [
7207 E('input', {
7208 type: 'file',
7209 style: 'display:none',
7210 change: function(ev) {
7211 var modal = dom.parent(ev.target, '.modal'),
7212 body = modal.querySelector('p'),
7213 upload = modal.querySelector('.cbi-button-action.important'),
7214 file = ev.currentTarget.files[0];
7215
7216 if (file == null)
7217 return;
7218
7219 dom.content(body, [
7220 E('ul', {}, [
7221 E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]),
7222 E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ])
7223 ])
7224 ]);
7225
7226 upload.disabled = false;
7227 upload.focus();
7228 }
7229 }),
7230 E('button', {
7231 'class': 'btn',
7232 'click': function(ev) {
7233 ev.target.previousElementSibling.click();
7234 }
7235 }, [ _('Browse…') ])
7236 ]),
7237 E('div', { 'class': 'right', 'style': 'flex:1' }, [
7238 E('button', {
7239 'class': 'btn',
7240 'click': function() {
7241 UI.prototype.hideModal();
7242 rejectFn(new Error('Upload has been cancelled'));
7243 }
7244 }, [ _('Cancel') ]),
7245 ' ',
7246 E('button', {
7247 'class': 'btn cbi-button-action important',
7248 'disabled': true,
7249 'click': function(ev) {
7250 var input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]');
7251
7252 if (!input.files[0])
7253 return;
7254
7255 var progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' }));
7256
7257 UI.prototype.showModal(_('Uploading file…'), [ progress ]);
7258
7259 var data = new FormData();
7260
7261 data.append('sessionid', rpc.getSessionID());
7262 data.append('filename', path);
7263 data.append('filedata', input.files[0]);
7264
7265 var filename = input.files[0].name;
7266
7267 request.post(L.env.cgi_base + '/cgi-upload', data, {
7268 timeout: 0,
7269 progress: function(pev) {
7270 var percent = (pev.loaded / pev.total) * 100;
7271
7272 if (progressStatusNode)
7273 progressStatusNode.data = '%.2f%%'.format(percent);
7274
7275 progress.setAttribute('title', '%.2f%%'.format(percent));
7276 progress.firstElementChild.style.width = '%.2f%%'.format(percent);
7277 }
7278 }).then(function(res) {
7279 var reply = res.json();
7280
7281 UI.prototype.hideModal();
7282
7283 if (L.isObject(reply) &amp;&amp; reply.failure) {
7284 UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message)));
7285 rejectFn(new Error(reply.failure));
7286 }
7287 else {
7288 reply.name = filename;
7289 resolveFn(reply);
7290 }
7291 }, function(err) {
7292 UI.prototype.hideModal();
7293 rejectFn(err);
7294 });
7295 }
7296 }, [ _('Upload') ])
7297 ])
7298 ])
7299 ]);
7300 });
7301 },
7302
7303 /**
7304 * Perform a device connectivity test.
7305 *
7306 * Attempt to fetch a well known ressource from the remote device via HTTP
7307 * in order to test connectivity. This function is mainly useful to wait
7308 * for the router to come back online after a reboot or reconfiguration.
7309 *
7310 * @param {string} [proto=http]
7311 * The protocol to use for fetching the resource. May be either `http`
7312 * (the default) or `https`.
7313 *
7314 * @param {string} [host=window.location.host]
7315 * Override the host address to probe. By default the current host as seen
7316 * in the address bar is probed.
7317 *
7318 * @returns {Promise&lt;Event>}
7319 * Returns a promise resolving to a `load` event in case the device is
7320 * reachable or rejecting with an `error` event in case it is not reachable
7321 * or rejecting with `null` when the connectivity check timed out.
7322 */
7323 pingDevice: function(proto, ipaddr) {
7324 var target = '%s://%s%s?%s'.format(proto || 'http', ipaddr || window.location.host, L.resource('icons/loading.gif'), Math.random());
7325
7326 return new Promise(function(resolveFn, rejectFn) {
7327 var img = new Image();
7328
7329 img.onload = resolveFn;
7330 img.onerror = rejectFn;
7331
7332 window.setTimeout(rejectFn, 1000);
7333
7334 img.src = target;
7335 });
7336 },
7337
7338 /**
7339 * Wait for device to come back online and reconnect to it.
7340 *
7341 * Poll each given hostname or IP address and navigate to it as soon as
7342 * one of the addresses becomes reachable.
7343 *
7344 * @param {...string} [hosts=[window.location.host]]
7345 * The list of IP addresses and host names to check for reachability.
7346 * If omitted, the current value of `window.location.host` is used by
7347 * default.
7348 */
7349 awaitReconnect: function(/* ... */) {
7350 var ipaddrs = arguments.length ? arguments : [ window.location.host ];
7351
7352 window.setTimeout(L.bind(function() {
7353 poll.add(L.bind(function() {
7354 var tasks = [], reachable = false;
7355
7356 for (var i = 0; i &lt; 2; i++)
7357 for (var j = 0; j &lt; ipaddrs.length; j++)
7358 tasks.push(this.pingDevice(i ? 'https' : 'http', ipaddrs[j])
7359 .then(function(ev) { reachable = ev.target.src.replace(/^(https?:\/\/[^\/]+).*$/, '$1/') }, function() {}));
7360
7361 return Promise.all(tasks).then(function() {
7362 if (reachable) {
7363 poll.stop();
7364 window.location = reachable;
7365 }
7366 });
7367 }, this));
7368 }, this), 5000);
7369 },
7370
7371 /**
7372 * @class
7373 * @memberof LuCI.ui
7374 * @hideconstructor
7375 * @classdesc
7376 *
7377 * The `changes` class encapsulates logic for visualizing, applying,
7378 * confirming and reverting staged UCI changesets.
7379 *
7380 * This class is automatically instantiated as part of `LuCI.ui`. To use it
7381 * in views, use `'require ui'` and refer to `ui.changes`. To import it in
7382 * external JavaScript, use `L.require("ui").then(...)` and access the
7383 * `changes` property of the class instance value.
7384 */
7385 changes: baseclass.singleton(/* @lends LuCI.ui.changes.prototype */ {
7386 init: function() {
7387 if (!L.env.sessionid)
7388 return;
7389
7390 return uci.changes().then(L.bind(this.renderChangeIndicator, this));
7391 },
7392
7393 /**
7394 * Set the change count indicator.
7395 *
7396 * This function updates or hides the UCI change count indicator,
7397 * depending on the passed change count. When the count is greater
7398 * than 0, the change indicator is displayed or updated, otherwise it
7399 * is removed.
7400 *
7401 * @instance
7402 * @memberof LuCI.ui.changes
7403 * @param {number} numChanges
7404 * The number of changes to indicate.
7405 */
7406 setIndicator: function(n) {
7407 if (n > 0) {
7408 UI.prototype.showIndicator('uci-changes',
7409 '%s: %d'.format(_('Unsaved Changes'), n),
7410 L.bind(this.displayChanges, this));
7411 }
7412 else {
7413 UI.prototype.hideIndicator('uci-changes');
7414 }
7415 },
7416
7417 /**
7418 * Update the change count indicator.
7419 *
7420 * This function updates the UCI change count indicator from the given
7421 * UCI changeset structure.
7422 *
7423 * @instance
7424 * @memberof LuCI.ui.changes
7425 * @param {Object&lt;string, Array&lt;LuCI.uci.ChangeRecord>>} changes
7426 * The UCI changeset to count.
7427 */
7428 renderChangeIndicator: function(changes) {
7429 var n_changes = 0;
7430
7431 for (var config in changes)
7432 if (changes.hasOwnProperty(config))
7433 n_changes += changes[config].length;
7434
7435 this.changes = changes;
7436 this.setIndicator(n_changes);
7437 },
7438
7439 /** @private */
7440 changeTemplates: {
7441 'add-3': '&lt;ins>uci add %0 &lt;strong>%3&lt;/strong> # =%2&lt;/ins>',
7442 'set-3': '&lt;ins>uci set %0.&lt;strong>%2&lt;/strong>=%3&lt;/ins>',
7443 'set-4': '&lt;var>&lt;ins>uci set %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/ins>&lt;/var>',
7444 'remove-2': '&lt;del>uci del %0.&lt;strong>%2&lt;/strong>&lt;/del>',
7445 'remove-3': '&lt;var>&lt;del>uci del %0.%2.&lt;strong>%3&lt;/strong>&lt;/del>&lt;/var>',
7446 'order-3': '&lt;var>uci reorder %0.%2=&lt;strong>%3&lt;/strong>&lt;/var>',
7447 'list-add-4': '&lt;var>&lt;ins>uci add_list %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/ins>&lt;/var>',
7448 'list-del-4': '&lt;var>&lt;del>uci del_list %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/del>&lt;/var>',
7449 'rename-3': '&lt;var>uci rename %0.%2=&lt;strong>%3&lt;/strong>&lt;/var>',
7450 'rename-4': '&lt;var>uci rename %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/var>'
7451 },
7452
7453 /**
7454 * Display the current changelog.
7455 *
7456 * Open a modal dialog visualizing the currently staged UCI changes
7457 * and offer options to revert or apply the shown changes.
7458 *
7459 * @instance
7460 * @memberof LuCI.ui.changes
7461 */
7462 displayChanges: function() {
7463 var list = E('div', { 'class': 'uci-change-list' }),
7464 dlg = UI.prototype.showModal(_('Configuration') + ' / ' + _('Changes'), [
7465 E('div', { 'class': 'cbi-section' }, [
7466 E('strong', _('Legend:')),
7467 E('div', { 'class': 'uci-change-legend' }, [
7468 E('div', { 'class': 'uci-change-legend-label' }, [
7469 E('ins', '&amp;#160;'), ' ', _('Section added') ]),
7470 E('div', { 'class': 'uci-change-legend-label' }, [
7471 E('del', '&amp;#160;'), ' ', _('Section removed') ]),
7472 E('div', { 'class': 'uci-change-legend-label' }, [
7473 E('var', {}, E('ins', '&amp;#160;')), ' ', _('Option changed') ]),
7474 E('div', { 'class': 'uci-change-legend-label' }, [
7475 E('var', {}, E('del', '&amp;#160;')), ' ', _('Option removed') ])]),
7476 E('br'), list,
7477 E('div', { 'class': 'right' }, [
7478 E('button', {
7479 'class': 'btn',
7480 'click': UI.prototype.hideModal
7481 }, [ _('Dismiss') ]), ' ',
7482 E('button', {
7483 'class': 'cbi-button cbi-button-positive important',
7484 'click': L.bind(this.apply, this, true)
7485 }, [ _('Save &amp; Apply') ]), ' ',
7486 E('button', {
7487 'class': 'cbi-button cbi-button-reset',
7488 'click': L.bind(this.revert, this)
7489 }, [ _('Revert') ])])])
7490 ]);
7491
7492 for (var config in this.changes) {
7493 if (!this.changes.hasOwnProperty(config))
7494 continue;
7495
7496 list.appendChild(E('h5', '# /etc/config/%s'.format(config)));
7497
7498 for (var i = 0, added = null; i &lt; this.changes[config].length; i++) {
7499 var chg = this.changes[config][i],
7500 tpl = this.changeTemplates['%s-%d'.format(chg[0], chg.length)];
7501
7502 list.appendChild(E(tpl.replace(/%([01234])/g, function(m0, m1) {
7503 switch (+m1) {
7504 case 0:
7505 return config;
7506
7507 case 2:
7508 if (added != null &amp;&amp; chg[1] == added[0])
7509 return '@' + added[1] + '[-1]';
7510 else
7511 return chg[1];
7512
7513 case 4:
7514 return "'%h'".format(chg[3].replace(/'/g, "'\"'\"'"));
7515
7516 default:
7517 return chg[m1-1];
7518 }
7519 })));
7520
7521 if (chg[0] == 'add')
7522 added = [ chg[1], chg[2] ];
7523 }
7524 }
7525
7526 list.appendChild(E('br'));
7527 dlg.classList.add('uci-dialog');
7528 },
7529
7530 /** @private */
7531 displayStatus: function(type, content) {
7532 if (type) {
7533 var message = UI.prototype.showModal('', '');
7534
7535 message.classList.add('alert-message');
7536 DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
7537
7538 if (content)
7539 dom.content(message, content);
7540
7541 if (!this.was_polling) {
7542 this.was_polling = request.poll.active();
7543 request.poll.stop();
7544 }
7545 }
7546 else {
7547 UI.prototype.hideModal();
7548
7549 if (this.was_polling)
7550 request.poll.start();
7551 }
7552 },
7553
7554 /** @private */
7555 rollback: function(checked) {
7556 if (checked) {
7557 this.displayStatus('warning spinning',
7558 E('p', _('Failed to confirm apply within %ds, waiting for rollback…')
7559 .format(L.env.apply_rollback)));
7560
7561 var call = function(r, data, duration) {
7562 if (r.status === 204) {
7563 UI.prototype.changes.displayStatus('warning', [
7564 E('h4', _('Configuration changes have been rolled back!')),
7565 E('p', _('The device could not be reached within %d seconds after applying the pending changes, which caused the configuration to be rolled back for safety reasons. If you believe that the configuration changes are correct nonetheless, perform an unchecked configuration apply. Alternatively, you can dismiss this warning and edit changes before attempting to apply again, or revert all pending changes to keep the currently working configuration state.').format(L.env.apply_rollback)),
7566 E('div', { 'class': 'right' }, [
7567 E('button', {
7568 'class': 'btn',
7569 'click': L.bind(UI.prototype.changes.displayStatus, UI.prototype.changes, false)
7570 }, [ _('Dismiss') ]), ' ',
7571 E('button', {
7572 'class': 'btn cbi-button-action important',
7573 'click': L.bind(UI.prototype.changes.revert, UI.prototype.changes)
7574 }, [ _('Revert changes') ]), ' ',
7575 E('button', {
7576 'class': 'btn cbi-button-negative important',
7577 'click': L.bind(UI.prototype.changes.apply, UI.prototype.changes, false)
7578 }, [ _('Apply unchecked') ])
7579 ])
7580 ]);
7581
7582 return;
7583 }
7584
7585 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
7586 window.setTimeout(function() {
7587 request.request(L.url('admin/uci/confirm'), {
7588 method: 'post',
7589 timeout: L.env.apply_timeout * 1000,
7590 query: { sid: L.env.sessionid, token: L.env.token }
7591 }).then(call);
7592 }, delay);
7593 };
7594
7595 call({ status: 0 });
7596 }
7597 else {
7598 this.displayStatus('warning', [
7599 E('h4', _('Device unreachable!')),
7600 E('p', _('Could not regain access to the device after applying the configuration changes. You might need to reconnect if you modified network related settings such as the IP address or wireless security credentials.'))
7601 ]);
7602 }
7603 },
7604
7605 /** @private */
7606 confirm: function(checked, deadline, override_token) {
7607 var tt;
7608 var ts = Date.now();
7609
7610 this.displayStatus('notice');
7611
7612 if (override_token)
7613 this.confirm_auth = { token: override_token };
7614
7615 var call = function(r, data, duration) {
7616 if (Date.now() >= deadline) {
7617 window.clearTimeout(tt);
7618 UI.prototype.changes.rollback(checked);
7619 return;
7620 }
7621 else if (r &amp;&amp; (r.status === 200 || r.status === 204)) {
7622 document.dispatchEvent(new CustomEvent('uci-applied'));
7623
7624 UI.prototype.changes.setIndicator(0);
7625 UI.prototype.changes.displayStatus('notice',
7626 E('p', _('Configuration changes applied.')));
7627
7628 window.clearTimeout(tt);
7629 window.setTimeout(function() {
7630 //UI.prototype.changes.displayStatus(false);
7631 window.location = window.location.href.split('#')[0];
7632 }, L.env.apply_display * 1000);
7633
7634 return;
7635 }
7636
7637 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
7638 window.setTimeout(function() {
7639 request.request(L.url('admin/uci/confirm'), {
7640 method: 'post',
7641 timeout: L.env.apply_timeout * 1000,
7642 query: UI.prototype.changes.confirm_auth
7643 }).then(call, call);
7644 }, delay);
7645 };
7646
7647 var tick = function() {
7648 var now = Date.now();
7649
7650 UI.prototype.changes.displayStatus('notice spinning',
7651 E('p', _('Applying configuration changes… %ds')
7652 .format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0))));
7653
7654 if (now >= deadline)
7655 return;
7656
7657 tt = window.setTimeout(tick, 1000 - (now - ts));
7658 ts = now;
7659 };
7660
7661 tick();
7662
7663 /* wait a few seconds for the settings to become effective */
7664 window.setTimeout(call, Math.max(L.env.apply_holdoff * 1000 - ((ts + L.env.apply_rollback * 1000) - deadline), 1));
7665 },
7666
7667 /**
7668 * Apply the staged configuration changes.
7669 *
7670 * Start applying staged configuration changes and open a modal dialog
7671 * with a progress indication to prevent interaction with the view
7672 * during the apply process. The modal dialog will be automatically
7673 * closed and the current view reloaded once the apply process is
7674 * complete.
7675 *
7676 * @instance
7677 * @memberof LuCI.ui.changes
7678 * @param {boolean} [checked=false]
7679 * Whether to perform a checked (`true`) configuration apply or an
7680 * unchecked (`false`) one.
7681
7682 * In case of a checked apply, the configuration changes must be
7683 * confirmed within a specific time interval, otherwise the device
7684 * will begin to roll back the changes in order to restore the previous
7685 * settings.
7686 */
7687 apply: function(checked) {
7688 this.displayStatus('notice spinning',
7689 E('p', _('Starting configuration apply…')));
7690
7691 request.request(L.url('admin/uci', checked ? 'apply_rollback' : 'apply_unchecked'), {
7692 method: 'post',
7693 query: { sid: L.env.sessionid, token: L.env.token }
7694 }).then(function(r) {
7695 if (r.status === (checked ? 200 : 204)) {
7696 var tok = null; try { tok = r.json(); } catch(e) {}
7697 if (checked &amp;&amp; tok !== null &amp;&amp; typeof(tok) === 'object' &amp;&amp; typeof(tok.token) === 'string')
7698 UI.prototype.changes.confirm_auth = tok;
7699
7700 UI.prototype.changes.confirm(checked, Date.now() + L.env.apply_rollback * 1000);
7701 }
7702 else if (checked &amp;&amp; r.status === 204) {
7703 UI.prototype.changes.displayStatus('notice',
7704 E('p', _('There are no changes to apply')));
7705
7706 window.setTimeout(function() {
7707 UI.prototype.changes.displayStatus(false);
7708 }, L.env.apply_display * 1000);
7709 }
7710 else {
7711 UI.prototype.changes.displayStatus('warning',
7712 E('p', _('Apply request failed with status &lt;code>%h&lt;/code>')
7713 .format(r.responseText || r.statusText || r.status)));
7714
7715 window.setTimeout(function() {
7716 UI.prototype.changes.displayStatus(false);
7717 }, L.env.apply_display * 1000);
7718 }
7719 });
7720 },
7721
7722 /**
7723 * Revert the staged configuration changes.
7724 *
7725 * Start reverting staged configuration changes and open a modal dialog
7726 * with a progress indication to prevent interaction with the view
7727 * during the revert process. The modal dialog will be automatically
7728 * closed and the current view reloaded once the revert process is
7729 * complete.
7730 *
7731 * @instance
7732 * @memberof LuCI.ui.changes
7733 */
7734 revert: function() {
7735 this.displayStatus('notice spinning',
7736 E('p', _('Reverting configuration…')));
7737
7738 request.request(L.url('admin/uci/revert'), {
7739 method: 'post',
7740 query: { sid: L.env.sessionid, token: L.env.token }
7741 }).then(function(r) {
7742 if (r.status === 200) {
7743 document.dispatchEvent(new CustomEvent('uci-reverted'));
7744
7745 UI.prototype.changes.setIndicator(0);
7746 UI.prototype.changes.displayStatus('notice',
7747 E('p', _('Changes have been reverted.')));
7748
7749 window.setTimeout(function() {
7750 //UI.prototype.changes.displayStatus(false);
7751 window.location = window.location.href.split('#')[0];
7752 }, L.env.apply_display * 1000);
7753 }
7754 else {
7755 UI.prototype.changes.displayStatus('warning',
7756 E('p', _('Revert request failed with status &lt;code>%h&lt;/code>')
7757 .format(r.statusText || r.status)));
7758
7759 window.setTimeout(function() {
7760 UI.prototype.changes.displayStatus(false);
7761 }, L.env.apply_display * 1000);
7762 }
7763 });
7764 }
7765 }),
7766
7767 /**
7768 * Add validation constraints to an input element.
7769 *
7770 * Compile the given type expression and optional validator function into
7771 * a validation function and bind it to the specified input element events.
7772 *
7773 * @param {Node} field
7774 * The DOM input element node to bind the validation constraints to.
7775 *
7776 * @param {string} type
7777 * The datatype specification to describe validation constraints.
7778 * Refer to the `LuCI.validation` class documentation for details.
7779 *
7780 * @param {boolean} [optional=false]
7781 * Specifies whether empty values are allowed (`true`) or not (`false`).
7782 * If an input element is not marked optional it must not be empty,
7783 * otherwise it will be marked as invalid.
7784 *
7785 * @param {function} [vfunc]
7786 * Specifies a custom validation function which is invoked after the
7787 * other validation constraints are applied. The validation must return
7788 * `true` to accept the passed value. Any other return type is converted
7789 * to a string and treated as validation error message.
7790 *
7791 * @param {...string} [events=blur, keyup]
7792 * The list of events to bind. Each received event will trigger a field
7793 * validation. If omitted, the `keyup` and `blur` events are bound by
7794 * default.
7795 *
7796 * @returns {function}
7797 * Returns the compiled validator function which can be used to manually
7798 * trigger field validation or to bind it to further events.
7799 *
7800 * @see LuCI.validation
7801 */
7802 addValidator: function(field, type, optional, vfunc /*, ... */) {
7803 if (type == null)
7804 return;
7805
7806 var events = this.varargs(arguments, 3);
7807 if (events.length == 0)
7808 events.push('blur', 'keyup');
7809
7810 try {
7811 var cbiValidator = validation.create(field, type, optional, vfunc),
7812 validatorFn = cbiValidator.validate.bind(cbiValidator);
7813
7814 for (var i = 0; i &lt; events.length; i++)
7815 field.addEventListener(events[i], validatorFn);
7816
7817 validatorFn();
7818
7819 return validatorFn;
7820 }
7821 catch (e) { }
7822 },
7823
7824 /**
7825 * Create a pre-bound event handler function.
7826 *
7827 * Generate and bind a function suitable for use in event handlers. The
7828 * generated function automatically disables the event source element
7829 * and adds an active indication to it by adding appropriate CSS classes.
7830 *
7831 * It will also await any promises returned by the wrapped function and
7832 * re-enable the source element after the promises ran to completion.
7833 *
7834 * @param {*} ctx
7835 * The `this` context to use for the wrapped function.
7836 *
7837 * @param {function|string} fn
7838 * Specifies the function to wrap. In case of a function value, the
7839 * function is used as-is. If a string is specified instead, it is looked
7840 * up in `ctx` to obtain the function to wrap. In both cases the bound
7841 * function will be invoked with `ctx` as `this` context
7842 *
7843 * @param {...*} extra_args
7844 * Any further parameter as passed as-is to the bound event handler
7845 * function in the same order as passed to `createHandlerFn()`.
7846 *
7847 * @returns {function|null}
7848 * Returns the pre-bound handler function which is suitable to be passed
7849 * to `addEventListener()`. Returns `null` if the given `fn` argument is
7850 * a string which could not be found in `ctx` or if `ctx[fn]` is not a
7851 * valid function value.
7852 */
7853 createHandlerFn: function(ctx, fn /*, ... */) {
7854 if (typeof(fn) == 'string')
7855 fn = ctx[fn];
7856
7857 if (typeof(fn) != 'function')
7858 return null;
7859
7860 var arg_offset = arguments.length - 2;
7861
7862 return Function.prototype.bind.apply(function() {
7863 var t = arguments[arg_offset].currentTarget;
7864
7865 t.classList.add('spinning');
7866 t.disabled = true;
7867
7868 if (t.blur)
7869 t.blur();
7870
7871 Promise.resolve(fn.apply(ctx, arguments)).finally(function() {
7872 t.classList.remove('spinning');
7873 t.disabled = false;
7874 });
7875 }, this.varargs(arguments, 2, ctx));
7876 },
7877
7878 /**
7879 * Load specified view class path and set it up.
7880 *
7881 * Transforms the given view path into a class name, requires it
7882 * using [LuCI.require()]{@link LuCI#require} and asserts that the
7883 * resulting class instance is a descendant of
7884 * [LuCI.view]{@link LuCI.view}.
7885 *
7886 * By instantiating the view class, its corresponding contents are
7887 * rendered and included into the view area. Any runtime errors are
7888 * catched and rendered using [LuCI.error()]{@link LuCI#error}.
7889 *
7890 * @param {string} path
7891 * The view path to render.
7892 *
7893 * @returns {Promise&lt;LuCI.view>}
7894 * Returns a promise resolving to the loaded view instance.
7895 */
7896 instantiateView: function(path) {
7897 var className = 'view.%s'.format(path.replace(/\//g, '.'));
7898
7899 return L.require(className).then(function(view) {
7900 if (!(view instanceof View))
7901 throw new TypeError('Loaded class %s is not a descendant of View'.format(className));
7902
7903 return view;
7904 }).catch(function(err) {
7905 dom.content(document.querySelector('#view'), null);
7906 L.error(err);
7907 });
7908 },
7909
7910 menu: UIMenu,
7911
7912 AbstractElement: UIElement,
7913
7914 /* Widgets */
7915 Textfield: UITextfield,
7916 Textarea: UITextarea,
7917 Checkbox: UICheckbox,
7918 Select: UISelect,
7919 Dropdown: UIDropdown,
7920 DynamicList: UIDynamicList,
7921 Combobox: UICombobox,
7922 ComboButton: UIComboButton,
7923 Hiddenfield: UIHiddenfield,
7924 FileUpload: UIFileUpload
7925 });
7926
7927 return UI;
7928 </code></pre>
7929 </article>
7930 </section>
7931
7932
7933
7934
7935
7936
7937
7938
7939 <footer>
7940 Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Thu Aug 06 2020 17:58:02 GMT+0200 (Central European Summer Time)
7941 </footer>
7942 </div>
7943 </div>
7944 <script>prettyPrint();</script>
7945 <script src="scripts/jaguar.js"></script>
7946 </body>
7947 </html>