5 <title>Source: ui.js</title>
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>
12 <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
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">
20 var config = {"monospaceLinks":true,"cleverLinks":true,"default":{"outputSourceFiles":true}};
27 <div id="wrap" class="clearfix">
29 <div class="navigation">
30 <h3 class="applicationName"><a href="index.html"></a></h3>
33 <input id="search" type="text" class="form-control input-sm" placeholder="Search Documentations">
37 <li class="item" data-name="LuCI">
39 <a href="LuCI.html">LuCI</a>
42 <ul class="members itemMembers">
44 <span class="subtitle">Members</span>
46 <li data-name="LuCI#Class"><a href="LuCI.html#Class">Class</a></li>
48 <li data-name="LuCI#dom"><a href="LuCI.html#dom">dom</a></li>
50 <li data-name="LuCI#env"><a href="LuCI.html#env">env</a></li>
52 <li data-name="LuCI#Poll"><a href="LuCI.html#Poll">Poll</a></li>
54 <li data-name="LuCI#Request"><a href="LuCI.html#Request">Request</a></li>
56 <li data-name="LuCI#view"><a href="LuCI.html#view">view</a></li>
59 <ul class="typedefs itemMembers">
61 <span class="subtitle">Typedefs</span>
63 <li data-name="LuCI.requestCallbackFn"><a href="LuCI.html#.requestCallbackFn">requestCallbackFn</a></li>
66 <ul class="typedefs itemMembers">
69 <ul class="methods itemMembers">
71 <span class="subtitle">Methods</span>
73 <li data-name="LuCI#bind"><a href="LuCI.html#bind">bind</a></li>
75 <li data-name="LuCI#error"><a href="LuCI.html#error">error</a></li>
77 <li data-name="LuCI#get"><a href="LuCI.html#get">get</a></li>
79 <li data-name="LuCI#halt"><a href="LuCI.html#halt">halt</a></li>
81 <li data-name="LuCI#hasSystemFeature"><a href="LuCI.html#hasSystemFeature">hasSystemFeature</a></li>
83 <li data-name="LuCI#isObject"><a href="LuCI.html#isObject">isObject</a></li>
85 <li data-name="LuCI#location"><a href="LuCI.html#location">location</a></li>
87 <li data-name="LuCI#media"><a href="LuCI.html#media">media</a></li>
89 <li data-name="LuCI#path"><a href="LuCI.html#path">path</a></li>
91 <li data-name="LuCI#poll"><a href="LuCI.html#poll">poll</a></li>
93 <li data-name="LuCI#post"><a href="LuCI.html#post">post</a></li>
95 <li data-name="LuCI#raise"><a href="LuCI.html#raise">raise</a></li>
97 <li data-name="LuCI#require"><a href="LuCI.html#require">require</a></li>
99 <li data-name="LuCI#resolveDefault"><a href="LuCI.html#resolveDefault">resolveDefault</a></li>
101 <li data-name="LuCI#resource"><a href="LuCI.html#resource">resource</a></li>
103 <li data-name="LuCI#run"><a href="LuCI.html#run">run</a></li>
105 <li data-name="LuCI#sortedKeys"><a href="LuCI.html#sortedKeys">sortedKeys</a></li>
107 <li data-name="LuCI#stop"><a href="LuCI.html#stop">stop</a></li>
109 <li data-name="LuCI#toArray"><a href="LuCI.html#toArray">toArray</a></li>
111 <li data-name="LuCI#url"><a href="LuCI.html#url">url</a></li>
114 <ul class="events itemMembers">
119 <li class="item" data-name="LuCI.baseclass">
121 <a href="LuCI.baseclass.html">LuCI.baseclass</a>
124 <ul class="members itemMembers">
127 <ul class="typedefs itemMembers">
130 <ul class="typedefs itemMembers">
133 <ul class="methods itemMembers">
135 <span class="subtitle">Methods</span>
137 <li data-name="LuCI.baseclass.extend"><a href="LuCI.baseclass.html#.extend">extend</a></li>
139 <li data-name="LuCI.baseclass.instantiate"><a href="LuCI.baseclass.html#.instantiate">instantiate</a></li>
141 <li data-name="LuCI.baseclass.isSubclass"><a href="LuCI.baseclass.html#.isSubclass">isSubclass</a></li>
143 <li data-name="LuCI.baseclass.singleton"><a href="LuCI.baseclass.html#.singleton">singleton</a></li>
145 <li data-name="LuCI.baseclass#super"><a href="LuCI.baseclass.html#super">super</a></li>
147 <li data-name="LuCI.baseclass#varargs"><a href="LuCI.baseclass.html#varargs">varargs</a></li>
150 <ul class="events itemMembers">
155 <li class="item" data-name="LuCI.dom">
157 <a href="LuCI.dom.html">LuCI.dom</a>
160 <ul class="members itemMembers">
163 <ul class="typedefs itemMembers">
165 <span class="subtitle">Typedefs</span>
167 <li data-name="LuCI.dom~ignoreCallbackFn"><a href="LuCI.dom.html#~ignoreCallbackFn">ignoreCallbackFn</a></li>
170 <ul class="typedefs itemMembers">
173 <ul class="methods itemMembers">
175 <span class="subtitle">Methods</span>
177 <li data-name="LuCI.dom#append"><a href="LuCI.dom.html#append">append</a></li>
179 <li data-name="LuCI.dom#attr"><a href="LuCI.dom.html#attr">attr</a></li>
181 <li data-name="LuCI.dom#bindClassInstance"><a href="LuCI.dom.html#bindClassInstance">bindClassInstance</a></li>
183 <li data-name="LuCI.dom#callClassMethod"><a href="LuCI.dom.html#callClassMethod">callClassMethod</a></li>
185 <li data-name="LuCI.dom#content"><a href="LuCI.dom.html#content">content</a></li>
187 <li data-name="LuCI.dom#create"><a href="LuCI.dom.html#create">create</a></li>
189 <li data-name="LuCI.dom#data"><a href="LuCI.dom.html#data">data</a></li>
191 <li data-name="LuCI.dom#elem"><a href="LuCI.dom.html#elem">elem</a></li>
193 <li data-name="LuCI.dom#findClassInstance"><a href="LuCI.dom.html#findClassInstance">findClassInstance</a></li>
195 <li data-name="LuCI.dom#isEmpty"><a href="LuCI.dom.html#isEmpty">isEmpty</a></li>
197 <li data-name="LuCI.dom#matches"><a href="LuCI.dom.html#matches">matches</a></li>
199 <li data-name="LuCI.dom#parent"><a href="LuCI.dom.html#parent">parent</a></li>
201 <li data-name="LuCI.dom#parse"><a href="LuCI.dom.html#parse">parse</a></li>
204 <ul class="events itemMembers">
209 <li class="item" data-name="LuCI.form">
211 <a href="LuCI.form.html">LuCI.form</a>
214 <ul class="members itemMembers">
217 <ul class="typedefs itemMembers">
220 <ul class="typedefs itemMembers">
223 <ul class="methods itemMembers">
226 <ul class="events itemMembers">
231 <li class="item" data-name="LuCI.form.AbstractElement">
233 <a href="LuCI.form.AbstractElement.html">LuCI.form.AbstractElement</a>
236 <ul class="members itemMembers">
239 <ul class="typedefs itemMembers">
242 <ul class="typedefs itemMembers">
245 <ul class="methods itemMembers">
247 <span class="subtitle">Methods</span>
249 <li data-name="LuCI.form.AbstractElement#append"><a href="LuCI.form.AbstractElement.html#append">append</a></li>
251 <li data-name="LuCI.form.AbstractElement#parse"><a href="LuCI.form.AbstractElement.html#parse">parse</a></li>
253 <li data-name="LuCI.form.AbstractElement#render"><a href="LuCI.form.AbstractElement.html#render">render</a></li>
255 <li data-name="LuCI.form.AbstractElement#stripTags"><a href="LuCI.form.AbstractElement.html#stripTags">stripTags</a></li>
257 <li data-name="LuCI.form.AbstractElement#titleFn"><a href="LuCI.form.AbstractElement.html#titleFn">titleFn</a></li>
260 <ul class="events itemMembers">
265 <li class="item" data-name="LuCI.form.AbstractSection">
267 <a href="LuCI.form.AbstractSection.html">LuCI.form.AbstractSection</a>
270 <ul class="members itemMembers">
272 <span class="subtitle">Members</span>
274 <li data-name="LuCI.form.AbstractSection##parentoption"><a href="LuCI.form.AbstractSection.html#parentoption">parentoption</a></li>
277 <ul class="typedefs itemMembers">
280 <ul class="typedefs itemMembers">
283 <ul class="methods itemMembers">
285 <span class="subtitle">Methods</span>
287 <li data-name="LuCI.form.AbstractSection#append"><a href="LuCI.form.AbstractSection.html#append">append</a></li>
289 <li data-name="LuCI.form.AbstractSection#cfgsections"><a href="LuCI.form.AbstractSection.html#cfgsections">cfgsections</a></li>
291 <li data-name="LuCI.form.AbstractSection#filter"><a href="LuCI.form.AbstractSection.html#filter">filter</a></li>
293 <li data-name="LuCI.form.AbstractSection#load"><a href="LuCI.form.AbstractSection.html#load">load</a></li>
295 <li data-name="LuCI.form.AbstractSection#option"><a href="LuCI.form.AbstractSection.html#option">option</a></li>
297 <li data-name="LuCI.form.AbstractSection#parse"><a href="LuCI.form.AbstractSection.html#parse">parse</a></li>
299 <li data-name="LuCI.form.AbstractSection#render"><a href="LuCI.form.AbstractSection.html#render">render</a></li>
301 <li data-name="LuCI.form.AbstractSection#stripTags"><a href="LuCI.form.AbstractSection.html#stripTags">stripTags</a></li>
303 <li data-name="LuCI.form.AbstractSection#tab"><a href="LuCI.form.AbstractSection.html#tab">tab</a></li>
305 <li data-name="LuCI.form.AbstractSection#taboption"><a href="LuCI.form.AbstractSection.html#taboption">taboption</a></li>
307 <li data-name="LuCI.form.AbstractSection#titleFn"><a href="LuCI.form.AbstractSection.html#titleFn">titleFn</a></li>
310 <ul class="events itemMembers">
315 <li class="item" data-name="LuCI.form.AbstractValue">
317 <a href="LuCI.form.AbstractValue.html">LuCI.form.AbstractValue</a>
320 <ul class="members itemMembers">
322 <span class="subtitle">Members</span>
324 <li data-name="LuCI.form.AbstractValue##datatype"><a href="LuCI.form.AbstractValue.html#datatype">datatype</a></li>
326 <li data-name="LuCI.form.AbstractValue##default"><a href="LuCI.form.AbstractValue.html#default">default</a></li>
328 <li data-name="LuCI.form.AbstractValue##editable"><a href="LuCI.form.AbstractValue.html#editable">editable</a></li>
330 <li data-name="LuCI.form.AbstractValue##modalonly"><a href="LuCI.form.AbstractValue.html#modalonly">modalonly</a></li>
332 <li data-name="LuCI.form.AbstractValue##optional"><a href="LuCI.form.AbstractValue.html#optional">optional</a></li>
334 <li data-name="LuCI.form.AbstractValue##rmempty"><a href="LuCI.form.AbstractValue.html#rmempty">rmempty</a></li>
336 <li data-name="LuCI.form.AbstractValue##uciconfig"><a href="LuCI.form.AbstractValue.html#uciconfig">uciconfig</a></li>
338 <li data-name="LuCI.form.AbstractValue##ucioption"><a href="LuCI.form.AbstractValue.html#ucioption">ucioption</a></li>
340 <li data-name="LuCI.form.AbstractValue##ucisection"><a href="LuCI.form.AbstractValue.html#ucisection">ucisection</a></li>
342 <li data-name="LuCI.form.AbstractValue##validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
344 <li data-name="LuCI.form.AbstractValue##width"><a href="LuCI.form.AbstractValue.html#width">width</a></li>
347 <ul class="typedefs itemMembers">
350 <ul class="typedefs itemMembers">
353 <ul class="methods itemMembers">
355 <span class="subtitle">Methods</span>
357 <li data-name="LuCI.form.AbstractValue#append"><a href="LuCI.form.AbstractValue.html#append">append</a></li>
359 <li data-name="LuCI.form.AbstractValue#cbid"><a href="LuCI.form.AbstractValue.html#cbid">cbid</a></li>
361 <li data-name="LuCI.form.AbstractValue#cfgvalue"><a href="LuCI.form.AbstractValue.html#cfgvalue">cfgvalue</a></li>
363 <li data-name="LuCI.form.AbstractValue#depends"><a href="LuCI.form.AbstractValue.html#depends">depends</a></li>
365 <li data-name="LuCI.form.AbstractValue#formvalue"><a href="LuCI.form.AbstractValue.html#formvalue">formvalue</a></li>
367 <li data-name="LuCI.form.AbstractValue#getUIElement"><a href="LuCI.form.AbstractValue.html#getUIElement">getUIElement</a></li>
369 <li data-name="LuCI.form.AbstractValue#isActive"><a href="LuCI.form.AbstractValue.html#isActive">isActive</a></li>
371 <li data-name="LuCI.form.AbstractValue#isValid"><a href="LuCI.form.AbstractValue.html#isValid">isValid</a></li>
373 <li data-name="LuCI.form.AbstractValue#load"><a href="LuCI.form.AbstractValue.html#load">load</a></li>
375 <li data-name="LuCI.form.AbstractValue#parse"><a href="LuCI.form.AbstractValue.html#parse">parse</a></li>
377 <li data-name="LuCI.form.AbstractValue#remove"><a href="LuCI.form.AbstractValue.html#remove">remove</a></li>
379 <li data-name="LuCI.form.AbstractValue#render"><a href="LuCI.form.AbstractValue.html#render">render</a></li>
381 <li data-name="LuCI.form.AbstractValue#stripTags"><a href="LuCI.form.AbstractValue.html#stripTags">stripTags</a></li>
383 <li data-name="LuCI.form.AbstractValue#textvalue"><a href="LuCI.form.AbstractValue.html#textvalue">textvalue</a></li>
385 <li data-name="LuCI.form.AbstractValue#titleFn"><a href="LuCI.form.AbstractValue.html#titleFn">titleFn</a></li>
387 <li data-name="LuCI.form.AbstractValue#validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
389 <li data-name="LuCI.form.AbstractValue#write"><a href="LuCI.form.AbstractValue.html#write">write</a></li>
392 <ul class="events itemMembers">
397 <li class="item" data-name="LuCI.form.ButtonValue">
399 <a href="LuCI.form.ButtonValue.html">LuCI.form.ButtonValue</a>
402 <ul class="members itemMembers">
404 <span class="subtitle">Members</span>
406 <li data-name="LuCI.form.ButtonValue##inputstyle"><a href="LuCI.form.ButtonValue.html#inputstyle">inputstyle</a></li>
408 <li data-name="LuCI.form.ButtonValue##inputtitle"><a href="LuCI.form.ButtonValue.html#inputtitle">inputtitle</a></li>
410 <li data-name="LuCI.form.ButtonValue##onclick"><a href="LuCI.form.ButtonValue.html#onclick">onclick</a></li>
412 <li data-name="LuCI.form.ButtonValue#datatype"><a href="LuCI.form.ButtonValue.html#datatype">datatype</a></li>
414 <li data-name="LuCI.form.ButtonValue#default"><a href="LuCI.form.ButtonValue.html#default">default</a></li>
416 <li data-name="LuCI.form.ButtonValue#editable"><a href="LuCI.form.ButtonValue.html#editable">editable</a></li>
418 <li data-name="LuCI.form.ButtonValue#modalonly"><a href="LuCI.form.ButtonValue.html#modalonly">modalonly</a></li>
420 <li data-name="LuCI.form.ButtonValue#optional"><a href="LuCI.form.ButtonValue.html#optional">optional</a></li>
422 <li data-name="LuCI.form.ButtonValue#password"><a href="LuCI.form.ButtonValue.html#password">password</a></li>
424 <li data-name="LuCI.form.ButtonValue#placeholder"><a href="LuCI.form.ButtonValue.html#placeholder">placeholder</a></li>
426 <li data-name="LuCI.form.ButtonValue#rmempty"><a href="LuCI.form.ButtonValue.html#rmempty">rmempty</a></li>
428 <li data-name="LuCI.form.ButtonValue#uciconfig"><a href="LuCI.form.ButtonValue.html#uciconfig">uciconfig</a></li>
430 <li data-name="LuCI.form.ButtonValue#ucioption"><a href="LuCI.form.ButtonValue.html#ucioption">ucioption</a></li>
432 <li data-name="LuCI.form.ButtonValue#ucisection"><a href="LuCI.form.ButtonValue.html#ucisection">ucisection</a></li>
434 <li data-name="LuCI.form.ButtonValue#validate"><a href="LuCI.form.ButtonValue.html#validate">validate</a></li>
436 <li data-name="LuCI.form.ButtonValue#width"><a href="LuCI.form.ButtonValue.html#width">width</a></li>
439 <ul class="typedefs itemMembers">
442 <ul class="typedefs itemMembers">
445 <ul class="methods itemMembers">
447 <span class="subtitle">Methods</span>
449 <li data-name="LuCI.form.ButtonValue#append"><a href="LuCI.form.ButtonValue.html#append">append</a></li>
451 <li data-name="LuCI.form.ButtonValue#cbid"><a href="LuCI.form.ButtonValue.html#cbid">cbid</a></li>
453 <li data-name="LuCI.form.ButtonValue#cfgvalue"><a href="LuCI.form.ButtonValue.html#cfgvalue">cfgvalue</a></li>
455 <li data-name="LuCI.form.ButtonValue#depends"><a href="LuCI.form.ButtonValue.html#depends">depends</a></li>
457 <li data-name="LuCI.form.ButtonValue#formvalue"><a href="LuCI.form.ButtonValue.html#formvalue">formvalue</a></li>
459 <li data-name="LuCI.form.ButtonValue#getUIElement"><a href="LuCI.form.ButtonValue.html#getUIElement">getUIElement</a></li>
461 <li data-name="LuCI.form.ButtonValue#isActive"><a href="LuCI.form.ButtonValue.html#isActive">isActive</a></li>
463 <li data-name="LuCI.form.ButtonValue#isValid"><a href="LuCI.form.ButtonValue.html#isValid">isValid</a></li>
465 <li data-name="LuCI.form.ButtonValue#load"><a href="LuCI.form.ButtonValue.html#load">load</a></li>
467 <li data-name="LuCI.form.ButtonValue#parse"><a href="LuCI.form.ButtonValue.html#parse">parse</a></li>
469 <li data-name="LuCI.form.ButtonValue#remove"><a href="LuCI.form.ButtonValue.html#remove">remove</a></li>
471 <li data-name="LuCI.form.ButtonValue#stripTags"><a href="LuCI.form.ButtonValue.html#stripTags">stripTags</a></li>
473 <li data-name="LuCI.form.ButtonValue#textvalue"><a href="LuCI.form.ButtonValue.html#textvalue">textvalue</a></li>
475 <li data-name="LuCI.form.ButtonValue#titleFn"><a href="LuCI.form.ButtonValue.html#titleFn">titleFn</a></li>
477 <li data-name="LuCI.form.ButtonValue#value"><a href="LuCI.form.ButtonValue.html#value">value</a></li>
479 <li data-name="LuCI.form.ButtonValue#write"><a href="LuCI.form.ButtonValue.html#write">write</a></li>
482 <ul class="events itemMembers">
487 <li class="item" data-name="LuCI.form.DummyValue">
489 <a href="LuCI.form.DummyValue.html">LuCI.form.DummyValue</a>
492 <ul class="members itemMembers">
494 <span class="subtitle">Members</span>
496 <li data-name="LuCI.form.DummyValue##href"><a href="LuCI.form.DummyValue.html#href">href</a></li>
498 <li data-name="LuCI.form.DummyValue##rawhtml"><a href="LuCI.form.DummyValue.html#rawhtml">rawhtml</a></li>
500 <li data-name="LuCI.form.DummyValue#datatype"><a href="LuCI.form.DummyValue.html#datatype">datatype</a></li>
502 <li data-name="LuCI.form.DummyValue#default"><a href="LuCI.form.DummyValue.html#default">default</a></li>
504 <li data-name="LuCI.form.DummyValue#editable"><a href="LuCI.form.DummyValue.html#editable">editable</a></li>
506 <li data-name="LuCI.form.DummyValue#modalonly"><a href="LuCI.form.DummyValue.html#modalonly">modalonly</a></li>
508 <li data-name="LuCI.form.DummyValue#optional"><a href="LuCI.form.DummyValue.html#optional">optional</a></li>
510 <li data-name="LuCI.form.DummyValue#password"><a href="LuCI.form.DummyValue.html#password">password</a></li>
512 <li data-name="LuCI.form.DummyValue#placeholder"><a href="LuCI.form.DummyValue.html#placeholder">placeholder</a></li>
514 <li data-name="LuCI.form.DummyValue#rmempty"><a href="LuCI.form.DummyValue.html#rmempty">rmempty</a></li>
516 <li data-name="LuCI.form.DummyValue#uciconfig"><a href="LuCI.form.DummyValue.html#uciconfig">uciconfig</a></li>
518 <li data-name="LuCI.form.DummyValue#ucioption"><a href="LuCI.form.DummyValue.html#ucioption">ucioption</a></li>
520 <li data-name="LuCI.form.DummyValue#ucisection"><a href="LuCI.form.DummyValue.html#ucisection">ucisection</a></li>
522 <li data-name="LuCI.form.DummyValue#validate"><a href="LuCI.form.DummyValue.html#validate">validate</a></li>
524 <li data-name="LuCI.form.DummyValue#width"><a href="LuCI.form.DummyValue.html#width">width</a></li>
527 <ul class="typedefs itemMembers">
530 <ul class="typedefs itemMembers">
533 <ul class="methods itemMembers">
535 <span class="subtitle">Methods</span>
537 <li data-name="LuCI.form.DummyValue#append"><a href="LuCI.form.DummyValue.html#append">append</a></li>
539 <li data-name="LuCI.form.DummyValue#cbid"><a href="LuCI.form.DummyValue.html#cbid">cbid</a></li>
541 <li data-name="LuCI.form.DummyValue#cfgvalue"><a href="LuCI.form.DummyValue.html#cfgvalue">cfgvalue</a></li>
543 <li data-name="LuCI.form.DummyValue#depends"><a href="LuCI.form.DummyValue.html#depends">depends</a></li>
545 <li data-name="LuCI.form.DummyValue#formvalue"><a href="LuCI.form.DummyValue.html#formvalue">formvalue</a></li>
547 <li data-name="LuCI.form.DummyValue#getUIElement"><a href="LuCI.form.DummyValue.html#getUIElement">getUIElement</a></li>
549 <li data-name="LuCI.form.DummyValue#isActive"><a href="LuCI.form.DummyValue.html#isActive">isActive</a></li>
551 <li data-name="LuCI.form.DummyValue#isValid"><a href="LuCI.form.DummyValue.html#isValid">isValid</a></li>
553 <li data-name="LuCI.form.DummyValue#load"><a href="LuCI.form.DummyValue.html#load">load</a></li>
555 <li data-name="LuCI.form.DummyValue#parse"><a href="LuCI.form.DummyValue.html#parse">parse</a></li>
557 <li data-name="LuCI.form.DummyValue#remove"><a href="LuCI.form.DummyValue.html#remove">remove</a></li>
559 <li data-name="LuCI.form.DummyValue#stripTags"><a href="LuCI.form.DummyValue.html#stripTags">stripTags</a></li>
561 <li data-name="LuCI.form.DummyValue#textvalue"><a href="LuCI.form.DummyValue.html#textvalue">textvalue</a></li>
563 <li data-name="LuCI.form.DummyValue#titleFn"><a href="LuCI.form.DummyValue.html#titleFn">titleFn</a></li>
565 <li data-name="LuCI.form.DummyValue#value"><a href="LuCI.form.DummyValue.html#value">value</a></li>
567 <li data-name="LuCI.form.DummyValue#write"><a href="LuCI.form.DummyValue.html#write">write</a></li>
570 <ul class="events itemMembers">
575 <li class="item" data-name="LuCI.form.DynamicList">
577 <a href="LuCI.form.DynamicList.html">LuCI.form.DynamicList</a>
580 <ul class="members itemMembers">
582 <span class="subtitle">Members</span>
584 <li data-name="LuCI.form.DynamicList#datatype"><a href="LuCI.form.DynamicList.html#datatype">datatype</a></li>
586 <li data-name="LuCI.form.DynamicList#default"><a href="LuCI.form.DynamicList.html#default">default</a></li>
588 <li data-name="LuCI.form.DynamicList#editable"><a href="LuCI.form.DynamicList.html#editable">editable</a></li>
590 <li data-name="LuCI.form.DynamicList#modalonly"><a href="LuCI.form.DynamicList.html#modalonly">modalonly</a></li>
592 <li data-name="LuCI.form.DynamicList#optional"><a href="LuCI.form.DynamicList.html#optional">optional</a></li>
594 <li data-name="LuCI.form.DynamicList#password"><a href="LuCI.form.DynamicList.html#password">password</a></li>
596 <li data-name="LuCI.form.DynamicList#placeholder"><a href="LuCI.form.DynamicList.html#placeholder">placeholder</a></li>
598 <li data-name="LuCI.form.DynamicList#rmempty"><a href="LuCI.form.DynamicList.html#rmempty">rmempty</a></li>
600 <li data-name="LuCI.form.DynamicList#uciconfig"><a href="LuCI.form.DynamicList.html#uciconfig">uciconfig</a></li>
602 <li data-name="LuCI.form.DynamicList#ucioption"><a href="LuCI.form.DynamicList.html#ucioption">ucioption</a></li>
604 <li data-name="LuCI.form.DynamicList#ucisection"><a href="LuCI.form.DynamicList.html#ucisection">ucisection</a></li>
606 <li data-name="LuCI.form.DynamicList#validate"><a href="LuCI.form.DynamicList.html#validate">validate</a></li>
608 <li data-name="LuCI.form.DynamicList#width"><a href="LuCI.form.DynamicList.html#width">width</a></li>
611 <ul class="typedefs itemMembers">
614 <ul class="typedefs itemMembers">
617 <ul class="methods itemMembers">
619 <span class="subtitle">Methods</span>
621 <li data-name="LuCI.form.DynamicList#append"><a href="LuCI.form.DynamicList.html#append">append</a></li>
623 <li data-name="LuCI.form.DynamicList#cbid"><a href="LuCI.form.DynamicList.html#cbid">cbid</a></li>
625 <li data-name="LuCI.form.DynamicList#cfgvalue"><a href="LuCI.form.DynamicList.html#cfgvalue">cfgvalue</a></li>
627 <li data-name="LuCI.form.DynamicList#depends"><a href="LuCI.form.DynamicList.html#depends">depends</a></li>
629 <li data-name="LuCI.form.DynamicList#formvalue"><a href="LuCI.form.DynamicList.html#formvalue">formvalue</a></li>
631 <li data-name="LuCI.form.DynamicList#getUIElement"><a href="LuCI.form.DynamicList.html#getUIElement">getUIElement</a></li>
633 <li data-name="LuCI.form.DynamicList#isActive"><a href="LuCI.form.DynamicList.html#isActive">isActive</a></li>
635 <li data-name="LuCI.form.DynamicList#isValid"><a href="LuCI.form.DynamicList.html#isValid">isValid</a></li>
637 <li data-name="LuCI.form.DynamicList#load"><a href="LuCI.form.DynamicList.html#load">load</a></li>
639 <li data-name="LuCI.form.DynamicList#parse"><a href="LuCI.form.DynamicList.html#parse">parse</a></li>
641 <li data-name="LuCI.form.DynamicList#remove"><a href="LuCI.form.DynamicList.html#remove">remove</a></li>
643 <li data-name="LuCI.form.DynamicList#stripTags"><a href="LuCI.form.DynamicList.html#stripTags">stripTags</a></li>
645 <li data-name="LuCI.form.DynamicList#textvalue"><a href="LuCI.form.DynamicList.html#textvalue">textvalue</a></li>
647 <li data-name="LuCI.form.DynamicList#titleFn"><a href="LuCI.form.DynamicList.html#titleFn">titleFn</a></li>
649 <li data-name="LuCI.form.DynamicList#value"><a href="LuCI.form.DynamicList.html#value">value</a></li>
651 <li data-name="LuCI.form.DynamicList#write"><a href="LuCI.form.DynamicList.html#write">write</a></li>
654 <ul class="events itemMembers">
659 <li class="item" data-name="LuCI.form.FileUpload">
661 <a href="LuCI.form.FileUpload.html">LuCI.form.FileUpload</a>
664 <ul class="members itemMembers">
666 <span class="subtitle">Members</span>
668 <li data-name="LuCI.form.FileUpload##enable_remove"><a href="LuCI.form.FileUpload.html#enable_remove">enable_remove</a></li>
670 <li data-name="LuCI.form.FileUpload##enable_upload"><a href="LuCI.form.FileUpload.html#enable_upload">enable_upload</a></li>
672 <li data-name="LuCI.form.FileUpload##root_directory"><a href="LuCI.form.FileUpload.html#root_directory">root_directory</a></li>
674 <li data-name="LuCI.form.FileUpload##show_hidden"><a href="LuCI.form.FileUpload.html#show_hidden">show_hidden</a></li>
676 <li data-name="LuCI.form.FileUpload#datatype"><a href="LuCI.form.FileUpload.html#datatype">datatype</a></li>
678 <li data-name="LuCI.form.FileUpload#default"><a href="LuCI.form.FileUpload.html#default">default</a></li>
680 <li data-name="LuCI.form.FileUpload#editable"><a href="LuCI.form.FileUpload.html#editable">editable</a></li>
682 <li data-name="LuCI.form.FileUpload#modalonly"><a href="LuCI.form.FileUpload.html#modalonly">modalonly</a></li>
684 <li data-name="LuCI.form.FileUpload#optional"><a href="LuCI.form.FileUpload.html#optional">optional</a></li>
686 <li data-name="LuCI.form.FileUpload#password"><a href="LuCI.form.FileUpload.html#password">password</a></li>
688 <li data-name="LuCI.form.FileUpload#placeholder"><a href="LuCI.form.FileUpload.html#placeholder">placeholder</a></li>
690 <li data-name="LuCI.form.FileUpload#rmempty"><a href="LuCI.form.FileUpload.html#rmempty">rmempty</a></li>
692 <li data-name="LuCI.form.FileUpload#uciconfig"><a href="LuCI.form.FileUpload.html#uciconfig">uciconfig</a></li>
694 <li data-name="LuCI.form.FileUpload#ucioption"><a href="LuCI.form.FileUpload.html#ucioption">ucioption</a></li>
696 <li data-name="LuCI.form.FileUpload#ucisection"><a href="LuCI.form.FileUpload.html#ucisection">ucisection</a></li>
698 <li data-name="LuCI.form.FileUpload#validate"><a href="LuCI.form.FileUpload.html#validate">validate</a></li>
700 <li data-name="LuCI.form.FileUpload#width"><a href="LuCI.form.FileUpload.html#width">width</a></li>
703 <ul class="typedefs itemMembers">
706 <ul class="typedefs itemMembers">
709 <ul class="methods itemMembers">
711 <span class="subtitle">Methods</span>
713 <li data-name="LuCI.form.FileUpload#append"><a href="LuCI.form.FileUpload.html#append">append</a></li>
715 <li data-name="LuCI.form.FileUpload#cbid"><a href="LuCI.form.FileUpload.html#cbid">cbid</a></li>
717 <li data-name="LuCI.form.FileUpload#cfgvalue"><a href="LuCI.form.FileUpload.html#cfgvalue">cfgvalue</a></li>
719 <li data-name="LuCI.form.FileUpload#depends"><a href="LuCI.form.FileUpload.html#depends">depends</a></li>
721 <li data-name="LuCI.form.FileUpload#formvalue"><a href="LuCI.form.FileUpload.html#formvalue">formvalue</a></li>
723 <li data-name="LuCI.form.FileUpload#getUIElement"><a href="LuCI.form.FileUpload.html#getUIElement">getUIElement</a></li>
725 <li data-name="LuCI.form.FileUpload#isActive"><a href="LuCI.form.FileUpload.html#isActive">isActive</a></li>
727 <li data-name="LuCI.form.FileUpload#isValid"><a href="LuCI.form.FileUpload.html#isValid">isValid</a></li>
729 <li data-name="LuCI.form.FileUpload#load"><a href="LuCI.form.FileUpload.html#load">load</a></li>
731 <li data-name="LuCI.form.FileUpload#parse"><a href="LuCI.form.FileUpload.html#parse">parse</a></li>
733 <li data-name="LuCI.form.FileUpload#remove"><a href="LuCI.form.FileUpload.html#remove">remove</a></li>
735 <li data-name="LuCI.form.FileUpload#stripTags"><a href="LuCI.form.FileUpload.html#stripTags">stripTags</a></li>
737 <li data-name="LuCI.form.FileUpload#textvalue"><a href="LuCI.form.FileUpload.html#textvalue">textvalue</a></li>
739 <li data-name="LuCI.form.FileUpload#titleFn"><a href="LuCI.form.FileUpload.html#titleFn">titleFn</a></li>
741 <li data-name="LuCI.form.FileUpload#value"><a href="LuCI.form.FileUpload.html#value">value</a></li>
743 <li data-name="LuCI.form.FileUpload#write"><a href="LuCI.form.FileUpload.html#write">write</a></li>
746 <ul class="events itemMembers">
751 <li class="item" data-name="LuCI.form.FlagValue">
753 <a href="LuCI.form.FlagValue.html">LuCI.form.FlagValue</a>
756 <ul class="members itemMembers">
758 <span class="subtitle">Members</span>
760 <li data-name="LuCI.form.FlagValue##disabled"><a href="LuCI.form.FlagValue.html#disabled">disabled</a></li>
762 <li data-name="LuCI.form.FlagValue##enabled"><a href="LuCI.form.FlagValue.html#enabled">enabled</a></li>
764 <li data-name="LuCI.form.FlagValue#datatype"><a href="LuCI.form.FlagValue.html#datatype">datatype</a></li>
766 <li data-name="LuCI.form.FlagValue#default"><a href="LuCI.form.FlagValue.html#default">default</a></li>
768 <li data-name="LuCI.form.FlagValue#editable"><a href="LuCI.form.FlagValue.html#editable">editable</a></li>
770 <li data-name="LuCI.form.FlagValue#modalonly"><a href="LuCI.form.FlagValue.html#modalonly">modalonly</a></li>
772 <li data-name="LuCI.form.FlagValue#optional"><a href="LuCI.form.FlagValue.html#optional">optional</a></li>
774 <li data-name="LuCI.form.FlagValue#password"><a href="LuCI.form.FlagValue.html#password">password</a></li>
776 <li data-name="LuCI.form.FlagValue#placeholder"><a href="LuCI.form.FlagValue.html#placeholder">placeholder</a></li>
778 <li data-name="LuCI.form.FlagValue#rmempty"><a href="LuCI.form.FlagValue.html#rmempty">rmempty</a></li>
780 <li data-name="LuCI.form.FlagValue#uciconfig"><a href="LuCI.form.FlagValue.html#uciconfig">uciconfig</a></li>
782 <li data-name="LuCI.form.FlagValue#ucioption"><a href="LuCI.form.FlagValue.html#ucioption">ucioption</a></li>
784 <li data-name="LuCI.form.FlagValue#ucisection"><a href="LuCI.form.FlagValue.html#ucisection">ucisection</a></li>
786 <li data-name="LuCI.form.FlagValue#validate"><a href="LuCI.form.FlagValue.html#validate">validate</a></li>
788 <li data-name="LuCI.form.FlagValue#width"><a href="LuCI.form.FlagValue.html#width">width</a></li>
791 <ul class="typedefs itemMembers">
794 <ul class="typedefs itemMembers">
797 <ul class="methods itemMembers">
799 <span class="subtitle">Methods</span>
801 <li data-name="LuCI.form.FlagValue#append"><a href="LuCI.form.FlagValue.html#append">append</a></li>
803 <li data-name="LuCI.form.FlagValue#cbid"><a href="LuCI.form.FlagValue.html#cbid">cbid</a></li>
805 <li data-name="LuCI.form.FlagValue#cfgvalue"><a href="LuCI.form.FlagValue.html#cfgvalue">cfgvalue</a></li>
807 <li data-name="LuCI.form.FlagValue#depends"><a href="LuCI.form.FlagValue.html#depends">depends</a></li>
809 <li data-name="LuCI.form.FlagValue#formvalue"><a href="LuCI.form.FlagValue.html#formvalue">formvalue</a></li>
811 <li data-name="LuCI.form.FlagValue#getUIElement"><a href="LuCI.form.FlagValue.html#getUIElement">getUIElement</a></li>
813 <li data-name="LuCI.form.FlagValue#isActive"><a href="LuCI.form.FlagValue.html#isActive">isActive</a></li>
815 <li data-name="LuCI.form.FlagValue#isValid"><a href="LuCI.form.FlagValue.html#isValid">isValid</a></li>
817 <li data-name="LuCI.form.FlagValue#load"><a href="LuCI.form.FlagValue.html#load">load</a></li>
819 <li data-name="LuCI.form.FlagValue#parse"><a href="LuCI.form.FlagValue.html#parse">parse</a></li>
821 <li data-name="LuCI.form.FlagValue#remove"><a href="LuCI.form.FlagValue.html#remove">remove</a></li>
823 <li data-name="LuCI.form.FlagValue#stripTags"><a href="LuCI.form.FlagValue.html#stripTags">stripTags</a></li>
825 <li data-name="LuCI.form.FlagValue#textvalue"><a href="LuCI.form.FlagValue.html#textvalue">textvalue</a></li>
827 <li data-name="LuCI.form.FlagValue#titleFn"><a href="LuCI.form.FlagValue.html#titleFn">titleFn</a></li>
829 <li data-name="LuCI.form.FlagValue#value"><a href="LuCI.form.FlagValue.html#value">value</a></li>
831 <li data-name="LuCI.form.FlagValue#write"><a href="LuCI.form.FlagValue.html#write">write</a></li>
834 <ul class="events itemMembers">
839 <li class="item" data-name="LuCI.form.GridSection">
841 <a href="LuCI.form.GridSection.html">LuCI.form.GridSection</a>
844 <ul class="members itemMembers">
846 <span class="subtitle">Members</span>
848 <li data-name="LuCI.form.GridSection#addbtntitle"><a href="LuCI.form.GridSection.html#addbtntitle">addbtntitle</a></li>
850 <li data-name="LuCI.form.GridSection#addremove"><a href="LuCI.form.GridSection.html#addremove">addremove</a></li>
852 <li data-name="LuCI.form.GridSection#anonymous"><a href="LuCI.form.GridSection.html#anonymous">anonymous</a></li>
854 <li data-name="LuCI.form.GridSection#extedit"><a href="LuCI.form.GridSection.html#extedit">extedit</a></li>
856 <li data-name="LuCI.form.GridSection#max_cols"><a href="LuCI.form.GridSection.html#max_cols">max_cols</a></li>
858 <li data-name="LuCI.form.GridSection#modaltitle"><a href="LuCI.form.GridSection.html#modaltitle">modaltitle</a></li>
860 <li data-name="LuCI.form.GridSection#parentoption"><a href="LuCI.form.GridSection.html#parentoption">parentoption</a></li>
862 <li data-name="LuCI.form.GridSection#rowcolors"><a href="LuCI.form.GridSection.html#rowcolors">rowcolors</a></li>
864 <li data-name="LuCI.form.GridSection#sectiontitle"><a href="LuCI.form.GridSection.html#sectiontitle">sectiontitle</a></li>
866 <li data-name="LuCI.form.GridSection#sortable"><a href="LuCI.form.GridSection.html#sortable">sortable</a></li>
868 <li data-name="LuCI.form.GridSection#tabbed"><a href="LuCI.form.GridSection.html#tabbed">tabbed</a></li>
870 <li data-name="LuCI.form.GridSection#uciconfig"><a href="LuCI.form.GridSection.html#uciconfig">uciconfig</a></li>
873 <ul class="typedefs itemMembers">
876 <ul class="typedefs itemMembers">
879 <ul class="methods itemMembers">
881 <span class="subtitle">Methods</span>
883 <li data-name="LuCI.form.GridSection#addModalOptions"><a href="LuCI.form.GridSection.html#addModalOptions">addModalOptions</a></li>
885 <li data-name="LuCI.form.GridSection#append"><a href="LuCI.form.GridSection.html#append">append</a></li>
887 <li data-name="LuCI.form.GridSection#filter"><a href="LuCI.form.GridSection.html#filter">filter</a></li>
889 <li data-name="LuCI.form.GridSection#load"><a href="LuCI.form.GridSection.html#load">load</a></li>
891 <li data-name="LuCI.form.GridSection#option"><a href="LuCI.form.GridSection.html#option">option</a></li>
893 <li data-name="LuCI.form.GridSection#parse"><a href="LuCI.form.GridSection.html#parse">parse</a></li>
895 <li data-name="LuCI.form.GridSection#stripTags"><a href="LuCI.form.GridSection.html#stripTags">stripTags</a></li>
897 <li data-name="LuCI.form.GridSection#tab"><a href="LuCI.form.GridSection.html#tab">tab</a></li>
899 <li data-name="LuCI.form.GridSection#taboption"><a href="LuCI.form.GridSection.html#taboption">taboption</a></li>
901 <li data-name="LuCI.form.GridSection#titleFn"><a href="LuCI.form.GridSection.html#titleFn">titleFn</a></li>
904 <ul class="events itemMembers">
909 <li class="item" data-name="LuCI.form.HiddenValue">
911 <a href="LuCI.form.HiddenValue.html">LuCI.form.HiddenValue</a>
914 <ul class="members itemMembers">
916 <span class="subtitle">Members</span>
918 <li data-name="LuCI.form.HiddenValue#datatype"><a href="LuCI.form.HiddenValue.html#datatype">datatype</a></li>
920 <li data-name="LuCI.form.HiddenValue#default"><a href="LuCI.form.HiddenValue.html#default">default</a></li>
922 <li data-name="LuCI.form.HiddenValue#editable"><a href="LuCI.form.HiddenValue.html#editable">editable</a></li>
924 <li data-name="LuCI.form.HiddenValue#modalonly"><a href="LuCI.form.HiddenValue.html#modalonly">modalonly</a></li>
926 <li data-name="LuCI.form.HiddenValue#optional"><a href="LuCI.form.HiddenValue.html#optional">optional</a></li>
928 <li data-name="LuCI.form.HiddenValue#password"><a href="LuCI.form.HiddenValue.html#password">password</a></li>
930 <li data-name="LuCI.form.HiddenValue#placeholder"><a href="LuCI.form.HiddenValue.html#placeholder">placeholder</a></li>
932 <li data-name="LuCI.form.HiddenValue#rmempty"><a href="LuCI.form.HiddenValue.html#rmempty">rmempty</a></li>
934 <li data-name="LuCI.form.HiddenValue#uciconfig"><a href="LuCI.form.HiddenValue.html#uciconfig">uciconfig</a></li>
936 <li data-name="LuCI.form.HiddenValue#ucioption"><a href="LuCI.form.HiddenValue.html#ucioption">ucioption</a></li>
938 <li data-name="LuCI.form.HiddenValue#ucisection"><a href="LuCI.form.HiddenValue.html#ucisection">ucisection</a></li>
940 <li data-name="LuCI.form.HiddenValue#validate"><a href="LuCI.form.HiddenValue.html#validate">validate</a></li>
942 <li data-name="LuCI.form.HiddenValue#width"><a href="LuCI.form.HiddenValue.html#width">width</a></li>
945 <ul class="typedefs itemMembers">
948 <ul class="typedefs itemMembers">
951 <ul class="methods itemMembers">
953 <span class="subtitle">Methods</span>
955 <li data-name="LuCI.form.HiddenValue#append"><a href="LuCI.form.HiddenValue.html#append">append</a></li>
957 <li data-name="LuCI.form.HiddenValue#cbid"><a href="LuCI.form.HiddenValue.html#cbid">cbid</a></li>
959 <li data-name="LuCI.form.HiddenValue#cfgvalue"><a href="LuCI.form.HiddenValue.html#cfgvalue">cfgvalue</a></li>
961 <li data-name="LuCI.form.HiddenValue#depends"><a href="LuCI.form.HiddenValue.html#depends">depends</a></li>
963 <li data-name="LuCI.form.HiddenValue#formvalue"><a href="LuCI.form.HiddenValue.html#formvalue">formvalue</a></li>
965 <li data-name="LuCI.form.HiddenValue#getUIElement"><a href="LuCI.form.HiddenValue.html#getUIElement">getUIElement</a></li>
967 <li data-name="LuCI.form.HiddenValue#isActive"><a href="LuCI.form.HiddenValue.html#isActive">isActive</a></li>
969 <li data-name="LuCI.form.HiddenValue#isValid"><a href="LuCI.form.HiddenValue.html#isValid">isValid</a></li>
971 <li data-name="LuCI.form.HiddenValue#load"><a href="LuCI.form.HiddenValue.html#load">load</a></li>
973 <li data-name="LuCI.form.HiddenValue#parse"><a href="LuCI.form.HiddenValue.html#parse">parse</a></li>
975 <li data-name="LuCI.form.HiddenValue#remove"><a href="LuCI.form.HiddenValue.html#remove">remove</a></li>
977 <li data-name="LuCI.form.HiddenValue#stripTags"><a href="LuCI.form.HiddenValue.html#stripTags">stripTags</a></li>
979 <li data-name="LuCI.form.HiddenValue#textvalue"><a href="LuCI.form.HiddenValue.html#textvalue">textvalue</a></li>
981 <li data-name="LuCI.form.HiddenValue#titleFn"><a href="LuCI.form.HiddenValue.html#titleFn">titleFn</a></li>
983 <li data-name="LuCI.form.HiddenValue#value"><a href="LuCI.form.HiddenValue.html#value">value</a></li>
985 <li data-name="LuCI.form.HiddenValue#write"><a href="LuCI.form.HiddenValue.html#write">write</a></li>
988 <ul class="events itemMembers">
993 <li class="item" data-name="LuCI.form.JSONMap">
995 <a href="LuCI.form.JSONMap.html">LuCI.form.JSONMap</a>
998 <ul class="members itemMembers">
1001 <ul class="typedefs itemMembers">
1004 <ul class="typedefs itemMembers">
1007 <ul class="methods itemMembers">
1009 <span class="subtitle">Methods</span>
1011 <li data-name="LuCI.form.JSONMap#append"><a href="LuCI.form.JSONMap.html#append">append</a></li>
1013 <li data-name="LuCI.form.JSONMap#chain"><a href="LuCI.form.JSONMap.html#chain">chain</a></li>
1015 <li data-name="LuCI.form.JSONMap#findElement"><a href="LuCI.form.JSONMap.html#findElement">findElement</a></li>
1017 <li data-name="LuCI.form.JSONMap#findElements"><a href="LuCI.form.JSONMap.html#findElements">findElements</a></li>
1019 <li data-name="LuCI.form.JSONMap#load"><a href="LuCI.form.JSONMap.html#load">load</a></li>
1021 <li data-name="LuCI.form.JSONMap#lookupOption"><a href="LuCI.form.JSONMap.html#lookupOption">lookupOption</a></li>
1023 <li data-name="LuCI.form.JSONMap#parse"><a href="LuCI.form.JSONMap.html#parse">parse</a></li>
1025 <li data-name="LuCI.form.JSONMap#render"><a href="LuCI.form.JSONMap.html#render">render</a></li>
1027 <li data-name="LuCI.form.JSONMap#reset"><a href="LuCI.form.JSONMap.html#reset">reset</a></li>
1029 <li data-name="LuCI.form.JSONMap#save"><a href="LuCI.form.JSONMap.html#save">save</a></li>
1031 <li data-name="LuCI.form.JSONMap#section"><a href="LuCI.form.JSONMap.html#section">section</a></li>
1033 <li data-name="LuCI.form.JSONMap#stripTags"><a href="LuCI.form.JSONMap.html#stripTags">stripTags</a></li>
1035 <li data-name="LuCI.form.JSONMap#titleFn"><a href="LuCI.form.JSONMap.html#titleFn">titleFn</a></li>
1038 <ul class="events itemMembers">
1043 <li class="item" data-name="LuCI.form.ListValue">
1044 <span class="title">
1045 <a href="LuCI.form.ListValue.html">LuCI.form.ListValue</a>
1048 <ul class="members itemMembers">
1050 <span class="subtitle">Members</span>
1052 <li data-name="LuCI.form.ListValue##size"><a href="LuCI.form.ListValue.html#size">size</a></li>
1054 <li data-name="LuCI.form.ListValue#datatype"><a href="LuCI.form.ListValue.html#datatype">datatype</a></li>
1056 <li data-name="LuCI.form.ListValue#default"><a href="LuCI.form.ListValue.html#default">default</a></li>
1058 <li data-name="LuCI.form.ListValue#editable"><a href="LuCI.form.ListValue.html#editable">editable</a></li>
1060 <li data-name="LuCI.form.ListValue#modalonly"><a href="LuCI.form.ListValue.html#modalonly">modalonly</a></li>
1062 <li data-name="LuCI.form.ListValue#optional"><a href="LuCI.form.ListValue.html#optional">optional</a></li>
1064 <li data-name="LuCI.form.ListValue#password"><a href="LuCI.form.ListValue.html#password">password</a></li>
1066 <li data-name="LuCI.form.ListValue#placeholder"><a href="LuCI.form.ListValue.html#placeholder">placeholder</a></li>
1068 <li data-name="LuCI.form.ListValue#rmempty"><a href="LuCI.form.ListValue.html#rmempty">rmempty</a></li>
1070 <li data-name="LuCI.form.ListValue#uciconfig"><a href="LuCI.form.ListValue.html#uciconfig">uciconfig</a></li>
1072 <li data-name="LuCI.form.ListValue#ucioption"><a href="LuCI.form.ListValue.html#ucioption">ucioption</a></li>
1074 <li data-name="LuCI.form.ListValue#ucisection"><a href="LuCI.form.ListValue.html#ucisection">ucisection</a></li>
1076 <li data-name="LuCI.form.ListValue#validate"><a href="LuCI.form.ListValue.html#validate">validate</a></li>
1078 <li data-name="LuCI.form.ListValue#width"><a href="LuCI.form.ListValue.html#width">width</a></li>
1081 <ul class="typedefs itemMembers">
1084 <ul class="typedefs itemMembers">
1087 <ul class="methods itemMembers">
1089 <span class="subtitle">Methods</span>
1091 <li data-name="LuCI.form.ListValue#append"><a href="LuCI.form.ListValue.html#append">append</a></li>
1093 <li data-name="LuCI.form.ListValue#cbid"><a href="LuCI.form.ListValue.html#cbid">cbid</a></li>
1095 <li data-name="LuCI.form.ListValue#cfgvalue"><a href="LuCI.form.ListValue.html#cfgvalue">cfgvalue</a></li>
1097 <li data-name="LuCI.form.ListValue#depends"><a href="LuCI.form.ListValue.html#depends">depends</a></li>
1099 <li data-name="LuCI.form.ListValue#formvalue"><a href="LuCI.form.ListValue.html#formvalue">formvalue</a></li>
1101 <li data-name="LuCI.form.ListValue#getUIElement"><a href="LuCI.form.ListValue.html#getUIElement">getUIElement</a></li>
1103 <li data-name="LuCI.form.ListValue#isActive"><a href="LuCI.form.ListValue.html#isActive">isActive</a></li>
1105 <li data-name="LuCI.form.ListValue#isValid"><a href="LuCI.form.ListValue.html#isValid">isValid</a></li>
1107 <li data-name="LuCI.form.ListValue#load"><a href="LuCI.form.ListValue.html#load">load</a></li>
1109 <li data-name="LuCI.form.ListValue#parse"><a href="LuCI.form.ListValue.html#parse">parse</a></li>
1111 <li data-name="LuCI.form.ListValue#remove"><a href="LuCI.form.ListValue.html#remove">remove</a></li>
1113 <li data-name="LuCI.form.ListValue#stripTags"><a href="LuCI.form.ListValue.html#stripTags">stripTags</a></li>
1115 <li data-name="LuCI.form.ListValue#textvalue"><a href="LuCI.form.ListValue.html#textvalue">textvalue</a></li>
1117 <li data-name="LuCI.form.ListValue#titleFn"><a href="LuCI.form.ListValue.html#titleFn">titleFn</a></li>
1119 <li data-name="LuCI.form.ListValue#value"><a href="LuCI.form.ListValue.html#value">value</a></li>
1121 <li data-name="LuCI.form.ListValue#write"><a href="LuCI.form.ListValue.html#write">write</a></li>
1124 <ul class="events itemMembers">
1129 <li class="item" data-name="LuCI.form.Map">
1130 <span class="title">
1131 <a href="LuCI.form.Map.html">LuCI.form.Map</a>
1134 <ul class="members itemMembers">
1137 <ul class="typedefs itemMembers">
1140 <ul class="typedefs itemMembers">
1143 <ul class="methods itemMembers">
1145 <span class="subtitle">Methods</span>
1147 <li data-name="LuCI.form.Map#append"><a href="LuCI.form.Map.html#append">append</a></li>
1149 <li data-name="LuCI.form.Map#chain"><a href="LuCI.form.Map.html#chain">chain</a></li>
1151 <li data-name="LuCI.form.Map#findElement"><a href="LuCI.form.Map.html#findElement">findElement</a></li>
1153 <li data-name="LuCI.form.Map#findElements"><a href="LuCI.form.Map.html#findElements">findElements</a></li>
1155 <li data-name="LuCI.form.Map#load"><a href="LuCI.form.Map.html#load">load</a></li>
1157 <li data-name="LuCI.form.Map#lookupOption"><a href="LuCI.form.Map.html#lookupOption">lookupOption</a></li>
1159 <li data-name="LuCI.form.Map#parse"><a href="LuCI.form.Map.html#parse">parse</a></li>
1161 <li data-name="LuCI.form.Map#render"><a href="LuCI.form.Map.html#render">render</a></li>
1163 <li data-name="LuCI.form.Map#reset"><a href="LuCI.form.Map.html#reset">reset</a></li>
1165 <li data-name="LuCI.form.Map#save"><a href="LuCI.form.Map.html#save">save</a></li>
1167 <li data-name="LuCI.form.Map#section"><a href="LuCI.form.Map.html#section">section</a></li>
1169 <li data-name="LuCI.form.Map#stripTags"><a href="LuCI.form.Map.html#stripTags">stripTags</a></li>
1171 <li data-name="LuCI.form.Map#titleFn"><a href="LuCI.form.Map.html#titleFn">titleFn</a></li>
1174 <ul class="events itemMembers">
1179 <li class="item" data-name="LuCI.form.MultiValue">
1180 <span class="title">
1181 <a href="LuCI.form.MultiValue.html">LuCI.form.MultiValue</a>
1184 <ul class="members itemMembers">
1186 <span class="subtitle">Members</span>
1188 <li data-name="LuCI.form.MultiValue##display_size"><a href="LuCI.form.MultiValue.html#display_size">display_size</a></li>
1190 <li data-name="LuCI.form.MultiValue##dropdown_size"><a href="LuCI.form.MultiValue.html#dropdown_size">dropdown_size</a></li>
1192 <li data-name="LuCI.form.MultiValue#datatype"><a href="LuCI.form.MultiValue.html#datatype">datatype</a></li>
1194 <li data-name="LuCI.form.MultiValue#default"><a href="LuCI.form.MultiValue.html#default">default</a></li>
1196 <li data-name="LuCI.form.MultiValue#editable"><a href="LuCI.form.MultiValue.html#editable">editable</a></li>
1198 <li data-name="LuCI.form.MultiValue#modalonly"><a href="LuCI.form.MultiValue.html#modalonly">modalonly</a></li>
1200 <li data-name="LuCI.form.MultiValue#optional"><a href="LuCI.form.MultiValue.html#optional">optional</a></li>
1202 <li data-name="LuCI.form.MultiValue#password"><a href="LuCI.form.MultiValue.html#password">password</a></li>
1204 <li data-name="LuCI.form.MultiValue#placeholder"><a href="LuCI.form.MultiValue.html#placeholder">placeholder</a></li>
1206 <li data-name="LuCI.form.MultiValue#rmempty"><a href="LuCI.form.MultiValue.html#rmempty">rmempty</a></li>
1208 <li data-name="LuCI.form.MultiValue#uciconfig"><a href="LuCI.form.MultiValue.html#uciconfig">uciconfig</a></li>
1210 <li data-name="LuCI.form.MultiValue#ucioption"><a href="LuCI.form.MultiValue.html#ucioption">ucioption</a></li>
1212 <li data-name="LuCI.form.MultiValue#ucisection"><a href="LuCI.form.MultiValue.html#ucisection">ucisection</a></li>
1214 <li data-name="LuCI.form.MultiValue#validate"><a href="LuCI.form.MultiValue.html#validate">validate</a></li>
1216 <li data-name="LuCI.form.MultiValue#width"><a href="LuCI.form.MultiValue.html#width">width</a></li>
1219 <ul class="typedefs itemMembers">
1222 <ul class="typedefs itemMembers">
1225 <ul class="methods itemMembers">
1227 <span class="subtitle">Methods</span>
1229 <li data-name="LuCI.form.MultiValue#append"><a href="LuCI.form.MultiValue.html#append">append</a></li>
1231 <li data-name="LuCI.form.MultiValue#cbid"><a href="LuCI.form.MultiValue.html#cbid">cbid</a></li>
1233 <li data-name="LuCI.form.MultiValue#cfgvalue"><a href="LuCI.form.MultiValue.html#cfgvalue">cfgvalue</a></li>
1235 <li data-name="LuCI.form.MultiValue#depends"><a href="LuCI.form.MultiValue.html#depends">depends</a></li>
1237 <li data-name="LuCI.form.MultiValue#formvalue"><a href="LuCI.form.MultiValue.html#formvalue">formvalue</a></li>
1239 <li data-name="LuCI.form.MultiValue#getUIElement"><a href="LuCI.form.MultiValue.html#getUIElement">getUIElement</a></li>
1241 <li data-name="LuCI.form.MultiValue#isActive"><a href="LuCI.form.MultiValue.html#isActive">isActive</a></li>
1243 <li data-name="LuCI.form.MultiValue#isValid"><a href="LuCI.form.MultiValue.html#isValid">isValid</a></li>
1245 <li data-name="LuCI.form.MultiValue#load"><a href="LuCI.form.MultiValue.html#load">load</a></li>
1247 <li data-name="LuCI.form.MultiValue#parse"><a href="LuCI.form.MultiValue.html#parse">parse</a></li>
1249 <li data-name="LuCI.form.MultiValue#remove"><a href="LuCI.form.MultiValue.html#remove">remove</a></li>
1251 <li data-name="LuCI.form.MultiValue#stripTags"><a href="LuCI.form.MultiValue.html#stripTags">stripTags</a></li>
1253 <li data-name="LuCI.form.MultiValue#textvalue"><a href="LuCI.form.MultiValue.html#textvalue">textvalue</a></li>
1255 <li data-name="LuCI.form.MultiValue#titleFn"><a href="LuCI.form.MultiValue.html#titleFn">titleFn</a></li>
1257 <li data-name="LuCI.form.MultiValue#value"><a href="LuCI.form.MultiValue.html#value">value</a></li>
1259 <li data-name="LuCI.form.MultiValue#write"><a href="LuCI.form.MultiValue.html#write">write</a></li>
1262 <ul class="events itemMembers">
1267 <li class="item" data-name="LuCI.form.NamedSection">
1268 <span class="title">
1269 <a href="LuCI.form.NamedSection.html">LuCI.form.NamedSection</a>
1272 <ul class="members itemMembers">
1274 <span class="subtitle">Members</span>
1276 <li data-name="LuCI.form.NamedSection##addremove"><a href="LuCI.form.NamedSection.html#addremove">addremove</a></li>
1278 <li data-name="LuCI.form.NamedSection##uciconfig"><a href="LuCI.form.NamedSection.html#uciconfig">uciconfig</a></li>
1280 <li data-name="LuCI.form.NamedSection#parentoption"><a href="LuCI.form.NamedSection.html#parentoption">parentoption</a></li>
1283 <ul class="typedefs itemMembers">
1286 <ul class="typedefs itemMembers">
1289 <ul class="methods itemMembers">
1291 <span class="subtitle">Methods</span>
1293 <li data-name="LuCI.form.NamedSection#append"><a href="LuCI.form.NamedSection.html#append">append</a></li>
1295 <li data-name="LuCI.form.NamedSection#cfgsections"><a href="LuCI.form.NamedSection.html#cfgsections">cfgsections</a></li>
1297 <li data-name="LuCI.form.NamedSection#filter"><a href="LuCI.form.NamedSection.html#filter">filter</a></li>
1299 <li data-name="LuCI.form.NamedSection#load"><a href="LuCI.form.NamedSection.html#load">load</a></li>
1301 <li data-name="LuCI.form.NamedSection#option"><a href="LuCI.form.NamedSection.html#option">option</a></li>
1303 <li data-name="LuCI.form.NamedSection#parse"><a href="LuCI.form.NamedSection.html#parse">parse</a></li>
1305 <li data-name="LuCI.form.NamedSection#render"><a href="LuCI.form.NamedSection.html#render">render</a></li>
1307 <li data-name="LuCI.form.NamedSection#stripTags"><a href="LuCI.form.NamedSection.html#stripTags">stripTags</a></li>
1309 <li data-name="LuCI.form.NamedSection#tab"><a href="LuCI.form.NamedSection.html#tab">tab</a></li>
1311 <li data-name="LuCI.form.NamedSection#taboption"><a href="LuCI.form.NamedSection.html#taboption">taboption</a></li>
1313 <li data-name="LuCI.form.NamedSection#titleFn"><a href="LuCI.form.NamedSection.html#titleFn">titleFn</a></li>
1316 <ul class="events itemMembers">
1321 <li class="item" data-name="LuCI.form.SectionValue">
1322 <span class="title">
1323 <a href="LuCI.form.SectionValue.html">LuCI.form.SectionValue</a>
1326 <ul class="members itemMembers">
1328 <span class="subtitle">Members</span>
1330 <li data-name="LuCI.form.SectionValue##subsection"><a href="LuCI.form.SectionValue.html#subsection">subsection</a></li>
1332 <li data-name="LuCI.form.SectionValue#datatype"><a href="LuCI.form.SectionValue.html#datatype">datatype</a></li>
1334 <li data-name="LuCI.form.SectionValue#default"><a href="LuCI.form.SectionValue.html#default">default</a></li>
1336 <li data-name="LuCI.form.SectionValue#editable"><a href="LuCI.form.SectionValue.html#editable">editable</a></li>
1338 <li data-name="LuCI.form.SectionValue#modalonly"><a href="LuCI.form.SectionValue.html#modalonly">modalonly</a></li>
1340 <li data-name="LuCI.form.SectionValue#optional"><a href="LuCI.form.SectionValue.html#optional">optional</a></li>
1342 <li data-name="LuCI.form.SectionValue#password"><a href="LuCI.form.SectionValue.html#password">password</a></li>
1344 <li data-name="LuCI.form.SectionValue#placeholder"><a href="LuCI.form.SectionValue.html#placeholder">placeholder</a></li>
1346 <li data-name="LuCI.form.SectionValue#rmempty"><a href="LuCI.form.SectionValue.html#rmempty">rmempty</a></li>
1348 <li data-name="LuCI.form.SectionValue#uciconfig"><a href="LuCI.form.SectionValue.html#uciconfig">uciconfig</a></li>
1350 <li data-name="LuCI.form.SectionValue#ucioption"><a href="LuCI.form.SectionValue.html#ucioption">ucioption</a></li>
1352 <li data-name="LuCI.form.SectionValue#ucisection"><a href="LuCI.form.SectionValue.html#ucisection">ucisection</a></li>
1354 <li data-name="LuCI.form.SectionValue#validate"><a href="LuCI.form.SectionValue.html#validate">validate</a></li>
1356 <li data-name="LuCI.form.SectionValue#width"><a href="LuCI.form.SectionValue.html#width">width</a></li>
1359 <ul class="typedefs itemMembers">
1362 <ul class="typedefs itemMembers">
1365 <ul class="methods itemMembers">
1367 <span class="subtitle">Methods</span>
1369 <li data-name="LuCI.form.SectionValue#append"><a href="LuCI.form.SectionValue.html#append">append</a></li>
1371 <li data-name="LuCI.form.SectionValue#cbid"><a href="LuCI.form.SectionValue.html#cbid">cbid</a></li>
1373 <li data-name="LuCI.form.SectionValue#cfgvalue"><a href="LuCI.form.SectionValue.html#cfgvalue">cfgvalue</a></li>
1375 <li data-name="LuCI.form.SectionValue#depends"><a href="LuCI.form.SectionValue.html#depends">depends</a></li>
1377 <li data-name="LuCI.form.SectionValue#formvalue"><a href="LuCI.form.SectionValue.html#formvalue">formvalue</a></li>
1379 <li data-name="LuCI.form.SectionValue#getUIElement"><a href="LuCI.form.SectionValue.html#getUIElement">getUIElement</a></li>
1381 <li data-name="LuCI.form.SectionValue#isActive"><a href="LuCI.form.SectionValue.html#isActive">isActive</a></li>
1383 <li data-name="LuCI.form.SectionValue#isValid"><a href="LuCI.form.SectionValue.html#isValid">isValid</a></li>
1385 <li data-name="LuCI.form.SectionValue#load"><a href="LuCI.form.SectionValue.html#load">load</a></li>
1387 <li data-name="LuCI.form.SectionValue#parse"><a href="LuCI.form.SectionValue.html#parse">parse</a></li>
1389 <li data-name="LuCI.form.SectionValue#remove"><a href="LuCI.form.SectionValue.html#remove">remove</a></li>
1391 <li data-name="LuCI.form.SectionValue#stripTags"><a href="LuCI.form.SectionValue.html#stripTags">stripTags</a></li>
1393 <li data-name="LuCI.form.SectionValue#textvalue"><a href="LuCI.form.SectionValue.html#textvalue">textvalue</a></li>
1395 <li data-name="LuCI.form.SectionValue#titleFn"><a href="LuCI.form.SectionValue.html#titleFn">titleFn</a></li>
1397 <li data-name="LuCI.form.SectionValue#value"><a href="LuCI.form.SectionValue.html#value">value</a></li>
1399 <li data-name="LuCI.form.SectionValue#write"><a href="LuCI.form.SectionValue.html#write">write</a></li>
1402 <ul class="events itemMembers">
1407 <li class="item" data-name="LuCI.form.TableSection">
1408 <span class="title">
1409 <a href="LuCI.form.TableSection.html">LuCI.form.TableSection</a>
1412 <ul class="members itemMembers">
1414 <span class="subtitle">Members</span>
1416 <li data-name="LuCI.form.TableSection##addbtntitle"><a href="LuCI.form.TableSection.html#addbtntitle">addbtntitle</a></li>
1418 <li data-name="LuCI.form.TableSection##addremove"><a href="LuCI.form.TableSection.html#addremove">addremove</a></li>
1420 <li data-name="LuCI.form.TableSection##anonymous"><a href="LuCI.form.TableSection.html#anonymous">anonymous</a></li>
1422 <li data-name="LuCI.form.TableSection##extedit"><a href="LuCI.form.TableSection.html#extedit">extedit</a></li>
1424 <li data-name="LuCI.form.TableSection##max_cols"><a href="LuCI.form.TableSection.html#max_cols">max_cols</a></li>
1426 <li data-name="LuCI.form.TableSection##modaltitle"><a href="LuCI.form.TableSection.html#modaltitle">modaltitle</a></li>
1428 <li data-name="LuCI.form.TableSection##rowcolors"><a href="LuCI.form.TableSection.html#rowcolors">rowcolors</a></li>
1430 <li data-name="LuCI.form.TableSection##sectiontitle"><a href="LuCI.form.TableSection.html#sectiontitle">sectiontitle</a></li>
1432 <li data-name="LuCI.form.TableSection##sortable"><a href="LuCI.form.TableSection.html#sortable">sortable</a></li>
1434 <li data-name="LuCI.form.TableSection##uciconfig"><a href="LuCI.form.TableSection.html#uciconfig">uciconfig</a></li>
1436 <li data-name="LuCI.form.TableSection#addbtntitle"><a href="LuCI.form.TableSection.html#addbtntitle">addbtntitle</a></li>
1438 <li data-name="LuCI.form.TableSection#addremove"><a href="LuCI.form.TableSection.html#addremove">addremove</a></li>
1440 <li data-name="LuCI.form.TableSection#anonymous"><a href="LuCI.form.TableSection.html#anonymous">anonymous</a></li>
1442 <li data-name="LuCI.form.TableSection#parentoption"><a href="LuCI.form.TableSection.html#parentoption">parentoption</a></li>
1444 <li data-name="LuCI.form.TableSection#tabbed"><a href="LuCI.form.TableSection.html#tabbed">tabbed</a></li>
1446 <li data-name="LuCI.form.TableSection#uciconfig"><a href="LuCI.form.TableSection.html#uciconfig">uciconfig</a></li>
1449 <ul class="typedefs itemMembers">
1452 <ul class="typedefs itemMembers">
1455 <ul class="methods itemMembers">
1457 <span class="subtitle">Methods</span>
1459 <li data-name="LuCI.form.TableSection#addModalOptions"><a href="LuCI.form.TableSection.html#addModalOptions">addModalOptions</a></li>
1461 <li data-name="LuCI.form.TableSection#append"><a href="LuCI.form.TableSection.html#append">append</a></li>
1463 <li data-name="LuCI.form.TableSection#filter"><a href="LuCI.form.TableSection.html#filter">filter</a></li>
1465 <li data-name="LuCI.form.TableSection#load"><a href="LuCI.form.TableSection.html#load">load</a></li>
1467 <li data-name="LuCI.form.TableSection#option"><a href="LuCI.form.TableSection.html#option">option</a></li>
1469 <li data-name="LuCI.form.TableSection#parse"><a href="LuCI.form.TableSection.html#parse">parse</a></li>
1471 <li data-name="LuCI.form.TableSection#stripTags"><a href="LuCI.form.TableSection.html#stripTags">stripTags</a></li>
1473 <li data-name="LuCI.form.TableSection#tab"><a href="LuCI.form.TableSection.html#tab">tab</a></li>
1475 <li data-name="LuCI.form.TableSection#taboption"><a href="LuCI.form.TableSection.html#taboption">taboption</a></li>
1477 <li data-name="LuCI.form.TableSection#titleFn"><a href="LuCI.form.TableSection.html#titleFn">titleFn</a></li>
1480 <ul class="events itemMembers">
1485 <li class="item" data-name="LuCI.form.TextValue">
1486 <span class="title">
1487 <a href="LuCI.form.TextValue.html">LuCI.form.TextValue</a>
1490 <ul class="members itemMembers">
1492 <span class="subtitle">Members</span>
1494 <li data-name="LuCI.form.TextValue##cols"><a href="LuCI.form.TextValue.html#cols">cols</a></li>
1496 <li data-name="LuCI.form.TextValue##monospace"><a href="LuCI.form.TextValue.html#monospace">monospace</a></li>
1498 <li data-name="LuCI.form.TextValue##rows"><a href="LuCI.form.TextValue.html#rows">rows</a></li>
1500 <li data-name="LuCI.form.TextValue##wrap"><a href="LuCI.form.TextValue.html#wrap">wrap</a></li>
1502 <li data-name="LuCI.form.TextValue#datatype"><a href="LuCI.form.TextValue.html#datatype">datatype</a></li>
1504 <li data-name="LuCI.form.TextValue#default"><a href="LuCI.form.TextValue.html#default">default</a></li>
1506 <li data-name="LuCI.form.TextValue#editable"><a href="LuCI.form.TextValue.html#editable">editable</a></li>
1508 <li data-name="LuCI.form.TextValue#modalonly"><a href="LuCI.form.TextValue.html#modalonly">modalonly</a></li>
1510 <li data-name="LuCI.form.TextValue#optional"><a href="LuCI.form.TextValue.html#optional">optional</a></li>
1512 <li data-name="LuCI.form.TextValue#password"><a href="LuCI.form.TextValue.html#password">password</a></li>
1514 <li data-name="LuCI.form.TextValue#placeholder"><a href="LuCI.form.TextValue.html#placeholder">placeholder</a></li>
1516 <li data-name="LuCI.form.TextValue#rmempty"><a href="LuCI.form.TextValue.html#rmempty">rmempty</a></li>
1518 <li data-name="LuCI.form.TextValue#uciconfig"><a href="LuCI.form.TextValue.html#uciconfig">uciconfig</a></li>
1520 <li data-name="LuCI.form.TextValue#ucioption"><a href="LuCI.form.TextValue.html#ucioption">ucioption</a></li>
1522 <li data-name="LuCI.form.TextValue#ucisection"><a href="LuCI.form.TextValue.html#ucisection">ucisection</a></li>
1524 <li data-name="LuCI.form.TextValue#validate"><a href="LuCI.form.TextValue.html#validate">validate</a></li>
1526 <li data-name="LuCI.form.TextValue#width"><a href="LuCI.form.TextValue.html#width">width</a></li>
1529 <ul class="typedefs itemMembers">
1532 <ul class="typedefs itemMembers">
1535 <ul class="methods itemMembers">
1537 <span class="subtitle">Methods</span>
1539 <li data-name="LuCI.form.TextValue#append"><a href="LuCI.form.TextValue.html#append">append</a></li>
1541 <li data-name="LuCI.form.TextValue#cbid"><a href="LuCI.form.TextValue.html#cbid">cbid</a></li>
1543 <li data-name="LuCI.form.TextValue#cfgvalue"><a href="LuCI.form.TextValue.html#cfgvalue">cfgvalue</a></li>
1545 <li data-name="LuCI.form.TextValue#depends"><a href="LuCI.form.TextValue.html#depends">depends</a></li>
1547 <li data-name="LuCI.form.TextValue#formvalue"><a href="LuCI.form.TextValue.html#formvalue">formvalue</a></li>
1549 <li data-name="LuCI.form.TextValue#getUIElement"><a href="LuCI.form.TextValue.html#getUIElement">getUIElement</a></li>
1551 <li data-name="LuCI.form.TextValue#isActive"><a href="LuCI.form.TextValue.html#isActive">isActive</a></li>
1553 <li data-name="LuCI.form.TextValue#isValid"><a href="LuCI.form.TextValue.html#isValid">isValid</a></li>
1555 <li data-name="LuCI.form.TextValue#load"><a href="LuCI.form.TextValue.html#load">load</a></li>
1557 <li data-name="LuCI.form.TextValue#parse"><a href="LuCI.form.TextValue.html#parse">parse</a></li>
1559 <li data-name="LuCI.form.TextValue#remove"><a href="LuCI.form.TextValue.html#remove">remove</a></li>
1561 <li data-name="LuCI.form.TextValue#stripTags"><a href="LuCI.form.TextValue.html#stripTags">stripTags</a></li>
1563 <li data-name="LuCI.form.TextValue#textvalue"><a href="LuCI.form.TextValue.html#textvalue">textvalue</a></li>
1565 <li data-name="LuCI.form.TextValue#titleFn"><a href="LuCI.form.TextValue.html#titleFn">titleFn</a></li>
1567 <li data-name="LuCI.form.TextValue#write"><a href="LuCI.form.TextValue.html#write">write</a></li>
1570 <ul class="events itemMembers">
1575 <li class="item" data-name="LuCI.form.TypedSection">
1576 <span class="title">
1577 <a href="LuCI.form.TypedSection.html">LuCI.form.TypedSection</a>
1580 <ul class="members itemMembers">
1582 <span class="subtitle">Members</span>
1584 <li data-name="LuCI.form.TypedSection##addbtntitle"><a href="LuCI.form.TypedSection.html#addbtntitle">addbtntitle</a></li>
1586 <li data-name="LuCI.form.TypedSection##addremove"><a href="LuCI.form.TypedSection.html#addremove">addremove</a></li>
1588 <li data-name="LuCI.form.TypedSection##anonymous"><a href="LuCI.form.TypedSection.html#anonymous">anonymous</a></li>
1590 <li data-name="LuCI.form.TypedSection##tabbed"><a href="LuCI.form.TypedSection.html#tabbed">tabbed</a></li>
1592 <li data-name="LuCI.form.TypedSection##uciconfig"><a href="LuCI.form.TypedSection.html#uciconfig">uciconfig</a></li>
1594 <li data-name="LuCI.form.TypedSection#parentoption"><a href="LuCI.form.TypedSection.html#parentoption">parentoption</a></li>
1597 <ul class="typedefs itemMembers">
1600 <ul class="typedefs itemMembers">
1603 <ul class="methods itemMembers">
1605 <span class="subtitle">Methods</span>
1607 <li data-name="LuCI.form.TypedSection#append"><a href="LuCI.form.TypedSection.html#append">append</a></li>
1609 <li data-name="LuCI.form.TypedSection#cfgsections"><a href="LuCI.form.TypedSection.html#cfgsections">cfgsections</a></li>
1611 <li data-name="LuCI.form.TypedSection#filter"><a href="LuCI.form.TypedSection.html#filter">filter</a></li>
1613 <li data-name="LuCI.form.TypedSection#load"><a href="LuCI.form.TypedSection.html#load">load</a></li>
1615 <li data-name="LuCI.form.TypedSection#option"><a href="LuCI.form.TypedSection.html#option">option</a></li>
1617 <li data-name="LuCI.form.TypedSection#parse"><a href="LuCI.form.TypedSection.html#parse">parse</a></li>
1619 <li data-name="LuCI.form.TypedSection#render"><a href="LuCI.form.TypedSection.html#render">render</a></li>
1621 <li data-name="LuCI.form.TypedSection#stripTags"><a href="LuCI.form.TypedSection.html#stripTags">stripTags</a></li>
1623 <li data-name="LuCI.form.TypedSection#tab"><a href="LuCI.form.TypedSection.html#tab">tab</a></li>
1625 <li data-name="LuCI.form.TypedSection#taboption"><a href="LuCI.form.TypedSection.html#taboption">taboption</a></li>
1627 <li data-name="LuCI.form.TypedSection#titleFn"><a href="LuCI.form.TypedSection.html#titleFn">titleFn</a></li>
1630 <ul class="events itemMembers">
1635 <li class="item" data-name="LuCI.form.Value">
1636 <span class="title">
1637 <a href="LuCI.form.Value.html">LuCI.form.Value</a>
1640 <ul class="members itemMembers">
1642 <span class="subtitle">Members</span>
1644 <li data-name="LuCI.form.Value##password"><a href="LuCI.form.Value.html#password">password</a></li>
1646 <li data-name="LuCI.form.Value##placeholder"><a href="LuCI.form.Value.html#placeholder">placeholder</a></li>
1648 <li data-name="LuCI.form.Value#datatype"><a href="LuCI.form.Value.html#datatype">datatype</a></li>
1650 <li data-name="LuCI.form.Value#default"><a href="LuCI.form.Value.html#default">default</a></li>
1652 <li data-name="LuCI.form.Value#editable"><a href="LuCI.form.Value.html#editable">editable</a></li>
1654 <li data-name="LuCI.form.Value#modalonly"><a href="LuCI.form.Value.html#modalonly">modalonly</a></li>
1656 <li data-name="LuCI.form.Value#optional"><a href="LuCI.form.Value.html#optional">optional</a></li>
1658 <li data-name="LuCI.form.Value#rmempty"><a href="LuCI.form.Value.html#rmempty">rmempty</a></li>
1660 <li data-name="LuCI.form.Value#uciconfig"><a href="LuCI.form.Value.html#uciconfig">uciconfig</a></li>
1662 <li data-name="LuCI.form.Value#ucioption"><a href="LuCI.form.Value.html#ucioption">ucioption</a></li>
1664 <li data-name="LuCI.form.Value#ucisection"><a href="LuCI.form.Value.html#ucisection">ucisection</a></li>
1666 <li data-name="LuCI.form.Value#validate"><a href="LuCI.form.Value.html#validate">validate</a></li>
1668 <li data-name="LuCI.form.Value#width"><a href="LuCI.form.Value.html#width">width</a></li>
1671 <ul class="typedefs itemMembers">
1674 <ul class="typedefs itemMembers">
1677 <ul class="methods itemMembers">
1679 <span class="subtitle">Methods</span>
1681 <li data-name="LuCI.form.Value#append"><a href="LuCI.form.Value.html#append">append</a></li>
1683 <li data-name="LuCI.form.Value#cbid"><a href="LuCI.form.Value.html#cbid">cbid</a></li>
1685 <li data-name="LuCI.form.Value#cfgvalue"><a href="LuCI.form.Value.html#cfgvalue">cfgvalue</a></li>
1687 <li data-name="LuCI.form.Value#depends"><a href="LuCI.form.Value.html#depends">depends</a></li>
1689 <li data-name="LuCI.form.Value#formvalue"><a href="LuCI.form.Value.html#formvalue">formvalue</a></li>
1691 <li data-name="LuCI.form.Value#getUIElement"><a href="LuCI.form.Value.html#getUIElement">getUIElement</a></li>
1693 <li data-name="LuCI.form.Value#isActive"><a href="LuCI.form.Value.html#isActive">isActive</a></li>
1695 <li data-name="LuCI.form.Value#isValid"><a href="LuCI.form.Value.html#isValid">isValid</a></li>
1697 <li data-name="LuCI.form.Value#load"><a href="LuCI.form.Value.html#load">load</a></li>
1699 <li data-name="LuCI.form.Value#parse"><a href="LuCI.form.Value.html#parse">parse</a></li>
1701 <li data-name="LuCI.form.Value#remove"><a href="LuCI.form.Value.html#remove">remove</a></li>
1703 <li data-name="LuCI.form.Value#render"><a href="LuCI.form.Value.html#render">render</a></li>
1705 <li data-name="LuCI.form.Value#stripTags"><a href="LuCI.form.Value.html#stripTags">stripTags</a></li>
1707 <li data-name="LuCI.form.Value#textvalue"><a href="LuCI.form.Value.html#textvalue">textvalue</a></li>
1709 <li data-name="LuCI.form.Value#titleFn"><a href="LuCI.form.Value.html#titleFn">titleFn</a></li>
1711 <li data-name="LuCI.form.Value#value"><a href="LuCI.form.Value.html#value">value</a></li>
1713 <li data-name="LuCI.form.Value#write"><a href="LuCI.form.Value.html#write">write</a></li>
1716 <ul class="events itemMembers">
1721 <li class="item" data-name="LuCI.fs">
1722 <span class="title">
1723 <a href="LuCI.fs.html">LuCI.fs</a>
1726 <ul class="members itemMembers">
1729 <ul class="typedefs itemMembers">
1731 <span class="subtitle">Typedefs</span>
1733 <li data-name="LuCI.fs.FileExecResult"><a href="LuCI.fs.html#.FileExecResult">FileExecResult</a></li>
1735 <li data-name="LuCI.fs.FileStatEntry"><a href="LuCI.fs.html#.FileStatEntry">FileStatEntry</a></li>
1738 <ul class="typedefs itemMembers">
1741 <ul class="methods itemMembers">
1743 <span class="subtitle">Methods</span>
1745 <li data-name="LuCI.fs#exec"><a href="LuCI.fs.html#exec">exec</a></li>
1747 <li data-name="LuCI.fs#exec_direct"><a href="LuCI.fs.html#exec_direct">exec_direct</a></li>
1749 <li data-name="LuCI.fs#lines"><a href="LuCI.fs.html#lines">lines</a></li>
1751 <li data-name="LuCI.fs#list"><a href="LuCI.fs.html#list">list</a></li>
1753 <li data-name="LuCI.fs#read"><a href="LuCI.fs.html#read">read</a></li>
1755 <li data-name="LuCI.fs#read_direct"><a href="LuCI.fs.html#read_direct">read_direct</a></li>
1757 <li data-name="LuCI.fs#remove"><a href="LuCI.fs.html#remove">remove</a></li>
1759 <li data-name="LuCI.fs#stat"><a href="LuCI.fs.html#stat">stat</a></li>
1761 <li data-name="LuCI.fs#trimmed"><a href="LuCI.fs.html#trimmed">trimmed</a></li>
1763 <li data-name="LuCI.fs#write"><a href="LuCI.fs.html#write">write</a></li>
1766 <ul class="events itemMembers">
1771 <li class="item" data-name="LuCI.headers">
1772 <span class="title">
1773 <a href="LuCI.headers.html">LuCI.headers</a>
1776 <ul class="members itemMembers">
1779 <ul class="typedefs itemMembers">
1782 <ul class="typedefs itemMembers">
1785 <ul class="methods itemMembers">
1787 <span class="subtitle">Methods</span>
1789 <li data-name="LuCI.headers#get"><a href="LuCI.headers.html#get">get</a></li>
1791 <li data-name="LuCI.headers#has"><a href="LuCI.headers.html#has">has</a></li>
1794 <ul class="events itemMembers">
1799 <li class="item" data-name="LuCI.network">
1800 <span class="title">
1801 <a href="LuCI.network.html">LuCI.network</a>
1804 <ul class="members itemMembers">
1807 <ul class="typedefs itemMembers">
1809 <span class="subtitle">Typedefs</span>
1811 <li data-name="LuCI.network.SwitchTopology"><a href="LuCI.network.html#.SwitchTopology">SwitchTopology</a></li>
1813 <li data-name="LuCI.network.WifiEncryption"><a href="LuCI.network.html#.WifiEncryption">WifiEncryption</a></li>
1815 <li data-name="LuCI.network.WifiPeerEntry"><a href="LuCI.network.html#.WifiPeerEntry">WifiPeerEntry</a></li>
1817 <li data-name="LuCI.network.WifiRateEntry"><a href="LuCI.network.html#.WifiRateEntry">WifiRateEntry</a></li>
1819 <li data-name="LuCI.network.WifiScanResult"><a href="LuCI.network.html#.WifiScanResult">WifiScanResult</a></li>
1822 <ul class="typedefs itemMembers">
1825 <ul class="methods itemMembers">
1827 <span class="subtitle">Methods</span>
1829 <li data-name="LuCI.network#addNetwork"><a href="LuCI.network.html#addNetwork">addNetwork</a></li>
1831 <li data-name="LuCI.network#addWifiNetwork"><a href="LuCI.network.html#addWifiNetwork">addWifiNetwork</a></li>
1833 <li data-name="LuCI.network#deleteNetwork"><a href="LuCI.network.html#deleteNetwork">deleteNetwork</a></li>
1835 <li data-name="LuCI.network#deleteWifiNetwork"><a href="LuCI.network.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
1837 <li data-name="LuCI.network#flushCache"><a href="LuCI.network.html#flushCache">flushCache</a></li>
1839 <li data-name="LuCI.network#formatWifiEncryption"><a href="LuCI.network.html#formatWifiEncryption">formatWifiEncryption</a></li>
1841 <li data-name="LuCI.network#getDevice"><a href="LuCI.network.html#getDevice">getDevice</a></li>
1843 <li data-name="LuCI.network#getDevices"><a href="LuCI.network.html#getDevices">getDevices</a></li>
1845 <li data-name="LuCI.network#getDSLModemType"><a href="LuCI.network.html#getDSLModemType">getDSLModemType</a></li>
1847 <li data-name="LuCI.network#getHostHints"><a href="LuCI.network.html#getHostHints">getHostHints</a></li>
1849 <li data-name="LuCI.network#getIfnameOf"><a href="LuCI.network.html#getIfnameOf">getIfnameOf</a></li>
1851 <li data-name="LuCI.network#getNetwork"><a href="LuCI.network.html#getNetwork">getNetwork</a></li>
1853 <li data-name="LuCI.network#getNetworks"><a href="LuCI.network.html#getNetworks">getNetworks</a></li>
1855 <li data-name="LuCI.network#getProtocol"><a href="LuCI.network.html#getProtocol">getProtocol</a></li>
1857 <li data-name="LuCI.network#getProtocols"><a href="LuCI.network.html#getProtocols">getProtocols</a></li>
1859 <li data-name="LuCI.network#getSwitchTopologies"><a href="LuCI.network.html#getSwitchTopologies">getSwitchTopologies</a></li>
1861 <li data-name="LuCI.network#getWAN6Networks"><a href="LuCI.network.html#getWAN6Networks">getWAN6Networks</a></li>
1863 <li data-name="LuCI.network#getWANNetworks"><a href="LuCI.network.html#getWANNetworks">getWANNetworks</a></li>
1865 <li data-name="LuCI.network#getWifiDevice"><a href="LuCI.network.html#getWifiDevice">getWifiDevice</a></li>
1867 <li data-name="LuCI.network#getWifiDevices"><a href="LuCI.network.html#getWifiDevices">getWifiDevices</a></li>
1869 <li data-name="LuCI.network#getWifiNetwork"><a href="LuCI.network.html#getWifiNetwork">getWifiNetwork</a></li>
1871 <li data-name="LuCI.network#getWifiNetworks"><a href="LuCI.network.html#getWifiNetworks">getWifiNetworks</a></li>
1873 <li data-name="LuCI.network#isIgnoredDevice"><a href="LuCI.network.html#isIgnoredDevice">isIgnoredDevice</a></li>
1875 <li data-name="LuCI.network#maskToPrefix"><a href="LuCI.network.html#maskToPrefix">maskToPrefix</a></li>
1877 <li data-name="LuCI.network#prefixToMask"><a href="LuCI.network.html#prefixToMask">prefixToMask</a></li>
1879 <li data-name="LuCI.network#registerErrorCode"><a href="LuCI.network.html#registerErrorCode">registerErrorCode</a></li>
1881 <li data-name="LuCI.network#registerPatternVirtual"><a href="LuCI.network.html#registerPatternVirtual">registerPatternVirtual</a></li>
1883 <li data-name="LuCI.network#registerProtocol"><a href="LuCI.network.html#registerProtocol">registerProtocol</a></li>
1885 <li data-name="LuCI.network#renameNetwork"><a href="LuCI.network.html#renameNetwork">renameNetwork</a></li>
1888 <ul class="events itemMembers">
1893 <li class="item" data-name="LuCI.network.Device">
1894 <span class="title">
1895 <a href="LuCI.network.Device.html">LuCI.network.Device</a>
1898 <ul class="members itemMembers">
1901 <ul class="typedefs itemMembers">
1904 <ul class="typedefs itemMembers">
1907 <ul class="methods itemMembers">
1909 <span class="subtitle">Methods</span>
1911 <li data-name="LuCI.network.Device#getBridgeID"><a href="LuCI.network.Device.html#getBridgeID">getBridgeID</a></li>
1913 <li data-name="LuCI.network.Device#getBridgeSTP"><a href="LuCI.network.Device.html#getBridgeSTP">getBridgeSTP</a></li>
1915 <li data-name="LuCI.network.Device#getI18n"><a href="LuCI.network.Device.html#getI18n">getI18n</a></li>
1917 <li data-name="LuCI.network.Device#getIP6Addrs"><a href="LuCI.network.Device.html#getIP6Addrs">getIP6Addrs</a></li>
1919 <li data-name="LuCI.network.Device#getIPAddrs"><a href="LuCI.network.Device.html#getIPAddrs">getIPAddrs</a></li>
1921 <li data-name="LuCI.network.Device#getMAC"><a href="LuCI.network.Device.html#getMAC">getMAC</a></li>
1923 <li data-name="LuCI.network.Device#getMTU"><a href="LuCI.network.Device.html#getMTU">getMTU</a></li>
1925 <li data-name="LuCI.network.Device#getName"><a href="LuCI.network.Device.html#getName">getName</a></li>
1927 <li data-name="LuCI.network.Device#getNetwork"><a href="LuCI.network.Device.html#getNetwork">getNetwork</a></li>
1929 <li data-name="LuCI.network.Device#getNetworks"><a href="LuCI.network.Device.html#getNetworks">getNetworks</a></li>
1931 <li data-name="LuCI.network.Device#getPorts"><a href="LuCI.network.Device.html#getPorts">getPorts</a></li>
1933 <li data-name="LuCI.network.Device#getRXBytes"><a href="LuCI.network.Device.html#getRXBytes">getRXBytes</a></li>
1935 <li data-name="LuCI.network.Device#getRXPackets"><a href="LuCI.network.Device.html#getRXPackets">getRXPackets</a></li>
1937 <li data-name="LuCI.network.Device#getShortName"><a href="LuCI.network.Device.html#getShortName">getShortName</a></li>
1939 <li data-name="LuCI.network.Device#getTXBytes"><a href="LuCI.network.Device.html#getTXBytes">getTXBytes</a></li>
1941 <li data-name="LuCI.network.Device#getTXPackets"><a href="LuCI.network.Device.html#getTXPackets">getTXPackets</a></li>
1943 <li data-name="LuCI.network.Device#getType"><a href="LuCI.network.Device.html#getType">getType</a></li>
1945 <li data-name="LuCI.network.Device#getTypeI18n"><a href="LuCI.network.Device.html#getTypeI18n">getTypeI18n</a></li>
1947 <li data-name="LuCI.network.Device#getWifiNetwork"><a href="LuCI.network.Device.html#getWifiNetwork">getWifiNetwork</a></li>
1949 <li data-name="LuCI.network.Device#isBridge"><a href="LuCI.network.Device.html#isBridge">isBridge</a></li>
1951 <li data-name="LuCI.network.Device#isBridgePort"><a href="LuCI.network.Device.html#isBridgePort">isBridgePort</a></li>
1953 <li data-name="LuCI.network.Device#isUp"><a href="LuCI.network.Device.html#isUp">isUp</a></li>
1956 <ul class="events itemMembers">
1961 <li class="item" data-name="LuCI.network.Hosts">
1962 <span class="title">
1963 <a href="LuCI.network.Hosts.html">LuCI.network.Hosts</a>
1966 <ul class="members itemMembers">
1969 <ul class="typedefs itemMembers">
1972 <ul class="typedefs itemMembers">
1975 <ul class="methods itemMembers">
1977 <span class="subtitle">Methods</span>
1979 <li data-name="LuCI.network.Hosts#getHostnameByIP6Addr"><a href="LuCI.network.Hosts.html#getHostnameByIP6Addr">getHostnameByIP6Addr</a></li>
1981 <li data-name="LuCI.network.Hosts#getHostnameByIPAddr"><a href="LuCI.network.Hosts.html#getHostnameByIPAddr">getHostnameByIPAddr</a></li>
1983 <li data-name="LuCI.network.Hosts#getHostnameByMACAddr"><a href="LuCI.network.Hosts.html#getHostnameByMACAddr">getHostnameByMACAddr</a></li>
1985 <li data-name="LuCI.network.Hosts#getIP6AddrByMACAddr"><a href="LuCI.network.Hosts.html#getIP6AddrByMACAddr">getIP6AddrByMACAddr</a></li>
1987 <li data-name="LuCI.network.Hosts#getIPAddrByMACAddr"><a href="LuCI.network.Hosts.html#getIPAddrByMACAddr">getIPAddrByMACAddr</a></li>
1989 <li data-name="LuCI.network.Hosts#getMACAddrByIP6Addr"><a href="LuCI.network.Hosts.html#getMACAddrByIP6Addr">getMACAddrByIP6Addr</a></li>
1991 <li data-name="LuCI.network.Hosts#getMACAddrByIPAddr"><a href="LuCI.network.Hosts.html#getMACAddrByIPAddr">getMACAddrByIPAddr</a></li>
1993 <li data-name="LuCI.network.Hosts#getMACHints"><a href="LuCI.network.Hosts.html#getMACHints">getMACHints</a></li>
1996 <ul class="events itemMembers">
2001 <li class="item" data-name="LuCI.network.Protocol">
2002 <span class="title">
2003 <a href="LuCI.network.Protocol.html">LuCI.network.Protocol</a>
2006 <ul class="members itemMembers">
2009 <ul class="typedefs itemMembers">
2012 <ul class="typedefs itemMembers">
2015 <ul class="methods itemMembers">
2017 <span class="subtitle">Methods</span>
2019 <li data-name="LuCI.network.Protocol#addDevice"><a href="LuCI.network.Protocol.html#addDevice">addDevice</a></li>
2021 <li data-name="LuCI.network.Protocol#containsDevice"><a href="LuCI.network.Protocol.html#containsDevice">containsDevice</a></li>
2023 <li data-name="LuCI.network.Protocol#deleteConfiguration"><a href="LuCI.network.Protocol.html#deleteConfiguration">deleteConfiguration</a></li>
2025 <li data-name="LuCI.network.Protocol#deleteDevice"><a href="LuCI.network.Protocol.html#deleteDevice">deleteDevice</a></li>
2027 <li data-name="LuCI.network.Protocol#get"><a href="LuCI.network.Protocol.html#get">get</a></li>
2029 <li data-name="LuCI.network.Protocol#getDevice"><a href="LuCI.network.Protocol.html#getDevice">getDevice</a></li>
2031 <li data-name="LuCI.network.Protocol#getDevices"><a href="LuCI.network.Protocol.html#getDevices">getDevices</a></li>
2033 <li data-name="LuCI.network.Protocol#getDNS6Addrs"><a href="LuCI.network.Protocol.html#getDNS6Addrs">getDNS6Addrs</a></li>
2035 <li data-name="LuCI.network.Protocol#getDNSAddrs"><a href="LuCI.network.Protocol.html#getDNSAddrs">getDNSAddrs</a></li>
2037 <li data-name="LuCI.network.Protocol#getErrors"><a href="LuCI.network.Protocol.html#getErrors">getErrors</a></li>
2039 <li data-name="LuCI.network.Protocol#getExpiry"><a href="LuCI.network.Protocol.html#getExpiry">getExpiry</a></li>
2041 <li data-name="LuCI.network.Protocol#getGateway6Addr"><a href="LuCI.network.Protocol.html#getGateway6Addr">getGateway6Addr</a></li>
2043 <li data-name="LuCI.network.Protocol#getGatewayAddr"><a href="LuCI.network.Protocol.html#getGatewayAddr">getGatewayAddr</a></li>
2045 <li data-name="LuCI.network.Protocol#getI18n"><a href="LuCI.network.Protocol.html#getI18n">getI18n</a></li>
2047 <li data-name="LuCI.network.Protocol#getIfname"><a href="LuCI.network.Protocol.html#getIfname">getIfname</a></li>
2049 <li data-name="LuCI.network.Protocol#getIP6Addr"><a href="LuCI.network.Protocol.html#getIP6Addr">getIP6Addr</a></li>
2051 <li data-name="LuCI.network.Protocol#getIP6Addrs"><a href="LuCI.network.Protocol.html#getIP6Addrs">getIP6Addrs</a></li>
2053 <li data-name="LuCI.network.Protocol#getIP6Prefix"><a href="LuCI.network.Protocol.html#getIP6Prefix">getIP6Prefix</a></li>
2055 <li data-name="LuCI.network.Protocol#getIPAddr"><a href="LuCI.network.Protocol.html#getIPAddr">getIPAddr</a></li>
2057 <li data-name="LuCI.network.Protocol#getIPAddrs"><a href="LuCI.network.Protocol.html#getIPAddrs">getIPAddrs</a></li>
2059 <li data-name="LuCI.network.Protocol#getL2Device"><a href="LuCI.network.Protocol.html#getL2Device">getL2Device</a></li>
2061 <li data-name="LuCI.network.Protocol#getL3Device"><a href="LuCI.network.Protocol.html#getL3Device">getL3Device</a></li>
2063 <li data-name="LuCI.network.Protocol#getMetric"><a href="LuCI.network.Protocol.html#getMetric">getMetric</a></li>
2065 <li data-name="LuCI.network.Protocol#getName"><a href="LuCI.network.Protocol.html#getName">getName</a></li>
2067 <li data-name="LuCI.network.Protocol#getNetmask"><a href="LuCI.network.Protocol.html#getNetmask">getNetmask</a></li>
2069 <li data-name="LuCI.network.Protocol#getOpkgPackage"><a href="LuCI.network.Protocol.html#getOpkgPackage">getOpkgPackage</a></li>
2071 <li data-name="LuCI.network.Protocol#getProtocol"><a href="LuCI.network.Protocol.html#getProtocol">getProtocol</a></li>
2073 <li data-name="LuCI.network.Protocol#getType"><a href="LuCI.network.Protocol.html#getType">getType</a></li>
2075 <li data-name="LuCI.network.Protocol#getUptime"><a href="LuCI.network.Protocol.html#getUptime">getUptime</a></li>
2077 <li data-name="LuCI.network.Protocol#getZoneName"><a href="LuCI.network.Protocol.html#getZoneName">getZoneName</a></li>
2079 <li data-name="LuCI.network.Protocol#isAlias"><a href="LuCI.network.Protocol.html#isAlias">isAlias</a></li>
2081 <li data-name="LuCI.network.Protocol#isBridge"><a href="LuCI.network.Protocol.html#isBridge">isBridge</a></li>
2083 <li data-name="LuCI.network.Protocol#isCreateable"><a href="LuCI.network.Protocol.html#isCreateable">isCreateable</a></li>
2085 <li data-name="LuCI.network.Protocol#isDynamic"><a href="LuCI.network.Protocol.html#isDynamic">isDynamic</a></li>
2087 <li data-name="LuCI.network.Protocol#isEmpty"><a href="LuCI.network.Protocol.html#isEmpty">isEmpty</a></li>
2089 <li data-name="LuCI.network.Protocol#isFloating"><a href="LuCI.network.Protocol.html#isFloating">isFloating</a></li>
2091 <li data-name="LuCI.network.Protocol#isInstalled"><a href="LuCI.network.Protocol.html#isInstalled">isInstalled</a></li>
2093 <li data-name="LuCI.network.Protocol#isUp"><a href="LuCI.network.Protocol.html#isUp">isUp</a></li>
2095 <li data-name="LuCI.network.Protocol#isVirtual"><a href="LuCI.network.Protocol.html#isVirtual">isVirtual</a></li>
2097 <li data-name="LuCI.network.Protocol#set"><a href="LuCI.network.Protocol.html#set">set</a></li>
2100 <ul class="events itemMembers">
2105 <li class="item" data-name="LuCI.network.WifiDevice">
2106 <span class="title">
2107 <a href="LuCI.network.WifiDevice.html">LuCI.network.WifiDevice</a>
2110 <ul class="members itemMembers">
2113 <ul class="typedefs itemMembers">
2116 <ul class="typedefs itemMembers">
2119 <ul class="methods itemMembers">
2121 <span class="subtitle">Methods</span>
2123 <li data-name="LuCI.network.WifiDevice#addWifiNetwork"><a href="LuCI.network.WifiDevice.html#addWifiNetwork">addWifiNetwork</a></li>
2125 <li data-name="LuCI.network.WifiDevice#deleteWifiNetwork"><a href="LuCI.network.WifiDevice.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
2127 <li data-name="LuCI.network.WifiDevice#get"><a href="LuCI.network.WifiDevice.html#get">get</a></li>
2129 <li data-name="LuCI.network.WifiDevice#getHTModes"><a href="LuCI.network.WifiDevice.html#getHTModes">getHTModes</a></li>
2131 <li data-name="LuCI.network.WifiDevice#getHWModes"><a href="LuCI.network.WifiDevice.html#getHWModes">getHWModes</a></li>
2133 <li data-name="LuCI.network.WifiDevice#getI18n"><a href="LuCI.network.WifiDevice.html#getI18n">getI18n</a></li>
2135 <li data-name="LuCI.network.WifiDevice#getName"><a href="LuCI.network.WifiDevice.html#getName">getName</a></li>
2137 <li data-name="LuCI.network.WifiDevice#getScanList"><a href="LuCI.network.WifiDevice.html#getScanList">getScanList</a></li>
2139 <li data-name="LuCI.network.WifiDevice#getWifiNetwork"><a href="LuCI.network.WifiDevice.html#getWifiNetwork">getWifiNetwork</a></li>
2141 <li data-name="LuCI.network.WifiDevice#getWifiNetworks"><a href="LuCI.network.WifiDevice.html#getWifiNetworks">getWifiNetworks</a></li>
2143 <li data-name="LuCI.network.WifiDevice#isDisabled"><a href="LuCI.network.WifiDevice.html#isDisabled">isDisabled</a></li>
2145 <li data-name="LuCI.network.WifiDevice#isUp"><a href="LuCI.network.WifiDevice.html#isUp">isUp</a></li>
2147 <li data-name="LuCI.network.WifiDevice#set"><a href="LuCI.network.WifiDevice.html#set">set</a></li>
2150 <ul class="events itemMembers">
2155 <li class="item" data-name="LuCI.network.WifiNetwork">
2156 <span class="title">
2157 <a href="LuCI.network.WifiNetwork.html">LuCI.network.WifiNetwork</a>
2160 <ul class="members itemMembers">
2163 <ul class="typedefs itemMembers">
2166 <ul class="typedefs itemMembers">
2169 <ul class="methods itemMembers">
2171 <span class="subtitle">Methods</span>
2173 <li data-name="LuCI.network.WifiNetwork#disconnectClient"><a href="LuCI.network.WifiNetwork.html#disconnectClient">disconnectClient</a></li>
2175 <li data-name="LuCI.network.WifiNetwork#get"><a href="LuCI.network.WifiNetwork.html#get">get</a></li>
2177 <li data-name="LuCI.network.WifiNetwork#getActiveBSSID"><a href="LuCI.network.WifiNetwork.html#getActiveBSSID">getActiveBSSID</a></li>
2179 <li data-name="LuCI.network.WifiNetwork#getActiveEncryption"><a href="LuCI.network.WifiNetwork.html#getActiveEncryption">getActiveEncryption</a></li>
2181 <li data-name="LuCI.network.WifiNetwork#getActiveMode"><a href="LuCI.network.WifiNetwork.html#getActiveMode">getActiveMode</a></li>
2183 <li data-name="LuCI.network.WifiNetwork#getActiveModeI18n"><a href="LuCI.network.WifiNetwork.html#getActiveModeI18n">getActiveModeI18n</a></li>
2185 <li data-name="LuCI.network.WifiNetwork#getActiveSSID"><a href="LuCI.network.WifiNetwork.html#getActiveSSID">getActiveSSID</a></li>
2187 <li data-name="LuCI.network.WifiNetwork#getAssocList"><a href="LuCI.network.WifiNetwork.html#getAssocList">getAssocList</a></li>
2189 <li data-name="LuCI.network.WifiNetwork#getBitRate"><a href="LuCI.network.WifiNetwork.html#getBitRate">getBitRate</a></li>
2191 <li data-name="LuCI.network.WifiNetwork#getBSSID"><a href="LuCI.network.WifiNetwork.html#getBSSID">getBSSID</a></li>
2193 <li data-name="LuCI.network.WifiNetwork#getChannel"><a href="LuCI.network.WifiNetwork.html#getChannel">getChannel</a></li>
2195 <li data-name="LuCI.network.WifiNetwork#getCountryCode"><a href="LuCI.network.WifiNetwork.html#getCountryCode">getCountryCode</a></li>
2197 <li data-name="LuCI.network.WifiNetwork#getDevice"><a href="LuCI.network.WifiNetwork.html#getDevice">getDevice</a></li>
2199 <li data-name="LuCI.network.WifiNetwork#getFrequency"><a href="LuCI.network.WifiNetwork.html#getFrequency">getFrequency</a></li>
2201 <li data-name="LuCI.network.WifiNetwork#getI18n"><a href="LuCI.network.WifiNetwork.html#getI18n">getI18n</a></li>
2203 <li data-name="LuCI.network.WifiNetwork#getID"><a href="LuCI.network.WifiNetwork.html#getID">getID</a></li>
2205 <li data-name="LuCI.network.WifiNetwork#getIfname"><a href="LuCI.network.WifiNetwork.html#getIfname">getIfname</a></li>
2207 <li data-name="LuCI.network.WifiNetwork#getMeshID"><a href="LuCI.network.WifiNetwork.html#getMeshID">getMeshID</a></li>
2209 <li data-name="LuCI.network.WifiNetwork#getMode"><a href="LuCI.network.WifiNetwork.html#getMode">getMode</a></li>
2211 <li data-name="LuCI.network.WifiNetwork#getName"><a href="LuCI.network.WifiNetwork.html#getName">getName</a></li>
2213 <li data-name="LuCI.network.WifiNetwork#getNetwork"><a href="LuCI.network.WifiNetwork.html#getNetwork">getNetwork</a></li>
2215 <li data-name="LuCI.network.WifiNetwork#getNetworkNames"><a href="LuCI.network.WifiNetwork.html#getNetworkNames">getNetworkNames</a></li>
2217 <li data-name="LuCI.network.WifiNetwork#getNetworks"><a href="LuCI.network.WifiNetwork.html#getNetworks">getNetworks</a></li>
2219 <li data-name="LuCI.network.WifiNetwork#getNoise"><a href="LuCI.network.WifiNetwork.html#getNoise">getNoise</a></li>
2221 <li data-name="LuCI.network.WifiNetwork#getShortName"><a href="LuCI.network.WifiNetwork.html#getShortName">getShortName</a></li>
2223 <li data-name="LuCI.network.WifiNetwork#getSignal"><a href="LuCI.network.WifiNetwork.html#getSignal">getSignal</a></li>
2225 <li data-name="LuCI.network.WifiNetwork#getSignalLevel"><a href="LuCI.network.WifiNetwork.html#getSignalLevel">getSignalLevel</a></li>
2227 <li data-name="LuCI.network.WifiNetwork#getSignalPercent"><a href="LuCI.network.WifiNetwork.html#getSignalPercent">getSignalPercent</a></li>
2229 <li data-name="LuCI.network.WifiNetwork#getSSID"><a href="LuCI.network.WifiNetwork.html#getSSID">getSSID</a></li>
2231 <li data-name="LuCI.network.WifiNetwork#getTXPower"><a href="LuCI.network.WifiNetwork.html#getTXPower">getTXPower</a></li>
2233 <li data-name="LuCI.network.WifiNetwork#getTXPowerOffset"><a href="LuCI.network.WifiNetwork.html#getTXPowerOffset">getTXPowerOffset</a></li>
2235 <li data-name="LuCI.network.WifiNetwork#getWifiDevice"><a href="LuCI.network.WifiNetwork.html#getWifiDevice">getWifiDevice</a></li>
2237 <li data-name="LuCI.network.WifiNetwork#getWifiDeviceName"><a href="LuCI.network.WifiNetwork.html#getWifiDeviceName">getWifiDeviceName</a></li>
2239 <li data-name="LuCI.network.WifiNetwork#isClientDisconnectSupported"><a href="LuCI.network.WifiNetwork.html#isClientDisconnectSupported">isClientDisconnectSupported</a></li>
2241 <li data-name="LuCI.network.WifiNetwork#isDisabled"><a href="LuCI.network.WifiNetwork.html#isDisabled">isDisabled</a></li>
2243 <li data-name="LuCI.network.WifiNetwork#isUp"><a href="LuCI.network.WifiNetwork.html#isUp">isUp</a></li>
2245 <li data-name="LuCI.network.WifiNetwork#set"><a href="LuCI.network.WifiNetwork.html#set">set</a></li>
2248 <ul class="events itemMembers">
2253 <li class="item" data-name="LuCI.poll">
2254 <span class="title">
2255 <a href="LuCI.poll.html">LuCI.poll</a>
2258 <ul class="members itemMembers">
2261 <ul class="typedefs itemMembers">
2264 <ul class="typedefs itemMembers">
2267 <ul class="methods itemMembers">
2269 <span class="subtitle">Methods</span>
2271 <li data-name="LuCI.poll#active"><a href="LuCI.poll.html#active">active</a></li>
2273 <li data-name="LuCI.poll#add"><a href="LuCI.poll.html#add">add</a></li>
2275 <li data-name="LuCI.poll#remove"><a href="LuCI.poll.html#remove">remove</a></li>
2277 <li data-name="LuCI.poll#start"><a href="LuCI.poll.html#start">start</a></li>
2279 <li data-name="LuCI.poll#stop"><a href="LuCI.poll.html#stop">stop</a></li>
2282 <ul class="events itemMembers">
2287 <li class="item" data-name="LuCI.request">
2288 <span class="title">
2289 <a href="LuCI.request.html">LuCI.request</a>
2292 <ul class="members itemMembers">
2295 <ul class="typedefs itemMembers">
2297 <span class="subtitle">Typedefs</span>
2299 <li data-name="LuCI.request.interceptorFn"><a href="LuCI.request.html#.interceptorFn">interceptorFn</a></li>
2301 <li data-name="LuCI.request.RequestOptions"><a href="LuCI.request.html#.RequestOptions">RequestOptions</a></li>
2304 <ul class="typedefs itemMembers">
2307 <ul class="methods itemMembers">
2309 <span class="subtitle">Methods</span>
2311 <li data-name="LuCI.request#addInterceptor"><a href="LuCI.request.html#addInterceptor">addInterceptor</a></li>
2313 <li data-name="LuCI.request#expandURL"><a href="LuCI.request.html#expandURL">expandURL</a></li>
2315 <li data-name="LuCI.request#get"><a href="LuCI.request.html#get">get</a></li>
2317 <li data-name="LuCI.request#post"><a href="LuCI.request.html#post">post</a></li>
2319 <li data-name="LuCI.request#removeInterceptor"><a href="LuCI.request.html#removeInterceptor">removeInterceptor</a></li>
2321 <li data-name="LuCI.request#request"><a href="LuCI.request.html#request">request</a></li>
2324 <ul class="events itemMembers">
2329 <li class="item" data-name="LuCI.request.poll">
2330 <span class="title">
2331 <a href="LuCI.request.poll.html">LuCI.request.poll</a>
2334 <ul class="members itemMembers">
2337 <ul class="typedefs itemMembers">
2339 <span class="subtitle">Typedefs</span>
2341 <li data-name="LuCI.request.poll~callbackFn"><a href="LuCI.request.poll.html#~callbackFn">callbackFn</a></li>
2344 <ul class="typedefs itemMembers">
2347 <ul class="methods itemMembers">
2349 <span class="subtitle">Methods</span>
2351 <li data-name="LuCI.request.poll#active"><a href="LuCI.request.poll.html#active">active</a></li>
2353 <li data-name="LuCI.request.poll#add"><a href="LuCI.request.poll.html#add">add</a></li>
2355 <li data-name="LuCI.request.poll#remove"><a href="LuCI.request.poll.html#remove">remove</a></li>
2357 <li data-name="LuCI.request.poll#start"><a href="LuCI.request.poll.html#start">start</a></li>
2359 <li data-name="LuCI.request.poll#stop"><a href="LuCI.request.poll.html#stop">stop</a></li>
2362 <ul class="events itemMembers">
2367 <li class="item" data-name="LuCI.response">
2368 <span class="title">
2369 <a href="LuCI.response.html">LuCI.response</a>
2372 <ul class="members itemMembers">
2374 <span class="subtitle">Members</span>
2376 <li data-name="LuCI.response#duration"><a href="LuCI.response.html#duration">duration</a></li>
2378 <li data-name="LuCI.response#headers"><a href="LuCI.response.html#headers">headers</a></li>
2380 <li data-name="LuCI.response#ok"><a href="LuCI.response.html#ok">ok</a></li>
2382 <li data-name="LuCI.response#status"><a href="LuCI.response.html#status">status</a></li>
2384 <li data-name="LuCI.response#statusText"><a href="LuCI.response.html#statusText">statusText</a></li>
2386 <li data-name="LuCI.response#url"><a href="LuCI.response.html#url">url</a></li>
2389 <ul class="typedefs itemMembers">
2392 <ul class="typedefs itemMembers">
2395 <ul class="methods itemMembers">
2397 <span class="subtitle">Methods</span>
2399 <li data-name="LuCI.response#blob"><a href="LuCI.response.html#blob">blob</a></li>
2401 <li data-name="LuCI.response#clone"><a href="LuCI.response.html#clone">clone</a></li>
2403 <li data-name="LuCI.response#json"><a href="LuCI.response.html#json">json</a></li>
2405 <li data-name="LuCI.response#text"><a href="LuCI.response.html#text">text</a></li>
2408 <ul class="events itemMembers">
2413 <li class="item" data-name="LuCI.rpc">
2414 <span class="title">
2415 <a href="LuCI.rpc.html">LuCI.rpc</a>
2418 <ul class="members itemMembers">
2421 <ul class="typedefs itemMembers">
2423 <span class="subtitle">Typedefs</span>
2425 <li data-name="LuCI.rpc.DeclareOptions"><a href="LuCI.rpc.html#.DeclareOptions">DeclareOptions</a></li>
2427 <li data-name="LuCI.rpc~filterFn"><a href="LuCI.rpc.html#~filterFn">filterFn</a></li>
2429 <li data-name="LuCI.rpc~interceptorFn"><a href="LuCI.rpc.html#~interceptorFn">interceptorFn</a></li>
2431 <li data-name="LuCI.rpc~invokeFn"><a href="LuCI.rpc.html#~invokeFn">invokeFn</a></li>
2434 <ul class="typedefs itemMembers">
2437 <ul class="methods itemMembers">
2439 <span class="subtitle">Methods</span>
2441 <li data-name="LuCI.rpc#addInterceptor"><a href="LuCI.rpc.html#addInterceptor">addInterceptor</a></li>
2443 <li data-name="LuCI.rpc#declare"><a href="LuCI.rpc.html#declare">declare</a></li>
2445 <li data-name="LuCI.rpc#getBaseURL"><a href="LuCI.rpc.html#getBaseURL">getBaseURL</a></li>
2447 <li data-name="LuCI.rpc#getSessionID"><a href="LuCI.rpc.html#getSessionID">getSessionID</a></li>
2449 <li data-name="LuCI.rpc#getStatusText"><a href="LuCI.rpc.html#getStatusText">getStatusText</a></li>
2451 <li data-name="LuCI.rpc#list"><a href="LuCI.rpc.html#list">list</a></li>
2453 <li data-name="LuCI.rpc#removeInterceptor"><a href="LuCI.rpc.html#removeInterceptor">removeInterceptor</a></li>
2455 <li data-name="LuCI.rpc#setBaseURL"><a href="LuCI.rpc.html#setBaseURL">setBaseURL</a></li>
2457 <li data-name="LuCI.rpc#setSessionID"><a href="LuCI.rpc.html#setSessionID">setSessionID</a></li>
2460 <ul class="events itemMembers">
2465 <li class="item" data-name="LuCI.uci">
2466 <span class="title">
2467 <a href="LuCI.uci.html">LuCI.uci</a>
2470 <ul class="members itemMembers">
2473 <ul class="typedefs itemMembers">
2475 <span class="subtitle">Typedefs</span>
2477 <li data-name="LuCI.uci.ChangeRecord"><a href="LuCI.uci.html#.ChangeRecord">ChangeRecord</a></li>
2479 <li data-name="LuCI.uci.SectionObject"><a href="LuCI.uci.html#.SectionObject">SectionObject</a></li>
2481 <li data-name="LuCI.uci~sectionsFn"><a href="LuCI.uci.html#~sectionsFn">sectionsFn</a></li>
2484 <ul class="typedefs itemMembers">
2487 <ul class="methods itemMembers">
2489 <span class="subtitle">Methods</span>
2491 <li data-name="LuCI.uci#add"><a href="LuCI.uci.html#add">add</a></li>
2493 <li data-name="LuCI.uci#apply"><a href="LuCI.uci.html#apply">apply</a></li>
2495 <li data-name="LuCI.uci#changes"><a href="LuCI.uci.html#changes">changes</a></li>
2497 <li data-name="LuCI.uci#createSID"><a href="LuCI.uci.html#createSID">createSID</a></li>
2499 <li data-name="LuCI.uci#get"><a href="LuCI.uci.html#get">get</a></li>
2501 <li data-name="LuCI.uci#get_first"><a href="LuCI.uci.html#get_first">get_first</a></li>
2503 <li data-name="LuCI.uci#load"><a href="LuCI.uci.html#load">load</a></li>
2505 <li data-name="LuCI.uci#move"><a href="LuCI.uci.html#move">move</a></li>
2507 <li data-name="LuCI.uci#remove"><a href="LuCI.uci.html#remove">remove</a></li>
2509 <li data-name="LuCI.uci#resolveSID"><a href="LuCI.uci.html#resolveSID">resolveSID</a></li>
2511 <li data-name="LuCI.uci#save"><a href="LuCI.uci.html#save">save</a></li>
2513 <li data-name="LuCI.uci#sections"><a href="LuCI.uci.html#sections">sections</a></li>
2515 <li data-name="LuCI.uci#set"><a href="LuCI.uci.html#set">set</a></li>
2517 <li data-name="LuCI.uci#set_first"><a href="LuCI.uci.html#set_first">set_first</a></li>
2519 <li data-name="LuCI.uci#unload"><a href="LuCI.uci.html#unload">unload</a></li>
2521 <li data-name="LuCI.uci#unset"><a href="LuCI.uci.html#unset">unset</a></li>
2523 <li data-name="LuCI.uci#unset_first"><a href="LuCI.uci.html#unset_first">unset_first</a></li>
2526 <ul class="events itemMembers">
2531 <li class="item" data-name="LuCI.ui">
2532 <span class="title">
2533 <a href="LuCI.ui.html">LuCI.ui</a>
2536 <ul class="members itemMembers">
2539 <ul class="typedefs itemMembers">
2541 <span class="subtitle">Typedefs</span>
2543 <li data-name="LuCI.ui.FileUploadReply"><a href="LuCI.ui.html#.FileUploadReply">FileUploadReply</a></li>
2546 <ul class="typedefs itemMembers">
2549 <ul class="methods itemMembers">
2551 <span class="subtitle">Methods</span>
2553 <li data-name="LuCI.ui#addNotification"><a href="LuCI.ui.html#addNotification">addNotification</a></li>
2555 <li data-name="LuCI.ui#addValidator"><a href="LuCI.ui.html#addValidator">addValidator</a></li>
2557 <li data-name="LuCI.ui#awaitReconnect"><a href="LuCI.ui.html#awaitReconnect">awaitReconnect</a></li>
2559 <li data-name="LuCI.ui#createHandlerFn"><a href="LuCI.ui.html#createHandlerFn">createHandlerFn</a></li>
2561 <li data-name="LuCI.ui#hideIndicator"><a href="LuCI.ui.html#hideIndicator">hideIndicator</a></li>
2563 <li data-name="LuCI.ui#hideModal"><a href="LuCI.ui.html#hideModal">hideModal</a></li>
2565 <li data-name="LuCI.ui#instantiateView"><a href="LuCI.ui.html#instantiateView">instantiateView</a></li>
2567 <li data-name="LuCI.ui#itemlist"><a href="LuCI.ui.html#itemlist">itemlist</a></li>
2569 <li data-name="LuCI.ui#pingDevice"><a href="LuCI.ui.html#pingDevice">pingDevice</a></li>
2571 <li data-name="LuCI.ui#showIndicator"><a href="LuCI.ui.html#showIndicator">showIndicator</a></li>
2573 <li data-name="LuCI.ui#showModal"><a href="LuCI.ui.html#showModal">showModal</a></li>
2575 <li data-name="LuCI.ui#uploadFile"><a href="LuCI.ui.html#uploadFile">uploadFile</a></li>
2578 <ul class="events itemMembers">
2583 <li class="item" data-name="LuCI.ui.AbstractElement">
2584 <span class="title">
2585 <a href="LuCI.ui.AbstractElement.html">LuCI.ui.AbstractElement</a>
2588 <ul class="members itemMembers">
2591 <ul class="typedefs itemMembers">
2593 <span class="subtitle">Typedefs</span>
2595 <li data-name="LuCI.ui.AbstractElement.InitOptions"><a href="LuCI.ui.AbstractElement.html#.InitOptions">InitOptions</a></li>
2598 <ul class="typedefs itemMembers">
2601 <ul class="methods itemMembers">
2603 <span class="subtitle">Methods</span>
2605 <li data-name="LuCI.ui.AbstractElement#getValue"><a href="LuCI.ui.AbstractElement.html#getValue">getValue</a></li>
2607 <li data-name="LuCI.ui.AbstractElement#isValid"><a href="LuCI.ui.AbstractElement.html#isValid">isValid</a></li>
2609 <li data-name="LuCI.ui.AbstractElement#registerEvents"><a href="LuCI.ui.AbstractElement.html#registerEvents">registerEvents</a></li>
2611 <li data-name="LuCI.ui.AbstractElement#render"><a href="LuCI.ui.AbstractElement.html#render">render</a></li>
2613 <li data-name="LuCI.ui.AbstractElement#setChangeEvents"><a href="LuCI.ui.AbstractElement.html#setChangeEvents">setChangeEvents</a></li>
2615 <li data-name="LuCI.ui.AbstractElement#setUpdateEvents"><a href="LuCI.ui.AbstractElement.html#setUpdateEvents">setUpdateEvents</a></li>
2617 <li data-name="LuCI.ui.AbstractElement#setValue"><a href="LuCI.ui.AbstractElement.html#setValue">setValue</a></li>
2619 <li data-name="LuCI.ui.AbstractElement#triggerValidation"><a href="LuCI.ui.AbstractElement.html#triggerValidation">triggerValidation</a></li>
2622 <ul class="events itemMembers">
2627 <li class="item" data-name="LuCI.ui.changes">
2628 <span class="title">
2629 <a href="LuCI.ui.changes.html">LuCI.ui.changes</a>
2632 <ul class="members itemMembers">
2635 <ul class="typedefs itemMembers">
2638 <ul class="typedefs itemMembers">
2641 <ul class="methods itemMembers">
2643 <span class="subtitle">Methods</span>
2645 <li data-name="LuCI.ui.changes#apply"><a href="LuCI.ui.changes.html#apply">apply</a></li>
2647 <li data-name="LuCI.ui.changes#displayChanges"><a href="LuCI.ui.changes.html#displayChanges">displayChanges</a></li>
2649 <li data-name="LuCI.ui.changes#renderChangeIndicator"><a href="LuCI.ui.changes.html#renderChangeIndicator">renderChangeIndicator</a></li>
2651 <li data-name="LuCI.ui.changes#revert"><a href="LuCI.ui.changes.html#revert">revert</a></li>
2653 <li data-name="LuCI.ui.changes#setIndicator"><a href="LuCI.ui.changes.html#setIndicator">setIndicator</a></li>
2656 <ul class="events itemMembers">
2661 <li class="item" data-name="LuCI.ui.Checkbox">
2662 <span class="title">
2663 <a href="LuCI.ui.Checkbox.html">LuCI.ui.Checkbox</a>
2666 <ul class="members itemMembers">
2669 <ul class="typedefs itemMembers">
2671 <span class="subtitle">Typedefs</span>
2673 <li data-name="LuCI.ui.Checkbox.InitOptions"><a href="LuCI.ui.Checkbox.html#.InitOptions">InitOptions</a></li>
2676 <ul class="typedefs itemMembers">
2679 <ul class="methods itemMembers">
2681 <span class="subtitle">Methods</span>
2683 <li data-name="LuCI.ui.Checkbox#getValue"><a href="LuCI.ui.Checkbox.html#getValue">getValue</a></li>
2685 <li data-name="LuCI.ui.Checkbox#isChecked"><a href="LuCI.ui.Checkbox.html#isChecked">isChecked</a></li>
2687 <li data-name="LuCI.ui.Checkbox#isValid"><a href="LuCI.ui.Checkbox.html#isValid">isValid</a></li>
2689 <li data-name="LuCI.ui.Checkbox#registerEvents"><a href="LuCI.ui.Checkbox.html#registerEvents">registerEvents</a></li>
2691 <li data-name="LuCI.ui.Checkbox#render"><a href="LuCI.ui.Checkbox.html#render">render</a></li>
2693 <li data-name="LuCI.ui.Checkbox#setChangeEvents"><a href="LuCI.ui.Checkbox.html#setChangeEvents">setChangeEvents</a></li>
2695 <li data-name="LuCI.ui.Checkbox#setUpdateEvents"><a href="LuCI.ui.Checkbox.html#setUpdateEvents">setUpdateEvents</a></li>
2697 <li data-name="LuCI.ui.Checkbox#setValue"><a href="LuCI.ui.Checkbox.html#setValue">setValue</a></li>
2699 <li data-name="LuCI.ui.Checkbox#triggerValidation"><a href="LuCI.ui.Checkbox.html#triggerValidation">triggerValidation</a></li>
2702 <ul class="events itemMembers">
2707 <li class="item" data-name="LuCI.ui.Combobox">
2708 <span class="title">
2709 <a href="LuCI.ui.Combobox.html">LuCI.ui.Combobox</a>
2712 <ul class="members itemMembers">
2715 <ul class="typedefs itemMembers">
2717 <span class="subtitle">Typedefs</span>
2719 <li data-name="LuCI.ui.Combobox.InitOptions"><a href="LuCI.ui.Combobox.html#.InitOptions">InitOptions</a></li>
2722 <ul class="typedefs itemMembers">
2725 <ul class="methods itemMembers">
2727 <span class="subtitle">Methods</span>
2729 <li data-name="LuCI.ui.Combobox#addChoices"><a href="LuCI.ui.Combobox.html#addChoices">addChoices</a></li>
2731 <li data-name="LuCI.ui.Combobox#clearChoices"><a href="LuCI.ui.Combobox.html#clearChoices">clearChoices</a></li>
2733 <li data-name="LuCI.ui.Combobox#closeAllDropdowns"><a href="LuCI.ui.Combobox.html#closeAllDropdowns">closeAllDropdowns</a></li>
2735 <li data-name="LuCI.ui.Combobox#isValid"><a href="LuCI.ui.Combobox.html#isValid">isValid</a></li>
2737 <li data-name="LuCI.ui.Combobox#registerEvents"><a href="LuCI.ui.Combobox.html#registerEvents">registerEvents</a></li>
2739 <li data-name="LuCI.ui.Combobox#setChangeEvents"><a href="LuCI.ui.Combobox.html#setChangeEvents">setChangeEvents</a></li>
2741 <li data-name="LuCI.ui.Combobox#setUpdateEvents"><a href="LuCI.ui.Combobox.html#setUpdateEvents">setUpdateEvents</a></li>
2743 <li data-name="LuCI.ui.Combobox#triggerValidation"><a href="LuCI.ui.Combobox.html#triggerValidation">triggerValidation</a></li>
2746 <ul class="events itemMembers">
2751 <li class="item" data-name="LuCI.ui.ComboButton">
2752 <span class="title">
2753 <a href="LuCI.ui.ComboButton.html">LuCI.ui.ComboButton</a>
2756 <ul class="members itemMembers">
2759 <ul class="typedefs itemMembers">
2761 <span class="subtitle">Typedefs</span>
2763 <li data-name="LuCI.ui.ComboButton.InitOptions"><a href="LuCI.ui.ComboButton.html#.InitOptions">InitOptions</a></li>
2766 <ul class="typedefs itemMembers">
2769 <ul class="methods itemMembers">
2771 <span class="subtitle">Methods</span>
2773 <li data-name="LuCI.ui.ComboButton#addChoices"><a href="LuCI.ui.ComboButton.html#addChoices">addChoices</a></li>
2775 <li data-name="LuCI.ui.ComboButton#clearChoices"><a href="LuCI.ui.ComboButton.html#clearChoices">clearChoices</a></li>
2777 <li data-name="LuCI.ui.ComboButton#closeAllDropdowns"><a href="LuCI.ui.ComboButton.html#closeAllDropdowns">closeAllDropdowns</a></li>
2779 <li data-name="LuCI.ui.ComboButton#isValid"><a href="LuCI.ui.ComboButton.html#isValid">isValid</a></li>
2781 <li data-name="LuCI.ui.ComboButton#registerEvents"><a href="LuCI.ui.ComboButton.html#registerEvents">registerEvents</a></li>
2783 <li data-name="LuCI.ui.ComboButton#setChangeEvents"><a href="LuCI.ui.ComboButton.html#setChangeEvents">setChangeEvents</a></li>
2785 <li data-name="LuCI.ui.ComboButton#setUpdateEvents"><a href="LuCI.ui.ComboButton.html#setUpdateEvents">setUpdateEvents</a></li>
2787 <li data-name="LuCI.ui.ComboButton#triggerValidation"><a href="LuCI.ui.ComboButton.html#triggerValidation">triggerValidation</a></li>
2790 <ul class="events itemMembers">
2795 <li class="item" data-name="LuCI.ui.Dropdown">
2796 <span class="title">
2797 <a href="LuCI.ui.Dropdown.html">LuCI.ui.Dropdown</a>
2800 <ul class="members itemMembers">
2803 <ul class="typedefs itemMembers">
2805 <span class="subtitle">Typedefs</span>
2807 <li data-name="LuCI.ui.Dropdown.InitOptions"><a href="LuCI.ui.Dropdown.html#.InitOptions">InitOptions</a></li>
2810 <ul class="typedefs itemMembers">
2813 <ul class="methods itemMembers">
2815 <span class="subtitle">Methods</span>
2817 <li data-name="LuCI.ui.Dropdown#addChoices"><a href="LuCI.ui.Dropdown.html#addChoices">addChoices</a></li>
2819 <li data-name="LuCI.ui.Dropdown#clearChoices"><a href="LuCI.ui.Dropdown.html#clearChoices">clearChoices</a></li>
2821 <li data-name="LuCI.ui.Dropdown#closeAllDropdowns"><a href="LuCI.ui.Dropdown.html#closeAllDropdowns">closeAllDropdowns</a></li>
2823 <li data-name="LuCI.ui.Dropdown#getValue"><a href="LuCI.ui.Dropdown.html#getValue">getValue</a></li>
2825 <li data-name="LuCI.ui.Dropdown#isValid"><a href="LuCI.ui.Dropdown.html#isValid">isValid</a></li>
2827 <li data-name="LuCI.ui.Dropdown#registerEvents"><a href="LuCI.ui.Dropdown.html#registerEvents">registerEvents</a></li>
2829 <li data-name="LuCI.ui.Dropdown#render"><a href="LuCI.ui.Dropdown.html#render">render</a></li>
2831 <li data-name="LuCI.ui.Dropdown#setChangeEvents"><a href="LuCI.ui.Dropdown.html#setChangeEvents">setChangeEvents</a></li>
2833 <li data-name="LuCI.ui.Dropdown#setUpdateEvents"><a href="LuCI.ui.Dropdown.html#setUpdateEvents">setUpdateEvents</a></li>
2835 <li data-name="LuCI.ui.Dropdown#setValue"><a href="LuCI.ui.Dropdown.html#setValue">setValue</a></li>
2837 <li data-name="LuCI.ui.Dropdown#triggerValidation"><a href="LuCI.ui.Dropdown.html#triggerValidation">triggerValidation</a></li>
2840 <ul class="events itemMembers">
2845 <li class="item" data-name="LuCI.ui.DynamicList">
2846 <span class="title">
2847 <a href="LuCI.ui.DynamicList.html">LuCI.ui.DynamicList</a>
2850 <ul class="members itemMembers">
2853 <ul class="typedefs itemMembers">
2855 <span class="subtitle">Typedefs</span>
2857 <li data-name="LuCI.ui.DynamicList.InitOptions"><a href="LuCI.ui.DynamicList.html#.InitOptions">InitOptions</a></li>
2860 <ul class="typedefs itemMembers">
2863 <ul class="methods itemMembers">
2865 <span class="subtitle">Methods</span>
2867 <li data-name="LuCI.ui.DynamicList#addChoices"><a href="LuCI.ui.DynamicList.html#addChoices">addChoices</a></li>
2869 <li data-name="LuCI.ui.DynamicList#clearChoices"><a href="LuCI.ui.DynamicList.html#clearChoices">clearChoices</a></li>
2871 <li data-name="LuCI.ui.DynamicList#getValue"><a href="LuCI.ui.DynamicList.html#getValue">getValue</a></li>
2873 <li data-name="LuCI.ui.DynamicList#isValid"><a href="LuCI.ui.DynamicList.html#isValid">isValid</a></li>
2875 <li data-name="LuCI.ui.DynamicList#registerEvents"><a href="LuCI.ui.DynamicList.html#registerEvents">registerEvents</a></li>
2877 <li data-name="LuCI.ui.DynamicList#render"><a href="LuCI.ui.DynamicList.html#render">render</a></li>
2879 <li data-name="LuCI.ui.DynamicList#setChangeEvents"><a href="LuCI.ui.DynamicList.html#setChangeEvents">setChangeEvents</a></li>
2881 <li data-name="LuCI.ui.DynamicList#setUpdateEvents"><a href="LuCI.ui.DynamicList.html#setUpdateEvents">setUpdateEvents</a></li>
2883 <li data-name="LuCI.ui.DynamicList#setValue"><a href="LuCI.ui.DynamicList.html#setValue">setValue</a></li>
2885 <li data-name="LuCI.ui.DynamicList#triggerValidation"><a href="LuCI.ui.DynamicList.html#triggerValidation">triggerValidation</a></li>
2888 <ul class="events itemMembers">
2893 <li class="item" data-name="LuCI.ui.FileUpload">
2894 <span class="title">
2895 <a href="LuCI.ui.FileUpload.html">LuCI.ui.FileUpload</a>
2898 <ul class="members itemMembers">
2901 <ul class="typedefs itemMembers">
2903 <span class="subtitle">Typedefs</span>
2905 <li data-name="LuCI.ui.FileUpload.InitOptions"><a href="LuCI.ui.FileUpload.html#.InitOptions">InitOptions</a></li>
2908 <ul class="typedefs itemMembers">
2911 <ul class="methods itemMembers">
2913 <span class="subtitle">Methods</span>
2915 <li data-name="LuCI.ui.FileUpload#getValue"><a href="LuCI.ui.FileUpload.html#getValue">getValue</a></li>
2917 <li data-name="LuCI.ui.FileUpload#isValid"><a href="LuCI.ui.FileUpload.html#isValid">isValid</a></li>
2919 <li data-name="LuCI.ui.FileUpload#registerEvents"><a href="LuCI.ui.FileUpload.html#registerEvents">registerEvents</a></li>
2921 <li data-name="LuCI.ui.FileUpload#render"><a href="LuCI.ui.FileUpload.html#render">render</a></li>
2923 <li data-name="LuCI.ui.FileUpload#setChangeEvents"><a href="LuCI.ui.FileUpload.html#setChangeEvents">setChangeEvents</a></li>
2925 <li data-name="LuCI.ui.FileUpload#setUpdateEvents"><a href="LuCI.ui.FileUpload.html#setUpdateEvents">setUpdateEvents</a></li>
2927 <li data-name="LuCI.ui.FileUpload#setValue"><a href="LuCI.ui.FileUpload.html#setValue">setValue</a></li>
2929 <li data-name="LuCI.ui.FileUpload#triggerValidation"><a href="LuCI.ui.FileUpload.html#triggerValidation">triggerValidation</a></li>
2932 <ul class="events itemMembers">
2937 <li class="item" data-name="LuCI.ui.Hiddenfield">
2938 <span class="title">
2939 <a href="LuCI.ui.Hiddenfield.html">LuCI.ui.Hiddenfield</a>
2942 <ul class="members itemMembers">
2945 <ul class="typedefs itemMembers">
2948 <ul class="typedefs itemMembers">
2951 <ul class="methods itemMembers">
2953 <span class="subtitle">Methods</span>
2955 <li data-name="LuCI.ui.Hiddenfield#getValue"><a href="LuCI.ui.Hiddenfield.html#getValue">getValue</a></li>
2957 <li data-name="LuCI.ui.Hiddenfield#isValid"><a href="LuCI.ui.Hiddenfield.html#isValid">isValid</a></li>
2959 <li data-name="LuCI.ui.Hiddenfield#registerEvents"><a href="LuCI.ui.Hiddenfield.html#registerEvents">registerEvents</a></li>
2961 <li data-name="LuCI.ui.Hiddenfield#render"><a href="LuCI.ui.Hiddenfield.html#render">render</a></li>
2963 <li data-name="LuCI.ui.Hiddenfield#setChangeEvents"><a href="LuCI.ui.Hiddenfield.html#setChangeEvents">setChangeEvents</a></li>
2965 <li data-name="LuCI.ui.Hiddenfield#setUpdateEvents"><a href="LuCI.ui.Hiddenfield.html#setUpdateEvents">setUpdateEvents</a></li>
2967 <li data-name="LuCI.ui.Hiddenfield#setValue"><a href="LuCI.ui.Hiddenfield.html#setValue">setValue</a></li>
2969 <li data-name="LuCI.ui.Hiddenfield#triggerValidation"><a href="LuCI.ui.Hiddenfield.html#triggerValidation">triggerValidation</a></li>
2972 <ul class="events itemMembers">
2977 <li class="item" data-name="LuCI.ui.Select">
2978 <span class="title">
2979 <a href="LuCI.ui.Select.html">LuCI.ui.Select</a>
2982 <ul class="members itemMembers">
2985 <ul class="typedefs itemMembers">
2987 <span class="subtitle">Typedefs</span>
2989 <li data-name="LuCI.ui.Select.InitOptions"><a href="LuCI.ui.Select.html#.InitOptions">InitOptions</a></li>
2992 <ul class="typedefs itemMembers">
2995 <ul class="methods itemMembers">
2997 <span class="subtitle">Methods</span>
2999 <li data-name="LuCI.ui.Select#getValue"><a href="LuCI.ui.Select.html#getValue">getValue</a></li>
3001 <li data-name="LuCI.ui.Select#isValid"><a href="LuCI.ui.Select.html#isValid">isValid</a></li>
3003 <li data-name="LuCI.ui.Select#registerEvents"><a href="LuCI.ui.Select.html#registerEvents">registerEvents</a></li>
3005 <li data-name="LuCI.ui.Select#render"><a href="LuCI.ui.Select.html#render">render</a></li>
3007 <li data-name="LuCI.ui.Select#setChangeEvents"><a href="LuCI.ui.Select.html#setChangeEvents">setChangeEvents</a></li>
3009 <li data-name="LuCI.ui.Select#setUpdateEvents"><a href="LuCI.ui.Select.html#setUpdateEvents">setUpdateEvents</a></li>
3011 <li data-name="LuCI.ui.Select#setValue"><a href="LuCI.ui.Select.html#setValue">setValue</a></li>
3013 <li data-name="LuCI.ui.Select#triggerValidation"><a href="LuCI.ui.Select.html#triggerValidation">triggerValidation</a></li>
3016 <ul class="events itemMembers">
3021 <li class="item" data-name="LuCI.ui.tabs">
3022 <span class="title">
3023 <a href="LuCI.ui.tabs.html">LuCI.ui.tabs</a>
3026 <ul class="members itemMembers">
3029 <ul class="typedefs itemMembers">
3032 <ul class="typedefs itemMembers">
3035 <ul class="methods itemMembers">
3037 <span class="subtitle">Methods</span>
3039 <li data-name="LuCI.ui.tabs#initTabGroup"><a href="LuCI.ui.tabs.html#initTabGroup">initTabGroup</a></li>
3041 <li data-name="LuCI.ui.tabs#isEmptyPane"><a href="LuCI.ui.tabs.html#isEmptyPane">isEmptyPane</a></li>
3044 <ul class="events itemMembers">
3049 <li class="item" data-name="LuCI.ui.Textarea">
3050 <span class="title">
3051 <a href="LuCI.ui.Textarea.html">LuCI.ui.Textarea</a>
3054 <ul class="members itemMembers">
3057 <ul class="typedefs itemMembers">
3059 <span class="subtitle">Typedefs</span>
3061 <li data-name="LuCI.ui.Textarea.InitOptions"><a href="LuCI.ui.Textarea.html#.InitOptions">InitOptions</a></li>
3064 <ul class="typedefs itemMembers">
3067 <ul class="methods itemMembers">
3069 <span class="subtitle">Methods</span>
3071 <li data-name="LuCI.ui.Textarea#getValue"><a href="LuCI.ui.Textarea.html#getValue">getValue</a></li>
3073 <li data-name="LuCI.ui.Textarea#isValid"><a href="LuCI.ui.Textarea.html#isValid">isValid</a></li>
3075 <li data-name="LuCI.ui.Textarea#registerEvents"><a href="LuCI.ui.Textarea.html#registerEvents">registerEvents</a></li>
3077 <li data-name="LuCI.ui.Textarea#render"><a href="LuCI.ui.Textarea.html#render">render</a></li>
3079 <li data-name="LuCI.ui.Textarea#setChangeEvents"><a href="LuCI.ui.Textarea.html#setChangeEvents">setChangeEvents</a></li>
3081 <li data-name="LuCI.ui.Textarea#setUpdateEvents"><a href="LuCI.ui.Textarea.html#setUpdateEvents">setUpdateEvents</a></li>
3083 <li data-name="LuCI.ui.Textarea#setValue"><a href="LuCI.ui.Textarea.html#setValue">setValue</a></li>
3085 <li data-name="LuCI.ui.Textarea#triggerValidation"><a href="LuCI.ui.Textarea.html#triggerValidation">triggerValidation</a></li>
3088 <ul class="events itemMembers">
3093 <li class="item" data-name="LuCI.ui.Textfield">
3094 <span class="title">
3095 <a href="LuCI.ui.Textfield.html">LuCI.ui.Textfield</a>
3098 <ul class="members itemMembers">
3101 <ul class="typedefs itemMembers">
3103 <span class="subtitle">Typedefs</span>
3105 <li data-name="LuCI.ui.Textfield.InitOptions"><a href="LuCI.ui.Textfield.html#.InitOptions">InitOptions</a></li>
3108 <ul class="typedefs itemMembers">
3111 <ul class="methods itemMembers">
3113 <span class="subtitle">Methods</span>
3115 <li data-name="LuCI.ui.Textfield#getValue"><a href="LuCI.ui.Textfield.html#getValue">getValue</a></li>
3117 <li data-name="LuCI.ui.Textfield#isValid"><a href="LuCI.ui.Textfield.html#isValid">isValid</a></li>
3119 <li data-name="LuCI.ui.Textfield#registerEvents"><a href="LuCI.ui.Textfield.html#registerEvents">registerEvents</a></li>
3121 <li data-name="LuCI.ui.Textfield#render"><a href="LuCI.ui.Textfield.html#render">render</a></li>
3123 <li data-name="LuCI.ui.Textfield#setChangeEvents"><a href="LuCI.ui.Textfield.html#setChangeEvents">setChangeEvents</a></li>
3125 <li data-name="LuCI.ui.Textfield#setUpdateEvents"><a href="LuCI.ui.Textfield.html#setUpdateEvents">setUpdateEvents</a></li>
3127 <li data-name="LuCI.ui.Textfield#setValue"><a href="LuCI.ui.Textfield.html#setValue">setValue</a></li>
3129 <li data-name="LuCI.ui.Textfield#triggerValidation"><a href="LuCI.ui.Textfield.html#triggerValidation">triggerValidation</a></li>
3132 <ul class="events itemMembers">
3137 <li class="item" data-name="LuCI.view">
3138 <span class="title">
3139 <a href="LuCI.view.html">LuCI.view</a>
3142 <ul class="members itemMembers">
3145 <ul class="typedefs itemMembers">
3148 <ul class="typedefs itemMembers">
3151 <ul class="methods itemMembers">
3153 <span class="subtitle">Methods</span>
3155 <li data-name="LuCI.view#addFooter"><a href="LuCI.view.html#addFooter">addFooter</a></li>
3157 <li data-name="LuCI.view#handleReset"><a href="LuCI.view.html#handleReset">handleReset</a></li>
3159 <li data-name="LuCI.view#handleSave"><a href="LuCI.view.html#handleSave">handleSave</a></li>
3161 <li data-name="LuCI.view#handleSaveApply"><a href="LuCI.view.html#handleSaveApply">handleSaveApply</a></li>
3163 <li data-name="LuCI.view#load"><a href="LuCI.view.html#load">load</a></li>
3165 <li data-name="LuCI.view#render"><a href="LuCI.view.html#render">render</a></li>
3168 <ul class="events itemMembers">
3173 <li class="item" data-name="LuCI.xhr">
3174 <span class="title">
3175 <a href="LuCI.xhr.html">LuCI.xhr</a>
3178 <ul class="members itemMembers">
3181 <ul class="typedefs itemMembers">
3184 <ul class="typedefs itemMembers">
3187 <ul class="methods itemMembers">
3189 <span class="subtitle">Methods</span>
3191 <li data-name="LuCI.xhr#abort"><a href="LuCI.xhr.html#abort">abort</a></li>
3193 <li data-name="LuCI.xhr#busy"><a href="LuCI.xhr.html#busy">busy</a></li>
3195 <li data-name="LuCI.xhr#cancel"><a href="LuCI.xhr.html#cancel">cancel</a></li>
3197 <li data-name="LuCI.xhr#get"><a href="LuCI.xhr.html#get">get</a></li>
3199 <li data-name="LuCI.xhr#post"><a href="LuCI.xhr.html#post">post</a></li>
3201 <li data-name="LuCI.xhr#send_form"><a href="LuCI.xhr.html#send_form">send_form</a></li>
3204 <ul class="events itemMembers">
3212 <h1 class="page-title" data-filename="ui.js.html">Source: ui.js</h1>
3219 <pre id="source-code" class="prettyprint source "><code>'use strict';
3220 'require validation';
3221 'require baseclass';
3229 var modalDiv = null,
3231 indicatorDiv = null,
3232 tooltipTimeout = null;
3235 * @class AbstractElement
3240 * The `AbstractElement` class serves as abstract base for the different widgets
3241 * implemented by `LuCI.ui`. It provides the common logic for getting and
3242 * setting values, for checking the validity state and for wiring up required
3245 * UI widget instances are usually not supposed to be created by view code
3246 * directly, instead they're implicitely created by `LuCI.form` when
3247 * instantiating CBI forms.
3249 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3250 * in views, use `'require ui'` and refer to `ui.AbstractElement`. To import
3251 * it in external JavaScript, use `L.require("ui").then(...)` and access the
3252 * `AbstractElement` property of the class instance value.
3254 var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ {
3256 * @typedef {Object} InitOptions
3257 * @memberof LuCI.ui.AbstractElement
3259 * @property {string} [id]
3260 * Specifies the widget ID to use. It will be used as HTML `id` attribute
3261 * on the toplevel widget DOM node.
3263 * @property {string} [name]
3264 * Specifies the widget name which is set as HTML `name` attribute on the
3265 * corresponding `<input>` element.
3267 * @property {boolean} [optional=true]
3268 * Specifies whether the input field allows empty values.
3270 * @property {string} [datatype=string]
3271 * An expression describing the input data validation constraints.
3272 * It defaults to `string` which will allow any value.
3273 * See {@link LuCI.validation} for details on the expression format.
3275 * @property {function} [validator]
3276 * Specifies a custom validator function which is invoked after the
3277 * standard validation constraints are checked. The function should return
3278 * `true` to accept the given input value. Any other return value type is
3279 * converted to a string and treated as validation error message.
3283 * Read the current value of the input widget.
3286 * @memberof LuCI.ui.AbstractElement
3287 * @returns {string|string[]|null}
3288 * The current value of the input element. For simple inputs like text
3289 * fields or selects, the return value type will be a - possibly empty -
3290 * string. Complex widgets such as `DynamicList` instances may result in
3291 * an array of strings or `null` for unset values.
3293 getValue: function() {
3294 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3295 return this.node.value;
3301 * Set the current value of the input widget.
3304 * @memberof LuCI.ui.AbstractElement
3305 * @param {string|string[]|null} value
3306 * The value to set the input element to. For simple inputs like text
3307 * fields or selects, the value should be a - possibly empty - string.
3308 * Complex widgets such as `DynamicList` instances may accept string array
3311 setValue: function(value) {
3312 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3313 this.node.value = value;
3317 * Check whether the current input value is valid.
3320 * @memberof LuCI.ui.AbstractElement
3321 * @returns {boolean}
3322 * Returns `true` if the current input value is valid or `false` if it does
3323 * not meet the validation constraints.
3325 isValid: function() {
3326 return (this.validState !== false);
3330 * Force validation of the current input value.
3332 * Usually input validation is automatically triggered by various DOM events
3333 * bound to the input widget. In some cases it is required though to manually
3334 * trigger validation runs, e.g. when programmatically altering values.
3337 * @memberof LuCI.ui.AbstractElement
3339 triggerValidation: function() {
3340 if (typeof(this.vfunc) != 'function')
3343 var wasValid = this.isValid();
3347 return (wasValid != this.isValid());
3351 * Dispatch a custom (synthetic) event in response to received events.
3353 * Sets up event handlers on the given target DOM node for the given event
3354 * names that dispatch a custom event of the given type to the widget root
3357 * The primary purpose of this function is to set up a series of custom
3358 * uniform standard events such as `widget-update`, `validation-success`,
3359 * `validation-failure` etc. which are triggered by various different
3360 * widget specific native DOM events.
3363 * @memberof LuCI.ui.AbstractElement
3364 * @param {Node} targetNode
3365 * Specifies the DOM node on which the native event listeners should be
3368 * @param {string} synevent
3369 * The name of the custom event to dispatch to the widget root DOM node.
3371 * @param {string[]} events
3372 * The native DOM events for which event handlers should be registered.
3374 registerEvents: function(targetNode, synevent, events) {
3375 var dispatchFn = L.bind(function(ev) {
3376 this.node.dispatchEvent(new CustomEvent(synevent, { bubbles: true }));
3379 for (var i = 0; i < events.length; i++)
3380 targetNode.addEventListener(events[i], dispatchFn);
3384 * Setup listeners for native DOM events that may update the widget value.
3386 * Sets up event handlers on the given target DOM node for the given event
3387 * names which may cause the input value to update, such as `keyup` or
3388 * `onclick` events. In contrast to change events, such update events will
3389 * trigger input value validation.
3392 * @memberof LuCI.ui.AbstractElement
3393 * @param {Node} targetNode
3394 * Specifies the DOM node on which the event listeners should be registered.
3396 * @param {...string} events
3397 * The DOM events for which event handlers should be registered.
3399 setUpdateEvents: function(targetNode /*, ... */) {
3400 var datatype = this.options.datatype,
3401 optional = this.options.hasOwnProperty('optional') ? this.options.optional : true,
3402 validate = this.options.validate,
3403 events = this.varargs(arguments, 1);
3405 this.registerEvents(targetNode, 'widget-update', events);
3407 if (!datatype && !validate)
3410 this.vfunc = UI.prototype.addValidator.apply(UI.prototype, [
3411 targetNode, datatype || 'string',
3415 this.node.addEventListener('validation-success', L.bind(function(ev) {
3416 this.validState = true;
3419 this.node.addEventListener('validation-failure', L.bind(function(ev) {
3420 this.validState = false;
3425 * Setup listeners for native DOM events that may change the widget value.
3427 * Sets up event handlers on the given target DOM node for the given event
3428 * names which may cause the input value to change completely, such as
3429 * `change` events in a select menu. In contrast to update events, such
3430 * change events will not trigger input value validation but they may cause
3431 * field dependencies to get re-evaluated and will mark the input widget
3435 * @memberof LuCI.ui.AbstractElement
3436 * @param {Node} targetNode
3437 * Specifies the DOM node on which the event listeners should be registered.
3439 * @param {...string} events
3440 * The DOM events for which event handlers should be registered.
3442 setChangeEvents: function(targetNode /*, ... */) {
3443 var tag_changed = L.bind(function(ev) { this.setAttribute('data-changed', true) }, this.node);
3445 for (var i = 1; i < arguments.length; i++)
3446 targetNode.addEventListener(arguments[i], tag_changed);
3448 this.registerEvents(targetNode, 'widget-change', this.varargs(arguments, 1));
3452 * Render the widget, setup event listeners and return resulting markup.
3455 * @memberof LuCI.ui.AbstractElement
3458 * Returns a DOM Node or DocumentFragment containing the rendered
3461 render: function() {}
3465 * Instantiate a text input widget.
3467 * @constructor Textfield
3469 * @augments LuCI.ui.AbstractElement
3473 * The `Textfield` class implements a standard single line text input field.
3475 * UI widget instances are usually not supposed to be created by view code
3476 * directly, instead they're implicitely created by `LuCI.form` when
3477 * instantiating CBI forms.
3479 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3480 * in views, use `'require ui'` and refer to `ui.Textfield`. To import it in
3481 * external JavaScript, use `L.require("ui").then(...)` and access the
3482 * `Textfield` property of the class instance value.
3484 * @param {string} [value=null]
3485 * The initial input value.
3487 * @param {LuCI.ui.Textfield.InitOptions} [options]
3488 * Object describing the widget specific options to initialize the input.
3490 var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ {
3492 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3493 * the following properties are recognized:
3495 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3496 * @memberof LuCI.ui.Textfield
3498 * @property {boolean} [password=false]
3499 * Specifies whether the input should be rendered as concealed password field.
3501 * @property {boolean} [readonly=false]
3502 * Specifies whether the input widget should be rendered readonly.
3504 * @property {number} [maxlength]
3505 * Specifies the HTML `maxlength` attribute to set on the corresponding
3506 * `<input>` element. Note that this a legacy property that exists for
3507 * compatibility reasons. It is usually better to `maxlength(N)` validation
3510 * @property {string} [placeholder]
3511 * Specifies the HTML `placeholder` attribute which is displayed when the
3512 * corresponding `<input>` element is empty.
3514 __init__: function(value, options) {
3516 this.options = Object.assign({
3523 render: function() {
3524 var frameEl = E('div', { 'id': this.options.id });
3526 if (this.options.password) {
3527 frameEl.classList.add('nowrap');
3528 frameEl.appendChild(E('input', {
3530 'style': 'position:absolute; left:-100000px',
3531 'aria-hidden': true,
3533 'name': this.options.name ? 'password.%s'.format(this.options.name) : null
3537 frameEl.appendChild(E('input', {
3538 'id': this.options.id ? 'widget.' + this.options.id : null,
3539 'name': this.options.name,
3540 'type': this.options.password ? 'password' : 'text',
3541 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text',
3542 'readonly': this.options.readonly ? '' : null,
3543 'maxlength': this.options.maxlength,
3544 'placeholder': this.options.placeholder,
3545 'value': this.value,
3548 if (this.options.password)
3549 frameEl.appendChild(E('button', {
3550 'class': 'cbi-button cbi-button-neutral',
3551 'title': _('Reveal/hide password'),
3552 'aria-label': _('Reveal/hide password'),
3553 'click': function(ev) {
3554 var e = this.previousElementSibling;
3555 e.type = (e.type === 'password') ? 'text' : 'password';
3556 ev.preventDefault();
3560 return this.bind(frameEl);
3564 bind: function(frameEl) {
3565 var inputEl = frameEl.childNodes[+!!this.options.password];
3567 this.node = frameEl;
3569 this.setUpdateEvents(inputEl, 'keyup', 'blur');
3570 this.setChangeEvents(inputEl, 'change');
3572 dom.bindClassInstance(frameEl, this);
3578 getValue: function() {
3579 var inputEl = this.node.childNodes[+!!this.options.password];
3580 return inputEl.value;
3584 setValue: function(value) {
3585 var inputEl = this.node.childNodes[+!!this.options.password];
3586 inputEl.value = value;
3591 * Instantiate a textarea widget.
3593 * @constructor Textarea
3595 * @augments LuCI.ui.AbstractElement
3599 * The `Textarea` class implements a multiline text area input field.
3601 * UI widget instances are usually not supposed to be created by view code
3602 * directly, instead they're implicitely created by `LuCI.form` when
3603 * instantiating CBI forms.
3605 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3606 * in views, use `'require ui'` and refer to `ui.Textarea`. To import it in
3607 * external JavaScript, use `L.require("ui").then(...)` and access the
3608 * `Textarea` property of the class instance value.
3610 * @param {string} [value=null]
3611 * The initial input value.
3613 * @param {LuCI.ui.Textarea.InitOptions} [options]
3614 * Object describing the widget specific options to initialize the input.
3616 var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ {
3618 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3619 * the following properties are recognized:
3621 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3622 * @memberof LuCI.ui.Textarea
3624 * @property {boolean} [readonly=false]
3625 * Specifies whether the input widget should be rendered readonly.
3627 * @property {string} [placeholder]
3628 * Specifies the HTML `placeholder` attribute which is displayed when the
3629 * corresponding `<textarea>` element is empty.
3631 * @property {boolean} [monospace=false]
3632 * Specifies whether a monospace font should be forced for the textarea
3635 * @property {number} [cols]
3636 * Specifies the HTML `cols` attribute to set on the corresponding
3637 * `<textarea>` element.
3639 * @property {number} [rows]
3640 * Specifies the HTML `rows` attribute to set on the corresponding
3641 * `<textarea>` element.
3643 * @property {boolean} [wrap=false]
3644 * Specifies whether the HTML `wrap` attribute should be set.
3646 __init__: function(value, options) {
3648 this.options = Object.assign({
3657 render: function() {
3658 var frameEl = E('div', { 'id': this.options.id }),
3659 value = (this.value != null) ? String(this.value) : '';
3661 frameEl.appendChild(E('textarea', {
3662 'id': this.options.id ? 'widget.' + this.options.id : null,
3663 'name': this.options.name,
3664 'class': 'cbi-input-textarea',
3665 'readonly': this.options.readonly ? '' : null,
3666 'placeholder': this.options.placeholder,
3667 'style': !this.options.cols ? 'width:100%' : null,
3668 'cols': this.options.cols,
3669 'rows': this.options.rows,
3670 'wrap': this.options.wrap ? '' : null
3673 if (this.options.monospace)
3674 frameEl.firstElementChild.style.fontFamily = 'monospace';
3676 return this.bind(frameEl);
3680 bind: function(frameEl) {
3681 var inputEl = frameEl.firstElementChild;
3683 this.node = frameEl;
3685 this.setUpdateEvents(inputEl, 'keyup', 'blur');
3686 this.setChangeEvents(inputEl, 'change');
3688 dom.bindClassInstance(frameEl, this);
3694 getValue: function() {
3695 return this.node.firstElementChild.value;
3699 setValue: function(value) {
3700 this.node.firstElementChild.value = value;
3705 * Instantiate a checkbox widget.
3707 * @constructor Checkbox
3709 * @augments LuCI.ui.AbstractElement
3713 * The `Checkbox` class implements a simple checkbox input field.
3715 * UI widget instances are usually not supposed to be created by view code
3716 * directly, instead they're implicitely created by `LuCI.form` when
3717 * instantiating CBI forms.
3719 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3720 * in views, use `'require ui'` and refer to `ui.Checkbox`. To import it in
3721 * external JavaScript, use `L.require("ui").then(...)` and access the
3722 * `Checkbox` property of the class instance value.
3724 * @param {string} [value=null]
3725 * The initial input value.
3727 * @param {LuCI.ui.Checkbox.InitOptions} [options]
3728 * Object describing the widget specific options to initialize the input.
3730 var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ {
3732 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3733 * the following properties are recognized:
3735 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3736 * @memberof LuCI.ui.Checkbox
3738 * @property {string} [value_enabled=1]
3739 * Specifies the value corresponding to a checked checkbox.
3741 * @property {string} [value_disabled=0]
3742 * Specifies the value corresponding to an unchecked checkbox.
3744 * @property {string} [hiddenname]
3745 * Specifies the HTML `name` attribute of the hidden input backing the
3746 * checkbox. This is a legacy property existing for compatibility reasons,
3747 * it is required for HTML based form submissions.
3749 __init__: function(value, options) {
3751 this.options = Object.assign({
3758 render: function() {
3759 var id = 'cb%08x'.format(Math.random() * 0xffffffff);
3760 var frameEl = E('div', {
3761 'id': this.options.id,
3762 'class': 'cbi-checkbox'
3765 if (this.options.hiddenname)
3766 frameEl.appendChild(E('input', {
3768 'name': this.options.hiddenname,
3772 frameEl.appendChild(E('input', {
3774 'name': this.options.name,
3776 'value': this.options.value_enabled,
3777 'checked': (this.value == this.options.value_enabled) ? '' : null,
3778 'data-widget-id': this.options.id ? 'widget.' + this.options.id : null
3781 frameEl.appendChild(E('label', { 'for': id }));
3783 return this.bind(frameEl);
3787 bind: function(frameEl) {
3788 this.node = frameEl;
3790 this.setUpdateEvents(frameEl.lastElementChild.previousElementSibling, 'click', 'blur');
3791 this.setChangeEvents(frameEl.lastElementChild.previousElementSibling, 'change');
3793 dom.bindClassInstance(frameEl, this);
3799 * Test whether the checkbox is currently checked.
3802 * @memberof LuCI.ui.Checkbox
3803 * @returns {boolean}
3804 * Returns `true` when the checkbox is currently checked, otherwise `false`.
3806 isChecked: function() {
3807 return this.node.lastElementChild.previousElementSibling.checked;
3811 getValue: function() {
3812 return this.isChecked()
3813 ? this.options.value_enabled
3814 : this.options.value_disabled;
3818 setValue: function(value) {
3819 this.node.lastElementChild.previousElementSibling.checked = (value == this.options.value_enabled);
3824 * Instantiate a select dropdown or checkbox/radiobutton group.
3826 * @constructor Select
3828 * @augments LuCI.ui.AbstractElement
3832 * The `Select` class implements either a traditional HTML `<select>` element
3833 * or a group of checkboxes or radio buttons, depending on whether multiple
3834 * values are enabled or not.
3836 * UI widget instances are usually not supposed to be created by view code
3837 * directly, instead they're implicitely created by `LuCI.form` when
3838 * instantiating CBI forms.
3840 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3841 * in views, use `'require ui'` and refer to `ui.Select`. To import it in
3842 * external JavaScript, use `L.require("ui").then(...)` and access the
3843 * `Select` property of the class instance value.
3845 * @param {string|string[]} [value=null]
3846 * The initial input value(s).
3848 * @param {Object<string, string>} choices
3849 * Object containing the selectable choices of the widget. The object keys
3850 * serve as values for the different choices while the values are used as
3853 * @param {LuCI.ui.Select.InitOptions} [options]
3854 * Object describing the widget specific options to initialize the inputs.
3856 var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ {
3858 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3859 * the following properties are recognized:
3861 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3862 * @memberof LuCI.ui.Select
3864 * @property {boolean} [multiple=false]
3865 * Specifies whether multiple choice values may be selected.
3867 * @property {string} [widget=select]
3868 * Specifies the kind of widget to render. May be either `select` or
3869 * `individual`. When set to `select` an HTML `<select>` element will be
3870 * used, otherwise a group of checkbox or radio button elements is created,
3871 * depending on the value of the `multiple` option.
3873 * @property {string} [orientation=horizontal]
3874 * Specifies whether checkbox / radio button groups should be rendered
3875 * in a `horizontal` or `vertical` manner. Does not apply to the `select`
3878 * @property {boolean|string[]} [sort=false]
3879 * Specifies if and how to sort choice values. If set to `true`, the choice
3880 * values will be sorted alphabetically. If set to an array of strings, the
3881 * choice sort order is derived from the array.
3883 * @property {number} [size]
3884 * Specifies the HTML `size` attribute to set on the `<select>` element.
3885 * Only applicable to the `select` widget type.
3887 * @property {string} [placeholder=-- Please choose --]
3888 * Specifies a placeholder text which is displayed when no choice is
3889 * selected yet. Only applicable to the `select` widget type.
3891 __init__: function(value, choices, options) {
3892 if (!L.isObject(choices))
3895 if (!Array.isArray(value))
3896 value = (value != null && value != '') ? [ value ] : [];
3898 if (!options.multiple && value.length > 1)
3901 this.values = value;
3902 this.choices = choices;
3903 this.options = Object.assign({
3906 orientation: 'horizontal'
3909 if (this.choices.hasOwnProperty(''))
3910 this.options.optional = true;
3914 render: function() {
3915 var frameEl = E('div', { 'id': this.options.id }),
3916 keys = Object.keys(this.choices);
3918 if (this.options.sort === true)
3920 else if (Array.isArray(this.options.sort))
3921 keys = this.options.sort;
3923 if (this.options.widget == 'select') {
3924 frameEl.appendChild(E('select', {
3925 'id': this.options.id ? 'widget.' + this.options.id : null,
3926 'name': this.options.name,
3927 'size': this.options.size,
3928 'class': 'cbi-input-select',
3929 'multiple': this.options.multiple ? '' : null
3932 if (this.options.optional)
3933 frameEl.lastChild.appendChild(E('option', {
3935 'selected': (this.values.length == 0 || this.values[0] == '') ? '' : null
3936 }, [ this.choices[''] || this.options.placeholder || _('-- Please choose --') ]));
3938 for (var i = 0; i < keys.length; i++) {
3939 if (keys[i] == null || keys[i] == '')
3942 frameEl.lastChild.appendChild(E('option', {
3944 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
3945 }, [ this.choices[keys[i]] || keys[i] ]));
3949 var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' ') : E('br');
3951 for (var i = 0; i < keys.length; i++) {
3952 frameEl.appendChild(E('label', {}, [
3954 'id': this.options.id ? 'widget.' + this.options.id : null,
3955 'name': this.options.id || this.options.name,
3956 'type': this.options.multiple ? 'checkbox' : 'radio',
3957 'class': this.options.multiple ? 'cbi-input-checkbox' : 'cbi-input-radio',
3959 'checked': (this.values.indexOf(keys[i]) > -1) ? '' : null
3961 this.choices[keys[i]] || keys[i]
3964 if (i + 1 == this.options.size)
3965 frameEl.appendChild(brEl);
3969 return this.bind(frameEl);
3973 bind: function(frameEl) {
3974 this.node = frameEl;
3976 if (this.options.widget == 'select') {
3977 this.setUpdateEvents(frameEl.firstChild, 'change', 'click', 'blur');
3978 this.setChangeEvents(frameEl.firstChild, 'change');
3981 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
3982 for (var i = 0; i < radioEls.length; i++) {
3983 this.setUpdateEvents(radioEls[i], 'change', 'click', 'blur');
3984 this.setChangeEvents(radioEls[i], 'change', 'click', 'blur');
3988 dom.bindClassInstance(frameEl, this);
3994 getValue: function() {
3995 if (this.options.widget == 'select')
3996 return this.node.firstChild.value;
3998 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
3999 for (var i = 0; i < radioEls.length; i++)
4000 if (radioEls[i].checked)
4001 return radioEls[i].value;
4007 setValue: function(value) {
4008 if (this.options.widget == 'select') {
4012 for (var i = 0; i < this.node.firstChild.options.length; i++)
4013 this.node.firstChild.options[i].selected = (this.node.firstChild.options[i].value == value);
4018 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
4019 for (var i = 0; i < radioEls.length; i++)
4020 radioEls[i].checked = (radioEls[i].value == value);
4025 * Instantiate a rich dropdown choice widget.
4027 * @constructor Dropdown
4029 * @augments LuCI.ui.AbstractElement
4033 * The `Dropdown` class implements a rich, stylable dropdown menu which
4034 * supports non-text choice labels.
4036 * UI widget instances are usually not supposed to be created by view code
4037 * directly, instead they're implicitely created by `LuCI.form` when
4038 * instantiating CBI forms.
4040 * This class is automatically instantiated as part of `LuCI.ui`. To use it
4041 * in views, use `'require ui'` and refer to `ui.Dropdown`. To import it in
4042 * external JavaScript, use `L.require("ui").then(...)` and access the
4043 * `Dropdown` property of the class instance value.
4045 * @param {string|string[]} [value=null]
4046 * The initial input value(s).
4048 * @param {Object<string, *>} choices
4049 * Object containing the selectable choices of the widget. The object keys
4050 * serve as values for the different choices while the values are used as
4053 * @param {LuCI.ui.Dropdown.InitOptions} [options]
4054 * Object describing the widget specific options to initialize the dropdown.
4056 var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
4058 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
4059 * the following properties are recognized:
4061 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4062 * @memberof LuCI.ui.Dropdown
4064 * @property {boolean} [optional=true]
4065 * Specifies whether the dropdown selection is optional. In contrast to
4066 * other widgets, the `optional` constraint of dropdowns works differently;
4067 * instead of marking the widget invalid on empty values when set to `false`,
4068 * the user is not allowed to deselect all choices.
4070 * For single value dropdowns that means that no empty "please select"
4071 * choice is offered and for multi value dropdowns, the last selected choice
4072 * may not be deselected without selecting another choice first.
4074 * @property {boolean} [multiple]
4075 * Specifies whether multiple choice values may be selected. It defaults
4076 * to `true` when an array is passed as input value to the constructor.
4078 * @property {boolean|string[]} [sort=false]
4079 * Specifies if and how to sort choice values. If set to `true`, the choice
4080 * values will be sorted alphabetically. If set to an array of strings, the
4081 * choice sort order is derived from the array.
4083 * @property {string} [select_placeholder=-- Please choose --]
4084 * Specifies a placeholder text which is displayed when no choice is
4087 * @property {string} [custom_placeholder=-- custom --]
4088 * Specifies a placeholder text which is displayed in the text input
4089 * field allowing to enter custom choice values. Only applicable if the
4090 * `create` option is set to `true`.
4092 * @property {boolean} [create=false]
4093 * Specifies whether custom choices may be entered into the dropdown
4096 * @property {string} [create_query=.create-item-input]
4097 * Specifies a CSS selector expression used to find the input element
4098 * which is used to enter custom choice values. This should not normally
4099 * be used except by widgets derived from the Dropdown class.
4101 * @property {string} [create_template=script[type="item-template"]]
4102 * Specifies a CSS selector expression used to find an HTML element
4103 * serving as template for newly added custom choice values.
4105 * Any `{{value}}` placeholder string within the template elements text
4106 * content will be replaced by the user supplied choice value, the
4107 * resulting string is parsed as HTML and appended to the end of the
4108 * choice list. The template markup may specify one HTML element with a
4109 * `data-label-placeholder` attribute which is replaced by a matching
4110 * label value from the `choices` object or with the user supplied value
4111 * itself in case `choices` contains no matching choice label.
4113 * If the template element is not found or if no `create_template` selector
4114 * expression is specified, the default markup for newly created elements is
4115 * `<li data-value="{{value}}"><span data-label-placeholder="true" /></li>`.
4117 * @property {string} [create_markup]
4118 * This property allows specifying the markup for custom choices directly
4119 * instead of referring to a template element through CSS selectors.
4121 * Apart from that it works exactly like `create_template`.
4123 * @property {number} [display_items=3]
4124 * Specifies the maximum amount of choice labels that should be shown in
4125 * collapsed dropdown state before further selected choices are cut off.
4127 * Only applicable when `multiple` is `true`.
4129 * @property {number} [dropdown_items=-1]
4130 * Specifies the maximum amount of choices that should be shown when the
4131 * dropdown is open. If the amount of available choices exceeds this number,
4132 * the dropdown area must be scrolled to reach further items.
4134 * If set to `-1`, the dropdown menu will attempt to show all choice values
4135 * and only resort to scrolling if the amount of choices exceeds the available
4136 * screen space above and below the dropdown widget.
4138 * @property {string} [placeholder]
4139 * This property serves as a shortcut to set both `select_placeholder` and
4140 * `custom_placeholder`. Either of these properties will fallback to
4141 * `placeholder` if not specified.
4143 * @property {boolean} [readonly=false]
4144 * Specifies whether the custom choice input field should be rendered
4145 * readonly. Only applicable when `create` is `true`.
4147 * @property {number} [maxlength]
4148 * Specifies the HTML `maxlength` attribute to set on the custom choice
4149 * `<input>` element. Note that this a legacy property that exists for
4150 * compatibility reasons. It is usually better to `maxlength(N)` validation
4151 * expression. Only applicable when `create` is `true`.
4153 __init__: function(value, choices, options) {
4154 if (typeof(choices) != 'object')
4157 if (!Array.isArray(value))
4158 this.values = (value != null && value != '') ? [ value ] : [];
4160 this.values = value;
4162 this.choices = choices;
4163 this.options = Object.assign({
4165 multiple: Array.isArray(value),
4167 select_placeholder: _('-- Please choose --'),
4168 custom_placeholder: _('-- custom --'),
4172 create_query: '.create-item-input',
4173 create_template: 'script[type="item-template"]'
4178 render: function() {
4180 'id': this.options.id,
4181 'class': 'cbi-dropdown',
4182 'multiple': this.options.multiple ? '' : null,
4183 'optional': this.options.optional ? '' : null,
4186 var keys = Object.keys(this.choices);
4188 if (this.options.sort === true)
4190 else if (Array.isArray(this.options.sort))
4191 keys = this.options.sort;
4193 if (this.options.create)
4194 for (var i = 0; i < this.values.length; i++)
4195 if (!this.choices.hasOwnProperty(this.values[i]))
4196 keys.push(this.values[i]);
4198 for (var i = 0; i < keys.length; i++) {
4199 var label = this.choices[keys[i]];
4201 if (dom.elem(label))
4202 label = label.cloneNode(true);
4204 sb.lastElementChild.appendChild(E('li', {
4205 'data-value': keys[i],
4206 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
4207 }, [ label || keys[i] ]));
4210 if (this.options.create) {
4211 var createEl = E('input', {
4213 'class': 'create-item-input',
4214 'readonly': this.options.readonly ? '' : null,
4215 'maxlength': this.options.maxlength,
4216 'placeholder': this.options.custom_placeholder || this.options.placeholder
4219 if (this.options.datatype || this.options.validate)
4220 UI.prototype.addValidator(createEl, this.options.datatype || 'string',
4221 true, this.options.validate, 'blur', 'keyup');
4223 sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl));
4226 if (this.options.create_markup)
4227 sb.appendChild(E('script', { type: 'item-template' },
4228 this.options.create_markup));
4230 return this.bind(sb);
4234 bind: function(sb) {
4235 var o = this.options;
4237 o.multiple = sb.hasAttribute('multiple');
4238 o.optional = sb.hasAttribute('optional');
4239 o.placeholder = sb.getAttribute('placeholder') || o.placeholder;
4240 o.display_items = parseInt(sb.getAttribute('display-items') || o.display_items);
4241 o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') || o.dropdown_items);
4242 o.create_query = sb.getAttribute('item-create') || o.create_query;
4243 o.create_template = sb.getAttribute('item-template') || o.create_template;
4245 var ul = sb.querySelector('ul'),
4246 more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')),
4247 open = sb.appendChild(E('span', { class: 'open', tabindex: -1 }, 'â–¾')),
4248 canary = sb.appendChild(E('div')),
4249 create = sb.querySelector(this.options.create_query),
4250 ndisplay = this.options.display_items,
4253 if (this.options.multiple) {
4254 var items = ul.querySelectorAll('li');
4256 for (var i = 0; i < items.length; i++) {
4257 this.transformItem(sb, items[i]);
4259 if (items[i].hasAttribute('selected') && ndisplay-- > 0)
4260 items[i].setAttribute('display', n++);
4264 if (this.options.optional && !ul.querySelector('li[data-value=""]')) {
4265 var placeholder = E('li', { placeholder: '' },
4266 this.options.select_placeholder || this.options.placeholder);
4269 ? ul.insertBefore(placeholder, ul.firstChild)
4270 : ul.appendChild(placeholder);
4273 var items = ul.querySelectorAll('li'),
4274 sel = sb.querySelectorAll('[selected]');
4276 sel.forEach(function(s) {
4277 s.removeAttribute('selected');
4280 var s = sel[0] || items[0];
4282 s.setAttribute('selected', '');
4283 s.setAttribute('display', n++);
4289 this.saveValues(sb, ul);
4291 ul.setAttribute('tabindex', -1);
4292 sb.setAttribute('tabindex', 0);
4294 if (ndisplay < 0)
4295 sb.setAttribute('more', '')
4297 sb.removeAttribute('more');
4299 if (ndisplay == this.options.display_items)
4300 sb.setAttribute('empty', '')
4302 sb.removeAttribute('empty');
4304 dom.content(more, (ndisplay == this.options.display_items)
4305 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4308 sb.addEventListener('click', this.handleClick.bind(this));
4309 sb.addEventListener('keydown', this.handleKeydown.bind(this));
4310 sb.addEventListener('cbi-dropdown-close', this.handleDropdownClose.bind(this));
4311 sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this));
4313 if ('ontouchstart' in window) {
4314 sb.addEventListener('touchstart', function(ev) { ev.stopPropagation(); });
4315 window.addEventListener('touchstart', this.closeAllDropdowns);
4318 sb.addEventListener('mouseover', this.handleMouseover.bind(this));
4319 sb.addEventListener('focus', this.handleFocus.bind(this));
4321 canary.addEventListener('focus', this.handleCanaryFocus.bind(this));
4323 window.addEventListener('mouseover', this.setFocus);
4324 window.addEventListener('click', this.closeAllDropdowns);
4328 create.addEventListener('keydown', this.handleCreateKeydown.bind(this));
4329 create.addEventListener('focus', this.handleCreateFocus.bind(this));
4330 create.addEventListener('blur', this.handleCreateBlur.bind(this));
4332 var li = findParent(create, 'li');
4334 li.setAttribute('unselectable', '');
4335 li.addEventListener('click', this.handleCreateClick.bind(this));
4340 this.setUpdateEvents(sb, 'cbi-dropdown-open', 'cbi-dropdown-close');
4341 this.setChangeEvents(sb, 'cbi-dropdown-change', 'cbi-dropdown-close');
4343 dom.bindClassInstance(sb, this);
4349 openDropdown: function(sb) {
4350 var st = window.getComputedStyle(sb, null),
4351 ul = sb.querySelector('ul'),
4352 li = ul.querySelectorAll('li'),
4353 fl = findParent(sb, '.cbi-value-field'),
4354 sel = ul.querySelector('[selected]'),
4355 rect = sb.getBoundingClientRect(),
4356 items = Math.min(this.options.dropdown_items, li.length);
4358 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
4359 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
4362 sb.setAttribute('open', '');
4364 var pv = ul.cloneNode(true);
4365 pv.classList.add('preview');
4368 fl.classList.add('cbi-dropdown-open');
4370 if ('ontouchstart' in window) {
4371 var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
4372 vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
4375 ul.style.top = sb.offsetHeight + 'px';
4376 ul.style.left = -rect.left + 'px';
4377 ul.style.right = (rect.right - vpWidth) + 'px';
4378 ul.style.maxHeight = (vpHeight * 0.5) + 'px';
4379 ul.style.WebkitOverflowScrolling = 'touch';
4381 function getScrollParent(element) {
4382 var parent = element,
4383 style = getComputedStyle(element),
4384 excludeStaticParent = (style.position === 'absolute');
4386 if (style.position === 'fixed')
4387 return document.body;
4389 while ((parent = parent.parentElement) != null) {
4390 style = getComputedStyle(parent);
4392 if (excludeStaticParent && style.position === 'static')
4395 if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX))
4399 return document.body;
4402 var scrollParent = getScrollParent(sb),
4403 scrollFrom = scrollParent.scrollTop,
4404 scrollTo = scrollFrom + rect.top - vpHeight * 0.5;
4406 var scrollStep = function(timestamp) {
4409 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
4412 var duration = Math.max(timestamp - start, 1);
4413 if (duration < 100) {
4414 scrollParent.scrollTop = scrollFrom + (scrollTo - scrollFrom) * (duration / 100);
4415 window.requestAnimationFrame(scrollStep);
4418 scrollParent.scrollTop = scrollTo;
4422 window.requestAnimationFrame(scrollStep);
4425 ul.style.maxHeight = '1px';
4426 ul.style.top = ul.style.bottom = '';
4428 window.requestAnimationFrame(function() {
4429 var itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height,
4431 spaceAbove = rect.top,
4432 spaceBelow = window.innerHeight - rect.height - rect.top;
4434 for (var i = 0; i < (items == -1 ? li.length : items); i++)
4435 fullHeight += li[i].getBoundingClientRect().height;
4437 if (fullHeight <= spaceBelow) {
4438 ul.style.top = rect.height + 'px';
4439 ul.style.maxHeight = spaceBelow + 'px';
4441 else if (fullHeight <= spaceAbove) {
4442 ul.style.bottom = rect.height + 'px';
4443 ul.style.maxHeight = spaceAbove + 'px';
4445 else if (spaceBelow >= spaceAbove) {
4446 ul.style.top = rect.height + 'px';
4447 ul.style.maxHeight = (spaceBelow - (spaceBelow % itemHeight)) + 'px';
4450 ul.style.bottom = rect.height + 'px';
4451 ul.style.maxHeight = (spaceAbove - (spaceAbove % itemHeight)) + 'px';
4454 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
4458 var cboxes = ul.querySelectorAll('[selected] input[type="checkbox"]');
4459 for (var i = 0; i < cboxes.length; i++) {
4460 cboxes[i].checked = true;
4461 cboxes[i].disabled = (cboxes.length == 1 && !this.options.optional);
4464 ul.classList.add('dropdown');
4466 sb.insertBefore(pv, ul.nextElementSibling);
4468 li.forEach(function(l) {
4469 l.setAttribute('tabindex', 0);
4472 sb.lastElementChild.setAttribute('tabindex', 0);
4474 this.setFocus(sb, sel || li[0], true);
4478 closeDropdown: function(sb, no_focus) {
4479 if (!sb.hasAttribute('open'))
4482 var pv = sb.querySelector('ul.preview'),
4483 ul = sb.querySelector('ul.dropdown'),
4484 li = ul.querySelectorAll('li'),
4485 fl = findParent(sb, '.cbi-value-field');
4487 li.forEach(function(l) { l.removeAttribute('tabindex'); });
4488 sb.lastElementChild.removeAttribute('tabindex');
4491 sb.removeAttribute('open');
4492 sb.style.width = sb.style.height = '';
4494 ul.classList.remove('dropdown');
4495 ul.style.top = ul.style.bottom = ul.style.maxHeight = '';
4498 fl.classList.remove('cbi-dropdown-open');
4501 this.setFocus(sb, sb);
4503 this.saveValues(sb, ul);
4507 toggleItem: function(sb, li, force_state) {
4508 if (li.hasAttribute('unselectable'))
4511 if (this.options.multiple) {
4512 var cbox = li.querySelector('input[type="checkbox"]'),
4513 items = li.parentNode.querySelectorAll('li'),
4514 label = sb.querySelector('ul.preview'),
4515 sel = li.parentNode.querySelectorAll('[selected]').length,
4516 more = sb.querySelector('.more'),
4517 ndisplay = this.options.display_items,
4520 if (li.hasAttribute('selected')) {
4521 if (force_state !== true) {
4522 if (sel > 1 || this.options.optional) {
4523 li.removeAttribute('selected');
4524 cbox.checked = cbox.disabled = false;
4528 cbox.disabled = true;
4533 if (force_state !== false) {
4534 li.setAttribute('selected', '');
4535 cbox.checked = true;
4536 cbox.disabled = false;
4541 while (label && label.firstElementChild)
4542 label.removeChild(label.firstElementChild);
4544 for (var i = 0; i < items.length; i++) {
4545 items[i].removeAttribute('display');
4546 if (items[i].hasAttribute('selected')) {
4547 if (ndisplay-- > 0) {
4548 items[i].setAttribute('display', n++);
4550 label.appendChild(items[i].cloneNode(true));
4552 var c = items[i].querySelector('input[type="checkbox"]');
4554 c.disabled = (sel == 1 && !this.options.optional);
4558 if (ndisplay < 0)
4559 sb.setAttribute('more', '');
4561 sb.removeAttribute('more');
4563 if (ndisplay === this.options.display_items)
4564 sb.setAttribute('empty', '');
4566 sb.removeAttribute('empty');
4568 dom.content(more, (ndisplay === this.options.display_items)
4569 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4572 var sel = li.parentNode.querySelector('[selected]');
4574 sel.removeAttribute('display');
4575 sel.removeAttribute('selected');
4578 li.setAttribute('display', 0);
4579 li.setAttribute('selected', '');
4581 this.closeDropdown(sb, true);
4584 this.saveValues(sb, li.parentNode);
4588 transformItem: function(sb, li) {
4589 var cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -1, onclick: 'event.preventDefault()' })),
4592 while (li.firstChild)
4593 label.appendChild(li.firstChild);
4595 li.appendChild(cbox);
4596 li.appendChild(label);
4600 saveValues: function(sb, ul) {
4601 var sel = ul.querySelectorAll('li[selected]'),
4602 div = sb.lastElementChild,
4603 name = this.options.name,
4607 while (div.lastElementChild)
4608 div.removeChild(div.lastElementChild);
4610 sel.forEach(function (s) {
4611 if (s.hasAttribute('placeholder'))
4616 value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText,
4620 div.appendChild(E('input', {
4628 strval += strval.length ? ' ' + v.value : v.value;
4636 if (this.options.multiple)
4637 detail.values = values;
4639 detail.value = values.length ? values[0] : null;
4643 sb.dispatchEvent(new CustomEvent('cbi-dropdown-change', {
4650 setValues: function(sb, values) {
4651 var ul = sb.querySelector('ul');
4653 if (this.options.create) {
4654 for (var value in values) {
4655 this.createItems(sb, value);
4657 if (!this.options.multiple)
4662 if (this.options.multiple) {
4663 var lis = ul.querySelectorAll('li[data-value]');
4664 for (var i = 0; i < lis.length; i++) {
4665 var value = lis[i].getAttribute('data-value');
4666 if (values === null || !(value in values))
4667 this.toggleItem(sb, lis[i], false);
4669 this.toggleItem(sb, lis[i], true);
4673 var ph = ul.querySelector('li[placeholder]');
4675 this.toggleItem(sb, ph);
4677 var lis = ul.querySelectorAll('li[data-value]');
4678 for (var i = 0; i < lis.length; i++) {
4679 var value = lis[i].getAttribute('data-value');
4680 if (values !== null && (value in values))
4681 this.toggleItem(sb, lis[i]);
4687 setFocus: function(sb, elem, scroll) {
4688 if (sb && sb.hasAttribute && sb.hasAttribute('locked-in'))
4691 if (sb.target && findParent(sb.target, 'ul.dropdown'))
4694 document.querySelectorAll('.focus').forEach(function(e) {
4695 if (!matchesElem(e, 'input')) {
4696 e.classList.remove('focus');
4703 elem.classList.add('focus');
4706 elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop;
4711 createChoiceElement: function(sb, value, label) {
4712 var tpl = sb.querySelector(this.options.create_template),
4716 markup = (tpl.textContent || tpl.innerHTML || tpl.firstChild.data).replace(/^<!--|-->$/, '').trim();
4718 markup = '<li data-value="{{value}}"><span data-label-placeholder="true" /></li>';
4720 var new_item = E(markup.replace(/{{value}}/g, '%h'.format(value))),
4721 placeholder = new_item.querySelector('[data-label-placeholder]');
4724 var content = E('span', {}, label || this.choices[value] || [ value ]);
4726 while (content.firstChild)
4727 placeholder.parentNode.insertBefore(content.firstChild, placeholder);
4729 placeholder.parentNode.removeChild(placeholder);
4732 if (this.options.multiple)
4733 this.transformItem(sb, new_item);
4739 createItems: function(sb, value) {
4741 val = (value || '').trim(),
4742 ul = sb.querySelector('ul');
4744 if (!sbox.options.multiple)
4745 val = val.length ? [ val ] : [];
4747 val = val.length ? val.split(/\s+/) : [];
4749 val.forEach(function(item) {
4750 var new_item = null;
4752 ul.childNodes.forEach(function(li) {
4753 if (li.getAttribute && li.getAttribute('data-value') === item)
4758 new_item = sbox.createChoiceElement(sb, item);
4760 if (!sbox.options.multiple) {
4761 var old = ul.querySelector('li[created]');
4763 ul.removeChild(old);
4765 new_item.setAttribute('created', '');
4768 new_item = ul.insertBefore(new_item, ul.lastElementChild);
4771 sbox.toggleItem(sb, new_item, true);
4772 sbox.setFocus(sb, new_item, true);
4777 * Remove all existing choices from the dropdown menu.
4779 * This function removes all preexisting dropdown choices from the widget,
4780 * keeping only choices currently being selected unless `reset_values` is
4781 * given, in which case all choices and deselected and removed.
4784 * @memberof LuCI.ui.Dropdown
4785 * @param {boolean} [reset_value=false]
4786 * If set to `true`, deselect and remove selected choices as well instead
4789 clearChoices: function(reset_value) {
4790 var ul = this.node.querySelector('ul'),
4791 lis = ul ? ul.querySelectorAll('li[data-value]') : [],
4792 len = lis.length - (this.options.create ? 1 : 0),
4793 val = reset_value ? null : this.getValue();
4795 for (var i = 0; i < len; i++) {
4796 var lival = lis[i].getAttribute('data-value');
4798 (!this.options.multiple && val != lival) ||
4799 (this.options.multiple && val.indexOf(lival) == -1))
4800 ul.removeChild(lis[i]);
4804 this.setValues(this.node, {});
4808 * Add new choices to the dropdown menu.
4810 * This function adds further choices to an existing dropdown menu,
4811 * ignoring choice values which are already present.
4814 * @memberof LuCI.ui.Dropdown
4815 * @param {string[]} values
4816 * The choice values to add to the dropdown widget.
4818 * @param {Object<string, *>} labels
4819 * The choice label values to use when adding dropdown choices. If no
4820 * label is found for a particular choice value, the value itself is used
4821 * as label text. Choice labels may be any valid value accepted by
4822 * {@link LuCI.dom#content}.
4824 addChoices: function(values, labels) {
4826 ul = sb.querySelector('ul'),
4827 lis = ul ? ul.querySelectorAll('li[data-value]') : [];
4829 if (!Array.isArray(values))
4830 values = L.toArray(values);
4832 if (!L.isObject(labels))
4835 for (var i = 0; i < values.length; i++) {
4838 for (var j = 0; j < lis.length; j++) {
4839 if (lis[j].getAttribute('data-value') === values[i]) {
4849 this.createChoiceElement(sb, values[i], labels[values[i]]),
4850 ul.lastElementChild);
4855 * Close all open dropdown widgets in the current document.
4857 closeAllDropdowns: function() {
4858 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
4859 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
4864 handleClick: function(ev) {
4865 var sb = ev.currentTarget;
4867 if (!sb.hasAttribute('open')) {
4868 if (!matchesElem(ev.target, 'input'))
4869 this.openDropdown(sb);
4872 var li = findParent(ev.target, 'li');
4873 if (li && li.parentNode.classList.contains('dropdown'))
4874 this.toggleItem(sb, li);
4875 else if (li && li.parentNode.classList.contains('preview'))
4876 this.closeDropdown(sb);
4877 else if (matchesElem(ev.target, 'span.open, span.more'))
4878 this.closeDropdown(sb);
4881 ev.preventDefault();
4882 ev.stopPropagation();
4886 handleKeydown: function(ev) {
4887 var sb = ev.currentTarget;
4889 if (matchesElem(ev.target, 'input'))
4892 if (!sb.hasAttribute('open')) {
4893 switch (ev.keyCode) {
4898 this.openDropdown(sb);
4899 ev.preventDefault();
4903 var active = findParent(document.activeElement, 'li');
4905 switch (ev.keyCode) {
4907 this.closeDropdown(sb);
4912 if (!active.hasAttribute('selected'))
4913 this.toggleItem(sb, active);
4914 this.closeDropdown(sb);
4915 ev.preventDefault();
4921 this.toggleItem(sb, active);
4922 ev.preventDefault();
4927 if (active && active.previousElementSibling) {
4928 this.setFocus(sb, active.previousElementSibling);
4929 ev.preventDefault();
4934 if (active && active.nextElementSibling) {
4935 this.setFocus(sb, active.nextElementSibling);
4936 ev.preventDefault();
4944 handleDropdownClose: function(ev) {
4945 var sb = ev.currentTarget;
4947 this.closeDropdown(sb, true);
4951 handleDropdownSelect: function(ev) {
4952 var sb = ev.currentTarget,
4953 li = findParent(ev.target, 'li');
4958 this.toggleItem(sb, li);
4959 this.closeDropdown(sb, true);
4963 handleMouseover: function(ev) {
4964 var sb = ev.currentTarget;
4966 if (!sb.hasAttribute('open'))
4969 var li = findParent(ev.target, 'li');
4971 if (li && li.parentNode.classList.contains('dropdown'))
4972 this.setFocus(sb, li);
4976 handleFocus: function(ev) {
4977 var sb = ev.currentTarget;
4979 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
4980 if (s !== sb || sb.hasAttribute('open'))
4981 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
4986 handleCanaryFocus: function(ev) {
4987 this.closeDropdown(ev.currentTarget.parentNode);
4991 handleCreateKeydown: function(ev) {
4992 var input = ev.currentTarget,
4993 sb = findParent(input, '.cbi-dropdown');
4995 switch (ev.keyCode) {
4997 ev.preventDefault();
4999 if (input.classList.contains('cbi-input-invalid'))
5002 this.createItems(sb, input.value);
5010 handleCreateFocus: function(ev) {
5011 var input = ev.currentTarget,
5012 cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'),
5013 sb = findParent(input, '.cbi-dropdown');
5016 cbox.checked = true;
5018 sb.setAttribute('locked-in', '');
5022 handleCreateBlur: function(ev) {
5023 var input = ev.currentTarget,
5024 cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'),
5025 sb = findParent(input, '.cbi-dropdown');
5028 cbox.checked = false;
5030 sb.removeAttribute('locked-in');
5034 handleCreateClick: function(ev) {
5035 ev.currentTarget.querySelector(this.options.create_query).focus();
5039 setValue: function(values) {
5040 if (this.options.multiple) {
5041 if (!Array.isArray(values))
5042 values = (values != null && values != '') ? [ values ] : [];
5046 for (var i = 0; i < values.length; i++)
5047 v[values[i]] = true;
5049 this.setValues(this.node, v);
5054 if (values != null) {
5055 if (Array.isArray(values))
5056 v[values[0]] = true;
5061 this.setValues(this.node, v);
5066 getValue: function() {
5067 var div = this.node.lastElementChild,
5068 h = div.querySelectorAll('input[type="hidden"]'),
5071 for (var i = 0; i < h.length; i++)
5074 return this.options.multiple ? v : v[0];
5079 * Instantiate a rich dropdown choice widget allowing custom values.
5081 * @constructor Combobox
5083 * @augments LuCI.ui.Dropdown
5087 * The `Combobox` class implements a rich, stylable dropdown menu which allows
5088 * to enter custom values. Historically, comboboxes used to be a dedicated
5089 * widget type in LuCI but nowadays they are direct aliases of dropdown widgets
5090 * with a set of enforced default properties for easier instantiation.
5092 * UI widget instances are usually not supposed to be created by view code
5093 * directly, instead they're implicitely created by `LuCI.form` when
5094 * instantiating CBI forms.
5096 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5097 * in views, use `'require ui'` and refer to `ui.Combobox`. To import it in
5098 * external JavaScript, use `L.require("ui").then(...)` and access the
5099 * `Combobox` property of the class instance value.
5101 * @param {string|string[]} [value=null]
5102 * The initial input value(s).
5104 * @param {Object<string, *>} choices
5105 * Object containing the selectable choices of the widget. The object keys
5106 * serve as values for the different choices while the values are used as
5109 * @param {LuCI.ui.Combobox.InitOptions} [options]
5110 * Object describing the widget specific options to initialize the dropdown.
5112 var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ {
5114 * Comboboxes support the same properties as
5115 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5116 * specific values for the following properties:
5118 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5119 * @memberof LuCI.ui.Combobox
5121 * @property {boolean} multiple=false
5122 * Since Comboboxes never allow selecting multiple values, this property
5123 * is forcibly set to `false`.
5125 * @property {boolean} create=true
5126 * Since Comboboxes always allow custom choice values, this property is
5127 * forcibly set to `true`.
5129 * @property {boolean} optional=true
5130 * Since Comboboxes are always optional, this property is forcibly set to
5133 __init__: function(value, choices, options) {
5134 this.super('__init__', [ value, choices, Object.assign({
5135 select_placeholder: _('-- Please choose --'),
5136 custom_placeholder: _('-- custom --'),
5148 * Instantiate a combo button widget offering multiple action choices.
5150 * @constructor ComboButton
5152 * @augments LuCI.ui.Dropdown
5156 * The `ComboButton` class implements a button element which can be expanded
5157 * into a dropdown to chose from a set of different action choices.
5159 * UI widget instances are usually not supposed to be created by view code
5160 * directly, instead they're implicitely created by `LuCI.form` when
5161 * instantiating CBI forms.
5163 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5164 * in views, use `'require ui'` and refer to `ui.ComboButton`. To import it in
5165 * external JavaScript, use `L.require("ui").then(...)` and access the
5166 * `ComboButton` property of the class instance value.
5168 * @param {string|string[]} [value=null]
5169 * The initial input value(s).
5171 * @param {Object<string, *>} choices
5172 * Object containing the selectable choices of the widget. The object keys
5173 * serve as values for the different choices while the values are used as
5176 * @param {LuCI.ui.ComboButton.InitOptions} [options]
5177 * Object describing the widget specific options to initialize the button.
5179 var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype */ {
5181 * ComboButtons support the same properties as
5182 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5183 * specific values for some properties and add aditional button specific
5186 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5187 * @memberof LuCI.ui.ComboButton
5189 * @property {boolean} multiple=false
5190 * Since ComboButtons never allow selecting multiple actions, this property
5191 * is forcibly set to `false`.
5193 * @property {boolean} create=false
5194 * Since ComboButtons never allow creating custom choices, this property
5195 * is forcibly set to `false`.
5197 * @property {boolean} optional=false
5198 * Since ComboButtons must always select one action, this property is
5199 * forcibly set to `false`.
5201 * @property {Object<string, string>} [classes]
5202 * Specifies a mapping of choice values to CSS class names. If an action
5203 * choice is selected by the user and if a corresponding entry exists in
5204 * the `classes` object, the class names corresponding to the selected
5205 * value are set on the button element.
5207 * This is useful to apply different button styles, such as colors, to the
5208 * combined button depending on the selected action.
5210 * @property {function} [click]
5211 * Specifies a handler function to invoke when the user clicks the button.
5212 * This function will be called with the button DOM node as `this` context
5213 * and receive the DOM click event as first as well as the selected action
5214 * choice value as second argument.
5216 __init__: function(value, choices, options) {
5217 this.super('__init__', [ value, choices, Object.assign({
5227 render: function(/* ... */) {
5228 var node = UIDropdown.prototype.render.apply(this, arguments),
5229 val = this.getValue();
5231 if (L.isObject(this.options.classes) && this.options.classes.hasOwnProperty(val))
5232 node.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5238 handleClick: function(ev) {
5239 var sb = ev.currentTarget,
5242 if (sb.hasAttribute('open') || dom.matches(t, '.cbi-dropdown > span.open'))
5243 return UIDropdown.prototype.handleClick.apply(this, arguments);
5245 if (this.options.click)
5246 return this.options.click.call(sb, ev, this.getValue());
5250 toggleItem: function(sb /*, ... */) {
5251 var rv = UIDropdown.prototype.toggleItem.apply(this, arguments),
5252 val = this.getValue();
5254 if (L.isObject(this.options.classes) && this.options.classes.hasOwnProperty(val))
5255 sb.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5257 sb.setAttribute('class', 'cbi-dropdown');
5264 * Instantiate a dynamic list widget.
5266 * @constructor DynamicList
5268 * @augments LuCI.ui.AbstractElement
5272 * The `DynamicList` class implements a widget which allows the user to specify
5273 * an arbitrary amount of input values, either from free formed text input or
5274 * from a set of predefined choices.
5276 * UI widget instances are usually not supposed to be created by view code
5277 * directly, instead they're implicitely created by `LuCI.form` when
5278 * instantiating CBI forms.
5280 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5281 * in views, use `'require ui'` and refer to `ui.DynamicList`. To import it in
5282 * external JavaScript, use `L.require("ui").then(...)` and access the
5283 * `DynamicList` property of the class instance value.
5285 * @param {string|string[]} [value=null]
5286 * The initial input value(s).
5288 * @param {Object<string, *>} [choices]
5289 * Object containing the selectable choices of the widget. The object keys
5290 * serve as values for the different choices while the values are used as
5291 * choice labels. If omitted, no default choices are presented to the user,
5292 * instead a plain text input field is rendered allowing the user to add
5293 * arbitrary values to the dynamic list.
5295 * @param {LuCI.ui.DynamicList.InitOptions} [options]
5296 * Object describing the widget specific options to initialize the dynamic list.
5298 var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ {
5300 * In case choices are passed to the dynamic list contructor, the widget
5301 * supports the same properties as [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions}
5302 * but enforces specific values for some dropdown properties.
5304 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5305 * @memberof LuCI.ui.DynamicList
5307 * @property {boolean} multiple=false
5308 * Since dynamic lists never allow selecting multiple choices when adding
5309 * another list item, this property is forcibly set to `false`.
5311 * @property {boolean} optional=true
5312 * Since dynamic lists use an embedded dropdown to present a list of
5313 * predefined choice values, the dropdown must be made optional to allow
5314 * it to remain unselected.
5316 __init__: function(values, choices, options) {
5317 if (!Array.isArray(values))
5318 values = (values != null && values != '') ? [ values ] : [];
5320 if (typeof(choices) != 'object')
5323 this.values = values;
5324 this.choices = choices;
5325 this.options = Object.assign({}, options, {
5332 render: function() {
5334 'id': this.options.id,
5335 'class': 'cbi-dynlist'
5336 }, E('div', { 'class': 'add-item' }));
5339 if (this.options.placeholder != null)
5340 this.options.select_placeholder = this.options.placeholder;
5342 var cbox = new UICombobox(null, this.choices, this.options);
5344 dl.lastElementChild.appendChild(cbox.render());
5347 var inputEl = E('input', {
5348 'id': this.options.id ? 'widget.' + this.options.id : null,
5350 'class': 'cbi-input-text',
5351 'placeholder': this.options.placeholder
5354 dl.lastElementChild.appendChild(inputEl);
5355 dl.lastElementChild.appendChild(E('div', { 'class': 'btn cbi-button cbi-button-add' }, '+'));
5357 if (this.options.datatype || this.options.validate)
5358 UI.prototype.addValidator(inputEl, this.options.datatype || 'string',
5359 true, this.options.validate, 'blur', 'keyup');
5362 for (var i = 0; i < this.values.length; i++) {
5363 var label = this.choices ? this.choices[this.values[i]] : null;
5365 if (dom.elem(label))
5366 label = label.cloneNode(true);
5368 this.addItem(dl, this.values[i], label);
5371 return this.bind(dl);
5375 bind: function(dl) {
5376 dl.addEventListener('click', L.bind(this.handleClick, this));
5377 dl.addEventListener('keydown', L.bind(this.handleKeydown, this));
5378 dl.addEventListener('cbi-dropdown-change', L.bind(this.handleDropdownChange, this));
5382 this.setUpdateEvents(dl, 'cbi-dynlist-change');
5383 this.setChangeEvents(dl, 'cbi-dynlist-change');
5385 dom.bindClassInstance(dl, this);
5391 addItem: function(dl, value, text, flash) {
5393 new_item = E('div', { 'class': flash ? 'item flash' : 'item', 'tabindex': 0 }, [
5394 E('span', {}, [ text || value ]),
5397 'name': this.options.name,
5398 'value': value })]);
5400 dl.querySelectorAll('.item').forEach(function(item) {
5404 var hidden = item.querySelector('input[type="hidden"]');
5406 if (hidden && hidden.parentNode !== item)
5409 if (hidden && hidden.value === value)
5414 var ai = dl.querySelector('.add-item');
5415 ai.parentNode.insertBefore(new_item, ai);
5418 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5430 removeItem: function(dl, item) {
5431 var value = item.querySelector('input[type="hidden"]').value;
5432 var sb = dl.querySelector('.cbi-dropdown');
5434 sb.querySelectorAll('ul > li').forEach(function(li) {
5435 if (li.getAttribute('data-value') === value) {
5436 if (li.hasAttribute('dynlistcustom'))
5437 li.parentNode.removeChild(li);
5439 li.removeAttribute('unselectable');
5443 item.parentNode.removeChild(item);
5445 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5457 handleClick: function(ev) {
5458 var dl = ev.currentTarget,
5459 item = findParent(ev.target, '.item');
5462 this.removeItem(dl, item);
5464 else if (matchesElem(ev.target, '.cbi-button-add')) {
5465 var input = ev.target.previousElementSibling;
5466 if (input.value.length && !input.classList.contains('cbi-input-invalid')) {
5467 this.addItem(dl, input.value, null, true);
5474 handleDropdownChange: function(ev) {
5475 var dl = ev.currentTarget,
5476 sbIn = ev.detail.instance,
5477 sbEl = ev.detail.element,
5478 sbVal = ev.detail.value;
5483 sbIn.setValues(sbEl, null);
5484 sbVal.element.setAttribute('unselectable', '');
5486 if (sbVal.element.hasAttribute('created')) {
5487 sbVal.element.removeAttribute('created');
5488 sbVal.element.setAttribute('dynlistcustom', '');
5491 var label = sbVal.text;
5493 if (sbVal.element) {
5496 for (var i = 0; i < sbVal.element.childNodes.length; i++)
5497 label.appendChild(sbVal.element.childNodes[i].cloneNode(true));
5500 this.addItem(dl, sbVal.value, label, true);
5504 handleKeydown: function(ev) {
5505 var dl = ev.currentTarget,
5506 item = findParent(ev.target, '.item');
5509 switch (ev.keyCode) {
5510 case 8: /* backspace */
5511 if (item.previousElementSibling)
5512 item.previousElementSibling.focus();
5514 this.removeItem(dl, item);
5517 case 46: /* delete */
5518 if (item.nextElementSibling) {
5519 if (item.nextElementSibling.classList.contains('item'))
5520 item.nextElementSibling.focus();
5522 item.nextElementSibling.firstElementChild.focus();
5525 this.removeItem(dl, item);
5529 else if (matchesElem(ev.target, '.cbi-input-text')) {
5530 switch (ev.keyCode) {
5531 case 13: /* enter */
5532 if (ev.target.value.length && !ev.target.classList.contains('cbi-input-invalid')) {
5533 this.addItem(dl, ev.target.value, null, true);
5534 ev.target.value = '';
5539 ev.preventDefault();
5546 getValue: function() {
5547 var items = this.node.querySelectorAll('.item > input[type="hidden"]'),
5548 input = this.node.querySelector('.add-item > input[type="text"]'),
5551 for (var i = 0; i < items.length; i++)
5552 v.push(items[i].value);
5554 if (input && input.value != null && input.value.match(/\S/) &&
5555 input.classList.contains('cbi-input-invalid') == false &&
5556 v.filter(function(s) { return s == input.value }).length == 0)
5557 v.push(input.value);
5563 setValue: function(values) {
5564 if (!Array.isArray(values))
5565 values = (values != null && values != '') ? [ values ] : [];
5567 var items = this.node.querySelectorAll('.item');
5569 for (var i = 0; i < items.length; i++)
5570 if (items[i].parentNode === this.node)
5571 this.removeItem(this.node, items[i]);
5573 for (var i = 0; i < values.length; i++)
5574 this.addItem(this.node, values[i],
5575 this.choices ? this.choices[values[i]] : null);
5579 * Add new suggested choices to the dynamic list.
5581 * This function adds further choices to an existing dynamic list,
5582 * ignoring choice values which are already present.
5585 * @memberof LuCI.ui.DynamicList
5586 * @param {string[]} values
5587 * The choice values to add to the dynamic lists suggestion dropdown.
5589 * @param {Object<string, *>} labels
5590 * The choice label values to use when adding suggested choices. If no
5591 * label is found for a particular choice value, the value itself is used
5592 * as label text. Choice labels may be any valid value accepted by
5593 * {@link LuCI.dom#content}.
5595 addChoices: function(values, labels) {
5596 var dl = this.node.lastElementChild.firstElementChild;
5597 dom.callClassMethod(dl, 'addChoices', values, labels);
5601 * Remove all existing choices from the dynamic list.
5603 * This function removes all preexisting suggested choices from the widget.
5606 * @memberof LuCI.ui.DynamicList
5608 clearChoices: function() {
5609 var dl = this.node.lastElementChild.firstElementChild;
5610 dom.callClassMethod(dl, 'clearChoices');
5615 * Instantiate a hidden input field widget.
5617 * @constructor Hiddenfield
5619 * @augments LuCI.ui.AbstractElement
5623 * The `Hiddenfield` class implements an HTML `<input type="hidden">` field
5624 * which allows to store form data without exposing it to the user.
5626 * UI widget instances are usually not supposed to be created by view code
5627 * directly, instead they're implicitely created by `LuCI.form` when
5628 * instantiating CBI forms.
5630 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5631 * in views, use `'require ui'` and refer to `ui.Hiddenfield`. To import it in
5632 * external JavaScript, use `L.require("ui").then(...)` and access the
5633 * `Hiddenfield` property of the class instance value.
5635 * @param {string|string[]} [value=null]
5636 * The initial input value.
5638 * @param {LuCI.ui.AbstractElement.InitOptions} [options]
5639 * Object describing the widget specific options to initialize the hidden input.
5641 var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ {
5642 __init__: function(value, options) {
5644 this.options = Object.assign({
5650 render: function() {
5651 var hiddenEl = E('input', {
5652 'id': this.options.id,
5657 return this.bind(hiddenEl);
5661 bind: function(hiddenEl) {
5662 this.node = hiddenEl;
5664 dom.bindClassInstance(hiddenEl, this);
5670 getValue: function() {
5671 return this.node.value;
5675 setValue: function(value) {
5676 this.node.value = value;
5681 * Instantiate a file upload widget.
5683 * @constructor FileUpload
5685 * @augments LuCI.ui.AbstractElement
5689 * The `FileUpload` class implements a widget which allows the user to upload,
5690 * browse, select and delete files beneath a predefined remote directory.
5692 * UI widget instances are usually not supposed to be created by view code
5693 * directly, instead they're implicitely created by `LuCI.form` when
5694 * instantiating CBI forms.
5696 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5697 * in views, use `'require ui'` and refer to `ui.FileUpload`. To import it in
5698 * external JavaScript, use `L.require("ui").then(...)` and access the
5699 * `FileUpload` property of the class instance value.
5701 * @param {string|string[]} [value=null]
5702 * The initial input value.
5704 * @param {LuCI.ui.DynamicList.InitOptions} [options]
5705 * Object describing the widget specific options to initialize the file
5708 var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
5710 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
5711 * the following properties are recognized:
5713 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
5714 * @memberof LuCI.ui.FileUpload
5716 * @property {boolean} [show_hidden=false]
5717 * Specifies whether hidden files should be displayed when browsing remote
5718 * files. Note that this is not a security feature, hidden files are always
5719 * present in the remote file listings received, this option merely controls
5720 * whether they're displayed or not.
5722 * @property {boolean} [enable_upload=true]
5723 * Specifies whether the widget allows the user to upload files. If set to
5724 * `false`, only existing files may be selected. Note that this is not a
5725 * security feature. Whether file upload requests are accepted remotely
5726 * depends on the ACL setup for the current session. This option merely
5727 * controls whether the upload controls are rendered or not.
5729 * @property {boolean} [enable_remove=true]
5730 * Specifies whether the widget allows the user to delete remove files.
5731 * If set to `false`, existing files may not be removed. Note that this is
5732 * not a security feature. Whether file delete requests are accepted
5733 * remotely depends on the ACL setup for the current session. This option
5734 * merely controls whether the file remove controls are rendered or not.
5736 * @property {string} [root_directory=/etc/luci-uploads]
5737 * Specifies the remote directory the upload and file browsing actions take
5738 * place in. Browsing to directories outside of the root directory is
5739 * prevented by the widget. Note that this is not a security feature.
5740 * Whether remote directories are browseable or not solely depends on the
5741 * ACL setup for the current session.
5743 __init__: function(value, options) {
5745 this.options = Object.assign({
5747 enable_upload: true,
5748 enable_remove: true,
5749 root_directory: '/etc/luci-uploads'
5754 bind: function(browserEl) {
5755 this.node = browserEl;
5757 this.setUpdateEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
5758 this.setChangeEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
5760 dom.bindClassInstance(browserEl, this);
5766 render: function() {
5767 return L.resolveDefault(this.value != null ? fs.stat(this.value) : null).then(L.bind(function(stat) {
5770 if (L.isObject(stat) && stat.type != 'directory')
5773 if (this.stat != null)
5774 label = [ this.iconForType(this.stat.type), ' %s (%1000mB)'.format(this.truncatePath(this.stat.path), this.stat.size) ];
5775 else if (this.value != null)
5776 label = [ this.iconForType('file'), ' %s (%s)'.format(this.truncatePath(this.value), _('File not accessible')) ];
5778 label = [ _('Select file…') ];
5780 return this.bind(E('div', { 'id': this.options.id }, [
5783 'click': UI.prototype.createHandlerFn(this, 'handleFileBrowser')
5786 'class': 'cbi-filebrowser'
5790 'name': this.options.name,
5798 truncatePath: function(path) {
5799 if (path.length > 50)
5800 path = path.substring(0, 25) + '…' + path.substring(path.length - 25);
5806 iconForType: function(type) {
5810 'src': L.resource('cbi/link.gif'),
5811 'title': _('Symbolic link'),
5817 'src': L.resource('cbi/folder.gif'),
5818 'title': _('Directory'),
5824 'src': L.resource('cbi/file.gif'),
5832 canonicalizePath: function(path) {
5833 return path.replace(/\/{2,}/, '/')
5834 .replace(/\/\.(\/|$)/g, '/')
5835 .replace(/[^\/]+\/\.\.(\/|$)/g, '/')
5836 .replace(/\/$/, '');
5840 splitPath: function(path) {
5841 var croot = this.canonicalizePath(this.options.root_directory || '/'),
5842 cpath = this.canonicalizePath(path || '/');
5844 if (cpath.length <= croot.length)
5847 if (cpath.charAt(croot.length) != '/')
5850 var parts = cpath.substring(croot.length + 1).split(/\//);
5852 parts.unshift(croot);
5858 handleUpload: function(path, list, ev) {
5859 var form = ev.target.parentNode,
5860 fileinput = form.querySelector('input[type="file"]'),
5861 nameinput = form.querySelector('input[type="text"]'),
5862 filename = (nameinput.value != null ? nameinput.value : '').trim();
5864 ev.preventDefault();
5866 if (filename == '' || filename.match(/\//) || fileinput.files[0] == null)
5869 var existing = list.filter(function(e) { return e.name == filename })[0];
5871 if (existing != null && existing.type == 'directory')
5872 return alert(_('A directory with the same name already exists.'));
5873 else if (existing != null && !confirm(_('Overwrite existing file "%s" ?').format(filename)))
5876 var data = new FormData();
5878 data.append('sessionid', L.env.sessionid);
5879 data.append('filename', path + '/' + filename);
5880 data.append('filedata', fileinput.files[0]);
5882 return request.post(L.env.cgi_base + '/cgi-upload', data, {
5883 progress: L.bind(function(btn, ev) {
5884 btn.firstChild.data = '%.2f%%'.format((ev.loaded / ev.total) * 100);
5886 }).then(L.bind(function(path, ev, res) {
5887 var reply = res.json();
5889 if (L.isObject(reply) && reply.failure)
5890 alert(_('Upload request failed: %s').format(reply.message));
5892 return this.handleSelect(path, null, ev);
5893 }, this, path, ev));
5897 handleDelete: function(path, fileStat, ev) {
5898 var parent = path.replace(/\/[^\/]+$/, '') || '/',
5899 name = path.replace(/^.+\//, ''),
5902 ev.preventDefault();
5904 if (fileStat.type == 'directory')
5905 msg = _('Do you really want to recursively delete the directory "%s" ?').format(name);
5907 msg = _('Do you really want to delete "%s" ?').format(name);
5910 var button = this.node.firstElementChild,
5911 hidden = this.node.lastElementChild;
5913 if (path == hidden.value) {
5914 dom.content(button, _('Select file…'));
5918 return fs.remove(path).then(L.bind(function(parent, ev) {
5919 return this.handleSelect(parent, null, ev);
5920 }, this, parent, ev)).catch(function(err) {
5921 alert(_('Delete request failed: %s').format(err.message));
5927 renderUpload: function(path, list) {
5928 if (!this.options.enable_upload)
5934 'class': 'btn cbi-button-positive',
5935 'click': function(ev) {
5936 var uploadForm = ev.target.nextElementSibling,
5937 fileInput = uploadForm.querySelector('input[type="file"]');
5939 ev.target.style.display = 'none';
5940 uploadForm.style.display = '';
5943 }, _('Upload file…')),
5944 E('div', { 'class': 'upload', 'style': 'display:none' }, [
5947 'style': 'display:none',
5948 'change': function(ev) {
5949 var nameinput = ev.target.parentNode.querySelector('input[type="text"]'),
5950 uploadbtn = ev.target.parentNode.querySelector('button.cbi-button-save');
5952 nameinput.value = ev.target.value.replace(/^.+[\/\\]/, '');
5953 uploadbtn.disabled = false;
5958 'click': function(ev) {
5959 ev.preventDefault();
5960 ev.target.previousElementSibling.click();
5962 }, [ _('Browse…') ]),
5963 E('div', {}, E('input', { 'type': 'text', 'placeholder': _('Filename') })),
5965 'class': 'btn cbi-button-save',
5966 'click': UI.prototype.createHandlerFn(this, 'handleUpload', path, list),
5968 }, [ _('Upload file') ])
5974 renderListing: function(container, path, list) {
5975 var breadcrumb = E('p'),
5978 list.sort(function(a, b) {
5979 var isDirA = (a.type == 'directory'),
5980 isDirB = (b.type == 'directory');
5982 if (isDirA != isDirB)
5983 return isDirA < isDirB;
5985 return a.name > b.name;
5988 for (var i = 0; i < list.length; i++) {
5989 if (!this.options.show_hidden && list[i].name.charAt(0) == '.')
5992 var entrypath = this.canonicalizePath(path + '/' + list[i].name),
5993 selected = (entrypath == this.node.lastElementChild.value),
5994 mtime = new Date(list[i].mtime * 1000);
5996 rows.appendChild(E('li', [
5997 E('div', { 'class': 'name' }, [
5998 this.iconForType(list[i].type),
6002 'style': selected ? 'font-weight:bold' : null,
6003 'click': UI.prototype.createHandlerFn(this, 'handleSelect',
6004 entrypath, list[i].type != 'directory' ? list[i] : null)
6005 }, '%h'.format(list[i].name))
6007 E('div', { 'class': 'mtime hide-xs' }, [
6008 ' %04d-%02d-%02d %02d:%02d:%02d '.format(
6009 mtime.getFullYear(),
6010 mtime.getMonth() + 1,
6017 selected ? E('button', {
6019 'click': UI.prototype.createHandlerFn(this, 'handleReset')
6020 }, [ _('Deselect') ]) : '',
6021 this.options.enable_remove ? E('button', {
6022 'class': 'btn cbi-button-negative',
6023 'click': UI.prototype.createHandlerFn(this, 'handleDelete', entrypath, list[i])
6024 }, [ _('Delete') ]) : ''
6029 if (!rows.firstElementChild)
6030 rows.appendChild(E('em', _('No entries in this directory')));
6032 var dirs = this.splitPath(path),
6035 for (var i = 0; i < dirs.length; i++) {
6036 cur = cur ? cur + '/' + dirs[i] : dirs[i];
6037 dom.append(breadcrumb, [
6041 'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur || '/', null)
6042 }, dirs[i] != '' ? '%h'.format(dirs[i]) : E('em', '(root)')),
6046 dom.content(container, [
6049 E('div', { 'class': 'right' }, [
6050 this.renderUpload(path, list),
6054 'click': UI.prototype.createHandlerFn(this, 'handleCancel')
6061 handleCancel: function(ev) {
6062 var button = this.node.firstElementChild,
6063 browser = button.nextElementSibling;
6065 browser.classList.remove('open');
6066 button.style.display = '';
6068 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-cancel', {}));
6070 ev.preventDefault();
6074 handleReset: function(ev) {
6075 var button = this.node.firstElementChild,
6076 hidden = this.node.lastElementChild;
6079 dom.content(button, _('Select file…'));
6081 this.handleCancel(ev);
6085 handleSelect: function(path, fileStat, ev) {
6086 var browser = dom.parent(ev.target, '.cbi-filebrowser'),
6087 ul = browser.querySelector('ul');
6089 if (fileStat == null) {
6090 dom.content(ul, E('em', { 'class': 'spinning' }, _('Loading directory contents…')));
6091 L.resolveDefault(fs.list(path), []).then(L.bind(this.renderListing, this, browser, path));
6094 var button = this.node.firstElementChild,
6095 hidden = this.node.lastElementChild;
6097 path = this.canonicalizePath(path);
6099 dom.content(button, [
6100 this.iconForType(fileStat.type),
6101 ' %s (%1000mB)'.format(this.truncatePath(path), fileStat.size)
6104 browser.classList.remove('open');
6105 button.style.display = '';
6106 hidden.value = path;
6108 this.stat = Object.assign({ path: path }, fileStat);
6109 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-select', { detail: this.stat }));
6114 handleFileBrowser: function(ev) {
6115 var button = ev.target,
6116 browser = button.nextElementSibling,
6117 path = this.stat ? this.stat.path.replace(/\/[^\/]+$/, '') : (this.options.initial_directory || this.options.root_directory);
6119 if (path.indexOf(this.options.root_directory) != 0)
6120 path = this.options.root_directory;
6122 ev.preventDefault();
6124 return L.resolveDefault(fs.list(path), []).then(L.bind(function(button, browser, path, list) {
6125 document.querySelectorAll('.cbi-filebrowser.open').forEach(function(browserEl) {
6126 dom.findClassInstance(browserEl).handleCancel(ev);
6129 button.style.display = 'none';
6130 browser.classList.add('open');
6132 return this.renderListing(browser, path, list);
6133 }, this, button, browser, path));
6137 getValue: function() {
6138 return this.node.lastElementChild.value;
6142 setValue: function(value) {
6143 this.node.lastElementChild.value = value;
6153 * Provides high level UI helper functionality.
6154 * To import the class in views, use `'require ui'`, to import it in
6155 * external JavaScript, use `L.require("ui").then(...)`.
6157 var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
6158 __init__: function() {
6159 modalDiv = document.body.appendChild(
6160 dom.create('div', { id: 'modal_overlay' },
6161 dom.create('div', { class: 'modal', role: 'dialog', 'aria-modal': true })));
6163 tooltipDiv = document.body.appendChild(
6164 dom.create('div', { class: 'cbi-tooltip' }));
6166 /* setup old aliases */
6167 L.showModal = this.showModal;
6168 L.hideModal = this.hideModal;
6169 L.showTooltip = this.showTooltip;
6170 L.hideTooltip = this.hideTooltip;
6171 L.itemlist = this.itemlist;
6173 document.addEventListener('mouseover', this.showTooltip.bind(this), true);
6174 document.addEventListener('mouseout', this.hideTooltip.bind(this), true);
6175 document.addEventListener('focus', this.showTooltip.bind(this), true);
6176 document.addEventListener('blur', this.hideTooltip.bind(this), true);
6178 document.addEventListener('luci-loaded', this.tabs.init.bind(this.tabs));
6179 document.addEventListener('luci-loaded', this.changes.init.bind(this.changes));
6180 document.addEventListener('uci-loaded', this.changes.init.bind(this.changes));
6184 * Display a modal overlay dialog with the specified contents.
6186 * The modal overlay dialog covers the current view preventing interaction
6187 * with the underlying view contents. Only one modal dialog instance can
6188 * be opened. Invoking showModal() while a modal dialog is already open will
6189 * replace the open dialog with a new one having the specified contents.
6191 * Additional CSS class names may be passed to influence the appearence of
6192 * the dialog. Valid values for the classes depend on the underlying theme.
6194 * @see LuCI.dom.content
6196 * @param {string} [title]
6197 * The title of the dialog. If `null`, no title element will be rendered.
6199 * @param {*} contents
6200 * The contents to add to the modal dialog. This should be a DOM node or
6201 * a document fragment in most cases. The value is passed as-is to the
6202 * `dom.content()` function - refer to its documentation for applicable
6205 * @param {...string} [classes]
6206 * A number of extra CSS class names which are set on the modal dialog
6210 * Returns a DOM Node representing the modal dialog element.
6212 showModal: function(title, children /* , ... */) {
6213 var dlg = modalDiv.firstElementChild;
6215 dlg.setAttribute('class', 'modal');
6217 for (var i = 2; i < arguments.length; i++)
6218 dlg.classList.add(arguments[i]);
6220 dom.content(dlg, dom.create('h4', {}, title));
6221 dom.append(dlg, children);
6223 document.body.classList.add('modal-overlay-active');
6229 * Close the open modal overlay dialog.
6231 * This function will close an open modal dialog and restore the normal view
6232 * behaviour. It has no effect if no modal dialog is currently open.
6234 * Note that this function is stand-alone, it does not rely on `this` and
6235 * will not invoke other class functions so it suitable to be used as event
6236 * handler as-is without the need to bind it first.
6238 hideModal: function() {
6239 document.body.classList.remove('modal-overlay-active');
6243 showTooltip: function(ev) {
6244 var target = findParent(ev.target, '[data-tooltip]');
6249 if (tooltipTimeout !== null) {
6250 window.clearTimeout(tooltipTimeout);
6251 tooltipTimeout = null;
6254 var rect = target.getBoundingClientRect(),
6255 x = rect.left + window.pageXOffset,
6256 y = rect.top + rect.height + window.pageYOffset;
6258 tooltipDiv.className = 'cbi-tooltip';
6259 tooltipDiv.innerHTML = 'â–² ';
6260 tooltipDiv.firstChild.data += target.getAttribute('data-tooltip');
6262 if (target.hasAttribute('data-tooltip-style'))
6263 tooltipDiv.classList.add(target.getAttribute('data-tooltip-style'));
6265 if ((y + tooltipDiv.offsetHeight) > (window.innerHeight + window.pageYOffset)) {
6266 y -= (tooltipDiv.offsetHeight + target.offsetHeight);
6267 tooltipDiv.firstChild.data = 'â–¼ ' + tooltipDiv.firstChild.data.substr(2);
6270 tooltipDiv.style.top = y + 'px';
6271 tooltipDiv.style.left = x + 'px';
6272 tooltipDiv.style.opacity = 1;
6274 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-open', {
6276 detail: { target: target }
6281 hideTooltip: function(ev) {
6282 if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv ||
6283 tooltipDiv.contains(ev.target) || tooltipDiv.contains(ev.relatedTarget))
6286 if (tooltipTimeout !== null) {
6287 window.clearTimeout(tooltipTimeout);
6288 tooltipTimeout = null;
6291 tooltipDiv.style.opacity = 0;
6292 tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250);
6294 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-close', { bubbles: true }));
6298 * Add a notification banner at the top of the current view.
6300 * A notification banner is an alert message usually displayed at the
6301 * top of the current view, spanning the entire availibe width.
6302 * Notification banners will stay in place until dismissed by the user.
6303 * Multiple banners may be shown at the same time.
6305 * Additional CSS class names may be passed to influence the appearence of
6306 * the banner. Valid values for the classes depend on the underlying theme.
6308 * @see LuCI.dom.content
6310 * @param {string} [title]
6311 * The title of the notification banner. If `null`, no title element
6314 * @param {*} contents
6315 * The contents to add to the notification banner. This should be a DOM
6316 * node or a document fragment in most cases. The value is passed as-is
6317 * to the `dom.content()` function - refer to its documentation for
6318 * applicable values.
6320 * @param {...string} [classes]
6321 * A number of extra CSS class names which are set on the notification
6325 * Returns a DOM Node representing the notification banner element.
6327 addNotification: function(title, children /*, ... */) {
6328 var mc = document.querySelector('#maincontent') || document.body;
6329 var msg = E('div', {
6330 'class': 'alert-message fade-in',
6331 'style': 'display:flex',
6332 'transitionend': function(ev) {
6333 var node = ev.currentTarget;
6334 if (node.parentNode && node.classList.contains('fade-out'))
6335 node.parentNode.removeChild(node);
6338 E('div', { 'style': 'flex:10' }),
6339 E('div', { 'style': 'flex:1 1 auto; display:flex' }, [
6342 'style': 'margin-left:auto; margin-top:auto',
6343 'click': function(ev) {
6344 dom.parent(ev.target, '.alert-message').classList.add('fade-out');
6347 }, [ _('Dismiss') ])
6352 dom.append(msg.firstElementChild, E('h4', {}, title));
6354 dom.append(msg.firstElementChild, children);
6356 for (var i = 2; i < arguments.length; i++)
6357 msg.classList.add(arguments[i]);
6359 mc.insertBefore(msg, mc.firstElementChild);
6365 * Display or update an header area indicator.
6367 * An indicator is a small label displayed in the header area of the screen
6368 * providing few amounts of status information such as item counts or state
6369 * toggle indicators.
6371 * Multiple indicators may be shown at the same time and indicator labels
6372 * may be made clickable to display extended information or to initiate
6375 * Indicators can either use a default `active` or a less accented `inactive`
6376 * style which is useful for indicators representing state toggles.
6378 * @param {string} id
6379 * The ID of the indicator. If an indicator with the given ID already exists,
6380 * it is updated with the given label and style.
6382 * @param {string} label
6383 * The text to display in the indicator label.
6385 * @param {function} [handler]
6386 * A handler function to invoke when the indicator label is clicked/touched
6387 * by the user. If omitted, the indicator is not clickable/touchable.
6389 * Note that this parameter only applies to new indicators, when updating
6390 * existing labels it is ignored.
6392 * @param {string} [style=active]
6393 * The indicator style to use. May be either `active` or `inactive`.
6395 * @returns {boolean}
6396 * Returns `true` when the indicator has been updated or `false` when no
6397 * changes were made.
6399 showIndicator: function(id, label, handler, style) {
6400 if (indicatorDiv == null) {
6401 indicatorDiv = document.body.querySelector('#indicators');
6403 if (indicatorDiv == null)
6407 var handlerFn = (typeof(handler) == 'function') ? handler : null,
6408 indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) ||
6409 indicatorDiv.appendChild(E('span', {
6410 'data-indicator': id,
6411 'data-clickable': handlerFn ? true : null,
6415 if (label == indicatorElem.firstChild.data && style == indicatorElem.getAttribute('data-style'))
6418 indicatorElem.firstChild.data = label;
6419 indicatorElem.setAttribute('data-style', (style == 'inactive') ? 'inactive' : 'active');
6424 * Remove an header area indicator.
6426 * This function removes the given indicator label from the header indicator
6427 * area. When the given indicator is not found, this function does nothing.
6429 * @param {string} id
6430 * The ID of the indicator to remove.
6432 * @returns {boolean}
6433 * Returns `true` when the indicator has been removed or `false` when the
6434 * requested indicator was not found.
6436 hideIndicator: function(id) {
6437 var indicatorElem = indicatorDiv ? indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) : null;
6439 if (indicatorElem == null)
6442 indicatorDiv.removeChild(indicatorElem);
6447 * Formats a series of label/value pairs into list-like markup.
6449 * This function transforms a flat array of alternating label and value
6450 * elements into a list-like markup, using the values in `separators` as
6451 * separators and appends the resulting nodes to the given parent DOM node.
6453 * Each label is suffixed with `: ` and wrapped into a `<strong>` tag, the
6454 * `<strong>` element and the value corresponding to the label are
6455 * subsequently wrapped into a `<span class="nowrap">` element.
6457 * The resulting `<span>` element tuples are joined by the given separators
6458 * to form the final markup which is appened to the given parent DOM node.
6460 * @param {Node} node
6461 * The parent DOM node to append the markup to. Any previous child elements
6464 * @param {Array<*>} items
6465 * An alternating array of labels and values. The label values will be
6466 * converted to plain strings, the values are used as-is and may be of
6467 * any type accepted by `LuCI.dom.content()`.
6469 * @param {*|Array<*>} [separators=[E('br')]]
6470 * A single value or an array of separator values to separate each
6471 * label/value pair with. The function will cycle through the separators
6472 * when joining the pairs. If omitted, the default separator is a sole HTML
6473 * `<br>` element. Separator values are used as-is and may be of any type
6474 * accepted by `LuCI.dom.content()`.
6477 * Returns the parent DOM node the formatted markup has been added to.
6479 itemlist: function(node, items, separators) {
6482 if (!Array.isArray(separators))
6483 separators = [ separators || E('br') ];
6485 for (var i = 0; i < items.length; i += 2) {
6486 if (items[i+1] !== null && items[i+1] !== undefined) {
6487 var sep = separators[(i/2) % separators.length],
6490 children.push(E('span', { class: 'nowrap' }, [
6491 items[i] ? E('strong', items[i] + ': ') : '',
6495 if ((i+2) < items.length)
6496 children.push(dom.elem(sep) ? sep.cloneNode(true) : sep);
6500 dom.content(node, children);
6511 * The `tabs` class handles tab menu groups used throughout the view area.
6512 * It takes care of setting up tab groups, tracking their state and handling
6515 * This class is automatically instantiated as part of `LuCI.ui`. To use it
6516 * in views, use `'require ui'` and refer to `ui.tabs`. To import it in
6517 * external JavaScript, use `L.require("ui").then(...)` and access the
6518 * `tabs` property of the class instance value.
6520 tabs: baseclass.singleton(/* @lends LuCI.ui.tabs.prototype */ {
6523 var groups = [], prevGroup = null, currGroup = null;
6525 document.querySelectorAll('[data-tab]').forEach(function(tab) {
6526 var parent = tab.parentNode;
6528 if (dom.matches(tab, 'li') && dom.matches(parent, 'ul.cbi-tabmenu'))
6531 if (!parent.hasAttribute('data-tab-group'))
6532 parent.setAttribute('data-tab-group', groups.length);
6534 currGroup = +parent.getAttribute('data-tab-group');
6536 if (currGroup !== prevGroup) {
6537 prevGroup = currGroup;
6539 if (!groups[currGroup])
6540 groups[currGroup] = [];
6543 groups[currGroup].push(tab);
6546 for (var i = 0; i < groups.length; i++)
6547 this.initTabGroup(groups[i]);
6549 document.addEventListener('dependency-update', this.updateTabs.bind(this));
6555 * Initializes a new tab group from the given tab pane collection.
6557 * This function cycles through the given tab pane DOM nodes, extracts
6558 * their tab IDs, titles and active states, renders a corresponding
6559 * tab menu and prepends it to the tab panes common parent DOM node.
6561 * The tab menu labels will be set to the value of the `data-tab-title`
6562 * attribute of each corresponding pane. The last pane with the
6563 * `data-tab-active` attribute set to `true` will be selected by default.
6565 * If no pane is marked as active, the first one will be preselected.
6568 * @memberof LuCI.ui.tabs
6569 * @param {Array<Node>|NodeList} panes
6570 * A collection of tab panes to build a tab group menu for. May be a
6571 * plain array of DOM nodes or a NodeList collection, such as the result
6572 * of a `querySelectorAll()` call or the `.childNodes` property of a
6575 initTabGroup: function(panes) {
6576 if (typeof(panes) != 'object' || !('length' in panes) || panes.length === 0)
6579 var menu = E('ul', { 'class': 'cbi-tabmenu' }),
6580 group = panes[0].parentNode,
6581 groupId = +group.getAttribute('data-tab-group'),
6584 if (group.getAttribute('data-initialized') === 'true')
6587 for (var i = 0, pane; pane = panes[i]; i++) {
6588 var name = pane.getAttribute('data-tab'),
6589 title = pane.getAttribute('data-tab-title'),
6590 active = pane.getAttribute('data-tab-active') === 'true';
6592 menu.appendChild(E('li', {
6593 'style': this.isEmptyPane(pane) ? 'display:none' : null,
6594 'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
6598 'click': this.switchTab.bind(this)
6605 group.parentNode.insertBefore(menu, group);
6606 group.setAttribute('data-initialized', true);
6608 if (selected === null) {
6609 selected = this.getActiveTabId(panes[0]);
6611 if (selected < 0 || selected >= panes.length || this.isEmptyPane(panes[selected])) {
6612 for (var i = 0; i < panes.length; i++) {
6613 if (!this.isEmptyPane(panes[i])) {
6620 menu.childNodes[selected].classList.add('cbi-tab');
6621 menu.childNodes[selected].classList.remove('cbi-tab-disabled');
6622 panes[selected].setAttribute('data-tab-active', 'true');
6624 this.setActiveTabId(panes[selected], selected);
6627 panes[selected].dispatchEvent(new CustomEvent('cbi-tab-active', {
6628 detail: { tab: panes[selected].getAttribute('data-tab') }
6631 this.updateTabs(group);
6635 * Checks whether the given tab pane node is empty.
6638 * @memberof LuCI.ui.tabs
6639 * @param {Node} pane
6640 * The tab pane to check.
6642 * @returns {boolean}
6643 * Returns `true` if the pane is empty, else `false`.
6645 isEmptyPane: function(pane) {
6646 return dom.isEmpty(pane, function(n) { return n.classList.contains('cbi-tab-descr') });
6650 getPathForPane: function(pane) {
6651 var path = [], node = null;
6653 for (node = pane ? pane.parentNode : null;
6654 node != null && node.hasAttribute != null;
6655 node = node.parentNode)
6657 if (node.hasAttribute('data-tab'))
6658 path.unshift(node.getAttribute('data-tab'));
6659 else if (node.hasAttribute('data-section-id'))
6660 path.unshift(node.getAttribute('data-section-id'));
6663 return path.join('/');
6667 getActiveTabState: function() {
6668 var page = document.body.getAttribute('data-page');
6671 var val = JSON.parse(window.sessionStorage.getItem('tab'));
6672 if (val.page === page && L.isObject(val.paths))
6677 window.sessionStorage.removeItem('tab');
6678 return { page: page, paths: {} };
6682 getActiveTabId: function(pane) {
6683 var path = this.getPathForPane(pane);
6684 return +this.getActiveTabState().paths[path] || 0;
6688 setActiveTabId: function(pane, tabIndex) {
6689 var path = this.getPathForPane(pane);
6692 var state = this.getActiveTabState();
6693 state.paths[path] = tabIndex;
6695 window.sessionStorage.setItem('tab', JSON.stringify(state));
6697 catch (e) { return false; }
6703 updateTabs: function(ev, root) {
6704 (root || document).querySelectorAll('[data-tab-title]').forEach(L.bind(function(pane) {
6705 var menu = pane.parentNode.previousElementSibling,
6706 tab = menu ? menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))) : null,
6707 n_errors = pane.querySelectorAll('.cbi-input-invalid').length;
6712 if (this.isEmptyPane(pane)) {
6713 tab.style.display = 'none';
6714 tab.classList.remove('flash');
6716 else if (tab.style.display === 'none') {
6717 tab.style.display = '';
6718 requestAnimationFrame(function() { tab.classList.add('flash') });
6722 tab.setAttribute('data-errors', n_errors);
6723 tab.setAttribute('data-tooltip', _('%d invalid field(s)').format(n_errors));
6724 tab.setAttribute('data-tooltip-style', 'error');
6727 tab.removeAttribute('data-errors');
6728 tab.removeAttribute('data-tooltip');
6734 switchTab: function(ev) {
6735 var tab = ev.target.parentNode,
6736 name = tab.getAttribute('data-tab'),
6737 menu = tab.parentNode,
6738 group = menu.nextElementSibling,
6739 groupId = +group.getAttribute('data-tab-group'),
6742 ev.preventDefault();
6744 if (!tab.classList.contains('cbi-tab-disabled'))
6747 menu.querySelectorAll('[data-tab]').forEach(function(tab) {
6748 tab.classList.remove('cbi-tab');
6749 tab.classList.remove('cbi-tab-disabled');
6751 tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled');
6754 group.childNodes.forEach(function(pane) {
6755 if (dom.matches(pane, '[data-tab]')) {
6756 if (pane.getAttribute('data-tab') === name) {
6757 pane.setAttribute('data-tab-active', 'true');
6758 pane.dispatchEvent(new CustomEvent('cbi-tab-active', { detail: { tab: name } }));
6759 UI.prototype.tabs.setActiveTabId(pane, index);
6762 pane.setAttribute('data-tab-active', 'false');
6772 * @typedef {Object} FileUploadReply
6775 * @property {string} name - Name of the uploaded file without directory components
6776 * @property {number} size - Size of the uploaded file in bytes
6777 * @property {string} checksum - The MD5 checksum of the received file data
6778 * @property {string} sha256sum - The SHA256 checksum of the received file data
6782 * Display a modal file upload prompt.
6784 * This function opens a modal dialog prompting the user to select and
6785 * upload a file to a predefined remote destination path.
6787 * @param {string} path
6788 * The remote file path to upload the local file to.
6790 * @param {Node} [progessStatusNode]
6791 * An optional DOM text node whose content text is set to the progress
6792 * percentage value during file upload.
6794 * @returns {Promise<LuCI.ui.FileUploadReply>}
6795 * Returns a promise resolving to a file upload status object on success
6796 * or rejecting with an error in case the upload failed or has been
6797 * cancelled by the user.
6799 uploadFile: function(path, progressStatusNode) {
6800 return new Promise(function(resolveFn, rejectFn) {
6801 UI.prototype.showModal(_('Uploading file…'), [
6802 E('p', _('Please select the file to upload.')),
6803 E('div', { 'style': 'display:flex' }, [
6804 E('div', { 'class': 'left', 'style': 'flex:1' }, [
6807 style: 'display:none',
6808 change: function(ev) {
6809 var modal = dom.parent(ev.target, '.modal'),
6810 body = modal.querySelector('p'),
6811 upload = modal.querySelector('.cbi-button-action.important'),
6812 file = ev.currentTarget.files[0];
6819 E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]),
6820 E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ])
6824 upload.disabled = false;
6830 'click': function(ev) {
6831 ev.target.previousElementSibling.click();
6833 }, [ _('Browse…') ])
6835 E('div', { 'class': 'right', 'style': 'flex:1' }, [
6838 'click': function() {
6839 UI.prototype.hideModal();
6840 rejectFn(new Error('Upload has been cancelled'));
6842 }, [ _('Cancel') ]),
6845 'class': 'btn cbi-button-action important',
6847 'click': function(ev) {
6848 var input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]');
6850 if (!input.files[0])
6853 var progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' }));
6855 UI.prototype.showModal(_('Uploading file…'), [ progress ]);
6857 var data = new FormData();
6859 data.append('sessionid', rpc.getSessionID());
6860 data.append('filename', path);
6861 data.append('filedata', input.files[0]);
6863 var filename = input.files[0].name;
6865 request.post(L.env.cgi_base + '/cgi-upload', data, {
6867 progress: function(pev) {
6868 var percent = (pev.loaded / pev.total) * 100;
6870 if (progressStatusNode)
6871 progressStatusNode.data = '%.2f%%'.format(percent);
6873 progress.setAttribute('title', '%.2f%%'.format(percent));
6874 progress.firstElementChild.style.width = '%.2f%%'.format(percent);
6876 }).then(function(res) {
6877 var reply = res.json();
6879 UI.prototype.hideModal();
6881 if (L.isObject(reply) && reply.failure) {
6882 UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message)));
6883 rejectFn(new Error(reply.failure));
6886 reply.name = filename;
6890 UI.prototype.hideModal();
6902 * Perform a device connectivity test.
6904 * Attempt to fetch a well known ressource from the remote device via HTTP
6905 * in order to test connectivity. This function is mainly useful to wait
6906 * for the router to come back online after a reboot or reconfiguration.
6908 * @param {string} [proto=http]
6909 * The protocol to use for fetching the resource. May be either `http`
6910 * (the default) or `https`.
6912 * @param {string} [host=window.location.host]
6913 * Override the host address to probe. By default the current host as seen
6914 * in the address bar is probed.
6916 * @returns {Promise<Event>}
6917 * Returns a promise resolving to a `load` event in case the device is
6918 * reachable or rejecting with an `error` event in case it is not reachable
6919 * or rejecting with `null` when the connectivity check timed out.
6921 pingDevice: function(proto, ipaddr) {
6922 var target = '%s://%s%s?%s'.format(proto || 'http', ipaddr || window.location.host, L.resource('icons/loading.gif'), Math.random());
6924 return new Promise(function(resolveFn, rejectFn) {
6925 var img = new Image();
6927 img.onload = resolveFn;
6928 img.onerror = rejectFn;
6930 window.setTimeout(rejectFn, 1000);
6937 * Wait for device to come back online and reconnect to it.
6939 * Poll each given hostname or IP address and navigate to it as soon as
6940 * one of the addresses becomes reachable.
6942 * @param {...string} [hosts=[window.location.host]]
6943 * The list of IP addresses and host names to check for reachability.
6944 * If omitted, the current value of `window.location.host` is used by
6947 awaitReconnect: function(/* ... */) {
6948 var ipaddrs = arguments.length ? arguments : [ window.location.host ];
6950 window.setTimeout(L.bind(function() {
6951 poll.add(L.bind(function() {
6952 var tasks = [], reachable = false;
6954 for (var i = 0; i < 2; i++)
6955 for (var j = 0; j < ipaddrs.length; j++)
6956 tasks.push(this.pingDevice(i ? 'https' : 'http', ipaddrs[j])
6957 .then(function(ev) { reachable = ev.target.src.replace(/^(https?:\/\/[^\/]+).*$/, '$1/') }, function() {}));
6959 return Promise.all(tasks).then(function() {
6962 window.location = reachable;
6975 * The `changes` class encapsulates logic for visualizing, applying,
6976 * confirming and reverting staged UCI changesets.
6978 * This class is automatically instantiated as part of `LuCI.ui`. To use it
6979 * in views, use `'require ui'` and refer to `ui.changes`. To import it in
6980 * external JavaScript, use `L.require("ui").then(...)` and access the
6981 * `changes` property of the class instance value.
6983 changes: baseclass.singleton(/* @lends LuCI.ui.changes.prototype */ {
6985 if (!L.env.sessionid)
6988 return uci.changes().then(L.bind(this.renderChangeIndicator, this));
6992 * Set the change count indicator.
6994 * This function updates or hides the UCI change count indicator,
6995 * depending on the passed change count. When the count is greater
6996 * than 0, the change indicator is displayed or updated, otherwise it
7000 * @memberof LuCI.ui.changes
7001 * @param {number} numChanges
7002 * The number of changes to indicate.
7004 setIndicator: function(n) {
7005 var i = document.querySelector('.uci_change_indicator');
7007 var poll = document.getElementById('xhr_poll_status');
7008 i = poll.parentNode.insertBefore(E('a', {
7010 'class': 'uci_change_indicator label notice',
7011 'click': L.bind(this.displayChanges, this)
7016 dom.content(i, [ _('Unsaved Changes'), ': ', n ]);
7017 i.classList.add('flash');
7018 i.style.display = '';
7019 document.dispatchEvent(new CustomEvent('uci-new-changes'));
7022 i.classList.remove('flash');
7023 i.style.display = 'none';
7024 document.dispatchEvent(new CustomEvent('uci-clear-changes'));
7029 * Update the change count indicator.
7031 * This function updates the UCI change count indicator from the given
7032 * UCI changeset structure.
7035 * @memberof LuCI.ui.changes
7036 * @param {Object<string, Array<LuCI.uci.ChangeRecord>>} changes
7037 * The UCI changeset to count.
7039 renderChangeIndicator: function(changes) {
7042 for (var config in changes)
7043 if (changes.hasOwnProperty(config))
7044 n_changes += changes[config].length;
7046 this.changes = changes;
7047 this.setIndicator(n_changes);
7052 'add-3': '<ins>uci add %0 <strong>%3</strong> # =%2</ins>',
7053 'set-3': '<ins>uci set %0.<strong>%2</strong>=%3</ins>',
7054 'set-4': '<var><ins>uci set %0.%2.%3=<strong>%4</strong></ins></var>',
7055 'remove-2': '<del>uci del %0.<strong>%2</strong></del>',
7056 'remove-3': '<var><del>uci del %0.%2.<strong>%3</strong></del></var>',
7057 'order-3': '<var>uci reorder %0.%2=<strong>%3</strong></var>',
7058 'list-add-4': '<var><ins>uci add_list %0.%2.%3=<strong>%4</strong></ins></var>',
7059 'list-del-4': '<var><del>uci del_list %0.%2.%3=<strong>%4</strong></del></var>',
7060 'rename-3': '<var>uci rename %0.%2=<strong>%3</strong></var>',
7061 'rename-4': '<var>uci rename %0.%2.%3=<strong>%4</strong></var>'
7065 * Display the current changelog.
7067 * Open a modal dialog visualizing the currently staged UCI changes
7068 * and offer options to revert or apply the shown changes.
7071 * @memberof LuCI.ui.changes
7073 displayChanges: function() {
7074 var list = E('div', { 'class': 'uci-change-list' }),
7075 dlg = UI.prototype.showModal(_('Configuration') + ' / ' + _('Changes'), [
7076 E('div', { 'class': 'cbi-section' }, [
7077 E('strong', _('Legend:')),
7078 E('div', { 'class': 'uci-change-legend' }, [
7079 E('div', { 'class': 'uci-change-legend-label' }, [
7080 E('ins', '&#160;'), ' ', _('Section added') ]),
7081 E('div', { 'class': 'uci-change-legend-label' }, [
7082 E('del', '&#160;'), ' ', _('Section removed') ]),
7083 E('div', { 'class': 'uci-change-legend-label' }, [
7084 E('var', {}, E('ins', '&#160;')), ' ', _('Option changed') ]),
7085 E('div', { 'class': 'uci-change-legend-label' }, [
7086 E('var', {}, E('del', '&#160;')), ' ', _('Option removed') ])]),
7088 E('div', { 'class': 'right' }, [
7091 'click': UI.prototype.hideModal
7092 }, [ _('Dismiss') ]), ' ',
7094 'class': 'cbi-button cbi-button-positive important',
7095 'click': L.bind(this.apply, this, true)
7096 }, [ _('Save & Apply') ]), ' ',
7098 'class': 'cbi-button cbi-button-reset',
7099 'click': L.bind(this.revert, this)
7100 }, [ _('Revert') ])])])
7103 for (var config in this.changes) {
7104 if (!this.changes.hasOwnProperty(config))
7107 list.appendChild(E('h5', '# /etc/config/%s'.format(config)));
7109 for (var i = 0, added = null; i < this.changes[config].length; i++) {
7110 var chg = this.changes[config][i],
7111 tpl = this.changeTemplates['%s-%d'.format(chg[0], chg.length)];
7113 list.appendChild(E(tpl.replace(/%([01234])/g, function(m0, m1) {
7119 if (added != null && chg[1] == added[0])
7120 return '@' + added[1] + '[-1]';
7125 return "'%h'".format(chg[3].replace(/'/g, "'\"'\"'"));
7132 if (chg[0] == 'add')
7133 added = [ chg[1], chg[2] ];
7137 list.appendChild(E('br'));
7138 dlg.classList.add('uci-dialog');
7142 displayStatus: function(type, content) {
7144 var message = UI.prototype.showModal('', '');
7146 message.classList.add('alert-message');
7147 DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
7150 dom.content(message, content);
7152 if (!this.was_polling) {
7153 this.was_polling = request.poll.active();
7154 request.poll.stop();
7158 UI.prototype.hideModal();
7160 if (this.was_polling)
7161 request.poll.start();
7166 rollback: function(checked) {
7168 this.displayStatus('warning spinning',
7169 E('p', _('Failed to confirm apply within %ds, waiting for rollback…')
7170 .format(L.env.apply_rollback)));
7172 var call = function(r, data, duration) {
7173 if (r.status === 204) {
7174 UI.prototype.changes.displayStatus('warning', [
7175 E('h4', _('Configuration changes have been rolled back!')),
7176 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)),
7177 E('div', { 'class': 'right' }, [
7180 'click': L.bind(UI.prototype.changes.displayStatus, UI.prototype.changes, false)
7181 }, [ _('Dismiss') ]), ' ',
7183 'class': 'btn cbi-button-action important',
7184 'click': L.bind(UI.prototype.changes.revert, UI.prototype.changes)
7185 }, [ _('Revert changes') ]), ' ',
7187 'class': 'btn cbi-button-negative important',
7188 'click': L.bind(UI.prototype.changes.apply, UI.prototype.changes, false)
7189 }, [ _('Apply unchecked') ])
7196 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
7197 window.setTimeout(function() {
7198 request.request(L.url('admin/uci/confirm'), {
7200 timeout: L.env.apply_timeout * 1000,
7201 query: { sid: L.env.sessionid, token: L.env.token }
7206 call({ status: 0 });
7209 this.displayStatus('warning', [
7210 E('h4', _('Device unreachable!')),
7211 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.'))
7217 confirm: function(checked, deadline, override_token) {
7219 var ts = Date.now();
7221 this.displayStatus('notice');
7224 this.confirm_auth = { token: override_token };
7226 var call = function(r, data, duration) {
7227 if (Date.now() >= deadline) {
7228 window.clearTimeout(tt);
7229 UI.prototype.changes.rollback(checked);
7232 else if (r && (r.status === 200 || r.status === 204)) {
7233 document.dispatchEvent(new CustomEvent('uci-applied'));
7235 UI.prototype.changes.setIndicator(0);
7236 UI.prototype.changes.displayStatus('notice',
7237 E('p', _('Configuration changes applied.')));
7239 window.clearTimeout(tt);
7240 window.setTimeout(function() {
7241 //UI.prototype.changes.displayStatus(false);
7242 window.location = window.location.href.split('#')[0];
7243 }, L.env.apply_display * 1000);
7248 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
7249 window.setTimeout(function() {
7250 request.request(L.url('admin/uci/confirm'), {
7252 timeout: L.env.apply_timeout * 1000,
7253 query: UI.prototype.changes.confirm_auth
7254 }).then(call, call);
7258 var tick = function() {
7259 var now = Date.now();
7261 UI.prototype.changes.displayStatus('notice spinning',
7262 E('p', _('Applying configuration changes… %ds')
7263 .format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0))));
7265 if (now >= deadline)
7268 tt = window.setTimeout(tick, 1000 - (now - ts));
7274 /* wait a few seconds for the settings to become effective */
7275 window.setTimeout(call, Math.max(L.env.apply_holdoff * 1000 - ((ts + L.env.apply_rollback * 1000) - deadline), 1));
7279 * Apply the staged configuration changes.
7281 * Start applying staged configuration changes and open a modal dialog
7282 * with a progress indication to prevent interaction with the view
7283 * during the apply process. The modal dialog will be automatically
7284 * closed and the current view reloaded once the apply process is
7288 * @memberof LuCI.ui.changes
7289 * @param {boolean} [checked=false]
7290 * Whether to perform a checked (`true`) configuration apply or an
7291 * unchecked (`false`) one.
7293 * In case of a checked apply, the configuration changes must be
7294 * confirmed within a specific time interval, otherwise the device
7295 * will begin to roll back the changes in order to restore the previous
7298 apply: function(checked) {
7299 this.displayStatus('notice spinning',
7300 E('p', _('Starting configuration apply…')));
7302 request.request(L.url('admin/uci', checked ? 'apply_rollback' : 'apply_unchecked'), {
7304 query: { sid: L.env.sessionid, token: L.env.token }
7305 }).then(function(r) {
7306 if (r.status === (checked ? 200 : 204)) {
7307 var tok = null; try { tok = r.json(); } catch(e) {}
7308 if (checked && tok !== null && typeof(tok) === 'object' && typeof(tok.token) === 'string')
7309 UI.prototype.changes.confirm_auth = tok;
7311 UI.prototype.changes.confirm(checked, Date.now() + L.env.apply_rollback * 1000);
7313 else if (checked && r.status === 204) {
7314 UI.prototype.changes.displayStatus('notice',
7315 E('p', _('There are no changes to apply')));
7317 window.setTimeout(function() {
7318 UI.prototype.changes.displayStatus(false);
7319 }, L.env.apply_display * 1000);
7322 UI.prototype.changes.displayStatus('warning',
7323 E('p', _('Apply request failed with status <code>%h</code>')
7324 .format(r.responseText || r.statusText || r.status)));
7326 window.setTimeout(function() {
7327 UI.prototype.changes.displayStatus(false);
7328 }, L.env.apply_display * 1000);
7334 * Revert the staged configuration changes.
7336 * Start reverting staged configuration changes and open a modal dialog
7337 * with a progress indication to prevent interaction with the view
7338 * during the revert process. The modal dialog will be automatically
7339 * closed and the current view reloaded once the revert process is
7343 * @memberof LuCI.ui.changes
7345 revert: function() {
7346 this.displayStatus('notice spinning',
7347 E('p', _('Reverting configuration…')));
7349 request.request(L.url('admin/uci/revert'), {
7351 query: { sid: L.env.sessionid, token: L.env.token }
7352 }).then(function(r) {
7353 if (r.status === 200) {
7354 document.dispatchEvent(new CustomEvent('uci-reverted'));
7356 UI.prototype.changes.setIndicator(0);
7357 UI.prototype.changes.displayStatus('notice',
7358 E('p', _('Changes have been reverted.')));
7360 window.setTimeout(function() {
7361 //UI.prototype.changes.displayStatus(false);
7362 window.location = window.location.href.split('#')[0];
7363 }, L.env.apply_display * 1000);
7366 UI.prototype.changes.displayStatus('warning',
7367 E('p', _('Revert request failed with status <code>%h</code>')
7368 .format(r.statusText || r.status)));
7370 window.setTimeout(function() {
7371 UI.prototype.changes.displayStatus(false);
7372 }, L.env.apply_display * 1000);
7379 * Add validation constraints to an input element.
7381 * Compile the given type expression and optional validator function into
7382 * a validation function and bind it to the specified input element events.
7384 * @param {Node} field
7385 * The DOM input element node to bind the validation constraints to.
7387 * @param {string} type
7388 * The datatype specification to describe validation constraints.
7389 * Refer to the `LuCI.validation` class documentation for details.
7391 * @param {boolean} [optional=false]
7392 * Specifies whether empty values are allowed (`true`) or not (`false`).
7393 * If an input element is not marked optional it must not be empty,
7394 * otherwise it will be marked as invalid.
7396 * @param {function} [vfunc]
7397 * Specifies a custom validation function which is invoked after the
7398 * other validation constraints are applied. The validation must return
7399 * `true` to accept the passed value. Any other return type is converted
7400 * to a string and treated as validation error message.
7402 * @param {...string} [events=blur, keyup]
7403 * The list of events to bind. Each received event will trigger a field
7404 * validation. If omitted, the `keyup` and `blur` events are bound by
7407 * @returns {function}
7408 * Returns the compiled validator function which can be used to manually
7409 * trigger field validation or to bind it to further events.
7411 * @see LuCI.validation
7413 addValidator: function(field, type, optional, vfunc /*, ... */) {
7417 var events = this.varargs(arguments, 3);
7418 if (events.length == 0)
7419 events.push('blur', 'keyup');
7422 var cbiValidator = validation.create(field, type, optional, vfunc),
7423 validatorFn = cbiValidator.validate.bind(cbiValidator);
7425 for (var i = 0; i < events.length; i++)
7426 field.addEventListener(events[i], validatorFn);
7436 * Create a pre-bound event handler function.
7438 * Generate and bind a function suitable for use in event handlers. The
7439 * generated function automatically disables the event source element
7440 * and adds an active indication to it by adding appropriate CSS classes.
7442 * It will also await any promises returned by the wrapped function and
7443 * re-enable the source element after the promises ran to completion.
7446 * The `this` context to use for the wrapped function.
7448 * @param {function|string} fn
7449 * Specifies the function to wrap. In case of a function value, the
7450 * function is used as-is. If a string is specified instead, it is looked
7451 * up in `ctx` to obtain the function to wrap. In both cases the bound
7452 * function will be invoked with `ctx` as `this` context
7454 * @param {...*} extra_args
7455 * Any further parameter as passed as-is to the bound event handler
7456 * function in the same order as passed to `createHandlerFn()`.
7458 * @returns {function|null}
7459 * Returns the pre-bound handler function which is suitable to be passed
7460 * to `addEventListener()`. Returns `null` if the given `fn` argument is
7461 * a string which could not be found in `ctx` or if `ctx[fn]` is not a
7462 * valid function value.
7464 createHandlerFn: function(ctx, fn /*, ... */) {
7465 if (typeof(fn) == 'string')
7468 if (typeof(fn) != 'function')
7471 var arg_offset = arguments.length - 2;
7473 return Function.prototype.bind.apply(function() {
7474 var t = arguments[arg_offset].currentTarget;
7476 t.classList.add('spinning');
7482 Promise.resolve(fn.apply(ctx, arguments)).finally(function() {
7483 t.classList.remove('spinning');
7486 }, this.varargs(arguments, 2, ctx));
7490 * Load specified view class path and set it up.
7492 * Transforms the given view path into a class name, requires it
7493 * using [LuCI.require()]{@link LuCI#require} and asserts that the
7494 * resulting class instance is a descendant of
7495 * [LuCI.view]{@link LuCI.view}.
7497 * By instantiating the view class, its corresponding contents are
7498 * rendered and included into the view area. Any runtime errors are
7499 * catched and rendered using [LuCI.error()]{@link LuCI#error}.
7501 * @param {string} path
7502 * The view path to render.
7504 * @returns {Promise<LuCI.view>}
7505 * Returns a promise resolving to the loaded view instance.
7507 instantiateView: function(path) {
7508 var className = 'view.%s'.format(path.replace(/\//g, '.'));
7510 return L.require(className).then(function(view) {
7511 if (!(view instanceof View))
7512 throw new TypeError('Loaded class %s is not a descendant of View'.format(className));
7515 }).catch(function(err) {
7516 dom.content(document.querySelector('#view'), null);
7521 AbstractElement: UIElement,
7524 Textfield: UITextfield,
7525 Textarea: UITextarea,
7526 Checkbox: UICheckbox,
7528 Dropdown: UIDropdown,
7529 DynamicList: UIDynamicList,
7530 Combobox: UICombobox,
7531 ComboButton: UIComboButton,
7532 Hiddenfield: UIHiddenfield,
7533 FileUpload: UIFileUpload
7549 Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Tue Apr 07 2020 16:33:40 GMT+0200 (Central European Summer Time)
7553 <script>prettyPrint();</script>
7554 <script src="scripts/jaguar.js"></script>