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#fspath"><a href="LuCI.html#fspath">fspath</a></li>
79 <li data-name="LuCI#get"><a href="LuCI.html#get">get</a></li>
81 <li data-name="LuCI#halt"><a href="LuCI.html#halt">halt</a></li>
83 <li data-name="LuCI#hasSystemFeature"><a href="LuCI.html#hasSystemFeature">hasSystemFeature</a></li>
85 <li data-name="LuCI#hasViewPermission"><a href="LuCI.html#hasViewPermission">hasViewPermission</a></li>
87 <li data-name="LuCI#isObject"><a href="LuCI.html#isObject">isObject</a></li>
89 <li data-name="LuCI#location"><a href="LuCI.html#location">location</a></li>
91 <li data-name="LuCI#media"><a href="LuCI.html#media">media</a></li>
93 <li data-name="LuCI#path"><a href="LuCI.html#path">path</a></li>
95 <li data-name="LuCI#poll"><a href="LuCI.html#poll">poll</a></li>
97 <li data-name="LuCI#post"><a href="LuCI.html#post">post</a></li>
99 <li data-name="LuCI#raise"><a href="LuCI.html#raise">raise</a></li>
101 <li data-name="LuCI#require"><a href="LuCI.html#require">require</a></li>
103 <li data-name="LuCI#resolveDefault"><a href="LuCI.html#resolveDefault">resolveDefault</a></li>
105 <li data-name="LuCI#resource"><a href="LuCI.html#resource">resource</a></li>
107 <li data-name="LuCI#run"><a href="LuCI.html#run">run</a></li>
109 <li data-name="LuCI#sortedKeys"><a href="LuCI.html#sortedKeys">sortedKeys</a></li>
111 <li data-name="LuCI#stop"><a href="LuCI.html#stop">stop</a></li>
113 <li data-name="LuCI#toArray"><a href="LuCI.html#toArray">toArray</a></li>
115 <li data-name="LuCI#url"><a href="LuCI.html#url">url</a></li>
118 <ul class="events itemMembers">
123 <li class="item" data-name="LuCI.baseclass">
125 <a href="LuCI.baseclass.html">LuCI.baseclass</a>
128 <ul class="members itemMembers">
131 <ul class="typedefs itemMembers">
134 <ul class="typedefs itemMembers">
137 <ul class="methods itemMembers">
139 <span class="subtitle">Methods</span>
141 <li data-name="LuCI.baseclass.extend"><a href="LuCI.baseclass.html#.extend">extend</a></li>
143 <li data-name="LuCI.baseclass.instantiate"><a href="LuCI.baseclass.html#.instantiate">instantiate</a></li>
145 <li data-name="LuCI.baseclass.isSubclass"><a href="LuCI.baseclass.html#.isSubclass">isSubclass</a></li>
147 <li data-name="LuCI.baseclass.singleton"><a href="LuCI.baseclass.html#.singleton">singleton</a></li>
149 <li data-name="LuCI.baseclass#super"><a href="LuCI.baseclass.html#super">super</a></li>
151 <li data-name="LuCI.baseclass#varargs"><a href="LuCI.baseclass.html#varargs">varargs</a></li>
154 <ul class="events itemMembers">
159 <li class="item" data-name="LuCI.dom">
161 <a href="LuCI.dom.html">LuCI.dom</a>
164 <ul class="members itemMembers">
167 <ul class="typedefs itemMembers">
169 <span class="subtitle">Typedefs</span>
171 <li data-name="LuCI.dom~ignoreCallbackFn"><a href="LuCI.dom.html#~ignoreCallbackFn">ignoreCallbackFn</a></li>
174 <ul class="typedefs itemMembers">
177 <ul class="methods itemMembers">
179 <span class="subtitle">Methods</span>
181 <li data-name="LuCI.dom#append"><a href="LuCI.dom.html#append">append</a></li>
183 <li data-name="LuCI.dom#attr"><a href="LuCI.dom.html#attr">attr</a></li>
185 <li data-name="LuCI.dom#bindClassInstance"><a href="LuCI.dom.html#bindClassInstance">bindClassInstance</a></li>
187 <li data-name="LuCI.dom#callClassMethod"><a href="LuCI.dom.html#callClassMethod">callClassMethod</a></li>
189 <li data-name="LuCI.dom#content"><a href="LuCI.dom.html#content">content</a></li>
191 <li data-name="LuCI.dom#create"><a href="LuCI.dom.html#create">create</a></li>
193 <li data-name="LuCI.dom#data"><a href="LuCI.dom.html#data">data</a></li>
195 <li data-name="LuCI.dom#elem"><a href="LuCI.dom.html#elem">elem</a></li>
197 <li data-name="LuCI.dom#findClassInstance"><a href="LuCI.dom.html#findClassInstance">findClassInstance</a></li>
199 <li data-name="LuCI.dom#isEmpty"><a href="LuCI.dom.html#isEmpty">isEmpty</a></li>
201 <li data-name="LuCI.dom#matches"><a href="LuCI.dom.html#matches">matches</a></li>
203 <li data-name="LuCI.dom#parent"><a href="LuCI.dom.html#parent">parent</a></li>
205 <li data-name="LuCI.dom#parse"><a href="LuCI.dom.html#parse">parse</a></li>
208 <ul class="events itemMembers">
213 <li class="item" data-name="LuCI.form">
215 <a href="LuCI.form.html">LuCI.form</a>
218 <ul class="members itemMembers">
221 <ul class="typedefs itemMembers">
224 <ul class="typedefs itemMembers">
227 <ul class="methods itemMembers">
230 <ul class="events itemMembers">
235 <li class="item" data-name="LuCI.form.AbstractElement">
237 <a href="LuCI.form.AbstractElement.html">LuCI.form.AbstractElement</a>
240 <ul class="members itemMembers">
243 <ul class="typedefs itemMembers">
246 <ul class="typedefs itemMembers">
249 <ul class="methods itemMembers">
251 <span class="subtitle">Methods</span>
253 <li data-name="LuCI.form.AbstractElement#append"><a href="LuCI.form.AbstractElement.html#append">append</a></li>
255 <li data-name="LuCI.form.AbstractElement#parse"><a href="LuCI.form.AbstractElement.html#parse">parse</a></li>
257 <li data-name="LuCI.form.AbstractElement#render"><a href="LuCI.form.AbstractElement.html#render">render</a></li>
259 <li data-name="LuCI.form.AbstractElement#stripTags"><a href="LuCI.form.AbstractElement.html#stripTags">stripTags</a></li>
261 <li data-name="LuCI.form.AbstractElement#titleFn"><a href="LuCI.form.AbstractElement.html#titleFn">titleFn</a></li>
264 <ul class="events itemMembers">
269 <li class="item" data-name="LuCI.form.AbstractSection">
271 <a href="LuCI.form.AbstractSection.html">LuCI.form.AbstractSection</a>
274 <ul class="members itemMembers">
276 <span class="subtitle">Members</span>
278 <li data-name="LuCI.form.AbstractSection##parentoption"><a href="LuCI.form.AbstractSection.html#parentoption">parentoption</a></li>
281 <ul class="typedefs itemMembers">
284 <ul class="typedefs itemMembers">
287 <ul class="methods itemMembers">
289 <span class="subtitle">Methods</span>
291 <li data-name="LuCI.form.AbstractSection#append"><a href="LuCI.form.AbstractSection.html#append">append</a></li>
293 <li data-name="LuCI.form.AbstractSection#cfgsections"><a href="LuCI.form.AbstractSection.html#cfgsections">cfgsections</a></li>
295 <li data-name="LuCI.form.AbstractSection#filter"><a href="LuCI.form.AbstractSection.html#filter">filter</a></li>
297 <li data-name="LuCI.form.AbstractSection#load"><a href="LuCI.form.AbstractSection.html#load">load</a></li>
299 <li data-name="LuCI.form.AbstractSection#option"><a href="LuCI.form.AbstractSection.html#option">option</a></li>
301 <li data-name="LuCI.form.AbstractSection#parse"><a href="LuCI.form.AbstractSection.html#parse">parse</a></li>
303 <li data-name="LuCI.form.AbstractSection#render"><a href="LuCI.form.AbstractSection.html#render">render</a></li>
305 <li data-name="LuCI.form.AbstractSection#stripTags"><a href="LuCI.form.AbstractSection.html#stripTags">stripTags</a></li>
307 <li data-name="LuCI.form.AbstractSection#tab"><a href="LuCI.form.AbstractSection.html#tab">tab</a></li>
309 <li data-name="LuCI.form.AbstractSection#taboption"><a href="LuCI.form.AbstractSection.html#taboption">taboption</a></li>
311 <li data-name="LuCI.form.AbstractSection#titleFn"><a href="LuCI.form.AbstractSection.html#titleFn">titleFn</a></li>
314 <ul class="events itemMembers">
319 <li class="item" data-name="LuCI.form.AbstractValue">
321 <a href="LuCI.form.AbstractValue.html">LuCI.form.AbstractValue</a>
324 <ul class="members itemMembers">
326 <span class="subtitle">Members</span>
328 <li data-name="LuCI.form.AbstractValue##datatype"><a href="LuCI.form.AbstractValue.html#datatype">datatype</a></li>
330 <li data-name="LuCI.form.AbstractValue##default"><a href="LuCI.form.AbstractValue.html#default">default</a></li>
332 <li data-name="LuCI.form.AbstractValue##editable"><a href="LuCI.form.AbstractValue.html#editable">editable</a></li>
334 <li data-name="LuCI.form.AbstractValue##modalonly"><a href="LuCI.form.AbstractValue.html#modalonly">modalonly</a></li>
336 <li data-name="LuCI.form.AbstractValue##optional"><a href="LuCI.form.AbstractValue.html#optional">optional</a></li>
338 <li data-name="LuCI.form.AbstractValue##readonly"><a href="LuCI.form.AbstractValue.html#readonly">readonly</a></li>
340 <li data-name="LuCI.form.AbstractValue##rmempty"><a href="LuCI.form.AbstractValue.html#rmempty">rmempty</a></li>
342 <li data-name="LuCI.form.AbstractValue##uciconfig"><a href="LuCI.form.AbstractValue.html#uciconfig">uciconfig</a></li>
344 <li data-name="LuCI.form.AbstractValue##ucioption"><a href="LuCI.form.AbstractValue.html#ucioption">ucioption</a></li>
346 <li data-name="LuCI.form.AbstractValue##ucisection"><a href="LuCI.form.AbstractValue.html#ucisection">ucisection</a></li>
348 <li data-name="LuCI.form.AbstractValue##validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
350 <li data-name="LuCI.form.AbstractValue##width"><a href="LuCI.form.AbstractValue.html#width">width</a></li>
353 <ul class="typedefs itemMembers">
356 <ul class="typedefs itemMembers">
359 <ul class="methods itemMembers">
361 <span class="subtitle">Methods</span>
363 <li data-name="LuCI.form.AbstractValue#append"><a href="LuCI.form.AbstractValue.html#append">append</a></li>
365 <li data-name="LuCI.form.AbstractValue#cbid"><a href="LuCI.form.AbstractValue.html#cbid">cbid</a></li>
367 <li data-name="LuCI.form.AbstractValue#cfgvalue"><a href="LuCI.form.AbstractValue.html#cfgvalue">cfgvalue</a></li>
369 <li data-name="LuCI.form.AbstractValue#depends"><a href="LuCI.form.AbstractValue.html#depends">depends</a></li>
371 <li data-name="LuCI.form.AbstractValue#formvalue"><a href="LuCI.form.AbstractValue.html#formvalue">formvalue</a></li>
373 <li data-name="LuCI.form.AbstractValue#getUIElement"><a href="LuCI.form.AbstractValue.html#getUIElement">getUIElement</a></li>
375 <li data-name="LuCI.form.AbstractValue#isActive"><a href="LuCI.form.AbstractValue.html#isActive">isActive</a></li>
377 <li data-name="LuCI.form.AbstractValue#isValid"><a href="LuCI.form.AbstractValue.html#isValid">isValid</a></li>
379 <li data-name="LuCI.form.AbstractValue#load"><a href="LuCI.form.AbstractValue.html#load">load</a></li>
381 <li data-name="LuCI.form.AbstractValue#parse"><a href="LuCI.form.AbstractValue.html#parse">parse</a></li>
383 <li data-name="LuCI.form.AbstractValue#remove"><a href="LuCI.form.AbstractValue.html#remove">remove</a></li>
385 <li data-name="LuCI.form.AbstractValue#render"><a href="LuCI.form.AbstractValue.html#render">render</a></li>
387 <li data-name="LuCI.form.AbstractValue#stripTags"><a href="LuCI.form.AbstractValue.html#stripTags">stripTags</a></li>
389 <li data-name="LuCI.form.AbstractValue#textvalue"><a href="LuCI.form.AbstractValue.html#textvalue">textvalue</a></li>
391 <li data-name="LuCI.form.AbstractValue#titleFn"><a href="LuCI.form.AbstractValue.html#titleFn">titleFn</a></li>
393 <li data-name="LuCI.form.AbstractValue#validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
395 <li data-name="LuCI.form.AbstractValue#write"><a href="LuCI.form.AbstractValue.html#write">write</a></li>
398 <ul class="events itemMembers">
403 <li class="item" data-name="LuCI.form.ButtonValue">
405 <a href="LuCI.form.ButtonValue.html">LuCI.form.ButtonValue</a>
408 <ul class="members itemMembers">
410 <span class="subtitle">Members</span>
412 <li data-name="LuCI.form.ButtonValue##inputstyle"><a href="LuCI.form.ButtonValue.html#inputstyle">inputstyle</a></li>
414 <li data-name="LuCI.form.ButtonValue##inputtitle"><a href="LuCI.form.ButtonValue.html#inputtitle">inputtitle</a></li>
416 <li data-name="LuCI.form.ButtonValue##onclick"><a href="LuCI.form.ButtonValue.html#onclick">onclick</a></li>
418 <li data-name="LuCI.form.ButtonValue#datatype"><a href="LuCI.form.ButtonValue.html#datatype">datatype</a></li>
420 <li data-name="LuCI.form.ButtonValue#default"><a href="LuCI.form.ButtonValue.html#default">default</a></li>
422 <li data-name="LuCI.form.ButtonValue#editable"><a href="LuCI.form.ButtonValue.html#editable">editable</a></li>
424 <li data-name="LuCI.form.ButtonValue#modalonly"><a href="LuCI.form.ButtonValue.html#modalonly">modalonly</a></li>
426 <li data-name="LuCI.form.ButtonValue#optional"><a href="LuCI.form.ButtonValue.html#optional">optional</a></li>
428 <li data-name="LuCI.form.ButtonValue#password"><a href="LuCI.form.ButtonValue.html#password">password</a></li>
430 <li data-name="LuCI.form.ButtonValue#placeholder"><a href="LuCI.form.ButtonValue.html#placeholder">placeholder</a></li>
432 <li data-name="LuCI.form.ButtonValue#readonly"><a href="LuCI.form.ButtonValue.html#readonly">readonly</a></li>
434 <li data-name="LuCI.form.ButtonValue#rmempty"><a href="LuCI.form.ButtonValue.html#rmempty">rmempty</a></li>
436 <li data-name="LuCI.form.ButtonValue#uciconfig"><a href="LuCI.form.ButtonValue.html#uciconfig">uciconfig</a></li>
438 <li data-name="LuCI.form.ButtonValue#ucioption"><a href="LuCI.form.ButtonValue.html#ucioption">ucioption</a></li>
440 <li data-name="LuCI.form.ButtonValue#ucisection"><a href="LuCI.form.ButtonValue.html#ucisection">ucisection</a></li>
442 <li data-name="LuCI.form.ButtonValue#validate"><a href="LuCI.form.ButtonValue.html#validate">validate</a></li>
444 <li data-name="LuCI.form.ButtonValue#width"><a href="LuCI.form.ButtonValue.html#width">width</a></li>
447 <ul class="typedefs itemMembers">
450 <ul class="typedefs itemMembers">
453 <ul class="methods itemMembers">
455 <span class="subtitle">Methods</span>
457 <li data-name="LuCI.form.ButtonValue#append"><a href="LuCI.form.ButtonValue.html#append">append</a></li>
459 <li data-name="LuCI.form.ButtonValue#cbid"><a href="LuCI.form.ButtonValue.html#cbid">cbid</a></li>
461 <li data-name="LuCI.form.ButtonValue#cfgvalue"><a href="LuCI.form.ButtonValue.html#cfgvalue">cfgvalue</a></li>
463 <li data-name="LuCI.form.ButtonValue#depends"><a href="LuCI.form.ButtonValue.html#depends">depends</a></li>
465 <li data-name="LuCI.form.ButtonValue#formvalue"><a href="LuCI.form.ButtonValue.html#formvalue">formvalue</a></li>
467 <li data-name="LuCI.form.ButtonValue#getUIElement"><a href="LuCI.form.ButtonValue.html#getUIElement">getUIElement</a></li>
469 <li data-name="LuCI.form.ButtonValue#isActive"><a href="LuCI.form.ButtonValue.html#isActive">isActive</a></li>
471 <li data-name="LuCI.form.ButtonValue#isValid"><a href="LuCI.form.ButtonValue.html#isValid">isValid</a></li>
473 <li data-name="LuCI.form.ButtonValue#load"><a href="LuCI.form.ButtonValue.html#load">load</a></li>
475 <li data-name="LuCI.form.ButtonValue#parse"><a href="LuCI.form.ButtonValue.html#parse">parse</a></li>
477 <li data-name="LuCI.form.ButtonValue#remove"><a href="LuCI.form.ButtonValue.html#remove">remove</a></li>
479 <li data-name="LuCI.form.ButtonValue#stripTags"><a href="LuCI.form.ButtonValue.html#stripTags">stripTags</a></li>
481 <li data-name="LuCI.form.ButtonValue#textvalue"><a href="LuCI.form.ButtonValue.html#textvalue">textvalue</a></li>
483 <li data-name="LuCI.form.ButtonValue#titleFn"><a href="LuCI.form.ButtonValue.html#titleFn">titleFn</a></li>
485 <li data-name="LuCI.form.ButtonValue#value"><a href="LuCI.form.ButtonValue.html#value">value</a></li>
487 <li data-name="LuCI.form.ButtonValue#write"><a href="LuCI.form.ButtonValue.html#write">write</a></li>
490 <ul class="events itemMembers">
495 <li class="item" data-name="LuCI.form.DummyValue">
497 <a href="LuCI.form.DummyValue.html">LuCI.form.DummyValue</a>
500 <ul class="members itemMembers">
502 <span class="subtitle">Members</span>
504 <li data-name="LuCI.form.DummyValue##href"><a href="LuCI.form.DummyValue.html#href">href</a></li>
506 <li data-name="LuCI.form.DummyValue##rawhtml"><a href="LuCI.form.DummyValue.html#rawhtml">rawhtml</a></li>
508 <li data-name="LuCI.form.DummyValue#datatype"><a href="LuCI.form.DummyValue.html#datatype">datatype</a></li>
510 <li data-name="LuCI.form.DummyValue#default"><a href="LuCI.form.DummyValue.html#default">default</a></li>
512 <li data-name="LuCI.form.DummyValue#editable"><a href="LuCI.form.DummyValue.html#editable">editable</a></li>
514 <li data-name="LuCI.form.DummyValue#modalonly"><a href="LuCI.form.DummyValue.html#modalonly">modalonly</a></li>
516 <li data-name="LuCI.form.DummyValue#optional"><a href="LuCI.form.DummyValue.html#optional">optional</a></li>
518 <li data-name="LuCI.form.DummyValue#password"><a href="LuCI.form.DummyValue.html#password">password</a></li>
520 <li data-name="LuCI.form.DummyValue#placeholder"><a href="LuCI.form.DummyValue.html#placeholder">placeholder</a></li>
522 <li data-name="LuCI.form.DummyValue#readonly"><a href="LuCI.form.DummyValue.html#readonly">readonly</a></li>
524 <li data-name="LuCI.form.DummyValue#rmempty"><a href="LuCI.form.DummyValue.html#rmempty">rmempty</a></li>
526 <li data-name="LuCI.form.DummyValue#uciconfig"><a href="LuCI.form.DummyValue.html#uciconfig">uciconfig</a></li>
528 <li data-name="LuCI.form.DummyValue#ucioption"><a href="LuCI.form.DummyValue.html#ucioption">ucioption</a></li>
530 <li data-name="LuCI.form.DummyValue#ucisection"><a href="LuCI.form.DummyValue.html#ucisection">ucisection</a></li>
532 <li data-name="LuCI.form.DummyValue#validate"><a href="LuCI.form.DummyValue.html#validate">validate</a></li>
534 <li data-name="LuCI.form.DummyValue#width"><a href="LuCI.form.DummyValue.html#width">width</a></li>
537 <ul class="typedefs itemMembers">
540 <ul class="typedefs itemMembers">
543 <ul class="methods itemMembers">
545 <span class="subtitle">Methods</span>
547 <li data-name="LuCI.form.DummyValue#append"><a href="LuCI.form.DummyValue.html#append">append</a></li>
549 <li data-name="LuCI.form.DummyValue#cbid"><a href="LuCI.form.DummyValue.html#cbid">cbid</a></li>
551 <li data-name="LuCI.form.DummyValue#cfgvalue"><a href="LuCI.form.DummyValue.html#cfgvalue">cfgvalue</a></li>
553 <li data-name="LuCI.form.DummyValue#depends"><a href="LuCI.form.DummyValue.html#depends">depends</a></li>
555 <li data-name="LuCI.form.DummyValue#formvalue"><a href="LuCI.form.DummyValue.html#formvalue">formvalue</a></li>
557 <li data-name="LuCI.form.DummyValue#getUIElement"><a href="LuCI.form.DummyValue.html#getUIElement">getUIElement</a></li>
559 <li data-name="LuCI.form.DummyValue#isActive"><a href="LuCI.form.DummyValue.html#isActive">isActive</a></li>
561 <li data-name="LuCI.form.DummyValue#isValid"><a href="LuCI.form.DummyValue.html#isValid">isValid</a></li>
563 <li data-name="LuCI.form.DummyValue#load"><a href="LuCI.form.DummyValue.html#load">load</a></li>
565 <li data-name="LuCI.form.DummyValue#parse"><a href="LuCI.form.DummyValue.html#parse">parse</a></li>
567 <li data-name="LuCI.form.DummyValue#remove"><a href="LuCI.form.DummyValue.html#remove">remove</a></li>
569 <li data-name="LuCI.form.DummyValue#stripTags"><a href="LuCI.form.DummyValue.html#stripTags">stripTags</a></li>
571 <li data-name="LuCI.form.DummyValue#textvalue"><a href="LuCI.form.DummyValue.html#textvalue">textvalue</a></li>
573 <li data-name="LuCI.form.DummyValue#titleFn"><a href="LuCI.form.DummyValue.html#titleFn">titleFn</a></li>
575 <li data-name="LuCI.form.DummyValue#value"><a href="LuCI.form.DummyValue.html#value">value</a></li>
577 <li data-name="LuCI.form.DummyValue#write"><a href="LuCI.form.DummyValue.html#write">write</a></li>
580 <ul class="events itemMembers">
585 <li class="item" data-name="LuCI.form.DynamicList">
587 <a href="LuCI.form.DynamicList.html">LuCI.form.DynamicList</a>
590 <ul class="members itemMembers">
592 <span class="subtitle">Members</span>
594 <li data-name="LuCI.form.DynamicList#datatype"><a href="LuCI.form.DynamicList.html#datatype">datatype</a></li>
596 <li data-name="LuCI.form.DynamicList#default"><a href="LuCI.form.DynamicList.html#default">default</a></li>
598 <li data-name="LuCI.form.DynamicList#editable"><a href="LuCI.form.DynamicList.html#editable">editable</a></li>
600 <li data-name="LuCI.form.DynamicList#modalonly"><a href="LuCI.form.DynamicList.html#modalonly">modalonly</a></li>
602 <li data-name="LuCI.form.DynamicList#optional"><a href="LuCI.form.DynamicList.html#optional">optional</a></li>
604 <li data-name="LuCI.form.DynamicList#password"><a href="LuCI.form.DynamicList.html#password">password</a></li>
606 <li data-name="LuCI.form.DynamicList#placeholder"><a href="LuCI.form.DynamicList.html#placeholder">placeholder</a></li>
608 <li data-name="LuCI.form.DynamicList#readonly"><a href="LuCI.form.DynamicList.html#readonly">readonly</a></li>
610 <li data-name="LuCI.form.DynamicList#rmempty"><a href="LuCI.form.DynamicList.html#rmempty">rmempty</a></li>
612 <li data-name="LuCI.form.DynamicList#uciconfig"><a href="LuCI.form.DynamicList.html#uciconfig">uciconfig</a></li>
614 <li data-name="LuCI.form.DynamicList#ucioption"><a href="LuCI.form.DynamicList.html#ucioption">ucioption</a></li>
616 <li data-name="LuCI.form.DynamicList#ucisection"><a href="LuCI.form.DynamicList.html#ucisection">ucisection</a></li>
618 <li data-name="LuCI.form.DynamicList#validate"><a href="LuCI.form.DynamicList.html#validate">validate</a></li>
620 <li data-name="LuCI.form.DynamicList#width"><a href="LuCI.form.DynamicList.html#width">width</a></li>
623 <ul class="typedefs itemMembers">
626 <ul class="typedefs itemMembers">
629 <ul class="methods itemMembers">
631 <span class="subtitle">Methods</span>
633 <li data-name="LuCI.form.DynamicList#append"><a href="LuCI.form.DynamicList.html#append">append</a></li>
635 <li data-name="LuCI.form.DynamicList#cbid"><a href="LuCI.form.DynamicList.html#cbid">cbid</a></li>
637 <li data-name="LuCI.form.DynamicList#cfgvalue"><a href="LuCI.form.DynamicList.html#cfgvalue">cfgvalue</a></li>
639 <li data-name="LuCI.form.DynamicList#depends"><a href="LuCI.form.DynamicList.html#depends">depends</a></li>
641 <li data-name="LuCI.form.DynamicList#formvalue"><a href="LuCI.form.DynamicList.html#formvalue">formvalue</a></li>
643 <li data-name="LuCI.form.DynamicList#getUIElement"><a href="LuCI.form.DynamicList.html#getUIElement">getUIElement</a></li>
645 <li data-name="LuCI.form.DynamicList#isActive"><a href="LuCI.form.DynamicList.html#isActive">isActive</a></li>
647 <li data-name="LuCI.form.DynamicList#isValid"><a href="LuCI.form.DynamicList.html#isValid">isValid</a></li>
649 <li data-name="LuCI.form.DynamicList#load"><a href="LuCI.form.DynamicList.html#load">load</a></li>
651 <li data-name="LuCI.form.DynamicList#parse"><a href="LuCI.form.DynamicList.html#parse">parse</a></li>
653 <li data-name="LuCI.form.DynamicList#remove"><a href="LuCI.form.DynamicList.html#remove">remove</a></li>
655 <li data-name="LuCI.form.DynamicList#stripTags"><a href="LuCI.form.DynamicList.html#stripTags">stripTags</a></li>
657 <li data-name="LuCI.form.DynamicList#textvalue"><a href="LuCI.form.DynamicList.html#textvalue">textvalue</a></li>
659 <li data-name="LuCI.form.DynamicList#titleFn"><a href="LuCI.form.DynamicList.html#titleFn">titleFn</a></li>
661 <li data-name="LuCI.form.DynamicList#value"><a href="LuCI.form.DynamicList.html#value">value</a></li>
663 <li data-name="LuCI.form.DynamicList#write"><a href="LuCI.form.DynamicList.html#write">write</a></li>
666 <ul class="events itemMembers">
671 <li class="item" data-name="LuCI.form.FileUpload">
673 <a href="LuCI.form.FileUpload.html">LuCI.form.FileUpload</a>
676 <ul class="members itemMembers">
678 <span class="subtitle">Members</span>
680 <li data-name="LuCI.form.FileUpload##enable_remove"><a href="LuCI.form.FileUpload.html#enable_remove">enable_remove</a></li>
682 <li data-name="LuCI.form.FileUpload##enable_upload"><a href="LuCI.form.FileUpload.html#enable_upload">enable_upload</a></li>
684 <li data-name="LuCI.form.FileUpload##root_directory"><a href="LuCI.form.FileUpload.html#root_directory">root_directory</a></li>
686 <li data-name="LuCI.form.FileUpload##show_hidden"><a href="LuCI.form.FileUpload.html#show_hidden">show_hidden</a></li>
688 <li data-name="LuCI.form.FileUpload#datatype"><a href="LuCI.form.FileUpload.html#datatype">datatype</a></li>
690 <li data-name="LuCI.form.FileUpload#default"><a href="LuCI.form.FileUpload.html#default">default</a></li>
692 <li data-name="LuCI.form.FileUpload#editable"><a href="LuCI.form.FileUpload.html#editable">editable</a></li>
694 <li data-name="LuCI.form.FileUpload#modalonly"><a href="LuCI.form.FileUpload.html#modalonly">modalonly</a></li>
696 <li data-name="LuCI.form.FileUpload#optional"><a href="LuCI.form.FileUpload.html#optional">optional</a></li>
698 <li data-name="LuCI.form.FileUpload#password"><a href="LuCI.form.FileUpload.html#password">password</a></li>
700 <li data-name="LuCI.form.FileUpload#placeholder"><a href="LuCI.form.FileUpload.html#placeholder">placeholder</a></li>
702 <li data-name="LuCI.form.FileUpload#readonly"><a href="LuCI.form.FileUpload.html#readonly">readonly</a></li>
704 <li data-name="LuCI.form.FileUpload#rmempty"><a href="LuCI.form.FileUpload.html#rmempty">rmempty</a></li>
706 <li data-name="LuCI.form.FileUpload#uciconfig"><a href="LuCI.form.FileUpload.html#uciconfig">uciconfig</a></li>
708 <li data-name="LuCI.form.FileUpload#ucioption"><a href="LuCI.form.FileUpload.html#ucioption">ucioption</a></li>
710 <li data-name="LuCI.form.FileUpload#ucisection"><a href="LuCI.form.FileUpload.html#ucisection">ucisection</a></li>
712 <li data-name="LuCI.form.FileUpload#validate"><a href="LuCI.form.FileUpload.html#validate">validate</a></li>
714 <li data-name="LuCI.form.FileUpload#width"><a href="LuCI.form.FileUpload.html#width">width</a></li>
717 <ul class="typedefs itemMembers">
720 <ul class="typedefs itemMembers">
723 <ul class="methods itemMembers">
725 <span class="subtitle">Methods</span>
727 <li data-name="LuCI.form.FileUpload#append"><a href="LuCI.form.FileUpload.html#append">append</a></li>
729 <li data-name="LuCI.form.FileUpload#cbid"><a href="LuCI.form.FileUpload.html#cbid">cbid</a></li>
731 <li data-name="LuCI.form.FileUpload#cfgvalue"><a href="LuCI.form.FileUpload.html#cfgvalue">cfgvalue</a></li>
733 <li data-name="LuCI.form.FileUpload#depends"><a href="LuCI.form.FileUpload.html#depends">depends</a></li>
735 <li data-name="LuCI.form.FileUpload#formvalue"><a href="LuCI.form.FileUpload.html#formvalue">formvalue</a></li>
737 <li data-name="LuCI.form.FileUpload#getUIElement"><a href="LuCI.form.FileUpload.html#getUIElement">getUIElement</a></li>
739 <li data-name="LuCI.form.FileUpload#isActive"><a href="LuCI.form.FileUpload.html#isActive">isActive</a></li>
741 <li data-name="LuCI.form.FileUpload#isValid"><a href="LuCI.form.FileUpload.html#isValid">isValid</a></li>
743 <li data-name="LuCI.form.FileUpload#load"><a href="LuCI.form.FileUpload.html#load">load</a></li>
745 <li data-name="LuCI.form.FileUpload#parse"><a href="LuCI.form.FileUpload.html#parse">parse</a></li>
747 <li data-name="LuCI.form.FileUpload#remove"><a href="LuCI.form.FileUpload.html#remove">remove</a></li>
749 <li data-name="LuCI.form.FileUpload#stripTags"><a href="LuCI.form.FileUpload.html#stripTags">stripTags</a></li>
751 <li data-name="LuCI.form.FileUpload#textvalue"><a href="LuCI.form.FileUpload.html#textvalue">textvalue</a></li>
753 <li data-name="LuCI.form.FileUpload#titleFn"><a href="LuCI.form.FileUpload.html#titleFn">titleFn</a></li>
755 <li data-name="LuCI.form.FileUpload#value"><a href="LuCI.form.FileUpload.html#value">value</a></li>
757 <li data-name="LuCI.form.FileUpload#write"><a href="LuCI.form.FileUpload.html#write">write</a></li>
760 <ul class="events itemMembers">
765 <li class="item" data-name="LuCI.form.FlagValue">
767 <a href="LuCI.form.FlagValue.html">LuCI.form.FlagValue</a>
770 <ul class="members itemMembers">
772 <span class="subtitle">Members</span>
774 <li data-name="LuCI.form.FlagValue##disabled"><a href="LuCI.form.FlagValue.html#disabled">disabled</a></li>
776 <li data-name="LuCI.form.FlagValue##enabled"><a href="LuCI.form.FlagValue.html#enabled">enabled</a></li>
778 <li data-name="LuCI.form.FlagValue#datatype"><a href="LuCI.form.FlagValue.html#datatype">datatype</a></li>
780 <li data-name="LuCI.form.FlagValue#default"><a href="LuCI.form.FlagValue.html#default">default</a></li>
782 <li data-name="LuCI.form.FlagValue#editable"><a href="LuCI.form.FlagValue.html#editable">editable</a></li>
784 <li data-name="LuCI.form.FlagValue#modalonly"><a href="LuCI.form.FlagValue.html#modalonly">modalonly</a></li>
786 <li data-name="LuCI.form.FlagValue#optional"><a href="LuCI.form.FlagValue.html#optional">optional</a></li>
788 <li data-name="LuCI.form.FlagValue#password"><a href="LuCI.form.FlagValue.html#password">password</a></li>
790 <li data-name="LuCI.form.FlagValue#placeholder"><a href="LuCI.form.FlagValue.html#placeholder">placeholder</a></li>
792 <li data-name="LuCI.form.FlagValue#readonly"><a href="LuCI.form.FlagValue.html#readonly">readonly</a></li>
794 <li data-name="LuCI.form.FlagValue#rmempty"><a href="LuCI.form.FlagValue.html#rmempty">rmempty</a></li>
796 <li data-name="LuCI.form.FlagValue#uciconfig"><a href="LuCI.form.FlagValue.html#uciconfig">uciconfig</a></li>
798 <li data-name="LuCI.form.FlagValue#ucioption"><a href="LuCI.form.FlagValue.html#ucioption">ucioption</a></li>
800 <li data-name="LuCI.form.FlagValue#ucisection"><a href="LuCI.form.FlagValue.html#ucisection">ucisection</a></li>
802 <li data-name="LuCI.form.FlagValue#validate"><a href="LuCI.form.FlagValue.html#validate">validate</a></li>
804 <li data-name="LuCI.form.FlagValue#width"><a href="LuCI.form.FlagValue.html#width">width</a></li>
807 <ul class="typedefs itemMembers">
810 <ul class="typedefs itemMembers">
813 <ul class="methods itemMembers">
815 <span class="subtitle">Methods</span>
817 <li data-name="LuCI.form.FlagValue#append"><a href="LuCI.form.FlagValue.html#append">append</a></li>
819 <li data-name="LuCI.form.FlagValue#cbid"><a href="LuCI.form.FlagValue.html#cbid">cbid</a></li>
821 <li data-name="LuCI.form.FlagValue#cfgvalue"><a href="LuCI.form.FlagValue.html#cfgvalue">cfgvalue</a></li>
823 <li data-name="LuCI.form.FlagValue#depends"><a href="LuCI.form.FlagValue.html#depends">depends</a></li>
825 <li data-name="LuCI.form.FlagValue#formvalue"><a href="LuCI.form.FlagValue.html#formvalue">formvalue</a></li>
827 <li data-name="LuCI.form.FlagValue#getUIElement"><a href="LuCI.form.FlagValue.html#getUIElement">getUIElement</a></li>
829 <li data-name="LuCI.form.FlagValue#isActive"><a href="LuCI.form.FlagValue.html#isActive">isActive</a></li>
831 <li data-name="LuCI.form.FlagValue#isValid"><a href="LuCI.form.FlagValue.html#isValid">isValid</a></li>
833 <li data-name="LuCI.form.FlagValue#load"><a href="LuCI.form.FlagValue.html#load">load</a></li>
835 <li data-name="LuCI.form.FlagValue#parse"><a href="LuCI.form.FlagValue.html#parse">parse</a></li>
837 <li data-name="LuCI.form.FlagValue#remove"><a href="LuCI.form.FlagValue.html#remove">remove</a></li>
839 <li data-name="LuCI.form.FlagValue#stripTags"><a href="LuCI.form.FlagValue.html#stripTags">stripTags</a></li>
841 <li data-name="LuCI.form.FlagValue#textvalue"><a href="LuCI.form.FlagValue.html#textvalue">textvalue</a></li>
843 <li data-name="LuCI.form.FlagValue#titleFn"><a href="LuCI.form.FlagValue.html#titleFn">titleFn</a></li>
845 <li data-name="LuCI.form.FlagValue#value"><a href="LuCI.form.FlagValue.html#value">value</a></li>
847 <li data-name="LuCI.form.FlagValue#write"><a href="LuCI.form.FlagValue.html#write">write</a></li>
850 <ul class="events itemMembers">
855 <li class="item" data-name="LuCI.form.GridSection">
857 <a href="LuCI.form.GridSection.html">LuCI.form.GridSection</a>
860 <ul class="members itemMembers">
862 <span class="subtitle">Members</span>
864 <li data-name="LuCI.form.GridSection#addbtntitle"><a href="LuCI.form.GridSection.html#addbtntitle">addbtntitle</a></li>
866 <li data-name="LuCI.form.GridSection#addremove"><a href="LuCI.form.GridSection.html#addremove">addremove</a></li>
868 <li data-name="LuCI.form.GridSection#anonymous"><a href="LuCI.form.GridSection.html#anonymous">anonymous</a></li>
870 <li data-name="LuCI.form.GridSection#extedit"><a href="LuCI.form.GridSection.html#extedit">extedit</a></li>
872 <li data-name="LuCI.form.GridSection#max_cols"><a href="LuCI.form.GridSection.html#max_cols">max_cols</a></li>
874 <li data-name="LuCI.form.GridSection#modaltitle"><a href="LuCI.form.GridSection.html#modaltitle">modaltitle</a></li>
876 <li data-name="LuCI.form.GridSection#parentoption"><a href="LuCI.form.GridSection.html#parentoption">parentoption</a></li>
878 <li data-name="LuCI.form.GridSection#rowcolors"><a href="LuCI.form.GridSection.html#rowcolors">rowcolors</a></li>
880 <li data-name="LuCI.form.GridSection#sectiontitle"><a href="LuCI.form.GridSection.html#sectiontitle">sectiontitle</a></li>
882 <li data-name="LuCI.form.GridSection#sortable"><a href="LuCI.form.GridSection.html#sortable">sortable</a></li>
884 <li data-name="LuCI.form.GridSection#tabbed"><a href="LuCI.form.GridSection.html#tabbed">tabbed</a></li>
886 <li data-name="LuCI.form.GridSection#uciconfig"><a href="LuCI.form.GridSection.html#uciconfig">uciconfig</a></li>
889 <ul class="typedefs itemMembers">
892 <ul class="typedefs itemMembers">
895 <ul class="methods itemMembers">
897 <span class="subtitle">Methods</span>
899 <li data-name="LuCI.form.GridSection#addModalOptions"><a href="LuCI.form.GridSection.html#addModalOptions">addModalOptions</a></li>
901 <li data-name="LuCI.form.GridSection#append"><a href="LuCI.form.GridSection.html#append">append</a></li>
903 <li data-name="LuCI.form.GridSection#filter"><a href="LuCI.form.GridSection.html#filter">filter</a></li>
905 <li data-name="LuCI.form.GridSection#load"><a href="LuCI.form.GridSection.html#load">load</a></li>
907 <li data-name="LuCI.form.GridSection#option"><a href="LuCI.form.GridSection.html#option">option</a></li>
909 <li data-name="LuCI.form.GridSection#parse"><a href="LuCI.form.GridSection.html#parse">parse</a></li>
911 <li data-name="LuCI.form.GridSection#stripTags"><a href="LuCI.form.GridSection.html#stripTags">stripTags</a></li>
913 <li data-name="LuCI.form.GridSection#tab"><a href="LuCI.form.GridSection.html#tab">tab</a></li>
915 <li data-name="LuCI.form.GridSection#taboption"><a href="LuCI.form.GridSection.html#taboption">taboption</a></li>
917 <li data-name="LuCI.form.GridSection#titleFn"><a href="LuCI.form.GridSection.html#titleFn">titleFn</a></li>
920 <ul class="events itemMembers">
925 <li class="item" data-name="LuCI.form.HiddenValue">
927 <a href="LuCI.form.HiddenValue.html">LuCI.form.HiddenValue</a>
930 <ul class="members itemMembers">
932 <span class="subtitle">Members</span>
934 <li data-name="LuCI.form.HiddenValue#datatype"><a href="LuCI.form.HiddenValue.html#datatype">datatype</a></li>
936 <li data-name="LuCI.form.HiddenValue#default"><a href="LuCI.form.HiddenValue.html#default">default</a></li>
938 <li data-name="LuCI.form.HiddenValue#editable"><a href="LuCI.form.HiddenValue.html#editable">editable</a></li>
940 <li data-name="LuCI.form.HiddenValue#modalonly"><a href="LuCI.form.HiddenValue.html#modalonly">modalonly</a></li>
942 <li data-name="LuCI.form.HiddenValue#optional"><a href="LuCI.form.HiddenValue.html#optional">optional</a></li>
944 <li data-name="LuCI.form.HiddenValue#password"><a href="LuCI.form.HiddenValue.html#password">password</a></li>
946 <li data-name="LuCI.form.HiddenValue#placeholder"><a href="LuCI.form.HiddenValue.html#placeholder">placeholder</a></li>
948 <li data-name="LuCI.form.HiddenValue#readonly"><a href="LuCI.form.HiddenValue.html#readonly">readonly</a></li>
950 <li data-name="LuCI.form.HiddenValue#rmempty"><a href="LuCI.form.HiddenValue.html#rmempty">rmempty</a></li>
952 <li data-name="LuCI.form.HiddenValue#uciconfig"><a href="LuCI.form.HiddenValue.html#uciconfig">uciconfig</a></li>
954 <li data-name="LuCI.form.HiddenValue#ucioption"><a href="LuCI.form.HiddenValue.html#ucioption">ucioption</a></li>
956 <li data-name="LuCI.form.HiddenValue#ucisection"><a href="LuCI.form.HiddenValue.html#ucisection">ucisection</a></li>
958 <li data-name="LuCI.form.HiddenValue#validate"><a href="LuCI.form.HiddenValue.html#validate">validate</a></li>
960 <li data-name="LuCI.form.HiddenValue#width"><a href="LuCI.form.HiddenValue.html#width">width</a></li>
963 <ul class="typedefs itemMembers">
966 <ul class="typedefs itemMembers">
969 <ul class="methods itemMembers">
971 <span class="subtitle">Methods</span>
973 <li data-name="LuCI.form.HiddenValue#append"><a href="LuCI.form.HiddenValue.html#append">append</a></li>
975 <li data-name="LuCI.form.HiddenValue#cbid"><a href="LuCI.form.HiddenValue.html#cbid">cbid</a></li>
977 <li data-name="LuCI.form.HiddenValue#cfgvalue"><a href="LuCI.form.HiddenValue.html#cfgvalue">cfgvalue</a></li>
979 <li data-name="LuCI.form.HiddenValue#depends"><a href="LuCI.form.HiddenValue.html#depends">depends</a></li>
981 <li data-name="LuCI.form.HiddenValue#formvalue"><a href="LuCI.form.HiddenValue.html#formvalue">formvalue</a></li>
983 <li data-name="LuCI.form.HiddenValue#getUIElement"><a href="LuCI.form.HiddenValue.html#getUIElement">getUIElement</a></li>
985 <li data-name="LuCI.form.HiddenValue#isActive"><a href="LuCI.form.HiddenValue.html#isActive">isActive</a></li>
987 <li data-name="LuCI.form.HiddenValue#isValid"><a href="LuCI.form.HiddenValue.html#isValid">isValid</a></li>
989 <li data-name="LuCI.form.HiddenValue#load"><a href="LuCI.form.HiddenValue.html#load">load</a></li>
991 <li data-name="LuCI.form.HiddenValue#parse"><a href="LuCI.form.HiddenValue.html#parse">parse</a></li>
993 <li data-name="LuCI.form.HiddenValue#remove"><a href="LuCI.form.HiddenValue.html#remove">remove</a></li>
995 <li data-name="LuCI.form.HiddenValue#stripTags"><a href="LuCI.form.HiddenValue.html#stripTags">stripTags</a></li>
997 <li data-name="LuCI.form.HiddenValue#textvalue"><a href="LuCI.form.HiddenValue.html#textvalue">textvalue</a></li>
999 <li data-name="LuCI.form.HiddenValue#titleFn"><a href="LuCI.form.HiddenValue.html#titleFn">titleFn</a></li>
1001 <li data-name="LuCI.form.HiddenValue#value"><a href="LuCI.form.HiddenValue.html#value">value</a></li>
1003 <li data-name="LuCI.form.HiddenValue#write"><a href="LuCI.form.HiddenValue.html#write">write</a></li>
1006 <ul class="events itemMembers">
1011 <li class="item" data-name="LuCI.form.JSONMap">
1012 <span class="title">
1013 <a href="LuCI.form.JSONMap.html">LuCI.form.JSONMap</a>
1016 <ul class="members itemMembers">
1018 <span class="subtitle">Members</span>
1020 <li data-name="LuCI.form.JSONMap#readonly"><a href="LuCI.form.JSONMap.html#readonly">readonly</a></li>
1023 <ul class="typedefs itemMembers">
1026 <ul class="typedefs itemMembers">
1029 <ul class="methods itemMembers">
1031 <span class="subtitle">Methods</span>
1033 <li data-name="LuCI.form.JSONMap#append"><a href="LuCI.form.JSONMap.html#append">append</a></li>
1035 <li data-name="LuCI.form.JSONMap#chain"><a href="LuCI.form.JSONMap.html#chain">chain</a></li>
1037 <li data-name="LuCI.form.JSONMap#findElement"><a href="LuCI.form.JSONMap.html#findElement">findElement</a></li>
1039 <li data-name="LuCI.form.JSONMap#findElements"><a href="LuCI.form.JSONMap.html#findElements">findElements</a></li>
1041 <li data-name="LuCI.form.JSONMap#load"><a href="LuCI.form.JSONMap.html#load">load</a></li>
1043 <li data-name="LuCI.form.JSONMap#lookupOption"><a href="LuCI.form.JSONMap.html#lookupOption">lookupOption</a></li>
1045 <li data-name="LuCI.form.JSONMap#parse"><a href="LuCI.form.JSONMap.html#parse">parse</a></li>
1047 <li data-name="LuCI.form.JSONMap#render"><a href="LuCI.form.JSONMap.html#render">render</a></li>
1049 <li data-name="LuCI.form.JSONMap#reset"><a href="LuCI.form.JSONMap.html#reset">reset</a></li>
1051 <li data-name="LuCI.form.JSONMap#save"><a href="LuCI.form.JSONMap.html#save">save</a></li>
1053 <li data-name="LuCI.form.JSONMap#section"><a href="LuCI.form.JSONMap.html#section">section</a></li>
1055 <li data-name="LuCI.form.JSONMap#stripTags"><a href="LuCI.form.JSONMap.html#stripTags">stripTags</a></li>
1057 <li data-name="LuCI.form.JSONMap#titleFn"><a href="LuCI.form.JSONMap.html#titleFn">titleFn</a></li>
1060 <ul class="events itemMembers">
1065 <li class="item" data-name="LuCI.form.ListValue">
1066 <span class="title">
1067 <a href="LuCI.form.ListValue.html">LuCI.form.ListValue</a>
1070 <ul class="members itemMembers">
1072 <span class="subtitle">Members</span>
1074 <li data-name="LuCI.form.ListValue##size"><a href="LuCI.form.ListValue.html#size">size</a></li>
1076 <li data-name="LuCI.form.ListValue#datatype"><a href="LuCI.form.ListValue.html#datatype">datatype</a></li>
1078 <li data-name="LuCI.form.ListValue#default"><a href="LuCI.form.ListValue.html#default">default</a></li>
1080 <li data-name="LuCI.form.ListValue#editable"><a href="LuCI.form.ListValue.html#editable">editable</a></li>
1082 <li data-name="LuCI.form.ListValue#modalonly"><a href="LuCI.form.ListValue.html#modalonly">modalonly</a></li>
1084 <li data-name="LuCI.form.ListValue#optional"><a href="LuCI.form.ListValue.html#optional">optional</a></li>
1086 <li data-name="LuCI.form.ListValue#password"><a href="LuCI.form.ListValue.html#password">password</a></li>
1088 <li data-name="LuCI.form.ListValue#placeholder"><a href="LuCI.form.ListValue.html#placeholder">placeholder</a></li>
1090 <li data-name="LuCI.form.ListValue#readonly"><a href="LuCI.form.ListValue.html#readonly">readonly</a></li>
1092 <li data-name="LuCI.form.ListValue#rmempty"><a href="LuCI.form.ListValue.html#rmempty">rmempty</a></li>
1094 <li data-name="LuCI.form.ListValue#uciconfig"><a href="LuCI.form.ListValue.html#uciconfig">uciconfig</a></li>
1096 <li data-name="LuCI.form.ListValue#ucioption"><a href="LuCI.form.ListValue.html#ucioption">ucioption</a></li>
1098 <li data-name="LuCI.form.ListValue#ucisection"><a href="LuCI.form.ListValue.html#ucisection">ucisection</a></li>
1100 <li data-name="LuCI.form.ListValue#validate"><a href="LuCI.form.ListValue.html#validate">validate</a></li>
1102 <li data-name="LuCI.form.ListValue#width"><a href="LuCI.form.ListValue.html#width">width</a></li>
1105 <ul class="typedefs itemMembers">
1108 <ul class="typedefs itemMembers">
1111 <ul class="methods itemMembers">
1113 <span class="subtitle">Methods</span>
1115 <li data-name="LuCI.form.ListValue#append"><a href="LuCI.form.ListValue.html#append">append</a></li>
1117 <li data-name="LuCI.form.ListValue#cbid"><a href="LuCI.form.ListValue.html#cbid">cbid</a></li>
1119 <li data-name="LuCI.form.ListValue#cfgvalue"><a href="LuCI.form.ListValue.html#cfgvalue">cfgvalue</a></li>
1121 <li data-name="LuCI.form.ListValue#depends"><a href="LuCI.form.ListValue.html#depends">depends</a></li>
1123 <li data-name="LuCI.form.ListValue#formvalue"><a href="LuCI.form.ListValue.html#formvalue">formvalue</a></li>
1125 <li data-name="LuCI.form.ListValue#getUIElement"><a href="LuCI.form.ListValue.html#getUIElement">getUIElement</a></li>
1127 <li data-name="LuCI.form.ListValue#isActive"><a href="LuCI.form.ListValue.html#isActive">isActive</a></li>
1129 <li data-name="LuCI.form.ListValue#isValid"><a href="LuCI.form.ListValue.html#isValid">isValid</a></li>
1131 <li data-name="LuCI.form.ListValue#load"><a href="LuCI.form.ListValue.html#load">load</a></li>
1133 <li data-name="LuCI.form.ListValue#parse"><a href="LuCI.form.ListValue.html#parse">parse</a></li>
1135 <li data-name="LuCI.form.ListValue#remove"><a href="LuCI.form.ListValue.html#remove">remove</a></li>
1137 <li data-name="LuCI.form.ListValue#stripTags"><a href="LuCI.form.ListValue.html#stripTags">stripTags</a></li>
1139 <li data-name="LuCI.form.ListValue#textvalue"><a href="LuCI.form.ListValue.html#textvalue">textvalue</a></li>
1141 <li data-name="LuCI.form.ListValue#titleFn"><a href="LuCI.form.ListValue.html#titleFn">titleFn</a></li>
1143 <li data-name="LuCI.form.ListValue#value"><a href="LuCI.form.ListValue.html#value">value</a></li>
1145 <li data-name="LuCI.form.ListValue#write"><a href="LuCI.form.ListValue.html#write">write</a></li>
1148 <ul class="events itemMembers">
1153 <li class="item" data-name="LuCI.form.Map">
1154 <span class="title">
1155 <a href="LuCI.form.Map.html">LuCI.form.Map</a>
1158 <ul class="members itemMembers">
1160 <span class="subtitle">Members</span>
1162 <li data-name="LuCI.form.Map##readonly"><a href="LuCI.form.Map.html#readonly">readonly</a></li>
1165 <ul class="typedefs itemMembers">
1168 <ul class="typedefs itemMembers">
1171 <ul class="methods itemMembers">
1173 <span class="subtitle">Methods</span>
1175 <li data-name="LuCI.form.Map#append"><a href="LuCI.form.Map.html#append">append</a></li>
1177 <li data-name="LuCI.form.Map#chain"><a href="LuCI.form.Map.html#chain">chain</a></li>
1179 <li data-name="LuCI.form.Map#findElement"><a href="LuCI.form.Map.html#findElement">findElement</a></li>
1181 <li data-name="LuCI.form.Map#findElements"><a href="LuCI.form.Map.html#findElements">findElements</a></li>
1183 <li data-name="LuCI.form.Map#load"><a href="LuCI.form.Map.html#load">load</a></li>
1185 <li data-name="LuCI.form.Map#lookupOption"><a href="LuCI.form.Map.html#lookupOption">lookupOption</a></li>
1187 <li data-name="LuCI.form.Map#parse"><a href="LuCI.form.Map.html#parse">parse</a></li>
1189 <li data-name="LuCI.form.Map#render"><a href="LuCI.form.Map.html#render">render</a></li>
1191 <li data-name="LuCI.form.Map#reset"><a href="LuCI.form.Map.html#reset">reset</a></li>
1193 <li data-name="LuCI.form.Map#save"><a href="LuCI.form.Map.html#save">save</a></li>
1195 <li data-name="LuCI.form.Map#section"><a href="LuCI.form.Map.html#section">section</a></li>
1197 <li data-name="LuCI.form.Map#stripTags"><a href="LuCI.form.Map.html#stripTags">stripTags</a></li>
1199 <li data-name="LuCI.form.Map#titleFn"><a href="LuCI.form.Map.html#titleFn">titleFn</a></li>
1202 <ul class="events itemMembers">
1207 <li class="item" data-name="LuCI.form.MultiValue">
1208 <span class="title">
1209 <a href="LuCI.form.MultiValue.html">LuCI.form.MultiValue</a>
1212 <ul class="members itemMembers">
1214 <span class="subtitle">Members</span>
1216 <li data-name="LuCI.form.MultiValue##display_size"><a href="LuCI.form.MultiValue.html#display_size">display_size</a></li>
1218 <li data-name="LuCI.form.MultiValue##dropdown_size"><a href="LuCI.form.MultiValue.html#dropdown_size">dropdown_size</a></li>
1220 <li data-name="LuCI.form.MultiValue#datatype"><a href="LuCI.form.MultiValue.html#datatype">datatype</a></li>
1222 <li data-name="LuCI.form.MultiValue#default"><a href="LuCI.form.MultiValue.html#default">default</a></li>
1224 <li data-name="LuCI.form.MultiValue#editable"><a href="LuCI.form.MultiValue.html#editable">editable</a></li>
1226 <li data-name="LuCI.form.MultiValue#modalonly"><a href="LuCI.form.MultiValue.html#modalonly">modalonly</a></li>
1228 <li data-name="LuCI.form.MultiValue#optional"><a href="LuCI.form.MultiValue.html#optional">optional</a></li>
1230 <li data-name="LuCI.form.MultiValue#password"><a href="LuCI.form.MultiValue.html#password">password</a></li>
1232 <li data-name="LuCI.form.MultiValue#placeholder"><a href="LuCI.form.MultiValue.html#placeholder">placeholder</a></li>
1234 <li data-name="LuCI.form.MultiValue#readonly"><a href="LuCI.form.MultiValue.html#readonly">readonly</a></li>
1236 <li data-name="LuCI.form.MultiValue#rmempty"><a href="LuCI.form.MultiValue.html#rmempty">rmempty</a></li>
1238 <li data-name="LuCI.form.MultiValue#uciconfig"><a href="LuCI.form.MultiValue.html#uciconfig">uciconfig</a></li>
1240 <li data-name="LuCI.form.MultiValue#ucioption"><a href="LuCI.form.MultiValue.html#ucioption">ucioption</a></li>
1242 <li data-name="LuCI.form.MultiValue#ucisection"><a href="LuCI.form.MultiValue.html#ucisection">ucisection</a></li>
1244 <li data-name="LuCI.form.MultiValue#validate"><a href="LuCI.form.MultiValue.html#validate">validate</a></li>
1246 <li data-name="LuCI.form.MultiValue#width"><a href="LuCI.form.MultiValue.html#width">width</a></li>
1249 <ul class="typedefs itemMembers">
1252 <ul class="typedefs itemMembers">
1255 <ul class="methods itemMembers">
1257 <span class="subtitle">Methods</span>
1259 <li data-name="LuCI.form.MultiValue#append"><a href="LuCI.form.MultiValue.html#append">append</a></li>
1261 <li data-name="LuCI.form.MultiValue#cbid"><a href="LuCI.form.MultiValue.html#cbid">cbid</a></li>
1263 <li data-name="LuCI.form.MultiValue#cfgvalue"><a href="LuCI.form.MultiValue.html#cfgvalue">cfgvalue</a></li>
1265 <li data-name="LuCI.form.MultiValue#depends"><a href="LuCI.form.MultiValue.html#depends">depends</a></li>
1267 <li data-name="LuCI.form.MultiValue#formvalue"><a href="LuCI.form.MultiValue.html#formvalue">formvalue</a></li>
1269 <li data-name="LuCI.form.MultiValue#getUIElement"><a href="LuCI.form.MultiValue.html#getUIElement">getUIElement</a></li>
1271 <li data-name="LuCI.form.MultiValue#isActive"><a href="LuCI.form.MultiValue.html#isActive">isActive</a></li>
1273 <li data-name="LuCI.form.MultiValue#isValid"><a href="LuCI.form.MultiValue.html#isValid">isValid</a></li>
1275 <li data-name="LuCI.form.MultiValue#load"><a href="LuCI.form.MultiValue.html#load">load</a></li>
1277 <li data-name="LuCI.form.MultiValue#parse"><a href="LuCI.form.MultiValue.html#parse">parse</a></li>
1279 <li data-name="LuCI.form.MultiValue#remove"><a href="LuCI.form.MultiValue.html#remove">remove</a></li>
1281 <li data-name="LuCI.form.MultiValue#stripTags"><a href="LuCI.form.MultiValue.html#stripTags">stripTags</a></li>
1283 <li data-name="LuCI.form.MultiValue#textvalue"><a href="LuCI.form.MultiValue.html#textvalue">textvalue</a></li>
1285 <li data-name="LuCI.form.MultiValue#titleFn"><a href="LuCI.form.MultiValue.html#titleFn">titleFn</a></li>
1287 <li data-name="LuCI.form.MultiValue#value"><a href="LuCI.form.MultiValue.html#value">value</a></li>
1289 <li data-name="LuCI.form.MultiValue#write"><a href="LuCI.form.MultiValue.html#write">write</a></li>
1292 <ul class="events itemMembers">
1297 <li class="item" data-name="LuCI.form.NamedSection">
1298 <span class="title">
1299 <a href="LuCI.form.NamedSection.html">LuCI.form.NamedSection</a>
1302 <ul class="members itemMembers">
1304 <span class="subtitle">Members</span>
1306 <li data-name="LuCI.form.NamedSection##addremove"><a href="LuCI.form.NamedSection.html#addremove">addremove</a></li>
1308 <li data-name="LuCI.form.NamedSection##uciconfig"><a href="LuCI.form.NamedSection.html#uciconfig">uciconfig</a></li>
1310 <li data-name="LuCI.form.NamedSection#parentoption"><a href="LuCI.form.NamedSection.html#parentoption">parentoption</a></li>
1313 <ul class="typedefs itemMembers">
1316 <ul class="typedefs itemMembers">
1319 <ul class="methods itemMembers">
1321 <span class="subtitle">Methods</span>
1323 <li data-name="LuCI.form.NamedSection#append"><a href="LuCI.form.NamedSection.html#append">append</a></li>
1325 <li data-name="LuCI.form.NamedSection#cfgsections"><a href="LuCI.form.NamedSection.html#cfgsections">cfgsections</a></li>
1327 <li data-name="LuCI.form.NamedSection#filter"><a href="LuCI.form.NamedSection.html#filter">filter</a></li>
1329 <li data-name="LuCI.form.NamedSection#load"><a href="LuCI.form.NamedSection.html#load">load</a></li>
1331 <li data-name="LuCI.form.NamedSection#option"><a href="LuCI.form.NamedSection.html#option">option</a></li>
1333 <li data-name="LuCI.form.NamedSection#parse"><a href="LuCI.form.NamedSection.html#parse">parse</a></li>
1335 <li data-name="LuCI.form.NamedSection#render"><a href="LuCI.form.NamedSection.html#render">render</a></li>
1337 <li data-name="LuCI.form.NamedSection#stripTags"><a href="LuCI.form.NamedSection.html#stripTags">stripTags</a></li>
1339 <li data-name="LuCI.form.NamedSection#tab"><a href="LuCI.form.NamedSection.html#tab">tab</a></li>
1341 <li data-name="LuCI.form.NamedSection#taboption"><a href="LuCI.form.NamedSection.html#taboption">taboption</a></li>
1343 <li data-name="LuCI.form.NamedSection#titleFn"><a href="LuCI.form.NamedSection.html#titleFn">titleFn</a></li>
1346 <ul class="events itemMembers">
1351 <li class="item" data-name="LuCI.form.SectionValue">
1352 <span class="title">
1353 <a href="LuCI.form.SectionValue.html">LuCI.form.SectionValue</a>
1356 <ul class="members itemMembers">
1358 <span class="subtitle">Members</span>
1360 <li data-name="LuCI.form.SectionValue##subsection"><a href="LuCI.form.SectionValue.html#subsection">subsection</a></li>
1362 <li data-name="LuCI.form.SectionValue#datatype"><a href="LuCI.form.SectionValue.html#datatype">datatype</a></li>
1364 <li data-name="LuCI.form.SectionValue#default"><a href="LuCI.form.SectionValue.html#default">default</a></li>
1366 <li data-name="LuCI.form.SectionValue#editable"><a href="LuCI.form.SectionValue.html#editable">editable</a></li>
1368 <li data-name="LuCI.form.SectionValue#modalonly"><a href="LuCI.form.SectionValue.html#modalonly">modalonly</a></li>
1370 <li data-name="LuCI.form.SectionValue#optional"><a href="LuCI.form.SectionValue.html#optional">optional</a></li>
1372 <li data-name="LuCI.form.SectionValue#password"><a href="LuCI.form.SectionValue.html#password">password</a></li>
1374 <li data-name="LuCI.form.SectionValue#placeholder"><a href="LuCI.form.SectionValue.html#placeholder">placeholder</a></li>
1376 <li data-name="LuCI.form.SectionValue#readonly"><a href="LuCI.form.SectionValue.html#readonly">readonly</a></li>
1378 <li data-name="LuCI.form.SectionValue#rmempty"><a href="LuCI.form.SectionValue.html#rmempty">rmempty</a></li>
1380 <li data-name="LuCI.form.SectionValue#uciconfig"><a href="LuCI.form.SectionValue.html#uciconfig">uciconfig</a></li>
1382 <li data-name="LuCI.form.SectionValue#ucioption"><a href="LuCI.form.SectionValue.html#ucioption">ucioption</a></li>
1384 <li data-name="LuCI.form.SectionValue#ucisection"><a href="LuCI.form.SectionValue.html#ucisection">ucisection</a></li>
1386 <li data-name="LuCI.form.SectionValue#validate"><a href="LuCI.form.SectionValue.html#validate">validate</a></li>
1388 <li data-name="LuCI.form.SectionValue#width"><a href="LuCI.form.SectionValue.html#width">width</a></li>
1391 <ul class="typedefs itemMembers">
1394 <ul class="typedefs itemMembers">
1397 <ul class="methods itemMembers">
1399 <span class="subtitle">Methods</span>
1401 <li data-name="LuCI.form.SectionValue#append"><a href="LuCI.form.SectionValue.html#append">append</a></li>
1403 <li data-name="LuCI.form.SectionValue#cbid"><a href="LuCI.form.SectionValue.html#cbid">cbid</a></li>
1405 <li data-name="LuCI.form.SectionValue#cfgvalue"><a href="LuCI.form.SectionValue.html#cfgvalue">cfgvalue</a></li>
1407 <li data-name="LuCI.form.SectionValue#depends"><a href="LuCI.form.SectionValue.html#depends">depends</a></li>
1409 <li data-name="LuCI.form.SectionValue#formvalue"><a href="LuCI.form.SectionValue.html#formvalue">formvalue</a></li>
1411 <li data-name="LuCI.form.SectionValue#getUIElement"><a href="LuCI.form.SectionValue.html#getUIElement">getUIElement</a></li>
1413 <li data-name="LuCI.form.SectionValue#isActive"><a href="LuCI.form.SectionValue.html#isActive">isActive</a></li>
1415 <li data-name="LuCI.form.SectionValue#isValid"><a href="LuCI.form.SectionValue.html#isValid">isValid</a></li>
1417 <li data-name="LuCI.form.SectionValue#load"><a href="LuCI.form.SectionValue.html#load">load</a></li>
1419 <li data-name="LuCI.form.SectionValue#parse"><a href="LuCI.form.SectionValue.html#parse">parse</a></li>
1421 <li data-name="LuCI.form.SectionValue#remove"><a href="LuCI.form.SectionValue.html#remove">remove</a></li>
1423 <li data-name="LuCI.form.SectionValue#stripTags"><a href="LuCI.form.SectionValue.html#stripTags">stripTags</a></li>
1425 <li data-name="LuCI.form.SectionValue#textvalue"><a href="LuCI.form.SectionValue.html#textvalue">textvalue</a></li>
1427 <li data-name="LuCI.form.SectionValue#titleFn"><a href="LuCI.form.SectionValue.html#titleFn">titleFn</a></li>
1429 <li data-name="LuCI.form.SectionValue#value"><a href="LuCI.form.SectionValue.html#value">value</a></li>
1431 <li data-name="LuCI.form.SectionValue#write"><a href="LuCI.form.SectionValue.html#write">write</a></li>
1434 <ul class="events itemMembers">
1439 <li class="item" data-name="LuCI.form.TableSection">
1440 <span class="title">
1441 <a href="LuCI.form.TableSection.html">LuCI.form.TableSection</a>
1444 <ul class="members itemMembers">
1446 <span class="subtitle">Members</span>
1448 <li data-name="LuCI.form.TableSection##addbtntitle"><a href="LuCI.form.TableSection.html#addbtntitle">addbtntitle</a></li>
1450 <li data-name="LuCI.form.TableSection##addremove"><a href="LuCI.form.TableSection.html#addremove">addremove</a></li>
1452 <li data-name="LuCI.form.TableSection##anonymous"><a href="LuCI.form.TableSection.html#anonymous">anonymous</a></li>
1454 <li data-name="LuCI.form.TableSection##extedit"><a href="LuCI.form.TableSection.html#extedit">extedit</a></li>
1456 <li data-name="LuCI.form.TableSection##max_cols"><a href="LuCI.form.TableSection.html#max_cols">max_cols</a></li>
1458 <li data-name="LuCI.form.TableSection##modaltitle"><a href="LuCI.form.TableSection.html#modaltitle">modaltitle</a></li>
1460 <li data-name="LuCI.form.TableSection##rowcolors"><a href="LuCI.form.TableSection.html#rowcolors">rowcolors</a></li>
1462 <li data-name="LuCI.form.TableSection##sectiontitle"><a href="LuCI.form.TableSection.html#sectiontitle">sectiontitle</a></li>
1464 <li data-name="LuCI.form.TableSection##sortable"><a href="LuCI.form.TableSection.html#sortable">sortable</a></li>
1466 <li data-name="LuCI.form.TableSection##uciconfig"><a href="LuCI.form.TableSection.html#uciconfig">uciconfig</a></li>
1468 <li data-name="LuCI.form.TableSection#addbtntitle"><a href="LuCI.form.TableSection.html#addbtntitle">addbtntitle</a></li>
1470 <li data-name="LuCI.form.TableSection#addremove"><a href="LuCI.form.TableSection.html#addremove">addremove</a></li>
1472 <li data-name="LuCI.form.TableSection#anonymous"><a href="LuCI.form.TableSection.html#anonymous">anonymous</a></li>
1474 <li data-name="LuCI.form.TableSection#parentoption"><a href="LuCI.form.TableSection.html#parentoption">parentoption</a></li>
1476 <li data-name="LuCI.form.TableSection#tabbed"><a href="LuCI.form.TableSection.html#tabbed">tabbed</a></li>
1478 <li data-name="LuCI.form.TableSection#uciconfig"><a href="LuCI.form.TableSection.html#uciconfig">uciconfig</a></li>
1481 <ul class="typedefs itemMembers">
1484 <ul class="typedefs itemMembers">
1487 <ul class="methods itemMembers">
1489 <span class="subtitle">Methods</span>
1491 <li data-name="LuCI.form.TableSection#addModalOptions"><a href="LuCI.form.TableSection.html#addModalOptions">addModalOptions</a></li>
1493 <li data-name="LuCI.form.TableSection#append"><a href="LuCI.form.TableSection.html#append">append</a></li>
1495 <li data-name="LuCI.form.TableSection#filter"><a href="LuCI.form.TableSection.html#filter">filter</a></li>
1497 <li data-name="LuCI.form.TableSection#load"><a href="LuCI.form.TableSection.html#load">load</a></li>
1499 <li data-name="LuCI.form.TableSection#option"><a href="LuCI.form.TableSection.html#option">option</a></li>
1501 <li data-name="LuCI.form.TableSection#parse"><a href="LuCI.form.TableSection.html#parse">parse</a></li>
1503 <li data-name="LuCI.form.TableSection#stripTags"><a href="LuCI.form.TableSection.html#stripTags">stripTags</a></li>
1505 <li data-name="LuCI.form.TableSection#tab"><a href="LuCI.form.TableSection.html#tab">tab</a></li>
1507 <li data-name="LuCI.form.TableSection#taboption"><a href="LuCI.form.TableSection.html#taboption">taboption</a></li>
1509 <li data-name="LuCI.form.TableSection#titleFn"><a href="LuCI.form.TableSection.html#titleFn">titleFn</a></li>
1512 <ul class="events itemMembers">
1517 <li class="item" data-name="LuCI.form.TextValue">
1518 <span class="title">
1519 <a href="LuCI.form.TextValue.html">LuCI.form.TextValue</a>
1522 <ul class="members itemMembers">
1524 <span class="subtitle">Members</span>
1526 <li data-name="LuCI.form.TextValue##cols"><a href="LuCI.form.TextValue.html#cols">cols</a></li>
1528 <li data-name="LuCI.form.TextValue##monospace"><a href="LuCI.form.TextValue.html#monospace">monospace</a></li>
1530 <li data-name="LuCI.form.TextValue##rows"><a href="LuCI.form.TextValue.html#rows">rows</a></li>
1532 <li data-name="LuCI.form.TextValue##wrap"><a href="LuCI.form.TextValue.html#wrap">wrap</a></li>
1534 <li data-name="LuCI.form.TextValue#datatype"><a href="LuCI.form.TextValue.html#datatype">datatype</a></li>
1536 <li data-name="LuCI.form.TextValue#default"><a href="LuCI.form.TextValue.html#default">default</a></li>
1538 <li data-name="LuCI.form.TextValue#editable"><a href="LuCI.form.TextValue.html#editable">editable</a></li>
1540 <li data-name="LuCI.form.TextValue#modalonly"><a href="LuCI.form.TextValue.html#modalonly">modalonly</a></li>
1542 <li data-name="LuCI.form.TextValue#optional"><a href="LuCI.form.TextValue.html#optional">optional</a></li>
1544 <li data-name="LuCI.form.TextValue#password"><a href="LuCI.form.TextValue.html#password">password</a></li>
1546 <li data-name="LuCI.form.TextValue#placeholder"><a href="LuCI.form.TextValue.html#placeholder">placeholder</a></li>
1548 <li data-name="LuCI.form.TextValue#readonly"><a href="LuCI.form.TextValue.html#readonly">readonly</a></li>
1550 <li data-name="LuCI.form.TextValue#rmempty"><a href="LuCI.form.TextValue.html#rmempty">rmempty</a></li>
1552 <li data-name="LuCI.form.TextValue#uciconfig"><a href="LuCI.form.TextValue.html#uciconfig">uciconfig</a></li>
1554 <li data-name="LuCI.form.TextValue#ucioption"><a href="LuCI.form.TextValue.html#ucioption">ucioption</a></li>
1556 <li data-name="LuCI.form.TextValue#ucisection"><a href="LuCI.form.TextValue.html#ucisection">ucisection</a></li>
1558 <li data-name="LuCI.form.TextValue#validate"><a href="LuCI.form.TextValue.html#validate">validate</a></li>
1560 <li data-name="LuCI.form.TextValue#width"><a href="LuCI.form.TextValue.html#width">width</a></li>
1563 <ul class="typedefs itemMembers">
1566 <ul class="typedefs itemMembers">
1569 <ul class="methods itemMembers">
1571 <span class="subtitle">Methods</span>
1573 <li data-name="LuCI.form.TextValue#append"><a href="LuCI.form.TextValue.html#append">append</a></li>
1575 <li data-name="LuCI.form.TextValue#cbid"><a href="LuCI.form.TextValue.html#cbid">cbid</a></li>
1577 <li data-name="LuCI.form.TextValue#cfgvalue"><a href="LuCI.form.TextValue.html#cfgvalue">cfgvalue</a></li>
1579 <li data-name="LuCI.form.TextValue#depends"><a href="LuCI.form.TextValue.html#depends">depends</a></li>
1581 <li data-name="LuCI.form.TextValue#formvalue"><a href="LuCI.form.TextValue.html#formvalue">formvalue</a></li>
1583 <li data-name="LuCI.form.TextValue#getUIElement"><a href="LuCI.form.TextValue.html#getUIElement">getUIElement</a></li>
1585 <li data-name="LuCI.form.TextValue#isActive"><a href="LuCI.form.TextValue.html#isActive">isActive</a></li>
1587 <li data-name="LuCI.form.TextValue#isValid"><a href="LuCI.form.TextValue.html#isValid">isValid</a></li>
1589 <li data-name="LuCI.form.TextValue#load"><a href="LuCI.form.TextValue.html#load">load</a></li>
1591 <li data-name="LuCI.form.TextValue#parse"><a href="LuCI.form.TextValue.html#parse">parse</a></li>
1593 <li data-name="LuCI.form.TextValue#remove"><a href="LuCI.form.TextValue.html#remove">remove</a></li>
1595 <li data-name="LuCI.form.TextValue#stripTags"><a href="LuCI.form.TextValue.html#stripTags">stripTags</a></li>
1597 <li data-name="LuCI.form.TextValue#textvalue"><a href="LuCI.form.TextValue.html#textvalue">textvalue</a></li>
1599 <li data-name="LuCI.form.TextValue#titleFn"><a href="LuCI.form.TextValue.html#titleFn">titleFn</a></li>
1601 <li data-name="LuCI.form.TextValue#write"><a href="LuCI.form.TextValue.html#write">write</a></li>
1604 <ul class="events itemMembers">
1609 <li class="item" data-name="LuCI.form.TypedSection">
1610 <span class="title">
1611 <a href="LuCI.form.TypedSection.html">LuCI.form.TypedSection</a>
1614 <ul class="members itemMembers">
1616 <span class="subtitle">Members</span>
1618 <li data-name="LuCI.form.TypedSection##addbtntitle"><a href="LuCI.form.TypedSection.html#addbtntitle">addbtntitle</a></li>
1620 <li data-name="LuCI.form.TypedSection##addremove"><a href="LuCI.form.TypedSection.html#addremove">addremove</a></li>
1622 <li data-name="LuCI.form.TypedSection##anonymous"><a href="LuCI.form.TypedSection.html#anonymous">anonymous</a></li>
1624 <li data-name="LuCI.form.TypedSection##tabbed"><a href="LuCI.form.TypedSection.html#tabbed">tabbed</a></li>
1626 <li data-name="LuCI.form.TypedSection##uciconfig"><a href="LuCI.form.TypedSection.html#uciconfig">uciconfig</a></li>
1628 <li data-name="LuCI.form.TypedSection#parentoption"><a href="LuCI.form.TypedSection.html#parentoption">parentoption</a></li>
1631 <ul class="typedefs itemMembers">
1634 <ul class="typedefs itemMembers">
1637 <ul class="methods itemMembers">
1639 <span class="subtitle">Methods</span>
1641 <li data-name="LuCI.form.TypedSection#append"><a href="LuCI.form.TypedSection.html#append">append</a></li>
1643 <li data-name="LuCI.form.TypedSection#cfgsections"><a href="LuCI.form.TypedSection.html#cfgsections">cfgsections</a></li>
1645 <li data-name="LuCI.form.TypedSection#filter"><a href="LuCI.form.TypedSection.html#filter">filter</a></li>
1647 <li data-name="LuCI.form.TypedSection#load"><a href="LuCI.form.TypedSection.html#load">load</a></li>
1649 <li data-name="LuCI.form.TypedSection#option"><a href="LuCI.form.TypedSection.html#option">option</a></li>
1651 <li data-name="LuCI.form.TypedSection#parse"><a href="LuCI.form.TypedSection.html#parse">parse</a></li>
1653 <li data-name="LuCI.form.TypedSection#render"><a href="LuCI.form.TypedSection.html#render">render</a></li>
1655 <li data-name="LuCI.form.TypedSection#stripTags"><a href="LuCI.form.TypedSection.html#stripTags">stripTags</a></li>
1657 <li data-name="LuCI.form.TypedSection#tab"><a href="LuCI.form.TypedSection.html#tab">tab</a></li>
1659 <li data-name="LuCI.form.TypedSection#taboption"><a href="LuCI.form.TypedSection.html#taboption">taboption</a></li>
1661 <li data-name="LuCI.form.TypedSection#titleFn"><a href="LuCI.form.TypedSection.html#titleFn">titleFn</a></li>
1664 <ul class="events itemMembers">
1669 <li class="item" data-name="LuCI.form.Value">
1670 <span class="title">
1671 <a href="LuCI.form.Value.html">LuCI.form.Value</a>
1674 <ul class="members itemMembers">
1676 <span class="subtitle">Members</span>
1678 <li data-name="LuCI.form.Value##password"><a href="LuCI.form.Value.html#password">password</a></li>
1680 <li data-name="LuCI.form.Value##placeholder"><a href="LuCI.form.Value.html#placeholder">placeholder</a></li>
1682 <li data-name="LuCI.form.Value#datatype"><a href="LuCI.form.Value.html#datatype">datatype</a></li>
1684 <li data-name="LuCI.form.Value#default"><a href="LuCI.form.Value.html#default">default</a></li>
1686 <li data-name="LuCI.form.Value#editable"><a href="LuCI.form.Value.html#editable">editable</a></li>
1688 <li data-name="LuCI.form.Value#modalonly"><a href="LuCI.form.Value.html#modalonly">modalonly</a></li>
1690 <li data-name="LuCI.form.Value#optional"><a href="LuCI.form.Value.html#optional">optional</a></li>
1692 <li data-name="LuCI.form.Value#readonly"><a href="LuCI.form.Value.html#readonly">readonly</a></li>
1694 <li data-name="LuCI.form.Value#rmempty"><a href="LuCI.form.Value.html#rmempty">rmempty</a></li>
1696 <li data-name="LuCI.form.Value#uciconfig"><a href="LuCI.form.Value.html#uciconfig">uciconfig</a></li>
1698 <li data-name="LuCI.form.Value#ucioption"><a href="LuCI.form.Value.html#ucioption">ucioption</a></li>
1700 <li data-name="LuCI.form.Value#ucisection"><a href="LuCI.form.Value.html#ucisection">ucisection</a></li>
1702 <li data-name="LuCI.form.Value#validate"><a href="LuCI.form.Value.html#validate">validate</a></li>
1704 <li data-name="LuCI.form.Value#width"><a href="LuCI.form.Value.html#width">width</a></li>
1707 <ul class="typedefs itemMembers">
1710 <ul class="typedefs itemMembers">
1713 <ul class="methods itemMembers">
1715 <span class="subtitle">Methods</span>
1717 <li data-name="LuCI.form.Value#append"><a href="LuCI.form.Value.html#append">append</a></li>
1719 <li data-name="LuCI.form.Value#cbid"><a href="LuCI.form.Value.html#cbid">cbid</a></li>
1721 <li data-name="LuCI.form.Value#cfgvalue"><a href="LuCI.form.Value.html#cfgvalue">cfgvalue</a></li>
1723 <li data-name="LuCI.form.Value#depends"><a href="LuCI.form.Value.html#depends">depends</a></li>
1725 <li data-name="LuCI.form.Value#formvalue"><a href="LuCI.form.Value.html#formvalue">formvalue</a></li>
1727 <li data-name="LuCI.form.Value#getUIElement"><a href="LuCI.form.Value.html#getUIElement">getUIElement</a></li>
1729 <li data-name="LuCI.form.Value#isActive"><a href="LuCI.form.Value.html#isActive">isActive</a></li>
1731 <li data-name="LuCI.form.Value#isValid"><a href="LuCI.form.Value.html#isValid">isValid</a></li>
1733 <li data-name="LuCI.form.Value#load"><a href="LuCI.form.Value.html#load">load</a></li>
1735 <li data-name="LuCI.form.Value#parse"><a href="LuCI.form.Value.html#parse">parse</a></li>
1737 <li data-name="LuCI.form.Value#remove"><a href="LuCI.form.Value.html#remove">remove</a></li>
1739 <li data-name="LuCI.form.Value#render"><a href="LuCI.form.Value.html#render">render</a></li>
1741 <li data-name="LuCI.form.Value#stripTags"><a href="LuCI.form.Value.html#stripTags">stripTags</a></li>
1743 <li data-name="LuCI.form.Value#textvalue"><a href="LuCI.form.Value.html#textvalue">textvalue</a></li>
1745 <li data-name="LuCI.form.Value#titleFn"><a href="LuCI.form.Value.html#titleFn">titleFn</a></li>
1747 <li data-name="LuCI.form.Value#value"><a href="LuCI.form.Value.html#value">value</a></li>
1749 <li data-name="LuCI.form.Value#write"><a href="LuCI.form.Value.html#write">write</a></li>
1752 <ul class="events itemMembers">
1757 <li class="item" data-name="LuCI.fs">
1758 <span class="title">
1759 <a href="LuCI.fs.html">LuCI.fs</a>
1762 <ul class="members itemMembers">
1765 <ul class="typedefs itemMembers">
1767 <span class="subtitle">Typedefs</span>
1769 <li data-name="LuCI.fs.FileExecResult"><a href="LuCI.fs.html#.FileExecResult">FileExecResult</a></li>
1771 <li data-name="LuCI.fs.FileStatEntry"><a href="LuCI.fs.html#.FileStatEntry">FileStatEntry</a></li>
1774 <ul class="typedefs itemMembers">
1777 <ul class="methods itemMembers">
1779 <span class="subtitle">Methods</span>
1781 <li data-name="LuCI.fs#exec"><a href="LuCI.fs.html#exec">exec</a></li>
1783 <li data-name="LuCI.fs#exec_direct"><a href="LuCI.fs.html#exec_direct">exec_direct</a></li>
1785 <li data-name="LuCI.fs#lines"><a href="LuCI.fs.html#lines">lines</a></li>
1787 <li data-name="LuCI.fs#list"><a href="LuCI.fs.html#list">list</a></li>
1789 <li data-name="LuCI.fs#read"><a href="LuCI.fs.html#read">read</a></li>
1791 <li data-name="LuCI.fs#read_direct"><a href="LuCI.fs.html#read_direct">read_direct</a></li>
1793 <li data-name="LuCI.fs#remove"><a href="LuCI.fs.html#remove">remove</a></li>
1795 <li data-name="LuCI.fs#stat"><a href="LuCI.fs.html#stat">stat</a></li>
1797 <li data-name="LuCI.fs#trimmed"><a href="LuCI.fs.html#trimmed">trimmed</a></li>
1799 <li data-name="LuCI.fs#write"><a href="LuCI.fs.html#write">write</a></li>
1802 <ul class="events itemMembers">
1807 <li class="item" data-name="LuCI.headers">
1808 <span class="title">
1809 <a href="LuCI.headers.html">LuCI.headers</a>
1812 <ul class="members itemMembers">
1815 <ul class="typedefs itemMembers">
1818 <ul class="typedefs itemMembers">
1821 <ul class="methods itemMembers">
1823 <span class="subtitle">Methods</span>
1825 <li data-name="LuCI.headers#get"><a href="LuCI.headers.html#get">get</a></li>
1827 <li data-name="LuCI.headers#has"><a href="LuCI.headers.html#has">has</a></li>
1830 <ul class="events itemMembers">
1835 <li class="item" data-name="LuCI.network">
1836 <span class="title">
1837 <a href="LuCI.network.html">LuCI.network</a>
1840 <ul class="members itemMembers">
1843 <ul class="typedefs itemMembers">
1845 <span class="subtitle">Typedefs</span>
1847 <li data-name="LuCI.network.SwitchTopology"><a href="LuCI.network.html#.SwitchTopology">SwitchTopology</a></li>
1849 <li data-name="LuCI.network.WifiEncryption"><a href="LuCI.network.html#.WifiEncryption">WifiEncryption</a></li>
1851 <li data-name="LuCI.network.WifiPeerEntry"><a href="LuCI.network.html#.WifiPeerEntry">WifiPeerEntry</a></li>
1853 <li data-name="LuCI.network.WifiRateEntry"><a href="LuCI.network.html#.WifiRateEntry">WifiRateEntry</a></li>
1855 <li data-name="LuCI.network.WifiScanResult"><a href="LuCI.network.html#.WifiScanResult">WifiScanResult</a></li>
1858 <ul class="typedefs itemMembers">
1861 <ul class="methods itemMembers">
1863 <span class="subtitle">Methods</span>
1865 <li data-name="LuCI.network#addNetwork"><a href="LuCI.network.html#addNetwork">addNetwork</a></li>
1867 <li data-name="LuCI.network#addWifiNetwork"><a href="LuCI.network.html#addWifiNetwork">addWifiNetwork</a></li>
1869 <li data-name="LuCI.network#deleteNetwork"><a href="LuCI.network.html#deleteNetwork">deleteNetwork</a></li>
1871 <li data-name="LuCI.network#deleteWifiNetwork"><a href="LuCI.network.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
1873 <li data-name="LuCI.network#flushCache"><a href="LuCI.network.html#flushCache">flushCache</a></li>
1875 <li data-name="LuCI.network#formatWifiEncryption"><a href="LuCI.network.html#formatWifiEncryption">formatWifiEncryption</a></li>
1877 <li data-name="LuCI.network#getDevice"><a href="LuCI.network.html#getDevice">getDevice</a></li>
1879 <li data-name="LuCI.network#getDevices"><a href="LuCI.network.html#getDevices">getDevices</a></li>
1881 <li data-name="LuCI.network#getDSLModemType"><a href="LuCI.network.html#getDSLModemType">getDSLModemType</a></li>
1883 <li data-name="LuCI.network#getHostHints"><a href="LuCI.network.html#getHostHints">getHostHints</a></li>
1885 <li data-name="LuCI.network#getIfnameOf"><a href="LuCI.network.html#getIfnameOf">getIfnameOf</a></li>
1887 <li data-name="LuCI.network#getNetwork"><a href="LuCI.network.html#getNetwork">getNetwork</a></li>
1889 <li data-name="LuCI.network#getNetworks"><a href="LuCI.network.html#getNetworks">getNetworks</a></li>
1891 <li data-name="LuCI.network#getProtocol"><a href="LuCI.network.html#getProtocol">getProtocol</a></li>
1893 <li data-name="LuCI.network#getProtocols"><a href="LuCI.network.html#getProtocols">getProtocols</a></li>
1895 <li data-name="LuCI.network#getSwitchTopologies"><a href="LuCI.network.html#getSwitchTopologies">getSwitchTopologies</a></li>
1897 <li data-name="LuCI.network#getWAN6Networks"><a href="LuCI.network.html#getWAN6Networks">getWAN6Networks</a></li>
1899 <li data-name="LuCI.network#getWANNetworks"><a href="LuCI.network.html#getWANNetworks">getWANNetworks</a></li>
1901 <li data-name="LuCI.network#getWifiDevice"><a href="LuCI.network.html#getWifiDevice">getWifiDevice</a></li>
1903 <li data-name="LuCI.network#getWifiDevices"><a href="LuCI.network.html#getWifiDevices">getWifiDevices</a></li>
1905 <li data-name="LuCI.network#getWifiNetwork"><a href="LuCI.network.html#getWifiNetwork">getWifiNetwork</a></li>
1907 <li data-name="LuCI.network#getWifiNetworks"><a href="LuCI.network.html#getWifiNetworks">getWifiNetworks</a></li>
1909 <li data-name="LuCI.network#isIgnoredDevice"><a href="LuCI.network.html#isIgnoredDevice">isIgnoredDevice</a></li>
1911 <li data-name="LuCI.network#maskToPrefix"><a href="LuCI.network.html#maskToPrefix">maskToPrefix</a></li>
1913 <li data-name="LuCI.network#prefixToMask"><a href="LuCI.network.html#prefixToMask">prefixToMask</a></li>
1915 <li data-name="LuCI.network#registerErrorCode"><a href="LuCI.network.html#registerErrorCode">registerErrorCode</a></li>
1917 <li data-name="LuCI.network#registerPatternVirtual"><a href="LuCI.network.html#registerPatternVirtual">registerPatternVirtual</a></li>
1919 <li data-name="LuCI.network#registerProtocol"><a href="LuCI.network.html#registerProtocol">registerProtocol</a></li>
1921 <li data-name="LuCI.network#renameNetwork"><a href="LuCI.network.html#renameNetwork">renameNetwork</a></li>
1924 <ul class="events itemMembers">
1929 <li class="item" data-name="LuCI.network.Device">
1930 <span class="title">
1931 <a href="LuCI.network.Device.html">LuCI.network.Device</a>
1934 <ul class="members itemMembers">
1937 <ul class="typedefs itemMembers">
1940 <ul class="typedefs itemMembers">
1943 <ul class="methods itemMembers">
1945 <span class="subtitle">Methods</span>
1947 <li data-name="LuCI.network.Device#getBridgeID"><a href="LuCI.network.Device.html#getBridgeID">getBridgeID</a></li>
1949 <li data-name="LuCI.network.Device#getBridgeSTP"><a href="LuCI.network.Device.html#getBridgeSTP">getBridgeSTP</a></li>
1951 <li data-name="LuCI.network.Device#getI18n"><a href="LuCI.network.Device.html#getI18n">getI18n</a></li>
1953 <li data-name="LuCI.network.Device#getIP6Addrs"><a href="LuCI.network.Device.html#getIP6Addrs">getIP6Addrs</a></li>
1955 <li data-name="LuCI.network.Device#getIPAddrs"><a href="LuCI.network.Device.html#getIPAddrs">getIPAddrs</a></li>
1957 <li data-name="LuCI.network.Device#getMAC"><a href="LuCI.network.Device.html#getMAC">getMAC</a></li>
1959 <li data-name="LuCI.network.Device#getMTU"><a href="LuCI.network.Device.html#getMTU">getMTU</a></li>
1961 <li data-name="LuCI.network.Device#getName"><a href="LuCI.network.Device.html#getName">getName</a></li>
1963 <li data-name="LuCI.network.Device#getNetwork"><a href="LuCI.network.Device.html#getNetwork">getNetwork</a></li>
1965 <li data-name="LuCI.network.Device#getNetworks"><a href="LuCI.network.Device.html#getNetworks">getNetworks</a></li>
1967 <li data-name="LuCI.network.Device#getPorts"><a href="LuCI.network.Device.html#getPorts">getPorts</a></li>
1969 <li data-name="LuCI.network.Device#getRXBytes"><a href="LuCI.network.Device.html#getRXBytes">getRXBytes</a></li>
1971 <li data-name="LuCI.network.Device#getRXPackets"><a href="LuCI.network.Device.html#getRXPackets">getRXPackets</a></li>
1973 <li data-name="LuCI.network.Device#getShortName"><a href="LuCI.network.Device.html#getShortName">getShortName</a></li>
1975 <li data-name="LuCI.network.Device#getTXBytes"><a href="LuCI.network.Device.html#getTXBytes">getTXBytes</a></li>
1977 <li data-name="LuCI.network.Device#getTXPackets"><a href="LuCI.network.Device.html#getTXPackets">getTXPackets</a></li>
1979 <li data-name="LuCI.network.Device#getType"><a href="LuCI.network.Device.html#getType">getType</a></li>
1981 <li data-name="LuCI.network.Device#getTypeI18n"><a href="LuCI.network.Device.html#getTypeI18n">getTypeI18n</a></li>
1983 <li data-name="LuCI.network.Device#getWifiNetwork"><a href="LuCI.network.Device.html#getWifiNetwork">getWifiNetwork</a></li>
1985 <li data-name="LuCI.network.Device#isBridge"><a href="LuCI.network.Device.html#isBridge">isBridge</a></li>
1987 <li data-name="LuCI.network.Device#isBridgePort"><a href="LuCI.network.Device.html#isBridgePort">isBridgePort</a></li>
1989 <li data-name="LuCI.network.Device#isUp"><a href="LuCI.network.Device.html#isUp">isUp</a></li>
1992 <ul class="events itemMembers">
1997 <li class="item" data-name="LuCI.network.Hosts">
1998 <span class="title">
1999 <a href="LuCI.network.Hosts.html">LuCI.network.Hosts</a>
2002 <ul class="members itemMembers">
2005 <ul class="typedefs itemMembers">
2008 <ul class="typedefs itemMembers">
2011 <ul class="methods itemMembers">
2013 <span class="subtitle">Methods</span>
2015 <li data-name="LuCI.network.Hosts#getHostnameByIP6Addr"><a href="LuCI.network.Hosts.html#getHostnameByIP6Addr">getHostnameByIP6Addr</a></li>
2017 <li data-name="LuCI.network.Hosts#getHostnameByIPAddr"><a href="LuCI.network.Hosts.html#getHostnameByIPAddr">getHostnameByIPAddr</a></li>
2019 <li data-name="LuCI.network.Hosts#getHostnameByMACAddr"><a href="LuCI.network.Hosts.html#getHostnameByMACAddr">getHostnameByMACAddr</a></li>
2021 <li data-name="LuCI.network.Hosts#getIP6AddrByMACAddr"><a href="LuCI.network.Hosts.html#getIP6AddrByMACAddr">getIP6AddrByMACAddr</a></li>
2023 <li data-name="LuCI.network.Hosts#getIPAddrByMACAddr"><a href="LuCI.network.Hosts.html#getIPAddrByMACAddr">getIPAddrByMACAddr</a></li>
2025 <li data-name="LuCI.network.Hosts#getMACAddrByIP6Addr"><a href="LuCI.network.Hosts.html#getMACAddrByIP6Addr">getMACAddrByIP6Addr</a></li>
2027 <li data-name="LuCI.network.Hosts#getMACAddrByIPAddr"><a href="LuCI.network.Hosts.html#getMACAddrByIPAddr">getMACAddrByIPAddr</a></li>
2029 <li data-name="LuCI.network.Hosts#getMACHints"><a href="LuCI.network.Hosts.html#getMACHints">getMACHints</a></li>
2032 <ul class="events itemMembers">
2037 <li class="item" data-name="LuCI.network.Protocol">
2038 <span class="title">
2039 <a href="LuCI.network.Protocol.html">LuCI.network.Protocol</a>
2042 <ul class="members itemMembers">
2045 <ul class="typedefs itemMembers">
2048 <ul class="typedefs itemMembers">
2051 <ul class="methods itemMembers">
2053 <span class="subtitle">Methods</span>
2055 <li data-name="LuCI.network.Protocol#addDevice"><a href="LuCI.network.Protocol.html#addDevice">addDevice</a></li>
2057 <li data-name="LuCI.network.Protocol#containsDevice"><a href="LuCI.network.Protocol.html#containsDevice">containsDevice</a></li>
2059 <li data-name="LuCI.network.Protocol#deleteConfiguration"><a href="LuCI.network.Protocol.html#deleteConfiguration">deleteConfiguration</a></li>
2061 <li data-name="LuCI.network.Protocol#deleteDevice"><a href="LuCI.network.Protocol.html#deleteDevice">deleteDevice</a></li>
2063 <li data-name="LuCI.network.Protocol#get"><a href="LuCI.network.Protocol.html#get">get</a></li>
2065 <li data-name="LuCI.network.Protocol#getDevice"><a href="LuCI.network.Protocol.html#getDevice">getDevice</a></li>
2067 <li data-name="LuCI.network.Protocol#getDevices"><a href="LuCI.network.Protocol.html#getDevices">getDevices</a></li>
2069 <li data-name="LuCI.network.Protocol#getDNS6Addrs"><a href="LuCI.network.Protocol.html#getDNS6Addrs">getDNS6Addrs</a></li>
2071 <li data-name="LuCI.network.Protocol#getDNSAddrs"><a href="LuCI.network.Protocol.html#getDNSAddrs">getDNSAddrs</a></li>
2073 <li data-name="LuCI.network.Protocol#getErrors"><a href="LuCI.network.Protocol.html#getErrors">getErrors</a></li>
2075 <li data-name="LuCI.network.Protocol#getExpiry"><a href="LuCI.network.Protocol.html#getExpiry">getExpiry</a></li>
2077 <li data-name="LuCI.network.Protocol#getGateway6Addr"><a href="LuCI.network.Protocol.html#getGateway6Addr">getGateway6Addr</a></li>
2079 <li data-name="LuCI.network.Protocol#getGatewayAddr"><a href="LuCI.network.Protocol.html#getGatewayAddr">getGatewayAddr</a></li>
2081 <li data-name="LuCI.network.Protocol#getI18n"><a href="LuCI.network.Protocol.html#getI18n">getI18n</a></li>
2083 <li data-name="LuCI.network.Protocol#getIfname"><a href="LuCI.network.Protocol.html#getIfname">getIfname</a></li>
2085 <li data-name="LuCI.network.Protocol#getIP6Addr"><a href="LuCI.network.Protocol.html#getIP6Addr">getIP6Addr</a></li>
2087 <li data-name="LuCI.network.Protocol#getIP6Addrs"><a href="LuCI.network.Protocol.html#getIP6Addrs">getIP6Addrs</a></li>
2089 <li data-name="LuCI.network.Protocol#getIP6Prefix"><a href="LuCI.network.Protocol.html#getIP6Prefix">getIP6Prefix</a></li>
2091 <li data-name="LuCI.network.Protocol#getIPAddr"><a href="LuCI.network.Protocol.html#getIPAddr">getIPAddr</a></li>
2093 <li data-name="LuCI.network.Protocol#getIPAddrs"><a href="LuCI.network.Protocol.html#getIPAddrs">getIPAddrs</a></li>
2095 <li data-name="LuCI.network.Protocol#getL2Device"><a href="LuCI.network.Protocol.html#getL2Device">getL2Device</a></li>
2097 <li data-name="LuCI.network.Protocol#getL3Device"><a href="LuCI.network.Protocol.html#getL3Device">getL3Device</a></li>
2099 <li data-name="LuCI.network.Protocol#getMetric"><a href="LuCI.network.Protocol.html#getMetric">getMetric</a></li>
2101 <li data-name="LuCI.network.Protocol#getName"><a href="LuCI.network.Protocol.html#getName">getName</a></li>
2103 <li data-name="LuCI.network.Protocol#getNetmask"><a href="LuCI.network.Protocol.html#getNetmask">getNetmask</a></li>
2105 <li data-name="LuCI.network.Protocol#getOpkgPackage"><a href="LuCI.network.Protocol.html#getOpkgPackage">getOpkgPackage</a></li>
2107 <li data-name="LuCI.network.Protocol#getProtocol"><a href="LuCI.network.Protocol.html#getProtocol">getProtocol</a></li>
2109 <li data-name="LuCI.network.Protocol#getType"><a href="LuCI.network.Protocol.html#getType">getType</a></li>
2111 <li data-name="LuCI.network.Protocol#getUptime"><a href="LuCI.network.Protocol.html#getUptime">getUptime</a></li>
2113 <li data-name="LuCI.network.Protocol#getZoneName"><a href="LuCI.network.Protocol.html#getZoneName">getZoneName</a></li>
2115 <li data-name="LuCI.network.Protocol#isAlias"><a href="LuCI.network.Protocol.html#isAlias">isAlias</a></li>
2117 <li data-name="LuCI.network.Protocol#isBridge"><a href="LuCI.network.Protocol.html#isBridge">isBridge</a></li>
2119 <li data-name="LuCI.network.Protocol#isCreateable"><a href="LuCI.network.Protocol.html#isCreateable">isCreateable</a></li>
2121 <li data-name="LuCI.network.Protocol#isDynamic"><a href="LuCI.network.Protocol.html#isDynamic">isDynamic</a></li>
2123 <li data-name="LuCI.network.Protocol#isEmpty"><a href="LuCI.network.Protocol.html#isEmpty">isEmpty</a></li>
2125 <li data-name="LuCI.network.Protocol#isFloating"><a href="LuCI.network.Protocol.html#isFloating">isFloating</a></li>
2127 <li data-name="LuCI.network.Protocol#isInstalled"><a href="LuCI.network.Protocol.html#isInstalled">isInstalled</a></li>
2129 <li data-name="LuCI.network.Protocol#isUp"><a href="LuCI.network.Protocol.html#isUp">isUp</a></li>
2131 <li data-name="LuCI.network.Protocol#isVirtual"><a href="LuCI.network.Protocol.html#isVirtual">isVirtual</a></li>
2133 <li data-name="LuCI.network.Protocol#set"><a href="LuCI.network.Protocol.html#set">set</a></li>
2136 <ul class="events itemMembers">
2141 <li class="item" data-name="LuCI.network.WifiDevice">
2142 <span class="title">
2143 <a href="LuCI.network.WifiDevice.html">LuCI.network.WifiDevice</a>
2146 <ul class="members itemMembers">
2149 <ul class="typedefs itemMembers">
2152 <ul class="typedefs itemMembers">
2155 <ul class="methods itemMembers">
2157 <span class="subtitle">Methods</span>
2159 <li data-name="LuCI.network.WifiDevice#addWifiNetwork"><a href="LuCI.network.WifiDevice.html#addWifiNetwork">addWifiNetwork</a></li>
2161 <li data-name="LuCI.network.WifiDevice#deleteWifiNetwork"><a href="LuCI.network.WifiDevice.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
2163 <li data-name="LuCI.network.WifiDevice#get"><a href="LuCI.network.WifiDevice.html#get">get</a></li>
2165 <li data-name="LuCI.network.WifiDevice#getHTModes"><a href="LuCI.network.WifiDevice.html#getHTModes">getHTModes</a></li>
2167 <li data-name="LuCI.network.WifiDevice#getHWModes"><a href="LuCI.network.WifiDevice.html#getHWModes">getHWModes</a></li>
2169 <li data-name="LuCI.network.WifiDevice#getI18n"><a href="LuCI.network.WifiDevice.html#getI18n">getI18n</a></li>
2171 <li data-name="LuCI.network.WifiDevice#getName"><a href="LuCI.network.WifiDevice.html#getName">getName</a></li>
2173 <li data-name="LuCI.network.WifiDevice#getScanList"><a href="LuCI.network.WifiDevice.html#getScanList">getScanList</a></li>
2175 <li data-name="LuCI.network.WifiDevice#getWifiNetwork"><a href="LuCI.network.WifiDevice.html#getWifiNetwork">getWifiNetwork</a></li>
2177 <li data-name="LuCI.network.WifiDevice#getWifiNetworks"><a href="LuCI.network.WifiDevice.html#getWifiNetworks">getWifiNetworks</a></li>
2179 <li data-name="LuCI.network.WifiDevice#isDisabled"><a href="LuCI.network.WifiDevice.html#isDisabled">isDisabled</a></li>
2181 <li data-name="LuCI.network.WifiDevice#isUp"><a href="LuCI.network.WifiDevice.html#isUp">isUp</a></li>
2183 <li data-name="LuCI.network.WifiDevice#set"><a href="LuCI.network.WifiDevice.html#set">set</a></li>
2186 <ul class="events itemMembers">
2191 <li class="item" data-name="LuCI.network.WifiNetwork">
2192 <span class="title">
2193 <a href="LuCI.network.WifiNetwork.html">LuCI.network.WifiNetwork</a>
2196 <ul class="members itemMembers">
2199 <ul class="typedefs itemMembers">
2202 <ul class="typedefs itemMembers">
2205 <ul class="methods itemMembers">
2207 <span class="subtitle">Methods</span>
2209 <li data-name="LuCI.network.WifiNetwork#disconnectClient"><a href="LuCI.network.WifiNetwork.html#disconnectClient">disconnectClient</a></li>
2211 <li data-name="LuCI.network.WifiNetwork#get"><a href="LuCI.network.WifiNetwork.html#get">get</a></li>
2213 <li data-name="LuCI.network.WifiNetwork#getActiveBSSID"><a href="LuCI.network.WifiNetwork.html#getActiveBSSID">getActiveBSSID</a></li>
2215 <li data-name="LuCI.network.WifiNetwork#getActiveEncryption"><a href="LuCI.network.WifiNetwork.html#getActiveEncryption">getActiveEncryption</a></li>
2217 <li data-name="LuCI.network.WifiNetwork#getActiveMode"><a href="LuCI.network.WifiNetwork.html#getActiveMode">getActiveMode</a></li>
2219 <li data-name="LuCI.network.WifiNetwork#getActiveModeI18n"><a href="LuCI.network.WifiNetwork.html#getActiveModeI18n">getActiveModeI18n</a></li>
2221 <li data-name="LuCI.network.WifiNetwork#getActiveSSID"><a href="LuCI.network.WifiNetwork.html#getActiveSSID">getActiveSSID</a></li>
2223 <li data-name="LuCI.network.WifiNetwork#getAssocList"><a href="LuCI.network.WifiNetwork.html#getAssocList">getAssocList</a></li>
2225 <li data-name="LuCI.network.WifiNetwork#getBitRate"><a href="LuCI.network.WifiNetwork.html#getBitRate">getBitRate</a></li>
2227 <li data-name="LuCI.network.WifiNetwork#getBSSID"><a href="LuCI.network.WifiNetwork.html#getBSSID">getBSSID</a></li>
2229 <li data-name="LuCI.network.WifiNetwork#getChannel"><a href="LuCI.network.WifiNetwork.html#getChannel">getChannel</a></li>
2231 <li data-name="LuCI.network.WifiNetwork#getCountryCode"><a href="LuCI.network.WifiNetwork.html#getCountryCode">getCountryCode</a></li>
2233 <li data-name="LuCI.network.WifiNetwork#getDevice"><a href="LuCI.network.WifiNetwork.html#getDevice">getDevice</a></li>
2235 <li data-name="LuCI.network.WifiNetwork#getFrequency"><a href="LuCI.network.WifiNetwork.html#getFrequency">getFrequency</a></li>
2237 <li data-name="LuCI.network.WifiNetwork#getI18n"><a href="LuCI.network.WifiNetwork.html#getI18n">getI18n</a></li>
2239 <li data-name="LuCI.network.WifiNetwork#getID"><a href="LuCI.network.WifiNetwork.html#getID">getID</a></li>
2241 <li data-name="LuCI.network.WifiNetwork#getIfname"><a href="LuCI.network.WifiNetwork.html#getIfname">getIfname</a></li>
2243 <li data-name="LuCI.network.WifiNetwork#getMeshID"><a href="LuCI.network.WifiNetwork.html#getMeshID">getMeshID</a></li>
2245 <li data-name="LuCI.network.WifiNetwork#getMode"><a href="LuCI.network.WifiNetwork.html#getMode">getMode</a></li>
2247 <li data-name="LuCI.network.WifiNetwork#getName"><a href="LuCI.network.WifiNetwork.html#getName">getName</a></li>
2249 <li data-name="LuCI.network.WifiNetwork#getNetwork"><a href="LuCI.network.WifiNetwork.html#getNetwork">getNetwork</a></li>
2251 <li data-name="LuCI.network.WifiNetwork#getNetworkNames"><a href="LuCI.network.WifiNetwork.html#getNetworkNames">getNetworkNames</a></li>
2253 <li data-name="LuCI.network.WifiNetwork#getNetworks"><a href="LuCI.network.WifiNetwork.html#getNetworks">getNetworks</a></li>
2255 <li data-name="LuCI.network.WifiNetwork#getNoise"><a href="LuCI.network.WifiNetwork.html#getNoise">getNoise</a></li>
2257 <li data-name="LuCI.network.WifiNetwork#getShortName"><a href="LuCI.network.WifiNetwork.html#getShortName">getShortName</a></li>
2259 <li data-name="LuCI.network.WifiNetwork#getSignal"><a href="LuCI.network.WifiNetwork.html#getSignal">getSignal</a></li>
2261 <li data-name="LuCI.network.WifiNetwork#getSignalLevel"><a href="LuCI.network.WifiNetwork.html#getSignalLevel">getSignalLevel</a></li>
2263 <li data-name="LuCI.network.WifiNetwork#getSignalPercent"><a href="LuCI.network.WifiNetwork.html#getSignalPercent">getSignalPercent</a></li>
2265 <li data-name="LuCI.network.WifiNetwork#getSSID"><a href="LuCI.network.WifiNetwork.html#getSSID">getSSID</a></li>
2267 <li data-name="LuCI.network.WifiNetwork#getTXPower"><a href="LuCI.network.WifiNetwork.html#getTXPower">getTXPower</a></li>
2269 <li data-name="LuCI.network.WifiNetwork#getTXPowerOffset"><a href="LuCI.network.WifiNetwork.html#getTXPowerOffset">getTXPowerOffset</a></li>
2271 <li data-name="LuCI.network.WifiNetwork#getWifiDevice"><a href="LuCI.network.WifiNetwork.html#getWifiDevice">getWifiDevice</a></li>
2273 <li data-name="LuCI.network.WifiNetwork#getWifiDeviceName"><a href="LuCI.network.WifiNetwork.html#getWifiDeviceName">getWifiDeviceName</a></li>
2275 <li data-name="LuCI.network.WifiNetwork#isClientDisconnectSupported"><a href="LuCI.network.WifiNetwork.html#isClientDisconnectSupported">isClientDisconnectSupported</a></li>
2277 <li data-name="LuCI.network.WifiNetwork#isDisabled"><a href="LuCI.network.WifiNetwork.html#isDisabled">isDisabled</a></li>
2279 <li data-name="LuCI.network.WifiNetwork#isUp"><a href="LuCI.network.WifiNetwork.html#isUp">isUp</a></li>
2281 <li data-name="LuCI.network.WifiNetwork#set"><a href="LuCI.network.WifiNetwork.html#set">set</a></li>
2284 <ul class="events itemMembers">
2289 <li class="item" data-name="LuCI.poll">
2290 <span class="title">
2291 <a href="LuCI.poll.html">LuCI.poll</a>
2294 <ul class="members itemMembers">
2297 <ul class="typedefs itemMembers">
2300 <ul class="typedefs itemMembers">
2303 <ul class="methods itemMembers">
2305 <span class="subtitle">Methods</span>
2307 <li data-name="LuCI.poll#active"><a href="LuCI.poll.html#active">active</a></li>
2309 <li data-name="LuCI.poll#add"><a href="LuCI.poll.html#add">add</a></li>
2311 <li data-name="LuCI.poll#remove"><a href="LuCI.poll.html#remove">remove</a></li>
2313 <li data-name="LuCI.poll#start"><a href="LuCI.poll.html#start">start</a></li>
2315 <li data-name="LuCI.poll#stop"><a href="LuCI.poll.html#stop">stop</a></li>
2318 <ul class="events itemMembers">
2323 <li class="item" data-name="LuCI.request">
2324 <span class="title">
2325 <a href="LuCI.request.html">LuCI.request</a>
2328 <ul class="members itemMembers">
2331 <ul class="typedefs itemMembers">
2333 <span class="subtitle">Typedefs</span>
2335 <li data-name="LuCI.request.interceptorFn"><a href="LuCI.request.html#.interceptorFn">interceptorFn</a></li>
2337 <li data-name="LuCI.request.RequestOptions"><a href="LuCI.request.html#.RequestOptions">RequestOptions</a></li>
2340 <ul class="typedefs itemMembers">
2343 <ul class="methods itemMembers">
2345 <span class="subtitle">Methods</span>
2347 <li data-name="LuCI.request#addInterceptor"><a href="LuCI.request.html#addInterceptor">addInterceptor</a></li>
2349 <li data-name="LuCI.request#expandURL"><a href="LuCI.request.html#expandURL">expandURL</a></li>
2351 <li data-name="LuCI.request#get"><a href="LuCI.request.html#get">get</a></li>
2353 <li data-name="LuCI.request#post"><a href="LuCI.request.html#post">post</a></li>
2355 <li data-name="LuCI.request#removeInterceptor"><a href="LuCI.request.html#removeInterceptor">removeInterceptor</a></li>
2357 <li data-name="LuCI.request#request"><a href="LuCI.request.html#request">request</a></li>
2360 <ul class="events itemMembers">
2365 <li class="item" data-name="LuCI.request.poll">
2366 <span class="title">
2367 <a href="LuCI.request.poll.html">LuCI.request.poll</a>
2370 <ul class="members itemMembers">
2373 <ul class="typedefs itemMembers">
2375 <span class="subtitle">Typedefs</span>
2377 <li data-name="LuCI.request.poll~callbackFn"><a href="LuCI.request.poll.html#~callbackFn">callbackFn</a></li>
2380 <ul class="typedefs itemMembers">
2383 <ul class="methods itemMembers">
2385 <span class="subtitle">Methods</span>
2387 <li data-name="LuCI.request.poll#active"><a href="LuCI.request.poll.html#active">active</a></li>
2389 <li data-name="LuCI.request.poll#add"><a href="LuCI.request.poll.html#add">add</a></li>
2391 <li data-name="LuCI.request.poll#remove"><a href="LuCI.request.poll.html#remove">remove</a></li>
2393 <li data-name="LuCI.request.poll#start"><a href="LuCI.request.poll.html#start">start</a></li>
2395 <li data-name="LuCI.request.poll#stop"><a href="LuCI.request.poll.html#stop">stop</a></li>
2398 <ul class="events itemMembers">
2403 <li class="item" data-name="LuCI.response">
2404 <span class="title">
2405 <a href="LuCI.response.html">LuCI.response</a>
2408 <ul class="members itemMembers">
2410 <span class="subtitle">Members</span>
2412 <li data-name="LuCI.response#duration"><a href="LuCI.response.html#duration">duration</a></li>
2414 <li data-name="LuCI.response#headers"><a href="LuCI.response.html#headers">headers</a></li>
2416 <li data-name="LuCI.response#ok"><a href="LuCI.response.html#ok">ok</a></li>
2418 <li data-name="LuCI.response#status"><a href="LuCI.response.html#status">status</a></li>
2420 <li data-name="LuCI.response#statusText"><a href="LuCI.response.html#statusText">statusText</a></li>
2422 <li data-name="LuCI.response#url"><a href="LuCI.response.html#url">url</a></li>
2425 <ul class="typedefs itemMembers">
2428 <ul class="typedefs itemMembers">
2431 <ul class="methods itemMembers">
2433 <span class="subtitle">Methods</span>
2435 <li data-name="LuCI.response#blob"><a href="LuCI.response.html#blob">blob</a></li>
2437 <li data-name="LuCI.response#clone"><a href="LuCI.response.html#clone">clone</a></li>
2439 <li data-name="LuCI.response#json"><a href="LuCI.response.html#json">json</a></li>
2441 <li data-name="LuCI.response#text"><a href="LuCI.response.html#text">text</a></li>
2444 <ul class="events itemMembers">
2449 <li class="item" data-name="LuCI.rpc">
2450 <span class="title">
2451 <a href="LuCI.rpc.html">LuCI.rpc</a>
2454 <ul class="members itemMembers">
2457 <ul class="typedefs itemMembers">
2459 <span class="subtitle">Typedefs</span>
2461 <li data-name="LuCI.rpc.DeclareOptions"><a href="LuCI.rpc.html#.DeclareOptions">DeclareOptions</a></li>
2463 <li data-name="LuCI.rpc~filterFn"><a href="LuCI.rpc.html#~filterFn">filterFn</a></li>
2465 <li data-name="LuCI.rpc~interceptorFn"><a href="LuCI.rpc.html#~interceptorFn">interceptorFn</a></li>
2467 <li data-name="LuCI.rpc~invokeFn"><a href="LuCI.rpc.html#~invokeFn">invokeFn</a></li>
2470 <ul class="typedefs itemMembers">
2473 <ul class="methods itemMembers">
2475 <span class="subtitle">Methods</span>
2477 <li data-name="LuCI.rpc#addInterceptor"><a href="LuCI.rpc.html#addInterceptor">addInterceptor</a></li>
2479 <li data-name="LuCI.rpc#declare"><a href="LuCI.rpc.html#declare">declare</a></li>
2481 <li data-name="LuCI.rpc#getBaseURL"><a href="LuCI.rpc.html#getBaseURL">getBaseURL</a></li>
2483 <li data-name="LuCI.rpc#getSessionID"><a href="LuCI.rpc.html#getSessionID">getSessionID</a></li>
2485 <li data-name="LuCI.rpc#getStatusText"><a href="LuCI.rpc.html#getStatusText">getStatusText</a></li>
2487 <li data-name="LuCI.rpc#list"><a href="LuCI.rpc.html#list">list</a></li>
2489 <li data-name="LuCI.rpc#removeInterceptor"><a href="LuCI.rpc.html#removeInterceptor">removeInterceptor</a></li>
2491 <li data-name="LuCI.rpc#setBaseURL"><a href="LuCI.rpc.html#setBaseURL">setBaseURL</a></li>
2493 <li data-name="LuCI.rpc#setSessionID"><a href="LuCI.rpc.html#setSessionID">setSessionID</a></li>
2496 <ul class="events itemMembers">
2501 <li class="item" data-name="LuCI.session">
2502 <span class="title">
2503 <a href="LuCI.session.html">LuCI.session</a>
2506 <ul class="members itemMembers">
2509 <ul class="typedefs itemMembers">
2512 <ul class="typedefs itemMembers">
2515 <ul class="methods itemMembers">
2517 <span class="subtitle">Methods</span>
2519 <li data-name="LuCI.session#getID"><a href="LuCI.session.html#getID">getID</a></li>
2521 <li data-name="LuCI.session#getLocalData"><a href="LuCI.session.html#getLocalData">getLocalData</a></li>
2523 <li data-name="LuCI.session#setLocalData"><a href="LuCI.session.html#setLocalData">setLocalData</a></li>
2526 <ul class="events itemMembers">
2531 <li class="item" data-name="LuCI.uci">
2532 <span class="title">
2533 <a href="LuCI.uci.html">LuCI.uci</a>
2536 <ul class="members itemMembers">
2539 <ul class="typedefs itemMembers">
2541 <span class="subtitle">Typedefs</span>
2543 <li data-name="LuCI.uci.ChangeRecord"><a href="LuCI.uci.html#.ChangeRecord">ChangeRecord</a></li>
2545 <li data-name="LuCI.uci.SectionObject"><a href="LuCI.uci.html#.SectionObject">SectionObject</a></li>
2547 <li data-name="LuCI.uci~sectionsFn"><a href="LuCI.uci.html#~sectionsFn">sectionsFn</a></li>
2550 <ul class="typedefs itemMembers">
2553 <ul class="methods itemMembers">
2555 <span class="subtitle">Methods</span>
2557 <li data-name="LuCI.uci#add"><a href="LuCI.uci.html#add">add</a></li>
2559 <li data-name="LuCI.uci#apply"><a href="LuCI.uci.html#apply">apply</a></li>
2561 <li data-name="LuCI.uci#changes"><a href="LuCI.uci.html#changes">changes</a></li>
2563 <li data-name="LuCI.uci#createSID"><a href="LuCI.uci.html#createSID">createSID</a></li>
2565 <li data-name="LuCI.uci#get"><a href="LuCI.uci.html#get">get</a></li>
2567 <li data-name="LuCI.uci#get_first"><a href="LuCI.uci.html#get_first">get_first</a></li>
2569 <li data-name="LuCI.uci#load"><a href="LuCI.uci.html#load">load</a></li>
2571 <li data-name="LuCI.uci#move"><a href="LuCI.uci.html#move">move</a></li>
2573 <li data-name="LuCI.uci#remove"><a href="LuCI.uci.html#remove">remove</a></li>
2575 <li data-name="LuCI.uci#resolveSID"><a href="LuCI.uci.html#resolveSID">resolveSID</a></li>
2577 <li data-name="LuCI.uci#save"><a href="LuCI.uci.html#save">save</a></li>
2579 <li data-name="LuCI.uci#sections"><a href="LuCI.uci.html#sections">sections</a></li>
2581 <li data-name="LuCI.uci#set"><a href="LuCI.uci.html#set">set</a></li>
2583 <li data-name="LuCI.uci#set_first"><a href="LuCI.uci.html#set_first">set_first</a></li>
2585 <li data-name="LuCI.uci#unload"><a href="LuCI.uci.html#unload">unload</a></li>
2587 <li data-name="LuCI.uci#unset"><a href="LuCI.uci.html#unset">unset</a></li>
2589 <li data-name="LuCI.uci#unset_first"><a href="LuCI.uci.html#unset_first">unset_first</a></li>
2592 <ul class="events itemMembers">
2597 <li class="item" data-name="LuCI.ui">
2598 <span class="title">
2599 <a href="LuCI.ui.html">LuCI.ui</a>
2602 <ul class="members itemMembers">
2605 <ul class="typedefs itemMembers">
2607 <span class="subtitle">Typedefs</span>
2609 <li data-name="LuCI.ui.FileUploadReply"><a href="LuCI.ui.html#.FileUploadReply">FileUploadReply</a></li>
2612 <ul class="typedefs itemMembers">
2615 <ul class="methods itemMembers">
2617 <span class="subtitle">Methods</span>
2619 <li data-name="LuCI.ui#addNotification"><a href="LuCI.ui.html#addNotification">addNotification</a></li>
2621 <li data-name="LuCI.ui#addValidator"><a href="LuCI.ui.html#addValidator">addValidator</a></li>
2623 <li data-name="LuCI.ui#awaitReconnect"><a href="LuCI.ui.html#awaitReconnect">awaitReconnect</a></li>
2625 <li data-name="LuCI.ui#createHandlerFn"><a href="LuCI.ui.html#createHandlerFn">createHandlerFn</a></li>
2627 <li data-name="LuCI.ui#hideIndicator"><a href="LuCI.ui.html#hideIndicator">hideIndicator</a></li>
2629 <li data-name="LuCI.ui#hideModal"><a href="LuCI.ui.html#hideModal">hideModal</a></li>
2631 <li data-name="LuCI.ui#instantiateView"><a href="LuCI.ui.html#instantiateView">instantiateView</a></li>
2633 <li data-name="LuCI.ui#itemlist"><a href="LuCI.ui.html#itemlist">itemlist</a></li>
2635 <li data-name="LuCI.ui#pingDevice"><a href="LuCI.ui.html#pingDevice">pingDevice</a></li>
2637 <li data-name="LuCI.ui#showIndicator"><a href="LuCI.ui.html#showIndicator">showIndicator</a></li>
2639 <li data-name="LuCI.ui#showModal"><a href="LuCI.ui.html#showModal">showModal</a></li>
2641 <li data-name="LuCI.ui#uploadFile"><a href="LuCI.ui.html#uploadFile">uploadFile</a></li>
2644 <ul class="events itemMembers">
2649 <li class="item" data-name="LuCI.ui.AbstractElement">
2650 <span class="title">
2651 <a href="LuCI.ui.AbstractElement.html">LuCI.ui.AbstractElement</a>
2654 <ul class="members itemMembers">
2657 <ul class="typedefs itemMembers">
2659 <span class="subtitle">Typedefs</span>
2661 <li data-name="LuCI.ui.AbstractElement.InitOptions"><a href="LuCI.ui.AbstractElement.html#.InitOptions">InitOptions</a></li>
2664 <ul class="typedefs itemMembers">
2667 <ul class="methods itemMembers">
2669 <span class="subtitle">Methods</span>
2671 <li data-name="LuCI.ui.AbstractElement#getValue"><a href="LuCI.ui.AbstractElement.html#getValue">getValue</a></li>
2673 <li data-name="LuCI.ui.AbstractElement#isValid"><a href="LuCI.ui.AbstractElement.html#isValid">isValid</a></li>
2675 <li data-name="LuCI.ui.AbstractElement#registerEvents"><a href="LuCI.ui.AbstractElement.html#registerEvents">registerEvents</a></li>
2677 <li data-name="LuCI.ui.AbstractElement#render"><a href="LuCI.ui.AbstractElement.html#render">render</a></li>
2679 <li data-name="LuCI.ui.AbstractElement#setChangeEvents"><a href="LuCI.ui.AbstractElement.html#setChangeEvents">setChangeEvents</a></li>
2681 <li data-name="LuCI.ui.AbstractElement#setUpdateEvents"><a href="LuCI.ui.AbstractElement.html#setUpdateEvents">setUpdateEvents</a></li>
2683 <li data-name="LuCI.ui.AbstractElement#setValue"><a href="LuCI.ui.AbstractElement.html#setValue">setValue</a></li>
2685 <li data-name="LuCI.ui.AbstractElement#triggerValidation"><a href="LuCI.ui.AbstractElement.html#triggerValidation">triggerValidation</a></li>
2688 <ul class="events itemMembers">
2693 <li class="item" data-name="LuCI.ui.changes">
2694 <span class="title">
2695 <a href="LuCI.ui.changes.html">LuCI.ui.changes</a>
2698 <ul class="members itemMembers">
2701 <ul class="typedefs itemMembers">
2704 <ul class="typedefs itemMembers">
2707 <ul class="methods itemMembers">
2709 <span class="subtitle">Methods</span>
2711 <li data-name="LuCI.ui.changes#apply"><a href="LuCI.ui.changes.html#apply">apply</a></li>
2713 <li data-name="LuCI.ui.changes#displayChanges"><a href="LuCI.ui.changes.html#displayChanges">displayChanges</a></li>
2715 <li data-name="LuCI.ui.changes#renderChangeIndicator"><a href="LuCI.ui.changes.html#renderChangeIndicator">renderChangeIndicator</a></li>
2717 <li data-name="LuCI.ui.changes#revert"><a href="LuCI.ui.changes.html#revert">revert</a></li>
2719 <li data-name="LuCI.ui.changes#setIndicator"><a href="LuCI.ui.changes.html#setIndicator">setIndicator</a></li>
2722 <ul class="events itemMembers">
2727 <li class="item" data-name="LuCI.ui.Checkbox">
2728 <span class="title">
2729 <a href="LuCI.ui.Checkbox.html">LuCI.ui.Checkbox</a>
2732 <ul class="members itemMembers">
2735 <ul class="typedefs itemMembers">
2737 <span class="subtitle">Typedefs</span>
2739 <li data-name="LuCI.ui.Checkbox.InitOptions"><a href="LuCI.ui.Checkbox.html#.InitOptions">InitOptions</a></li>
2742 <ul class="typedefs itemMembers">
2745 <ul class="methods itemMembers">
2747 <span class="subtitle">Methods</span>
2749 <li data-name="LuCI.ui.Checkbox#getValue"><a href="LuCI.ui.Checkbox.html#getValue">getValue</a></li>
2751 <li data-name="LuCI.ui.Checkbox#isChecked"><a href="LuCI.ui.Checkbox.html#isChecked">isChecked</a></li>
2753 <li data-name="LuCI.ui.Checkbox#isValid"><a href="LuCI.ui.Checkbox.html#isValid">isValid</a></li>
2755 <li data-name="LuCI.ui.Checkbox#registerEvents"><a href="LuCI.ui.Checkbox.html#registerEvents">registerEvents</a></li>
2757 <li data-name="LuCI.ui.Checkbox#render"><a href="LuCI.ui.Checkbox.html#render">render</a></li>
2759 <li data-name="LuCI.ui.Checkbox#setChangeEvents"><a href="LuCI.ui.Checkbox.html#setChangeEvents">setChangeEvents</a></li>
2761 <li data-name="LuCI.ui.Checkbox#setUpdateEvents"><a href="LuCI.ui.Checkbox.html#setUpdateEvents">setUpdateEvents</a></li>
2763 <li data-name="LuCI.ui.Checkbox#setValue"><a href="LuCI.ui.Checkbox.html#setValue">setValue</a></li>
2765 <li data-name="LuCI.ui.Checkbox#triggerValidation"><a href="LuCI.ui.Checkbox.html#triggerValidation">triggerValidation</a></li>
2768 <ul class="events itemMembers">
2773 <li class="item" data-name="LuCI.ui.Combobox">
2774 <span class="title">
2775 <a href="LuCI.ui.Combobox.html">LuCI.ui.Combobox</a>
2778 <ul class="members itemMembers">
2781 <ul class="typedefs itemMembers">
2783 <span class="subtitle">Typedefs</span>
2785 <li data-name="LuCI.ui.Combobox.InitOptions"><a href="LuCI.ui.Combobox.html#.InitOptions">InitOptions</a></li>
2788 <ul class="typedefs itemMembers">
2791 <ul class="methods itemMembers">
2793 <span class="subtitle">Methods</span>
2795 <li data-name="LuCI.ui.Combobox#addChoices"><a href="LuCI.ui.Combobox.html#addChoices">addChoices</a></li>
2797 <li data-name="LuCI.ui.Combobox#clearChoices"><a href="LuCI.ui.Combobox.html#clearChoices">clearChoices</a></li>
2799 <li data-name="LuCI.ui.Combobox#closeAllDropdowns"><a href="LuCI.ui.Combobox.html#closeAllDropdowns">closeAllDropdowns</a></li>
2801 <li data-name="LuCI.ui.Combobox#isValid"><a href="LuCI.ui.Combobox.html#isValid">isValid</a></li>
2803 <li data-name="LuCI.ui.Combobox#registerEvents"><a href="LuCI.ui.Combobox.html#registerEvents">registerEvents</a></li>
2805 <li data-name="LuCI.ui.Combobox#setChangeEvents"><a href="LuCI.ui.Combobox.html#setChangeEvents">setChangeEvents</a></li>
2807 <li data-name="LuCI.ui.Combobox#setUpdateEvents"><a href="LuCI.ui.Combobox.html#setUpdateEvents">setUpdateEvents</a></li>
2809 <li data-name="LuCI.ui.Combobox#triggerValidation"><a href="LuCI.ui.Combobox.html#triggerValidation">triggerValidation</a></li>
2812 <ul class="events itemMembers">
2817 <li class="item" data-name="LuCI.ui.ComboButton">
2818 <span class="title">
2819 <a href="LuCI.ui.ComboButton.html">LuCI.ui.ComboButton</a>
2822 <ul class="members itemMembers">
2825 <ul class="typedefs itemMembers">
2827 <span class="subtitle">Typedefs</span>
2829 <li data-name="LuCI.ui.ComboButton.InitOptions"><a href="LuCI.ui.ComboButton.html#.InitOptions">InitOptions</a></li>
2832 <ul class="typedefs itemMembers">
2835 <ul class="methods itemMembers">
2837 <span class="subtitle">Methods</span>
2839 <li data-name="LuCI.ui.ComboButton#addChoices"><a href="LuCI.ui.ComboButton.html#addChoices">addChoices</a></li>
2841 <li data-name="LuCI.ui.ComboButton#clearChoices"><a href="LuCI.ui.ComboButton.html#clearChoices">clearChoices</a></li>
2843 <li data-name="LuCI.ui.ComboButton#closeAllDropdowns"><a href="LuCI.ui.ComboButton.html#closeAllDropdowns">closeAllDropdowns</a></li>
2845 <li data-name="LuCI.ui.ComboButton#isValid"><a href="LuCI.ui.ComboButton.html#isValid">isValid</a></li>
2847 <li data-name="LuCI.ui.ComboButton#registerEvents"><a href="LuCI.ui.ComboButton.html#registerEvents">registerEvents</a></li>
2849 <li data-name="LuCI.ui.ComboButton#setChangeEvents"><a href="LuCI.ui.ComboButton.html#setChangeEvents">setChangeEvents</a></li>
2851 <li data-name="LuCI.ui.ComboButton#setUpdateEvents"><a href="LuCI.ui.ComboButton.html#setUpdateEvents">setUpdateEvents</a></li>
2853 <li data-name="LuCI.ui.ComboButton#triggerValidation"><a href="LuCI.ui.ComboButton.html#triggerValidation">triggerValidation</a></li>
2856 <ul class="events itemMembers">
2861 <li class="item" data-name="LuCI.ui.Dropdown">
2862 <span class="title">
2863 <a href="LuCI.ui.Dropdown.html">LuCI.ui.Dropdown</a>
2866 <ul class="members itemMembers">
2869 <ul class="typedefs itemMembers">
2871 <span class="subtitle">Typedefs</span>
2873 <li data-name="LuCI.ui.Dropdown.InitOptions"><a href="LuCI.ui.Dropdown.html#.InitOptions">InitOptions</a></li>
2876 <ul class="typedefs itemMembers">
2879 <ul class="methods itemMembers">
2881 <span class="subtitle">Methods</span>
2883 <li data-name="LuCI.ui.Dropdown#addChoices"><a href="LuCI.ui.Dropdown.html#addChoices">addChoices</a></li>
2885 <li data-name="LuCI.ui.Dropdown#clearChoices"><a href="LuCI.ui.Dropdown.html#clearChoices">clearChoices</a></li>
2887 <li data-name="LuCI.ui.Dropdown#closeAllDropdowns"><a href="LuCI.ui.Dropdown.html#closeAllDropdowns">closeAllDropdowns</a></li>
2889 <li data-name="LuCI.ui.Dropdown#getValue"><a href="LuCI.ui.Dropdown.html#getValue">getValue</a></li>
2891 <li data-name="LuCI.ui.Dropdown#isValid"><a href="LuCI.ui.Dropdown.html#isValid">isValid</a></li>
2893 <li data-name="LuCI.ui.Dropdown#registerEvents"><a href="LuCI.ui.Dropdown.html#registerEvents">registerEvents</a></li>
2895 <li data-name="LuCI.ui.Dropdown#render"><a href="LuCI.ui.Dropdown.html#render">render</a></li>
2897 <li data-name="LuCI.ui.Dropdown#setChangeEvents"><a href="LuCI.ui.Dropdown.html#setChangeEvents">setChangeEvents</a></li>
2899 <li data-name="LuCI.ui.Dropdown#setUpdateEvents"><a href="LuCI.ui.Dropdown.html#setUpdateEvents">setUpdateEvents</a></li>
2901 <li data-name="LuCI.ui.Dropdown#setValue"><a href="LuCI.ui.Dropdown.html#setValue">setValue</a></li>
2903 <li data-name="LuCI.ui.Dropdown#triggerValidation"><a href="LuCI.ui.Dropdown.html#triggerValidation">triggerValidation</a></li>
2906 <ul class="events itemMembers">
2911 <li class="item" data-name="LuCI.ui.DynamicList">
2912 <span class="title">
2913 <a href="LuCI.ui.DynamicList.html">LuCI.ui.DynamicList</a>
2916 <ul class="members itemMembers">
2919 <ul class="typedefs itemMembers">
2921 <span class="subtitle">Typedefs</span>
2923 <li data-name="LuCI.ui.DynamicList.InitOptions"><a href="LuCI.ui.DynamicList.html#.InitOptions">InitOptions</a></li>
2926 <ul class="typedefs itemMembers">
2929 <ul class="methods itemMembers">
2931 <span class="subtitle">Methods</span>
2933 <li data-name="LuCI.ui.DynamicList#addChoices"><a href="LuCI.ui.DynamicList.html#addChoices">addChoices</a></li>
2935 <li data-name="LuCI.ui.DynamicList#clearChoices"><a href="LuCI.ui.DynamicList.html#clearChoices">clearChoices</a></li>
2937 <li data-name="LuCI.ui.DynamicList#getValue"><a href="LuCI.ui.DynamicList.html#getValue">getValue</a></li>
2939 <li data-name="LuCI.ui.DynamicList#isValid"><a href="LuCI.ui.DynamicList.html#isValid">isValid</a></li>
2941 <li data-name="LuCI.ui.DynamicList#registerEvents"><a href="LuCI.ui.DynamicList.html#registerEvents">registerEvents</a></li>
2943 <li data-name="LuCI.ui.DynamicList#render"><a href="LuCI.ui.DynamicList.html#render">render</a></li>
2945 <li data-name="LuCI.ui.DynamicList#setChangeEvents"><a href="LuCI.ui.DynamicList.html#setChangeEvents">setChangeEvents</a></li>
2947 <li data-name="LuCI.ui.DynamicList#setUpdateEvents"><a href="LuCI.ui.DynamicList.html#setUpdateEvents">setUpdateEvents</a></li>
2949 <li data-name="LuCI.ui.DynamicList#setValue"><a href="LuCI.ui.DynamicList.html#setValue">setValue</a></li>
2951 <li data-name="LuCI.ui.DynamicList#triggerValidation"><a href="LuCI.ui.DynamicList.html#triggerValidation">triggerValidation</a></li>
2954 <ul class="events itemMembers">
2959 <li class="item" data-name="LuCI.ui.FileUpload">
2960 <span class="title">
2961 <a href="LuCI.ui.FileUpload.html">LuCI.ui.FileUpload</a>
2964 <ul class="members itemMembers">
2967 <ul class="typedefs itemMembers">
2969 <span class="subtitle">Typedefs</span>
2971 <li data-name="LuCI.ui.FileUpload.InitOptions"><a href="LuCI.ui.FileUpload.html#.InitOptions">InitOptions</a></li>
2974 <ul class="typedefs itemMembers">
2977 <ul class="methods itemMembers">
2979 <span class="subtitle">Methods</span>
2981 <li data-name="LuCI.ui.FileUpload#getValue"><a href="LuCI.ui.FileUpload.html#getValue">getValue</a></li>
2983 <li data-name="LuCI.ui.FileUpload#isValid"><a href="LuCI.ui.FileUpload.html#isValid">isValid</a></li>
2985 <li data-name="LuCI.ui.FileUpload#registerEvents"><a href="LuCI.ui.FileUpload.html#registerEvents">registerEvents</a></li>
2987 <li data-name="LuCI.ui.FileUpload#render"><a href="LuCI.ui.FileUpload.html#render">render</a></li>
2989 <li data-name="LuCI.ui.FileUpload#setChangeEvents"><a href="LuCI.ui.FileUpload.html#setChangeEvents">setChangeEvents</a></li>
2991 <li data-name="LuCI.ui.FileUpload#setUpdateEvents"><a href="LuCI.ui.FileUpload.html#setUpdateEvents">setUpdateEvents</a></li>
2993 <li data-name="LuCI.ui.FileUpload#setValue"><a href="LuCI.ui.FileUpload.html#setValue">setValue</a></li>
2995 <li data-name="LuCI.ui.FileUpload#triggerValidation"><a href="LuCI.ui.FileUpload.html#triggerValidation">triggerValidation</a></li>
2998 <ul class="events itemMembers">
3003 <li class="item" data-name="LuCI.ui.Hiddenfield">
3004 <span class="title">
3005 <a href="LuCI.ui.Hiddenfield.html">LuCI.ui.Hiddenfield</a>
3008 <ul class="members itemMembers">
3011 <ul class="typedefs itemMembers">
3014 <ul class="typedefs itemMembers">
3017 <ul class="methods itemMembers">
3019 <span class="subtitle">Methods</span>
3021 <li data-name="LuCI.ui.Hiddenfield#getValue"><a href="LuCI.ui.Hiddenfield.html#getValue">getValue</a></li>
3023 <li data-name="LuCI.ui.Hiddenfield#isValid"><a href="LuCI.ui.Hiddenfield.html#isValid">isValid</a></li>
3025 <li data-name="LuCI.ui.Hiddenfield#registerEvents"><a href="LuCI.ui.Hiddenfield.html#registerEvents">registerEvents</a></li>
3027 <li data-name="LuCI.ui.Hiddenfield#render"><a href="LuCI.ui.Hiddenfield.html#render">render</a></li>
3029 <li data-name="LuCI.ui.Hiddenfield#setChangeEvents"><a href="LuCI.ui.Hiddenfield.html#setChangeEvents">setChangeEvents</a></li>
3031 <li data-name="LuCI.ui.Hiddenfield#setUpdateEvents"><a href="LuCI.ui.Hiddenfield.html#setUpdateEvents">setUpdateEvents</a></li>
3033 <li data-name="LuCI.ui.Hiddenfield#setValue"><a href="LuCI.ui.Hiddenfield.html#setValue">setValue</a></li>
3035 <li data-name="LuCI.ui.Hiddenfield#triggerValidation"><a href="LuCI.ui.Hiddenfield.html#triggerValidation">triggerValidation</a></li>
3038 <ul class="events itemMembers">
3043 <li class="item" data-name="LuCI.ui.menu">
3044 <span class="title">
3045 <a href="LuCI.ui.menu.html">LuCI.ui.menu</a>
3048 <ul class="members itemMembers">
3051 <ul class="typedefs itemMembers">
3053 <span class="subtitle">Typedefs</span>
3055 <li data-name="LuCI.ui.menu.MenuNode"><a href="LuCI.ui.menu.html#.MenuNode">MenuNode</a></li>
3058 <ul class="typedefs itemMembers">
3061 <ul class="methods itemMembers">
3063 <span class="subtitle">Methods</span>
3065 <li data-name="LuCI.ui.menu#getChildren"><a href="LuCI.ui.menu.html#getChildren">getChildren</a></li>
3067 <li data-name="LuCI.ui.menu#load"><a href="LuCI.ui.menu.html#load">load</a></li>
3070 <ul class="events itemMembers">
3075 <li class="item" data-name="LuCI.ui.Select">
3076 <span class="title">
3077 <a href="LuCI.ui.Select.html">LuCI.ui.Select</a>
3080 <ul class="members itemMembers">
3083 <ul class="typedefs itemMembers">
3085 <span class="subtitle">Typedefs</span>
3087 <li data-name="LuCI.ui.Select.InitOptions"><a href="LuCI.ui.Select.html#.InitOptions">InitOptions</a></li>
3090 <ul class="typedefs itemMembers">
3093 <ul class="methods itemMembers">
3095 <span class="subtitle">Methods</span>
3097 <li data-name="LuCI.ui.Select#getValue"><a href="LuCI.ui.Select.html#getValue">getValue</a></li>
3099 <li data-name="LuCI.ui.Select#isValid"><a href="LuCI.ui.Select.html#isValid">isValid</a></li>
3101 <li data-name="LuCI.ui.Select#registerEvents"><a href="LuCI.ui.Select.html#registerEvents">registerEvents</a></li>
3103 <li data-name="LuCI.ui.Select#render"><a href="LuCI.ui.Select.html#render">render</a></li>
3105 <li data-name="LuCI.ui.Select#setChangeEvents"><a href="LuCI.ui.Select.html#setChangeEvents">setChangeEvents</a></li>
3107 <li data-name="LuCI.ui.Select#setUpdateEvents"><a href="LuCI.ui.Select.html#setUpdateEvents">setUpdateEvents</a></li>
3109 <li data-name="LuCI.ui.Select#setValue"><a href="LuCI.ui.Select.html#setValue">setValue</a></li>
3111 <li data-name="LuCI.ui.Select#triggerValidation"><a href="LuCI.ui.Select.html#triggerValidation">triggerValidation</a></li>
3114 <ul class="events itemMembers">
3119 <li class="item" data-name="LuCI.ui.tabs">
3120 <span class="title">
3121 <a href="LuCI.ui.tabs.html">LuCI.ui.tabs</a>
3124 <ul class="members itemMembers">
3127 <ul class="typedefs itemMembers">
3130 <ul class="typedefs itemMembers">
3133 <ul class="methods itemMembers">
3135 <span class="subtitle">Methods</span>
3137 <li data-name="LuCI.ui.tabs#initTabGroup"><a href="LuCI.ui.tabs.html#initTabGroup">initTabGroup</a></li>
3139 <li data-name="LuCI.ui.tabs#isEmptyPane"><a href="LuCI.ui.tabs.html#isEmptyPane">isEmptyPane</a></li>
3142 <ul class="events itemMembers">
3147 <li class="item" data-name="LuCI.ui.Textarea">
3148 <span class="title">
3149 <a href="LuCI.ui.Textarea.html">LuCI.ui.Textarea</a>
3152 <ul class="members itemMembers">
3155 <ul class="typedefs itemMembers">
3157 <span class="subtitle">Typedefs</span>
3159 <li data-name="LuCI.ui.Textarea.InitOptions"><a href="LuCI.ui.Textarea.html#.InitOptions">InitOptions</a></li>
3162 <ul class="typedefs itemMembers">
3165 <ul class="methods itemMembers">
3167 <span class="subtitle">Methods</span>
3169 <li data-name="LuCI.ui.Textarea#getValue"><a href="LuCI.ui.Textarea.html#getValue">getValue</a></li>
3171 <li data-name="LuCI.ui.Textarea#isValid"><a href="LuCI.ui.Textarea.html#isValid">isValid</a></li>
3173 <li data-name="LuCI.ui.Textarea#registerEvents"><a href="LuCI.ui.Textarea.html#registerEvents">registerEvents</a></li>
3175 <li data-name="LuCI.ui.Textarea#render"><a href="LuCI.ui.Textarea.html#render">render</a></li>
3177 <li data-name="LuCI.ui.Textarea#setChangeEvents"><a href="LuCI.ui.Textarea.html#setChangeEvents">setChangeEvents</a></li>
3179 <li data-name="LuCI.ui.Textarea#setUpdateEvents"><a href="LuCI.ui.Textarea.html#setUpdateEvents">setUpdateEvents</a></li>
3181 <li data-name="LuCI.ui.Textarea#setValue"><a href="LuCI.ui.Textarea.html#setValue">setValue</a></li>
3183 <li data-name="LuCI.ui.Textarea#triggerValidation"><a href="LuCI.ui.Textarea.html#triggerValidation">triggerValidation</a></li>
3186 <ul class="events itemMembers">
3191 <li class="item" data-name="LuCI.ui.Textfield">
3192 <span class="title">
3193 <a href="LuCI.ui.Textfield.html">LuCI.ui.Textfield</a>
3196 <ul class="members itemMembers">
3199 <ul class="typedefs itemMembers">
3201 <span class="subtitle">Typedefs</span>
3203 <li data-name="LuCI.ui.Textfield.InitOptions"><a href="LuCI.ui.Textfield.html#.InitOptions">InitOptions</a></li>
3206 <ul class="typedefs itemMembers">
3209 <ul class="methods itemMembers">
3211 <span class="subtitle">Methods</span>
3213 <li data-name="LuCI.ui.Textfield#getValue"><a href="LuCI.ui.Textfield.html#getValue">getValue</a></li>
3215 <li data-name="LuCI.ui.Textfield#isValid"><a href="LuCI.ui.Textfield.html#isValid">isValid</a></li>
3217 <li data-name="LuCI.ui.Textfield#registerEvents"><a href="LuCI.ui.Textfield.html#registerEvents">registerEvents</a></li>
3219 <li data-name="LuCI.ui.Textfield#render"><a href="LuCI.ui.Textfield.html#render">render</a></li>
3221 <li data-name="LuCI.ui.Textfield#setChangeEvents"><a href="LuCI.ui.Textfield.html#setChangeEvents">setChangeEvents</a></li>
3223 <li data-name="LuCI.ui.Textfield#setUpdateEvents"><a href="LuCI.ui.Textfield.html#setUpdateEvents">setUpdateEvents</a></li>
3225 <li data-name="LuCI.ui.Textfield#setValue"><a href="LuCI.ui.Textfield.html#setValue">setValue</a></li>
3227 <li data-name="LuCI.ui.Textfield#triggerValidation"><a href="LuCI.ui.Textfield.html#triggerValidation">triggerValidation</a></li>
3230 <ul class="events itemMembers">
3235 <li class="item" data-name="LuCI.view">
3236 <span class="title">
3237 <a href="LuCI.view.html">LuCI.view</a>
3240 <ul class="members itemMembers">
3243 <ul class="typedefs itemMembers">
3246 <ul class="typedefs itemMembers">
3249 <ul class="methods itemMembers">
3251 <span class="subtitle">Methods</span>
3253 <li data-name="LuCI.view#addFooter"><a href="LuCI.view.html#addFooter">addFooter</a></li>
3255 <li data-name="LuCI.view#handleReset"><a href="LuCI.view.html#handleReset">handleReset</a></li>
3257 <li data-name="LuCI.view#handleSave"><a href="LuCI.view.html#handleSave">handleSave</a></li>
3259 <li data-name="LuCI.view#handleSaveApply"><a href="LuCI.view.html#handleSaveApply">handleSaveApply</a></li>
3261 <li data-name="LuCI.view#load"><a href="LuCI.view.html#load">load</a></li>
3263 <li data-name="LuCI.view#render"><a href="LuCI.view.html#render">render</a></li>
3266 <ul class="events itemMembers">
3271 <li class="item" data-name="LuCI.xhr">
3272 <span class="title">
3273 <a href="LuCI.xhr.html">LuCI.xhr</a>
3276 <ul class="members itemMembers">
3279 <ul class="typedefs itemMembers">
3282 <ul class="typedefs itemMembers">
3285 <ul class="methods itemMembers">
3287 <span class="subtitle">Methods</span>
3289 <li data-name="LuCI.xhr#abort"><a href="LuCI.xhr.html#abort">abort</a></li>
3291 <li data-name="LuCI.xhr#busy"><a href="LuCI.xhr.html#busy">busy</a></li>
3293 <li data-name="LuCI.xhr#cancel"><a href="LuCI.xhr.html#cancel">cancel</a></li>
3295 <li data-name="LuCI.xhr#get"><a href="LuCI.xhr.html#get">get</a></li>
3297 <li data-name="LuCI.xhr#post"><a href="LuCI.xhr.html#post">post</a></li>
3299 <li data-name="LuCI.xhr#send_form"><a href="LuCI.xhr.html#send_form">send_form</a></li>
3302 <ul class="events itemMembers">
3310 <h1 class="page-title" data-filename="ui.js.html">Source: ui.js</h1>
3317 <pre id="source-code" class="prettyprint source "><code>'use strict';
3318 'require validation';
3319 'require baseclass';
3328 var modalDiv = null,
3330 indicatorDiv = null,
3331 tooltipTimeout = null;
3334 * @class AbstractElement
3339 * The `AbstractElement` class serves as abstract base for the different widgets
3340 * implemented by `LuCI.ui`. It provides the common logic for getting and
3341 * setting values, for checking the validity state and for wiring up required
3344 * UI widget instances are usually not supposed to be created by view code
3345 * directly, instead they're implicitely created by `LuCI.form` when
3346 * instantiating CBI forms.
3348 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3349 * in views, use `'require ui'` and refer to `ui.AbstractElement`. To import
3350 * it in external JavaScript, use `L.require("ui").then(...)` and access the
3351 * `AbstractElement` property of the class instance value.
3353 var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ {
3355 * @typedef {Object} InitOptions
3356 * @memberof LuCI.ui.AbstractElement
3358 * @property {string} [id]
3359 * Specifies the widget ID to use. It will be used as HTML `id` attribute
3360 * on the toplevel widget DOM node.
3362 * @property {string} [name]
3363 * Specifies the widget name which is set as HTML `name` attribute on the
3364 * corresponding `<input>` element.
3366 * @property {boolean} [optional=true]
3367 * Specifies whether the input field allows empty values.
3369 * @property {string} [datatype=string]
3370 * An expression describing the input data validation constraints.
3371 * It defaults to `string` which will allow any value.
3372 * See {@link LuCI.validation} for details on the expression format.
3374 * @property {function} [validator]
3375 * Specifies a custom validator function which is invoked after the
3376 * standard validation constraints are checked. The function should return
3377 * `true` to accept the given input value. Any other return value type is
3378 * converted to a string and treated as validation error message.
3380 * @property {boolean} [disabled=false]
3381 * Specifies whether the widget should be rendered in disabled state
3382 * (`true`) or not (`false`). Disabled widgets cannot be interacted with
3383 * and are displayed in a slightly faded style.
3387 * Read the current value of the input widget.
3390 * @memberof LuCI.ui.AbstractElement
3391 * @returns {string|string[]|null}
3392 * The current value of the input element. For simple inputs like text
3393 * fields or selects, the return value type will be a - possibly empty -
3394 * string. Complex widgets such as `DynamicList` instances may result in
3395 * an array of strings or `null` for unset values.
3397 getValue: function() {
3398 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3399 return this.node.value;
3405 * Set the current value of the input widget.
3408 * @memberof LuCI.ui.AbstractElement
3409 * @param {string|string[]|null} value
3410 * The value to set the input element to. For simple inputs like text
3411 * fields or selects, the value should be a - possibly empty - string.
3412 * Complex widgets such as `DynamicList` instances may accept string array
3415 setValue: function(value) {
3416 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3417 this.node.value = value;
3421 * Check whether the current input value is valid.
3424 * @memberof LuCI.ui.AbstractElement
3425 * @returns {boolean}
3426 * Returns `true` if the current input value is valid or `false` if it does
3427 * not meet the validation constraints.
3429 isValid: function() {
3430 return (this.validState !== false);
3434 * Force validation of the current input value.
3436 * Usually input validation is automatically triggered by various DOM events
3437 * bound to the input widget. In some cases it is required though to manually
3438 * trigger validation runs, e.g. when programmatically altering values.
3441 * @memberof LuCI.ui.AbstractElement
3443 triggerValidation: function() {
3444 if (typeof(this.vfunc) != 'function')
3447 var wasValid = this.isValid();
3451 return (wasValid != this.isValid());
3455 * Dispatch a custom (synthetic) event in response to received events.
3457 * Sets up event handlers on the given target DOM node for the given event
3458 * names that dispatch a custom event of the given type to the widget root
3461 * The primary purpose of this function is to set up a series of custom
3462 * uniform standard events such as `widget-update`, `validation-success`,
3463 * `validation-failure` etc. which are triggered by various different
3464 * widget specific native DOM events.
3467 * @memberof LuCI.ui.AbstractElement
3468 * @param {Node} targetNode
3469 * Specifies the DOM node on which the native event listeners should be
3472 * @param {string} synevent
3473 * The name of the custom event to dispatch to the widget root DOM node.
3475 * @param {string[]} events
3476 * The native DOM events for which event handlers should be registered.
3478 registerEvents: function(targetNode, synevent, events) {
3479 var dispatchFn = L.bind(function(ev) {
3480 this.node.dispatchEvent(new CustomEvent(synevent, { bubbles: true }));
3483 for (var i = 0; i < events.length; i++)
3484 targetNode.addEventListener(events[i], dispatchFn);
3488 * Setup listeners for native DOM events that may update the widget value.
3490 * Sets up event handlers on the given target DOM node for the given event
3491 * names which may cause the input value to update, such as `keyup` or
3492 * `onclick` events. In contrast to change events, such update events will
3493 * trigger input value validation.
3496 * @memberof LuCI.ui.AbstractElement
3497 * @param {Node} targetNode
3498 * Specifies the DOM node on which the event listeners should be registered.
3500 * @param {...string} events
3501 * The DOM events for which event handlers should be registered.
3503 setUpdateEvents: function(targetNode /*, ... */) {
3504 var datatype = this.options.datatype,
3505 optional = this.options.hasOwnProperty('optional') ? this.options.optional : true,
3506 validate = this.options.validate,
3507 events = this.varargs(arguments, 1);
3509 this.registerEvents(targetNode, 'widget-update', events);
3511 if (!datatype && !validate)
3514 this.vfunc = UI.prototype.addValidator.apply(UI.prototype, [
3515 targetNode, datatype || 'string',
3519 this.node.addEventListener('validation-success', L.bind(function(ev) {
3520 this.validState = true;
3523 this.node.addEventListener('validation-failure', L.bind(function(ev) {
3524 this.validState = false;
3529 * Setup listeners for native DOM events that may change the widget value.
3531 * Sets up event handlers on the given target DOM node for the given event
3532 * names which may cause the input value to change completely, such as
3533 * `change` events in a select menu. In contrast to update events, such
3534 * change events will not trigger input value validation but they may cause
3535 * field dependencies to get re-evaluated and will mark the input widget
3539 * @memberof LuCI.ui.AbstractElement
3540 * @param {Node} targetNode
3541 * Specifies the DOM node on which the event listeners should be registered.
3543 * @param {...string} events
3544 * The DOM events for which event handlers should be registered.
3546 setChangeEvents: function(targetNode /*, ... */) {
3547 var tag_changed = L.bind(function(ev) { this.setAttribute('data-changed', true) }, this.node);
3549 for (var i = 1; i < arguments.length; i++)
3550 targetNode.addEventListener(arguments[i], tag_changed);
3552 this.registerEvents(targetNode, 'widget-change', this.varargs(arguments, 1));
3556 * Render the widget, setup event listeners and return resulting markup.
3559 * @memberof LuCI.ui.AbstractElement
3562 * Returns a DOM Node or DocumentFragment containing the rendered
3565 render: function() {}
3569 * Instantiate a text input widget.
3571 * @constructor Textfield
3573 * @augments LuCI.ui.AbstractElement
3577 * The `Textfield` class implements a standard single line text input field.
3579 * UI widget instances are usually not supposed to be created by view code
3580 * directly, instead they're implicitely created by `LuCI.form` when
3581 * instantiating CBI forms.
3583 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3584 * in views, use `'require ui'` and refer to `ui.Textfield`. To import it in
3585 * external JavaScript, use `L.require("ui").then(...)` and access the
3586 * `Textfield` property of the class instance value.
3588 * @param {string} [value=null]
3589 * The initial input value.
3591 * @param {LuCI.ui.Textfield.InitOptions} [options]
3592 * Object describing the widget specific options to initialize the input.
3594 var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ {
3596 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3597 * the following properties are recognized:
3599 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3600 * @memberof LuCI.ui.Textfield
3602 * @property {boolean} [password=false]
3603 * Specifies whether the input should be rendered as concealed password field.
3605 * @property {boolean} [readonly=false]
3606 * Specifies whether the input widget should be rendered readonly.
3608 * @property {number} [maxlength]
3609 * Specifies the HTML `maxlength` attribute to set on the corresponding
3610 * `<input>` element. Note that this a legacy property that exists for
3611 * compatibility reasons. It is usually better to `maxlength(N)` validation
3614 * @property {string} [placeholder]
3615 * Specifies the HTML `placeholder` attribute which is displayed when the
3616 * corresponding `<input>` element is empty.
3618 __init__: function(value, options) {
3620 this.options = Object.assign({
3627 render: function() {
3628 var frameEl = E('div', { 'id': this.options.id });
3630 if (this.options.password) {
3631 frameEl.classList.add('nowrap');
3632 frameEl.appendChild(E('input', {
3634 'style': 'position:absolute; left:-100000px',
3635 'aria-hidden': true,
3637 'name': this.options.name ? 'password.%s'.format(this.options.name) : null
3641 frameEl.appendChild(E('input', {
3642 'id': this.options.id ? 'widget.' + this.options.id : null,
3643 'name': this.options.name,
3644 'type': this.options.password ? 'password' : 'text',
3645 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text',
3646 'readonly': this.options.readonly ? '' : null,
3647 'disabled': this.options.disabled ? '' : null,
3648 'maxlength': this.options.maxlength,
3649 'placeholder': this.options.placeholder,
3650 'value': this.value,
3653 if (this.options.password)
3654 frameEl.appendChild(E('button', {
3655 'class': 'cbi-button cbi-button-neutral',
3656 'title': _('Reveal/hide password'),
3657 'aria-label': _('Reveal/hide password'),
3658 'click': function(ev) {
3659 var e = this.previousElementSibling;
3660 e.type = (e.type === 'password') ? 'text' : 'password';
3661 ev.preventDefault();
3665 return this.bind(frameEl);
3669 bind: function(frameEl) {
3670 var inputEl = frameEl.childNodes[+!!this.options.password];
3672 this.node = frameEl;
3674 this.setUpdateEvents(inputEl, 'keyup', 'blur');
3675 this.setChangeEvents(inputEl, 'change');
3677 dom.bindClassInstance(frameEl, this);
3683 getValue: function() {
3684 var inputEl = this.node.childNodes[+!!this.options.password];
3685 return inputEl.value;
3689 setValue: function(value) {
3690 var inputEl = this.node.childNodes[+!!this.options.password];
3691 inputEl.value = value;
3696 * Instantiate a textarea widget.
3698 * @constructor Textarea
3700 * @augments LuCI.ui.AbstractElement
3704 * The `Textarea` class implements a multiline text area input field.
3706 * UI widget instances are usually not supposed to be created by view code
3707 * directly, instead they're implicitely created by `LuCI.form` when
3708 * instantiating CBI forms.
3710 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3711 * in views, use `'require ui'` and refer to `ui.Textarea`. To import it in
3712 * external JavaScript, use `L.require("ui").then(...)` and access the
3713 * `Textarea` property of the class instance value.
3715 * @param {string} [value=null]
3716 * The initial input value.
3718 * @param {LuCI.ui.Textarea.InitOptions} [options]
3719 * Object describing the widget specific options to initialize the input.
3721 var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ {
3723 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3724 * the following properties are recognized:
3726 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3727 * @memberof LuCI.ui.Textarea
3729 * @property {boolean} [readonly=false]
3730 * Specifies whether the input widget should be rendered readonly.
3732 * @property {string} [placeholder]
3733 * Specifies the HTML `placeholder` attribute which is displayed when the
3734 * corresponding `<textarea>` element is empty.
3736 * @property {boolean} [monospace=false]
3737 * Specifies whether a monospace font should be forced for the textarea
3740 * @property {number} [cols]
3741 * Specifies the HTML `cols` attribute to set on the corresponding
3742 * `<textarea>` element.
3744 * @property {number} [rows]
3745 * Specifies the HTML `rows` attribute to set on the corresponding
3746 * `<textarea>` element.
3748 * @property {boolean} [wrap=false]
3749 * Specifies whether the HTML `wrap` attribute should be set.
3751 __init__: function(value, options) {
3753 this.options = Object.assign({
3762 render: function() {
3763 var frameEl = E('div', { 'id': this.options.id }),
3764 value = (this.value != null) ? String(this.value) : '';
3766 frameEl.appendChild(E('textarea', {
3767 'id': this.options.id ? 'widget.' + this.options.id : null,
3768 'name': this.options.name,
3769 'class': 'cbi-input-textarea',
3770 'readonly': this.options.readonly ? '' : null,
3771 'disabled': this.options.disabled ? '' : null,
3772 'placeholder': this.options.placeholder,
3773 'style': !this.options.cols ? 'width:100%' : null,
3774 'cols': this.options.cols,
3775 'rows': this.options.rows,
3776 'wrap': this.options.wrap ? '' : null
3779 if (this.options.monospace)
3780 frameEl.firstElementChild.style.fontFamily = 'monospace';
3782 return this.bind(frameEl);
3786 bind: function(frameEl) {
3787 var inputEl = frameEl.firstElementChild;
3789 this.node = frameEl;
3791 this.setUpdateEvents(inputEl, 'keyup', 'blur');
3792 this.setChangeEvents(inputEl, 'change');
3794 dom.bindClassInstance(frameEl, this);
3800 getValue: function() {
3801 return this.node.firstElementChild.value;
3805 setValue: function(value) {
3806 this.node.firstElementChild.value = value;
3811 * Instantiate a checkbox widget.
3813 * @constructor Checkbox
3815 * @augments LuCI.ui.AbstractElement
3819 * The `Checkbox` class implements a simple checkbox input field.
3821 * UI widget instances are usually not supposed to be created by view code
3822 * directly, instead they're implicitely created by `LuCI.form` when
3823 * instantiating CBI forms.
3825 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3826 * in views, use `'require ui'` and refer to `ui.Checkbox`. To import it in
3827 * external JavaScript, use `L.require("ui").then(...)` and access the
3828 * `Checkbox` property of the class instance value.
3830 * @param {string} [value=null]
3831 * The initial input value.
3833 * @param {LuCI.ui.Checkbox.InitOptions} [options]
3834 * Object describing the widget specific options to initialize the input.
3836 var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ {
3838 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3839 * the following properties are recognized:
3841 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3842 * @memberof LuCI.ui.Checkbox
3844 * @property {string} [value_enabled=1]
3845 * Specifies the value corresponding to a checked checkbox.
3847 * @property {string} [value_disabled=0]
3848 * Specifies the value corresponding to an unchecked checkbox.
3850 * @property {string} [hiddenname]
3851 * Specifies the HTML `name` attribute of the hidden input backing the
3852 * checkbox. This is a legacy property existing for compatibility reasons,
3853 * it is required for HTML based form submissions.
3855 __init__: function(value, options) {
3857 this.options = Object.assign({
3864 render: function() {
3865 var id = 'cb%08x'.format(Math.random() * 0xffffffff);
3866 var frameEl = E('div', {
3867 'id': this.options.id,
3868 'class': 'cbi-checkbox'
3871 if (this.options.hiddenname)
3872 frameEl.appendChild(E('input', {
3874 'name': this.options.hiddenname,
3878 frameEl.appendChild(E('input', {
3880 'name': this.options.name,
3882 'value': this.options.value_enabled,
3883 'checked': (this.value == this.options.value_enabled) ? '' : null,
3884 'disabled': this.options.disabled ? '' : null,
3885 'data-widget-id': this.options.id ? 'widget.' + this.options.id : null
3888 frameEl.appendChild(E('label', { 'for': id }));
3890 return this.bind(frameEl);
3894 bind: function(frameEl) {
3895 this.node = frameEl;
3897 this.setUpdateEvents(frameEl.lastElementChild.previousElementSibling, 'click', 'blur');
3898 this.setChangeEvents(frameEl.lastElementChild.previousElementSibling, 'change');
3900 dom.bindClassInstance(frameEl, this);
3906 * Test whether the checkbox is currently checked.
3909 * @memberof LuCI.ui.Checkbox
3910 * @returns {boolean}
3911 * Returns `true` when the checkbox is currently checked, otherwise `false`.
3913 isChecked: function() {
3914 return this.node.lastElementChild.previousElementSibling.checked;
3918 getValue: function() {
3919 return this.isChecked()
3920 ? this.options.value_enabled
3921 : this.options.value_disabled;
3925 setValue: function(value) {
3926 this.node.lastElementChild.previousElementSibling.checked = (value == this.options.value_enabled);
3931 * Instantiate a select dropdown or checkbox/radiobutton group.
3933 * @constructor Select
3935 * @augments LuCI.ui.AbstractElement
3939 * The `Select` class implements either a traditional HTML `<select>` element
3940 * or a group of checkboxes or radio buttons, depending on whether multiple
3941 * values are enabled or not.
3943 * UI widget instances are usually not supposed to be created by view code
3944 * directly, instead they're implicitely created by `LuCI.form` when
3945 * instantiating CBI forms.
3947 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3948 * in views, use `'require ui'` and refer to `ui.Select`. To import it in
3949 * external JavaScript, use `L.require("ui").then(...)` and access the
3950 * `Select` property of the class instance value.
3952 * @param {string|string[]} [value=null]
3953 * The initial input value(s).
3955 * @param {Object<string, string>} choices
3956 * Object containing the selectable choices of the widget. The object keys
3957 * serve as values for the different choices while the values are used as
3960 * @param {LuCI.ui.Select.InitOptions} [options]
3961 * Object describing the widget specific options to initialize the inputs.
3963 var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ {
3965 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3966 * the following properties are recognized:
3968 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3969 * @memberof LuCI.ui.Select
3971 * @property {boolean} [multiple=false]
3972 * Specifies whether multiple choice values may be selected.
3974 * @property {string} [widget=select]
3975 * Specifies the kind of widget to render. May be either `select` or
3976 * `individual`. When set to `select` an HTML `<select>` element will be
3977 * used, otherwise a group of checkbox or radio button elements is created,
3978 * depending on the value of the `multiple` option.
3980 * @property {string} [orientation=horizontal]
3981 * Specifies whether checkbox / radio button groups should be rendered
3982 * in a `horizontal` or `vertical` manner. Does not apply to the `select`
3985 * @property {boolean|string[]} [sort=false]
3986 * Specifies if and how to sort choice values. If set to `true`, the choice
3987 * values will be sorted alphabetically. If set to an array of strings, the
3988 * choice sort order is derived from the array.
3990 * @property {number} [size]
3991 * Specifies the HTML `size` attribute to set on the `<select>` element.
3992 * Only applicable to the `select` widget type.
3994 * @property {string} [placeholder=-- Please choose --]
3995 * Specifies a placeholder text which is displayed when no choice is
3996 * selected yet. Only applicable to the `select` widget type.
3998 __init__: function(value, choices, options) {
3999 if (!L.isObject(choices))
4002 if (!Array.isArray(value))
4003 value = (value != null && value != '') ? [ value ] : [];
4005 if (!options.multiple && value.length > 1)
4008 this.values = value;
4009 this.choices = choices;
4010 this.options = Object.assign({
4013 orientation: 'horizontal'
4016 if (this.choices.hasOwnProperty(''))
4017 this.options.optional = true;
4021 render: function() {
4022 var frameEl = E('div', { 'id': this.options.id }),
4023 keys = Object.keys(this.choices);
4025 if (this.options.sort === true)
4027 else if (Array.isArray(this.options.sort))
4028 keys = this.options.sort;
4030 if (this.options.widget == 'select') {
4031 frameEl.appendChild(E('select', {
4032 'id': this.options.id ? 'widget.' + this.options.id : null,
4033 'name': this.options.name,
4034 'size': this.options.size,
4035 'class': 'cbi-input-select',
4036 'multiple': this.options.multiple ? '' : null,
4037 'disabled': this.options.disabled ? '' : null
4040 if (this.options.optional)
4041 frameEl.lastChild.appendChild(E('option', {
4043 'selected': (this.values.length == 0 || this.values[0] == '') ? '' : null
4044 }, [ this.choices[''] || this.options.placeholder || _('-- Please choose --') ]));
4046 for (var i = 0; i < keys.length; i++) {
4047 if (keys[i] == null || keys[i] == '')
4050 frameEl.lastChild.appendChild(E('option', {
4052 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
4053 }, [ this.choices[keys[i]] || keys[i] ]));
4057 var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' ') : E('br');
4059 for (var i = 0; i < keys.length; i++) {
4060 frameEl.appendChild(E('label', {}, [
4062 'id': this.options.id ? 'widget.' + this.options.id : null,
4063 'name': this.options.id || this.options.name,
4064 'type': this.options.multiple ? 'checkbox' : 'radio',
4065 'class': this.options.multiple ? 'cbi-input-checkbox' : 'cbi-input-radio',
4067 'checked': (this.values.indexOf(keys[i]) > -1) ? '' : null,
4068 'disabled': this.options.disabled ? '' : null
4070 this.choices[keys[i]] || keys[i]
4073 if (i + 1 == this.options.size)
4074 frameEl.appendChild(brEl);
4078 return this.bind(frameEl);
4082 bind: function(frameEl) {
4083 this.node = frameEl;
4085 if (this.options.widget == 'select') {
4086 this.setUpdateEvents(frameEl.firstChild, 'change', 'click', 'blur');
4087 this.setChangeEvents(frameEl.firstChild, 'change');
4090 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
4091 for (var i = 0; i < radioEls.length; i++) {
4092 this.setUpdateEvents(radioEls[i], 'change', 'click', 'blur');
4093 this.setChangeEvents(radioEls[i], 'change', 'click', 'blur');
4097 dom.bindClassInstance(frameEl, this);
4103 getValue: function() {
4104 if (this.options.widget == 'select')
4105 return this.node.firstChild.value;
4107 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
4108 for (var i = 0; i < radioEls.length; i++)
4109 if (radioEls[i].checked)
4110 return radioEls[i].value;
4116 setValue: function(value) {
4117 if (this.options.widget == 'select') {
4121 for (var i = 0; i < this.node.firstChild.options.length; i++)
4122 this.node.firstChild.options[i].selected = (this.node.firstChild.options[i].value == value);
4127 var radioEls = frameEl.querySelectorAll('input[type="radio"]');
4128 for (var i = 0; i < radioEls.length; i++)
4129 radioEls[i].checked = (radioEls[i].value == value);
4134 * Instantiate a rich dropdown choice widget.
4136 * @constructor Dropdown
4138 * @augments LuCI.ui.AbstractElement
4142 * The `Dropdown` class implements a rich, stylable dropdown menu which
4143 * supports non-text choice labels.
4145 * UI widget instances are usually not supposed to be created by view code
4146 * directly, instead they're implicitely created by `LuCI.form` when
4147 * instantiating CBI forms.
4149 * This class is automatically instantiated as part of `LuCI.ui`. To use it
4150 * in views, use `'require ui'` and refer to `ui.Dropdown`. To import it in
4151 * external JavaScript, use `L.require("ui").then(...)` and access the
4152 * `Dropdown` property of the class instance value.
4154 * @param {string|string[]} [value=null]
4155 * The initial input value(s).
4157 * @param {Object<string, *>} choices
4158 * Object containing the selectable choices of the widget. The object keys
4159 * serve as values for the different choices while the values are used as
4162 * @param {LuCI.ui.Dropdown.InitOptions} [options]
4163 * Object describing the widget specific options to initialize the dropdown.
4165 var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
4167 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
4168 * the following properties are recognized:
4170 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4171 * @memberof LuCI.ui.Dropdown
4173 * @property {boolean} [optional=true]
4174 * Specifies whether the dropdown selection is optional. In contrast to
4175 * other widgets, the `optional` constraint of dropdowns works differently;
4176 * instead of marking the widget invalid on empty values when set to `false`,
4177 * the user is not allowed to deselect all choices.
4179 * For single value dropdowns that means that no empty "please select"
4180 * choice is offered and for multi value dropdowns, the last selected choice
4181 * may not be deselected without selecting another choice first.
4183 * @property {boolean} [multiple]
4184 * Specifies whether multiple choice values may be selected. It defaults
4185 * to `true` when an array is passed as input value to the constructor.
4187 * @property {boolean|string[]} [sort=false]
4188 * Specifies if and how to sort choice values. If set to `true`, the choice
4189 * values will be sorted alphabetically. If set to an array of strings, the
4190 * choice sort order is derived from the array.
4192 * @property {string} [select_placeholder=-- Please choose --]
4193 * Specifies a placeholder text which is displayed when no choice is
4196 * @property {string} [custom_placeholder=-- custom --]
4197 * Specifies a placeholder text which is displayed in the text input
4198 * field allowing to enter custom choice values. Only applicable if the
4199 * `create` option is set to `true`.
4201 * @property {boolean} [create=false]
4202 * Specifies whether custom choices may be entered into the dropdown
4205 * @property {string} [create_query=.create-item-input]
4206 * Specifies a CSS selector expression used to find the input element
4207 * which is used to enter custom choice values. This should not normally
4208 * be used except by widgets derived from the Dropdown class.
4210 * @property {string} [create_template=script[type="item-template"]]
4211 * Specifies a CSS selector expression used to find an HTML element
4212 * serving as template for newly added custom choice values.
4214 * Any `{{value}}` placeholder string within the template elements text
4215 * content will be replaced by the user supplied choice value, the
4216 * resulting string is parsed as HTML and appended to the end of the
4217 * choice list. The template markup may specify one HTML element with a
4218 * `data-label-placeholder` attribute which is replaced by a matching
4219 * label value from the `choices` object or with the user supplied value
4220 * itself in case `choices` contains no matching choice label.
4222 * If the template element is not found or if no `create_template` selector
4223 * expression is specified, the default markup for newly created elements is
4224 * `<li data-value="{{value}}"><span data-label-placeholder="true" /></li>`.
4226 * @property {string} [create_markup]
4227 * This property allows specifying the markup for custom choices directly
4228 * instead of referring to a template element through CSS selectors.
4230 * Apart from that it works exactly like `create_template`.
4232 * @property {number} [display_items=3]
4233 * Specifies the maximum amount of choice labels that should be shown in
4234 * collapsed dropdown state before further selected choices are cut off.
4236 * Only applicable when `multiple` is `true`.
4238 * @property {number} [dropdown_items=-1]
4239 * Specifies the maximum amount of choices that should be shown when the
4240 * dropdown is open. If the amount of available choices exceeds this number,
4241 * the dropdown area must be scrolled to reach further items.
4243 * If set to `-1`, the dropdown menu will attempt to show all choice values
4244 * and only resort to scrolling if the amount of choices exceeds the available
4245 * screen space above and below the dropdown widget.
4247 * @property {string} [placeholder]
4248 * This property serves as a shortcut to set both `select_placeholder` and
4249 * `custom_placeholder`. Either of these properties will fallback to
4250 * `placeholder` if not specified.
4252 * @property {boolean} [readonly=false]
4253 * Specifies whether the custom choice input field should be rendered
4254 * readonly. Only applicable when `create` is `true`.
4256 * @property {number} [maxlength]
4257 * Specifies the HTML `maxlength` attribute to set on the custom choice
4258 * `<input>` element. Note that this a legacy property that exists for
4259 * compatibility reasons. It is usually better to `maxlength(N)` validation
4260 * expression. Only applicable when `create` is `true`.
4262 __init__: function(value, choices, options) {
4263 if (typeof(choices) != 'object')
4266 if (!Array.isArray(value))
4267 this.values = (value != null && value != '') ? [ value ] : [];
4269 this.values = value;
4271 this.choices = choices;
4272 this.options = Object.assign({
4274 multiple: Array.isArray(value),
4276 select_placeholder: _('-- Please choose --'),
4277 custom_placeholder: _('-- custom --'),
4281 create_query: '.create-item-input',
4282 create_template: 'script[type="item-template"]'
4287 render: function() {
4289 'id': this.options.id,
4290 'class': 'cbi-dropdown',
4291 'multiple': this.options.multiple ? '' : null,
4292 'optional': this.options.optional ? '' : null,
4293 'disabled': this.options.disabled ? '' : null
4296 var keys = Object.keys(this.choices);
4298 if (this.options.sort === true)
4300 else if (Array.isArray(this.options.sort))
4301 keys = this.options.sort;
4303 if (this.options.create)
4304 for (var i = 0; i < this.values.length; i++)
4305 if (!this.choices.hasOwnProperty(this.values[i]))
4306 keys.push(this.values[i]);
4308 for (var i = 0; i < keys.length; i++) {
4309 var label = this.choices[keys[i]];
4311 if (dom.elem(label))
4312 label = label.cloneNode(true);
4314 sb.lastElementChild.appendChild(E('li', {
4315 'data-value': keys[i],
4316 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
4317 }, [ label || keys[i] ]));
4320 if (this.options.create) {
4321 var createEl = E('input', {
4323 'class': 'create-item-input',
4324 'readonly': this.options.readonly ? '' : null,
4325 'maxlength': this.options.maxlength,
4326 'placeholder': this.options.custom_placeholder || this.options.placeholder
4329 if (this.options.datatype || this.options.validate)
4330 UI.prototype.addValidator(createEl, this.options.datatype || 'string',
4331 true, this.options.validate, 'blur', 'keyup');
4333 sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl));
4336 if (this.options.create_markup)
4337 sb.appendChild(E('script', { type: 'item-template' },
4338 this.options.create_markup));
4340 return this.bind(sb);
4344 bind: function(sb) {
4345 var o = this.options;
4347 o.multiple = sb.hasAttribute('multiple');
4348 o.optional = sb.hasAttribute('optional');
4349 o.placeholder = sb.getAttribute('placeholder') || o.placeholder;
4350 o.display_items = parseInt(sb.getAttribute('display-items') || o.display_items);
4351 o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') || o.dropdown_items);
4352 o.create_query = sb.getAttribute('item-create') || o.create_query;
4353 o.create_template = sb.getAttribute('item-template') || o.create_template;
4355 var ul = sb.querySelector('ul'),
4356 more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')),
4357 open = sb.appendChild(E('span', { class: 'open', tabindex: -1 }, 'â–¾')),
4358 canary = sb.appendChild(E('div')),
4359 create = sb.querySelector(this.options.create_query),
4360 ndisplay = this.options.display_items,
4363 if (this.options.multiple) {
4364 var items = ul.querySelectorAll('li');
4366 for (var i = 0; i < items.length; i++) {
4367 this.transformItem(sb, items[i]);
4369 if (items[i].hasAttribute('selected') && ndisplay-- > 0)
4370 items[i].setAttribute('display', n++);
4374 if (this.options.optional && !ul.querySelector('li[data-value=""]')) {
4375 var placeholder = E('li', { placeholder: '' },
4376 this.options.select_placeholder || this.options.placeholder);
4379 ? ul.insertBefore(placeholder, ul.firstChild)
4380 : ul.appendChild(placeholder);
4383 var items = ul.querySelectorAll('li'),
4384 sel = sb.querySelectorAll('[selected]');
4386 sel.forEach(function(s) {
4387 s.removeAttribute('selected');
4390 var s = sel[0] || items[0];
4392 s.setAttribute('selected', '');
4393 s.setAttribute('display', n++);
4399 this.saveValues(sb, ul);
4401 ul.setAttribute('tabindex', -1);
4402 sb.setAttribute('tabindex', 0);
4404 if (ndisplay < 0)
4405 sb.setAttribute('more', '')
4407 sb.removeAttribute('more');
4409 if (ndisplay == this.options.display_items)
4410 sb.setAttribute('empty', '')
4412 sb.removeAttribute('empty');
4414 dom.content(more, (ndisplay == this.options.display_items)
4415 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4418 sb.addEventListener('click', this.handleClick.bind(this));
4419 sb.addEventListener('keydown', this.handleKeydown.bind(this));
4420 sb.addEventListener('cbi-dropdown-close', this.handleDropdownClose.bind(this));
4421 sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this));
4423 if ('ontouchstart' in window) {
4424 sb.addEventListener('touchstart', function(ev) { ev.stopPropagation(); });
4425 window.addEventListener('touchstart', this.closeAllDropdowns);
4428 sb.addEventListener('mouseover', this.handleMouseover.bind(this));
4429 sb.addEventListener('focus', this.handleFocus.bind(this));
4431 canary.addEventListener('focus', this.handleCanaryFocus.bind(this));
4433 window.addEventListener('mouseover', this.setFocus);
4434 window.addEventListener('click', this.closeAllDropdowns);
4438 create.addEventListener('keydown', this.handleCreateKeydown.bind(this));
4439 create.addEventListener('focus', this.handleCreateFocus.bind(this));
4440 create.addEventListener('blur', this.handleCreateBlur.bind(this));
4442 var li = findParent(create, 'li');
4444 li.setAttribute('unselectable', '');
4445 li.addEventListener('click', this.handleCreateClick.bind(this));
4450 this.setUpdateEvents(sb, 'cbi-dropdown-open', 'cbi-dropdown-close');
4451 this.setChangeEvents(sb, 'cbi-dropdown-change', 'cbi-dropdown-close');
4453 dom.bindClassInstance(sb, this);
4459 openDropdown: function(sb) {
4460 var st = window.getComputedStyle(sb, null),
4461 ul = sb.querySelector('ul'),
4462 li = ul.querySelectorAll('li'),
4463 fl = findParent(sb, '.cbi-value-field'),
4464 sel = ul.querySelector('[selected]'),
4465 rect = sb.getBoundingClientRect(),
4466 items = Math.min(this.options.dropdown_items, li.length);
4468 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
4469 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
4472 sb.setAttribute('open', '');
4474 var pv = ul.cloneNode(true);
4475 pv.classList.add('preview');
4478 fl.classList.add('cbi-dropdown-open');
4480 if ('ontouchstart' in window) {
4481 var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
4482 vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
4485 ul.style.top = sb.offsetHeight + 'px';
4486 ul.style.left = -rect.left + 'px';
4487 ul.style.right = (rect.right - vpWidth) + 'px';
4488 ul.style.maxHeight = (vpHeight * 0.5) + 'px';
4489 ul.style.WebkitOverflowScrolling = 'touch';
4491 function getScrollParent(element) {
4492 var parent = element,
4493 style = getComputedStyle(element),
4494 excludeStaticParent = (style.position === 'absolute');
4496 if (style.position === 'fixed')
4497 return document.body;
4499 while ((parent = parent.parentElement) != null) {
4500 style = getComputedStyle(parent);
4502 if (excludeStaticParent && style.position === 'static')
4505 if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX))
4509 return document.body;
4512 var scrollParent = getScrollParent(sb),
4513 scrollFrom = scrollParent.scrollTop,
4514 scrollTo = scrollFrom + rect.top - vpHeight * 0.5;
4516 var scrollStep = function(timestamp) {
4519 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
4522 var duration = Math.max(timestamp - start, 1);
4523 if (duration < 100) {
4524 scrollParent.scrollTop = scrollFrom + (scrollTo - scrollFrom) * (duration / 100);
4525 window.requestAnimationFrame(scrollStep);
4528 scrollParent.scrollTop = scrollTo;
4532 window.requestAnimationFrame(scrollStep);
4535 ul.style.maxHeight = '1px';
4536 ul.style.top = ul.style.bottom = '';
4538 window.requestAnimationFrame(function() {
4539 var itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height,
4541 spaceAbove = rect.top,
4542 spaceBelow = window.innerHeight - rect.height - rect.top;
4544 for (var i = 0; i < (items == -1 ? li.length : items); i++)
4545 fullHeight += li[i].getBoundingClientRect().height;
4547 if (fullHeight <= spaceBelow) {
4548 ul.style.top = rect.height + 'px';
4549 ul.style.maxHeight = spaceBelow + 'px';
4551 else if (fullHeight <= spaceAbove) {
4552 ul.style.bottom = rect.height + 'px';
4553 ul.style.maxHeight = spaceAbove + 'px';
4555 else if (spaceBelow >= spaceAbove) {
4556 ul.style.top = rect.height + 'px';
4557 ul.style.maxHeight = (spaceBelow - (spaceBelow % itemHeight)) + 'px';
4560 ul.style.bottom = rect.height + 'px';
4561 ul.style.maxHeight = (spaceAbove - (spaceAbove % itemHeight)) + 'px';
4564 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
4568 var cboxes = ul.querySelectorAll('[selected] input[type="checkbox"]');
4569 for (var i = 0; i < cboxes.length; i++) {
4570 cboxes[i].checked = true;
4571 cboxes[i].disabled = (cboxes.length == 1 && !this.options.optional);
4574 ul.classList.add('dropdown');
4576 sb.insertBefore(pv, ul.nextElementSibling);
4578 li.forEach(function(l) {
4579 l.setAttribute('tabindex', 0);
4582 sb.lastElementChild.setAttribute('tabindex', 0);
4584 this.setFocus(sb, sel || li[0], true);
4588 closeDropdown: function(sb, no_focus) {
4589 if (!sb.hasAttribute('open'))
4592 var pv = sb.querySelector('ul.preview'),
4593 ul = sb.querySelector('ul.dropdown'),
4594 li = ul.querySelectorAll('li'),
4595 fl = findParent(sb, '.cbi-value-field');
4597 li.forEach(function(l) { l.removeAttribute('tabindex'); });
4598 sb.lastElementChild.removeAttribute('tabindex');
4601 sb.removeAttribute('open');
4602 sb.style.width = sb.style.height = '';
4604 ul.classList.remove('dropdown');
4605 ul.style.top = ul.style.bottom = ul.style.maxHeight = '';
4608 fl.classList.remove('cbi-dropdown-open');
4611 this.setFocus(sb, sb);
4613 this.saveValues(sb, ul);
4617 toggleItem: function(sb, li, force_state) {
4618 if (li.hasAttribute('unselectable'))
4621 if (this.options.multiple) {
4622 var cbox = li.querySelector('input[type="checkbox"]'),
4623 items = li.parentNode.querySelectorAll('li'),
4624 label = sb.querySelector('ul.preview'),
4625 sel = li.parentNode.querySelectorAll('[selected]').length,
4626 more = sb.querySelector('.more'),
4627 ndisplay = this.options.display_items,
4630 if (li.hasAttribute('selected')) {
4631 if (force_state !== true) {
4632 if (sel > 1 || this.options.optional) {
4633 li.removeAttribute('selected');
4634 cbox.checked = cbox.disabled = false;
4638 cbox.disabled = true;
4643 if (force_state !== false) {
4644 li.setAttribute('selected', '');
4645 cbox.checked = true;
4646 cbox.disabled = false;
4651 while (label && label.firstElementChild)
4652 label.removeChild(label.firstElementChild);
4654 for (var i = 0; i < items.length; i++) {
4655 items[i].removeAttribute('display');
4656 if (items[i].hasAttribute('selected')) {
4657 if (ndisplay-- > 0) {
4658 items[i].setAttribute('display', n++);
4660 label.appendChild(items[i].cloneNode(true));
4662 var c = items[i].querySelector('input[type="checkbox"]');
4664 c.disabled = (sel == 1 && !this.options.optional);
4668 if (ndisplay < 0)
4669 sb.setAttribute('more', '');
4671 sb.removeAttribute('more');
4673 if (ndisplay === this.options.display_items)
4674 sb.setAttribute('empty', '');
4676 sb.removeAttribute('empty');
4678 dom.content(more, (ndisplay === this.options.display_items)
4679 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4682 var sel = li.parentNode.querySelector('[selected]');
4684 sel.removeAttribute('display');
4685 sel.removeAttribute('selected');
4688 li.setAttribute('display', 0);
4689 li.setAttribute('selected', '');
4691 this.closeDropdown(sb, true);
4694 this.saveValues(sb, li.parentNode);
4698 transformItem: function(sb, li) {
4699 var cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -1, onclick: 'event.preventDefault()' })),
4702 while (li.firstChild)
4703 label.appendChild(li.firstChild);
4705 li.appendChild(cbox);
4706 li.appendChild(label);
4710 saveValues: function(sb, ul) {
4711 var sel = ul.querySelectorAll('li[selected]'),
4712 div = sb.lastElementChild,
4713 name = this.options.name,
4717 while (div.lastElementChild)
4718 div.removeChild(div.lastElementChild);
4720 sel.forEach(function (s) {
4721 if (s.hasAttribute('placeholder'))
4726 value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText,
4730 div.appendChild(E('input', {
4738 strval += strval.length ? ' ' + v.value : v.value;
4746 if (this.options.multiple)
4747 detail.values = values;
4749 detail.value = values.length ? values[0] : null;
4753 sb.dispatchEvent(new CustomEvent('cbi-dropdown-change', {
4760 setValues: function(sb, values) {
4761 var ul = sb.querySelector('ul');
4763 if (this.options.create) {
4764 for (var value in values) {
4765 this.createItems(sb, value);
4767 if (!this.options.multiple)
4772 if (this.options.multiple) {
4773 var lis = ul.querySelectorAll('li[data-value]');
4774 for (var i = 0; i < lis.length; i++) {
4775 var value = lis[i].getAttribute('data-value');
4776 if (values === null || !(value in values))
4777 this.toggleItem(sb, lis[i], false);
4779 this.toggleItem(sb, lis[i], true);
4783 var ph = ul.querySelector('li[placeholder]');
4785 this.toggleItem(sb, ph);
4787 var lis = ul.querySelectorAll('li[data-value]');
4788 for (var i = 0; i < lis.length; i++) {
4789 var value = lis[i].getAttribute('data-value');
4790 if (values !== null && (value in values))
4791 this.toggleItem(sb, lis[i]);
4797 setFocus: function(sb, elem, scroll) {
4798 if (sb && sb.hasAttribute && sb.hasAttribute('locked-in'))
4801 if (sb.target && findParent(sb.target, 'ul.dropdown'))
4804 document.querySelectorAll('.focus').forEach(function(e) {
4805 if (!matchesElem(e, 'input')) {
4806 e.classList.remove('focus');
4813 elem.classList.add('focus');
4816 elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop;
4821 createChoiceElement: function(sb, value, label) {
4822 var tpl = sb.querySelector(this.options.create_template),
4826 markup = (tpl.textContent || tpl.innerHTML || tpl.firstChild.data).replace(/^<!--|-->$/, '').trim();
4828 markup = '<li data-value="{{value}}"><span data-label-placeholder="true" /></li>';
4830 var new_item = E(markup.replace(/{{value}}/g, '%h'.format(value))),
4831 placeholder = new_item.querySelector('[data-label-placeholder]');
4834 var content = E('span', {}, label || this.choices[value] || [ value ]);
4836 while (content.firstChild)
4837 placeholder.parentNode.insertBefore(content.firstChild, placeholder);
4839 placeholder.parentNode.removeChild(placeholder);
4842 if (this.options.multiple)
4843 this.transformItem(sb, new_item);
4849 createItems: function(sb, value) {
4851 val = (value || '').trim(),
4852 ul = sb.querySelector('ul');
4854 if (!sbox.options.multiple)
4855 val = val.length ? [ val ] : [];
4857 val = val.length ? val.split(/\s+/) : [];
4859 val.forEach(function(item) {
4860 var new_item = null;
4862 ul.childNodes.forEach(function(li) {
4863 if (li.getAttribute && li.getAttribute('data-value') === item)
4868 new_item = sbox.createChoiceElement(sb, item);
4870 if (!sbox.options.multiple) {
4871 var old = ul.querySelector('li[created]');
4873 ul.removeChild(old);
4875 new_item.setAttribute('created', '');
4878 new_item = ul.insertBefore(new_item, ul.lastElementChild);
4881 sbox.toggleItem(sb, new_item, true);
4882 sbox.setFocus(sb, new_item, true);
4887 * Remove all existing choices from the dropdown menu.
4889 * This function removes all preexisting dropdown choices from the widget,
4890 * keeping only choices currently being selected unless `reset_values` is
4891 * given, in which case all choices and deselected and removed.
4894 * @memberof LuCI.ui.Dropdown
4895 * @param {boolean} [reset_value=false]
4896 * If set to `true`, deselect and remove selected choices as well instead
4899 clearChoices: function(reset_value) {
4900 var ul = this.node.querySelector('ul'),
4901 lis = ul ? ul.querySelectorAll('li[data-value]') : [],
4902 len = lis.length - (this.options.create ? 1 : 0),
4903 val = reset_value ? null : this.getValue();
4905 for (var i = 0; i < len; i++) {
4906 var lival = lis[i].getAttribute('data-value');
4908 (!this.options.multiple && val != lival) ||
4909 (this.options.multiple && val.indexOf(lival) == -1))
4910 ul.removeChild(lis[i]);
4914 this.setValues(this.node, {});
4918 * Add new choices to the dropdown menu.
4920 * This function adds further choices to an existing dropdown menu,
4921 * ignoring choice values which are already present.
4924 * @memberof LuCI.ui.Dropdown
4925 * @param {string[]} values
4926 * The choice values to add to the dropdown widget.
4928 * @param {Object<string, *>} labels
4929 * The choice label values to use when adding dropdown choices. If no
4930 * label is found for a particular choice value, the value itself is used
4931 * as label text. Choice labels may be any valid value accepted by
4932 * {@link LuCI.dom#content}.
4934 addChoices: function(values, labels) {
4936 ul = sb.querySelector('ul'),
4937 lis = ul ? ul.querySelectorAll('li[data-value]') : [];
4939 if (!Array.isArray(values))
4940 values = L.toArray(values);
4942 if (!L.isObject(labels))
4945 for (var i = 0; i < values.length; i++) {
4948 for (var j = 0; j < lis.length; j++) {
4949 if (lis[j].getAttribute('data-value') === values[i]) {
4959 this.createChoiceElement(sb, values[i], labels[values[i]]),
4960 ul.lastElementChild);
4965 * Close all open dropdown widgets in the current document.
4967 closeAllDropdowns: function() {
4968 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
4969 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
4974 handleClick: function(ev) {
4975 var sb = ev.currentTarget;
4977 if (!sb.hasAttribute('open')) {
4978 if (!matchesElem(ev.target, 'input'))
4979 this.openDropdown(sb);
4982 var li = findParent(ev.target, 'li');
4983 if (li && li.parentNode.classList.contains('dropdown'))
4984 this.toggleItem(sb, li);
4985 else if (li && li.parentNode.classList.contains('preview'))
4986 this.closeDropdown(sb);
4987 else if (matchesElem(ev.target, 'span.open, span.more'))
4988 this.closeDropdown(sb);
4991 ev.preventDefault();
4992 ev.stopPropagation();
4996 handleKeydown: function(ev) {
4997 var sb = ev.currentTarget;
4999 if (matchesElem(ev.target, 'input'))
5002 if (!sb.hasAttribute('open')) {
5003 switch (ev.keyCode) {
5008 this.openDropdown(sb);
5009 ev.preventDefault();
5013 var active = findParent(document.activeElement, 'li');
5015 switch (ev.keyCode) {
5017 this.closeDropdown(sb);
5022 if (!active.hasAttribute('selected'))
5023 this.toggleItem(sb, active);
5024 this.closeDropdown(sb);
5025 ev.preventDefault();
5031 this.toggleItem(sb, active);
5032 ev.preventDefault();
5037 if (active && active.previousElementSibling) {
5038 this.setFocus(sb, active.previousElementSibling);
5039 ev.preventDefault();
5044 if (active && active.nextElementSibling) {
5045 this.setFocus(sb, active.nextElementSibling);
5046 ev.preventDefault();
5054 handleDropdownClose: function(ev) {
5055 var sb = ev.currentTarget;
5057 this.closeDropdown(sb, true);
5061 handleDropdownSelect: function(ev) {
5062 var sb = ev.currentTarget,
5063 li = findParent(ev.target, 'li');
5068 this.toggleItem(sb, li);
5069 this.closeDropdown(sb, true);
5073 handleMouseover: function(ev) {
5074 var sb = ev.currentTarget;
5076 if (!sb.hasAttribute('open'))
5079 var li = findParent(ev.target, 'li');
5081 if (li && li.parentNode.classList.contains('dropdown'))
5082 this.setFocus(sb, li);
5086 handleFocus: function(ev) {
5087 var sb = ev.currentTarget;
5089 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
5090 if (s !== sb || sb.hasAttribute('open'))
5091 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
5096 handleCanaryFocus: function(ev) {
5097 this.closeDropdown(ev.currentTarget.parentNode);
5101 handleCreateKeydown: function(ev) {
5102 var input = ev.currentTarget,
5103 sb = findParent(input, '.cbi-dropdown');
5105 switch (ev.keyCode) {
5107 ev.preventDefault();
5109 if (input.classList.contains('cbi-input-invalid'))
5112 this.createItems(sb, input.value);
5120 handleCreateFocus: function(ev) {
5121 var input = ev.currentTarget,
5122 cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'),
5123 sb = findParent(input, '.cbi-dropdown');
5126 cbox.checked = true;
5128 sb.setAttribute('locked-in', '');
5132 handleCreateBlur: function(ev) {
5133 var input = ev.currentTarget,
5134 cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'),
5135 sb = findParent(input, '.cbi-dropdown');
5138 cbox.checked = false;
5140 sb.removeAttribute('locked-in');
5144 handleCreateClick: function(ev) {
5145 ev.currentTarget.querySelector(this.options.create_query).focus();
5149 setValue: function(values) {
5150 if (this.options.multiple) {
5151 if (!Array.isArray(values))
5152 values = (values != null && values != '') ? [ values ] : [];
5156 for (var i = 0; i < values.length; i++)
5157 v[values[i]] = true;
5159 this.setValues(this.node, v);
5164 if (values != null) {
5165 if (Array.isArray(values))
5166 v[values[0]] = true;
5171 this.setValues(this.node, v);
5176 getValue: function() {
5177 var div = this.node.lastElementChild,
5178 h = div.querySelectorAll('input[type="hidden"]'),
5181 for (var i = 0; i < h.length; i++)
5184 return this.options.multiple ? v : v[0];
5189 * Instantiate a rich dropdown choice widget allowing custom values.
5191 * @constructor Combobox
5193 * @augments LuCI.ui.Dropdown
5197 * The `Combobox` class implements a rich, stylable dropdown menu which allows
5198 * to enter custom values. Historically, comboboxes used to be a dedicated
5199 * widget type in LuCI but nowadays they are direct aliases of dropdown widgets
5200 * with a set of enforced default properties for easier instantiation.
5202 * UI widget instances are usually not supposed to be created by view code
5203 * directly, instead they're implicitely created by `LuCI.form` when
5204 * instantiating CBI forms.
5206 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5207 * in views, use `'require ui'` and refer to `ui.Combobox`. To import it in
5208 * external JavaScript, use `L.require("ui").then(...)` and access the
5209 * `Combobox` property of the class instance value.
5211 * @param {string|string[]} [value=null]
5212 * The initial input value(s).
5214 * @param {Object<string, *>} choices
5215 * Object containing the selectable choices of the widget. The object keys
5216 * serve as values for the different choices while the values are used as
5219 * @param {LuCI.ui.Combobox.InitOptions} [options]
5220 * Object describing the widget specific options to initialize the dropdown.
5222 var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ {
5224 * Comboboxes support the same properties as
5225 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5226 * specific values for the following properties:
5228 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5229 * @memberof LuCI.ui.Combobox
5231 * @property {boolean} multiple=false
5232 * Since Comboboxes never allow selecting multiple values, this property
5233 * is forcibly set to `false`.
5235 * @property {boolean} create=true
5236 * Since Comboboxes always allow custom choice values, this property is
5237 * forcibly set to `true`.
5239 * @property {boolean} optional=true
5240 * Since Comboboxes are always optional, this property is forcibly set to
5243 __init__: function(value, choices, options) {
5244 this.super('__init__', [ value, choices, Object.assign({
5245 select_placeholder: _('-- Please choose --'),
5246 custom_placeholder: _('-- custom --'),
5258 * Instantiate a combo button widget offering multiple action choices.
5260 * @constructor ComboButton
5262 * @augments LuCI.ui.Dropdown
5266 * The `ComboButton` class implements a button element which can be expanded
5267 * into a dropdown to chose from a set of different action choices.
5269 * UI widget instances are usually not supposed to be created by view code
5270 * directly, instead they're implicitely created by `LuCI.form` when
5271 * instantiating CBI forms.
5273 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5274 * in views, use `'require ui'` and refer to `ui.ComboButton`. To import it in
5275 * external JavaScript, use `L.require("ui").then(...)` and access the
5276 * `ComboButton` property of the class instance value.
5278 * @param {string|string[]} [value=null]
5279 * The initial input value(s).
5281 * @param {Object<string, *>} choices
5282 * Object containing the selectable choices of the widget. The object keys
5283 * serve as values for the different choices while the values are used as
5286 * @param {LuCI.ui.ComboButton.InitOptions} [options]
5287 * Object describing the widget specific options to initialize the button.
5289 var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype */ {
5291 * ComboButtons support the same properties as
5292 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5293 * specific values for some properties and add aditional button specific
5296 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5297 * @memberof LuCI.ui.ComboButton
5299 * @property {boolean} multiple=false
5300 * Since ComboButtons never allow selecting multiple actions, this property
5301 * is forcibly set to `false`.
5303 * @property {boolean} create=false
5304 * Since ComboButtons never allow creating custom choices, this property
5305 * is forcibly set to `false`.
5307 * @property {boolean} optional=false
5308 * Since ComboButtons must always select one action, this property is
5309 * forcibly set to `false`.
5311 * @property {Object<string, string>} [classes]
5312 * Specifies a mapping of choice values to CSS class names. If an action
5313 * choice is selected by the user and if a corresponding entry exists in
5314 * the `classes` object, the class names corresponding to the selected
5315 * value are set on the button element.
5317 * This is useful to apply different button styles, such as colors, to the
5318 * combined button depending on the selected action.
5320 * @property {function} [click]
5321 * Specifies a handler function to invoke when the user clicks the button.
5322 * This function will be called with the button DOM node as `this` context
5323 * and receive the DOM click event as first as well as the selected action
5324 * choice value as second argument.
5326 __init__: function(value, choices, options) {
5327 this.super('__init__', [ value, choices, Object.assign({
5337 render: function(/* ... */) {
5338 var node = UIDropdown.prototype.render.apply(this, arguments),
5339 val = this.getValue();
5341 if (L.isObject(this.options.classes) && this.options.classes.hasOwnProperty(val))
5342 node.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5348 handleClick: function(ev) {
5349 var sb = ev.currentTarget,
5352 if (sb.hasAttribute('open') || dom.matches(t, '.cbi-dropdown > span.open'))
5353 return UIDropdown.prototype.handleClick.apply(this, arguments);
5355 if (this.options.click)
5356 return this.options.click.call(sb, ev, this.getValue());
5360 toggleItem: function(sb /*, ... */) {
5361 var rv = UIDropdown.prototype.toggleItem.apply(this, arguments),
5362 val = this.getValue();
5364 if (L.isObject(this.options.classes) && this.options.classes.hasOwnProperty(val))
5365 sb.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5367 sb.setAttribute('class', 'cbi-dropdown');
5374 * Instantiate a dynamic list widget.
5376 * @constructor DynamicList
5378 * @augments LuCI.ui.AbstractElement
5382 * The `DynamicList` class implements a widget which allows the user to specify
5383 * an arbitrary amount of input values, either from free formed text input or
5384 * from a set of predefined choices.
5386 * UI widget instances are usually not supposed to be created by view code
5387 * directly, instead they're implicitely created by `LuCI.form` when
5388 * instantiating CBI forms.
5390 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5391 * in views, use `'require ui'` and refer to `ui.DynamicList`. To import it in
5392 * external JavaScript, use `L.require("ui").then(...)` and access the
5393 * `DynamicList` property of the class instance value.
5395 * @param {string|string[]} [value=null]
5396 * The initial input value(s).
5398 * @param {Object<string, *>} [choices]
5399 * Object containing the selectable choices of the widget. The object keys
5400 * serve as values for the different choices while the values are used as
5401 * choice labels. If omitted, no default choices are presented to the user,
5402 * instead a plain text input field is rendered allowing the user to add
5403 * arbitrary values to the dynamic list.
5405 * @param {LuCI.ui.DynamicList.InitOptions} [options]
5406 * Object describing the widget specific options to initialize the dynamic list.
5408 var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ {
5410 * In case choices are passed to the dynamic list contructor, the widget
5411 * supports the same properties as [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions}
5412 * but enforces specific values for some dropdown properties.
5414 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5415 * @memberof LuCI.ui.DynamicList
5417 * @property {boolean} multiple=false
5418 * Since dynamic lists never allow selecting multiple choices when adding
5419 * another list item, this property is forcibly set to `false`.
5421 * @property {boolean} optional=true
5422 * Since dynamic lists use an embedded dropdown to present a list of
5423 * predefined choice values, the dropdown must be made optional to allow
5424 * it to remain unselected.
5426 __init__: function(values, choices, options) {
5427 if (!Array.isArray(values))
5428 values = (values != null && values != '') ? [ values ] : [];
5430 if (typeof(choices) != 'object')
5433 this.values = values;
5434 this.choices = choices;
5435 this.options = Object.assign({}, options, {
5442 render: function() {
5444 'id': this.options.id,
5445 'class': 'cbi-dynlist',
5446 'disabled': this.options.disabled ? '' : null
5447 }, E('div', { 'class': 'add-item' }));
5450 if (this.options.placeholder != null)
5451 this.options.select_placeholder = this.options.placeholder;
5453 var cbox = new UICombobox(null, this.choices, this.options);
5455 dl.lastElementChild.appendChild(cbox.render());
5458 var inputEl = E('input', {
5459 'id': this.options.id ? 'widget.' + this.options.id : null,
5461 'class': 'cbi-input-text',
5462 'placeholder': this.options.placeholder,
5463 'disabled': this.options.disabled ? '' : null
5466 dl.lastElementChild.appendChild(inputEl);
5467 dl.lastElementChild.appendChild(E('div', { 'class': 'btn cbi-button cbi-button-add' }, '+'));
5469 if (this.options.datatype || this.options.validate)
5470 UI.prototype.addValidator(inputEl, this.options.datatype || 'string',
5471 true, this.options.validate, 'blur', 'keyup');
5474 for (var i = 0; i < this.values.length; i++) {
5475 var label = this.choices ? this.choices[this.values[i]] : null;
5477 if (dom.elem(label))
5478 label = label.cloneNode(true);
5480 this.addItem(dl, this.values[i], label);
5483 return this.bind(dl);
5487 bind: function(dl) {
5488 dl.addEventListener('click', L.bind(this.handleClick, this));
5489 dl.addEventListener('keydown', L.bind(this.handleKeydown, this));
5490 dl.addEventListener('cbi-dropdown-change', L.bind(this.handleDropdownChange, this));
5494 this.setUpdateEvents(dl, 'cbi-dynlist-change');
5495 this.setChangeEvents(dl, 'cbi-dynlist-change');
5497 dom.bindClassInstance(dl, this);
5503 addItem: function(dl, value, text, flash) {
5505 new_item = E('div', { 'class': flash ? 'item flash' : 'item', 'tabindex': 0 }, [
5506 E('span', {}, [ text || value ]),
5509 'name': this.options.name,
5510 'value': value })]);
5512 dl.querySelectorAll('.item').forEach(function(item) {
5516 var hidden = item.querySelector('input[type="hidden"]');
5518 if (hidden && hidden.parentNode !== item)
5521 if (hidden && hidden.value === value)
5526 var ai = dl.querySelector('.add-item');
5527 ai.parentNode.insertBefore(new_item, ai);
5530 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5542 removeItem: function(dl, item) {
5543 var value = item.querySelector('input[type="hidden"]').value;
5544 var sb = dl.querySelector('.cbi-dropdown');
5546 sb.querySelectorAll('ul > li').forEach(function(li) {
5547 if (li.getAttribute('data-value') === value) {
5548 if (li.hasAttribute('dynlistcustom'))
5549 li.parentNode.removeChild(li);
5551 li.removeAttribute('unselectable');
5555 item.parentNode.removeChild(item);
5557 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5569 handleClick: function(ev) {
5570 var dl = ev.currentTarget,
5571 item = findParent(ev.target, '.item');
5573 if (this.options.disabled)
5577 this.removeItem(dl, item);
5579 else if (matchesElem(ev.target, '.cbi-button-add')) {
5580 var input = ev.target.previousElementSibling;
5581 if (input.value.length && !input.classList.contains('cbi-input-invalid')) {
5582 this.addItem(dl, input.value, null, true);
5589 handleDropdownChange: function(ev) {
5590 var dl = ev.currentTarget,
5591 sbIn = ev.detail.instance,
5592 sbEl = ev.detail.element,
5593 sbVal = ev.detail.value;
5598 sbIn.setValues(sbEl, null);
5599 sbVal.element.setAttribute('unselectable', '');
5601 if (sbVal.element.hasAttribute('created')) {
5602 sbVal.element.removeAttribute('created');
5603 sbVal.element.setAttribute('dynlistcustom', '');
5606 var label = sbVal.text;
5608 if (sbVal.element) {
5611 for (var i = 0; i < sbVal.element.childNodes.length; i++)
5612 label.appendChild(sbVal.element.childNodes[i].cloneNode(true));
5615 this.addItem(dl, sbVal.value, label, true);
5619 handleKeydown: function(ev) {
5620 var dl = ev.currentTarget,
5621 item = findParent(ev.target, '.item');
5624 switch (ev.keyCode) {
5625 case 8: /* backspace */
5626 if (item.previousElementSibling)
5627 item.previousElementSibling.focus();
5629 this.removeItem(dl, item);
5632 case 46: /* delete */
5633 if (item.nextElementSibling) {
5634 if (item.nextElementSibling.classList.contains('item'))
5635 item.nextElementSibling.focus();
5637 item.nextElementSibling.firstElementChild.focus();
5640 this.removeItem(dl, item);
5644 else if (matchesElem(ev.target, '.cbi-input-text')) {
5645 switch (ev.keyCode) {
5646 case 13: /* enter */
5647 if (ev.target.value.length && !ev.target.classList.contains('cbi-input-invalid')) {
5648 this.addItem(dl, ev.target.value, null, true);
5649 ev.target.value = '';
5654 ev.preventDefault();
5661 getValue: function() {
5662 var items = this.node.querySelectorAll('.item > input[type="hidden"]'),
5663 input = this.node.querySelector('.add-item > input[type="text"]'),
5666 for (var i = 0; i < items.length; i++)
5667 v.push(items[i].value);
5669 if (input && input.value != null && input.value.match(/\S/) &&
5670 input.classList.contains('cbi-input-invalid') == false &&
5671 v.filter(function(s) { return s == input.value }).length == 0)
5672 v.push(input.value);
5678 setValue: function(values) {
5679 if (!Array.isArray(values))
5680 values = (values != null && values != '') ? [ values ] : [];
5682 var items = this.node.querySelectorAll('.item');
5684 for (var i = 0; i < items.length; i++)
5685 if (items[i].parentNode === this.node)
5686 this.removeItem(this.node, items[i]);
5688 for (var i = 0; i < values.length; i++)
5689 this.addItem(this.node, values[i],
5690 this.choices ? this.choices[values[i]] : null);
5694 * Add new suggested choices to the dynamic list.
5696 * This function adds further choices to an existing dynamic list,
5697 * ignoring choice values which are already present.
5700 * @memberof LuCI.ui.DynamicList
5701 * @param {string[]} values
5702 * The choice values to add to the dynamic lists suggestion dropdown.
5704 * @param {Object<string, *>} labels
5705 * The choice label values to use when adding suggested choices. If no
5706 * label is found for a particular choice value, the value itself is used
5707 * as label text. Choice labels may be any valid value accepted by
5708 * {@link LuCI.dom#content}.
5710 addChoices: function(values, labels) {
5711 var dl = this.node.lastElementChild.firstElementChild;
5712 dom.callClassMethod(dl, 'addChoices', values, labels);
5716 * Remove all existing choices from the dynamic list.
5718 * This function removes all preexisting suggested choices from the widget.
5721 * @memberof LuCI.ui.DynamicList
5723 clearChoices: function() {
5724 var dl = this.node.lastElementChild.firstElementChild;
5725 dom.callClassMethod(dl, 'clearChoices');
5730 * Instantiate a hidden input field widget.
5732 * @constructor Hiddenfield
5734 * @augments LuCI.ui.AbstractElement
5738 * The `Hiddenfield` class implements an HTML `<input type="hidden">` field
5739 * which allows to store form data without exposing it to the user.
5741 * UI widget instances are usually not supposed to be created by view code
5742 * directly, instead they're implicitely created by `LuCI.form` when
5743 * instantiating CBI forms.
5745 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5746 * in views, use `'require ui'` and refer to `ui.Hiddenfield`. To import it in
5747 * external JavaScript, use `L.require("ui").then(...)` and access the
5748 * `Hiddenfield` property of the class instance value.
5750 * @param {string|string[]} [value=null]
5751 * The initial input value.
5753 * @param {LuCI.ui.AbstractElement.InitOptions} [options]
5754 * Object describing the widget specific options to initialize the hidden input.
5756 var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ {
5757 __init__: function(value, options) {
5759 this.options = Object.assign({
5765 render: function() {
5766 var hiddenEl = E('input', {
5767 'id': this.options.id,
5772 return this.bind(hiddenEl);
5776 bind: function(hiddenEl) {
5777 this.node = hiddenEl;
5779 dom.bindClassInstance(hiddenEl, this);
5785 getValue: function() {
5786 return this.node.value;
5790 setValue: function(value) {
5791 this.node.value = value;
5796 * Instantiate a file upload widget.
5798 * @constructor FileUpload
5800 * @augments LuCI.ui.AbstractElement
5804 * The `FileUpload` class implements a widget which allows the user to upload,
5805 * browse, select and delete files beneath a predefined remote directory.
5807 * UI widget instances are usually not supposed to be created by view code
5808 * directly, instead they're implicitely created by `LuCI.form` when
5809 * instantiating CBI forms.
5811 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5812 * in views, use `'require ui'` and refer to `ui.FileUpload`. To import it in
5813 * external JavaScript, use `L.require("ui").then(...)` and access the
5814 * `FileUpload` property of the class instance value.
5816 * @param {string|string[]} [value=null]
5817 * The initial input value.
5819 * @param {LuCI.ui.DynamicList.InitOptions} [options]
5820 * Object describing the widget specific options to initialize the file
5823 var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
5825 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
5826 * the following properties are recognized:
5828 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
5829 * @memberof LuCI.ui.FileUpload
5831 * @property {boolean} [show_hidden=false]
5832 * Specifies whether hidden files should be displayed when browsing remote
5833 * files. Note that this is not a security feature, hidden files are always
5834 * present in the remote file listings received, this option merely controls
5835 * whether they're displayed or not.
5837 * @property {boolean} [enable_upload=true]
5838 * Specifies whether the widget allows the user to upload files. If set to
5839 * `false`, only existing files may be selected. Note that this is not a
5840 * security feature. Whether file upload requests are accepted remotely
5841 * depends on the ACL setup for the current session. This option merely
5842 * controls whether the upload controls are rendered or not.
5844 * @property {boolean} [enable_remove=true]
5845 * Specifies whether the widget allows the user to delete remove files.
5846 * If set to `false`, existing files may not be removed. Note that this is
5847 * not a security feature. Whether file delete requests are accepted
5848 * remotely depends on the ACL setup for the current session. This option
5849 * merely controls whether the file remove controls are rendered or not.
5851 * @property {string} [root_directory=/etc/luci-uploads]
5852 * Specifies the remote directory the upload and file browsing actions take
5853 * place in. Browsing to directories outside of the root directory is
5854 * prevented by the widget. Note that this is not a security feature.
5855 * Whether remote directories are browseable or not solely depends on the
5856 * ACL setup for the current session.
5858 __init__: function(value, options) {
5860 this.options = Object.assign({
5862 enable_upload: true,
5863 enable_remove: true,
5864 root_directory: '/etc/luci-uploads'
5869 bind: function(browserEl) {
5870 this.node = browserEl;
5872 this.setUpdateEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
5873 this.setChangeEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
5875 dom.bindClassInstance(browserEl, this);
5881 render: function() {
5882 return L.resolveDefault(this.value != null ? fs.stat(this.value) : null).then(L.bind(function(stat) {
5885 if (L.isObject(stat) && stat.type != 'directory')
5888 if (this.stat != null)
5889 label = [ this.iconForType(this.stat.type), ' %s (%1000mB)'.format(this.truncatePath(this.stat.path), this.stat.size) ];
5890 else if (this.value != null)
5891 label = [ this.iconForType('file'), ' %s (%s)'.format(this.truncatePath(this.value), _('File not accessible')) ];
5893 label = [ _('Select file…') ];
5895 return this.bind(E('div', { 'id': this.options.id }, [
5898 'click': UI.prototype.createHandlerFn(this, 'handleFileBrowser'),
5899 'disabled': this.options.disabled ? '' : null
5902 'class': 'cbi-filebrowser'
5906 'name': this.options.name,
5914 truncatePath: function(path) {
5915 if (path.length > 50)
5916 path = path.substring(0, 25) + '…' + path.substring(path.length - 25);
5922 iconForType: function(type) {
5926 'src': L.resource('cbi/link.gif'),
5927 'title': _('Symbolic link'),
5933 'src': L.resource('cbi/folder.gif'),
5934 'title': _('Directory'),
5940 'src': L.resource('cbi/file.gif'),
5948 canonicalizePath: function(path) {
5949 return path.replace(/\/{2,}/, '/')
5950 .replace(/\/\.(\/|$)/g, '/')
5951 .replace(/[^\/]+\/\.\.(\/|$)/g, '/')
5952 .replace(/\/$/, '');
5956 splitPath: function(path) {
5957 var croot = this.canonicalizePath(this.options.root_directory || '/'),
5958 cpath = this.canonicalizePath(path || '/');
5960 if (cpath.length <= croot.length)
5963 if (cpath.charAt(croot.length) != '/')
5966 var parts = cpath.substring(croot.length + 1).split(/\//);
5968 parts.unshift(croot);
5974 handleUpload: function(path, list, ev) {
5975 var form = ev.target.parentNode,
5976 fileinput = form.querySelector('input[type="file"]'),
5977 nameinput = form.querySelector('input[type="text"]'),
5978 filename = (nameinput.value != null ? nameinput.value : '').trim();
5980 ev.preventDefault();
5982 if (filename == '' || filename.match(/\//) || fileinput.files[0] == null)
5985 var existing = list.filter(function(e) { return e.name == filename })[0];
5987 if (existing != null && existing.type == 'directory')
5988 return alert(_('A directory with the same name already exists.'));
5989 else if (existing != null && !confirm(_('Overwrite existing file "%s" ?').format(filename)))
5992 var data = new FormData();
5994 data.append('sessionid', L.env.sessionid);
5995 data.append('filename', path + '/' + filename);
5996 data.append('filedata', fileinput.files[0]);
5998 return request.post(L.env.cgi_base + '/cgi-upload', data, {
5999 progress: L.bind(function(btn, ev) {
6000 btn.firstChild.data = '%.2f%%'.format((ev.loaded / ev.total) * 100);
6002 }).then(L.bind(function(path, ev, res) {
6003 var reply = res.json();
6005 if (L.isObject(reply) && reply.failure)
6006 alert(_('Upload request failed: %s').format(reply.message));
6008 return this.handleSelect(path, null, ev);
6009 }, this, path, ev));
6013 handleDelete: function(path, fileStat, ev) {
6014 var parent = path.replace(/\/[^\/]+$/, '') || '/',
6015 name = path.replace(/^.+\//, ''),
6018 ev.preventDefault();
6020 if (fileStat.type == 'directory')
6021 msg = _('Do you really want to recursively delete the directory "%s" ?').format(name);
6023 msg = _('Do you really want to delete "%s" ?').format(name);
6026 var button = this.node.firstElementChild,
6027 hidden = this.node.lastElementChild;
6029 if (path == hidden.value) {
6030 dom.content(button, _('Select file…'));
6034 return fs.remove(path).then(L.bind(function(parent, ev) {
6035 return this.handleSelect(parent, null, ev);
6036 }, this, parent, ev)).catch(function(err) {
6037 alert(_('Delete request failed: %s').format(err.message));
6043 renderUpload: function(path, list) {
6044 if (!this.options.enable_upload)
6050 'class': 'btn cbi-button-positive',
6051 'click': function(ev) {
6052 var uploadForm = ev.target.nextElementSibling,
6053 fileInput = uploadForm.querySelector('input[type="file"]');
6055 ev.target.style.display = 'none';
6056 uploadForm.style.display = '';
6059 }, _('Upload file…')),
6060 E('div', { 'class': 'upload', 'style': 'display:none' }, [
6063 'style': 'display:none',
6064 'change': function(ev) {
6065 var nameinput = ev.target.parentNode.querySelector('input[type="text"]'),
6066 uploadbtn = ev.target.parentNode.querySelector('button.cbi-button-save');
6068 nameinput.value = ev.target.value.replace(/^.+[\/\\]/, '');
6069 uploadbtn.disabled = false;
6074 'click': function(ev) {
6075 ev.preventDefault();
6076 ev.target.previousElementSibling.click();
6078 }, [ _('Browse…') ]),
6079 E('div', {}, E('input', { 'type': 'text', 'placeholder': _('Filename') })),
6081 'class': 'btn cbi-button-save',
6082 'click': UI.prototype.createHandlerFn(this, 'handleUpload', path, list),
6084 }, [ _('Upload file') ])
6090 renderListing: function(container, path, list) {
6091 var breadcrumb = E('p'),
6094 list.sort(function(a, b) {
6095 var isDirA = (a.type == 'directory'),
6096 isDirB = (b.type == 'directory');
6098 if (isDirA != isDirB)
6099 return isDirA < isDirB;
6101 return a.name > b.name;
6104 for (var i = 0; i < list.length; i++) {
6105 if (!this.options.show_hidden && list[i].name.charAt(0) == '.')
6108 var entrypath = this.canonicalizePath(path + '/' + list[i].name),
6109 selected = (entrypath == this.node.lastElementChild.value),
6110 mtime = new Date(list[i].mtime * 1000);
6112 rows.appendChild(E('li', [
6113 E('div', { 'class': 'name' }, [
6114 this.iconForType(list[i].type),
6118 'style': selected ? 'font-weight:bold' : null,
6119 'click': UI.prototype.createHandlerFn(this, 'handleSelect',
6120 entrypath, list[i].type != 'directory' ? list[i] : null)
6121 }, '%h'.format(list[i].name))
6123 E('div', { 'class': 'mtime hide-xs' }, [
6124 ' %04d-%02d-%02d %02d:%02d:%02d '.format(
6125 mtime.getFullYear(),
6126 mtime.getMonth() + 1,
6133 selected ? E('button', {
6135 'click': UI.prototype.createHandlerFn(this, 'handleReset')
6136 }, [ _('Deselect') ]) : '',
6137 this.options.enable_remove ? E('button', {
6138 'class': 'btn cbi-button-negative',
6139 'click': UI.prototype.createHandlerFn(this, 'handleDelete', entrypath, list[i])
6140 }, [ _('Delete') ]) : ''
6145 if (!rows.firstElementChild)
6146 rows.appendChild(E('em', _('No entries in this directory')));
6148 var dirs = this.splitPath(path),
6151 for (var i = 0; i < dirs.length; i++) {
6152 cur = cur ? cur + '/' + dirs[i] : dirs[i];
6153 dom.append(breadcrumb, [
6157 'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur || '/', null)
6158 }, dirs[i] != '' ? '%h'.format(dirs[i]) : E('em', '(root)')),
6162 dom.content(container, [
6165 E('div', { 'class': 'right' }, [
6166 this.renderUpload(path, list),
6170 'click': UI.prototype.createHandlerFn(this, 'handleCancel')
6177 handleCancel: function(ev) {
6178 var button = this.node.firstElementChild,
6179 browser = button.nextElementSibling;
6181 browser.classList.remove('open');
6182 button.style.display = '';
6184 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-cancel', {}));
6186 ev.preventDefault();
6190 handleReset: function(ev) {
6191 var button = this.node.firstElementChild,
6192 hidden = this.node.lastElementChild;
6195 dom.content(button, _('Select file…'));
6197 this.handleCancel(ev);
6201 handleSelect: function(path, fileStat, ev) {
6202 var browser = dom.parent(ev.target, '.cbi-filebrowser'),
6203 ul = browser.querySelector('ul');
6205 if (fileStat == null) {
6206 dom.content(ul, E('em', { 'class': 'spinning' }, _('Loading directory contents…')));
6207 L.resolveDefault(fs.list(path), []).then(L.bind(this.renderListing, this, browser, path));
6210 var button = this.node.firstElementChild,
6211 hidden = this.node.lastElementChild;
6213 path = this.canonicalizePath(path);
6215 dom.content(button, [
6216 this.iconForType(fileStat.type),
6217 ' %s (%1000mB)'.format(this.truncatePath(path), fileStat.size)
6220 browser.classList.remove('open');
6221 button.style.display = '';
6222 hidden.value = path;
6224 this.stat = Object.assign({ path: path }, fileStat);
6225 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-select', { detail: this.stat }));
6230 handleFileBrowser: function(ev) {
6231 var button = ev.target,
6232 browser = button.nextElementSibling,
6233 path = this.stat ? this.stat.path.replace(/\/[^\/]+$/, '') : (this.options.initial_directory || this.options.root_directory);
6235 if (path.indexOf(this.options.root_directory) != 0)
6236 path = this.options.root_directory;
6238 ev.preventDefault();
6240 return L.resolveDefault(fs.list(path), []).then(L.bind(function(button, browser, path, list) {
6241 document.querySelectorAll('.cbi-filebrowser.open').forEach(function(browserEl) {
6242 dom.findClassInstance(browserEl).handleCancel(ev);
6245 button.style.display = 'none';
6246 browser.classList.add('open');
6248 return this.renderListing(browser, path, list);
6249 }, this, button, browser, path));
6253 getValue: function() {
6254 return this.node.lastElementChild.value;
6258 setValue: function(value) {
6259 this.node.lastElementChild.value = value;
6273 var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ {
6275 * @typedef {Object} MenuNode
6276 * @memberof LuCI.ui.menu
6278 * @property {string} name - The internal name of the node, as used in the URL
6279 * @property {number} order - The sort index of the menu node
6280 * @property {string} [title] - The title of the menu node, `null` if the node should be hidden
6281 * @property {satisified} boolean - Boolean indicating whether the menu enries dependencies are satisfied
6282 * @property {readonly} [boolean] - Boolean indicating whether the menu entries underlying ACLs are readonly
6283 * @property {LuCI.ui.menu.MenuNode[]} [children] - Array of child menu nodes.
6287 * Load and cache current menu tree.
6289 * @returns {Promise<LuCI.ui.menu.MenuNode>}
6290 * Returns a promise resolving to the root element of the menu tree.
6293 if (this.menu == null)
6294 this.menu = session.getLocalData('menu');
6296 if (!L.isObject(this.menu)) {
6297 this.menu = request.get(L.url('admin/menu')).then(L.bind(function(menu) {
6298 this.menu = menu.json();
6299 session.setLocalData('menu', this.menu);
6305 return Promise.resolve(this.menu);
6309 * @param {LuCI.ui.menu.MenuNode} [node]
6310 * The menu node to retrieve the children for. Defaults to the menu's
6311 * internal root node if omitted.
6313 * @returns {LuCI.ui.menu.MenuNode[]}
6314 * Returns an array of child menu nodes.
6316 getChildren: function(node) {
6322 for (var k in node.children) {
6323 if (!node.children.hasOwnProperty(k))
6326 if (!node.children[k].satisfied)
6329 if (!node.children[k].hasOwnProperty('title'))
6332 children.push(Object.assign(node.children[k], { name: k }));
6335 return children.sort(function(a, b) {
6336 return ((a.order || 1000) - (b.order || 1000));
6347 * Provides high level UI helper functionality.
6348 * To import the class in views, use `'require ui'`, to import it in
6349 * external JavaScript, use `L.require("ui").then(...)`.
6351 var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
6352 __init__: function() {
6353 modalDiv = document.body.appendChild(
6354 dom.create('div', { id: 'modal_overlay' },
6355 dom.create('div', { class: 'modal', role: 'dialog', 'aria-modal': true })));
6357 tooltipDiv = document.body.appendChild(
6358 dom.create('div', { class: 'cbi-tooltip' }));
6360 /* setup old aliases */
6361 L.showModal = this.showModal;
6362 L.hideModal = this.hideModal;
6363 L.showTooltip = this.showTooltip;
6364 L.hideTooltip = this.hideTooltip;
6365 L.itemlist = this.itemlist;
6367 document.addEventListener('mouseover', this.showTooltip.bind(this), true);
6368 document.addEventListener('mouseout', this.hideTooltip.bind(this), true);
6369 document.addEventListener('focus', this.showTooltip.bind(this), true);
6370 document.addEventListener('blur', this.hideTooltip.bind(this), true);
6372 document.addEventListener('luci-loaded', this.tabs.init.bind(this.tabs));
6373 document.addEventListener('luci-loaded', this.changes.init.bind(this.changes));
6374 document.addEventListener('uci-loaded', this.changes.init.bind(this.changes));
6378 * Display a modal overlay dialog with the specified contents.
6380 * The modal overlay dialog covers the current view preventing interaction
6381 * with the underlying view contents. Only one modal dialog instance can
6382 * be opened. Invoking showModal() while a modal dialog is already open will
6383 * replace the open dialog with a new one having the specified contents.
6385 * Additional CSS class names may be passed to influence the appearence of
6386 * the dialog. Valid values for the classes depend on the underlying theme.
6388 * @see LuCI.dom.content
6390 * @param {string} [title]
6391 * The title of the dialog. If `null`, no title element will be rendered.
6393 * @param {*} contents
6394 * The contents to add to the modal dialog. This should be a DOM node or
6395 * a document fragment in most cases. The value is passed as-is to the
6396 * `dom.content()` function - refer to its documentation for applicable
6399 * @param {...string} [classes]
6400 * A number of extra CSS class names which are set on the modal dialog
6404 * Returns a DOM Node representing the modal dialog element.
6406 showModal: function(title, children /* , ... */) {
6407 var dlg = modalDiv.firstElementChild;
6409 dlg.setAttribute('class', 'modal');
6411 for (var i = 2; i < arguments.length; i++)
6412 dlg.classList.add(arguments[i]);
6414 dom.content(dlg, dom.create('h4', {}, title));
6415 dom.append(dlg, children);
6417 document.body.classList.add('modal-overlay-active');
6423 * Close the open modal overlay dialog.
6425 * This function will close an open modal dialog and restore the normal view
6426 * behaviour. It has no effect if no modal dialog is currently open.
6428 * Note that this function is stand-alone, it does not rely on `this` and
6429 * will not invoke other class functions so it suitable to be used as event
6430 * handler as-is without the need to bind it first.
6432 hideModal: function() {
6433 document.body.classList.remove('modal-overlay-active');
6437 showTooltip: function(ev) {
6438 var target = findParent(ev.target, '[data-tooltip]');
6443 if (tooltipTimeout !== null) {
6444 window.clearTimeout(tooltipTimeout);
6445 tooltipTimeout = null;
6448 var rect = target.getBoundingClientRect(),
6449 x = rect.left + window.pageXOffset,
6450 y = rect.top + rect.height + window.pageYOffset;
6452 tooltipDiv.className = 'cbi-tooltip';
6453 tooltipDiv.innerHTML = 'â–² ';
6454 tooltipDiv.firstChild.data += target.getAttribute('data-tooltip');
6456 if (target.hasAttribute('data-tooltip-style'))
6457 tooltipDiv.classList.add(target.getAttribute('data-tooltip-style'));
6459 if ((y + tooltipDiv.offsetHeight) > (window.innerHeight + window.pageYOffset)) {
6460 y -= (tooltipDiv.offsetHeight + target.offsetHeight);
6461 tooltipDiv.firstChild.data = 'â–¼ ' + tooltipDiv.firstChild.data.substr(2);
6464 tooltipDiv.style.top = y + 'px';
6465 tooltipDiv.style.left = x + 'px';
6466 tooltipDiv.style.opacity = 1;
6468 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-open', {
6470 detail: { target: target }
6475 hideTooltip: function(ev) {
6476 if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv ||
6477 tooltipDiv.contains(ev.target) || tooltipDiv.contains(ev.relatedTarget))
6480 if (tooltipTimeout !== null) {
6481 window.clearTimeout(tooltipTimeout);
6482 tooltipTimeout = null;
6485 tooltipDiv.style.opacity = 0;
6486 tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250);
6488 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-close', { bubbles: true }));
6492 * Add a notification banner at the top of the current view.
6494 * A notification banner is an alert message usually displayed at the
6495 * top of the current view, spanning the entire availibe width.
6496 * Notification banners will stay in place until dismissed by the user.
6497 * Multiple banners may be shown at the same time.
6499 * Additional CSS class names may be passed to influence the appearence of
6500 * the banner. Valid values for the classes depend on the underlying theme.
6502 * @see LuCI.dom.content
6504 * @param {string} [title]
6505 * The title of the notification banner. If `null`, no title element
6508 * @param {*} contents
6509 * The contents to add to the notification banner. This should be a DOM
6510 * node or a document fragment in most cases. The value is passed as-is
6511 * to the `dom.content()` function - refer to its documentation for
6512 * applicable values.
6514 * @param {...string} [classes]
6515 * A number of extra CSS class names which are set on the notification
6519 * Returns a DOM Node representing the notification banner element.
6521 addNotification: function(title, children /*, ... */) {
6522 var mc = document.querySelector('#maincontent') || document.body;
6523 var msg = E('div', {
6524 'class': 'alert-message fade-in',
6525 'style': 'display:flex',
6526 'transitionend': function(ev) {
6527 var node = ev.currentTarget;
6528 if (node.parentNode && node.classList.contains('fade-out'))
6529 node.parentNode.removeChild(node);
6532 E('div', { 'style': 'flex:10' }),
6533 E('div', { 'style': 'flex:1 1 auto; display:flex' }, [
6536 'style': 'margin-left:auto; margin-top:auto',
6537 'click': function(ev) {
6538 dom.parent(ev.target, '.alert-message').classList.add('fade-out');
6541 }, [ _('Dismiss') ])
6546 dom.append(msg.firstElementChild, E('h4', {}, title));
6548 dom.append(msg.firstElementChild, children);
6550 for (var i = 2; i < arguments.length; i++)
6551 msg.classList.add(arguments[i]);
6553 mc.insertBefore(msg, mc.firstElementChild);
6559 * Display or update an header area indicator.
6561 * An indicator is a small label displayed in the header area of the screen
6562 * providing few amounts of status information such as item counts or state
6563 * toggle indicators.
6565 * Multiple indicators may be shown at the same time and indicator labels
6566 * may be made clickable to display extended information or to initiate
6569 * Indicators can either use a default `active` or a less accented `inactive`
6570 * style which is useful for indicators representing state toggles.
6572 * @param {string} id
6573 * The ID of the indicator. If an indicator with the given ID already exists,
6574 * it is updated with the given label and style.
6576 * @param {string} label
6577 * The text to display in the indicator label.
6579 * @param {function} [handler]
6580 * A handler function to invoke when the indicator label is clicked/touched
6581 * by the user. If omitted, the indicator is not clickable/touchable.
6583 * Note that this parameter only applies to new indicators, when updating
6584 * existing labels it is ignored.
6586 * @param {string} [style=active]
6587 * The indicator style to use. May be either `active` or `inactive`.
6589 * @returns {boolean}
6590 * Returns `true` when the indicator has been updated or `false` when no
6591 * changes were made.
6593 showIndicator: function(id, label, handler, style) {
6594 if (indicatorDiv == null) {
6595 indicatorDiv = document.body.querySelector('#indicators');
6597 if (indicatorDiv == null)
6601 var handlerFn = (typeof(handler) == 'function') ? handler : null,
6602 indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) ||
6603 indicatorDiv.appendChild(E('span', {
6604 'data-indicator': id,
6605 'data-clickable': handlerFn ? true : null,
6609 if (label == indicatorElem.firstChild.data && style == indicatorElem.getAttribute('data-style'))
6612 indicatorElem.firstChild.data = label;
6613 indicatorElem.setAttribute('data-style', (style == 'inactive') ? 'inactive' : 'active');
6618 * Remove an header area indicator.
6620 * This function removes the given indicator label from the header indicator
6621 * area. When the given indicator is not found, this function does nothing.
6623 * @param {string} id
6624 * The ID of the indicator to remove.
6626 * @returns {boolean}
6627 * Returns `true` when the indicator has been removed or `false` when the
6628 * requested indicator was not found.
6630 hideIndicator: function(id) {
6631 var indicatorElem = indicatorDiv ? indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) : null;
6633 if (indicatorElem == null)
6636 indicatorDiv.removeChild(indicatorElem);
6641 * Formats a series of label/value pairs into list-like markup.
6643 * This function transforms a flat array of alternating label and value
6644 * elements into a list-like markup, using the values in `separators` as
6645 * separators and appends the resulting nodes to the given parent DOM node.
6647 * Each label is suffixed with `: ` and wrapped into a `<strong>` tag, the
6648 * `<strong>` element and the value corresponding to the label are
6649 * subsequently wrapped into a `<span class="nowrap">` element.
6651 * The resulting `<span>` element tuples are joined by the given separators
6652 * to form the final markup which is appened to the given parent DOM node.
6654 * @param {Node} node
6655 * The parent DOM node to append the markup to. Any previous child elements
6658 * @param {Array<*>} items
6659 * An alternating array of labels and values. The label values will be
6660 * converted to plain strings, the values are used as-is and may be of
6661 * any type accepted by `LuCI.dom.content()`.
6663 * @param {*|Array<*>} [separators=[E('br')]]
6664 * A single value or an array of separator values to separate each
6665 * label/value pair with. The function will cycle through the separators
6666 * when joining the pairs. If omitted, the default separator is a sole HTML
6667 * `<br>` element. Separator values are used as-is and may be of any type
6668 * accepted by `LuCI.dom.content()`.
6671 * Returns the parent DOM node the formatted markup has been added to.
6673 itemlist: function(node, items, separators) {
6676 if (!Array.isArray(separators))
6677 separators = [ separators || E('br') ];
6679 for (var i = 0; i < items.length; i += 2) {
6680 if (items[i+1] !== null && items[i+1] !== undefined) {
6681 var sep = separators[(i/2) % separators.length],
6684 children.push(E('span', { class: 'nowrap' }, [
6685 items[i] ? E('strong', items[i] + ': ') : '',
6689 if ((i+2) < items.length)
6690 children.push(dom.elem(sep) ? sep.cloneNode(true) : sep);
6694 dom.content(node, children);
6705 * The `tabs` class handles tab menu groups used throughout the view area.
6706 * It takes care of setting up tab groups, tracking their state and handling
6709 * This class is automatically instantiated as part of `LuCI.ui`. To use it
6710 * in views, use `'require ui'` and refer to `ui.tabs`. To import it in
6711 * external JavaScript, use `L.require("ui").then(...)` and access the
6712 * `tabs` property of the class instance value.
6714 tabs: baseclass.singleton(/* @lends LuCI.ui.tabs.prototype */ {
6717 var groups = [], prevGroup = null, currGroup = null;
6719 document.querySelectorAll('[data-tab]').forEach(function(tab) {
6720 var parent = tab.parentNode;
6722 if (dom.matches(tab, 'li') && dom.matches(parent, 'ul.cbi-tabmenu'))
6725 if (!parent.hasAttribute('data-tab-group'))
6726 parent.setAttribute('data-tab-group', groups.length);
6728 currGroup = +parent.getAttribute('data-tab-group');
6730 if (currGroup !== prevGroup) {
6731 prevGroup = currGroup;
6733 if (!groups[currGroup])
6734 groups[currGroup] = [];
6737 groups[currGroup].push(tab);
6740 for (var i = 0; i < groups.length; i++)
6741 this.initTabGroup(groups[i]);
6743 document.addEventListener('dependency-update', this.updateTabs.bind(this));
6749 * Initializes a new tab group from the given tab pane collection.
6751 * This function cycles through the given tab pane DOM nodes, extracts
6752 * their tab IDs, titles and active states, renders a corresponding
6753 * tab menu and prepends it to the tab panes common parent DOM node.
6755 * The tab menu labels will be set to the value of the `data-tab-title`
6756 * attribute of each corresponding pane. The last pane with the
6757 * `data-tab-active` attribute set to `true` will be selected by default.
6759 * If no pane is marked as active, the first one will be preselected.
6762 * @memberof LuCI.ui.tabs
6763 * @param {Array<Node>|NodeList} panes
6764 * A collection of tab panes to build a tab group menu for. May be a
6765 * plain array of DOM nodes or a NodeList collection, such as the result
6766 * of a `querySelectorAll()` call or the `.childNodes` property of a
6769 initTabGroup: function(panes) {
6770 if (typeof(panes) != 'object' || !('length' in panes) || panes.length === 0)
6773 var menu = E('ul', { 'class': 'cbi-tabmenu' }),
6774 group = panes[0].parentNode,
6775 groupId = +group.getAttribute('data-tab-group'),
6778 if (group.getAttribute('data-initialized') === 'true')
6781 for (var i = 0, pane; pane = panes[i]; i++) {
6782 var name = pane.getAttribute('data-tab'),
6783 title = pane.getAttribute('data-tab-title'),
6784 active = pane.getAttribute('data-tab-active') === 'true';
6786 menu.appendChild(E('li', {
6787 'style': this.isEmptyPane(pane) ? 'display:none' : null,
6788 'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
6792 'click': this.switchTab.bind(this)
6799 group.parentNode.insertBefore(menu, group);
6800 group.setAttribute('data-initialized', true);
6802 if (selected === null) {
6803 selected = this.getActiveTabId(panes[0]);
6805 if (selected < 0 || selected >= panes.length || this.isEmptyPane(panes[selected])) {
6806 for (var i = 0; i < panes.length; i++) {
6807 if (!this.isEmptyPane(panes[i])) {
6814 menu.childNodes[selected].classList.add('cbi-tab');
6815 menu.childNodes[selected].classList.remove('cbi-tab-disabled');
6816 panes[selected].setAttribute('data-tab-active', 'true');
6818 this.setActiveTabId(panes[selected], selected);
6821 panes[selected].dispatchEvent(new CustomEvent('cbi-tab-active', {
6822 detail: { tab: panes[selected].getAttribute('data-tab') }
6825 this.updateTabs(group);
6829 * Checks whether the given tab pane node is empty.
6832 * @memberof LuCI.ui.tabs
6833 * @param {Node} pane
6834 * The tab pane to check.
6836 * @returns {boolean}
6837 * Returns `true` if the pane is empty, else `false`.
6839 isEmptyPane: function(pane) {
6840 return dom.isEmpty(pane, function(n) { return n.classList.contains('cbi-tab-descr') });
6844 getPathForPane: function(pane) {
6845 var path = [], node = null;
6847 for (node = pane ? pane.parentNode : null;
6848 node != null && node.hasAttribute != null;
6849 node = node.parentNode)
6851 if (node.hasAttribute('data-tab'))
6852 path.unshift(node.getAttribute('data-tab'));
6853 else if (node.hasAttribute('data-section-id'))
6854 path.unshift(node.getAttribute('data-section-id'));
6857 return path.join('/');
6861 getActiveTabState: function() {
6862 var page = document.body.getAttribute('data-page'),
6863 state = session.getLocalData('tab');
6865 if (L.isObject(state) && state.page === page && L.isObject(state.paths))
6868 session.setLocalData('tab', null);
6870 return { page: page, paths: {} };
6874 getActiveTabId: function(pane) {
6875 var path = this.getPathForPane(pane);
6876 return +this.getActiveTabState().paths[path] || 0;
6880 setActiveTabId: function(pane, tabIndex) {
6881 var path = this.getPathForPane(pane),
6882 state = this.getActiveTabState();
6884 state.paths[path] = tabIndex;
6886 return session.setLocalData('tab', state);
6890 updateTabs: function(ev, root) {
6891 (root || document).querySelectorAll('[data-tab-title]').forEach(L.bind(function(pane) {
6892 var menu = pane.parentNode.previousElementSibling,
6893 tab = menu ? menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))) : null,
6894 n_errors = pane.querySelectorAll('.cbi-input-invalid').length;
6899 if (this.isEmptyPane(pane)) {
6900 tab.style.display = 'none';
6901 tab.classList.remove('flash');
6903 else if (tab.style.display === 'none') {
6904 tab.style.display = '';
6905 requestAnimationFrame(function() { tab.classList.add('flash') });
6909 tab.setAttribute('data-errors', n_errors);
6910 tab.setAttribute('data-tooltip', _('%d invalid field(s)').format(n_errors));
6911 tab.setAttribute('data-tooltip-style', 'error');
6914 tab.removeAttribute('data-errors');
6915 tab.removeAttribute('data-tooltip');
6921 switchTab: function(ev) {
6922 var tab = ev.target.parentNode,
6923 name = tab.getAttribute('data-tab'),
6924 menu = tab.parentNode,
6925 group = menu.nextElementSibling,
6926 groupId = +group.getAttribute('data-tab-group'),
6929 ev.preventDefault();
6931 if (!tab.classList.contains('cbi-tab-disabled'))
6934 menu.querySelectorAll('[data-tab]').forEach(function(tab) {
6935 tab.classList.remove('cbi-tab');
6936 tab.classList.remove('cbi-tab-disabled');
6938 tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled');
6941 group.childNodes.forEach(function(pane) {
6942 if (dom.matches(pane, '[data-tab]')) {
6943 if (pane.getAttribute('data-tab') === name) {
6944 pane.setAttribute('data-tab-active', 'true');
6945 pane.dispatchEvent(new CustomEvent('cbi-tab-active', { detail: { tab: name } }));
6946 UI.prototype.tabs.setActiveTabId(pane, index);
6949 pane.setAttribute('data-tab-active', 'false');
6959 * @typedef {Object} FileUploadReply
6962 * @property {string} name - Name of the uploaded file without directory components
6963 * @property {number} size - Size of the uploaded file in bytes
6964 * @property {string} checksum - The MD5 checksum of the received file data
6965 * @property {string} sha256sum - The SHA256 checksum of the received file data
6969 * Display a modal file upload prompt.
6971 * This function opens a modal dialog prompting the user to select and
6972 * upload a file to a predefined remote destination path.
6974 * @param {string} path
6975 * The remote file path to upload the local file to.
6977 * @param {Node} [progessStatusNode]
6978 * An optional DOM text node whose content text is set to the progress
6979 * percentage value during file upload.
6981 * @returns {Promise<LuCI.ui.FileUploadReply>}
6982 * Returns a promise resolving to a file upload status object on success
6983 * or rejecting with an error in case the upload failed or has been
6984 * cancelled by the user.
6986 uploadFile: function(path, progressStatusNode) {
6987 return new Promise(function(resolveFn, rejectFn) {
6988 UI.prototype.showModal(_('Uploading file…'), [
6989 E('p', _('Please select the file to upload.')),
6990 E('div', { 'style': 'display:flex' }, [
6991 E('div', { 'class': 'left', 'style': 'flex:1' }, [
6994 style: 'display:none',
6995 change: function(ev) {
6996 var modal = dom.parent(ev.target, '.modal'),
6997 body = modal.querySelector('p'),
6998 upload = modal.querySelector('.cbi-button-action.important'),
6999 file = ev.currentTarget.files[0];
7006 E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]),
7007 E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ])
7011 upload.disabled = false;
7017 'click': function(ev) {
7018 ev.target.previousElementSibling.click();
7020 }, [ _('Browse…') ])
7022 E('div', { 'class': 'right', 'style': 'flex:1' }, [
7025 'click': function() {
7026 UI.prototype.hideModal();
7027 rejectFn(new Error('Upload has been cancelled'));
7029 }, [ _('Cancel') ]),
7032 'class': 'btn cbi-button-action important',
7034 'click': function(ev) {
7035 var input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]');
7037 if (!input.files[0])
7040 var progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' }));
7042 UI.prototype.showModal(_('Uploading file…'), [ progress ]);
7044 var data = new FormData();
7046 data.append('sessionid', rpc.getSessionID());
7047 data.append('filename', path);
7048 data.append('filedata', input.files[0]);
7050 var filename = input.files[0].name;
7052 request.post(L.env.cgi_base + '/cgi-upload', data, {
7054 progress: function(pev) {
7055 var percent = (pev.loaded / pev.total) * 100;
7057 if (progressStatusNode)
7058 progressStatusNode.data = '%.2f%%'.format(percent);
7060 progress.setAttribute('title', '%.2f%%'.format(percent));
7061 progress.firstElementChild.style.width = '%.2f%%'.format(percent);
7063 }).then(function(res) {
7064 var reply = res.json();
7066 UI.prototype.hideModal();
7068 if (L.isObject(reply) && reply.failure) {
7069 UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message)));
7070 rejectFn(new Error(reply.failure));
7073 reply.name = filename;
7077 UI.prototype.hideModal();
7089 * Perform a device connectivity test.
7091 * Attempt to fetch a well known ressource from the remote device via HTTP
7092 * in order to test connectivity. This function is mainly useful to wait
7093 * for the router to come back online after a reboot or reconfiguration.
7095 * @param {string} [proto=http]
7096 * The protocol to use for fetching the resource. May be either `http`
7097 * (the default) or `https`.
7099 * @param {string} [host=window.location.host]
7100 * Override the host address to probe. By default the current host as seen
7101 * in the address bar is probed.
7103 * @returns {Promise<Event>}
7104 * Returns a promise resolving to a `load` event in case the device is
7105 * reachable or rejecting with an `error` event in case it is not reachable
7106 * or rejecting with `null` when the connectivity check timed out.
7108 pingDevice: function(proto, ipaddr) {
7109 var target = '%s://%s%s?%s'.format(proto || 'http', ipaddr || window.location.host, L.resource('icons/loading.gif'), Math.random());
7111 return new Promise(function(resolveFn, rejectFn) {
7112 var img = new Image();
7114 img.onload = resolveFn;
7115 img.onerror = rejectFn;
7117 window.setTimeout(rejectFn, 1000);
7124 * Wait for device to come back online and reconnect to it.
7126 * Poll each given hostname or IP address and navigate to it as soon as
7127 * one of the addresses becomes reachable.
7129 * @param {...string} [hosts=[window.location.host]]
7130 * The list of IP addresses and host names to check for reachability.
7131 * If omitted, the current value of `window.location.host` is used by
7134 awaitReconnect: function(/* ... */) {
7135 var ipaddrs = arguments.length ? arguments : [ window.location.host ];
7137 window.setTimeout(L.bind(function() {
7138 poll.add(L.bind(function() {
7139 var tasks = [], reachable = false;
7141 for (var i = 0; i < 2; i++)
7142 for (var j = 0; j < ipaddrs.length; j++)
7143 tasks.push(this.pingDevice(i ? 'https' : 'http', ipaddrs[j])
7144 .then(function(ev) { reachable = ev.target.src.replace(/^(https?:\/\/[^\/]+).*$/, '$1/') }, function() {}));
7146 return Promise.all(tasks).then(function() {
7149 window.location = reachable;
7162 * The `changes` class encapsulates logic for visualizing, applying,
7163 * confirming and reverting staged UCI changesets.
7165 * This class is automatically instantiated as part of `LuCI.ui`. To use it
7166 * in views, use `'require ui'` and refer to `ui.changes`. To import it in
7167 * external JavaScript, use `L.require("ui").then(...)` and access the
7168 * `changes` property of the class instance value.
7170 changes: baseclass.singleton(/* @lends LuCI.ui.changes.prototype */ {
7172 if (!L.env.sessionid)
7175 return uci.changes().then(L.bind(this.renderChangeIndicator, this));
7179 * Set the change count indicator.
7181 * This function updates or hides the UCI change count indicator,
7182 * depending on the passed change count. When the count is greater
7183 * than 0, the change indicator is displayed or updated, otherwise it
7187 * @memberof LuCI.ui.changes
7188 * @param {number} numChanges
7189 * The number of changes to indicate.
7191 setIndicator: function(n) {
7193 UI.prototype.showIndicator('uci-changes',
7194 '%s: %d'.format(_('Unsaved Changes'), n),
7195 L.bind(this.displayChanges, this));
7198 UI.prototype.hideIndicator('uci-changes');
7203 * Update the change count indicator.
7205 * This function updates the UCI change count indicator from the given
7206 * UCI changeset structure.
7209 * @memberof LuCI.ui.changes
7210 * @param {Object<string, Array<LuCI.uci.ChangeRecord>>} changes
7211 * The UCI changeset to count.
7213 renderChangeIndicator: function(changes) {
7216 for (var config in changes)
7217 if (changes.hasOwnProperty(config))
7218 n_changes += changes[config].length;
7220 this.changes = changes;
7221 this.setIndicator(n_changes);
7226 'add-3': '<ins>uci add %0 <strong>%3</strong> # =%2</ins>',
7227 'set-3': '<ins>uci set %0.<strong>%2</strong>=%3</ins>',
7228 'set-4': '<var><ins>uci set %0.%2.%3=<strong>%4</strong></ins></var>',
7229 'remove-2': '<del>uci del %0.<strong>%2</strong></del>',
7230 'remove-3': '<var><del>uci del %0.%2.<strong>%3</strong></del></var>',
7231 'order-3': '<var>uci reorder %0.%2=<strong>%3</strong></var>',
7232 'list-add-4': '<var><ins>uci add_list %0.%2.%3=<strong>%4</strong></ins></var>',
7233 'list-del-4': '<var><del>uci del_list %0.%2.%3=<strong>%4</strong></del></var>',
7234 'rename-3': '<var>uci rename %0.%2=<strong>%3</strong></var>',
7235 'rename-4': '<var>uci rename %0.%2.%3=<strong>%4</strong></var>'
7239 * Display the current changelog.
7241 * Open a modal dialog visualizing the currently staged UCI changes
7242 * and offer options to revert or apply the shown changes.
7245 * @memberof LuCI.ui.changes
7247 displayChanges: function() {
7248 var list = E('div', { 'class': 'uci-change-list' }),
7249 dlg = UI.prototype.showModal(_('Configuration') + ' / ' + _('Changes'), [
7250 E('div', { 'class': 'cbi-section' }, [
7251 E('strong', _('Legend:')),
7252 E('div', { 'class': 'uci-change-legend' }, [
7253 E('div', { 'class': 'uci-change-legend-label' }, [
7254 E('ins', '&#160;'), ' ', _('Section added') ]),
7255 E('div', { 'class': 'uci-change-legend-label' }, [
7256 E('del', '&#160;'), ' ', _('Section removed') ]),
7257 E('div', { 'class': 'uci-change-legend-label' }, [
7258 E('var', {}, E('ins', '&#160;')), ' ', _('Option changed') ]),
7259 E('div', { 'class': 'uci-change-legend-label' }, [
7260 E('var', {}, E('del', '&#160;')), ' ', _('Option removed') ])]),
7262 E('div', { 'class': 'right' }, [
7265 'click': UI.prototype.hideModal
7266 }, [ _('Dismiss') ]), ' ',
7268 'class': 'cbi-button cbi-button-positive important',
7269 'click': L.bind(this.apply, this, true)
7270 }, [ _('Save & Apply') ]), ' ',
7272 'class': 'cbi-button cbi-button-reset',
7273 'click': L.bind(this.revert, this)
7274 }, [ _('Revert') ])])])
7277 for (var config in this.changes) {
7278 if (!this.changes.hasOwnProperty(config))
7281 list.appendChild(E('h5', '# /etc/config/%s'.format(config)));
7283 for (var i = 0, added = null; i < this.changes[config].length; i++) {
7284 var chg = this.changes[config][i],
7285 tpl = this.changeTemplates['%s-%d'.format(chg[0], chg.length)];
7287 list.appendChild(E(tpl.replace(/%([01234])/g, function(m0, m1) {
7293 if (added != null && chg[1] == added[0])
7294 return '@' + added[1] + '[-1]';
7299 return "'%h'".format(chg[3].replace(/'/g, "'\"'\"'"));
7306 if (chg[0] == 'add')
7307 added = [ chg[1], chg[2] ];
7311 list.appendChild(E('br'));
7312 dlg.classList.add('uci-dialog');
7316 displayStatus: function(type, content) {
7318 var message = UI.prototype.showModal('', '');
7320 message.classList.add('alert-message');
7321 DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
7324 dom.content(message, content);
7326 if (!this.was_polling) {
7327 this.was_polling = request.poll.active();
7328 request.poll.stop();
7332 UI.prototype.hideModal();
7334 if (this.was_polling)
7335 request.poll.start();
7340 rollback: function(checked) {
7342 this.displayStatus('warning spinning',
7343 E('p', _('Failed to confirm apply within %ds, waiting for rollback…')
7344 .format(L.env.apply_rollback)));
7346 var call = function(r, data, duration) {
7347 if (r.status === 204) {
7348 UI.prototype.changes.displayStatus('warning', [
7349 E('h4', _('Configuration changes have been rolled back!')),
7350 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)),
7351 E('div', { 'class': 'right' }, [
7354 'click': L.bind(UI.prototype.changes.displayStatus, UI.prototype.changes, false)
7355 }, [ _('Dismiss') ]), ' ',
7357 'class': 'btn cbi-button-action important',
7358 'click': L.bind(UI.prototype.changes.revert, UI.prototype.changes)
7359 }, [ _('Revert changes') ]), ' ',
7361 'class': 'btn cbi-button-negative important',
7362 'click': L.bind(UI.prototype.changes.apply, UI.prototype.changes, false)
7363 }, [ _('Apply unchecked') ])
7370 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
7371 window.setTimeout(function() {
7372 request.request(L.url('admin/uci/confirm'), {
7374 timeout: L.env.apply_timeout * 1000,
7375 query: { sid: L.env.sessionid, token: L.env.token }
7380 call({ status: 0 });
7383 this.displayStatus('warning', [
7384 E('h4', _('Device unreachable!')),
7385 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.'))
7391 confirm: function(checked, deadline, override_token) {
7393 var ts = Date.now();
7395 this.displayStatus('notice');
7398 this.confirm_auth = { token: override_token };
7400 var call = function(r, data, duration) {
7401 if (Date.now() >= deadline) {
7402 window.clearTimeout(tt);
7403 UI.prototype.changes.rollback(checked);
7406 else if (r && (r.status === 200 || r.status === 204)) {
7407 document.dispatchEvent(new CustomEvent('uci-applied'));
7409 UI.prototype.changes.setIndicator(0);
7410 UI.prototype.changes.displayStatus('notice',
7411 E('p', _('Configuration changes applied.')));
7413 window.clearTimeout(tt);
7414 window.setTimeout(function() {
7415 //UI.prototype.changes.displayStatus(false);
7416 window.location = window.location.href.split('#')[0];
7417 }, L.env.apply_display * 1000);
7422 var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
7423 window.setTimeout(function() {
7424 request.request(L.url('admin/uci/confirm'), {
7426 timeout: L.env.apply_timeout * 1000,
7427 query: UI.prototype.changes.confirm_auth
7428 }).then(call, call);
7432 var tick = function() {
7433 var now = Date.now();
7435 UI.prototype.changes.displayStatus('notice spinning',
7436 E('p', _('Applying configuration changes… %ds')
7437 .format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0))));
7439 if (now >= deadline)
7442 tt = window.setTimeout(tick, 1000 - (now - ts));
7448 /* wait a few seconds for the settings to become effective */
7449 window.setTimeout(call, Math.max(L.env.apply_holdoff * 1000 - ((ts + L.env.apply_rollback * 1000) - deadline), 1));
7453 * Apply the staged configuration changes.
7455 * Start applying staged configuration changes and open a modal dialog
7456 * with a progress indication to prevent interaction with the view
7457 * during the apply process. The modal dialog will be automatically
7458 * closed and the current view reloaded once the apply process is
7462 * @memberof LuCI.ui.changes
7463 * @param {boolean} [checked=false]
7464 * Whether to perform a checked (`true`) configuration apply or an
7465 * unchecked (`false`) one.
7467 * In case of a checked apply, the configuration changes must be
7468 * confirmed within a specific time interval, otherwise the device
7469 * will begin to roll back the changes in order to restore the previous
7472 apply: function(checked) {
7473 this.displayStatus('notice spinning',
7474 E('p', _('Starting configuration apply…')));
7476 request.request(L.url('admin/uci', checked ? 'apply_rollback' : 'apply_unchecked'), {
7478 query: { sid: L.env.sessionid, token: L.env.token }
7479 }).then(function(r) {
7480 if (r.status === (checked ? 200 : 204)) {
7481 var tok = null; try { tok = r.json(); } catch(e) {}
7482 if (checked && tok !== null && typeof(tok) === 'object' && typeof(tok.token) === 'string')
7483 UI.prototype.changes.confirm_auth = tok;
7485 UI.prototype.changes.confirm(checked, Date.now() + L.env.apply_rollback * 1000);
7487 else if (checked && r.status === 204) {
7488 UI.prototype.changes.displayStatus('notice',
7489 E('p', _('There are no changes to apply')));
7491 window.setTimeout(function() {
7492 UI.prototype.changes.displayStatus(false);
7493 }, L.env.apply_display * 1000);
7496 UI.prototype.changes.displayStatus('warning',
7497 E('p', _('Apply request failed with status <code>%h</code>')
7498 .format(r.responseText || r.statusText || r.status)));
7500 window.setTimeout(function() {
7501 UI.prototype.changes.displayStatus(false);
7502 }, L.env.apply_display * 1000);
7508 * Revert the staged configuration changes.
7510 * Start reverting staged configuration changes and open a modal dialog
7511 * with a progress indication to prevent interaction with the view
7512 * during the revert process. The modal dialog will be automatically
7513 * closed and the current view reloaded once the revert process is
7517 * @memberof LuCI.ui.changes
7519 revert: function() {
7520 this.displayStatus('notice spinning',
7521 E('p', _('Reverting configuration…')));
7523 request.request(L.url('admin/uci/revert'), {
7525 query: { sid: L.env.sessionid, token: L.env.token }
7526 }).then(function(r) {
7527 if (r.status === 200) {
7528 document.dispatchEvent(new CustomEvent('uci-reverted'));
7530 UI.prototype.changes.setIndicator(0);
7531 UI.prototype.changes.displayStatus('notice',
7532 E('p', _('Changes have been reverted.')));
7534 window.setTimeout(function() {
7535 //UI.prototype.changes.displayStatus(false);
7536 window.location = window.location.href.split('#')[0];
7537 }, L.env.apply_display * 1000);
7540 UI.prototype.changes.displayStatus('warning',
7541 E('p', _('Revert request failed with status <code>%h</code>')
7542 .format(r.statusText || r.status)));
7544 window.setTimeout(function() {
7545 UI.prototype.changes.displayStatus(false);
7546 }, L.env.apply_display * 1000);
7553 * Add validation constraints to an input element.
7555 * Compile the given type expression and optional validator function into
7556 * a validation function and bind it to the specified input element events.
7558 * @param {Node} field
7559 * The DOM input element node to bind the validation constraints to.
7561 * @param {string} type
7562 * The datatype specification to describe validation constraints.
7563 * Refer to the `LuCI.validation` class documentation for details.
7565 * @param {boolean} [optional=false]
7566 * Specifies whether empty values are allowed (`true`) or not (`false`).
7567 * If an input element is not marked optional it must not be empty,
7568 * otherwise it will be marked as invalid.
7570 * @param {function} [vfunc]
7571 * Specifies a custom validation function which is invoked after the
7572 * other validation constraints are applied. The validation must return
7573 * `true` to accept the passed value. Any other return type is converted
7574 * to a string and treated as validation error message.
7576 * @param {...string} [events=blur, keyup]
7577 * The list of events to bind. Each received event will trigger a field
7578 * validation. If omitted, the `keyup` and `blur` events are bound by
7581 * @returns {function}
7582 * Returns the compiled validator function which can be used to manually
7583 * trigger field validation or to bind it to further events.
7585 * @see LuCI.validation
7587 addValidator: function(field, type, optional, vfunc /*, ... */) {
7591 var events = this.varargs(arguments, 3);
7592 if (events.length == 0)
7593 events.push('blur', 'keyup');
7596 var cbiValidator = validation.create(field, type, optional, vfunc),
7597 validatorFn = cbiValidator.validate.bind(cbiValidator);
7599 for (var i = 0; i < events.length; i++)
7600 field.addEventListener(events[i], validatorFn);
7610 * Create a pre-bound event handler function.
7612 * Generate and bind a function suitable for use in event handlers. The
7613 * generated function automatically disables the event source element
7614 * and adds an active indication to it by adding appropriate CSS classes.
7616 * It will also await any promises returned by the wrapped function and
7617 * re-enable the source element after the promises ran to completion.
7620 * The `this` context to use for the wrapped function.
7622 * @param {function|string} fn
7623 * Specifies the function to wrap. In case of a function value, the
7624 * function is used as-is. If a string is specified instead, it is looked
7625 * up in `ctx` to obtain the function to wrap. In both cases the bound
7626 * function will be invoked with `ctx` as `this` context
7628 * @param {...*} extra_args
7629 * Any further parameter as passed as-is to the bound event handler
7630 * function in the same order as passed to `createHandlerFn()`.
7632 * @returns {function|null}
7633 * Returns the pre-bound handler function which is suitable to be passed
7634 * to `addEventListener()`. Returns `null` if the given `fn` argument is
7635 * a string which could not be found in `ctx` or if `ctx[fn]` is not a
7636 * valid function value.
7638 createHandlerFn: function(ctx, fn /*, ... */) {
7639 if (typeof(fn) == 'string')
7642 if (typeof(fn) != 'function')
7645 var arg_offset = arguments.length - 2;
7647 return Function.prototype.bind.apply(function() {
7648 var t = arguments[arg_offset].currentTarget;
7650 t.classList.add('spinning');
7656 Promise.resolve(fn.apply(ctx, arguments)).finally(function() {
7657 t.classList.remove('spinning');
7660 }, this.varargs(arguments, 2, ctx));
7664 * Load specified view class path and set it up.
7666 * Transforms the given view path into a class name, requires it
7667 * using [LuCI.require()]{@link LuCI#require} and asserts that the
7668 * resulting class instance is a descendant of
7669 * [LuCI.view]{@link LuCI.view}.
7671 * By instantiating the view class, its corresponding contents are
7672 * rendered and included into the view area. Any runtime errors are
7673 * catched and rendered using [LuCI.error()]{@link LuCI#error}.
7675 * @param {string} path
7676 * The view path to render.
7678 * @returns {Promise<LuCI.view>}
7679 * Returns a promise resolving to the loaded view instance.
7681 instantiateView: function(path) {
7682 var className = 'view.%s'.format(path.replace(/\//g, '.'));
7684 return L.require(className).then(function(view) {
7685 if (!(view instanceof View))
7686 throw new TypeError('Loaded class %s is not a descendant of View'.format(className));
7689 }).catch(function(err) {
7690 dom.content(document.querySelector('#view'), null);
7697 AbstractElement: UIElement,
7700 Textfield: UITextfield,
7701 Textarea: UITextarea,
7702 Checkbox: UICheckbox,
7704 Dropdown: UIDropdown,
7705 DynamicList: UIDynamicList,
7706 Combobox: UICombobox,
7707 ComboButton: UIComboButton,
7708 Hiddenfield: UIHiddenfield,
7709 FileUpload: UIFileUpload
7725 Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Thu Apr 16 2020 13:30:42 GMT+0200 (Central European Summer Time)
7729 <script>prettyPrint();</script>
7730 <script src="scripts/jaguar.js"></script>