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#naturalCompare"><a href=
"LuCI.html#naturalCompare">naturalCompare
</a></li>
54 <li data-name=
"LuCI#Poll"><a href=
"LuCI.html#Poll">Poll
</a></li>
56 <li data-name=
"LuCI#Request"><a href=
"LuCI.html#Request">Request
</a></li>
58 <li data-name=
"LuCI#view"><a href=
"LuCI.html#view">view
</a></li>
61 <ul class=
"typedefs itemMembers">
63 <span class=
"subtitle">Typedefs
</span>
65 <li data-name=
"LuCI.requestCallbackFn"><a href=
"LuCI.html#.requestCallbackFn">requestCallbackFn
</a></li>
68 <ul class=
"typedefs itemMembers">
71 <ul class=
"methods itemMembers">
73 <span class=
"subtitle">Methods
</span>
75 <li data-name=
"LuCI#bind"><a href=
"LuCI.html#bind">bind
</a></li>
77 <li data-name=
"LuCI#error"><a href=
"LuCI.html#error">error
</a></li>
79 <li data-name=
"LuCI#fspath"><a href=
"LuCI.html#fspath">fspath
</a></li>
81 <li data-name=
"LuCI#get"><a href=
"LuCI.html#get">get
</a></li>
83 <li data-name=
"LuCI#halt"><a href=
"LuCI.html#halt">halt
</a></li>
85 <li data-name=
"LuCI#hasSystemFeature"><a href=
"LuCI.html#hasSystemFeature">hasSystemFeature
</a></li>
87 <li data-name=
"LuCI#hasViewPermission"><a href=
"LuCI.html#hasViewPermission">hasViewPermission
</a></li>
89 <li data-name=
"LuCI#isObject"><a href=
"LuCI.html#isObject">isObject
</a></li>
91 <li data-name=
"LuCI#location"><a href=
"LuCI.html#location">location
</a></li>
93 <li data-name=
"LuCI#media"><a href=
"LuCI.html#media">media
</a></li>
95 <li data-name=
"LuCI#path"><a href=
"LuCI.html#path">path
</a></li>
97 <li data-name=
"LuCI#poll"><a href=
"LuCI.html#poll">poll
</a></li>
99 <li data-name=
"LuCI#post"><a href=
"LuCI.html#post">post
</a></li>
101 <li data-name=
"LuCI#raise"><a href=
"LuCI.html#raise">raise
</a></li>
103 <li data-name=
"LuCI#require"><a href=
"LuCI.html#require">require
</a></li>
105 <li data-name=
"LuCI#resolveDefault"><a href=
"LuCI.html#resolveDefault">resolveDefault
</a></li>
107 <li data-name=
"LuCI#resource"><a href=
"LuCI.html#resource">resource
</a></li>
109 <li data-name=
"LuCI#run"><a href=
"LuCI.html#run">run
</a></li>
111 <li data-name=
"LuCI#sortedArray"><a href=
"LuCI.html#sortedArray">sortedArray
</a></li>
113 <li data-name=
"LuCI#sortedKeys"><a href=
"LuCI.html#sortedKeys">sortedKeys
</a></li>
115 <li data-name=
"LuCI#stop"><a href=
"LuCI.html#stop">stop
</a></li>
117 <li data-name=
"LuCI#toArray"><a href=
"LuCI.html#toArray">toArray
</a></li>
119 <li data-name=
"LuCI#url"><a href=
"LuCI.html#url">url
</a></li>
122 <ul class=
"events itemMembers">
127 <li class=
"item" data-name=
"LuCI.baseclass">
129 <a href=
"LuCI.baseclass.html">LuCI.baseclass
</a>
132 <ul class=
"members itemMembers">
135 <ul class=
"typedefs itemMembers">
138 <ul class=
"typedefs itemMembers">
141 <ul class=
"methods itemMembers">
143 <span class=
"subtitle">Methods
</span>
145 <li data-name=
"LuCI.baseclass.extend"><a href=
"LuCI.baseclass.html#.extend">extend
</a></li>
147 <li data-name=
"LuCI.baseclass.instantiate"><a href=
"LuCI.baseclass.html#.instantiate">instantiate
</a></li>
149 <li data-name=
"LuCI.baseclass.isSubclass"><a href=
"LuCI.baseclass.html#.isSubclass">isSubclass
</a></li>
151 <li data-name=
"LuCI.baseclass.singleton"><a href=
"LuCI.baseclass.html#.singleton">singleton
</a></li>
153 <li data-name=
"LuCI.baseclass#super"><a href=
"LuCI.baseclass.html#super">super
</a></li>
155 <li data-name=
"LuCI.baseclass#varargs"><a href=
"LuCI.baseclass.html#varargs">varargs
</a></li>
158 <ul class=
"events itemMembers">
163 <li class=
"item" data-name=
"LuCI.dom">
165 <a href=
"LuCI.dom.html">LuCI.dom
</a>
168 <ul class=
"members itemMembers">
171 <ul class=
"typedefs itemMembers">
173 <span class=
"subtitle">Typedefs
</span>
175 <li data-name=
"LuCI.dom~ignoreCallbackFn"><a href=
"LuCI.dom.html#~ignoreCallbackFn">ignoreCallbackFn
</a></li>
178 <ul class=
"typedefs itemMembers">
181 <ul class=
"methods itemMembers">
183 <span class=
"subtitle">Methods
</span>
185 <li data-name=
"LuCI.dom#append"><a href=
"LuCI.dom.html#append">append
</a></li>
187 <li data-name=
"LuCI.dom#attr"><a href=
"LuCI.dom.html#attr">attr
</a></li>
189 <li data-name=
"LuCI.dom#bindClassInstance"><a href=
"LuCI.dom.html#bindClassInstance">bindClassInstance
</a></li>
191 <li data-name=
"LuCI.dom#callClassMethod"><a href=
"LuCI.dom.html#callClassMethod">callClassMethod
</a></li>
193 <li data-name=
"LuCI.dom#content"><a href=
"LuCI.dom.html#content">content
</a></li>
195 <li data-name=
"LuCI.dom#create"><a href=
"LuCI.dom.html#create">create
</a></li>
197 <li data-name=
"LuCI.dom#data"><a href=
"LuCI.dom.html#data">data
</a></li>
199 <li data-name=
"LuCI.dom#elem"><a href=
"LuCI.dom.html#elem">elem
</a></li>
201 <li data-name=
"LuCI.dom#findClassInstance"><a href=
"LuCI.dom.html#findClassInstance">findClassInstance
</a></li>
203 <li data-name=
"LuCI.dom#isEmpty"><a href=
"LuCI.dom.html#isEmpty">isEmpty
</a></li>
205 <li data-name=
"LuCI.dom#matches"><a href=
"LuCI.dom.html#matches">matches
</a></li>
207 <li data-name=
"LuCI.dom#parent"><a href=
"LuCI.dom.html#parent">parent
</a></li>
209 <li data-name=
"LuCI.dom#parse"><a href=
"LuCI.dom.html#parse">parse
</a></li>
212 <ul class=
"events itemMembers">
217 <li class=
"item" data-name=
"LuCI.form">
219 <a href=
"LuCI.form.html">LuCI.form
</a>
222 <ul class=
"members itemMembers">
225 <ul class=
"typedefs itemMembers">
228 <ul class=
"typedefs itemMembers">
231 <ul class=
"methods itemMembers">
234 <ul class=
"events itemMembers">
239 <li class=
"item" data-name=
"LuCI.form.AbstractElement">
241 <a href=
"LuCI.form.AbstractElement.html">LuCI.form.AbstractElement
</a>
244 <ul class=
"members itemMembers">
247 <ul class=
"typedefs itemMembers">
250 <ul class=
"typedefs itemMembers">
253 <ul class=
"methods itemMembers">
255 <span class=
"subtitle">Methods
</span>
257 <li data-name=
"LuCI.form.AbstractElement#append"><a href=
"LuCI.form.AbstractElement.html#append">append
</a></li>
259 <li data-name=
"LuCI.form.AbstractElement#parse"><a href=
"LuCI.form.AbstractElement.html#parse">parse
</a></li>
261 <li data-name=
"LuCI.form.AbstractElement#render"><a href=
"LuCI.form.AbstractElement.html#render">render
</a></li>
263 <li data-name=
"LuCI.form.AbstractElement#stripTags"><a href=
"LuCI.form.AbstractElement.html#stripTags">stripTags
</a></li>
265 <li data-name=
"LuCI.form.AbstractElement#titleFn"><a href=
"LuCI.form.AbstractElement.html#titleFn">titleFn
</a></li>
268 <ul class=
"events itemMembers">
273 <li class=
"item" data-name=
"LuCI.form.AbstractSection">
275 <a href=
"LuCI.form.AbstractSection.html">LuCI.form.AbstractSection
</a>
278 <ul class=
"members itemMembers">
280 <span class=
"subtitle">Members
</span>
282 <li data-name=
"LuCI.form.AbstractSection##parentoption"><a href=
"LuCI.form.AbstractSection.html#parentoption">parentoption
</a></li>
285 <ul class=
"typedefs itemMembers">
288 <ul class=
"typedefs itemMembers">
291 <ul class=
"methods itemMembers">
293 <span class=
"subtitle">Methods
</span>
295 <li data-name=
"LuCI.form.AbstractSection#append"><a href=
"LuCI.form.AbstractSection.html#append">append
</a></li>
297 <li data-name=
"LuCI.form.AbstractSection#cfgsections"><a href=
"LuCI.form.AbstractSection.html#cfgsections">cfgsections
</a></li>
299 <li data-name=
"LuCI.form.AbstractSection#cfgvalue"><a href=
"LuCI.form.AbstractSection.html#cfgvalue">cfgvalue
</a></li>
301 <li data-name=
"LuCI.form.AbstractSection#filter"><a href=
"LuCI.form.AbstractSection.html#filter">filter
</a></li>
303 <li data-name=
"LuCI.form.AbstractSection#formvalue"><a href=
"LuCI.form.AbstractSection.html#formvalue">formvalue
</a></li>
305 <li data-name=
"LuCI.form.AbstractSection#getOption"><a href=
"LuCI.form.AbstractSection.html#getOption">getOption
</a></li>
307 <li data-name=
"LuCI.form.AbstractSection#getUIElement"><a href=
"LuCI.form.AbstractSection.html#getUIElement">getUIElement
</a></li>
309 <li data-name=
"LuCI.form.AbstractSection#load"><a href=
"LuCI.form.AbstractSection.html#load">load
</a></li>
311 <li data-name=
"LuCI.form.AbstractSection#option"><a href=
"LuCI.form.AbstractSection.html#option">option
</a></li>
313 <li data-name=
"LuCI.form.AbstractSection#parse"><a href=
"LuCI.form.AbstractSection.html#parse">parse
</a></li>
315 <li data-name=
"LuCI.form.AbstractSection#render"><a href=
"LuCI.form.AbstractSection.html#render">render
</a></li>
317 <li data-name=
"LuCI.form.AbstractSection#stripTags"><a href=
"LuCI.form.AbstractSection.html#stripTags">stripTags
</a></li>
319 <li data-name=
"LuCI.form.AbstractSection#tab"><a href=
"LuCI.form.AbstractSection.html#tab">tab
</a></li>
321 <li data-name=
"LuCI.form.AbstractSection#taboption"><a href=
"LuCI.form.AbstractSection.html#taboption">taboption
</a></li>
323 <li data-name=
"LuCI.form.AbstractSection#titleFn"><a href=
"LuCI.form.AbstractSection.html#titleFn">titleFn
</a></li>
326 <ul class=
"events itemMembers">
331 <li class=
"item" data-name=
"LuCI.form.AbstractValue">
333 <a href=
"LuCI.form.AbstractValue.html">LuCI.form.AbstractValue
</a>
336 <ul class=
"members itemMembers">
338 <span class=
"subtitle">Members
</span>
340 <li data-name=
"LuCI.form.AbstractValue##datatype"><a href=
"LuCI.form.AbstractValue.html#datatype">datatype
</a></li>
342 <li data-name=
"LuCI.form.AbstractValue##default"><a href=
"LuCI.form.AbstractValue.html#default">default
</a></li>
344 <li data-name=
"LuCI.form.AbstractValue##editable"><a href=
"LuCI.form.AbstractValue.html#editable">editable
</a></li>
346 <li data-name=
"LuCI.form.AbstractValue##modalonly"><a href=
"LuCI.form.AbstractValue.html#modalonly">modalonly
</a></li>
348 <li data-name=
"LuCI.form.AbstractValue##onchange"><a href=
"LuCI.form.AbstractValue.html#onchange">onchange
</a></li>
350 <li data-name=
"LuCI.form.AbstractValue##optional"><a href=
"LuCI.form.AbstractValue.html#optional">optional
</a></li>
352 <li data-name=
"LuCI.form.AbstractValue##readonly"><a href=
"LuCI.form.AbstractValue.html#readonly">readonly
</a></li>
354 <li data-name=
"LuCI.form.AbstractValue##retain"><a href=
"LuCI.form.AbstractValue.html#retain">retain
</a></li>
356 <li data-name=
"LuCI.form.AbstractValue##rmempty"><a href=
"LuCI.form.AbstractValue.html#rmempty">rmempty
</a></li>
358 <li data-name=
"LuCI.form.AbstractValue##uciconfig"><a href=
"LuCI.form.AbstractValue.html#uciconfig">uciconfig
</a></li>
360 <li data-name=
"LuCI.form.AbstractValue##ucioption"><a href=
"LuCI.form.AbstractValue.html#ucioption">ucioption
</a></li>
362 <li data-name=
"LuCI.form.AbstractValue##ucisection"><a href=
"LuCI.form.AbstractValue.html#ucisection">ucisection
</a></li>
364 <li data-name=
"LuCI.form.AbstractValue##validate"><a href=
"LuCI.form.AbstractValue.html#validate">validate
</a></li>
366 <li data-name=
"LuCI.form.AbstractValue##width"><a href=
"LuCI.form.AbstractValue.html#width">width
</a></li>
369 <ul class=
"typedefs itemMembers">
372 <ul class=
"typedefs itemMembers">
375 <ul class=
"methods itemMembers">
377 <span class=
"subtitle">Methods
</span>
379 <li data-name=
"LuCI.form.AbstractValue#append"><a href=
"LuCI.form.AbstractValue.html#append">append
</a></li>
381 <li data-name=
"LuCI.form.AbstractValue#cbid"><a href=
"LuCI.form.AbstractValue.html#cbid">cbid
</a></li>
383 <li data-name=
"LuCI.form.AbstractValue#cfgvalue"><a href=
"LuCI.form.AbstractValue.html#cfgvalue">cfgvalue
</a></li>
385 <li data-name=
"LuCI.form.AbstractValue#depends"><a href=
"LuCI.form.AbstractValue.html#depends">depends
</a></li>
387 <li data-name=
"LuCI.form.AbstractValue#formvalue"><a href=
"LuCI.form.AbstractValue.html#formvalue">formvalue
</a></li>
389 <li data-name=
"LuCI.form.AbstractValue#getUIElement"><a href=
"LuCI.form.AbstractValue.html#getUIElement">getUIElement
</a></li>
391 <li data-name=
"LuCI.form.AbstractValue#getValidationError"><a href=
"LuCI.form.AbstractValue.html#getValidationError">getValidationError
</a></li>
393 <li data-name=
"LuCI.form.AbstractValue#isActive"><a href=
"LuCI.form.AbstractValue.html#isActive">isActive
</a></li>
395 <li data-name=
"LuCI.form.AbstractValue#isValid"><a href=
"LuCI.form.AbstractValue.html#isValid">isValid
</a></li>
397 <li data-name=
"LuCI.form.AbstractValue#load"><a href=
"LuCI.form.AbstractValue.html#load">load
</a></li>
399 <li data-name=
"LuCI.form.AbstractValue#parse"><a href=
"LuCI.form.AbstractValue.html#parse">parse
</a></li>
401 <li data-name=
"LuCI.form.AbstractValue#remove"><a href=
"LuCI.form.AbstractValue.html#remove">remove
</a></li>
403 <li data-name=
"LuCI.form.AbstractValue#render"><a href=
"LuCI.form.AbstractValue.html#render">render
</a></li>
405 <li data-name=
"LuCI.form.AbstractValue#stripTags"><a href=
"LuCI.form.AbstractValue.html#stripTags">stripTags
</a></li>
407 <li data-name=
"LuCI.form.AbstractValue#textvalue"><a href=
"LuCI.form.AbstractValue.html#textvalue">textvalue
</a></li>
409 <li data-name=
"LuCI.form.AbstractValue#titleFn"><a href=
"LuCI.form.AbstractValue.html#titleFn">titleFn
</a></li>
411 <li data-name=
"LuCI.form.AbstractValue#validate"><a href=
"LuCI.form.AbstractValue.html#validate">validate
</a></li>
413 <li data-name=
"LuCI.form.AbstractValue#write"><a href=
"LuCI.form.AbstractValue.html#write">write
</a></li>
416 <ul class=
"events itemMembers">
421 <li class=
"item" data-name=
"LuCI.form.ButtonValue">
423 <a href=
"LuCI.form.ButtonValue.html">LuCI.form.ButtonValue
</a>
426 <ul class=
"members itemMembers">
428 <span class=
"subtitle">Members
</span>
430 <li data-name=
"LuCI.form.ButtonValue##inputstyle"><a href=
"LuCI.form.ButtonValue.html#inputstyle">inputstyle
</a></li>
432 <li data-name=
"LuCI.form.ButtonValue##inputtitle"><a href=
"LuCI.form.ButtonValue.html#inputtitle">inputtitle
</a></li>
434 <li data-name=
"LuCI.form.ButtonValue##onclick"><a href=
"LuCI.form.ButtonValue.html#onclick">onclick
</a></li>
436 <li data-name=
"LuCI.form.ButtonValue#datatype"><a href=
"LuCI.form.ButtonValue.html#datatype">datatype
</a></li>
438 <li data-name=
"LuCI.form.ButtonValue#default"><a href=
"LuCI.form.ButtonValue.html#default">default
</a></li>
440 <li data-name=
"LuCI.form.ButtonValue#editable"><a href=
"LuCI.form.ButtonValue.html#editable">editable
</a></li>
442 <li data-name=
"LuCI.form.ButtonValue#modalonly"><a href=
"LuCI.form.ButtonValue.html#modalonly">modalonly
</a></li>
444 <li data-name=
"LuCI.form.ButtonValue#onchange"><a href=
"LuCI.form.ButtonValue.html#onchange">onchange
</a></li>
446 <li data-name=
"LuCI.form.ButtonValue#optional"><a href=
"LuCI.form.ButtonValue.html#optional">optional
</a></li>
448 <li data-name=
"LuCI.form.ButtonValue#password"><a href=
"LuCI.form.ButtonValue.html#password">password
</a></li>
450 <li data-name=
"LuCI.form.ButtonValue#placeholder"><a href=
"LuCI.form.ButtonValue.html#placeholder">placeholder
</a></li>
452 <li data-name=
"LuCI.form.ButtonValue#readonly"><a href=
"LuCI.form.ButtonValue.html#readonly">readonly
</a></li>
454 <li data-name=
"LuCI.form.ButtonValue#retain"><a href=
"LuCI.form.ButtonValue.html#retain">retain
</a></li>
456 <li data-name=
"LuCI.form.ButtonValue#rmempty"><a href=
"LuCI.form.ButtonValue.html#rmempty">rmempty
</a></li>
458 <li data-name=
"LuCI.form.ButtonValue#uciconfig"><a href=
"LuCI.form.ButtonValue.html#uciconfig">uciconfig
</a></li>
460 <li data-name=
"LuCI.form.ButtonValue#ucioption"><a href=
"LuCI.form.ButtonValue.html#ucioption">ucioption
</a></li>
462 <li data-name=
"LuCI.form.ButtonValue#ucisection"><a href=
"LuCI.form.ButtonValue.html#ucisection">ucisection
</a></li>
464 <li data-name=
"LuCI.form.ButtonValue#validate"><a href=
"LuCI.form.ButtonValue.html#validate">validate
</a></li>
466 <li data-name=
"LuCI.form.ButtonValue#width"><a href=
"LuCI.form.ButtonValue.html#width">width
</a></li>
469 <ul class=
"typedefs itemMembers">
472 <ul class=
"typedefs itemMembers">
475 <ul class=
"methods itemMembers">
477 <span class=
"subtitle">Methods
</span>
479 <li data-name=
"LuCI.form.ButtonValue#append"><a href=
"LuCI.form.ButtonValue.html#append">append
</a></li>
481 <li data-name=
"LuCI.form.ButtonValue#cbid"><a href=
"LuCI.form.ButtonValue.html#cbid">cbid
</a></li>
483 <li data-name=
"LuCI.form.ButtonValue#cfgvalue"><a href=
"LuCI.form.ButtonValue.html#cfgvalue">cfgvalue
</a></li>
485 <li data-name=
"LuCI.form.ButtonValue#depends"><a href=
"LuCI.form.ButtonValue.html#depends">depends
</a></li>
487 <li data-name=
"LuCI.form.ButtonValue#formvalue"><a href=
"LuCI.form.ButtonValue.html#formvalue">formvalue
</a></li>
489 <li data-name=
"LuCI.form.ButtonValue#getUIElement"><a href=
"LuCI.form.ButtonValue.html#getUIElement">getUIElement
</a></li>
491 <li data-name=
"LuCI.form.ButtonValue#getValidationError"><a href=
"LuCI.form.ButtonValue.html#getValidationError">getValidationError
</a></li>
493 <li data-name=
"LuCI.form.ButtonValue#isActive"><a href=
"LuCI.form.ButtonValue.html#isActive">isActive
</a></li>
495 <li data-name=
"LuCI.form.ButtonValue#isValid"><a href=
"LuCI.form.ButtonValue.html#isValid">isValid
</a></li>
497 <li data-name=
"LuCI.form.ButtonValue#load"><a href=
"LuCI.form.ButtonValue.html#load">load
</a></li>
499 <li data-name=
"LuCI.form.ButtonValue#parse"><a href=
"LuCI.form.ButtonValue.html#parse">parse
</a></li>
501 <li data-name=
"LuCI.form.ButtonValue#remove"><a href=
"LuCI.form.ButtonValue.html#remove">remove
</a></li>
503 <li data-name=
"LuCI.form.ButtonValue#stripTags"><a href=
"LuCI.form.ButtonValue.html#stripTags">stripTags
</a></li>
505 <li data-name=
"LuCI.form.ButtonValue#textvalue"><a href=
"LuCI.form.ButtonValue.html#textvalue">textvalue
</a></li>
507 <li data-name=
"LuCI.form.ButtonValue#titleFn"><a href=
"LuCI.form.ButtonValue.html#titleFn">titleFn
</a></li>
509 <li data-name=
"LuCI.form.ButtonValue#value"><a href=
"LuCI.form.ButtonValue.html#value">value
</a></li>
511 <li data-name=
"LuCI.form.ButtonValue#write"><a href=
"LuCI.form.ButtonValue.html#write">write
</a></li>
514 <ul class=
"events itemMembers">
519 <li class=
"item" data-name=
"LuCI.form.DummyValue">
521 <a href=
"LuCI.form.DummyValue.html">LuCI.form.DummyValue
</a>
524 <ul class=
"members itemMembers">
526 <span class=
"subtitle">Members
</span>
528 <li data-name=
"LuCI.form.DummyValue##hidden"><a href=
"LuCI.form.DummyValue.html#hidden">hidden
</a></li>
530 <li data-name=
"LuCI.form.DummyValue##href"><a href=
"LuCI.form.DummyValue.html#href">href
</a></li>
532 <li data-name=
"LuCI.form.DummyValue##rawhtml"><a href=
"LuCI.form.DummyValue.html#rawhtml">rawhtml
</a></li>
534 <li data-name=
"LuCI.form.DummyValue#datatype"><a href=
"LuCI.form.DummyValue.html#datatype">datatype
</a></li>
536 <li data-name=
"LuCI.form.DummyValue#default"><a href=
"LuCI.form.DummyValue.html#default">default
</a></li>
538 <li data-name=
"LuCI.form.DummyValue#editable"><a href=
"LuCI.form.DummyValue.html#editable">editable
</a></li>
540 <li data-name=
"LuCI.form.DummyValue#modalonly"><a href=
"LuCI.form.DummyValue.html#modalonly">modalonly
</a></li>
542 <li data-name=
"LuCI.form.DummyValue#onchange"><a href=
"LuCI.form.DummyValue.html#onchange">onchange
</a></li>
544 <li data-name=
"LuCI.form.DummyValue#optional"><a href=
"LuCI.form.DummyValue.html#optional">optional
</a></li>
546 <li data-name=
"LuCI.form.DummyValue#password"><a href=
"LuCI.form.DummyValue.html#password">password
</a></li>
548 <li data-name=
"LuCI.form.DummyValue#placeholder"><a href=
"LuCI.form.DummyValue.html#placeholder">placeholder
</a></li>
550 <li data-name=
"LuCI.form.DummyValue#readonly"><a href=
"LuCI.form.DummyValue.html#readonly">readonly
</a></li>
552 <li data-name=
"LuCI.form.DummyValue#retain"><a href=
"LuCI.form.DummyValue.html#retain">retain
</a></li>
554 <li data-name=
"LuCI.form.DummyValue#rmempty"><a href=
"LuCI.form.DummyValue.html#rmempty">rmempty
</a></li>
556 <li data-name=
"LuCI.form.DummyValue#uciconfig"><a href=
"LuCI.form.DummyValue.html#uciconfig">uciconfig
</a></li>
558 <li data-name=
"LuCI.form.DummyValue#ucioption"><a href=
"LuCI.form.DummyValue.html#ucioption">ucioption
</a></li>
560 <li data-name=
"LuCI.form.DummyValue#ucisection"><a href=
"LuCI.form.DummyValue.html#ucisection">ucisection
</a></li>
562 <li data-name=
"LuCI.form.DummyValue#validate"><a href=
"LuCI.form.DummyValue.html#validate">validate
</a></li>
564 <li data-name=
"LuCI.form.DummyValue#width"><a href=
"LuCI.form.DummyValue.html#width">width
</a></li>
567 <ul class=
"typedefs itemMembers">
570 <ul class=
"typedefs itemMembers">
573 <ul class=
"methods itemMembers">
575 <span class=
"subtitle">Methods
</span>
577 <li data-name=
"LuCI.form.DummyValue#append"><a href=
"LuCI.form.DummyValue.html#append">append
</a></li>
579 <li data-name=
"LuCI.form.DummyValue#cbid"><a href=
"LuCI.form.DummyValue.html#cbid">cbid
</a></li>
581 <li data-name=
"LuCI.form.DummyValue#cfgvalue"><a href=
"LuCI.form.DummyValue.html#cfgvalue">cfgvalue
</a></li>
583 <li data-name=
"LuCI.form.DummyValue#depends"><a href=
"LuCI.form.DummyValue.html#depends">depends
</a></li>
585 <li data-name=
"LuCI.form.DummyValue#formvalue"><a href=
"LuCI.form.DummyValue.html#formvalue">formvalue
</a></li>
587 <li data-name=
"LuCI.form.DummyValue#getUIElement"><a href=
"LuCI.form.DummyValue.html#getUIElement">getUIElement
</a></li>
589 <li data-name=
"LuCI.form.DummyValue#getValidationError"><a href=
"LuCI.form.DummyValue.html#getValidationError">getValidationError
</a></li>
591 <li data-name=
"LuCI.form.DummyValue#isActive"><a href=
"LuCI.form.DummyValue.html#isActive">isActive
</a></li>
593 <li data-name=
"LuCI.form.DummyValue#isValid"><a href=
"LuCI.form.DummyValue.html#isValid">isValid
</a></li>
595 <li data-name=
"LuCI.form.DummyValue#load"><a href=
"LuCI.form.DummyValue.html#load">load
</a></li>
597 <li data-name=
"LuCI.form.DummyValue#parse"><a href=
"LuCI.form.DummyValue.html#parse">parse
</a></li>
599 <li data-name=
"LuCI.form.DummyValue#remove"><a href=
"LuCI.form.DummyValue.html#remove">remove
</a></li>
601 <li data-name=
"LuCI.form.DummyValue#stripTags"><a href=
"LuCI.form.DummyValue.html#stripTags">stripTags
</a></li>
603 <li data-name=
"LuCI.form.DummyValue#textvalue"><a href=
"LuCI.form.DummyValue.html#textvalue">textvalue
</a></li>
605 <li data-name=
"LuCI.form.DummyValue#titleFn"><a href=
"LuCI.form.DummyValue.html#titleFn">titleFn
</a></li>
607 <li data-name=
"LuCI.form.DummyValue#value"><a href=
"LuCI.form.DummyValue.html#value">value
</a></li>
609 <li data-name=
"LuCI.form.DummyValue#write"><a href=
"LuCI.form.DummyValue.html#write">write
</a></li>
612 <ul class=
"events itemMembers">
617 <li class=
"item" data-name=
"LuCI.form.DynamicList">
619 <a href=
"LuCI.form.DynamicList.html">LuCI.form.DynamicList
</a>
622 <ul class=
"members itemMembers">
624 <span class=
"subtitle">Members
</span>
626 <li data-name=
"LuCI.form.DynamicList#datatype"><a href=
"LuCI.form.DynamicList.html#datatype">datatype
</a></li>
628 <li data-name=
"LuCI.form.DynamicList#default"><a href=
"LuCI.form.DynamicList.html#default">default
</a></li>
630 <li data-name=
"LuCI.form.DynamicList#editable"><a href=
"LuCI.form.DynamicList.html#editable">editable
</a></li>
632 <li data-name=
"LuCI.form.DynamicList#modalonly"><a href=
"LuCI.form.DynamicList.html#modalonly">modalonly
</a></li>
634 <li data-name=
"LuCI.form.DynamicList#onchange"><a href=
"LuCI.form.DynamicList.html#onchange">onchange
</a></li>
636 <li data-name=
"LuCI.form.DynamicList#optional"><a href=
"LuCI.form.DynamicList.html#optional">optional
</a></li>
638 <li data-name=
"LuCI.form.DynamicList#password"><a href=
"LuCI.form.DynamicList.html#password">password
</a></li>
640 <li data-name=
"LuCI.form.DynamicList#placeholder"><a href=
"LuCI.form.DynamicList.html#placeholder">placeholder
</a></li>
642 <li data-name=
"LuCI.form.DynamicList#readonly"><a href=
"LuCI.form.DynamicList.html#readonly">readonly
</a></li>
644 <li data-name=
"LuCI.form.DynamicList#retain"><a href=
"LuCI.form.DynamicList.html#retain">retain
</a></li>
646 <li data-name=
"LuCI.form.DynamicList#rmempty"><a href=
"LuCI.form.DynamicList.html#rmempty">rmempty
</a></li>
648 <li data-name=
"LuCI.form.DynamicList#uciconfig"><a href=
"LuCI.form.DynamicList.html#uciconfig">uciconfig
</a></li>
650 <li data-name=
"LuCI.form.DynamicList#ucioption"><a href=
"LuCI.form.DynamicList.html#ucioption">ucioption
</a></li>
652 <li data-name=
"LuCI.form.DynamicList#ucisection"><a href=
"LuCI.form.DynamicList.html#ucisection">ucisection
</a></li>
654 <li data-name=
"LuCI.form.DynamicList#validate"><a href=
"LuCI.form.DynamicList.html#validate">validate
</a></li>
656 <li data-name=
"LuCI.form.DynamicList#width"><a href=
"LuCI.form.DynamicList.html#width">width
</a></li>
659 <ul class=
"typedefs itemMembers">
662 <ul class=
"typedefs itemMembers">
665 <ul class=
"methods itemMembers">
667 <span class=
"subtitle">Methods
</span>
669 <li data-name=
"LuCI.form.DynamicList#append"><a href=
"LuCI.form.DynamicList.html#append">append
</a></li>
671 <li data-name=
"LuCI.form.DynamicList#cbid"><a href=
"LuCI.form.DynamicList.html#cbid">cbid
</a></li>
673 <li data-name=
"LuCI.form.DynamicList#cfgvalue"><a href=
"LuCI.form.DynamicList.html#cfgvalue">cfgvalue
</a></li>
675 <li data-name=
"LuCI.form.DynamicList#depends"><a href=
"LuCI.form.DynamicList.html#depends">depends
</a></li>
677 <li data-name=
"LuCI.form.DynamicList#formvalue"><a href=
"LuCI.form.DynamicList.html#formvalue">formvalue
</a></li>
679 <li data-name=
"LuCI.form.DynamicList#getUIElement"><a href=
"LuCI.form.DynamicList.html#getUIElement">getUIElement
</a></li>
681 <li data-name=
"LuCI.form.DynamicList#getValidationError"><a href=
"LuCI.form.DynamicList.html#getValidationError">getValidationError
</a></li>
683 <li data-name=
"LuCI.form.DynamicList#isActive"><a href=
"LuCI.form.DynamicList.html#isActive">isActive
</a></li>
685 <li data-name=
"LuCI.form.DynamicList#isValid"><a href=
"LuCI.form.DynamicList.html#isValid">isValid
</a></li>
687 <li data-name=
"LuCI.form.DynamicList#load"><a href=
"LuCI.form.DynamicList.html#load">load
</a></li>
689 <li data-name=
"LuCI.form.DynamicList#parse"><a href=
"LuCI.form.DynamicList.html#parse">parse
</a></li>
691 <li data-name=
"LuCI.form.DynamicList#remove"><a href=
"LuCI.form.DynamicList.html#remove">remove
</a></li>
693 <li data-name=
"LuCI.form.DynamicList#stripTags"><a href=
"LuCI.form.DynamicList.html#stripTags">stripTags
</a></li>
695 <li data-name=
"LuCI.form.DynamicList#textvalue"><a href=
"LuCI.form.DynamicList.html#textvalue">textvalue
</a></li>
697 <li data-name=
"LuCI.form.DynamicList#titleFn"><a href=
"LuCI.form.DynamicList.html#titleFn">titleFn
</a></li>
699 <li data-name=
"LuCI.form.DynamicList#value"><a href=
"LuCI.form.DynamicList.html#value">value
</a></li>
701 <li data-name=
"LuCI.form.DynamicList#write"><a href=
"LuCI.form.DynamicList.html#write">write
</a></li>
704 <ul class=
"events itemMembers">
709 <li class=
"item" data-name=
"LuCI.form.FileUpload">
711 <a href=
"LuCI.form.FileUpload.html">LuCI.form.FileUpload
</a>
714 <ul class=
"members itemMembers">
716 <span class=
"subtitle">Members
</span>
718 <li data-name=
"LuCI.form.FileUpload##enable_remove"><a href=
"LuCI.form.FileUpload.html#enable_remove">enable_remove
</a></li>
720 <li data-name=
"LuCI.form.FileUpload##enable_upload"><a href=
"LuCI.form.FileUpload.html#enable_upload">enable_upload
</a></li>
722 <li data-name=
"LuCI.form.FileUpload##root_directory"><a href=
"LuCI.form.FileUpload.html#root_directory">root_directory
</a></li>
724 <li data-name=
"LuCI.form.FileUpload##show_hidden"><a href=
"LuCI.form.FileUpload.html#show_hidden">show_hidden
</a></li>
726 <li data-name=
"LuCI.form.FileUpload#datatype"><a href=
"LuCI.form.FileUpload.html#datatype">datatype
</a></li>
728 <li data-name=
"LuCI.form.FileUpload#default"><a href=
"LuCI.form.FileUpload.html#default">default
</a></li>
730 <li data-name=
"LuCI.form.FileUpload#editable"><a href=
"LuCI.form.FileUpload.html#editable">editable
</a></li>
732 <li data-name=
"LuCI.form.FileUpload#modalonly"><a href=
"LuCI.form.FileUpload.html#modalonly">modalonly
</a></li>
734 <li data-name=
"LuCI.form.FileUpload#onchange"><a href=
"LuCI.form.FileUpload.html#onchange">onchange
</a></li>
736 <li data-name=
"LuCI.form.FileUpload#optional"><a href=
"LuCI.form.FileUpload.html#optional">optional
</a></li>
738 <li data-name=
"LuCI.form.FileUpload#password"><a href=
"LuCI.form.FileUpload.html#password">password
</a></li>
740 <li data-name=
"LuCI.form.FileUpload#placeholder"><a href=
"LuCI.form.FileUpload.html#placeholder">placeholder
</a></li>
742 <li data-name=
"LuCI.form.FileUpload#readonly"><a href=
"LuCI.form.FileUpload.html#readonly">readonly
</a></li>
744 <li data-name=
"LuCI.form.FileUpload#retain"><a href=
"LuCI.form.FileUpload.html#retain">retain
</a></li>
746 <li data-name=
"LuCI.form.FileUpload#rmempty"><a href=
"LuCI.form.FileUpload.html#rmempty">rmempty
</a></li>
748 <li data-name=
"LuCI.form.FileUpload#uciconfig"><a href=
"LuCI.form.FileUpload.html#uciconfig">uciconfig
</a></li>
750 <li data-name=
"LuCI.form.FileUpload#ucioption"><a href=
"LuCI.form.FileUpload.html#ucioption">ucioption
</a></li>
752 <li data-name=
"LuCI.form.FileUpload#ucisection"><a href=
"LuCI.form.FileUpload.html#ucisection">ucisection
</a></li>
754 <li data-name=
"LuCI.form.FileUpload#validate"><a href=
"LuCI.form.FileUpload.html#validate">validate
</a></li>
756 <li data-name=
"LuCI.form.FileUpload#width"><a href=
"LuCI.form.FileUpload.html#width">width
</a></li>
759 <ul class=
"typedefs itemMembers">
762 <ul class=
"typedefs itemMembers">
765 <ul class=
"methods itemMembers">
767 <span class=
"subtitle">Methods
</span>
769 <li data-name=
"LuCI.form.FileUpload#append"><a href=
"LuCI.form.FileUpload.html#append">append
</a></li>
771 <li data-name=
"LuCI.form.FileUpload#cbid"><a href=
"LuCI.form.FileUpload.html#cbid">cbid
</a></li>
773 <li data-name=
"LuCI.form.FileUpload#cfgvalue"><a href=
"LuCI.form.FileUpload.html#cfgvalue">cfgvalue
</a></li>
775 <li data-name=
"LuCI.form.FileUpload#depends"><a href=
"LuCI.form.FileUpload.html#depends">depends
</a></li>
777 <li data-name=
"LuCI.form.FileUpload#formvalue"><a href=
"LuCI.form.FileUpload.html#formvalue">formvalue
</a></li>
779 <li data-name=
"LuCI.form.FileUpload#getUIElement"><a href=
"LuCI.form.FileUpload.html#getUIElement">getUIElement
</a></li>
781 <li data-name=
"LuCI.form.FileUpload#getValidationError"><a href=
"LuCI.form.FileUpload.html#getValidationError">getValidationError
</a></li>
783 <li data-name=
"LuCI.form.FileUpload#isActive"><a href=
"LuCI.form.FileUpload.html#isActive">isActive
</a></li>
785 <li data-name=
"LuCI.form.FileUpload#isValid"><a href=
"LuCI.form.FileUpload.html#isValid">isValid
</a></li>
787 <li data-name=
"LuCI.form.FileUpload#load"><a href=
"LuCI.form.FileUpload.html#load">load
</a></li>
789 <li data-name=
"LuCI.form.FileUpload#parse"><a href=
"LuCI.form.FileUpload.html#parse">parse
</a></li>
791 <li data-name=
"LuCI.form.FileUpload#remove"><a href=
"LuCI.form.FileUpload.html#remove">remove
</a></li>
793 <li data-name=
"LuCI.form.FileUpload#stripTags"><a href=
"LuCI.form.FileUpload.html#stripTags">stripTags
</a></li>
795 <li data-name=
"LuCI.form.FileUpload#textvalue"><a href=
"LuCI.form.FileUpload.html#textvalue">textvalue
</a></li>
797 <li data-name=
"LuCI.form.FileUpload#titleFn"><a href=
"LuCI.form.FileUpload.html#titleFn">titleFn
</a></li>
799 <li data-name=
"LuCI.form.FileUpload#value"><a href=
"LuCI.form.FileUpload.html#value">value
</a></li>
801 <li data-name=
"LuCI.form.FileUpload#write"><a href=
"LuCI.form.FileUpload.html#write">write
</a></li>
804 <ul class=
"events itemMembers">
809 <li class=
"item" data-name=
"LuCI.form.FlagValue">
811 <a href=
"LuCI.form.FlagValue.html">LuCI.form.FlagValue
</a>
814 <ul class=
"members itemMembers">
816 <span class=
"subtitle">Members
</span>
818 <li data-name=
"LuCI.form.FlagValue##disabled"><a href=
"LuCI.form.FlagValue.html#disabled">disabled
</a></li>
820 <li data-name=
"LuCI.form.FlagValue##enabled"><a href=
"LuCI.form.FlagValue.html#enabled">enabled
</a></li>
822 <li data-name=
"LuCI.form.FlagValue#datatype"><a href=
"LuCI.form.FlagValue.html#datatype">datatype
</a></li>
824 <li data-name=
"LuCI.form.FlagValue#default"><a href=
"LuCI.form.FlagValue.html#default">default
</a></li>
826 <li data-name=
"LuCI.form.FlagValue#editable"><a href=
"LuCI.form.FlagValue.html#editable">editable
</a></li>
828 <li data-name=
"LuCI.form.FlagValue#modalonly"><a href=
"LuCI.form.FlagValue.html#modalonly">modalonly
</a></li>
830 <li data-name=
"LuCI.form.FlagValue#onchange"><a href=
"LuCI.form.FlagValue.html#onchange">onchange
</a></li>
832 <li data-name=
"LuCI.form.FlagValue#optional"><a href=
"LuCI.form.FlagValue.html#optional">optional
</a></li>
834 <li data-name=
"LuCI.form.FlagValue#password"><a href=
"LuCI.form.FlagValue.html#password">password
</a></li>
836 <li data-name=
"LuCI.form.FlagValue#placeholder"><a href=
"LuCI.form.FlagValue.html#placeholder">placeholder
</a></li>
838 <li data-name=
"LuCI.form.FlagValue#readonly"><a href=
"LuCI.form.FlagValue.html#readonly">readonly
</a></li>
840 <li data-name=
"LuCI.form.FlagValue#retain"><a href=
"LuCI.form.FlagValue.html#retain">retain
</a></li>
842 <li data-name=
"LuCI.form.FlagValue#rmempty"><a href=
"LuCI.form.FlagValue.html#rmempty">rmempty
</a></li>
844 <li data-name=
"LuCI.form.FlagValue#uciconfig"><a href=
"LuCI.form.FlagValue.html#uciconfig">uciconfig
</a></li>
846 <li data-name=
"LuCI.form.FlagValue#ucioption"><a href=
"LuCI.form.FlagValue.html#ucioption">ucioption
</a></li>
848 <li data-name=
"LuCI.form.FlagValue#ucisection"><a href=
"LuCI.form.FlagValue.html#ucisection">ucisection
</a></li>
850 <li data-name=
"LuCI.form.FlagValue#validate"><a href=
"LuCI.form.FlagValue.html#validate">validate
</a></li>
852 <li data-name=
"LuCI.form.FlagValue#width"><a href=
"LuCI.form.FlagValue.html#width">width
</a></li>
855 <ul class=
"typedefs itemMembers">
858 <ul class=
"typedefs itemMembers">
861 <ul class=
"methods itemMembers">
863 <span class=
"subtitle">Methods
</span>
865 <li data-name=
"LuCI.form.FlagValue#append"><a href=
"LuCI.form.FlagValue.html#append">append
</a></li>
867 <li data-name=
"LuCI.form.FlagValue#cbid"><a href=
"LuCI.form.FlagValue.html#cbid">cbid
</a></li>
869 <li data-name=
"LuCI.form.FlagValue#cfgvalue"><a href=
"LuCI.form.FlagValue.html#cfgvalue">cfgvalue
</a></li>
871 <li data-name=
"LuCI.form.FlagValue#depends"><a href=
"LuCI.form.FlagValue.html#depends">depends
</a></li>
873 <li data-name=
"LuCI.form.FlagValue#formvalue"><a href=
"LuCI.form.FlagValue.html#formvalue">formvalue
</a></li>
875 <li data-name=
"LuCI.form.FlagValue#getUIElement"><a href=
"LuCI.form.FlagValue.html#getUIElement">getUIElement
</a></li>
877 <li data-name=
"LuCI.form.FlagValue#getValidationError"><a href=
"LuCI.form.FlagValue.html#getValidationError">getValidationError
</a></li>
879 <li data-name=
"LuCI.form.FlagValue#isActive"><a href=
"LuCI.form.FlagValue.html#isActive">isActive
</a></li>
881 <li data-name=
"LuCI.form.FlagValue#isValid"><a href=
"LuCI.form.FlagValue.html#isValid">isValid
</a></li>
883 <li data-name=
"LuCI.form.FlagValue#load"><a href=
"LuCI.form.FlagValue.html#load">load
</a></li>
885 <li data-name=
"LuCI.form.FlagValue#parse"><a href=
"LuCI.form.FlagValue.html#parse">parse
</a></li>
887 <li data-name=
"LuCI.form.FlagValue#remove"><a href=
"LuCI.form.FlagValue.html#remove">remove
</a></li>
889 <li data-name=
"LuCI.form.FlagValue#stripTags"><a href=
"LuCI.form.FlagValue.html#stripTags">stripTags
</a></li>
891 <li data-name=
"LuCI.form.FlagValue#textvalue"><a href=
"LuCI.form.FlagValue.html#textvalue">textvalue
</a></li>
893 <li data-name=
"LuCI.form.FlagValue#titleFn"><a href=
"LuCI.form.FlagValue.html#titleFn">titleFn
</a></li>
895 <li data-name=
"LuCI.form.FlagValue#value"><a href=
"LuCI.form.FlagValue.html#value">value
</a></li>
897 <li data-name=
"LuCI.form.FlagValue#write"><a href=
"LuCI.form.FlagValue.html#write">write
</a></li>
900 <ul class=
"events itemMembers">
905 <li class=
"item" data-name=
"LuCI.form.GridSection">
907 <a href=
"LuCI.form.GridSection.html">LuCI.form.GridSection
</a>
910 <ul class=
"members itemMembers">
912 <span class=
"subtitle">Members
</span>
914 <li data-name=
"LuCI.form.GridSection#addbtntitle"><a href=
"LuCI.form.GridSection.html#addbtntitle">addbtntitle
</a></li>
916 <li data-name=
"LuCI.form.GridSection#addremove"><a href=
"LuCI.form.GridSection.html#addremove">addremove
</a></li>
918 <li data-name=
"LuCI.form.GridSection#anonymous"><a href=
"LuCI.form.GridSection.html#anonymous">anonymous
</a></li>
920 <li data-name=
"LuCI.form.GridSection#extedit"><a href=
"LuCI.form.GridSection.html#extedit">extedit
</a></li>
922 <li data-name=
"LuCI.form.GridSection#max_cols"><a href=
"LuCI.form.GridSection.html#max_cols">max_cols
</a></li>
924 <li data-name=
"LuCI.form.GridSection#modaltitle"><a href=
"LuCI.form.GridSection.html#modaltitle">modaltitle
</a></li>
926 <li data-name=
"LuCI.form.GridSection#nodescriptions"><a href=
"LuCI.form.GridSection.html#nodescriptions">nodescriptions
</a></li>
928 <li data-name=
"LuCI.form.GridSection#parentoption"><a href=
"LuCI.form.GridSection.html#parentoption">parentoption
</a></li>
930 <li data-name=
"LuCI.form.GridSection#rowcolors"><a href=
"LuCI.form.GridSection.html#rowcolors">rowcolors
</a></li>
932 <li data-name=
"LuCI.form.GridSection#sectiontitle"><a href=
"LuCI.form.GridSection.html#sectiontitle">sectiontitle
</a></li>
934 <li data-name=
"LuCI.form.GridSection#sortable"><a href=
"LuCI.form.GridSection.html#sortable">sortable
</a></li>
936 <li data-name=
"LuCI.form.GridSection#tabbed"><a href=
"LuCI.form.GridSection.html#tabbed">tabbed
</a></li>
938 <li data-name=
"LuCI.form.GridSection#tooltip"><a href=
"LuCI.form.GridSection.html#tooltip">tooltip
</a></li>
940 <li data-name=
"LuCI.form.GridSection#tooltipicon"><a href=
"LuCI.form.GridSection.html#tooltipicon">tooltipicon
</a></li>
942 <li data-name=
"LuCI.form.GridSection#uciconfig"><a href=
"LuCI.form.GridSection.html#uciconfig">uciconfig
</a></li>
945 <ul class=
"typedefs itemMembers">
948 <ul class=
"typedefs itemMembers">
951 <ul class=
"methods itemMembers">
953 <span class=
"subtitle">Methods
</span>
955 <li data-name=
"LuCI.form.GridSection#addModalOptions"><a href=
"LuCI.form.GridSection.html#addModalOptions">addModalOptions
</a></li>
957 <li data-name=
"LuCI.form.GridSection#append"><a href=
"LuCI.form.GridSection.html#append">append
</a></li>
959 <li data-name=
"LuCI.form.GridSection#cfgvalue"><a href=
"LuCI.form.GridSection.html#cfgvalue">cfgvalue
</a></li>
961 <li data-name=
"LuCI.form.GridSection#filter"><a href=
"LuCI.form.GridSection.html#filter">filter
</a></li>
963 <li data-name=
"LuCI.form.GridSection#formvalue"><a href=
"LuCI.form.GridSection.html#formvalue">formvalue
</a></li>
965 <li data-name=
"LuCI.form.GridSection#getOption"><a href=
"LuCI.form.GridSection.html#getOption">getOption
</a></li>
967 <li data-name=
"LuCI.form.GridSection#getUIElement"><a href=
"LuCI.form.GridSection.html#getUIElement">getUIElement
</a></li>
969 <li data-name=
"LuCI.form.GridSection#load"><a href=
"LuCI.form.GridSection.html#load">load
</a></li>
971 <li data-name=
"LuCI.form.GridSection#option"><a href=
"LuCI.form.GridSection.html#option">option
</a></li>
973 <li data-name=
"LuCI.form.GridSection#parse"><a href=
"LuCI.form.GridSection.html#parse">parse
</a></li>
975 <li data-name=
"LuCI.form.GridSection#stripTags"><a href=
"LuCI.form.GridSection.html#stripTags">stripTags
</a></li>
977 <li data-name=
"LuCI.form.GridSection#tab"><a href=
"LuCI.form.GridSection.html#tab">tab
</a></li>
979 <li data-name=
"LuCI.form.GridSection#taboption"><a href=
"LuCI.form.GridSection.html#taboption">taboption
</a></li>
981 <li data-name=
"LuCI.form.GridSection#titleFn"><a href=
"LuCI.form.GridSection.html#titleFn">titleFn
</a></li>
984 <ul class=
"events itemMembers">
989 <li class=
"item" data-name=
"LuCI.form.HiddenValue">
991 <a href=
"LuCI.form.HiddenValue.html">LuCI.form.HiddenValue
</a>
994 <ul class=
"members itemMembers">
996 <span class=
"subtitle">Members
</span>
998 <li data-name=
"LuCI.form.HiddenValue#datatype"><a href=
"LuCI.form.HiddenValue.html#datatype">datatype
</a></li>
1000 <li data-name=
"LuCI.form.HiddenValue#default"><a href=
"LuCI.form.HiddenValue.html#default">default
</a></li>
1002 <li data-name=
"LuCI.form.HiddenValue#editable"><a href=
"LuCI.form.HiddenValue.html#editable">editable
</a></li>
1004 <li data-name=
"LuCI.form.HiddenValue#modalonly"><a href=
"LuCI.form.HiddenValue.html#modalonly">modalonly
</a></li>
1006 <li data-name=
"LuCI.form.HiddenValue#onchange"><a href=
"LuCI.form.HiddenValue.html#onchange">onchange
</a></li>
1008 <li data-name=
"LuCI.form.HiddenValue#optional"><a href=
"LuCI.form.HiddenValue.html#optional">optional
</a></li>
1010 <li data-name=
"LuCI.form.HiddenValue#password"><a href=
"LuCI.form.HiddenValue.html#password">password
</a></li>
1012 <li data-name=
"LuCI.form.HiddenValue#placeholder"><a href=
"LuCI.form.HiddenValue.html#placeholder">placeholder
</a></li>
1014 <li data-name=
"LuCI.form.HiddenValue#readonly"><a href=
"LuCI.form.HiddenValue.html#readonly">readonly
</a></li>
1016 <li data-name=
"LuCI.form.HiddenValue#retain"><a href=
"LuCI.form.HiddenValue.html#retain">retain
</a></li>
1018 <li data-name=
"LuCI.form.HiddenValue#rmempty"><a href=
"LuCI.form.HiddenValue.html#rmempty">rmempty
</a></li>
1020 <li data-name=
"LuCI.form.HiddenValue#uciconfig"><a href=
"LuCI.form.HiddenValue.html#uciconfig">uciconfig
</a></li>
1022 <li data-name=
"LuCI.form.HiddenValue#ucioption"><a href=
"LuCI.form.HiddenValue.html#ucioption">ucioption
</a></li>
1024 <li data-name=
"LuCI.form.HiddenValue#ucisection"><a href=
"LuCI.form.HiddenValue.html#ucisection">ucisection
</a></li>
1026 <li data-name=
"LuCI.form.HiddenValue#validate"><a href=
"LuCI.form.HiddenValue.html#validate">validate
</a></li>
1028 <li data-name=
"LuCI.form.HiddenValue#width"><a href=
"LuCI.form.HiddenValue.html#width">width
</a></li>
1031 <ul class=
"typedefs itemMembers">
1034 <ul class=
"typedefs itemMembers">
1037 <ul class=
"methods itemMembers">
1039 <span class=
"subtitle">Methods
</span>
1041 <li data-name=
"LuCI.form.HiddenValue#append"><a href=
"LuCI.form.HiddenValue.html#append">append
</a></li>
1043 <li data-name=
"LuCI.form.HiddenValue#cbid"><a href=
"LuCI.form.HiddenValue.html#cbid">cbid
</a></li>
1045 <li data-name=
"LuCI.form.HiddenValue#cfgvalue"><a href=
"LuCI.form.HiddenValue.html#cfgvalue">cfgvalue
</a></li>
1047 <li data-name=
"LuCI.form.HiddenValue#depends"><a href=
"LuCI.form.HiddenValue.html#depends">depends
</a></li>
1049 <li data-name=
"LuCI.form.HiddenValue#formvalue"><a href=
"LuCI.form.HiddenValue.html#formvalue">formvalue
</a></li>
1051 <li data-name=
"LuCI.form.HiddenValue#getUIElement"><a href=
"LuCI.form.HiddenValue.html#getUIElement">getUIElement
</a></li>
1053 <li data-name=
"LuCI.form.HiddenValue#getValidationError"><a href=
"LuCI.form.HiddenValue.html#getValidationError">getValidationError
</a></li>
1055 <li data-name=
"LuCI.form.HiddenValue#isActive"><a href=
"LuCI.form.HiddenValue.html#isActive">isActive
</a></li>
1057 <li data-name=
"LuCI.form.HiddenValue#isValid"><a href=
"LuCI.form.HiddenValue.html#isValid">isValid
</a></li>
1059 <li data-name=
"LuCI.form.HiddenValue#load"><a href=
"LuCI.form.HiddenValue.html#load">load
</a></li>
1061 <li data-name=
"LuCI.form.HiddenValue#parse"><a href=
"LuCI.form.HiddenValue.html#parse">parse
</a></li>
1063 <li data-name=
"LuCI.form.HiddenValue#remove"><a href=
"LuCI.form.HiddenValue.html#remove">remove
</a></li>
1065 <li data-name=
"LuCI.form.HiddenValue#stripTags"><a href=
"LuCI.form.HiddenValue.html#stripTags">stripTags
</a></li>
1067 <li data-name=
"LuCI.form.HiddenValue#textvalue"><a href=
"LuCI.form.HiddenValue.html#textvalue">textvalue
</a></li>
1069 <li data-name=
"LuCI.form.HiddenValue#titleFn"><a href=
"LuCI.form.HiddenValue.html#titleFn">titleFn
</a></li>
1071 <li data-name=
"LuCI.form.HiddenValue#value"><a href=
"LuCI.form.HiddenValue.html#value">value
</a></li>
1073 <li data-name=
"LuCI.form.HiddenValue#write"><a href=
"LuCI.form.HiddenValue.html#write">write
</a></li>
1076 <ul class=
"events itemMembers">
1081 <li class=
"item" data-name=
"LuCI.form.JSONMap">
1082 <span class=
"title">
1083 <a href=
"LuCI.form.JSONMap.html">LuCI.form.JSONMap
</a>
1086 <ul class=
"members itemMembers">
1088 <span class=
"subtitle">Members
</span>
1090 <li data-name=
"LuCI.form.JSONMap#readonly"><a href=
"LuCI.form.JSONMap.html#readonly">readonly
</a></li>
1093 <ul class=
"typedefs itemMembers">
1096 <ul class=
"typedefs itemMembers">
1099 <ul class=
"methods itemMembers">
1101 <span class=
"subtitle">Methods
</span>
1103 <li data-name=
"LuCI.form.JSONMap#append"><a href=
"LuCI.form.JSONMap.html#append">append
</a></li>
1105 <li data-name=
"LuCI.form.JSONMap#chain"><a href=
"LuCI.form.JSONMap.html#chain">chain
</a></li>
1107 <li data-name=
"LuCI.form.JSONMap#findElement"><a href=
"LuCI.form.JSONMap.html#findElement">findElement
</a></li>
1109 <li data-name=
"LuCI.form.JSONMap#findElements"><a href=
"LuCI.form.JSONMap.html#findElements">findElements
</a></li>
1111 <li data-name=
"LuCI.form.JSONMap#load"><a href=
"LuCI.form.JSONMap.html#load">load
</a></li>
1113 <li data-name=
"LuCI.form.JSONMap#lookupOption"><a href=
"LuCI.form.JSONMap.html#lookupOption">lookupOption
</a></li>
1115 <li data-name=
"LuCI.form.JSONMap#parse"><a href=
"LuCI.form.JSONMap.html#parse">parse
</a></li>
1117 <li data-name=
"LuCI.form.JSONMap#render"><a href=
"LuCI.form.JSONMap.html#render">render
</a></li>
1119 <li data-name=
"LuCI.form.JSONMap#reset"><a href=
"LuCI.form.JSONMap.html#reset">reset
</a></li>
1121 <li data-name=
"LuCI.form.JSONMap#save"><a href=
"LuCI.form.JSONMap.html#save">save
</a></li>
1123 <li data-name=
"LuCI.form.JSONMap#section"><a href=
"LuCI.form.JSONMap.html#section">section
</a></li>
1125 <li data-name=
"LuCI.form.JSONMap#stripTags"><a href=
"LuCI.form.JSONMap.html#stripTags">stripTags
</a></li>
1127 <li data-name=
"LuCI.form.JSONMap#titleFn"><a href=
"LuCI.form.JSONMap.html#titleFn">titleFn
</a></li>
1130 <ul class=
"events itemMembers">
1135 <li class=
"item" data-name=
"LuCI.form.ListValue">
1136 <span class=
"title">
1137 <a href=
"LuCI.form.ListValue.html">LuCI.form.ListValue
</a>
1140 <ul class=
"members itemMembers">
1142 <span class=
"subtitle">Members
</span>
1144 <li data-name=
"LuCI.form.ListValue##orientation"><a href=
"LuCI.form.ListValue.html#orientation">orientation
</a></li>
1146 <li data-name=
"LuCI.form.ListValue##size"><a href=
"LuCI.form.ListValue.html#size">size
</a></li>
1148 <li data-name=
"LuCI.form.ListValue##widget"><a href=
"LuCI.form.ListValue.html#widget">widget
</a></li>
1150 <li data-name=
"LuCI.form.ListValue#datatype"><a href=
"LuCI.form.ListValue.html#datatype">datatype
</a></li>
1152 <li data-name=
"LuCI.form.ListValue#default"><a href=
"LuCI.form.ListValue.html#default">default
</a></li>
1154 <li data-name=
"LuCI.form.ListValue#editable"><a href=
"LuCI.form.ListValue.html#editable">editable
</a></li>
1156 <li data-name=
"LuCI.form.ListValue#modalonly"><a href=
"LuCI.form.ListValue.html#modalonly">modalonly
</a></li>
1158 <li data-name=
"LuCI.form.ListValue#onchange"><a href=
"LuCI.form.ListValue.html#onchange">onchange
</a></li>
1160 <li data-name=
"LuCI.form.ListValue#optional"><a href=
"LuCI.form.ListValue.html#optional">optional
</a></li>
1162 <li data-name=
"LuCI.form.ListValue#password"><a href=
"LuCI.form.ListValue.html#password">password
</a></li>
1164 <li data-name=
"LuCI.form.ListValue#placeholder"><a href=
"LuCI.form.ListValue.html#placeholder">placeholder
</a></li>
1166 <li data-name=
"LuCI.form.ListValue#readonly"><a href=
"LuCI.form.ListValue.html#readonly">readonly
</a></li>
1168 <li data-name=
"LuCI.form.ListValue#retain"><a href=
"LuCI.form.ListValue.html#retain">retain
</a></li>
1170 <li data-name=
"LuCI.form.ListValue#rmempty"><a href=
"LuCI.form.ListValue.html#rmempty">rmempty
</a></li>
1172 <li data-name=
"LuCI.form.ListValue#uciconfig"><a href=
"LuCI.form.ListValue.html#uciconfig">uciconfig
</a></li>
1174 <li data-name=
"LuCI.form.ListValue#ucioption"><a href=
"LuCI.form.ListValue.html#ucioption">ucioption
</a></li>
1176 <li data-name=
"LuCI.form.ListValue#ucisection"><a href=
"LuCI.form.ListValue.html#ucisection">ucisection
</a></li>
1178 <li data-name=
"LuCI.form.ListValue#validate"><a href=
"LuCI.form.ListValue.html#validate">validate
</a></li>
1180 <li data-name=
"LuCI.form.ListValue#width"><a href=
"LuCI.form.ListValue.html#width">width
</a></li>
1183 <ul class=
"typedefs itemMembers">
1186 <ul class=
"typedefs itemMembers">
1189 <ul class=
"methods itemMembers">
1191 <span class=
"subtitle">Methods
</span>
1193 <li data-name=
"LuCI.form.ListValue#append"><a href=
"LuCI.form.ListValue.html#append">append
</a></li>
1195 <li data-name=
"LuCI.form.ListValue#cbid"><a href=
"LuCI.form.ListValue.html#cbid">cbid
</a></li>
1197 <li data-name=
"LuCI.form.ListValue#cfgvalue"><a href=
"LuCI.form.ListValue.html#cfgvalue">cfgvalue
</a></li>
1199 <li data-name=
"LuCI.form.ListValue#depends"><a href=
"LuCI.form.ListValue.html#depends">depends
</a></li>
1201 <li data-name=
"LuCI.form.ListValue#formvalue"><a href=
"LuCI.form.ListValue.html#formvalue">formvalue
</a></li>
1203 <li data-name=
"LuCI.form.ListValue#getUIElement"><a href=
"LuCI.form.ListValue.html#getUIElement">getUIElement
</a></li>
1205 <li data-name=
"LuCI.form.ListValue#getValidationError"><a href=
"LuCI.form.ListValue.html#getValidationError">getValidationError
</a></li>
1207 <li data-name=
"LuCI.form.ListValue#isActive"><a href=
"LuCI.form.ListValue.html#isActive">isActive
</a></li>
1209 <li data-name=
"LuCI.form.ListValue#isValid"><a href=
"LuCI.form.ListValue.html#isValid">isValid
</a></li>
1211 <li data-name=
"LuCI.form.ListValue#load"><a href=
"LuCI.form.ListValue.html#load">load
</a></li>
1213 <li data-name=
"LuCI.form.ListValue#parse"><a href=
"LuCI.form.ListValue.html#parse">parse
</a></li>
1215 <li data-name=
"LuCI.form.ListValue#remove"><a href=
"LuCI.form.ListValue.html#remove">remove
</a></li>
1217 <li data-name=
"LuCI.form.ListValue#stripTags"><a href=
"LuCI.form.ListValue.html#stripTags">stripTags
</a></li>
1219 <li data-name=
"LuCI.form.ListValue#textvalue"><a href=
"LuCI.form.ListValue.html#textvalue">textvalue
</a></li>
1221 <li data-name=
"LuCI.form.ListValue#titleFn"><a href=
"LuCI.form.ListValue.html#titleFn">titleFn
</a></li>
1223 <li data-name=
"LuCI.form.ListValue#value"><a href=
"LuCI.form.ListValue.html#value">value
</a></li>
1225 <li data-name=
"LuCI.form.ListValue#write"><a href=
"LuCI.form.ListValue.html#write">write
</a></li>
1228 <ul class=
"events itemMembers">
1233 <li class=
"item" data-name=
"LuCI.form.Map">
1234 <span class=
"title">
1235 <a href=
"LuCI.form.Map.html">LuCI.form.Map
</a>
1238 <ul class=
"members itemMembers">
1240 <span class=
"subtitle">Members
</span>
1242 <li data-name=
"LuCI.form.Map##readonly"><a href=
"LuCI.form.Map.html#readonly">readonly
</a></li>
1245 <ul class=
"typedefs itemMembers">
1248 <ul class=
"typedefs itemMembers">
1251 <ul class=
"methods itemMembers">
1253 <span class=
"subtitle">Methods
</span>
1255 <li data-name=
"LuCI.form.Map#append"><a href=
"LuCI.form.Map.html#append">append
</a></li>
1257 <li data-name=
"LuCI.form.Map#chain"><a href=
"LuCI.form.Map.html#chain">chain
</a></li>
1259 <li data-name=
"LuCI.form.Map#findElement"><a href=
"LuCI.form.Map.html#findElement">findElement
</a></li>
1261 <li data-name=
"LuCI.form.Map#findElements"><a href=
"LuCI.form.Map.html#findElements">findElements
</a></li>
1263 <li data-name=
"LuCI.form.Map#load"><a href=
"LuCI.form.Map.html#load">load
</a></li>
1265 <li data-name=
"LuCI.form.Map#lookupOption"><a href=
"LuCI.form.Map.html#lookupOption">lookupOption
</a></li>
1267 <li data-name=
"LuCI.form.Map#parse"><a href=
"LuCI.form.Map.html#parse">parse
</a></li>
1269 <li data-name=
"LuCI.form.Map#render"><a href=
"LuCI.form.Map.html#render">render
</a></li>
1271 <li data-name=
"LuCI.form.Map#reset"><a href=
"LuCI.form.Map.html#reset">reset
</a></li>
1273 <li data-name=
"LuCI.form.Map#save"><a href=
"LuCI.form.Map.html#save">save
</a></li>
1275 <li data-name=
"LuCI.form.Map#section"><a href=
"LuCI.form.Map.html#section">section
</a></li>
1277 <li data-name=
"LuCI.form.Map#stripTags"><a href=
"LuCI.form.Map.html#stripTags">stripTags
</a></li>
1279 <li data-name=
"LuCI.form.Map#titleFn"><a href=
"LuCI.form.Map.html#titleFn">titleFn
</a></li>
1282 <ul class=
"events itemMembers">
1287 <li class=
"item" data-name=
"LuCI.form.MultiValue">
1288 <span class=
"title">
1289 <a href=
"LuCI.form.MultiValue.html">LuCI.form.MultiValue
</a>
1292 <ul class=
"members itemMembers">
1294 <span class=
"subtitle">Members
</span>
1296 <li data-name=
"LuCI.form.MultiValue##display_size"><a href=
"LuCI.form.MultiValue.html#display_size">display_size
</a></li>
1298 <li data-name=
"LuCI.form.MultiValue##dropdown_size"><a href=
"LuCI.form.MultiValue.html#dropdown_size">dropdown_size
</a></li>
1300 <li data-name=
"LuCI.form.MultiValue#datatype"><a href=
"LuCI.form.MultiValue.html#datatype">datatype
</a></li>
1302 <li data-name=
"LuCI.form.MultiValue#default"><a href=
"LuCI.form.MultiValue.html#default">default
</a></li>
1304 <li data-name=
"LuCI.form.MultiValue#editable"><a href=
"LuCI.form.MultiValue.html#editable">editable
</a></li>
1306 <li data-name=
"LuCI.form.MultiValue#modalonly"><a href=
"LuCI.form.MultiValue.html#modalonly">modalonly
</a></li>
1308 <li data-name=
"LuCI.form.MultiValue#onchange"><a href=
"LuCI.form.MultiValue.html#onchange">onchange
</a></li>
1310 <li data-name=
"LuCI.form.MultiValue#optional"><a href=
"LuCI.form.MultiValue.html#optional">optional
</a></li>
1312 <li data-name=
"LuCI.form.MultiValue#password"><a href=
"LuCI.form.MultiValue.html#password">password
</a></li>
1314 <li data-name=
"LuCI.form.MultiValue#placeholder"><a href=
"LuCI.form.MultiValue.html#placeholder">placeholder
</a></li>
1316 <li data-name=
"LuCI.form.MultiValue#readonly"><a href=
"LuCI.form.MultiValue.html#readonly">readonly
</a></li>
1318 <li data-name=
"LuCI.form.MultiValue#retain"><a href=
"LuCI.form.MultiValue.html#retain">retain
</a></li>
1320 <li data-name=
"LuCI.form.MultiValue#rmempty"><a href=
"LuCI.form.MultiValue.html#rmempty">rmempty
</a></li>
1322 <li data-name=
"LuCI.form.MultiValue#uciconfig"><a href=
"LuCI.form.MultiValue.html#uciconfig">uciconfig
</a></li>
1324 <li data-name=
"LuCI.form.MultiValue#ucioption"><a href=
"LuCI.form.MultiValue.html#ucioption">ucioption
</a></li>
1326 <li data-name=
"LuCI.form.MultiValue#ucisection"><a href=
"LuCI.form.MultiValue.html#ucisection">ucisection
</a></li>
1328 <li data-name=
"LuCI.form.MultiValue#validate"><a href=
"LuCI.form.MultiValue.html#validate">validate
</a></li>
1330 <li data-name=
"LuCI.form.MultiValue#width"><a href=
"LuCI.form.MultiValue.html#width">width
</a></li>
1333 <ul class=
"typedefs itemMembers">
1336 <ul class=
"typedefs itemMembers">
1339 <ul class=
"methods itemMembers">
1341 <span class=
"subtitle">Methods
</span>
1343 <li data-name=
"LuCI.form.MultiValue#append"><a href=
"LuCI.form.MultiValue.html#append">append
</a></li>
1345 <li data-name=
"LuCI.form.MultiValue#cbid"><a href=
"LuCI.form.MultiValue.html#cbid">cbid
</a></li>
1347 <li data-name=
"LuCI.form.MultiValue#cfgvalue"><a href=
"LuCI.form.MultiValue.html#cfgvalue">cfgvalue
</a></li>
1349 <li data-name=
"LuCI.form.MultiValue#depends"><a href=
"LuCI.form.MultiValue.html#depends">depends
</a></li>
1351 <li data-name=
"LuCI.form.MultiValue#formvalue"><a href=
"LuCI.form.MultiValue.html#formvalue">formvalue
</a></li>
1353 <li data-name=
"LuCI.form.MultiValue#getUIElement"><a href=
"LuCI.form.MultiValue.html#getUIElement">getUIElement
</a></li>
1355 <li data-name=
"LuCI.form.MultiValue#getValidationError"><a href=
"LuCI.form.MultiValue.html#getValidationError">getValidationError
</a></li>
1357 <li data-name=
"LuCI.form.MultiValue#isActive"><a href=
"LuCI.form.MultiValue.html#isActive">isActive
</a></li>
1359 <li data-name=
"LuCI.form.MultiValue#isValid"><a href=
"LuCI.form.MultiValue.html#isValid">isValid
</a></li>
1361 <li data-name=
"LuCI.form.MultiValue#load"><a href=
"LuCI.form.MultiValue.html#load">load
</a></li>
1363 <li data-name=
"LuCI.form.MultiValue#parse"><a href=
"LuCI.form.MultiValue.html#parse">parse
</a></li>
1365 <li data-name=
"LuCI.form.MultiValue#remove"><a href=
"LuCI.form.MultiValue.html#remove">remove
</a></li>
1367 <li data-name=
"LuCI.form.MultiValue#stripTags"><a href=
"LuCI.form.MultiValue.html#stripTags">stripTags
</a></li>
1369 <li data-name=
"LuCI.form.MultiValue#textvalue"><a href=
"LuCI.form.MultiValue.html#textvalue">textvalue
</a></li>
1371 <li data-name=
"LuCI.form.MultiValue#titleFn"><a href=
"LuCI.form.MultiValue.html#titleFn">titleFn
</a></li>
1373 <li data-name=
"LuCI.form.MultiValue#value"><a href=
"LuCI.form.MultiValue.html#value">value
</a></li>
1375 <li data-name=
"LuCI.form.MultiValue#write"><a href=
"LuCI.form.MultiValue.html#write">write
</a></li>
1378 <ul class=
"events itemMembers">
1383 <li class=
"item" data-name=
"LuCI.form.NamedSection">
1384 <span class=
"title">
1385 <a href=
"LuCI.form.NamedSection.html">LuCI.form.NamedSection
</a>
1388 <ul class=
"members itemMembers">
1390 <span class=
"subtitle">Members
</span>
1392 <li data-name=
"LuCI.form.NamedSection##addremove"><a href=
"LuCI.form.NamedSection.html#addremove">addremove
</a></li>
1394 <li data-name=
"LuCI.form.NamedSection##uciconfig"><a href=
"LuCI.form.NamedSection.html#uciconfig">uciconfig
</a></li>
1396 <li data-name=
"LuCI.form.NamedSection#parentoption"><a href=
"LuCI.form.NamedSection.html#parentoption">parentoption
</a></li>
1399 <ul class=
"typedefs itemMembers">
1402 <ul class=
"typedefs itemMembers">
1405 <ul class=
"methods itemMembers">
1407 <span class=
"subtitle">Methods
</span>
1409 <li data-name=
"LuCI.form.NamedSection#append"><a href=
"LuCI.form.NamedSection.html#append">append
</a></li>
1411 <li data-name=
"LuCI.form.NamedSection#cfgsections"><a href=
"LuCI.form.NamedSection.html#cfgsections">cfgsections
</a></li>
1413 <li data-name=
"LuCI.form.NamedSection#cfgvalue"><a href=
"LuCI.form.NamedSection.html#cfgvalue">cfgvalue
</a></li>
1415 <li data-name=
"LuCI.form.NamedSection#filter"><a href=
"LuCI.form.NamedSection.html#filter">filter
</a></li>
1417 <li data-name=
"LuCI.form.NamedSection#formvalue"><a href=
"LuCI.form.NamedSection.html#formvalue">formvalue
</a></li>
1419 <li data-name=
"LuCI.form.NamedSection#getOption"><a href=
"LuCI.form.NamedSection.html#getOption">getOption
</a></li>
1421 <li data-name=
"LuCI.form.NamedSection#getUIElement"><a href=
"LuCI.form.NamedSection.html#getUIElement">getUIElement
</a></li>
1423 <li data-name=
"LuCI.form.NamedSection#load"><a href=
"LuCI.form.NamedSection.html#load">load
</a></li>
1425 <li data-name=
"LuCI.form.NamedSection#option"><a href=
"LuCI.form.NamedSection.html#option">option
</a></li>
1427 <li data-name=
"LuCI.form.NamedSection#parse"><a href=
"LuCI.form.NamedSection.html#parse">parse
</a></li>
1429 <li data-name=
"LuCI.form.NamedSection#render"><a href=
"LuCI.form.NamedSection.html#render">render
</a></li>
1431 <li data-name=
"LuCI.form.NamedSection#stripTags"><a href=
"LuCI.form.NamedSection.html#stripTags">stripTags
</a></li>
1433 <li data-name=
"LuCI.form.NamedSection#tab"><a href=
"LuCI.form.NamedSection.html#tab">tab
</a></li>
1435 <li data-name=
"LuCI.form.NamedSection#taboption"><a href=
"LuCI.form.NamedSection.html#taboption">taboption
</a></li>
1437 <li data-name=
"LuCI.form.NamedSection#titleFn"><a href=
"LuCI.form.NamedSection.html#titleFn">titleFn
</a></li>
1440 <ul class=
"events itemMembers">
1445 <li class=
"item" data-name=
"LuCI.form.SectionValue">
1446 <span class=
"title">
1447 <a href=
"LuCI.form.SectionValue.html">LuCI.form.SectionValue
</a>
1450 <ul class=
"members itemMembers">
1452 <span class=
"subtitle">Members
</span>
1454 <li data-name=
"LuCI.form.SectionValue##subsection"><a href=
"LuCI.form.SectionValue.html#subsection">subsection
</a></li>
1456 <li data-name=
"LuCI.form.SectionValue#datatype"><a href=
"LuCI.form.SectionValue.html#datatype">datatype
</a></li>
1458 <li data-name=
"LuCI.form.SectionValue#default"><a href=
"LuCI.form.SectionValue.html#default">default
</a></li>
1460 <li data-name=
"LuCI.form.SectionValue#editable"><a href=
"LuCI.form.SectionValue.html#editable">editable
</a></li>
1462 <li data-name=
"LuCI.form.SectionValue#modalonly"><a href=
"LuCI.form.SectionValue.html#modalonly">modalonly
</a></li>
1464 <li data-name=
"LuCI.form.SectionValue#onchange"><a href=
"LuCI.form.SectionValue.html#onchange">onchange
</a></li>
1466 <li data-name=
"LuCI.form.SectionValue#optional"><a href=
"LuCI.form.SectionValue.html#optional">optional
</a></li>
1468 <li data-name=
"LuCI.form.SectionValue#password"><a href=
"LuCI.form.SectionValue.html#password">password
</a></li>
1470 <li data-name=
"LuCI.form.SectionValue#placeholder"><a href=
"LuCI.form.SectionValue.html#placeholder">placeholder
</a></li>
1472 <li data-name=
"LuCI.form.SectionValue#readonly"><a href=
"LuCI.form.SectionValue.html#readonly">readonly
</a></li>
1474 <li data-name=
"LuCI.form.SectionValue#retain"><a href=
"LuCI.form.SectionValue.html#retain">retain
</a></li>
1476 <li data-name=
"LuCI.form.SectionValue#rmempty"><a href=
"LuCI.form.SectionValue.html#rmempty">rmempty
</a></li>
1478 <li data-name=
"LuCI.form.SectionValue#uciconfig"><a href=
"LuCI.form.SectionValue.html#uciconfig">uciconfig
</a></li>
1480 <li data-name=
"LuCI.form.SectionValue#ucioption"><a href=
"LuCI.form.SectionValue.html#ucioption">ucioption
</a></li>
1482 <li data-name=
"LuCI.form.SectionValue#ucisection"><a href=
"LuCI.form.SectionValue.html#ucisection">ucisection
</a></li>
1484 <li data-name=
"LuCI.form.SectionValue#validate"><a href=
"LuCI.form.SectionValue.html#validate">validate
</a></li>
1486 <li data-name=
"LuCI.form.SectionValue#width"><a href=
"LuCI.form.SectionValue.html#width">width
</a></li>
1489 <ul class=
"typedefs itemMembers">
1492 <ul class=
"typedefs itemMembers">
1495 <ul class=
"methods itemMembers">
1497 <span class=
"subtitle">Methods
</span>
1499 <li data-name=
"LuCI.form.SectionValue#append"><a href=
"LuCI.form.SectionValue.html#append">append
</a></li>
1501 <li data-name=
"LuCI.form.SectionValue#cbid"><a href=
"LuCI.form.SectionValue.html#cbid">cbid
</a></li>
1503 <li data-name=
"LuCI.form.SectionValue#cfgvalue"><a href=
"LuCI.form.SectionValue.html#cfgvalue">cfgvalue
</a></li>
1505 <li data-name=
"LuCI.form.SectionValue#depends"><a href=
"LuCI.form.SectionValue.html#depends">depends
</a></li>
1507 <li data-name=
"LuCI.form.SectionValue#formvalue"><a href=
"LuCI.form.SectionValue.html#formvalue">formvalue
</a></li>
1509 <li data-name=
"LuCI.form.SectionValue#getUIElement"><a href=
"LuCI.form.SectionValue.html#getUIElement">getUIElement
</a></li>
1511 <li data-name=
"LuCI.form.SectionValue#getValidationError"><a href=
"LuCI.form.SectionValue.html#getValidationError">getValidationError
</a></li>
1513 <li data-name=
"LuCI.form.SectionValue#isActive"><a href=
"LuCI.form.SectionValue.html#isActive">isActive
</a></li>
1515 <li data-name=
"LuCI.form.SectionValue#isValid"><a href=
"LuCI.form.SectionValue.html#isValid">isValid
</a></li>
1517 <li data-name=
"LuCI.form.SectionValue#load"><a href=
"LuCI.form.SectionValue.html#load">load
</a></li>
1519 <li data-name=
"LuCI.form.SectionValue#parse"><a href=
"LuCI.form.SectionValue.html#parse">parse
</a></li>
1521 <li data-name=
"LuCI.form.SectionValue#remove"><a href=
"LuCI.form.SectionValue.html#remove">remove
</a></li>
1523 <li data-name=
"LuCI.form.SectionValue#stripTags"><a href=
"LuCI.form.SectionValue.html#stripTags">stripTags
</a></li>
1525 <li data-name=
"LuCI.form.SectionValue#textvalue"><a href=
"LuCI.form.SectionValue.html#textvalue">textvalue
</a></li>
1527 <li data-name=
"LuCI.form.SectionValue#titleFn"><a href=
"LuCI.form.SectionValue.html#titleFn">titleFn
</a></li>
1529 <li data-name=
"LuCI.form.SectionValue#value"><a href=
"LuCI.form.SectionValue.html#value">value
</a></li>
1531 <li data-name=
"LuCI.form.SectionValue#write"><a href=
"LuCI.form.SectionValue.html#write">write
</a></li>
1534 <ul class=
"events itemMembers">
1539 <li class=
"item" data-name=
"LuCI.form.TableSection">
1540 <span class=
"title">
1541 <a href=
"LuCI.form.TableSection.html">LuCI.form.TableSection
</a>
1544 <ul class=
"members itemMembers">
1546 <span class=
"subtitle">Members
</span>
1548 <li data-name=
"LuCI.form.TableSection##addbtntitle"><a href=
"LuCI.form.TableSection.html#addbtntitle">addbtntitle
</a></li>
1550 <li data-name=
"LuCI.form.TableSection##addremove"><a href=
"LuCI.form.TableSection.html#addremove">addremove
</a></li>
1552 <li data-name=
"LuCI.form.TableSection##anonymous"><a href=
"LuCI.form.TableSection.html#anonymous">anonymous
</a></li>
1554 <li data-name=
"LuCI.form.TableSection##extedit"><a href=
"LuCI.form.TableSection.html#extedit">extedit
</a></li>
1556 <li data-name=
"LuCI.form.TableSection##max_cols"><a href=
"LuCI.form.TableSection.html#max_cols">max_cols
</a></li>
1558 <li data-name=
"LuCI.form.TableSection##modaltitle"><a href=
"LuCI.form.TableSection.html#modaltitle">modaltitle
</a></li>
1560 <li data-name=
"LuCI.form.TableSection##nodescriptions"><a href=
"LuCI.form.TableSection.html#nodescriptions">nodescriptions
</a></li>
1562 <li data-name=
"LuCI.form.TableSection##rowcolors"><a href=
"LuCI.form.TableSection.html#rowcolors">rowcolors
</a></li>
1564 <li data-name=
"LuCI.form.TableSection##sectiontitle"><a href=
"LuCI.form.TableSection.html#sectiontitle">sectiontitle
</a></li>
1566 <li data-name=
"LuCI.form.TableSection##sortable"><a href=
"LuCI.form.TableSection.html#sortable">sortable
</a></li>
1568 <li data-name=
"LuCI.form.TableSection##uciconfig"><a href=
"LuCI.form.TableSection.html#uciconfig">uciconfig
</a></li>
1570 <li data-name=
"LuCI.form.TableSection#addbtntitle"><a href=
"LuCI.form.TableSection.html#addbtntitle">addbtntitle
</a></li>
1572 <li data-name=
"LuCI.form.TableSection#addremove"><a href=
"LuCI.form.TableSection.html#addremove">addremove
</a></li>
1574 <li data-name=
"LuCI.form.TableSection#anonymous"><a href=
"LuCI.form.TableSection.html#anonymous">anonymous
</a></li>
1576 <li data-name=
"LuCI.form.TableSection#parentoption"><a href=
"LuCI.form.TableSection.html#parentoption">parentoption
</a></li>
1578 <li data-name=
"LuCI.form.TableSection#tabbed"><a href=
"LuCI.form.TableSection.html#tabbed">tabbed
</a></li>
1580 <li data-name=
"LuCI.form.TableSection#tooltip"><a href=
"LuCI.form.TableSection.html#tooltip">tooltip
</a></li>
1582 <li data-name=
"LuCI.form.TableSection#tooltipicon"><a href=
"LuCI.form.TableSection.html#tooltipicon">tooltipicon
</a></li>
1584 <li data-name=
"LuCI.form.TableSection#uciconfig"><a href=
"LuCI.form.TableSection.html#uciconfig">uciconfig
</a></li>
1587 <ul class=
"typedefs itemMembers">
1590 <ul class=
"typedefs itemMembers">
1593 <ul class=
"methods itemMembers">
1595 <span class=
"subtitle">Methods
</span>
1597 <li data-name=
"LuCI.form.TableSection#addModalOptions"><a href=
"LuCI.form.TableSection.html#addModalOptions">addModalOptions
</a></li>
1599 <li data-name=
"LuCI.form.TableSection#append"><a href=
"LuCI.form.TableSection.html#append">append
</a></li>
1601 <li data-name=
"LuCI.form.TableSection#cfgvalue"><a href=
"LuCI.form.TableSection.html#cfgvalue">cfgvalue
</a></li>
1603 <li data-name=
"LuCI.form.TableSection#filter"><a href=
"LuCI.form.TableSection.html#filter">filter
</a></li>
1605 <li data-name=
"LuCI.form.TableSection#formvalue"><a href=
"LuCI.form.TableSection.html#formvalue">formvalue
</a></li>
1607 <li data-name=
"LuCI.form.TableSection#getOption"><a href=
"LuCI.form.TableSection.html#getOption">getOption
</a></li>
1609 <li data-name=
"LuCI.form.TableSection#getUIElement"><a href=
"LuCI.form.TableSection.html#getUIElement">getUIElement
</a></li>
1611 <li data-name=
"LuCI.form.TableSection#load"><a href=
"LuCI.form.TableSection.html#load">load
</a></li>
1613 <li data-name=
"LuCI.form.TableSection#option"><a href=
"LuCI.form.TableSection.html#option">option
</a></li>
1615 <li data-name=
"LuCI.form.TableSection#parse"><a href=
"LuCI.form.TableSection.html#parse">parse
</a></li>
1617 <li data-name=
"LuCI.form.TableSection#stripTags"><a href=
"LuCI.form.TableSection.html#stripTags">stripTags
</a></li>
1619 <li data-name=
"LuCI.form.TableSection#tab"><a href=
"LuCI.form.TableSection.html#tab">tab
</a></li>
1621 <li data-name=
"LuCI.form.TableSection#taboption"><a href=
"LuCI.form.TableSection.html#taboption">taboption
</a></li>
1623 <li data-name=
"LuCI.form.TableSection#titleFn"><a href=
"LuCI.form.TableSection.html#titleFn">titleFn
</a></li>
1626 <ul class=
"events itemMembers">
1631 <li class=
"item" data-name=
"LuCI.form.TextValue">
1632 <span class=
"title">
1633 <a href=
"LuCI.form.TextValue.html">LuCI.form.TextValue
</a>
1636 <ul class=
"members itemMembers">
1638 <span class=
"subtitle">Members
</span>
1640 <li data-name=
"LuCI.form.TextValue##cols"><a href=
"LuCI.form.TextValue.html#cols">cols
</a></li>
1642 <li data-name=
"LuCI.form.TextValue##monospace"><a href=
"LuCI.form.TextValue.html#monospace">monospace
</a></li>
1644 <li data-name=
"LuCI.form.TextValue##rows"><a href=
"LuCI.form.TextValue.html#rows">rows
</a></li>
1646 <li data-name=
"LuCI.form.TextValue##wrap"><a href=
"LuCI.form.TextValue.html#wrap">wrap
</a></li>
1648 <li data-name=
"LuCI.form.TextValue#datatype"><a href=
"LuCI.form.TextValue.html#datatype">datatype
</a></li>
1650 <li data-name=
"LuCI.form.TextValue#default"><a href=
"LuCI.form.TextValue.html#default">default
</a></li>
1652 <li data-name=
"LuCI.form.TextValue#editable"><a href=
"LuCI.form.TextValue.html#editable">editable
</a></li>
1654 <li data-name=
"LuCI.form.TextValue#modalonly"><a href=
"LuCI.form.TextValue.html#modalonly">modalonly
</a></li>
1656 <li data-name=
"LuCI.form.TextValue#onchange"><a href=
"LuCI.form.TextValue.html#onchange">onchange
</a></li>
1658 <li data-name=
"LuCI.form.TextValue#optional"><a href=
"LuCI.form.TextValue.html#optional">optional
</a></li>
1660 <li data-name=
"LuCI.form.TextValue#password"><a href=
"LuCI.form.TextValue.html#password">password
</a></li>
1662 <li data-name=
"LuCI.form.TextValue#placeholder"><a href=
"LuCI.form.TextValue.html#placeholder">placeholder
</a></li>
1664 <li data-name=
"LuCI.form.TextValue#readonly"><a href=
"LuCI.form.TextValue.html#readonly">readonly
</a></li>
1666 <li data-name=
"LuCI.form.TextValue#retain"><a href=
"LuCI.form.TextValue.html#retain">retain
</a></li>
1668 <li data-name=
"LuCI.form.TextValue#rmempty"><a href=
"LuCI.form.TextValue.html#rmempty">rmempty
</a></li>
1670 <li data-name=
"LuCI.form.TextValue#uciconfig"><a href=
"LuCI.form.TextValue.html#uciconfig">uciconfig
</a></li>
1672 <li data-name=
"LuCI.form.TextValue#ucioption"><a href=
"LuCI.form.TextValue.html#ucioption">ucioption
</a></li>
1674 <li data-name=
"LuCI.form.TextValue#ucisection"><a href=
"LuCI.form.TextValue.html#ucisection">ucisection
</a></li>
1676 <li data-name=
"LuCI.form.TextValue#validate"><a href=
"LuCI.form.TextValue.html#validate">validate
</a></li>
1678 <li data-name=
"LuCI.form.TextValue#width"><a href=
"LuCI.form.TextValue.html#width">width
</a></li>
1681 <ul class=
"typedefs itemMembers">
1684 <ul class=
"typedefs itemMembers">
1687 <ul class=
"methods itemMembers">
1689 <span class=
"subtitle">Methods
</span>
1691 <li data-name=
"LuCI.form.TextValue#append"><a href=
"LuCI.form.TextValue.html#append">append
</a></li>
1693 <li data-name=
"LuCI.form.TextValue#cbid"><a href=
"LuCI.form.TextValue.html#cbid">cbid
</a></li>
1695 <li data-name=
"LuCI.form.TextValue#cfgvalue"><a href=
"LuCI.form.TextValue.html#cfgvalue">cfgvalue
</a></li>
1697 <li data-name=
"LuCI.form.TextValue#depends"><a href=
"LuCI.form.TextValue.html#depends">depends
</a></li>
1699 <li data-name=
"LuCI.form.TextValue#formvalue"><a href=
"LuCI.form.TextValue.html#formvalue">formvalue
</a></li>
1701 <li data-name=
"LuCI.form.TextValue#getUIElement"><a href=
"LuCI.form.TextValue.html#getUIElement">getUIElement
</a></li>
1703 <li data-name=
"LuCI.form.TextValue#getValidationError"><a href=
"LuCI.form.TextValue.html#getValidationError">getValidationError
</a></li>
1705 <li data-name=
"LuCI.form.TextValue#isActive"><a href=
"LuCI.form.TextValue.html#isActive">isActive
</a></li>
1707 <li data-name=
"LuCI.form.TextValue#isValid"><a href=
"LuCI.form.TextValue.html#isValid">isValid
</a></li>
1709 <li data-name=
"LuCI.form.TextValue#load"><a href=
"LuCI.form.TextValue.html#load">load
</a></li>
1711 <li data-name=
"LuCI.form.TextValue#parse"><a href=
"LuCI.form.TextValue.html#parse">parse
</a></li>
1713 <li data-name=
"LuCI.form.TextValue#remove"><a href=
"LuCI.form.TextValue.html#remove">remove
</a></li>
1715 <li data-name=
"LuCI.form.TextValue#stripTags"><a href=
"LuCI.form.TextValue.html#stripTags">stripTags
</a></li>
1717 <li data-name=
"LuCI.form.TextValue#textvalue"><a href=
"LuCI.form.TextValue.html#textvalue">textvalue
</a></li>
1719 <li data-name=
"LuCI.form.TextValue#titleFn"><a href=
"LuCI.form.TextValue.html#titleFn">titleFn
</a></li>
1721 <li data-name=
"LuCI.form.TextValue#write"><a href=
"LuCI.form.TextValue.html#write">write
</a></li>
1724 <ul class=
"events itemMembers">
1729 <li class=
"item" data-name=
"LuCI.form.TypedSection">
1730 <span class=
"title">
1731 <a href=
"LuCI.form.TypedSection.html">LuCI.form.TypedSection
</a>
1734 <ul class=
"members itemMembers">
1736 <span class=
"subtitle">Members
</span>
1738 <li data-name=
"LuCI.form.TypedSection##addbtntitle"><a href=
"LuCI.form.TypedSection.html#addbtntitle">addbtntitle
</a></li>
1740 <li data-name=
"LuCI.form.TypedSection##addremove"><a href=
"LuCI.form.TypedSection.html#addremove">addremove
</a></li>
1742 <li data-name=
"LuCI.form.TypedSection##anonymous"><a href=
"LuCI.form.TypedSection.html#anonymous">anonymous
</a></li>
1744 <li data-name=
"LuCI.form.TypedSection##tabbed"><a href=
"LuCI.form.TypedSection.html#tabbed">tabbed
</a></li>
1746 <li data-name=
"LuCI.form.TypedSection##tooltip"><a href=
"LuCI.form.TypedSection.html#tooltip">tooltip
</a></li>
1748 <li data-name=
"LuCI.form.TypedSection##tooltipicon"><a href=
"LuCI.form.TypedSection.html#tooltipicon">tooltipicon
</a></li>
1750 <li data-name=
"LuCI.form.TypedSection##uciconfig"><a href=
"LuCI.form.TypedSection.html#uciconfig">uciconfig
</a></li>
1752 <li data-name=
"LuCI.form.TypedSection#parentoption"><a href=
"LuCI.form.TypedSection.html#parentoption">parentoption
</a></li>
1755 <ul class=
"typedefs itemMembers">
1758 <ul class=
"typedefs itemMembers">
1761 <ul class=
"methods itemMembers">
1763 <span class=
"subtitle">Methods
</span>
1765 <li data-name=
"LuCI.form.TypedSection#append"><a href=
"LuCI.form.TypedSection.html#append">append
</a></li>
1767 <li data-name=
"LuCI.form.TypedSection#cfgsections"><a href=
"LuCI.form.TypedSection.html#cfgsections">cfgsections
</a></li>
1769 <li data-name=
"LuCI.form.TypedSection#cfgvalue"><a href=
"LuCI.form.TypedSection.html#cfgvalue">cfgvalue
</a></li>
1771 <li data-name=
"LuCI.form.TypedSection#filter"><a href=
"LuCI.form.TypedSection.html#filter">filter
</a></li>
1773 <li data-name=
"LuCI.form.TypedSection#formvalue"><a href=
"LuCI.form.TypedSection.html#formvalue">formvalue
</a></li>
1775 <li data-name=
"LuCI.form.TypedSection#getOption"><a href=
"LuCI.form.TypedSection.html#getOption">getOption
</a></li>
1777 <li data-name=
"LuCI.form.TypedSection#getUIElement"><a href=
"LuCI.form.TypedSection.html#getUIElement">getUIElement
</a></li>
1779 <li data-name=
"LuCI.form.TypedSection#load"><a href=
"LuCI.form.TypedSection.html#load">load
</a></li>
1781 <li data-name=
"LuCI.form.TypedSection#option"><a href=
"LuCI.form.TypedSection.html#option">option
</a></li>
1783 <li data-name=
"LuCI.form.TypedSection#parse"><a href=
"LuCI.form.TypedSection.html#parse">parse
</a></li>
1785 <li data-name=
"LuCI.form.TypedSection#render"><a href=
"LuCI.form.TypedSection.html#render">render
</a></li>
1787 <li data-name=
"LuCI.form.TypedSection#stripTags"><a href=
"LuCI.form.TypedSection.html#stripTags">stripTags
</a></li>
1789 <li data-name=
"LuCI.form.TypedSection#tab"><a href=
"LuCI.form.TypedSection.html#tab">tab
</a></li>
1791 <li data-name=
"LuCI.form.TypedSection#taboption"><a href=
"LuCI.form.TypedSection.html#taboption">taboption
</a></li>
1793 <li data-name=
"LuCI.form.TypedSection#titleFn"><a href=
"LuCI.form.TypedSection.html#titleFn">titleFn
</a></li>
1796 <ul class=
"events itemMembers">
1801 <li class=
"item" data-name=
"LuCI.form.Value">
1802 <span class=
"title">
1803 <a href=
"LuCI.form.Value.html">LuCI.form.Value
</a>
1806 <ul class=
"members itemMembers">
1808 <span class=
"subtitle">Members
</span>
1810 <li data-name=
"LuCI.form.Value##password"><a href=
"LuCI.form.Value.html#password">password
</a></li>
1812 <li data-name=
"LuCI.form.Value##placeholder"><a href=
"LuCI.form.Value.html#placeholder">placeholder
</a></li>
1814 <li data-name=
"LuCI.form.Value#datatype"><a href=
"LuCI.form.Value.html#datatype">datatype
</a></li>
1816 <li data-name=
"LuCI.form.Value#default"><a href=
"LuCI.form.Value.html#default">default
</a></li>
1818 <li data-name=
"LuCI.form.Value#editable"><a href=
"LuCI.form.Value.html#editable">editable
</a></li>
1820 <li data-name=
"LuCI.form.Value#modalonly"><a href=
"LuCI.form.Value.html#modalonly">modalonly
</a></li>
1822 <li data-name=
"LuCI.form.Value#onchange"><a href=
"LuCI.form.Value.html#onchange">onchange
</a></li>
1824 <li data-name=
"LuCI.form.Value#optional"><a href=
"LuCI.form.Value.html#optional">optional
</a></li>
1826 <li data-name=
"LuCI.form.Value#readonly"><a href=
"LuCI.form.Value.html#readonly">readonly
</a></li>
1828 <li data-name=
"LuCI.form.Value#retain"><a href=
"LuCI.form.Value.html#retain">retain
</a></li>
1830 <li data-name=
"LuCI.form.Value#rmempty"><a href=
"LuCI.form.Value.html#rmempty">rmempty
</a></li>
1832 <li data-name=
"LuCI.form.Value#uciconfig"><a href=
"LuCI.form.Value.html#uciconfig">uciconfig
</a></li>
1834 <li data-name=
"LuCI.form.Value#ucioption"><a href=
"LuCI.form.Value.html#ucioption">ucioption
</a></li>
1836 <li data-name=
"LuCI.form.Value#ucisection"><a href=
"LuCI.form.Value.html#ucisection">ucisection
</a></li>
1838 <li data-name=
"LuCI.form.Value#validate"><a href=
"LuCI.form.Value.html#validate">validate
</a></li>
1840 <li data-name=
"LuCI.form.Value#width"><a href=
"LuCI.form.Value.html#width">width
</a></li>
1843 <ul class=
"typedefs itemMembers">
1846 <ul class=
"typedefs itemMembers">
1849 <ul class=
"methods itemMembers">
1851 <span class=
"subtitle">Methods
</span>
1853 <li data-name=
"LuCI.form.Value#append"><a href=
"LuCI.form.Value.html#append">append
</a></li>
1855 <li data-name=
"LuCI.form.Value#cbid"><a href=
"LuCI.form.Value.html#cbid">cbid
</a></li>
1857 <li data-name=
"LuCI.form.Value#cfgvalue"><a href=
"LuCI.form.Value.html#cfgvalue">cfgvalue
</a></li>
1859 <li data-name=
"LuCI.form.Value#depends"><a href=
"LuCI.form.Value.html#depends">depends
</a></li>
1861 <li data-name=
"LuCI.form.Value#formvalue"><a href=
"LuCI.form.Value.html#formvalue">formvalue
</a></li>
1863 <li data-name=
"LuCI.form.Value#getUIElement"><a href=
"LuCI.form.Value.html#getUIElement">getUIElement
</a></li>
1865 <li data-name=
"LuCI.form.Value#getValidationError"><a href=
"LuCI.form.Value.html#getValidationError">getValidationError
</a></li>
1867 <li data-name=
"LuCI.form.Value#isActive"><a href=
"LuCI.form.Value.html#isActive">isActive
</a></li>
1869 <li data-name=
"LuCI.form.Value#isValid"><a href=
"LuCI.form.Value.html#isValid">isValid
</a></li>
1871 <li data-name=
"LuCI.form.Value#load"><a href=
"LuCI.form.Value.html#load">load
</a></li>
1873 <li data-name=
"LuCI.form.Value#parse"><a href=
"LuCI.form.Value.html#parse">parse
</a></li>
1875 <li data-name=
"LuCI.form.Value#remove"><a href=
"LuCI.form.Value.html#remove">remove
</a></li>
1877 <li data-name=
"LuCI.form.Value#render"><a href=
"LuCI.form.Value.html#render">render
</a></li>
1879 <li data-name=
"LuCI.form.Value#stripTags"><a href=
"LuCI.form.Value.html#stripTags">stripTags
</a></li>
1881 <li data-name=
"LuCI.form.Value#textvalue"><a href=
"LuCI.form.Value.html#textvalue">textvalue
</a></li>
1883 <li data-name=
"LuCI.form.Value#titleFn"><a href=
"LuCI.form.Value.html#titleFn">titleFn
</a></li>
1885 <li data-name=
"LuCI.form.Value#value"><a href=
"LuCI.form.Value.html#value">value
</a></li>
1887 <li data-name=
"LuCI.form.Value#write"><a href=
"LuCI.form.Value.html#write">write
</a></li>
1890 <ul class=
"events itemMembers">
1895 <li class=
"item" data-name=
"LuCI.fs">
1896 <span class=
"title">
1897 <a href=
"LuCI.fs.html">LuCI.fs
</a>
1900 <ul class=
"members itemMembers">
1903 <ul class=
"typedefs itemMembers">
1905 <span class=
"subtitle">Typedefs
</span>
1907 <li data-name=
"LuCI.fs.FileExecResult"><a href=
"LuCI.fs.html#.FileExecResult">FileExecResult
</a></li>
1909 <li data-name=
"LuCI.fs.FileStatEntry"><a href=
"LuCI.fs.html#.FileStatEntry">FileStatEntry
</a></li>
1912 <ul class=
"typedefs itemMembers">
1915 <ul class=
"methods itemMembers">
1917 <span class=
"subtitle">Methods
</span>
1919 <li data-name=
"LuCI.fs#exec"><a href=
"LuCI.fs.html#exec">exec
</a></li>
1921 <li data-name=
"LuCI.fs#exec_direct"><a href=
"LuCI.fs.html#exec_direct">exec_direct
</a></li>
1923 <li data-name=
"LuCI.fs#lines"><a href=
"LuCI.fs.html#lines">lines
</a></li>
1925 <li data-name=
"LuCI.fs#list"><a href=
"LuCI.fs.html#list">list
</a></li>
1927 <li data-name=
"LuCI.fs#read"><a href=
"LuCI.fs.html#read">read
</a></li>
1929 <li data-name=
"LuCI.fs#read_direct"><a href=
"LuCI.fs.html#read_direct">read_direct
</a></li>
1931 <li data-name=
"LuCI.fs#remove"><a href=
"LuCI.fs.html#remove">remove
</a></li>
1933 <li data-name=
"LuCI.fs#stat"><a href=
"LuCI.fs.html#stat">stat
</a></li>
1935 <li data-name=
"LuCI.fs#trimmed"><a href=
"LuCI.fs.html#trimmed">trimmed
</a></li>
1937 <li data-name=
"LuCI.fs#write"><a href=
"LuCI.fs.html#write">write
</a></li>
1940 <ul class=
"events itemMembers">
1945 <li class=
"item" data-name=
"LuCI.headers">
1946 <span class=
"title">
1947 <a href=
"LuCI.headers.html">LuCI.headers
</a>
1950 <ul class=
"members itemMembers">
1953 <ul class=
"typedefs itemMembers">
1956 <ul class=
"typedefs itemMembers">
1959 <ul class=
"methods itemMembers">
1961 <span class=
"subtitle">Methods
</span>
1963 <li data-name=
"LuCI.headers#get"><a href=
"LuCI.headers.html#get">get
</a></li>
1965 <li data-name=
"LuCI.headers#has"><a href=
"LuCI.headers.html#has">has
</a></li>
1968 <ul class=
"events itemMembers">
1973 <li class=
"item" data-name=
"LuCI.network">
1974 <span class=
"title">
1975 <a href=
"LuCI.network.html">LuCI.network
</a>
1978 <ul class=
"members itemMembers">
1981 <ul class=
"typedefs itemMembers">
1983 <span class=
"subtitle">Typedefs
</span>
1985 <li data-name=
"LuCI.network.SwitchTopology"><a href=
"LuCI.network.html#.SwitchTopology">SwitchTopology
</a></li>
1987 <li data-name=
"LuCI.network.WifiEncryption"><a href=
"LuCI.network.html#.WifiEncryption">WifiEncryption
</a></li>
1989 <li data-name=
"LuCI.network.WifiPeerEntry"><a href=
"LuCI.network.html#.WifiPeerEntry">WifiPeerEntry
</a></li>
1991 <li data-name=
"LuCI.network.WifiRateEntry"><a href=
"LuCI.network.html#.WifiRateEntry">WifiRateEntry
</a></li>
1993 <li data-name=
"LuCI.network.WifiScanResult"><a href=
"LuCI.network.html#.WifiScanResult">WifiScanResult
</a></li>
1996 <ul class=
"typedefs itemMembers">
1999 <ul class=
"methods itemMembers">
2001 <span class=
"subtitle">Methods
</span>
2003 <li data-name=
"LuCI.network#addNetwork"><a href=
"LuCI.network.html#addNetwork">addNetwork
</a></li>
2005 <li data-name=
"LuCI.network#addWifiNetwork"><a href=
"LuCI.network.html#addWifiNetwork">addWifiNetwork
</a></li>
2007 <li data-name=
"LuCI.network#deleteNetwork"><a href=
"LuCI.network.html#deleteNetwork">deleteNetwork
</a></li>
2009 <li data-name=
"LuCI.network#deleteWifiNetwork"><a href=
"LuCI.network.html#deleteWifiNetwork">deleteWifiNetwork
</a></li>
2011 <li data-name=
"LuCI.network#flushCache"><a href=
"LuCI.network.html#flushCache">flushCache
</a></li>
2013 <li data-name=
"LuCI.network#formatWifiEncryption"><a href=
"LuCI.network.html#formatWifiEncryption">formatWifiEncryption
</a></li>
2015 <li data-name=
"LuCI.network#getDevice"><a href=
"LuCI.network.html#getDevice">getDevice
</a></li>
2017 <li data-name=
"LuCI.network#getDevices"><a href=
"LuCI.network.html#getDevices">getDevices
</a></li>
2019 <li data-name=
"LuCI.network#getDSLModemType"><a href=
"LuCI.network.html#getDSLModemType">getDSLModemType
</a></li>
2021 <li data-name=
"LuCI.network#getHostHints"><a href=
"LuCI.network.html#getHostHints">getHostHints
</a></li>
2023 <li data-name=
"LuCI.network#getIfnameOf"><a href=
"LuCI.network.html#getIfnameOf">getIfnameOf
</a></li>
2025 <li data-name=
"LuCI.network#getNetwork"><a href=
"LuCI.network.html#getNetwork">getNetwork
</a></li>
2027 <li data-name=
"LuCI.network#getNetworks"><a href=
"LuCI.network.html#getNetworks">getNetworks
</a></li>
2029 <li data-name=
"LuCI.network#getProtocol"><a href=
"LuCI.network.html#getProtocol">getProtocol
</a></li>
2031 <li data-name=
"LuCI.network#getProtocols"><a href=
"LuCI.network.html#getProtocols">getProtocols
</a></li>
2033 <li data-name=
"LuCI.network#getSwitchTopologies"><a href=
"LuCI.network.html#getSwitchTopologies">getSwitchTopologies
</a></li>
2035 <li data-name=
"LuCI.network#getWAN6Networks"><a href=
"LuCI.network.html#getWAN6Networks">getWAN6Networks
</a></li>
2037 <li data-name=
"LuCI.network#getWANNetworks"><a href=
"LuCI.network.html#getWANNetworks">getWANNetworks
</a></li>
2039 <li data-name=
"LuCI.network#getWifiDevice"><a href=
"LuCI.network.html#getWifiDevice">getWifiDevice
</a></li>
2041 <li data-name=
"LuCI.network#getWifiDevices"><a href=
"LuCI.network.html#getWifiDevices">getWifiDevices
</a></li>
2043 <li data-name=
"LuCI.network#getWifiNetwork"><a href=
"LuCI.network.html#getWifiNetwork">getWifiNetwork
</a></li>
2045 <li data-name=
"LuCI.network#getWifiNetworks"><a href=
"LuCI.network.html#getWifiNetworks">getWifiNetworks
</a></li>
2047 <li data-name=
"LuCI.network#isIgnoredDevice"><a href=
"LuCI.network.html#isIgnoredDevice">isIgnoredDevice
</a></li>
2049 <li data-name=
"LuCI.network#maskToPrefix"><a href=
"LuCI.network.html#maskToPrefix">maskToPrefix
</a></li>
2051 <li data-name=
"LuCI.network#prefixToMask"><a href=
"LuCI.network.html#prefixToMask">prefixToMask
</a></li>
2053 <li data-name=
"LuCI.network#registerErrorCode"><a href=
"LuCI.network.html#registerErrorCode">registerErrorCode
</a></li>
2055 <li data-name=
"LuCI.network#registerPatternVirtual"><a href=
"LuCI.network.html#registerPatternVirtual">registerPatternVirtual
</a></li>
2057 <li data-name=
"LuCI.network#registerProtocol"><a href=
"LuCI.network.html#registerProtocol">registerProtocol
</a></li>
2059 <li data-name=
"LuCI.network#renameNetwork"><a href=
"LuCI.network.html#renameNetwork">renameNetwork
</a></li>
2062 <ul class=
"events itemMembers">
2067 <li class=
"item" data-name=
"LuCI.network.Device">
2068 <span class=
"title">
2069 <a href=
"LuCI.network.Device.html">LuCI.network.Device
</a>
2072 <ul class=
"members itemMembers">
2075 <ul class=
"typedefs itemMembers">
2078 <ul class=
"typedefs itemMembers">
2081 <ul class=
"methods itemMembers">
2083 <span class=
"subtitle">Methods
</span>
2085 <li data-name=
"LuCI.network.Device#getBridgeID"><a href=
"LuCI.network.Device.html#getBridgeID">getBridgeID
</a></li>
2087 <li data-name=
"LuCI.network.Device#getBridgeSTP"><a href=
"LuCI.network.Device.html#getBridgeSTP">getBridgeSTP
</a></li>
2089 <li data-name=
"LuCI.network.Device#getCarrier"><a href=
"LuCI.network.Device.html#getCarrier">getCarrier
</a></li>
2091 <li data-name=
"LuCI.network.Device#getDuplex"><a href=
"LuCI.network.Device.html#getDuplex">getDuplex
</a></li>
2093 <li data-name=
"LuCI.network.Device#getI18n"><a href=
"LuCI.network.Device.html#getI18n">getI18n
</a></li>
2095 <li data-name=
"LuCI.network.Device#getIP6Addrs"><a href=
"LuCI.network.Device.html#getIP6Addrs">getIP6Addrs
</a></li>
2097 <li data-name=
"LuCI.network.Device#getIPAddrs"><a href=
"LuCI.network.Device.html#getIPAddrs">getIPAddrs
</a></li>
2099 <li data-name=
"LuCI.network.Device#getMAC"><a href=
"LuCI.network.Device.html#getMAC">getMAC
</a></li>
2101 <li data-name=
"LuCI.network.Device#getMTU"><a href=
"LuCI.network.Device.html#getMTU">getMTU
</a></li>
2103 <li data-name=
"LuCI.network.Device#getName"><a href=
"LuCI.network.Device.html#getName">getName
</a></li>
2105 <li data-name=
"LuCI.network.Device#getNetwork"><a href=
"LuCI.network.Device.html#getNetwork">getNetwork
</a></li>
2107 <li data-name=
"LuCI.network.Device#getNetworks"><a href=
"LuCI.network.Device.html#getNetworks">getNetworks
</a></li>
2109 <li data-name=
"LuCI.network.Device#getParent"><a href=
"LuCI.network.Device.html#getParent">getParent
</a></li>
2111 <li data-name=
"LuCI.network.Device#getPorts"><a href=
"LuCI.network.Device.html#getPorts">getPorts
</a></li>
2113 <li data-name=
"LuCI.network.Device#getRXBytes"><a href=
"LuCI.network.Device.html#getRXBytes">getRXBytes
</a></li>
2115 <li data-name=
"LuCI.network.Device#getRXPackets"><a href=
"LuCI.network.Device.html#getRXPackets">getRXPackets
</a></li>
2117 <li data-name=
"LuCI.network.Device#getShortName"><a href=
"LuCI.network.Device.html#getShortName">getShortName
</a></li>
2119 <li data-name=
"LuCI.network.Device#getSpeed"><a href=
"LuCI.network.Device.html#getSpeed">getSpeed
</a></li>
2121 <li data-name=
"LuCI.network.Device#getTXBytes"><a href=
"LuCI.network.Device.html#getTXBytes">getTXBytes
</a></li>
2123 <li data-name=
"LuCI.network.Device#getTXPackets"><a href=
"LuCI.network.Device.html#getTXPackets">getTXPackets
</a></li>
2125 <li data-name=
"LuCI.network.Device#getType"><a href=
"LuCI.network.Device.html#getType">getType
</a></li>
2127 <li data-name=
"LuCI.network.Device#getTypeI18n"><a href=
"LuCI.network.Device.html#getTypeI18n">getTypeI18n
</a></li>
2129 <li data-name=
"LuCI.network.Device#getWifiNetwork"><a href=
"LuCI.network.Device.html#getWifiNetwork">getWifiNetwork
</a></li>
2131 <li data-name=
"LuCI.network.Device#isBridge"><a href=
"LuCI.network.Device.html#isBridge">isBridge
</a></li>
2133 <li data-name=
"LuCI.network.Device#isBridgePort"><a href=
"LuCI.network.Device.html#isBridgePort">isBridgePort
</a></li>
2135 <li data-name=
"LuCI.network.Device#isUp"><a href=
"LuCI.network.Device.html#isUp">isUp
</a></li>
2138 <ul class=
"events itemMembers">
2143 <li class=
"item" data-name=
"LuCI.network.Hosts">
2144 <span class=
"title">
2145 <a href=
"LuCI.network.Hosts.html">LuCI.network.Hosts
</a>
2148 <ul class=
"members itemMembers">
2151 <ul class=
"typedefs itemMembers">
2154 <ul class=
"typedefs itemMembers">
2157 <ul class=
"methods itemMembers">
2159 <span class=
"subtitle">Methods
</span>
2161 <li data-name=
"LuCI.network.Hosts#getHostnameByIP6Addr"><a href=
"LuCI.network.Hosts.html#getHostnameByIP6Addr">getHostnameByIP6Addr
</a></li>
2163 <li data-name=
"LuCI.network.Hosts#getHostnameByIPAddr"><a href=
"LuCI.network.Hosts.html#getHostnameByIPAddr">getHostnameByIPAddr
</a></li>
2165 <li data-name=
"LuCI.network.Hosts#getHostnameByMACAddr"><a href=
"LuCI.network.Hosts.html#getHostnameByMACAddr">getHostnameByMACAddr
</a></li>
2167 <li data-name=
"LuCI.network.Hosts#getIP6AddrByMACAddr"><a href=
"LuCI.network.Hosts.html#getIP6AddrByMACAddr">getIP6AddrByMACAddr
</a></li>
2169 <li data-name=
"LuCI.network.Hosts#getIPAddrByMACAddr"><a href=
"LuCI.network.Hosts.html#getIPAddrByMACAddr">getIPAddrByMACAddr
</a></li>
2171 <li data-name=
"LuCI.network.Hosts#getMACAddrByIP6Addr"><a href=
"LuCI.network.Hosts.html#getMACAddrByIP6Addr">getMACAddrByIP6Addr
</a></li>
2173 <li data-name=
"LuCI.network.Hosts#getMACAddrByIPAddr"><a href=
"LuCI.network.Hosts.html#getMACAddrByIPAddr">getMACAddrByIPAddr
</a></li>
2175 <li data-name=
"LuCI.network.Hosts#getMACHints"><a href=
"LuCI.network.Hosts.html#getMACHints">getMACHints
</a></li>
2178 <ul class=
"events itemMembers">
2183 <li class=
"item" data-name=
"LuCI.network.Protocol">
2184 <span class=
"title">
2185 <a href=
"LuCI.network.Protocol.html">LuCI.network.Protocol
</a>
2188 <ul class=
"members itemMembers">
2191 <ul class=
"typedefs itemMembers">
2194 <ul class=
"typedefs itemMembers">
2197 <ul class=
"methods itemMembers">
2199 <span class=
"subtitle">Methods
</span>
2201 <li data-name=
"LuCI.network.Protocol#addDevice"><a href=
"LuCI.network.Protocol.html#addDevice">addDevice
</a></li>
2203 <li data-name=
"LuCI.network.Protocol#containsDevice"><a href=
"LuCI.network.Protocol.html#containsDevice">containsDevice
</a></li>
2205 <li data-name=
"LuCI.network.Protocol#deleteConfiguration"><a href=
"LuCI.network.Protocol.html#deleteConfiguration">deleteConfiguration
</a></li>
2207 <li data-name=
"LuCI.network.Protocol#deleteDevice"><a href=
"LuCI.network.Protocol.html#deleteDevice">deleteDevice
</a></li>
2209 <li data-name=
"LuCI.network.Protocol#get"><a href=
"LuCI.network.Protocol.html#get">get
</a></li>
2211 <li data-name=
"LuCI.network.Protocol#getDevice"><a href=
"LuCI.network.Protocol.html#getDevice">getDevice
</a></li>
2213 <li data-name=
"LuCI.network.Protocol#getDevices"><a href=
"LuCI.network.Protocol.html#getDevices">getDevices
</a></li>
2215 <li data-name=
"LuCI.network.Protocol#getDNS6Addrs"><a href=
"LuCI.network.Protocol.html#getDNS6Addrs">getDNS6Addrs
</a></li>
2217 <li data-name=
"LuCI.network.Protocol#getDNSAddrs"><a href=
"LuCI.network.Protocol.html#getDNSAddrs">getDNSAddrs
</a></li>
2219 <li data-name=
"LuCI.network.Protocol#getErrors"><a href=
"LuCI.network.Protocol.html#getErrors">getErrors
</a></li>
2221 <li data-name=
"LuCI.network.Protocol#getExpiry"><a href=
"LuCI.network.Protocol.html#getExpiry">getExpiry
</a></li>
2223 <li data-name=
"LuCI.network.Protocol#getGateway6Addr"><a href=
"LuCI.network.Protocol.html#getGateway6Addr">getGateway6Addr
</a></li>
2225 <li data-name=
"LuCI.network.Protocol#getGatewayAddr"><a href=
"LuCI.network.Protocol.html#getGatewayAddr">getGatewayAddr
</a></li>
2227 <li data-name=
"LuCI.network.Protocol#getI18n"><a href=
"LuCI.network.Protocol.html#getI18n">getI18n
</a></li>
2229 <li data-name=
"LuCI.network.Protocol#getIfname"><a href=
"LuCI.network.Protocol.html#getIfname">getIfname
</a></li>
2231 <li data-name=
"LuCI.network.Protocol#getIP6Addr"><a href=
"LuCI.network.Protocol.html#getIP6Addr">getIP6Addr
</a></li>
2233 <li data-name=
"LuCI.network.Protocol#getIP6Addrs"><a href=
"LuCI.network.Protocol.html#getIP6Addrs">getIP6Addrs
</a></li>
2235 <li data-name=
"LuCI.network.Protocol#getIP6Prefix"><a href=
"LuCI.network.Protocol.html#getIP6Prefix">getIP6Prefix
</a></li>
2237 <li data-name=
"LuCI.network.Protocol#getIPAddr"><a href=
"LuCI.network.Protocol.html#getIPAddr">getIPAddr
</a></li>
2239 <li data-name=
"LuCI.network.Protocol#getIPAddrs"><a href=
"LuCI.network.Protocol.html#getIPAddrs">getIPAddrs
</a></li>
2241 <li data-name=
"LuCI.network.Protocol#getL2Device"><a href=
"LuCI.network.Protocol.html#getL2Device">getL2Device
</a></li>
2243 <li data-name=
"LuCI.network.Protocol#getL3Device"><a href=
"LuCI.network.Protocol.html#getL3Device">getL3Device
</a></li>
2245 <li data-name=
"LuCI.network.Protocol#getMetric"><a href=
"LuCI.network.Protocol.html#getMetric">getMetric
</a></li>
2247 <li data-name=
"LuCI.network.Protocol#getName"><a href=
"LuCI.network.Protocol.html#getName">getName
</a></li>
2249 <li data-name=
"LuCI.network.Protocol#getNetmask"><a href=
"LuCI.network.Protocol.html#getNetmask">getNetmask
</a></li>
2251 <li data-name=
"LuCI.network.Protocol#getOpkgPackage"><a href=
"LuCI.network.Protocol.html#getOpkgPackage">getOpkgPackage
</a></li>
2253 <li data-name=
"LuCI.network.Protocol#getProtocol"><a href=
"LuCI.network.Protocol.html#getProtocol">getProtocol
</a></li>
2255 <li data-name=
"LuCI.network.Protocol#getType"><a href=
"LuCI.network.Protocol.html#getType">getType
</a></li>
2257 <li data-name=
"LuCI.network.Protocol#getUptime"><a href=
"LuCI.network.Protocol.html#getUptime">getUptime
</a></li>
2259 <li data-name=
"LuCI.network.Protocol#getZoneName"><a href=
"LuCI.network.Protocol.html#getZoneName">getZoneName
</a></li>
2261 <li data-name=
"LuCI.network.Protocol#isAlias"><a href=
"LuCI.network.Protocol.html#isAlias">isAlias
</a></li>
2263 <li data-name=
"LuCI.network.Protocol#isBridge"><a href=
"LuCI.network.Protocol.html#isBridge">isBridge
</a></li>
2265 <li data-name=
"LuCI.network.Protocol#isCreateable"><a href=
"LuCI.network.Protocol.html#isCreateable">isCreateable
</a></li>
2267 <li data-name=
"LuCI.network.Protocol#isDynamic"><a href=
"LuCI.network.Protocol.html#isDynamic">isDynamic
</a></li>
2269 <li data-name=
"LuCI.network.Protocol#isEmpty"><a href=
"LuCI.network.Protocol.html#isEmpty">isEmpty
</a></li>
2271 <li data-name=
"LuCI.network.Protocol#isFloating"><a href=
"LuCI.network.Protocol.html#isFloating">isFloating
</a></li>
2273 <li data-name=
"LuCI.network.Protocol#isInstalled"><a href=
"LuCI.network.Protocol.html#isInstalled">isInstalled
</a></li>
2275 <li data-name=
"LuCI.network.Protocol#isUp"><a href=
"LuCI.network.Protocol.html#isUp">isUp
</a></li>
2277 <li data-name=
"LuCI.network.Protocol#isVirtual"><a href=
"LuCI.network.Protocol.html#isVirtual">isVirtual
</a></li>
2279 <li data-name=
"LuCI.network.Protocol#set"><a href=
"LuCI.network.Protocol.html#set">set
</a></li>
2282 <ul class=
"events itemMembers">
2287 <li class=
"item" data-name=
"LuCI.network.WifiDevice">
2288 <span class=
"title">
2289 <a href=
"LuCI.network.WifiDevice.html">LuCI.network.WifiDevice
</a>
2292 <ul class=
"members itemMembers">
2295 <ul class=
"typedefs itemMembers">
2298 <ul class=
"typedefs itemMembers">
2301 <ul class=
"methods itemMembers">
2303 <span class=
"subtitle">Methods
</span>
2305 <li data-name=
"LuCI.network.WifiDevice#addWifiNetwork"><a href=
"LuCI.network.WifiDevice.html#addWifiNetwork">addWifiNetwork
</a></li>
2307 <li data-name=
"LuCI.network.WifiDevice#deleteWifiNetwork"><a href=
"LuCI.network.WifiDevice.html#deleteWifiNetwork">deleteWifiNetwork
</a></li>
2309 <li data-name=
"LuCI.network.WifiDevice#get"><a href=
"LuCI.network.WifiDevice.html#get">get
</a></li>
2311 <li data-name=
"LuCI.network.WifiDevice#getHTModes"><a href=
"LuCI.network.WifiDevice.html#getHTModes">getHTModes
</a></li>
2313 <li data-name=
"LuCI.network.WifiDevice#getHWModes"><a href=
"LuCI.network.WifiDevice.html#getHWModes">getHWModes
</a></li>
2315 <li data-name=
"LuCI.network.WifiDevice#getI18n"><a href=
"LuCI.network.WifiDevice.html#getI18n">getI18n
</a></li>
2317 <li data-name=
"LuCI.network.WifiDevice#getName"><a href=
"LuCI.network.WifiDevice.html#getName">getName
</a></li>
2319 <li data-name=
"LuCI.network.WifiDevice#getScanList"><a href=
"LuCI.network.WifiDevice.html#getScanList">getScanList
</a></li>
2321 <li data-name=
"LuCI.network.WifiDevice#getWifiNetwork"><a href=
"LuCI.network.WifiDevice.html#getWifiNetwork">getWifiNetwork
</a></li>
2323 <li data-name=
"LuCI.network.WifiDevice#getWifiNetworks"><a href=
"LuCI.network.WifiDevice.html#getWifiNetworks">getWifiNetworks
</a></li>
2325 <li data-name=
"LuCI.network.WifiDevice#isDisabled"><a href=
"LuCI.network.WifiDevice.html#isDisabled">isDisabled
</a></li>
2327 <li data-name=
"LuCI.network.WifiDevice#isUp"><a href=
"LuCI.network.WifiDevice.html#isUp">isUp
</a></li>
2329 <li data-name=
"LuCI.network.WifiDevice#set"><a href=
"LuCI.network.WifiDevice.html#set">set
</a></li>
2332 <ul class=
"events itemMembers">
2337 <li class=
"item" data-name=
"LuCI.network.WifiNetwork">
2338 <span class=
"title">
2339 <a href=
"LuCI.network.WifiNetwork.html">LuCI.network.WifiNetwork
</a>
2342 <ul class=
"members itemMembers">
2345 <ul class=
"typedefs itemMembers">
2348 <ul class=
"typedefs itemMembers">
2351 <ul class=
"methods itemMembers">
2353 <span class=
"subtitle">Methods
</span>
2355 <li data-name=
"LuCI.network.WifiNetwork#disconnectClient"><a href=
"LuCI.network.WifiNetwork.html#disconnectClient">disconnectClient
</a></li>
2357 <li data-name=
"LuCI.network.WifiNetwork#get"><a href=
"LuCI.network.WifiNetwork.html#get">get
</a></li>
2359 <li data-name=
"LuCI.network.WifiNetwork#getActiveBSSID"><a href=
"LuCI.network.WifiNetwork.html#getActiveBSSID">getActiveBSSID
</a></li>
2361 <li data-name=
"LuCI.network.WifiNetwork#getActiveEncryption"><a href=
"LuCI.network.WifiNetwork.html#getActiveEncryption">getActiveEncryption
</a></li>
2363 <li data-name=
"LuCI.network.WifiNetwork#getActiveMode"><a href=
"LuCI.network.WifiNetwork.html#getActiveMode">getActiveMode
</a></li>
2365 <li data-name=
"LuCI.network.WifiNetwork#getActiveModeI18n"><a href=
"LuCI.network.WifiNetwork.html#getActiveModeI18n">getActiveModeI18n
</a></li>
2367 <li data-name=
"LuCI.network.WifiNetwork#getActiveSSID"><a href=
"LuCI.network.WifiNetwork.html#getActiveSSID">getActiveSSID
</a></li>
2369 <li data-name=
"LuCI.network.WifiNetwork#getAssocList"><a href=
"LuCI.network.WifiNetwork.html#getAssocList">getAssocList
</a></li>
2371 <li data-name=
"LuCI.network.WifiNetwork#getBitRate"><a href=
"LuCI.network.WifiNetwork.html#getBitRate">getBitRate
</a></li>
2373 <li data-name=
"LuCI.network.WifiNetwork#getBSSID"><a href=
"LuCI.network.WifiNetwork.html#getBSSID">getBSSID
</a></li>
2375 <li data-name=
"LuCI.network.WifiNetwork#getChannel"><a href=
"LuCI.network.WifiNetwork.html#getChannel">getChannel
</a></li>
2377 <li data-name=
"LuCI.network.WifiNetwork#getCountryCode"><a href=
"LuCI.network.WifiNetwork.html#getCountryCode">getCountryCode
</a></li>
2379 <li data-name=
"LuCI.network.WifiNetwork#getDevice"><a href=
"LuCI.network.WifiNetwork.html#getDevice">getDevice
</a></li>
2381 <li data-name=
"LuCI.network.WifiNetwork#getFrequency"><a href=
"LuCI.network.WifiNetwork.html#getFrequency">getFrequency
</a></li>
2383 <li data-name=
"LuCI.network.WifiNetwork#getI18n"><a href=
"LuCI.network.WifiNetwork.html#getI18n">getI18n
</a></li>
2385 <li data-name=
"LuCI.network.WifiNetwork#getID"><a href=
"LuCI.network.WifiNetwork.html#getID">getID
</a></li>
2387 <li data-name=
"LuCI.network.WifiNetwork#getIfname"><a href=
"LuCI.network.WifiNetwork.html#getIfname">getIfname
</a></li>
2389 <li data-name=
"LuCI.network.WifiNetwork#getMeshID"><a href=
"LuCI.network.WifiNetwork.html#getMeshID">getMeshID
</a></li>
2391 <li data-name=
"LuCI.network.WifiNetwork#getMode"><a href=
"LuCI.network.WifiNetwork.html#getMode">getMode
</a></li>
2393 <li data-name=
"LuCI.network.WifiNetwork#getName"><a href=
"LuCI.network.WifiNetwork.html#getName">getName
</a></li>
2395 <li data-name=
"LuCI.network.WifiNetwork#getNetwork"><a href=
"LuCI.network.WifiNetwork.html#getNetwork">getNetwork
</a></li>
2397 <li data-name=
"LuCI.network.WifiNetwork#getNetworkNames"><a href=
"LuCI.network.WifiNetwork.html#getNetworkNames">getNetworkNames
</a></li>
2399 <li data-name=
"LuCI.network.WifiNetwork#getNetworks"><a href=
"LuCI.network.WifiNetwork.html#getNetworks">getNetworks
</a></li>
2401 <li data-name=
"LuCI.network.WifiNetwork#getNoise"><a href=
"LuCI.network.WifiNetwork.html#getNoise">getNoise
</a></li>
2403 <li data-name=
"LuCI.network.WifiNetwork#getShortName"><a href=
"LuCI.network.WifiNetwork.html#getShortName">getShortName
</a></li>
2405 <li data-name=
"LuCI.network.WifiNetwork#getSignal"><a href=
"LuCI.network.WifiNetwork.html#getSignal">getSignal
</a></li>
2407 <li data-name=
"LuCI.network.WifiNetwork#getSignalLevel"><a href=
"LuCI.network.WifiNetwork.html#getSignalLevel">getSignalLevel
</a></li>
2409 <li data-name=
"LuCI.network.WifiNetwork#getSignalPercent"><a href=
"LuCI.network.WifiNetwork.html#getSignalPercent">getSignalPercent
</a></li>
2411 <li data-name=
"LuCI.network.WifiNetwork#getSSID"><a href=
"LuCI.network.WifiNetwork.html#getSSID">getSSID
</a></li>
2413 <li data-name=
"LuCI.network.WifiNetwork#getTXPower"><a href=
"LuCI.network.WifiNetwork.html#getTXPower">getTXPower
</a></li>
2415 <li data-name=
"LuCI.network.WifiNetwork#getTXPowerOffset"><a href=
"LuCI.network.WifiNetwork.html#getTXPowerOffset">getTXPowerOffset
</a></li>
2417 <li data-name=
"LuCI.network.WifiNetwork#getVlanIfnames"><a href=
"LuCI.network.WifiNetwork.html#getVlanIfnames">getVlanIfnames
</a></li>
2419 <li data-name=
"LuCI.network.WifiNetwork#getWifiDevice"><a href=
"LuCI.network.WifiNetwork.html#getWifiDevice">getWifiDevice
</a></li>
2421 <li data-name=
"LuCI.network.WifiNetwork#getWifiDeviceName"><a href=
"LuCI.network.WifiNetwork.html#getWifiDeviceName">getWifiDeviceName
</a></li>
2423 <li data-name=
"LuCI.network.WifiNetwork#isClientDisconnectSupported"><a href=
"LuCI.network.WifiNetwork.html#isClientDisconnectSupported">isClientDisconnectSupported
</a></li>
2425 <li data-name=
"LuCI.network.WifiNetwork#isDisabled"><a href=
"LuCI.network.WifiNetwork.html#isDisabled">isDisabled
</a></li>
2427 <li data-name=
"LuCI.network.WifiNetwork#isUp"><a href=
"LuCI.network.WifiNetwork.html#isUp">isUp
</a></li>
2429 <li data-name=
"LuCI.network.WifiNetwork#set"><a href=
"LuCI.network.WifiNetwork.html#set">set
</a></li>
2432 <ul class=
"events itemMembers">
2437 <li class=
"item" data-name=
"LuCI.poll">
2438 <span class=
"title">
2439 <a href=
"LuCI.poll.html">LuCI.poll
</a>
2442 <ul class=
"members itemMembers">
2445 <ul class=
"typedefs itemMembers">
2448 <ul class=
"typedefs itemMembers">
2451 <ul class=
"methods itemMembers">
2453 <span class=
"subtitle">Methods
</span>
2455 <li data-name=
"LuCI.poll#active"><a href=
"LuCI.poll.html#active">active
</a></li>
2457 <li data-name=
"LuCI.poll#add"><a href=
"LuCI.poll.html#add">add
</a></li>
2459 <li data-name=
"LuCI.poll#remove"><a href=
"LuCI.poll.html#remove">remove
</a></li>
2461 <li data-name=
"LuCI.poll#start"><a href=
"LuCI.poll.html#start">start
</a></li>
2463 <li data-name=
"LuCI.poll#stop"><a href=
"LuCI.poll.html#stop">stop
</a></li>
2466 <ul class=
"events itemMembers">
2471 <li class=
"item" data-name=
"LuCI.request">
2472 <span class=
"title">
2473 <a href=
"LuCI.request.html">LuCI.request
</a>
2476 <ul class=
"members itemMembers">
2479 <ul class=
"typedefs itemMembers">
2481 <span class=
"subtitle">Typedefs
</span>
2483 <li data-name=
"LuCI.request.interceptorFn"><a href=
"LuCI.request.html#.interceptorFn">interceptorFn
</a></li>
2485 <li data-name=
"LuCI.request.RequestOptions"><a href=
"LuCI.request.html#.RequestOptions">RequestOptions
</a></li>
2488 <ul class=
"typedefs itemMembers">
2491 <ul class=
"methods itemMembers">
2493 <span class=
"subtitle">Methods
</span>
2495 <li data-name=
"LuCI.request#addInterceptor"><a href=
"LuCI.request.html#addInterceptor">addInterceptor
</a></li>
2497 <li data-name=
"LuCI.request#expandURL"><a href=
"LuCI.request.html#expandURL">expandURL
</a></li>
2499 <li data-name=
"LuCI.request#get"><a href=
"LuCI.request.html#get">get
</a></li>
2501 <li data-name=
"LuCI.request#post"><a href=
"LuCI.request.html#post">post
</a></li>
2503 <li data-name=
"LuCI.request#removeInterceptor"><a href=
"LuCI.request.html#removeInterceptor">removeInterceptor
</a></li>
2505 <li data-name=
"LuCI.request#request"><a href=
"LuCI.request.html#request">request
</a></li>
2508 <ul class=
"events itemMembers">
2513 <li class=
"item" data-name=
"LuCI.request.poll">
2514 <span class=
"title">
2515 <a href=
"LuCI.request.poll.html">LuCI.request.poll
</a>
2518 <ul class=
"members itemMembers">
2521 <ul class=
"typedefs itemMembers">
2523 <span class=
"subtitle">Typedefs
</span>
2525 <li data-name=
"LuCI.request.poll~callbackFn"><a href=
"LuCI.request.poll.html#~callbackFn">callbackFn
</a></li>
2528 <ul class=
"typedefs itemMembers">
2531 <ul class=
"methods itemMembers">
2533 <span class=
"subtitle">Methods
</span>
2535 <li data-name=
"LuCI.request.poll#active"><a href=
"LuCI.request.poll.html#active">active
</a></li>
2537 <li data-name=
"LuCI.request.poll#add"><a href=
"LuCI.request.poll.html#add">add
</a></li>
2539 <li data-name=
"LuCI.request.poll#remove"><a href=
"LuCI.request.poll.html#remove">remove
</a></li>
2541 <li data-name=
"LuCI.request.poll#start"><a href=
"LuCI.request.poll.html#start">start
</a></li>
2543 <li data-name=
"LuCI.request.poll#stop"><a href=
"LuCI.request.poll.html#stop">stop
</a></li>
2546 <ul class=
"events itemMembers">
2551 <li class=
"item" data-name=
"LuCI.response">
2552 <span class=
"title">
2553 <a href=
"LuCI.response.html">LuCI.response
</a>
2556 <ul class=
"members itemMembers">
2558 <span class=
"subtitle">Members
</span>
2560 <li data-name=
"LuCI.response#duration"><a href=
"LuCI.response.html#duration">duration
</a></li>
2562 <li data-name=
"LuCI.response#headers"><a href=
"LuCI.response.html#headers">headers
</a></li>
2564 <li data-name=
"LuCI.response#ok"><a href=
"LuCI.response.html#ok">ok
</a></li>
2566 <li data-name=
"LuCI.response#status"><a href=
"LuCI.response.html#status">status
</a></li>
2568 <li data-name=
"LuCI.response#statusText"><a href=
"LuCI.response.html#statusText">statusText
</a></li>
2570 <li data-name=
"LuCI.response#url"><a href=
"LuCI.response.html#url">url
</a></li>
2573 <ul class=
"typedefs itemMembers">
2576 <ul class=
"typedefs itemMembers">
2579 <ul class=
"methods itemMembers">
2581 <span class=
"subtitle">Methods
</span>
2583 <li data-name=
"LuCI.response#blob"><a href=
"LuCI.response.html#blob">blob
</a></li>
2585 <li data-name=
"LuCI.response#clone"><a href=
"LuCI.response.html#clone">clone
</a></li>
2587 <li data-name=
"LuCI.response#json"><a href=
"LuCI.response.html#json">json
</a></li>
2589 <li data-name=
"LuCI.response#text"><a href=
"LuCI.response.html#text">text
</a></li>
2592 <ul class=
"events itemMembers">
2597 <li class=
"item" data-name=
"LuCI.rpc">
2598 <span class=
"title">
2599 <a href=
"LuCI.rpc.html">LuCI.rpc
</a>
2602 <ul class=
"members itemMembers">
2605 <ul class=
"typedefs itemMembers">
2607 <span class=
"subtitle">Typedefs
</span>
2609 <li data-name=
"LuCI.rpc.DeclareOptions"><a href=
"LuCI.rpc.html#.DeclareOptions">DeclareOptions
</a></li>
2611 <li data-name=
"LuCI.rpc~filterFn"><a href=
"LuCI.rpc.html#~filterFn">filterFn
</a></li>
2613 <li data-name=
"LuCI.rpc~interceptorFn"><a href=
"LuCI.rpc.html#~interceptorFn">interceptorFn
</a></li>
2615 <li data-name=
"LuCI.rpc~invokeFn"><a href=
"LuCI.rpc.html#~invokeFn">invokeFn
</a></li>
2618 <ul class=
"typedefs itemMembers">
2621 <ul class=
"methods itemMembers">
2623 <span class=
"subtitle">Methods
</span>
2625 <li data-name=
"LuCI.rpc#addInterceptor"><a href=
"LuCI.rpc.html#addInterceptor">addInterceptor
</a></li>
2627 <li data-name=
"LuCI.rpc#declare"><a href=
"LuCI.rpc.html#declare">declare
</a></li>
2629 <li data-name=
"LuCI.rpc#getBaseURL"><a href=
"LuCI.rpc.html#getBaseURL">getBaseURL
</a></li>
2631 <li data-name=
"LuCI.rpc#getSessionID"><a href=
"LuCI.rpc.html#getSessionID">getSessionID
</a></li>
2633 <li data-name=
"LuCI.rpc#getStatusText"><a href=
"LuCI.rpc.html#getStatusText">getStatusText
</a></li>
2635 <li data-name=
"LuCI.rpc#list"><a href=
"LuCI.rpc.html#list">list
</a></li>
2637 <li data-name=
"LuCI.rpc#removeInterceptor"><a href=
"LuCI.rpc.html#removeInterceptor">removeInterceptor
</a></li>
2639 <li data-name=
"LuCI.rpc#setBaseURL"><a href=
"LuCI.rpc.html#setBaseURL">setBaseURL
</a></li>
2641 <li data-name=
"LuCI.rpc#setSessionID"><a href=
"LuCI.rpc.html#setSessionID">setSessionID
</a></li>
2644 <ul class=
"events itemMembers">
2649 <li class=
"item" data-name=
"LuCI.session">
2650 <span class=
"title">
2651 <a href=
"LuCI.session.html">LuCI.session
</a>
2654 <ul class=
"members itemMembers">
2657 <ul class=
"typedefs itemMembers">
2660 <ul class=
"typedefs itemMembers">
2663 <ul class=
"methods itemMembers">
2665 <span class=
"subtitle">Methods
</span>
2667 <li data-name=
"LuCI.session#getID"><a href=
"LuCI.session.html#getID">getID
</a></li>
2669 <li data-name=
"LuCI.session#getLocalData"><a href=
"LuCI.session.html#getLocalData">getLocalData
</a></li>
2671 <li data-name=
"LuCI.session#getToken"><a href=
"LuCI.session.html#getToken">getToken
</a></li>
2673 <li data-name=
"LuCI.session#setLocalData"><a href=
"LuCI.session.html#setLocalData">setLocalData
</a></li>
2676 <ul class=
"events itemMembers">
2681 <li class=
"item" data-name=
"LuCI.uci">
2682 <span class=
"title">
2683 <a href=
"LuCI.uci.html">LuCI.uci
</a>
2686 <ul class=
"members itemMembers">
2689 <ul class=
"typedefs itemMembers">
2691 <span class=
"subtitle">Typedefs
</span>
2693 <li data-name=
"LuCI.uci.ChangeRecord"><a href=
"LuCI.uci.html#.ChangeRecord">ChangeRecord
</a></li>
2695 <li data-name=
"LuCI.uci.SectionObject"><a href=
"LuCI.uci.html#.SectionObject">SectionObject
</a></li>
2697 <li data-name=
"LuCI.uci~sectionsFn"><a href=
"LuCI.uci.html#~sectionsFn">sectionsFn
</a></li>
2700 <ul class=
"typedefs itemMembers">
2703 <ul class=
"methods itemMembers">
2705 <span class=
"subtitle">Methods
</span>
2707 <li data-name=
"LuCI.uci#add"><a href=
"LuCI.uci.html#add">add
</a></li>
2709 <li data-name=
"LuCI.uci#apply"><a href=
"LuCI.uci.html#apply">apply
</a></li>
2711 <li data-name=
"LuCI.uci#changes"><a href=
"LuCI.uci.html#changes">changes
</a></li>
2713 <li data-name=
"LuCI.uci#createSID"><a href=
"LuCI.uci.html#createSID">createSID
</a></li>
2715 <li data-name=
"LuCI.uci#get"><a href=
"LuCI.uci.html#get">get
</a></li>
2717 <li data-name=
"LuCI.uci#get_first"><a href=
"LuCI.uci.html#get_first">get_first
</a></li>
2719 <li data-name=
"LuCI.uci#load"><a href=
"LuCI.uci.html#load">load
</a></li>
2721 <li data-name=
"LuCI.uci#move"><a href=
"LuCI.uci.html#move">move
</a></li>
2723 <li data-name=
"LuCI.uci#remove"><a href=
"LuCI.uci.html#remove">remove
</a></li>
2725 <li data-name=
"LuCI.uci#resolveSID"><a href=
"LuCI.uci.html#resolveSID">resolveSID
</a></li>
2727 <li data-name=
"LuCI.uci#save"><a href=
"LuCI.uci.html#save">save
</a></li>
2729 <li data-name=
"LuCI.uci#sections"><a href=
"LuCI.uci.html#sections">sections
</a></li>
2731 <li data-name=
"LuCI.uci#set"><a href=
"LuCI.uci.html#set">set
</a></li>
2733 <li data-name=
"LuCI.uci#set_first"><a href=
"LuCI.uci.html#set_first">set_first
</a></li>
2735 <li data-name=
"LuCI.uci#unload"><a href=
"LuCI.uci.html#unload">unload
</a></li>
2737 <li data-name=
"LuCI.uci#unset"><a href=
"LuCI.uci.html#unset">unset
</a></li>
2739 <li data-name=
"LuCI.uci#unset_first"><a href=
"LuCI.uci.html#unset_first">unset_first
</a></li>
2742 <ul class=
"events itemMembers">
2747 <li class=
"item" data-name=
"LuCI.ui">
2748 <span class=
"title">
2749 <a href=
"LuCI.ui.html">LuCI.ui
</a>
2752 <ul class=
"members itemMembers">
2755 <ul class=
"typedefs itemMembers">
2757 <span class=
"subtitle">Typedefs
</span>
2759 <li data-name=
"LuCI.ui.FileUploadReply"><a href=
"LuCI.ui.html#.FileUploadReply">FileUploadReply
</a></li>
2762 <ul class=
"typedefs itemMembers">
2765 <ul class=
"methods itemMembers">
2767 <span class=
"subtitle">Methods
</span>
2769 <li data-name=
"LuCI.ui#addNotification"><a href=
"LuCI.ui.html#addNotification">addNotification
</a></li>
2771 <li data-name=
"LuCI.ui#addValidator"><a href=
"LuCI.ui.html#addValidator">addValidator
</a></li>
2773 <li data-name=
"LuCI.ui#awaitReconnect"><a href=
"LuCI.ui.html#awaitReconnect">awaitReconnect
</a></li>
2775 <li data-name=
"LuCI.ui#createHandlerFn"><a href=
"LuCI.ui.html#createHandlerFn">createHandlerFn
</a></li>
2777 <li data-name=
"LuCI.ui#hideIndicator"><a href=
"LuCI.ui.html#hideIndicator">hideIndicator
</a></li>
2779 <li data-name=
"LuCI.ui#hideModal"><a href=
"LuCI.ui.html#hideModal">hideModal
</a></li>
2781 <li data-name=
"LuCI.ui#instantiateView"><a href=
"LuCI.ui.html#instantiateView">instantiateView
</a></li>
2783 <li data-name=
"LuCI.ui#itemlist"><a href=
"LuCI.ui.html#itemlist">itemlist
</a></li>
2785 <li data-name=
"LuCI.ui#pingDevice"><a href=
"LuCI.ui.html#pingDevice">pingDevice
</a></li>
2787 <li data-name=
"LuCI.ui#showIndicator"><a href=
"LuCI.ui.html#showIndicator">showIndicator
</a></li>
2789 <li data-name=
"LuCI.ui#showModal"><a href=
"LuCI.ui.html#showModal">showModal
</a></li>
2791 <li data-name=
"LuCI.ui#uploadFile"><a href=
"LuCI.ui.html#uploadFile">uploadFile
</a></li>
2794 <ul class=
"events itemMembers">
2799 <li class=
"item" data-name=
"LuCI.ui.AbstractElement">
2800 <span class=
"title">
2801 <a href=
"LuCI.ui.AbstractElement.html">LuCI.ui.AbstractElement
</a>
2804 <ul class=
"members itemMembers">
2807 <ul class=
"typedefs itemMembers">
2809 <span class=
"subtitle">Typedefs
</span>
2811 <li data-name=
"LuCI.ui.AbstractElement.InitOptions"><a href=
"LuCI.ui.AbstractElement.html#.InitOptions">InitOptions
</a></li>
2814 <ul class=
"typedefs itemMembers">
2817 <ul class=
"methods itemMembers">
2819 <span class=
"subtitle">Methods
</span>
2821 <li data-name=
"LuCI.ui.AbstractElement#getValidationError"><a href=
"LuCI.ui.AbstractElement.html#getValidationError">getValidationError
</a></li>
2823 <li data-name=
"LuCI.ui.AbstractElement#getValue"><a href=
"LuCI.ui.AbstractElement.html#getValue">getValue
</a></li>
2825 <li data-name=
"LuCI.ui.AbstractElement#isChanged"><a href=
"LuCI.ui.AbstractElement.html#isChanged">isChanged
</a></li>
2827 <li data-name=
"LuCI.ui.AbstractElement#isValid"><a href=
"LuCI.ui.AbstractElement.html#isValid">isValid
</a></li>
2829 <li data-name=
"LuCI.ui.AbstractElement#registerEvents"><a href=
"LuCI.ui.AbstractElement.html#registerEvents">registerEvents
</a></li>
2831 <li data-name=
"LuCI.ui.AbstractElement#render"><a href=
"LuCI.ui.AbstractElement.html#render">render
</a></li>
2833 <li data-name=
"LuCI.ui.AbstractElement#setChangeEvents"><a href=
"LuCI.ui.AbstractElement.html#setChangeEvents">setChangeEvents
</a></li>
2835 <li data-name=
"LuCI.ui.AbstractElement#setPlaceholder"><a href=
"LuCI.ui.AbstractElement.html#setPlaceholder">setPlaceholder
</a></li>
2837 <li data-name=
"LuCI.ui.AbstractElement#setUpdateEvents"><a href=
"LuCI.ui.AbstractElement.html#setUpdateEvents">setUpdateEvents
</a></li>
2839 <li data-name=
"LuCI.ui.AbstractElement#setValue"><a href=
"LuCI.ui.AbstractElement.html#setValue">setValue
</a></li>
2841 <li data-name=
"LuCI.ui.AbstractElement#triggerValidation"><a href=
"LuCI.ui.AbstractElement.html#triggerValidation">triggerValidation
</a></li>
2844 <ul class=
"events itemMembers">
2849 <li class=
"item" data-name=
"LuCI.ui.changes">
2850 <span class=
"title">
2851 <a href=
"LuCI.ui.changes.html">LuCI.ui.changes
</a>
2854 <ul class=
"members itemMembers">
2857 <ul class=
"typedefs itemMembers">
2860 <ul class=
"typedefs itemMembers">
2863 <ul class=
"methods itemMembers">
2865 <span class=
"subtitle">Methods
</span>
2867 <li data-name=
"LuCI.ui.changes#apply"><a href=
"LuCI.ui.changes.html#apply">apply
</a></li>
2869 <li data-name=
"LuCI.ui.changes#displayChanges"><a href=
"LuCI.ui.changes.html#displayChanges">displayChanges
</a></li>
2871 <li data-name=
"LuCI.ui.changes#renderChangeIndicator"><a href=
"LuCI.ui.changes.html#renderChangeIndicator">renderChangeIndicator
</a></li>
2873 <li data-name=
"LuCI.ui.changes#revert"><a href=
"LuCI.ui.changes.html#revert">revert
</a></li>
2875 <li data-name=
"LuCI.ui.changes#setIndicator"><a href=
"LuCI.ui.changes.html#setIndicator">setIndicator
</a></li>
2878 <ul class=
"events itemMembers">
2883 <li class=
"item" data-name=
"LuCI.ui.Checkbox">
2884 <span class=
"title">
2885 <a href=
"LuCI.ui.Checkbox.html">LuCI.ui.Checkbox
</a>
2888 <ul class=
"members itemMembers">
2891 <ul class=
"typedefs itemMembers">
2893 <span class=
"subtitle">Typedefs
</span>
2895 <li data-name=
"LuCI.ui.Checkbox.InitOptions"><a href=
"LuCI.ui.Checkbox.html#.InitOptions">InitOptions
</a></li>
2898 <ul class=
"typedefs itemMembers">
2901 <ul class=
"methods itemMembers">
2903 <span class=
"subtitle">Methods
</span>
2905 <li data-name=
"LuCI.ui.Checkbox#getValidationError"><a href=
"LuCI.ui.Checkbox.html#getValidationError">getValidationError
</a></li>
2907 <li data-name=
"LuCI.ui.Checkbox#getValue"><a href=
"LuCI.ui.Checkbox.html#getValue">getValue
</a></li>
2909 <li data-name=
"LuCI.ui.Checkbox#isChanged"><a href=
"LuCI.ui.Checkbox.html#isChanged">isChanged
</a></li>
2911 <li data-name=
"LuCI.ui.Checkbox#isChecked"><a href=
"LuCI.ui.Checkbox.html#isChecked">isChecked
</a></li>
2913 <li data-name=
"LuCI.ui.Checkbox#isValid"><a href=
"LuCI.ui.Checkbox.html#isValid">isValid
</a></li>
2915 <li data-name=
"LuCI.ui.Checkbox#registerEvents"><a href=
"LuCI.ui.Checkbox.html#registerEvents">registerEvents
</a></li>
2917 <li data-name=
"LuCI.ui.Checkbox#render"><a href=
"LuCI.ui.Checkbox.html#render">render
</a></li>
2919 <li data-name=
"LuCI.ui.Checkbox#setChangeEvents"><a href=
"LuCI.ui.Checkbox.html#setChangeEvents">setChangeEvents
</a></li>
2921 <li data-name=
"LuCI.ui.Checkbox#setPlaceholder"><a href=
"LuCI.ui.Checkbox.html#setPlaceholder">setPlaceholder
</a></li>
2923 <li data-name=
"LuCI.ui.Checkbox#setUpdateEvents"><a href=
"LuCI.ui.Checkbox.html#setUpdateEvents">setUpdateEvents
</a></li>
2925 <li data-name=
"LuCI.ui.Checkbox#setValue"><a href=
"LuCI.ui.Checkbox.html#setValue">setValue
</a></li>
2927 <li data-name=
"LuCI.ui.Checkbox#triggerValidation"><a href=
"LuCI.ui.Checkbox.html#triggerValidation">triggerValidation
</a></li>
2930 <ul class=
"events itemMembers">
2935 <li class=
"item" data-name=
"LuCI.ui.Combobox">
2936 <span class=
"title">
2937 <a href=
"LuCI.ui.Combobox.html">LuCI.ui.Combobox
</a>
2940 <ul class=
"members itemMembers">
2943 <ul class=
"typedefs itemMembers">
2945 <span class=
"subtitle">Typedefs
</span>
2947 <li data-name=
"LuCI.ui.Combobox.InitOptions"><a href=
"LuCI.ui.Combobox.html#.InitOptions">InitOptions
</a></li>
2950 <ul class=
"typedefs itemMembers">
2953 <ul class=
"methods itemMembers">
2955 <span class=
"subtitle">Methods
</span>
2957 <li data-name=
"LuCI.ui.Combobox#addChoices"><a href=
"LuCI.ui.Combobox.html#addChoices">addChoices
</a></li>
2959 <li data-name=
"LuCI.ui.Combobox#clearChoices"><a href=
"LuCI.ui.Combobox.html#clearChoices">clearChoices
</a></li>
2961 <li data-name=
"LuCI.ui.Combobox#closeAllDropdowns"><a href=
"LuCI.ui.Combobox.html#closeAllDropdowns">closeAllDropdowns
</a></li>
2963 <li data-name=
"LuCI.ui.Combobox#getValidationError"><a href=
"LuCI.ui.Combobox.html#getValidationError">getValidationError
</a></li>
2965 <li data-name=
"LuCI.ui.Combobox#isChanged"><a href=
"LuCI.ui.Combobox.html#isChanged">isChanged
</a></li>
2967 <li data-name=
"LuCI.ui.Combobox#isValid"><a href=
"LuCI.ui.Combobox.html#isValid">isValid
</a></li>
2969 <li data-name=
"LuCI.ui.Combobox#registerEvents"><a href=
"LuCI.ui.Combobox.html#registerEvents">registerEvents
</a></li>
2971 <li data-name=
"LuCI.ui.Combobox#setChangeEvents"><a href=
"LuCI.ui.Combobox.html#setChangeEvents">setChangeEvents
</a></li>
2973 <li data-name=
"LuCI.ui.Combobox#setPlaceholder"><a href=
"LuCI.ui.Combobox.html#setPlaceholder">setPlaceholder
</a></li>
2975 <li data-name=
"LuCI.ui.Combobox#setUpdateEvents"><a href=
"LuCI.ui.Combobox.html#setUpdateEvents">setUpdateEvents
</a></li>
2977 <li data-name=
"LuCI.ui.Combobox#triggerValidation"><a href=
"LuCI.ui.Combobox.html#triggerValidation">triggerValidation
</a></li>
2980 <ul class=
"events itemMembers">
2985 <li class=
"item" data-name=
"LuCI.ui.ComboButton">
2986 <span class=
"title">
2987 <a href=
"LuCI.ui.ComboButton.html">LuCI.ui.ComboButton
</a>
2990 <ul class=
"members itemMembers">
2993 <ul class=
"typedefs itemMembers">
2995 <span class=
"subtitle">Typedefs
</span>
2997 <li data-name=
"LuCI.ui.ComboButton.InitOptions"><a href=
"LuCI.ui.ComboButton.html#.InitOptions">InitOptions
</a></li>
3000 <ul class=
"typedefs itemMembers">
3003 <ul class=
"methods itemMembers">
3005 <span class=
"subtitle">Methods
</span>
3007 <li data-name=
"LuCI.ui.ComboButton#addChoices"><a href=
"LuCI.ui.ComboButton.html#addChoices">addChoices
</a></li>
3009 <li data-name=
"LuCI.ui.ComboButton#clearChoices"><a href=
"LuCI.ui.ComboButton.html#clearChoices">clearChoices
</a></li>
3011 <li data-name=
"LuCI.ui.ComboButton#closeAllDropdowns"><a href=
"LuCI.ui.ComboButton.html#closeAllDropdowns">closeAllDropdowns
</a></li>
3013 <li data-name=
"LuCI.ui.ComboButton#getValidationError"><a href=
"LuCI.ui.ComboButton.html#getValidationError">getValidationError
</a></li>
3015 <li data-name=
"LuCI.ui.ComboButton#isChanged"><a href=
"LuCI.ui.ComboButton.html#isChanged">isChanged
</a></li>
3017 <li data-name=
"LuCI.ui.ComboButton#isValid"><a href=
"LuCI.ui.ComboButton.html#isValid">isValid
</a></li>
3019 <li data-name=
"LuCI.ui.ComboButton#registerEvents"><a href=
"LuCI.ui.ComboButton.html#registerEvents">registerEvents
</a></li>
3021 <li data-name=
"LuCI.ui.ComboButton#setChangeEvents"><a href=
"LuCI.ui.ComboButton.html#setChangeEvents">setChangeEvents
</a></li>
3023 <li data-name=
"LuCI.ui.ComboButton#setPlaceholder"><a href=
"LuCI.ui.ComboButton.html#setPlaceholder">setPlaceholder
</a></li>
3025 <li data-name=
"LuCI.ui.ComboButton#setUpdateEvents"><a href=
"LuCI.ui.ComboButton.html#setUpdateEvents">setUpdateEvents
</a></li>
3027 <li data-name=
"LuCI.ui.ComboButton#triggerValidation"><a href=
"LuCI.ui.ComboButton.html#triggerValidation">triggerValidation
</a></li>
3030 <ul class=
"events itemMembers">
3035 <li class=
"item" data-name=
"LuCI.ui.Dropdown">
3036 <span class=
"title">
3037 <a href=
"LuCI.ui.Dropdown.html">LuCI.ui.Dropdown
</a>
3040 <ul class=
"members itemMembers">
3043 <ul class=
"typedefs itemMembers">
3045 <span class=
"subtitle">Typedefs
</span>
3047 <li data-name=
"LuCI.ui.Dropdown.InitOptions"><a href=
"LuCI.ui.Dropdown.html#.InitOptions">InitOptions
</a></li>
3050 <ul class=
"typedefs itemMembers">
3053 <ul class=
"methods itemMembers">
3055 <span class=
"subtitle">Methods
</span>
3057 <li data-name=
"LuCI.ui.Dropdown#addChoices"><a href=
"LuCI.ui.Dropdown.html#addChoices">addChoices
</a></li>
3059 <li data-name=
"LuCI.ui.Dropdown#clearChoices"><a href=
"LuCI.ui.Dropdown.html#clearChoices">clearChoices
</a></li>
3061 <li data-name=
"LuCI.ui.Dropdown#closeAllDropdowns"><a href=
"LuCI.ui.Dropdown.html#closeAllDropdowns">closeAllDropdowns
</a></li>
3063 <li data-name=
"LuCI.ui.Dropdown#getValidationError"><a href=
"LuCI.ui.Dropdown.html#getValidationError">getValidationError
</a></li>
3065 <li data-name=
"LuCI.ui.Dropdown#getValue"><a href=
"LuCI.ui.Dropdown.html#getValue">getValue
</a></li>
3067 <li data-name=
"LuCI.ui.Dropdown#isChanged"><a href=
"LuCI.ui.Dropdown.html#isChanged">isChanged
</a></li>
3069 <li data-name=
"LuCI.ui.Dropdown#isValid"><a href=
"LuCI.ui.Dropdown.html#isValid">isValid
</a></li>
3071 <li data-name=
"LuCI.ui.Dropdown#registerEvents"><a href=
"LuCI.ui.Dropdown.html#registerEvents">registerEvents
</a></li>
3073 <li data-name=
"LuCI.ui.Dropdown#render"><a href=
"LuCI.ui.Dropdown.html#render">render
</a></li>
3075 <li data-name=
"LuCI.ui.Dropdown#setChangeEvents"><a href=
"LuCI.ui.Dropdown.html#setChangeEvents">setChangeEvents
</a></li>
3077 <li data-name=
"LuCI.ui.Dropdown#setPlaceholder"><a href=
"LuCI.ui.Dropdown.html#setPlaceholder">setPlaceholder
</a></li>
3079 <li data-name=
"LuCI.ui.Dropdown#setUpdateEvents"><a href=
"LuCI.ui.Dropdown.html#setUpdateEvents">setUpdateEvents
</a></li>
3081 <li data-name=
"LuCI.ui.Dropdown#setValue"><a href=
"LuCI.ui.Dropdown.html#setValue">setValue
</a></li>
3083 <li data-name=
"LuCI.ui.Dropdown#triggerValidation"><a href=
"LuCI.ui.Dropdown.html#triggerValidation">triggerValidation
</a></li>
3086 <ul class=
"events itemMembers">
3091 <li class=
"item" data-name=
"LuCI.ui.DynamicList">
3092 <span class=
"title">
3093 <a href=
"LuCI.ui.DynamicList.html">LuCI.ui.DynamicList
</a>
3096 <ul class=
"members itemMembers">
3099 <ul class=
"typedefs itemMembers">
3101 <span class=
"subtitle">Typedefs
</span>
3103 <li data-name=
"LuCI.ui.DynamicList.InitOptions"><a href=
"LuCI.ui.DynamicList.html#.InitOptions">InitOptions
</a></li>
3106 <ul class=
"typedefs itemMembers">
3109 <ul class=
"methods itemMembers">
3111 <span class=
"subtitle">Methods
</span>
3113 <li data-name=
"LuCI.ui.DynamicList#addChoices"><a href=
"LuCI.ui.DynamicList.html#addChoices">addChoices
</a></li>
3115 <li data-name=
"LuCI.ui.DynamicList#clearChoices"><a href=
"LuCI.ui.DynamicList.html#clearChoices">clearChoices
</a></li>
3117 <li data-name=
"LuCI.ui.DynamicList#getValidationError"><a href=
"LuCI.ui.DynamicList.html#getValidationError">getValidationError
</a></li>
3119 <li data-name=
"LuCI.ui.DynamicList#getValue"><a href=
"LuCI.ui.DynamicList.html#getValue">getValue
</a></li>
3121 <li data-name=
"LuCI.ui.DynamicList#isChanged"><a href=
"LuCI.ui.DynamicList.html#isChanged">isChanged
</a></li>
3123 <li data-name=
"LuCI.ui.DynamicList#isValid"><a href=
"LuCI.ui.DynamicList.html#isValid">isValid
</a></li>
3125 <li data-name=
"LuCI.ui.DynamicList#registerEvents"><a href=
"LuCI.ui.DynamicList.html#registerEvents">registerEvents
</a></li>
3127 <li data-name=
"LuCI.ui.DynamicList#render"><a href=
"LuCI.ui.DynamicList.html#render">render
</a></li>
3129 <li data-name=
"LuCI.ui.DynamicList#setChangeEvents"><a href=
"LuCI.ui.DynamicList.html#setChangeEvents">setChangeEvents
</a></li>
3131 <li data-name=
"LuCI.ui.DynamicList#setPlaceholder"><a href=
"LuCI.ui.DynamicList.html#setPlaceholder">setPlaceholder
</a></li>
3133 <li data-name=
"LuCI.ui.DynamicList#setUpdateEvents"><a href=
"LuCI.ui.DynamicList.html#setUpdateEvents">setUpdateEvents
</a></li>
3135 <li data-name=
"LuCI.ui.DynamicList#setValue"><a href=
"LuCI.ui.DynamicList.html#setValue">setValue
</a></li>
3137 <li data-name=
"LuCI.ui.DynamicList#triggerValidation"><a href=
"LuCI.ui.DynamicList.html#triggerValidation">triggerValidation
</a></li>
3140 <ul class=
"events itemMembers">
3145 <li class=
"item" data-name=
"LuCI.ui.FileUpload">
3146 <span class=
"title">
3147 <a href=
"LuCI.ui.FileUpload.html">LuCI.ui.FileUpload
</a>
3150 <ul class=
"members itemMembers">
3153 <ul class=
"typedefs itemMembers">
3155 <span class=
"subtitle">Typedefs
</span>
3157 <li data-name=
"LuCI.ui.FileUpload.InitOptions"><a href=
"LuCI.ui.FileUpload.html#.InitOptions">InitOptions
</a></li>
3160 <ul class=
"typedefs itemMembers">
3163 <ul class=
"methods itemMembers">
3165 <span class=
"subtitle">Methods
</span>
3167 <li data-name=
"LuCI.ui.FileUpload#getValidationError"><a href=
"LuCI.ui.FileUpload.html#getValidationError">getValidationError
</a></li>
3169 <li data-name=
"LuCI.ui.FileUpload#getValue"><a href=
"LuCI.ui.FileUpload.html#getValue">getValue
</a></li>
3171 <li data-name=
"LuCI.ui.FileUpload#isChanged"><a href=
"LuCI.ui.FileUpload.html#isChanged">isChanged
</a></li>
3173 <li data-name=
"LuCI.ui.FileUpload#isValid"><a href=
"LuCI.ui.FileUpload.html#isValid">isValid
</a></li>
3175 <li data-name=
"LuCI.ui.FileUpload#registerEvents"><a href=
"LuCI.ui.FileUpload.html#registerEvents">registerEvents
</a></li>
3177 <li data-name=
"LuCI.ui.FileUpload#render"><a href=
"LuCI.ui.FileUpload.html#render">render
</a></li>
3179 <li data-name=
"LuCI.ui.FileUpload#setChangeEvents"><a href=
"LuCI.ui.FileUpload.html#setChangeEvents">setChangeEvents
</a></li>
3181 <li data-name=
"LuCI.ui.FileUpload#setPlaceholder"><a href=
"LuCI.ui.FileUpload.html#setPlaceholder">setPlaceholder
</a></li>
3183 <li data-name=
"LuCI.ui.FileUpload#setUpdateEvents"><a href=
"LuCI.ui.FileUpload.html#setUpdateEvents">setUpdateEvents
</a></li>
3185 <li data-name=
"LuCI.ui.FileUpload#setValue"><a href=
"LuCI.ui.FileUpload.html#setValue">setValue
</a></li>
3187 <li data-name=
"LuCI.ui.FileUpload#triggerValidation"><a href=
"LuCI.ui.FileUpload.html#triggerValidation">triggerValidation
</a></li>
3190 <ul class=
"events itemMembers">
3195 <li class=
"item" data-name=
"LuCI.ui.Hiddenfield">
3196 <span class=
"title">
3197 <a href=
"LuCI.ui.Hiddenfield.html">LuCI.ui.Hiddenfield
</a>
3200 <ul class=
"members itemMembers">
3203 <ul class=
"typedefs itemMembers">
3206 <ul class=
"typedefs itemMembers">
3209 <ul class=
"methods itemMembers">
3211 <span class=
"subtitle">Methods
</span>
3213 <li data-name=
"LuCI.ui.Hiddenfield#getValidationError"><a href=
"LuCI.ui.Hiddenfield.html#getValidationError">getValidationError
</a></li>
3215 <li data-name=
"LuCI.ui.Hiddenfield#getValue"><a href=
"LuCI.ui.Hiddenfield.html#getValue">getValue
</a></li>
3217 <li data-name=
"LuCI.ui.Hiddenfield#isChanged"><a href=
"LuCI.ui.Hiddenfield.html#isChanged">isChanged
</a></li>
3219 <li data-name=
"LuCI.ui.Hiddenfield#isValid"><a href=
"LuCI.ui.Hiddenfield.html#isValid">isValid
</a></li>
3221 <li data-name=
"LuCI.ui.Hiddenfield#registerEvents"><a href=
"LuCI.ui.Hiddenfield.html#registerEvents">registerEvents
</a></li>
3223 <li data-name=
"LuCI.ui.Hiddenfield#render"><a href=
"LuCI.ui.Hiddenfield.html#render">render
</a></li>
3225 <li data-name=
"LuCI.ui.Hiddenfield#setChangeEvents"><a href=
"LuCI.ui.Hiddenfield.html#setChangeEvents">setChangeEvents
</a></li>
3227 <li data-name=
"LuCI.ui.Hiddenfield#setPlaceholder"><a href=
"LuCI.ui.Hiddenfield.html#setPlaceholder">setPlaceholder
</a></li>
3229 <li data-name=
"LuCI.ui.Hiddenfield#setUpdateEvents"><a href=
"LuCI.ui.Hiddenfield.html#setUpdateEvents">setUpdateEvents
</a></li>
3231 <li data-name=
"LuCI.ui.Hiddenfield#setValue"><a href=
"LuCI.ui.Hiddenfield.html#setValue">setValue
</a></li>
3233 <li data-name=
"LuCI.ui.Hiddenfield#triggerValidation"><a href=
"LuCI.ui.Hiddenfield.html#triggerValidation">triggerValidation
</a></li>
3236 <ul class=
"events itemMembers">
3241 <li class=
"item" data-name=
"LuCI.ui.menu">
3242 <span class=
"title">
3243 <a href=
"LuCI.ui.menu.html">LuCI.ui.menu
</a>
3246 <ul class=
"members itemMembers">
3249 <ul class=
"typedefs itemMembers">
3251 <span class=
"subtitle">Typedefs
</span>
3253 <li data-name=
"LuCI.ui.menu.MenuNode"><a href=
"LuCI.ui.menu.html#.MenuNode">MenuNode
</a></li>
3256 <ul class=
"typedefs itemMembers">
3259 <ul class=
"methods itemMembers">
3261 <span class=
"subtitle">Methods
</span>
3263 <li data-name=
"LuCI.ui.menu#flushCache"><a href=
"LuCI.ui.menu.html#flushCache">flushCache
</a></li>
3265 <li data-name=
"LuCI.ui.menu#getChildren"><a href=
"LuCI.ui.menu.html#getChildren">getChildren
</a></li>
3267 <li data-name=
"LuCI.ui.menu#load"><a href=
"LuCI.ui.menu.html#load">load
</a></li>
3270 <ul class=
"events itemMembers">
3275 <li class=
"item" data-name=
"LuCI.ui.Select">
3276 <span class=
"title">
3277 <a href=
"LuCI.ui.Select.html">LuCI.ui.Select
</a>
3280 <ul class=
"members itemMembers">
3283 <ul class=
"typedefs itemMembers">
3285 <span class=
"subtitle">Typedefs
</span>
3287 <li data-name=
"LuCI.ui.Select.InitOptions"><a href=
"LuCI.ui.Select.html#.InitOptions">InitOptions
</a></li>
3290 <ul class=
"typedefs itemMembers">
3293 <ul class=
"methods itemMembers">
3295 <span class=
"subtitle">Methods
</span>
3297 <li data-name=
"LuCI.ui.Select#getValidationError"><a href=
"LuCI.ui.Select.html#getValidationError">getValidationError
</a></li>
3299 <li data-name=
"LuCI.ui.Select#getValue"><a href=
"LuCI.ui.Select.html#getValue">getValue
</a></li>
3301 <li data-name=
"LuCI.ui.Select#isChanged"><a href=
"LuCI.ui.Select.html#isChanged">isChanged
</a></li>
3303 <li data-name=
"LuCI.ui.Select#isValid"><a href=
"LuCI.ui.Select.html#isValid">isValid
</a></li>
3305 <li data-name=
"LuCI.ui.Select#registerEvents"><a href=
"LuCI.ui.Select.html#registerEvents">registerEvents
</a></li>
3307 <li data-name=
"LuCI.ui.Select#render"><a href=
"LuCI.ui.Select.html#render">render
</a></li>
3309 <li data-name=
"LuCI.ui.Select#setChangeEvents"><a href=
"LuCI.ui.Select.html#setChangeEvents">setChangeEvents
</a></li>
3311 <li data-name=
"LuCI.ui.Select#setPlaceholder"><a href=
"LuCI.ui.Select.html#setPlaceholder">setPlaceholder
</a></li>
3313 <li data-name=
"LuCI.ui.Select#setUpdateEvents"><a href=
"LuCI.ui.Select.html#setUpdateEvents">setUpdateEvents
</a></li>
3315 <li data-name=
"LuCI.ui.Select#setValue"><a href=
"LuCI.ui.Select.html#setValue">setValue
</a></li>
3317 <li data-name=
"LuCI.ui.Select#triggerValidation"><a href=
"LuCI.ui.Select.html#triggerValidation">triggerValidation
</a></li>
3320 <ul class=
"events itemMembers">
3325 <li class=
"item" data-name=
"LuCI.ui.tabs">
3326 <span class=
"title">
3327 <a href=
"LuCI.ui.tabs.html">LuCI.ui.tabs
</a>
3330 <ul class=
"members itemMembers">
3333 <ul class=
"typedefs itemMembers">
3336 <ul class=
"typedefs itemMembers">
3339 <ul class=
"methods itemMembers">
3341 <span class=
"subtitle">Methods
</span>
3343 <li data-name=
"LuCI.ui.tabs#initTabGroup"><a href=
"LuCI.ui.tabs.html#initTabGroup">initTabGroup
</a></li>
3345 <li data-name=
"LuCI.ui.tabs#isEmptyPane"><a href=
"LuCI.ui.tabs.html#isEmptyPane">isEmptyPane
</a></li>
3348 <ul class=
"events itemMembers">
3353 <li class=
"item" data-name=
"LuCI.ui.Textarea">
3354 <span class=
"title">
3355 <a href=
"LuCI.ui.Textarea.html">LuCI.ui.Textarea
</a>
3358 <ul class=
"members itemMembers">
3361 <ul class=
"typedefs itemMembers">
3363 <span class=
"subtitle">Typedefs
</span>
3365 <li data-name=
"LuCI.ui.Textarea.InitOptions"><a href=
"LuCI.ui.Textarea.html#.InitOptions">InitOptions
</a></li>
3368 <ul class=
"typedefs itemMembers">
3371 <ul class=
"methods itemMembers">
3373 <span class=
"subtitle">Methods
</span>
3375 <li data-name=
"LuCI.ui.Textarea#getValidationError"><a href=
"LuCI.ui.Textarea.html#getValidationError">getValidationError
</a></li>
3377 <li data-name=
"LuCI.ui.Textarea#getValue"><a href=
"LuCI.ui.Textarea.html#getValue">getValue
</a></li>
3379 <li data-name=
"LuCI.ui.Textarea#isChanged"><a href=
"LuCI.ui.Textarea.html#isChanged">isChanged
</a></li>
3381 <li data-name=
"LuCI.ui.Textarea#isValid"><a href=
"LuCI.ui.Textarea.html#isValid">isValid
</a></li>
3383 <li data-name=
"LuCI.ui.Textarea#registerEvents"><a href=
"LuCI.ui.Textarea.html#registerEvents">registerEvents
</a></li>
3385 <li data-name=
"LuCI.ui.Textarea#render"><a href=
"LuCI.ui.Textarea.html#render">render
</a></li>
3387 <li data-name=
"LuCI.ui.Textarea#setChangeEvents"><a href=
"LuCI.ui.Textarea.html#setChangeEvents">setChangeEvents
</a></li>
3389 <li data-name=
"LuCI.ui.Textarea#setPlaceholder"><a href=
"LuCI.ui.Textarea.html#setPlaceholder">setPlaceholder
</a></li>
3391 <li data-name=
"LuCI.ui.Textarea#setUpdateEvents"><a href=
"LuCI.ui.Textarea.html#setUpdateEvents">setUpdateEvents
</a></li>
3393 <li data-name=
"LuCI.ui.Textarea#setValue"><a href=
"LuCI.ui.Textarea.html#setValue">setValue
</a></li>
3395 <li data-name=
"LuCI.ui.Textarea#triggerValidation"><a href=
"LuCI.ui.Textarea.html#triggerValidation">triggerValidation
</a></li>
3398 <ul class=
"events itemMembers">
3403 <li class=
"item" data-name=
"LuCI.ui.Textfield">
3404 <span class=
"title">
3405 <a href=
"LuCI.ui.Textfield.html">LuCI.ui.Textfield
</a>
3408 <ul class=
"members itemMembers">
3411 <ul class=
"typedefs itemMembers">
3413 <span class=
"subtitle">Typedefs
</span>
3415 <li data-name=
"LuCI.ui.Textfield.InitOptions"><a href=
"LuCI.ui.Textfield.html#.InitOptions">InitOptions
</a></li>
3418 <ul class=
"typedefs itemMembers">
3421 <ul class=
"methods itemMembers">
3423 <span class=
"subtitle">Methods
</span>
3425 <li data-name=
"LuCI.ui.Textfield#getValidationError"><a href=
"LuCI.ui.Textfield.html#getValidationError">getValidationError
</a></li>
3427 <li data-name=
"LuCI.ui.Textfield#getValue"><a href=
"LuCI.ui.Textfield.html#getValue">getValue
</a></li>
3429 <li data-name=
"LuCI.ui.Textfield#isChanged"><a href=
"LuCI.ui.Textfield.html#isChanged">isChanged
</a></li>
3431 <li data-name=
"LuCI.ui.Textfield#isValid"><a href=
"LuCI.ui.Textfield.html#isValid">isValid
</a></li>
3433 <li data-name=
"LuCI.ui.Textfield#registerEvents"><a href=
"LuCI.ui.Textfield.html#registerEvents">registerEvents
</a></li>
3435 <li data-name=
"LuCI.ui.Textfield#render"><a href=
"LuCI.ui.Textfield.html#render">render
</a></li>
3437 <li data-name=
"LuCI.ui.Textfield#setChangeEvents"><a href=
"LuCI.ui.Textfield.html#setChangeEvents">setChangeEvents
</a></li>
3439 <li data-name=
"LuCI.ui.Textfield#setPlaceholder"><a href=
"LuCI.ui.Textfield.html#setPlaceholder">setPlaceholder
</a></li>
3441 <li data-name=
"LuCI.ui.Textfield#setUpdateEvents"><a href=
"LuCI.ui.Textfield.html#setUpdateEvents">setUpdateEvents
</a></li>
3443 <li data-name=
"LuCI.ui.Textfield#setValue"><a href=
"LuCI.ui.Textfield.html#setValue">setValue
</a></li>
3445 <li data-name=
"LuCI.ui.Textfield#triggerValidation"><a href=
"LuCI.ui.Textfield.html#triggerValidation">triggerValidation
</a></li>
3448 <ul class=
"events itemMembers">
3453 <li class=
"item" data-name=
"LuCI.view">
3454 <span class=
"title">
3455 <a href=
"LuCI.view.html">LuCI.view
</a>
3458 <ul class=
"members itemMembers">
3461 <ul class=
"typedefs itemMembers">
3464 <ul class=
"typedefs itemMembers">
3467 <ul class=
"methods itemMembers">
3469 <span class=
"subtitle">Methods
</span>
3471 <li data-name=
"LuCI.view#addFooter"><a href=
"LuCI.view.html#addFooter">addFooter
</a></li>
3473 <li data-name=
"LuCI.view#handleReset"><a href=
"LuCI.view.html#handleReset">handleReset
</a></li>
3475 <li data-name=
"LuCI.view#handleSave"><a href=
"LuCI.view.html#handleSave">handleSave
</a></li>
3477 <li data-name=
"LuCI.view#handleSaveApply"><a href=
"LuCI.view.html#handleSaveApply">handleSaveApply
</a></li>
3479 <li data-name=
"LuCI.view#load"><a href=
"LuCI.view.html#load">load
</a></li>
3481 <li data-name=
"LuCI.view#render"><a href=
"LuCI.view.html#render">render
</a></li>
3484 <ul class=
"events itemMembers">
3489 <li class=
"item" data-name=
"LuCI.xhr">
3490 <span class=
"title">
3491 <a href=
"LuCI.xhr.html">LuCI.xhr
</a>
3494 <ul class=
"members itemMembers">
3497 <ul class=
"typedefs itemMembers">
3500 <ul class=
"typedefs itemMembers">
3503 <ul class=
"methods itemMembers">
3505 <span class=
"subtitle">Methods
</span>
3507 <li data-name=
"LuCI.xhr#abort"><a href=
"LuCI.xhr.html#abort">abort
</a></li>
3509 <li data-name=
"LuCI.xhr#busy"><a href=
"LuCI.xhr.html#busy">busy
</a></li>
3511 <li data-name=
"LuCI.xhr#cancel"><a href=
"LuCI.xhr.html#cancel">cancel
</a></li>
3513 <li data-name=
"LuCI.xhr#get"><a href=
"LuCI.xhr.html#get">get
</a></li>
3515 <li data-name=
"LuCI.xhr#post"><a href=
"LuCI.xhr.html#post">post
</a></li>
3517 <li data-name=
"LuCI.xhr#send_form"><a href=
"LuCI.xhr.html#send_form">send_form
</a></li>
3520 <ul class=
"events itemMembers">
3528 <h1 class=
"page-title" data-filename=
"ui.js.html">Source: ui.js
</h1>
3535 <pre id=
"source-code" class=
"prettyprint source "><code>'use strict';
3536 'require validation';
3537 'require baseclass';
3546 var modalDiv = null,
3548 indicatorDiv = null,
3549 tooltipTimeout = null;
3552 * @class AbstractElement
3557 * The `AbstractElement` class serves as abstract base for the different widgets
3558 * implemented by `LuCI.ui`. It provides the common logic for getting and
3559 * setting values, for checking the validity state and for wiring up required
3562 * UI widget instances are usually not supposed to be created by view code
3563 * directly, instead they're implicitly created by `LuCI.form` when
3564 * instantiating CBI forms.
3566 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3567 * in views, use `'require ui'` and refer to `ui.AbstractElement`. To import
3568 * it in external JavaScript, use `L.require(
"ui").then(...)` and access the
3569 * `AbstractElement` property of the class instance value.
3571 var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ {
3573 * @typedef {Object} InitOptions
3574 * @memberof LuCI.ui.AbstractElement
3576 * @property {string} [id]
3577 * Specifies the widget ID to use. It will be used as HTML `id` attribute
3578 * on the toplevel widget DOM node.
3580 * @property {string} [name]
3581 * Specifies the widget name which is set as HTML `name` attribute on the
3582 * corresponding `
<input
>` element.
3584 * @property {boolean} [optional=true]
3585 * Specifies whether the input field allows empty values.
3587 * @property {string} [datatype=string]
3588 * An expression describing the input data validation constraints.
3589 * It defaults to `string` which will allow any value.
3590 * See {@link LuCI.validation} for details on the expression format.
3592 * @property {function} [validator]
3593 * Specifies a custom validator function which is invoked after the
3594 * standard validation constraints are checked. The function should return
3595 * `true` to accept the given input value. Any other return value type is
3596 * converted to a string and treated as validation error message.
3598 * @property {boolean} [disabled=false]
3599 * Specifies whether the widget should be rendered in disabled state
3600 * (`true`) or not (`false`). Disabled widgets cannot be interacted with
3601 * and are displayed in a slightly faded style.
3605 * Read the current value of the input widget.
3608 * @memberof LuCI.ui.AbstractElement
3609 * @returns {string|string[]|null}
3610 * The current value of the input element. For simple inputs like text
3611 * fields or selects, the return value type will be a - possibly empty -
3612 * string. Complex widgets such as `DynamicList` instances may result in
3613 * an array of strings or `null` for unset values.
3615 getValue: function() {
3616 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3617 return this.node.value;
3623 * Set the current value of the input widget.
3626 * @memberof LuCI.ui.AbstractElement
3627 * @param {string|string[]|null} value
3628 * The value to set the input element to. For simple inputs like text
3629 * fields or selects, the value should be a - possibly empty - string.
3630 * Complex widgets such as `DynamicList` instances may accept string array
3633 setValue: function(value) {
3634 if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
3635 this.node.value = value;
3639 * Set the current placeholder value of the input widget.
3642 * @memberof LuCI.ui.AbstractElement
3643 * @param {string|string[]|null} value
3644 * The placeholder to set for the input element. Only applicable to text
3645 * inputs, not to radio buttons, selects or similar.
3647 setPlaceholder: function(value) {
3648 var node = this.node ? this.node.querySelector('input,textarea') : null;
3650 switch (node.getAttribute('type') || 'text') {
3656 if (value != null
&& value != '')
3657 node.setAttribute('placeholder', value);
3659 node.removeAttribute('placeholder');
3665 * Check whether the input value was altered by the user.
3668 * @memberof LuCI.ui.AbstractElement
3669 * @returns {boolean}
3670 * Returns `true` if the input value has been altered by the user or
3671 * `false` if it is unchanged. Note that if the user modifies the initial
3672 * value and changes it back to the original state, it is still reported
3675 isChanged: function() {
3676 return (this.node ? this.node.getAttribute('data-changed') : null) == 'true';
3680 * Check whether the current input value is valid.
3683 * @memberof LuCI.ui.AbstractElement
3684 * @returns {boolean}
3685 * Returns `true` if the current input value is valid or `false` if it does
3686 * not meet the validation constraints.
3688 isValid: function() {
3689 return (this.validState !== false);
3693 * Returns the current validation error
3696 * @memberof LuCI.ui.AbstractElement
3698 * The validation error at this time
3700 getValidationError: function() {
3701 return this.validationError || '';
3705 * Force validation of the current input value.
3707 * Usually input validation is automatically triggered by various DOM events
3708 * bound to the input widget. In some cases it is required though to manually
3709 * trigger validation runs, e.g. when programmatically altering values.
3712 * @memberof LuCI.ui.AbstractElement
3714 triggerValidation: function() {
3715 if (typeof(this.vfunc) != 'function')
3718 var wasValid = this.isValid();
3722 return (wasValid != this.isValid());
3726 * Dispatch a custom (synthetic) event in response to received events.
3728 * Sets up event handlers on the given target DOM node for the given event
3729 * names that dispatch a custom event of the given type to the widget root
3732 * The primary purpose of this function is to set up a series of custom
3733 * uniform standard events such as `widget-update`, `validation-success`,
3734 * `validation-failure` etc. which are triggered by various different
3735 * widget specific native DOM events.
3738 * @memberof LuCI.ui.AbstractElement
3739 * @param {Node} targetNode
3740 * Specifies the DOM node on which the native event listeners should be
3743 * @param {string} synevent
3744 * The name of the custom event to dispatch to the widget root DOM node.
3746 * @param {string[]} events
3747 * The native DOM events for which event handlers should be registered.
3749 registerEvents: function(targetNode, synevent, events) {
3750 var dispatchFn = L.bind(function(ev) {
3751 this.node.dispatchEvent(new CustomEvent(synevent, { bubbles: true }));
3754 for (var i =
0; i
< events.length; i++)
3755 targetNode.addEventListener(events[i], dispatchFn);
3759 * Setup listeners for native DOM events that may update the widget value.
3761 * Sets up event handlers on the given target DOM node for the given event
3762 * names which may cause the input value to update, such as `keyup` or
3763 * `onclick` events. In contrast to change events, such update events will
3764 * trigger input value validation.
3767 * @memberof LuCI.ui.AbstractElement
3768 * @param {Node} targetNode
3769 * Specifies the DOM node on which the event listeners should be registered.
3771 * @param {...string} events
3772 * The DOM events for which event handlers should be registered.
3774 setUpdateEvents: function(targetNode /*, ... */) {
3775 var datatype = this.options.datatype,
3776 optional = this.options.hasOwnProperty('optional') ? this.options.optional : true,
3777 validate = this.options.validate,
3778 events = this.varargs(arguments,
1);
3780 this.registerEvents(targetNode, 'widget-update', events);
3782 if (!datatype
&& !validate)
3785 this.vfunc = UI.prototype.addValidator.apply(UI.prototype, [
3786 targetNode, datatype || 'string',
3790 this.node.addEventListener('validation-success', L.bind(function(ev) {
3791 this.validState = true;
3792 this.validationError = '';
3795 this.node.addEventListener('validation-failure', L.bind(function(ev) {
3796 this.validState = false;
3797 this.validationError = ev.detail.message;
3802 * Setup listeners for native DOM events that may change the widget value.
3804 * Sets up event handlers on the given target DOM node for the given event
3805 * names which may cause the input value to change completely, such as
3806 * `change` events in a select menu. In contrast to update events, such
3807 * change events will not trigger input value validation but they may cause
3808 * field dependencies to get re-evaluated and will mark the input widget
3812 * @memberof LuCI.ui.AbstractElement
3813 * @param {Node} targetNode
3814 * Specifies the DOM node on which the event listeners should be registered.
3816 * @param {...string} events
3817 * The DOM events for which event handlers should be registered.
3819 setChangeEvents: function(targetNode /*, ... */) {
3820 var tag_changed = L.bind(function(ev) { this.setAttribute('data-changed', true) }, this.node);
3822 for (var i =
1; i
< arguments.length; i++)
3823 targetNode.addEventListener(arguments[i], tag_changed);
3825 this.registerEvents(targetNode, 'widget-change', this.varargs(arguments,
1));
3829 * Render the widget, setup event listeners and return resulting markup.
3832 * @memberof LuCI.ui.AbstractElement
3835 * Returns a DOM Node or DocumentFragment containing the rendered
3838 render: function() {}
3842 * Instantiate a text input widget.
3844 * @constructor Textfield
3846 * @augments LuCI.ui.AbstractElement
3850 * The `Textfield` class implements a standard single line text input field.
3852 * UI widget instances are usually not supposed to be created by view code
3853 * directly, instead they're implicitly created by `LuCI.form` when
3854 * instantiating CBI forms.
3856 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3857 * in views, use `'require ui'` and refer to `ui.Textfield`. To import it in
3858 * external JavaScript, use `L.require(
"ui").then(...)` and access the
3859 * `Textfield` property of the class instance value.
3861 * @param {string} [value=null]
3862 * The initial input value.
3864 * @param {LuCI.ui.Textfield.InitOptions} [options]
3865 * Object describing the widget specific options to initialize the input.
3867 var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ {
3869 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3870 * the following properties are recognized:
3872 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3873 * @memberof LuCI.ui.Textfield
3875 * @property {boolean} [password=false]
3876 * Specifies whether the input should be rendered as concealed password field.
3878 * @property {boolean} [readonly=false]
3879 * Specifies whether the input widget should be rendered readonly.
3881 * @property {number} [maxlength]
3882 * Specifies the HTML `maxlength` attribute to set on the corresponding
3883 * `
<input
>` element. Note that this a legacy property that exists for
3884 * compatibility reasons. It is usually better to `maxlength(N)` validation
3887 * @property {string} [placeholder]
3888 * Specifies the HTML `placeholder` attribute which is displayed when the
3889 * corresponding `
<input
>` element is empty.
3891 __init__: function(value, options) {
3893 this.options = Object.assign({
3900 render: function() {
3901 var frameEl = E('div', { 'id': this.options.id });
3902 var inputEl = E('input', {
3903 'id': this.options.id ? 'widget.' + this.options.id : null,
3904 'name': this.options.name,
3906 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text',
3907 'readonly': this.options.readonly ? '' : null,
3908 'disabled': this.options.disabled ? '' : null,
3909 'maxlength': this.options.maxlength,
3910 'placeholder': this.options.placeholder,
3911 'autocomplete': this.options.password ? 'new-password' : null,
3912 'value': this.value,
3915 if (this.options.password) {
3916 frameEl.appendChild(E('div', { 'class': 'control-group' }, [
3919 'class': 'cbi-button cbi-button-neutral',
3920 'title': _('Reveal/hide password'),
3921 'aria-label': _('Reveal/hide password'),
3922 'click': function(ev) {
3923 var e = this.previousElementSibling;
3924 e.type = (e.type === 'password') ? 'text' : 'password';
3925 ev.preventDefault();
3930 window.requestAnimationFrame(function() { inputEl.type = 'password' });
3933 frameEl.appendChild(inputEl);
3936 return this.bind(frameEl);
3940 bind: function(frameEl) {
3941 var inputEl = frameEl.querySelector('input');
3943 this.node = frameEl;
3945 this.setUpdateEvents(inputEl, 'keyup', 'blur');
3946 this.setChangeEvents(inputEl, 'change');
3948 dom.bindClassInstance(frameEl, this);
3954 getValue: function() {
3955 var inputEl = this.node.querySelector('input');
3956 return inputEl.value;
3960 setValue: function(value) {
3961 var inputEl = this.node.querySelector('input');
3962 inputEl.value = value;
3967 * Instantiate a textarea widget.
3969 * @constructor Textarea
3971 * @augments LuCI.ui.AbstractElement
3975 * The `Textarea` class implements a multiline text area input field.
3977 * UI widget instances are usually not supposed to be created by view code
3978 * directly, instead they're implicitly created by `LuCI.form` when
3979 * instantiating CBI forms.
3981 * This class is automatically instantiated as part of `LuCI.ui`. To use it
3982 * in views, use `'require ui'` and refer to `ui.Textarea`. To import it in
3983 * external JavaScript, use `L.require(
"ui").then(...)` and access the
3984 * `Textarea` property of the class instance value.
3986 * @param {string} [value=null]
3987 * The initial input value.
3989 * @param {LuCI.ui.Textarea.InitOptions} [options]
3990 * Object describing the widget specific options to initialize the input.
3992 var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ {
3994 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
3995 * the following properties are recognized:
3997 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
3998 * @memberof LuCI.ui.Textarea
4000 * @property {boolean} [readonly=false]
4001 * Specifies whether the input widget should be rendered readonly.
4003 * @property {string} [placeholder]
4004 * Specifies the HTML `placeholder` attribute which is displayed when the
4005 * corresponding `
<textarea
>` element is empty.
4007 * @property {boolean} [monospace=false]
4008 * Specifies whether a monospace font should be forced for the textarea
4011 * @property {number} [cols]
4012 * Specifies the HTML `cols` attribute to set on the corresponding
4013 * `
<textarea
>` element.
4015 * @property {number} [rows]
4016 * Specifies the HTML `rows` attribute to set on the corresponding
4017 * `
<textarea
>` element.
4019 * @property {boolean} [wrap=false]
4020 * Specifies whether the HTML `wrap` attribute should be set.
4022 __init__: function(value, options) {
4024 this.options = Object.assign({
4033 render: function() {
4034 var style = !this.options.cols ? 'width:
100%' : null,
4035 frameEl = E('div', { 'id': this.options.id, 'style': style }),
4036 value = (this.value != null) ? String(this.value) : '';
4038 frameEl.appendChild(E('textarea', {
4039 'id': this.options.id ? 'widget.' + this.options.id : null,
4040 'name': this.options.name,
4041 'class': 'cbi-input-textarea',
4042 'readonly': this.options.readonly ? '' : null,
4043 'disabled': this.options.disabled ? '' : null,
4044 'placeholder': this.options.placeholder,
4046 'cols': this.options.cols,
4047 'rows': this.options.rows,
4048 'wrap': this.options.wrap ? '' : null
4051 if (this.options.monospace)
4052 frameEl.firstElementChild.style.fontFamily = 'monospace';
4054 return this.bind(frameEl);
4058 bind: function(frameEl) {
4059 var inputEl = frameEl.firstElementChild;
4061 this.node = frameEl;
4063 this.setUpdateEvents(inputEl, 'keyup', 'blur');
4064 this.setChangeEvents(inputEl, 'change');
4066 dom.bindClassInstance(frameEl, this);
4072 getValue: function() {
4073 return this.node.firstElementChild.value;
4077 setValue: function(value) {
4078 this.node.firstElementChild.value = value;
4083 * Instantiate a checkbox widget.
4085 * @constructor Checkbox
4087 * @augments LuCI.ui.AbstractElement
4091 * The `Checkbox` class implements a simple checkbox input field.
4093 * UI widget instances are usually not supposed to be created by view code
4094 * directly, instead they're implicitly created by `LuCI.form` when
4095 * instantiating CBI forms.
4097 * This class is automatically instantiated as part of `LuCI.ui`. To use it
4098 * in views, use `'require ui'` and refer to `ui.Checkbox`. To import it in
4099 * external JavaScript, use `L.require(
"ui").then(...)` and access the
4100 * `Checkbox` property of the class instance value.
4102 * @param {string} [value=null]
4103 * The initial input value.
4105 * @param {LuCI.ui.Checkbox.InitOptions} [options]
4106 * Object describing the widget specific options to initialize the input.
4108 var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ {
4110 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
4111 * the following properties are recognized:
4113 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4114 * @memberof LuCI.ui.Checkbox
4116 * @property {string} [value_enabled=
1]
4117 * Specifies the value corresponding to a checked checkbox.
4119 * @property {string} [value_disabled=
0]
4120 * Specifies the value corresponding to an unchecked checkbox.
4122 * @property {string} [hiddenname]
4123 * Specifies the HTML `name` attribute of the hidden input backing the
4124 * checkbox. This is a legacy property existing for compatibility reasons,
4125 * it is required for HTML based form submissions.
4127 __init__: function(value, options) {
4129 this.options = Object.assign({
4136 render: function() {
4137 var id = 'cb%
08x'.format(Math.random() *
0xffffffff);
4138 var frameEl = E('div', {
4139 'id': this.options.id,
4140 'class': 'cbi-checkbox'
4143 if (this.options.hiddenname)
4144 frameEl.appendChild(E('input', {
4146 'name': this.options.hiddenname,
4150 frameEl.appendChild(E('input', {
4152 'name': this.options.name,
4154 'value': this.options.value_enabled,
4155 'checked': (this.value == this.options.value_enabled) ? '' : null,
4156 'disabled': this.options.disabled ? '' : null,
4157 'data-widget-id': this.options.id ? 'widget.' + this.options.id : null
4160 frameEl.appendChild(E('label', { 'for': id }));
4162 if (this.options.tooltip != null) {
4165 if (this.options.tooltipicon != null)
4166 icon = this.options.tooltipicon;
4168 frameEl.appendChild(
4169 E('label', { 'class': 'cbi-tooltip-container' },[
4171 E('div', { 'class': 'cbi-tooltip' },
4172 this.options.tooltip
4178 return this.bind(frameEl);
4182 bind: function(frameEl) {
4183 this.node = frameEl;
4185 var input = frameEl.querySelector('input[
type=
"checkbox"]');
4186 this.setUpdateEvents(input, 'click', 'blur');
4187 this.setChangeEvents(input, 'change');
4189 dom.bindClassInstance(frameEl, this);
4195 * Test whether the checkbox is currently checked.
4198 * @memberof LuCI.ui.Checkbox
4199 * @returns {boolean}
4200 * Returns `true` when the checkbox is currently checked, otherwise `false`.
4202 isChecked: function() {
4203 return this.node.querySelector('input[
type=
"checkbox"]').checked;
4207 getValue: function() {
4208 return this.isChecked()
4209 ? this.options.value_enabled
4210 : this.options.value_disabled;
4214 setValue: function(value) {
4215 this.node.querySelector('input[
type=
"checkbox"]').checked = (value == this.options.value_enabled);
4220 * Instantiate a select dropdown or checkbox/radiobutton group.
4222 * @constructor Select
4224 * @augments LuCI.ui.AbstractElement
4228 * The `Select` class implements either a traditional HTML `
<select
>` element
4229 * or a group of checkboxes or radio buttons, depending on whether multiple
4230 * values are enabled or not.
4232 * UI widget instances are usually not supposed to be created by view code
4233 * directly, instead they're implicitly created by `LuCI.form` when
4234 * instantiating CBI forms.
4236 * This class is automatically instantiated as part of `LuCI.ui`. To use it
4237 * in views, use `'require ui'` and refer to `ui.Select`. To import it in
4238 * external JavaScript, use `L.require(
"ui").then(...)` and access the
4239 * `Select` property of the class instance value.
4241 * @param {string|string[]} [value=null]
4242 * The initial input value(s).
4244 * @param {Object
<string, string
>} choices
4245 * Object containing the selectable choices of the widget. The object keys
4246 * serve as values for the different choices while the values are used as
4249 * @param {LuCI.ui.Select.InitOptions} [options]
4250 * Object describing the widget specific options to initialize the inputs.
4252 var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ {
4254 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
4255 * the following properties are recognized:
4257 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4258 * @memberof LuCI.ui.Select
4260 * @property {boolean} [multiple=false]
4261 * Specifies whether multiple choice values may be selected.
4263 * @property {
"select"|
"individual"} [widget=select]
4264 * Specifies the kind of widget to render. May be either `select` or
4265 * `individual`. When set to `select` an HTML `
<select
>` element will be
4266 * used, otherwise a group of checkbox or radio button elements is created,
4267 * depending on the value of the `multiple` option.
4269 * @property {string} [orientation=horizontal]
4270 * Specifies whether checkbox / radio button groups should be rendered
4271 * in a `horizontal` or `vertical` manner. Does not apply to the `select`
4274 * @property {boolean|string[]} [sort=false]
4275 * Specifies if and how to sort choice values. If set to `true`, the choice
4276 * values will be sorted alphabetically. If set to an array of strings, the
4277 * choice sort order is derived from the array.
4279 * @property {number} [size]
4280 * Specifies the HTML `size` attribute to set on the `
<select
>` element.
4281 * Only applicable to the `select` widget type.
4283 * @property {string} [placeholder=-- Please choose --]
4284 * Specifies a placeholder text which is displayed when no choice is
4285 * selected yet. Only applicable to the `select` widget type.
4287 __init__: function(value, choices, options) {
4288 if (!L.isObject(choices))
4291 if (!Array.isArray(value))
4292 value = (value != null
&& value != '') ? [ value ] : [];
4294 if (!options.multiple
&& value.length
> 1)
4297 this.values = value;
4298 this.choices = choices;
4299 this.options = Object.assign({
4302 orientation: 'horizontal'
4305 if (this.choices.hasOwnProperty(''))
4306 this.options.optional = true;
4310 render: function() {
4311 var frameEl = E('div', { 'id': this.options.id }),
4312 keys = Object.keys(this.choices);
4314 if (this.options.sort === true)
4315 keys.sort(L.naturalCompare);
4316 else if (Array.isArray(this.options.sort))
4317 keys = this.options.sort;
4319 if (this.options.widget != 'radio'
&& this.options.widget != 'checkbox') {
4320 frameEl.appendChild(E('select', {
4321 'id': this.options.id ? 'widget.' + this.options.id : null,
4322 'name': this.options.name,
4323 'size': this.options.size,
4324 'class': 'cbi-input-select',
4325 'multiple': this.options.multiple ? '' : null,
4326 'disabled': this.options.disabled ? '' : null
4329 if (this.options.optional)
4330 frameEl.lastChild.appendChild(E('option', {
4332 'selected': (this.values.length ==
0 || this.values[
0] == '') ? '' : null
4333 }, [ this.choices[''] || this.options.placeholder || _('-- Please choose --') ]));
4335 for (var i =
0; i
< keys.length; i++) {
4336 if (keys[i] == null || keys[i] == '')
4339 frameEl.lastChild.appendChild(E('option', {
4341 'selected': (this.values.indexOf(keys[i])
> -
1) ? '' : null
4342 }, [ this.choices[keys[i]] || keys[i] ]));
4346 var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' \xa0 ') : E('br');
4348 for (var i =
0; i
< keys.length; i++) {
4349 frameEl.appendChild(E('span', {
4350 'class': 'cbi-%s'.format(this.options.multiple ? 'checkbox' : 'radio')
4353 'id': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null,
4354 'name': this.options.id || this.options.name,
4355 'type': this.options.multiple ? 'checkbox' : 'radio',
4356 'class': this.options.multiple ? 'cbi-input-checkbox' : 'cbi-input-radio',
4358 'checked': (this.values.indexOf(keys[i])
> -
1) ? '' : null,
4359 'disabled': this.options.disabled ? '' : null
4361 E('label', { 'for': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null }),
4363 'click': function(ev) {
4364 ev.currentTarget.previousElementSibling.previousElementSibling.click();
4366 }, [ this.choices[keys[i]] || keys[i] ])
4369 frameEl.appendChild(brEl.cloneNode());
4373 return this.bind(frameEl);
4377 bind: function(frameEl) {
4378 this.node = frameEl;
4380 if (this.options.widget != 'radio'
&& this.options.widget != 'checkbox') {
4381 this.setUpdateEvents(frameEl.firstChild, 'change', 'click', 'blur');
4382 this.setChangeEvents(frameEl.firstChild, 'change');
4385 var radioEls = frameEl.querySelectorAll('input[
type=
"radio"]');
4386 for (var i =
0; i
< radioEls.length; i++) {
4387 this.setUpdateEvents(radioEls[i], 'change', 'click', 'blur');
4388 this.setChangeEvents(radioEls[i], 'change', 'click', 'blur');
4392 dom.bindClassInstance(frameEl, this);
4398 getValue: function() {
4399 if (this.options.widget != 'radio'
&& this.options.widget != 'checkbox')
4400 return this.node.firstChild.value;
4402 var radioEls = this.node.querySelectorAll('input[
type=
"radio"]');
4403 for (var i =
0; i
< radioEls.length; i++)
4404 if (radioEls[i].checked)
4405 return radioEls[i].value;
4411 setValue: function(value) {
4412 if (this.options.widget != 'radio'
&& this.options.widget != 'checkbox') {
4416 for (var i =
0; i
< this.node.firstChild.options.length; i++)
4417 this.node.firstChild.options[i].selected = (this.node.firstChild.options[i].value == value);
4422 var radioEls = frameEl.querySelectorAll('input[
type=
"radio"]');
4423 for (var i =
0; i
< radioEls.length; i++)
4424 radioEls[i].checked = (radioEls[i].value == value);
4429 * Instantiate a rich dropdown choice widget.
4431 * @constructor Dropdown
4433 * @augments LuCI.ui.AbstractElement
4437 * The `Dropdown` class implements a rich, stylable dropdown menu which
4438 * supports non-text choice labels.
4440 * UI widget instances are usually not supposed to be created by view code
4441 * directly, instead they're implicitly created by `LuCI.form` when
4442 * instantiating CBI forms.
4444 * This class is automatically instantiated as part of `LuCI.ui`. To use it
4445 * in views, use `'require ui'` and refer to `ui.Dropdown`. To import it in
4446 * external JavaScript, use `L.require(
"ui").then(...)` and access the
4447 * `Dropdown` property of the class instance value.
4449 * @param {string|string[]} [value=null]
4450 * The initial input value(s).
4452 * @param {Object
<string, *
>} choices
4453 * Object containing the selectable choices of the widget. The object keys
4454 * serve as values for the different choices while the values are used as
4457 * @param {LuCI.ui.Dropdown.InitOptions} [options]
4458 * Object describing the widget specific options to initialize the dropdown.
4460 var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
4462 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
4463 * the following properties are recognized:
4465 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
4466 * @memberof LuCI.ui.Dropdown
4468 * @property {boolean} [optional=true]
4469 * Specifies whether the dropdown selection is optional. In contrast to
4470 * other widgets, the `optional` constraint of dropdowns works differently;
4471 * instead of marking the widget invalid on empty values when set to `false`,
4472 * the user is not allowed to deselect all choices.
4474 * For single value dropdowns that means that no empty
"please select"
4475 * choice is offered and for multi value dropdowns, the last selected choice
4476 * may not be deselected without selecting another choice first.
4478 * @property {boolean} [multiple]
4479 * Specifies whether multiple choice values may be selected. It defaults
4480 * to `true` when an array is passed as input value to the constructor.
4482 * @property {boolean|string[]} [sort=false]
4483 * Specifies if and how to sort choice values. If set to `true`, the choice
4484 * values will be sorted alphabetically. If set to an array of strings, the
4485 * choice sort order is derived from the array.
4487 * @property {string} [select_placeholder=-- Please choose --]
4488 * Specifies a placeholder text which is displayed when no choice is
4491 * @property {string} [custom_placeholder=-- custom --]
4492 * Specifies a placeholder text which is displayed in the text input
4493 * field allowing to enter custom choice values. Only applicable if the
4494 * `create` option is set to `true`.
4496 * @property {boolean} [create=false]
4497 * Specifies whether custom choices may be entered into the dropdown
4500 * @property {string} [create_query=.create-item-input]
4501 * Specifies a CSS selector expression used to find the input element
4502 * which is used to enter custom choice values. This should not normally
4503 * be used except by widgets derived from the Dropdown class.
4505 * @property {string} [create_template=script[
type=
"item-template"]]
4506 * Specifies a CSS selector expression used to find an HTML element
4507 * serving as template for newly added custom choice values.
4509 * Any `{{value}}` placeholder string within the template elements text
4510 * content will be replaced by the user supplied choice value, the
4511 * resulting string is parsed as HTML and appended to the end of the
4512 * choice list. The template markup may specify one HTML element with a
4513 * `data-label-placeholder` attribute which is replaced by a matching
4514 * label value from the `choices` object or with the user supplied value
4515 * itself in case `choices` contains no matching choice label.
4517 * If the template element is not found or if no `create_template` selector
4518 * expression is specified, the default markup for newly created elements is
4519 * `
<li
data-value=
"{{value}}"><span
data-label-placeholder=
"true" /></li
>`.
4521 * @property {string} [create_markup]
4522 * This property allows specifying the markup for custom choices directly
4523 * instead of referring to a template element through CSS selectors.
4525 * Apart from that it works exactly like `create_template`.
4527 * @property {number} [display_items=
3]
4528 * Specifies the maximum amount of choice labels that should be shown in
4529 * collapsed dropdown state before further selected choices are cut off.
4531 * Only applicable when `multiple` is `true`.
4533 * @property {number} [dropdown_items=-
1]
4534 * Specifies the maximum amount of choices that should be shown when the
4535 * dropdown is open. If the amount of available choices exceeds this number,
4536 * the dropdown area must be scrolled to reach further items.
4538 * If set to `-
1`, the dropdown menu will attempt to show all choice values
4539 * and only resort to scrolling if the amount of choices exceeds the available
4540 * screen space above and below the dropdown widget.
4542 * @property {string} [placeholder]
4543 * This property serves as a shortcut to set both `select_placeholder` and
4544 * `custom_placeholder`. Either of these properties will fallback to
4545 * `placeholder` if not specified.
4547 * @property {boolean} [readonly=false]
4548 * Specifies whether the custom choice input field should be rendered
4549 * readonly. Only applicable when `create` is `true`.
4551 * @property {number} [maxlength]
4552 * Specifies the HTML `maxlength` attribute to set on the custom choice
4553 * `
<input
>` element. Note that this a legacy property that exists for
4554 * compatibility reasons. It is usually better to `maxlength(N)` validation
4555 * expression. Only applicable when `create` is `true`.
4557 __init__: function(value, choices, options) {
4558 if (typeof(choices) != 'object')
4561 if (!Array.isArray(value))
4562 this.values = (value != null
&& value != '') ? [ value ] : [];
4564 this.values = value;
4566 this.choices = choices;
4567 this.options = Object.assign({
4569 multiple: Array.isArray(value),
4571 select_placeholder: _('-- Please choose --'),
4572 custom_placeholder: _('-- custom --'),
4576 create_query: '.create-item-input',
4577 create_template: 'script[
type=
"item-template"]'
4582 render: function() {
4584 'id': this.options.id,
4585 'class': 'cbi-dropdown',
4586 'multiple': this.options.multiple ? '' : null,
4587 'optional': this.options.optional ? '' : null,
4588 'disabled': this.options.disabled ? '' : null,
4592 var keys = Object.keys(this.choices);
4594 if (this.options.sort === true)
4595 keys.sort(L.naturalCompare);
4596 else if (Array.isArray(this.options.sort))
4597 keys = this.options.sort;
4599 if (this.options.create)
4600 for (var i =
0; i
< this.values.length; i++)
4601 if (!this.choices.hasOwnProperty(this.values[i]))
4602 keys.push(this.values[i]);
4604 for (var i =
0; i
< keys.length; i++) {
4605 var label = this.choices[keys[i]];
4607 if (dom.elem(label))
4608 label = label.cloneNode(true);
4610 sb.lastElementChild.appendChild(E('li', {
4611 'data-value': keys[i],
4612 'selected': (this.values.indexOf(keys[i])
> -
1) ? '' : null
4613 }, [ label || keys[i] ]));
4616 if (this.options.create) {
4617 var createEl = E('input', {
4619 'class': 'create-item-input',
4620 'readonly': this.options.readonly ? '' : null,
4621 'maxlength': this.options.maxlength,
4622 'placeholder': this.options.custom_placeholder || this.options.placeholder
4625 if (this.options.datatype || this.options.validate)
4626 UI.prototype.addValidator(createEl, this.options.datatype || 'string',
4627 true, this.options.validate, 'blur', 'keyup');
4629 sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl));
4632 if (this.options.create_markup)
4633 sb.appendChild(E('script', { type: 'item-template' },
4634 this.options.create_markup));
4636 return this.bind(sb);
4640 bind: function(sb) {
4641 var o = this.options;
4643 o.multiple = sb.hasAttribute('multiple');
4644 o.optional = sb.hasAttribute('optional');
4645 o.placeholder = sb.getAttribute('placeholder') || o.placeholder;
4646 o.display_items = parseInt(sb.getAttribute('display-items') || o.display_items);
4647 o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') || o.dropdown_items);
4648 o.create_query = sb.getAttribute('item-create') || o.create_query;
4649 o.create_template = sb.getAttribute('item-template') || o.create_template;
4651 var ul = sb.querySelector('ul'),
4652 more = sb.appendChild(E('span', { class: 'more', tabindex: -
1 }, '···')),
4653 open = sb.appendChild(E('span', { class: 'open', tabindex: -
1 }, '▾')),
4654 canary = sb.appendChild(E('div')),
4655 create = sb.querySelector(this.options.create_query),
4656 ndisplay = this.options.display_items,
4659 if (this.options.multiple) {
4660 var items = ul.querySelectorAll('li');
4662 for (var i =
0; i
< items.length; i++) {
4663 this.transformItem(sb, items[i]);
4665 if (items[i].hasAttribute('selected')
&& ndisplay--
> 0)
4666 items[i].setAttribute('display', n++);
4670 if (this.options.optional
&& !ul.querySelector('li[
data-value=
""]')) {
4671 var placeholder = E('li', { placeholder: '' },
4672 this.options.select_placeholder || this.options.placeholder);
4675 ? ul.insertBefore(placeholder, ul.firstChild)
4676 : ul.appendChild(placeholder);
4679 var items = ul.querySelectorAll('li'),
4680 sel = sb.querySelectorAll('[selected]');
4682 sel.forEach(function(s) {
4683 s.removeAttribute('selected');
4686 var s = sel[
0] || items[
0];
4688 s.setAttribute('selected', '');
4689 s.setAttribute('display', n++);
4695 this.saveValues(sb, ul);
4697 ul.setAttribute('tabindex', -
1);
4698 sb.setAttribute('tabindex',
0);
4700 if (ndisplay
< 0)
4701 sb.setAttribute('more', '')
4703 sb.removeAttribute('more');
4705 if (ndisplay == this.options.display_items)
4706 sb.setAttribute('empty', '')
4708 sb.removeAttribute('empty');
4710 dom.content(more, (ndisplay == this.options.display_items)
4711 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4714 sb.addEventListener('click', this.handleClick.bind(this));
4715 sb.addEventListener('keydown', this.handleKeydown.bind(this));
4716 sb.addEventListener('cbi-dropdown-close', this.handleDropdownClose.bind(this));
4717 sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this));
4719 if ('ontouchstart' in window) {
4720 sb.addEventListener('touchstart', function(ev) { ev.stopPropagation(); });
4721 window.addEventListener('touchstart', this.closeAllDropdowns);
4724 sb.addEventListener('mouseover', this.handleMouseover.bind(this));
4725 sb.addEventListener('mouseout', this.handleMouseout.bind(this));
4726 sb.addEventListener('focus', this.handleFocus.bind(this));
4728 canary.addEventListener('focus', this.handleCanaryFocus.bind(this));
4730 window.addEventListener('click', this.closeAllDropdowns);
4734 create.addEventListener('keydown', this.handleCreateKeydown.bind(this));
4735 create.addEventListener('focus', this.handleCreateFocus.bind(this));
4736 create.addEventListener('blur', this.handleCreateBlur.bind(this));
4738 var li = findParent(create, 'li');
4740 li.setAttribute('unselectable', '');
4741 li.addEventListener('click', this.handleCreateClick.bind(this));
4746 this.setUpdateEvents(sb, 'cbi-dropdown-open', 'cbi-dropdown-close');
4747 this.setChangeEvents(sb, 'cbi-dropdown-change', 'cbi-dropdown-close');
4749 dom.bindClassInstance(sb, this);
4755 getScrollParent: function(element) {
4756 var parent = element,
4757 style = getComputedStyle(element),
4758 excludeStaticParent = (style.position === 'absolute');
4760 if (style.position === 'fixed')
4761 return document.body;
4763 while ((parent = parent.parentElement) != null) {
4764 style = getComputedStyle(parent);
4766 if (excludeStaticParent
&& style.position === 'static')
4769 if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX))
4773 return document.body;
4777 openDropdown: function(sb) {
4778 var st = window.getComputedStyle(sb, null),
4779 ul = sb.querySelector('ul'),
4780 li = ul.querySelectorAll('li'),
4781 fl = findParent(sb, '.cbi-value-field'),
4782 sel = ul.querySelector('[selected]'),
4783 rect = sb.getBoundingClientRect(),
4784 items = Math.min(this.options.dropdown_items, li.length),
4785 scrollParent = this.getScrollParent(sb);
4787 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
4788 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
4791 sb.setAttribute('open', '');
4793 var pv = ul.cloneNode(true);
4794 pv.classList.add('preview');
4797 fl.classList.add('cbi-dropdown-open');
4799 if ('ontouchstart' in window) {
4800 var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth ||
0),
4801 vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight ||
0),
4804 ul.style.top = sb.offsetHeight + 'px';
4805 ul.style.left = -rect.left + 'px';
4806 ul.style.right = (rect.right - vpWidth) + 'px';
4807 ul.style.maxHeight = (vpHeight *
0.5) + 'px';
4808 ul.style.WebkitOverflowScrolling = 'touch';
4810 var scrollFrom = scrollParent.scrollTop,
4811 scrollTo = scrollFrom + rect.top - vpHeight *
0.5;
4813 var scrollStep = function(timestamp) {
4816 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight,
0) :
0;
4819 var duration = Math.max(timestamp - start,
1);
4820 if (duration
< 100) {
4821 scrollParent.scrollTop = scrollFrom + (scrollTo - scrollFrom) * (duration /
100);
4822 window.requestAnimationFrame(scrollStep);
4825 scrollParent.scrollTop = scrollTo;
4829 window.requestAnimationFrame(scrollStep);
4832 ul.style.maxHeight = '
1px';
4833 ul.style.top = ul.style.bottom = '';
4835 window.requestAnimationFrame(function() {
4836 var containerRect = scrollParent.getBoundingClientRect(),
4837 itemHeight = li[Math.max(
0, li.length -
2)].getBoundingClientRect().height,
4839 spaceAbove = rect.top - containerRect.top,
4840 spaceBelow = containerRect.bottom - rect.bottom;
4842 for (var i =
0; i
< (items == -
1 ? li.length : items); i++)
4843 fullHeight += li[i].getBoundingClientRect().height;
4845 if (fullHeight
<= spaceBelow) {
4846 ul.style.top = rect.height + 'px';
4847 ul.style.maxHeight = spaceBelow + 'px';
4849 else if (fullHeight
<= spaceAbove) {
4850 ul.style.bottom = rect.height + 'px';
4851 ul.style.maxHeight = spaceAbove + 'px';
4853 else if (spaceBelow
>= spaceAbove) {
4854 ul.style.top = rect.height + 'px';
4855 ul.style.maxHeight = (spaceBelow - (spaceBelow % itemHeight)) + 'px';
4858 ul.style.bottom = rect.height + 'px';
4859 ul.style.maxHeight = (spaceAbove - (spaceAbove % itemHeight)) + 'px';
4862 ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight,
0) :
0;
4866 var cboxes = ul.querySelectorAll('[selected] input[
type=
"checkbox"]');
4867 for (var i =
0; i
< cboxes.length; i++) {
4868 cboxes[i].checked = true;
4869 cboxes[i].disabled = (cboxes.length ==
1 && !this.options.optional);
4872 ul.classList.add('dropdown');
4874 sb.insertBefore(pv, ul.nextElementSibling);
4876 li.forEach(function(l) {
4877 l.setAttribute('tabindex',
0);
4880 sb.lastElementChild.setAttribute('tabindex',
0);
4882 var focusFn = L.bind(function(el) {
4883 this.setFocus(sb, el, true);
4884 ul.removeEventListener('transitionend', focusFn);
4885 }, this, sel || li[
0]);
4887 ul.addEventListener('transitionend', focusFn);
4891 closeDropdown: function(sb, no_focus) {
4892 if (!sb.hasAttribute('open'))
4895 var pv = sb.querySelector('ul.preview'),
4896 ul = sb.querySelector('ul.dropdown'),
4897 li = ul.querySelectorAll('li'),
4898 fl = findParent(sb, '.cbi-value-field');
4900 li.forEach(function(l) { l.removeAttribute('tabindex'); });
4901 sb.lastElementChild.removeAttribute('tabindex');
4904 sb.removeAttribute('open');
4905 sb.style.width = sb.style.height = '';
4907 ul.classList.remove('dropdown');
4908 ul.style.top = ul.style.bottom = ul.style.maxHeight = '';
4911 fl.classList.remove('cbi-dropdown-open');
4914 this.setFocus(sb, sb);
4916 this.saveValues(sb, ul);
4920 toggleItem: function(sb, li, force_state) {
4921 var ul = li.parentNode;
4923 if (li.hasAttribute('unselectable'))
4926 if (this.options.multiple) {
4927 var cbox = li.querySelector('input[
type=
"checkbox"]'),
4928 items = li.parentNode.querySelectorAll('li'),
4929 label = sb.querySelector('ul.preview'),
4930 sel = li.parentNode.querySelectorAll('[selected]').length,
4931 more = sb.querySelector('.more'),
4932 ndisplay = this.options.display_items,
4935 if (li.hasAttribute('selected')) {
4936 if (force_state !== true) {
4937 if (sel
> 1 || this.options.optional) {
4938 li.removeAttribute('selected');
4939 cbox.checked = cbox.disabled = false;
4943 cbox.disabled = true;
4948 if (force_state !== false) {
4949 li.setAttribute('selected', '');
4950 cbox.checked = true;
4951 cbox.disabled = false;
4956 while (label
&& label.firstElementChild)
4957 label.removeChild(label.firstElementChild);
4959 for (var i =
0; i
< items.length; i++) {
4960 items[i].removeAttribute('display');
4961 if (items[i].hasAttribute('selected')) {
4962 if (ndisplay--
> 0) {
4963 items[i].setAttribute('display', n++);
4965 label.appendChild(items[i].cloneNode(true));
4967 var c = items[i].querySelector('input[
type=
"checkbox"]');
4969 c.disabled = (sel ==
1 && !this.options.optional);
4973 if (ndisplay
< 0)
4974 sb.setAttribute('more', '');
4976 sb.removeAttribute('more');
4978 if (ndisplay === this.options.display_items)
4979 sb.setAttribute('empty', '');
4981 sb.removeAttribute('empty');
4983 dom.content(more, (ndisplay === this.options.display_items)
4984 ? (this.options.select_placeholder || this.options.placeholder) : '···');
4987 var sel = li.parentNode.querySelector('[selected]');
4989 sel.removeAttribute('display');
4990 sel.removeAttribute('selected');
4993 li.setAttribute('display',
0);
4994 li.setAttribute('selected', '');
4996 this.closeDropdown(sb, true);
4999 this.saveValues(sb, ul);
5003 transformItem: function(sb, li) {
5004 var cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -
1, onclick: 'event.preventDefault()' })),
5007 while (li.firstChild)
5008 label.appendChild(li.firstChild);
5010 li.appendChild(cbox);
5011 li.appendChild(label);
5015 saveValues: function(sb, ul) {
5016 var sel = ul.querySelectorAll('li[selected]'),
5017 div = sb.lastElementChild,
5018 name = this.options.name,
5022 while (div.lastElementChild)
5023 div.removeChild(div.lastElementChild);
5025 sel.forEach(function (s) {
5026 if (s.hasAttribute('placeholder'))
5031 value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText,
5035 div.appendChild(E('input', {
5043 strval += strval.length ? ' ' + v.value : v.value;
5051 if (this.options.multiple)
5052 detail.values = values;
5054 detail.value = values.length ? values[
0] : null;
5058 sb.dispatchEvent(new CustomEvent('cbi-dropdown-change', {
5065 setValues: function(sb, values) {
5066 var ul = sb.querySelector('ul');
5068 if (this.options.create) {
5069 for (var value in values) {
5070 this.createItems(sb, value);
5072 if (!this.options.multiple)
5077 if (this.options.multiple) {
5078 var lis = ul.querySelectorAll('li[data-value]');
5079 for (var i =
0; i
< lis.length; i++) {
5080 var value = lis[i].getAttribute('data-value');
5081 if (values === null || !(value in values))
5082 this.toggleItem(sb, lis[i], false);
5084 this.toggleItem(sb, lis[i], true);
5088 var ph = ul.querySelector('li[placeholder]');
5090 this.toggleItem(sb, ph);
5092 var lis = ul.querySelectorAll('li[data-value]');
5093 for (var i =
0; i
< lis.length; i++) {
5094 var value = lis[i].getAttribute('data-value');
5095 if (values !== null
&& (value in values))
5096 this.toggleItem(sb, lis[i]);
5102 setFocus: function(sb, elem, scroll) {
5103 if (sb.hasAttribute('locked-in'))
5106 sb.querySelectorAll('.focus').forEach(function(e) {
5107 e.classList.remove('focus');
5110 elem.classList.add('focus');
5113 elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop;
5119 handleMouseout: function(ev) {
5120 var sb = ev.currentTarget;
5122 if (!sb.hasAttribute('open'))
5125 sb.querySelectorAll('.focus').forEach(function(e) {
5126 e.classList.remove('focus');
5129 sb.querySelector('ul.dropdown').focus();
5133 createChoiceElement: function(sb, value, label) {
5134 var tpl = sb.querySelector(this.options.create_template),
5138 markup = (tpl.textContent || tpl.innerHTML || tpl.firstChild.data).replace(/^
<!--|-->$/, '').trim();
5140 markup = '
<li
data-value=
"{{value}}"><span
data-label-placeholder=
"true" /></li
>';
5142 var new_item = E(markup.replace(/{{value}}/g, '%h'.format(value))),
5143 placeholder = new_item.querySelector('[data-label-placeholder]');
5146 var content = E('span', {}, label || this.choices[value] || [ value ]);
5148 while (content.firstChild)
5149 placeholder.parentNode.insertBefore(content.firstChild, placeholder);
5151 placeholder.parentNode.removeChild(placeholder);
5154 if (this.options.multiple)
5155 this.transformItem(sb, new_item);
5161 createItems: function(sb, value) {
5163 val = (value || '').trim(),
5164 ul = sb.querySelector('ul');
5166 if (!sbox.options.multiple)
5167 val = val.length ? [ val ] : [];
5169 val = val.length ? val.split(/\s+/) : [];
5171 val.forEach(function(item) {
5172 var new_item = null;
5174 ul.childNodes.forEach(function(li) {
5175 if (li.getAttribute
&& li.getAttribute('data-value') === item)
5180 new_item = sbox.createChoiceElement(sb, item);
5182 if (!sbox.options.multiple) {
5183 var old = ul.querySelector('li[created]');
5185 ul.removeChild(old);
5187 new_item.setAttribute('created', '');
5190 new_item = ul.insertBefore(new_item, ul.lastElementChild);
5193 sbox.toggleItem(sb, new_item, true);
5194 sbox.setFocus(sb, new_item, true);
5199 * Remove all existing choices from the dropdown menu.
5201 * This function removes all preexisting dropdown choices from the widget,
5202 * keeping only choices currently being selected unless `reset_values` is
5203 * given, in which case all choices and deselected and removed.
5206 * @memberof LuCI.ui.Dropdown
5207 * @param {boolean} [reset_value=false]
5208 * If set to `true`, deselect and remove selected choices as well instead
5211 clearChoices: function(reset_value) {
5212 var ul = this.node.querySelector('ul'),
5213 lis = ul ? ul.querySelectorAll('li[data-value]') : [],
5214 len = lis.length - (this.options.create ?
1 :
0),
5215 val = reset_value ? null : this.getValue();
5217 for (var i =
0; i
< len; i++) {
5218 var lival = lis[i].getAttribute('data-value');
5220 (!this.options.multiple
&& val != lival) ||
5221 (this.options.multiple
&& val.indexOf(lival) == -
1))
5222 ul.removeChild(lis[i]);
5226 this.setValues(this.node, {});
5230 * Add new choices to the dropdown menu.
5232 * This function adds further choices to an existing dropdown menu,
5233 * ignoring choice values which are already present.
5236 * @memberof LuCI.ui.Dropdown
5237 * @param {string[]} values
5238 * The choice values to add to the dropdown widget.
5240 * @param {Object
<string, *
>} labels
5241 * The choice label values to use when adding dropdown choices. If no
5242 * label is found for a particular choice value, the value itself is used
5243 * as label text. Choice labels may be any valid value accepted by
5244 * {@link LuCI.dom#content}.
5246 addChoices: function(values, labels) {
5248 ul = sb.querySelector('ul'),
5249 lis = ul ? ul.querySelectorAll('li[data-value]') : [];
5251 if (!Array.isArray(values))
5252 values = L.toArray(values);
5254 if (!L.isObject(labels))
5257 for (var i =
0; i
< values.length; i++) {
5260 for (var j =
0; j
< lis.length; j++) {
5261 if (lis[j].getAttribute('data-value') === values[i]) {
5271 this.createChoiceElement(sb, values[i], labels[values[i]]),
5272 ul.lastElementChild);
5277 * Close all open dropdown widgets in the current document.
5279 closeAllDropdowns: function() {
5280 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
5281 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
5286 handleClick: function(ev) {
5287 var sb = ev.currentTarget;
5289 if (!sb.hasAttribute('open')) {
5290 if (!matchesElem(ev.target, 'input'))
5291 this.openDropdown(sb);
5294 var li = findParent(ev.target, 'li');
5295 if (li
&& li.parentNode.classList.contains('dropdown'))
5296 this.toggleItem(sb, li);
5297 else if (li
&& li.parentNode.classList.contains('preview'))
5298 this.closeDropdown(sb);
5299 else if (matchesElem(ev.target, 'span.open, span.more'))
5300 this.closeDropdown(sb);
5303 ev.preventDefault();
5304 ev.stopPropagation();
5308 handleKeydown: function(ev) {
5309 var sb = ev.currentTarget,
5310 ul = sb.querySelector('ul.dropdown');
5312 if (matchesElem(ev.target, 'input'))
5315 if (!sb.hasAttribute('open')) {
5316 switch (ev.keyCode) {
5321 this.openDropdown(sb);
5322 ev.preventDefault();
5326 var active = findParent(document.activeElement, 'li');
5328 switch (ev.keyCode) {
5330 this.closeDropdown(sb);
5331 ev.stopPropagation();
5336 if (!active.hasAttribute('selected'))
5337 this.toggleItem(sb, active);
5338 this.closeDropdown(sb);
5339 ev.preventDefault();
5345 this.toggleItem(sb, active);
5346 ev.preventDefault();
5351 if (active
&& active.previousElementSibling) {
5352 this.setFocus(sb, active.previousElementSibling);
5353 ev.preventDefault();
5355 else if (document.activeElement === ul) {
5356 this.setFocus(sb, ul.lastElementChild);
5357 ev.preventDefault();
5362 if (active
&& active.nextElementSibling) {
5363 this.setFocus(sb, active.nextElementSibling);
5364 ev.preventDefault();
5366 else if (document.activeElement === ul) {
5367 this.setFocus(sb, ul.firstElementChild);
5368 ev.preventDefault();
5376 handleDropdownClose: function(ev) {
5377 var sb = ev.currentTarget;
5379 this.closeDropdown(sb, true);
5383 handleDropdownSelect: function(ev) {
5384 var sb = ev.currentTarget,
5385 li = findParent(ev.target, 'li');
5390 this.toggleItem(sb, li);
5391 this.closeDropdown(sb, true);
5395 handleMouseover: function(ev) {
5396 var sb = ev.currentTarget;
5398 if (!sb.hasAttribute('open'))
5401 var li = findParent(ev.target, 'li');
5403 if (li
&& li.parentNode.classList.contains('dropdown'))
5404 this.setFocus(sb, li);
5408 handleFocus: function(ev) {
5409 var sb = ev.currentTarget;
5411 document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
5412 if (s !== sb || sb.hasAttribute('open'))
5413 s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
5418 handleCanaryFocus: function(ev) {
5419 this.closeDropdown(ev.currentTarget.parentNode);
5423 handleCreateKeydown: function(ev) {
5424 var input = ev.currentTarget,
5425 sb = findParent(input, '.cbi-dropdown');
5427 switch (ev.keyCode) {
5429 ev.preventDefault();
5431 if (input.classList.contains('cbi-input-invalid'))
5434 this.createItems(sb, input.value);
5442 handleCreateFocus: function(ev) {
5443 var input = ev.currentTarget,
5444 cbox = findParent(input, 'li').querySelector('input[
type=
"checkbox"]'),
5445 sb = findParent(input, '.cbi-dropdown');
5448 cbox.checked = true;
5450 sb.setAttribute('locked-in', '');
5454 handleCreateBlur: function(ev) {
5455 var input = ev.currentTarget,
5456 cbox = findParent(input, 'li').querySelector('input[
type=
"checkbox"]'),
5457 sb = findParent(input, '.cbi-dropdown');
5460 cbox.checked = false;
5462 sb.removeAttribute('locked-in');
5466 handleCreateClick: function(ev) {
5467 ev.currentTarget.querySelector(this.options.create_query).focus();
5471 setValue: function(values) {
5472 if (this.options.multiple) {
5473 if (!Array.isArray(values))
5474 values = (values != null
&& values != '') ? [ values ] : [];
5478 for (var i =
0; i
< values.length; i++)
5479 v[values[i]] = true;
5481 this.setValues(this.node, v);
5486 if (values != null) {
5487 if (Array.isArray(values))
5488 v[values[
0]] = true;
5493 this.setValues(this.node, v);
5498 getValue: function() {
5499 var div = this.node.lastElementChild,
5500 h = div.querySelectorAll('input[
type=
"hidden"]'),
5503 for (var i =
0; i
< h.length; i++)
5506 return this.options.multiple ? v : v[
0];
5511 * Instantiate a rich dropdown choice widget allowing custom values.
5513 * @constructor Combobox
5515 * @augments LuCI.ui.Dropdown
5519 * The `Combobox` class implements a rich, stylable dropdown menu which allows
5520 * to enter custom values. Historically, comboboxes used to be a dedicated
5521 * widget type in LuCI but nowadays they are direct aliases of dropdown widgets
5522 * with a set of enforced default properties for easier instantiation.
5524 * UI widget instances are usually not supposed to be created by view code
5525 * directly, instead they're implicitly created by `LuCI.form` when
5526 * instantiating CBI forms.
5528 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5529 * in views, use `'require ui'` and refer to `ui.Combobox`. To import it in
5530 * external JavaScript, use `L.require(
"ui").then(...)` and access the
5531 * `Combobox` property of the class instance value.
5533 * @param {string|string[]} [value=null]
5534 * The initial input value(s).
5536 * @param {Object
<string, *
>} choices
5537 * Object containing the selectable choices of the widget. The object keys
5538 * serve as values for the different choices while the values are used as
5541 * @param {LuCI.ui.Combobox.InitOptions} [options]
5542 * Object describing the widget specific options to initialize the dropdown.
5544 var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ {
5546 * Comboboxes support the same properties as
5547 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5548 * specific values for the following properties:
5550 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5551 * @memberof LuCI.ui.Combobox
5553 * @property {boolean} multiple=false
5554 * Since Comboboxes never allow selecting multiple values, this property
5555 * is forcibly set to `false`.
5557 * @property {boolean} create=true
5558 * Since Comboboxes always allow custom choice values, this property is
5559 * forcibly set to `true`.
5561 * @property {boolean} optional=true
5562 * Since Comboboxes are always optional, this property is forcibly set to
5565 __init__: function(value, choices, options) {
5566 this.super('__init__', [ value, choices, Object.assign({
5567 select_placeholder: _('-- Please choose --'),
5568 custom_placeholder: _('-- custom --'),
5580 * Instantiate a combo button widget offering multiple action choices.
5582 * @constructor ComboButton
5584 * @augments LuCI.ui.Dropdown
5588 * The `ComboButton` class implements a button element which can be expanded
5589 * into a dropdown to chose from a set of different action choices.
5591 * UI widget instances are usually not supposed to be created by view code
5592 * directly, instead they're implicitly created by `LuCI.form` when
5593 * instantiating CBI forms.
5595 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5596 * in views, use `'require ui'` and refer to `ui.ComboButton`. To import it in
5597 * external JavaScript, use `L.require(
"ui").then(...)` and access the
5598 * `ComboButton` property of the class instance value.
5600 * @param {string|string[]} [value=null]
5601 * The initial input value(s).
5603 * @param {Object
<string, *
>} choices
5604 * Object containing the selectable choices of the widget. The object keys
5605 * serve as values for the different choices while the values are used as
5608 * @param {LuCI.ui.ComboButton.InitOptions} [options]
5609 * Object describing the widget specific options to initialize the button.
5611 var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype */ {
5613 * ComboButtons support the same properties as
5614 * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
5615 * specific values for some properties and add additional button specific
5618 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5619 * @memberof LuCI.ui.ComboButton
5621 * @property {boolean} multiple=false
5622 * Since ComboButtons never allow selecting multiple actions, this property
5623 * is forcibly set to `false`.
5625 * @property {boolean} create=false
5626 * Since ComboButtons never allow creating custom choices, this property
5627 * is forcibly set to `false`.
5629 * @property {boolean} optional=false
5630 * Since ComboButtons must always select one action, this property is
5631 * forcibly set to `false`.
5633 * @property {Object
<string, string
>} [classes]
5634 * Specifies a mapping of choice values to CSS class names. If an action
5635 * choice is selected by the user and if a corresponding entry exists in
5636 * the `classes` object, the class names corresponding to the selected
5637 * value are set on the button element.
5639 * This is useful to apply different button styles, such as colors, to the
5640 * combined button depending on the selected action.
5642 * @property {function} [click]
5643 * Specifies a handler function to invoke when the user clicks the button.
5644 * This function will be called with the button DOM node as `this` context
5645 * and receive the DOM click event as first as well as the selected action
5646 * choice value as second argument.
5648 __init__: function(value, choices, options) {
5649 this.super('__init__', [ value, choices, Object.assign({
5659 render: function(/* ... */) {
5660 var node = UIDropdown.prototype.render.apply(this, arguments),
5661 val = this.getValue();
5663 if (L.isObject(this.options.classes)
&& this.options.classes.hasOwnProperty(val))
5664 node.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5670 handleClick: function(ev) {
5671 var sb = ev.currentTarget,
5674 if (sb.hasAttribute('open') || dom.matches(t, '.cbi-dropdown
> span.open'))
5675 return UIDropdown.prototype.handleClick.apply(this, arguments);
5677 if (this.options.click)
5678 return this.options.click.call(sb, ev, this.getValue());
5682 toggleItem: function(sb /*, ... */) {
5683 var rv = UIDropdown.prototype.toggleItem.apply(this, arguments),
5684 val = this.getValue();
5686 if (L.isObject(this.options.classes)
&& this.options.classes.hasOwnProperty(val))
5687 sb.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
5689 sb.setAttribute('class', 'cbi-dropdown');
5696 * Instantiate a dynamic list widget.
5698 * @constructor DynamicList
5700 * @augments LuCI.ui.AbstractElement
5704 * The `DynamicList` class implements a widget which allows the user to specify
5705 * an arbitrary amount of input values, either from free formed text input or
5706 * from a set of predefined choices.
5708 * UI widget instances are usually not supposed to be created by view code
5709 * directly, instead they're implicitly created by `LuCI.form` when
5710 * instantiating CBI forms.
5712 * This class is automatically instantiated as part of `LuCI.ui`. To use it
5713 * in views, use `'require ui'` and refer to `ui.DynamicList`. To import it in
5714 * external JavaScript, use `L.require(
"ui").then(...)` and access the
5715 * `DynamicList` property of the class instance value.
5717 * @param {string|string[]} [value=null]
5718 * The initial input value(s).
5720 * @param {Object
<string, *
>} [choices]
5721 * Object containing the selectable choices of the widget. The object keys
5722 * serve as values for the different choices while the values are used as
5723 * choice labels. If omitted, no default choices are presented to the user,
5724 * instead a plain text input field is rendered allowing the user to add
5725 * arbitrary values to the dynamic list.
5727 * @param {LuCI.ui.DynamicList.InitOptions} [options]
5728 * Object describing the widget specific options to initialize the dynamic list.
5730 var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ {
5732 * In case choices are passed to the dynamic list constructor, the widget
5733 * supports the same properties as [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions}
5734 * but enforces specific values for some dropdown properties.
5736 * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
5737 * @memberof LuCI.ui.DynamicList
5739 * @property {boolean} multiple=false
5740 * Since dynamic lists never allow selecting multiple choices when adding
5741 * another list item, this property is forcibly set to `false`.
5743 * @property {boolean} optional=true
5744 * Since dynamic lists use an embedded dropdown to present a list of
5745 * predefined choice values, the dropdown must be made optional to allow
5746 * it to remain unselected.
5748 __init__: function(values, choices, options) {
5749 if (!Array.isArray(values))
5750 values = (values != null
&& values != '') ? [ values ] : [];
5752 if (typeof(choices) != 'object')
5755 this.values = values;
5756 this.choices = choices;
5757 this.options = Object.assign({}, options, {
5764 render: function() {
5766 'id': this.options.id,
5767 'class': 'cbi-dynlist',
5768 'disabled': this.options.disabled ? '' : null
5769 }, E('div', { 'class': 'add-item control-group' }));
5772 if (this.options.placeholder != null)
5773 this.options.select_placeholder = this.options.placeholder;
5775 var cbox = new UICombobox(null, this.choices, this.options);
5777 dl.lastElementChild.appendChild(cbox.render());
5780 var inputEl = E('input', {
5781 'id': this.options.id ? 'widget.' + this.options.id : null,
5783 'class': 'cbi-input-text',
5784 'placeholder': this.options.placeholder,
5785 'disabled': this.options.disabled ? '' : null
5788 dl.lastElementChild.appendChild(inputEl);
5789 dl.lastElementChild.appendChild(E('div', { 'class': 'btn cbi-button cbi-button-add' }, '+'));
5791 if (this.options.datatype || this.options.validate)
5792 UI.prototype.addValidator(inputEl, this.options.datatype || 'string',
5793 true, this.options.validate, 'blur', 'keyup');
5796 for (var i =
0; i
< this.values.length; i++) {
5797 var label = this.choices ? this.choices[this.values[i]] : null;
5799 if (dom.elem(label))
5800 label = label.cloneNode(true);
5802 this.addItem(dl, this.values[i], label);
5805 return this.bind(dl);
5809 bind: function(dl) {
5810 dl.addEventListener('click', L.bind(this.handleClick, this));
5811 dl.addEventListener('keydown', L.bind(this.handleKeydown, this));
5812 dl.addEventListener('cbi-dropdown-change', L.bind(this.handleDropdownChange, this));
5816 this.setUpdateEvents(dl, 'cbi-dynlist-change');
5817 this.setChangeEvents(dl, 'cbi-dynlist-change');
5819 dom.bindClassInstance(dl, this);
5825 addItem: function(dl, value, text, flash) {
5827 new_item = E('div', { 'class': flash ? 'item flash' : 'item', 'tabindex':
0 }, [
5828 E('span', {}, [ text || value ]),
5831 'name': this.options.name,
5832 'value': value })]);
5834 dl.querySelectorAll('.item').forEach(function(item) {
5838 var hidden = item.querySelector('input[
type=
"hidden"]');
5840 if (hidden
&& hidden.parentNode !== item)
5843 if (hidden
&& hidden.value === value)
5848 var ai = dl.querySelector('.add-item');
5849 ai.parentNode.insertBefore(new_item, ai);
5852 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5864 removeItem: function(dl, item) {
5865 var value = item.querySelector('input[
type=
"hidden"]').value;
5866 var sb = dl.querySelector('.cbi-dropdown');
5868 sb.querySelectorAll('ul
> li').forEach(function(li) {
5869 if (li.getAttribute('data-value') === value) {
5870 if (li.hasAttribute('dynlistcustom'))
5871 li.parentNode.removeChild(li);
5873 li.removeAttribute('unselectable');
5877 item.parentNode.removeChild(item);
5879 dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
5891 handleClick: function(ev) {
5892 var dl = ev.currentTarget,
5893 item = findParent(ev.target, '.item');
5895 if (this.options.disabled)
5899 this.removeItem(dl, item);
5901 else if (matchesElem(ev.target, '.cbi-button-add')) {
5902 var input = ev.target.previousElementSibling;
5903 if (input.value.length
&& !input.classList.contains('cbi-input-invalid')) {
5904 this.addItem(dl, input.value, null, true);
5911 handleDropdownChange: function(ev) {
5912 var dl = ev.currentTarget,
5913 sbIn = ev.detail.instance,
5914 sbEl = ev.detail.element,
5915 sbVal = ev.detail.value;
5920 sbIn.setValues(sbEl, null);
5921 sbVal.element.setAttribute('unselectable', '');
5923 if (sbVal.element.hasAttribute('created')) {
5924 sbVal.element.removeAttribute('created');
5925 sbVal.element.setAttribute('dynlistcustom', '');
5928 var label = sbVal.text;
5930 if (sbVal.element) {
5933 for (var i =
0; i
< sbVal.element.childNodes.length; i++)
5934 label.appendChild(sbVal.element.childNodes[i].cloneNode(true));
5937 this.addItem(dl, sbVal.value, label, true);
5941 handleKeydown: function(ev) {
5942 var dl = ev.currentTarget,
5943 item = findParent(ev.target, '.item');
5946 switch (ev.keyCode) {
5947 case
8: /* backspace */
5948 if (item.previousElementSibling)
5949 item.previousElementSibling.focus();
5951 this.removeItem(dl, item);
5954 case
46: /* delete */
5955 if (item.nextElementSibling) {
5956 if (item.nextElementSibling.classList.contains('item'))
5957 item.nextElementSibling.focus();
5959 item.nextElementSibling.firstElementChild.focus();
5962 this.removeItem(dl, item);
5966 else if (matchesElem(ev.target, '.cbi-input-text')) {
5967 switch (ev.keyCode) {
5968 case
13: /* enter */
5969 if (ev.target.value.length
&& !ev.target.classList.contains('cbi-input-invalid')) {
5970 this.addItem(dl, ev.target.value, null, true);
5971 ev.target.value = '';
5976 ev.preventDefault();
5983 getValue: function() {
5984 var items = this.node.querySelectorAll('.item
> input[
type=
"hidden"]'),
5985 input = this.node.querySelector('.add-item
> input[
type=
"text"]'),
5988 for (var i =
0; i
< items.length; i++)
5989 v.push(items[i].value);
5991 if (input
&& input.value != null
&& input.value.match(/\S/)
&&
5992 input.classList.contains('cbi-input-invalid') == false
&&
5993 v.filter(function(s) { return s == input.value }).length ==
0)
5994 v.push(input.value);
6000 setValue: function(values) {
6001 if (!Array.isArray(values))
6002 values = (values != null
&& values != '') ? [ values ] : [];
6004 var items = this.node.querySelectorAll('.item');
6006 for (var i =
0; i
< items.length; i++)
6007 if (items[i].parentNode === this.node)
6008 this.removeItem(this.node, items[i]);
6010 for (var i =
0; i
< values.length; i++)
6011 this.addItem(this.node, values[i],
6012 this.choices ? this.choices[values[i]] : null);
6016 * Add new suggested choices to the dynamic list.
6018 * This function adds further choices to an existing dynamic list,
6019 * ignoring choice values which are already present.
6022 * @memberof LuCI.ui.DynamicList
6023 * @param {string[]} values
6024 * The choice values to add to the dynamic lists suggestion dropdown.
6026 * @param {Object
<string, *
>} labels
6027 * The choice label values to use when adding suggested choices. If no
6028 * label is found for a particular choice value, the value itself is used
6029 * as label text. Choice labels may be any valid value accepted by
6030 * {@link LuCI.dom#content}.
6032 addChoices: function(values, labels) {
6033 var dl = this.node.lastElementChild.firstElementChild;
6034 dom.callClassMethod(dl, 'addChoices', values, labels);
6038 * Remove all existing choices from the dynamic list.
6040 * This function removes all preexisting suggested choices from the widget.
6043 * @memberof LuCI.ui.DynamicList
6045 clearChoices: function() {
6046 var dl = this.node.lastElementChild.firstElementChild;
6047 dom.callClassMethod(dl, 'clearChoices');
6052 * Instantiate a hidden input field widget.
6054 * @constructor Hiddenfield
6056 * @augments LuCI.ui.AbstractElement
6060 * The `Hiddenfield` class implements an HTML `
<input
type=
"hidden">` field
6061 * which allows to store form data without exposing it to the user.
6063 * UI widget instances are usually not supposed to be created by view code
6064 * directly, instead they're implicitly created by `LuCI.form` when
6065 * instantiating CBI forms.
6067 * This class is automatically instantiated as part of `LuCI.ui`. To use it
6068 * in views, use `'require ui'` and refer to `ui.Hiddenfield`. To import it in
6069 * external JavaScript, use `L.require(
"ui").then(...)` and access the
6070 * `Hiddenfield` property of the class instance value.
6072 * @param {string|string[]} [value=null]
6073 * The initial input value.
6075 * @param {LuCI.ui.AbstractElement.InitOptions} [options]
6076 * Object describing the widget specific options to initialize the hidden input.
6078 var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ {
6079 __init__: function(value, options) {
6081 this.options = Object.assign({
6087 render: function() {
6088 var hiddenEl = E('input', {
6089 'id': this.options.id,
6094 return this.bind(hiddenEl);
6098 bind: function(hiddenEl) {
6099 this.node = hiddenEl;
6101 dom.bindClassInstance(hiddenEl, this);
6107 getValue: function() {
6108 return this.node.value;
6112 setValue: function(value) {
6113 this.node.value = value;
6118 * Instantiate a file upload widget.
6120 * @constructor FileUpload
6122 * @augments LuCI.ui.AbstractElement
6126 * The `FileUpload` class implements a widget which allows the user to upload,
6127 * browse, select and delete files beneath a predefined remote directory.
6129 * UI widget instances are usually not supposed to be created by view code
6130 * directly, instead they're implicitly created by `LuCI.form` when
6131 * instantiating CBI forms.
6133 * This class is automatically instantiated as part of `LuCI.ui`. To use it
6134 * in views, use `'require ui'` and refer to `ui.FileUpload`. To import it in
6135 * external JavaScript, use `L.require(
"ui").then(...)` and access the
6136 * `FileUpload` property of the class instance value.
6138 * @param {string|string[]} [value=null]
6139 * The initial input value.
6141 * @param {LuCI.ui.DynamicList.InitOptions} [options]
6142 * Object describing the widget specific options to initialize the file
6145 var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
6147 * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
6148 * the following properties are recognized:
6150 * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
6151 * @memberof LuCI.ui.FileUpload
6153 * @property {boolean} [show_hidden=false]
6154 * Specifies whether hidden files should be displayed when browsing remote
6155 * files. Note that this is not a security feature, hidden files are always
6156 * present in the remote file listings received, this option merely controls
6157 * whether they're displayed or not.
6159 * @property {boolean} [enable_upload=true]
6160 * Specifies whether the widget allows the user to upload files. If set to
6161 * `false`, only existing files may be selected. Note that this is not a
6162 * security feature. Whether file upload requests are accepted remotely
6163 * depends on the ACL setup for the current session. This option merely
6164 * controls whether the upload controls are rendered or not.
6166 * @property {boolean} [enable_remove=true]
6167 * Specifies whether the widget allows the user to delete remove files.
6168 * If set to `false`, existing files may not be removed. Note that this is
6169 * not a security feature. Whether file delete requests are accepted
6170 * remotely depends on the ACL setup for the current session. This option
6171 * merely controls whether the file remove controls are rendered or not.
6173 * @property {string} [root_directory=/etc/luci-uploads]
6174 * Specifies the remote directory the upload and file browsing actions take
6175 * place in. Browsing to directories outside the root directory is
6176 * prevented by the widget. Note that this is not a security feature.
6177 * Whether remote directories are browsable or not solely depends on the
6178 * ACL setup for the current session.
6180 __init__: function(value, options) {
6182 this.options = Object.assign({
6184 enable_upload: true,
6185 enable_remove: true,
6186 root_directory: '/etc/luci-uploads'
6191 bind: function(browserEl) {
6192 this.node = browserEl;
6194 this.setUpdateEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
6195 this.setChangeEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
6197 dom.bindClassInstance(browserEl, this);
6203 render: function() {
6204 return L.resolveDefault(this.value != null ? fs.stat(this.value) : null).then(L.bind(function(stat) {
6207 if (L.isObject(stat)
&& stat.type != 'directory')
6210 if (this.stat != null)
6211 label = [ this.iconForType(this.stat.type), ' %s (%
1000mB)'.format(this.truncatePath(this.stat.path), this.stat.size) ];
6212 else if (this.value != null)
6213 label = [ this.iconForType('file'), ' %s (%s)'.format(this.truncatePath(this.value), _('File not accessible')) ];
6215 label = [ _('Select file…') ];
6217 return this.bind(E('div', { 'id': this.options.id }, [
6220 'click': UI.prototype.createHandlerFn(this, 'handleFileBrowser'),
6221 'disabled': this.options.disabled ? '' : null
6224 'class': 'cbi-filebrowser'
6228 'name': this.options.name,
6236 truncatePath: function(path) {
6237 if (path.length
> 50)
6238 path = path.substring(
0,
25) + '…' + path.substring(path.length -
25);
6244 iconForType: function(type) {
6248 'src': L.resource('cbi/link.svg'),
6250 'title': _('Symbolic link'),
6256 'src': L.resource('cbi/folder.svg'),
6258 'title': _('Directory'),
6264 'src': L.resource('cbi/file.svg'),
6273 canonicalizePath: function(path) {
6274 return path.replace(/\/{
2,}/, '/')
6275 .replace(/\/\.(\/|$)/g, '/')
6276 .replace(/[^\/]+\/\.\.(\/|$)/g, '/')
6277 .replace(/\/$/, '');
6281 splitPath: function(path) {
6282 var croot = this.canonicalizePath(this.options.root_directory || '/'),
6283 cpath = this.canonicalizePath(path || '/');
6285 if (cpath.length
<= croot.length)
6288 if (cpath.charAt(croot.length) != '/')
6291 var parts = cpath.substring(croot.length +
1).split(/\//);
6293 parts.unshift(croot);
6299 handleUpload: function(path, list, ev) {
6300 var form = ev.target.parentNode,
6301 fileinput = form.querySelector('input[
type=
"file"]'),
6302 nameinput = form.querySelector('input[
type=
"text"]'),
6303 filename = (nameinput.value != null ? nameinput.value : '').trim();
6305 ev.preventDefault();
6307 if (filename == '' || filename.match(/\//) || fileinput.files[
0] == null)
6310 var existing = list.filter(function(e) { return e.name == filename })[
0];
6312 if (existing != null
&& existing.type == 'directory')
6313 return alert(_('A directory with the same name already exists.'));
6314 else if (existing != null
&& !confirm(_('Overwrite existing file
"%s" ?').format(filename)))
6317 var data = new FormData();
6319 data.append('sessionid', L.env.sessionid);
6320 data.append('filename', path + '/' + filename);
6321 data.append('filedata', fileinput.files[
0]);
6323 return request.post(L.env.cgi_base + '/cgi-upload', data, {
6324 progress: L.bind(function(btn, ev) {
6325 btn.firstChild.data = '%
.2f%%'.format((ev.loaded / ev.total) *
100);
6327 }).then(L.bind(function(path, ev, res) {
6328 var reply = res.json();
6330 if (L.isObject(reply)
&& reply.failure)
6331 alert(_('Upload request failed: %s').format(reply.message));
6333 return this.handleSelect(path, null, ev);
6334 }, this, path, ev));
6338 handleDelete: function(path, fileStat, ev) {
6339 var parent = path.replace(/\/[^\/]+$/, '') || '/',
6340 name = path.replace(/^.+\//, ''),
6343 ev.preventDefault();
6345 if (fileStat.type == 'directory')
6346 msg = _('Do you really want to recursively delete the directory
"%s" ?').format(name);
6348 msg = _('Do you really want to delete
"%s" ?').format(name);
6351 var button = this.node.firstElementChild,
6352 hidden = this.node.lastElementChild;
6354 if (path == hidden.value) {
6355 dom.content(button, _('Select file…'));
6359 return fs.remove(path).then(L.bind(function(parent, ev) {
6360 return this.handleSelect(parent, null, ev);
6361 }, this, parent, ev)).catch(function(err) {
6362 alert(_('Delete request failed: %s').format(err.message));
6368 renderUpload: function(path, list) {
6369 if (!this.options.enable_upload)
6375 'class': 'btn cbi-button-positive',
6376 'click': function(ev) {
6377 var uploadForm = ev.target.nextElementSibling,
6378 fileInput = uploadForm.querySelector('input[
type=
"file"]');
6380 ev.target.style.display = 'none';
6381 uploadForm.style.display = '';
6384 }, _('Upload file…')),
6385 E('div', { 'class': 'upload', 'style': 'display:none' }, [
6388 'style': 'display:none',
6389 'change': function(ev) {
6390 var nameinput = ev.target.parentNode.querySelector('input[
type=
"text"]'),
6391 uploadbtn = ev.target.parentNode.querySelector('button.cbi-button-save');
6393 nameinput.value = ev.target.value.replace(/^.+[\/\\]/, '');
6394 uploadbtn.disabled = false;
6399 'click': function(ev) {
6400 ev.preventDefault();
6401 ev.target.previousElementSibling.click();
6403 }, [ _('Browse…') ]),
6404 E('div', {}, E('input', { 'type': 'text', 'placeholder': _('Filename') })),
6406 'class': 'btn cbi-button-save',
6407 'click': UI.prototype.createHandlerFn(this, 'handleUpload', path, list),
6409 }, [ _('Upload file') ])
6415 renderListing: function(container, path, list) {
6416 var breadcrumb = E('p'),
6419 list.sort(function(a, b) {
6420 return L.naturalCompare(a.type == 'directory', b.type == 'directory') ||
6421 L.naturalCompare(a.name, b.name);
6424 for (var i =
0; i
< list.length; i++) {
6425 if (!this.options.show_hidden
&& list[i].name.charAt(
0) == '.')
6428 var entrypath = this.canonicalizePath(path + '/' + list[i].name),
6429 selected = (entrypath == this.node.lastElementChild.value),
6430 mtime = new Date(list[i].mtime *
1000);
6432 rows.appendChild(E('li', [
6433 E('div', { 'class': 'name' }, [
6434 this.iconForType(list[i].type),
6438 'style': selected ? 'font-weight:bold' : null,
6439 'click': UI.prototype.createHandlerFn(this, 'handleSelect',
6440 entrypath, list[i].type != 'directory' ? list[i] : null)
6441 }, '%h'.format(list[i].name))
6443 E('div', { 'class': 'mtime hide-xs' }, [
6444 ' %
04d-%
02d-%
02d %
02d:%
02d:%
02d '.format(
6445 mtime.getFullYear(),
6446 mtime.getMonth() +
1,
6453 selected ? E('button', {
6455 'click': UI.prototype.createHandlerFn(this, 'handleReset')
6456 }, [ _('Deselect') ]) : '',
6457 this.options.enable_remove ? E('button', {
6458 'class': 'btn cbi-button-negative',
6459 'click': UI.prototype.createHandlerFn(this, 'handleDelete', entrypath, list[i])
6460 }, [ _('Delete') ]) : ''
6465 if (!rows.firstElementChild)
6466 rows.appendChild(E('em', _('No entries in this directory')));
6468 var dirs = this.splitPath(path),
6471 for (var i =
0; i
< dirs.length; i++) {
6472 cur = cur ? cur + '/' + dirs[i] : dirs[i];
6473 dom.append(breadcrumb, [
6477 'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur || '/', null)
6478 }, dirs[i] != '' ? '%h'.format(dirs[i]) : E('em', '(root)')),
6482 dom.content(container, [
6485 E('div', { 'class': 'right' }, [
6486 this.renderUpload(path, list),
6490 'click': UI.prototype.createHandlerFn(this, 'handleCancel')
6497 handleCancel: function(ev) {
6498 var button = this.node.firstElementChild,
6499 browser = button.nextElementSibling;
6501 browser.classList.remove('open');
6502 button.style.display = '';
6504 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-cancel', {}));
6506 ev.preventDefault();
6510 handleReset: function(ev) {
6511 var button = this.node.firstElementChild,
6512 hidden = this.node.lastElementChild;
6515 dom.content(button, _('Select file…'));
6517 this.handleCancel(ev);
6521 handleSelect: function(path, fileStat, ev) {
6522 var browser = dom.parent(ev.target, '.cbi-filebrowser'),
6523 ul = browser.querySelector('ul');
6525 if (fileStat == null) {
6526 dom.content(ul, E('em', { 'class': 'spinning' }, _('Loading directory contents…')));
6527 L.resolveDefault(fs.list(path), []).then(L.bind(this.renderListing, this, browser, path));
6530 var button = this.node.firstElementChild,
6531 hidden = this.node.lastElementChild;
6533 path = this.canonicalizePath(path);
6535 dom.content(button, [
6536 this.iconForType(fileStat.type),
6537 ' %s (%
1000mB)'.format(this.truncatePath(path), fileStat.size)
6540 browser.classList.remove('open');
6541 button.style.display = '';
6542 hidden.value = path;
6544 this.stat = Object.assign({ path: path }, fileStat);
6545 this.node.dispatchEvent(new CustomEvent('cbi-fileupload-select', { detail: this.stat }));
6550 handleFileBrowser: function(ev) {
6551 var button = ev.target,
6552 browser = button.nextElementSibling,
6553 path = this.stat ? this.stat.path.replace(/\/[^\/]+$/, '') : (this.options.initial_directory || this.options.root_directory);
6555 if (path.indexOf(this.options.root_directory) !=
0)
6556 path = this.options.root_directory;
6558 ev.preventDefault();
6560 return L.resolveDefault(fs.list(path), []).then(L.bind(function(button, browser, path, list) {
6561 document.querySelectorAll('.cbi-filebrowser.open').forEach(function(browserEl) {
6562 dom.findClassInstance(browserEl).handleCancel(ev);
6565 button.style.display = 'none';
6566 browser.classList.add('open');
6568 return this.renderListing(browser, path, list);
6569 }, this, button, browser, path));
6573 getValue: function() {
6574 return this.node.lastElementChild.value;
6578 setValue: function(value) {
6579 this.node.lastElementChild.value = value;
6584 function scrubMenu(node) {
6585 var hasSatisfiedChild = false;
6587 if (L.isObject(node.children)) {
6588 for (var k in node.children) {
6589 var child = scrubMenu(node.children[k]);
6591 if (child.title
&& !child.firstchild_ineligible)
6592 hasSatisfiedChild = hasSatisfiedChild || child.satisfied;
6596 if (L.isObject(node.action)
&&
6597 node.action.type == 'firstchild'
&&
6598 hasSatisfiedChild == false)
6599 node.satisfied = false;
6614 var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ {
6616 * @typedef {Object} MenuNode
6617 * @memberof LuCI.ui.menu
6619 * @property {string} name - The internal name of the node, as used in the URL
6620 * @property {number} order - The sort index of the menu node
6621 * @property {string} [title] - The title of the menu node, `null` if the node should be hidden
6622 * @property {satisfied} boolean - Boolean indicating whether the menu entries dependencies are satisfied
6623 * @property {readonly} [boolean] - Boolean indicating whether the menu entries underlying ACLs are readonly
6624 * @property {LuCI.ui.menu.MenuNode[]} [children] - Array of child menu nodes.
6628 * Load and cache current menu tree.
6630 * @returns {Promise
<LuCI.ui.menu.MenuNode
>}
6631 * Returns a promise resolving to the root element of the menu tree.
6634 if (this.menu == null)
6635 this.menu = session.getLocalData('menu');
6637 if (!L.isObject(this.menu)) {
6638 this.menu = request.get(L.url('admin/menu')).then(L.bind(function(menu) {
6639 this.menu = scrubMenu(menu.json());
6640 session.setLocalData('menu', this.menu);
6646 return Promise.resolve(this.menu);
6650 * Flush the internal menu cache to force loading a new structure on the
6653 flushCache: function() {
6654 session.setLocalData('menu', null);
6658 * @param {LuCI.ui.menu.MenuNode} [node]
6659 * The menu node to retrieve the children for. Defaults to the menu's
6660 * internal root node if omitted.
6662 * @returns {LuCI.ui.menu.MenuNode[]}
6663 * Returns an array of child menu nodes.
6665 getChildren: function(node) {
6671 for (var k in node.children) {
6672 if (!node.children.hasOwnProperty(k))
6675 if (!node.children[k].satisfied)
6678 if (!node.children[k].hasOwnProperty('title'))
6681 var subnode = Object.assign(node.children[k], { name: k });
6683 if (L.isObject(subnode.action)
&& subnode.action.path != null
&&
6684 (subnode.action.type == 'alias' || subnode.action.type == 'rewrite')) {
6685 var root = this.menu,
6686 path = subnode.action.path.split('/');
6688 for (var i =
0; root != null
&& i
< path.length; i++)
6689 root = L.isObject(root.children) ? root.children[path[i]] : null;
6692 subnode = Object.assign({}, subnode, {
6693 children: root.children,
6698 children.push(subnode);
6701 return children.sort(function(a, b) {
6702 var wA = a.order ||
1000,
6703 wB = b.order ||
1000;
6708 return L.naturalCompare(a.name, b.name);
6713 var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ {
6714 __init__: function(captions, options, placeholder) {
6715 if (!Array.isArray(captions)) {
6716 this.initFromMarkup(captions);
6721 var id = options.id || 'table%
08x'.format(Math.random() *
0xffffffff);
6723 var table = E('table', { 'id': id, 'class': 'table' }, [
6724 E('tr', { 'class': 'tr table-titles', 'click': UI.prototype.createHandlerFn(this, 'handleSort') })
6729 this.options = options;
6731 var sorting = this.getActiveSortState();
6733 for (var i =
0; i
< captions.length; i++) {
6734 if (captions[i] == null)
6737 var th = E('th', { 'class': 'th' }, [ captions[i] ]);
6739 if (typeof(options.captionClasses) == 'object')
6740 DOMTokenList.prototype.add.apply(th.classList, L.toArray(options.captionClasses[i]));
6742 if (options.sortable !== false
&& (typeof(options.sortable) != 'object' || options.sortable[i] !== false)) {
6743 th.setAttribute('data-sortable-row', true);
6745 if (sorting
&& sorting[
0] == i)
6746 th.setAttribute('data-sort-direction', sorting[
1] ? 'desc' : 'asc');
6749 table.firstElementChild.appendChild(th);
6753 var trow = table.appendChild(E('tr', { 'class': 'tr placeholder' })),
6754 td = trow.appendChild(E('td', { 'class': 'td' }, placeholder));
6756 if (typeof(captionClasses) == 'object')
6757 DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[
0]));
6760 DOMTokenList.prototype.add.apply(table.classList, L.toArray(options.classes));
6763 update: function(data, placeholder) {
6764 var placeholder = placeholder || this.options.placeholder || _('No data', 'empty table placeholder'),
6765 sorting = this.getActiveSortState();
6767 if (!Array.isArray(data))
6771 this.placeholder = placeholder;
6774 rows = this.node.querySelectorAll('tr, .tr'),
6776 headings = [].slice.call(this.node.firstElementChild.querySelectorAll('th, .th')),
6777 captionClasses = this.options.captionClasses,
6778 trTag = (rows[
0]
&& rows[
0].nodeName == 'DIV') ? 'div' : 'tr',
6779 tdTag = (headings[
0]
&& headings[
0].nodeName == 'DIV') ? 'div' : 'td';
6782 var list = data.map(L.bind(function(row) {
6783 return [ this.deriveSortKey(row[sorting[
0]], sorting[
0]), row ];
6786 list.sort(function(a, b) {
6788 ? -L.naturalCompare(a[
0], b[
0])
6789 : L.naturalCompare(a[
0], b[
0]);
6794 list.forEach(function(item) {
6798 headings.forEach(function(th, i) {
6799 if (i == sorting[
0])
6800 th.setAttribute('data-sort-direction', sorting[
1] ? 'desc' : 'asc');
6802 th.removeAttribute('data-sort-direction');
6806 data.forEach(function(row) {
6807 trows[n] = E(trTag, { 'class': 'tr' });
6809 for (var i =
0; i
< headings.length; i++) {
6810 var text = (headings[i].innerText || '').trim();
6811 var raw_val = Array.isArray(row[i]) ? row[i][
0] : null;
6812 var disp_val = Array.isArray(row[i]) ? row[i][
1] : row[i];
6813 var td = trows[n].appendChild(E(tdTag, {
6815 'data-title': (text !== '') ? text : null,
6816 'data-value': raw_val
6817 }, (disp_val != null) ? ((disp_val instanceof DocumentFragment) ? disp_val.cloneNode(true) : disp_val) : ''));
6819 if (typeof(captionClasses) == 'object')
6820 DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[i]));
6822 if (!td.classList.contains('cbi-section-actions'))
6823 headings[i].setAttribute('data-sortable-row', true);
6826 trows[n].classList.add('cbi-rowstyle-%d'.format((n++ %
2) ?
2 :
1));
6829 for (var i =
0; i
< n; i++) {
6831 this.node.replaceChild(trows[i], rows[i+
1]);
6833 this.node.appendChild(trows[i]);
6837 this.node.removeChild(rows[n]);
6839 if (placeholder
&& this.node.firstElementChild === this.node.lastElementChild) {
6840 var trow = this.node.appendChild(E(trTag, { 'class': 'tr placeholder' })),
6841 td = trow.appendChild(E(tdTag, { 'class': 'td' }, placeholder));
6843 if (typeof(captionClasses) == 'object')
6844 DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[
0]));
6850 render: function() {
6855 initFromMarkup: function(node) {
6856 if (!dom.elem(node))
6857 node = document.querySelector(node);
6860 throw 'Invalid table selector';
6863 headrow = node.querySelector('tr, .tr');
6868 options.id = node.id;
6869 options.classes = [].slice.call(node.classList).filter(function(c) { return c != 'table' });
6870 options.sortable = [];
6871 options.captionClasses = [];
6873 headrow.querySelectorAll('th, .th').forEach(function(th, i) {
6874 options.sortable[i] = !th.classList.contains('cbi-section-actions');
6875 options.captionClasses[i] = [].slice.call(th.classList).filter(function(c) { return c != 'th' });
6878 headrow.addEventListener('click', UI.prototype.createHandlerFn(this, 'handleSort'));
6882 this.options = options;
6886 deriveSortKey: function(value, index) {
6887 var opts = this.options || {},
6890 if (opts.sortable == true || opts.sortable == null)
6892 else if (typeof( opts.sortable) == 'object')
6893 hint = opts.sortable[index];
6895 if (dom.elem(value)) {
6896 if (value.hasAttribute('data-value'))
6897 value = value.getAttribute('data-value');
6899 value = (value.innerText || '').trim();
6902 switch (hint || 'auto') {
6905 m = /^([
0-
9a-fA-F:.]+)(?:\/([
0-
9a-fA-F:.]+))?$/.exec(value);
6910 addr = validation.parseIPv6(m[
1]);
6911 mask = m[
2] ? validation.parseIPv6(m[
2]) : null;
6913 if (addr
&& mask != null)
6914 return '%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x'.format(
6915 addr[
0], addr[
1], addr[
2], addr[
3], addr[
4], addr[
5], addr[
6], addr[
7],
6916 mask[
0], mask[
1], mask[
2], mask[
3], mask[
4], mask[
5], mask[
6], mask[
7]
6919 return '%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
04x%
02x'.format(
6920 addr[
0], addr[
1], addr[
2], addr[
3], addr[
4], addr[
5], addr[
6], addr[
7],
6924 addr = validation.parseIPv4(m[
1]);
6925 mask = m[
2] ? validation.parseIPv4(m[
2]) : null;
6927 if (addr
&& mask != null)
6928 return '%
03d%
03d%
03d%
03d%
03d%
03d%
03d%
03d'.format(
6929 addr[
0], addr[
1], addr[
2], addr[
3],
6930 mask[
0], mask[
1], mask[
2], mask[
3]
6933 return '%
03d%
03d%
03d%
03d%
02d'.format(
6934 addr[
0], addr[
1], addr[
2], addr[
3],
6939 m = /^(?:(\d+)d )?(\d+)h (\d+)m (\d+)s$/.exec(value);
6942 return '%
05d%
02d%
02d%
02d'.format(+m[
1], +m[
2], +m[
3], +m[
4]);
6944 m = /^(\d+)\b(\D*)$/.exec(value);
6947 return '%
010d%s'.format(+m[
1], m[
2]);
6949 return String(value);
6952 return String(value).toLowerCase();
6958 return String(value);
6963 getActiveSortState: function() {
6965 return this.sortState;
6967 if (!this.options.id)
6970 var page = document.body.getAttribute('data-page'),
6971 key = page + '.' + this.options.id,
6972 state = session.getLocalData('tablesort');
6974 if (L.isObject(state)
&& Array.isArray(state[key]))
6981 setActiveSortState: function(index, descending) {
6982 this.sortState = [ index, descending ];
6984 if (!this.options.id)
6987 var page = document.body.getAttribute('data-page'),
6988 key = page + '.' + this.options.id,
6989 state = session.getLocalData('tablesort');
6991 if (!L.isObject(state))
6994 state[key] = this.sortState;
6996 session.setLocalData('tablesort', state);
7000 handleSort: function(ev) {
7001 if (!ev.target.matches('th[data-sortable-row]'))
7004 var index, direction;
7006 this.node.firstElementChild.querySelectorAll('th, .th').forEach(function(th, i) {
7007 if (th === ev.target) {
7009 direction = th.getAttribute('data-sort-direction') == 'asc';
7013 this.setActiveSortState(index, direction);
7014 this.update(this.data, this.placeholder);
7024 * Provides high level UI helper functionality.
7025 * To import the class in views, use `'require ui'`, to import it in
7026 * external JavaScript, use `L.require(
"ui").then(...)`.
7028 var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
7029 __init__: function() {
7030 modalDiv = document.body.appendChild(
7032 id: 'modal_overlay',
7034 keydown: this.cancelModal
7043 tooltipDiv = document.body.appendChild(
7044 dom.create('div', { class: 'cbi-tooltip' }));
7046 /* setup old aliases */
7047 L.showModal = this.showModal;
7048 L.hideModal = this.hideModal;
7049 L.showTooltip = this.showTooltip;
7050 L.hideTooltip = this.hideTooltip;
7051 L.itemlist = this.itemlist;
7053 document.addEventListener('mouseover', this.showTooltip.bind(this), true);
7054 document.addEventListener('mouseout', this.hideTooltip.bind(this), true);
7055 document.addEventListener('focus', this.showTooltip.bind(this), true);
7056 document.addEventListener('blur', this.hideTooltip.bind(this), true);
7058 document.addEventListener('luci-loaded', this.tabs.init.bind(this.tabs));
7059 document.addEventListener('luci-loaded', this.changes.init.bind(this.changes));
7060 document.addEventListener('uci-loaded', this.changes.init.bind(this.changes));
7064 * Display a modal overlay dialog with the specified contents.
7066 * The modal overlay dialog covers the current view preventing interaction
7067 * with the underlying view contents. Only one modal dialog instance can
7068 * be opened. Invoking showModal() while a modal dialog is already open will
7069 * replace the open dialog with a new one having the specified contents.
7071 * Additional CSS class names may be passed to influence the appearance of
7072 * the dialog. Valid values for the classes depend on the underlying theme.
7074 * @see LuCI.dom.content
7076 * @param {string} [title]
7077 * The title of the dialog. If `null`, no title element will be rendered.
7079 * @param {*} children
7080 * The contents to add to the modal dialog. This should be a DOM node or
7081 * a document fragment in most cases. The value is passed as-is to the
7082 * `dom.content()` function - refer to its documentation for applicable
7085 * @param {...string} [classes]
7086 * A number of extra CSS class names which are set on the modal dialog
7090 * Returns a DOM Node representing the modal dialog element.
7092 showModal: function(title, children /* , ... */) {
7093 var dlg = modalDiv.firstElementChild;
7095 dlg.setAttribute('class', 'modal');
7097 for (var i =
2; i
< arguments.length; i++)
7098 dlg.classList.add(arguments[i]);
7100 dom.content(dlg, dom.create('h4', {}, title));
7101 dom.append(dlg, children);
7103 document.body.classList.add('modal-overlay-active');
7104 modalDiv.scrollTop =
0;
7111 * Close the open modal overlay dialog.
7113 * This function will close an open modal dialog and restore the normal view
7114 * behaviour. It has no effect if no modal dialog is currently open.
7116 * Note that this function is stand-alone, it does not rely on `this` and
7117 * will not invoke other class functions so it suitable to be used as event
7118 * handler as-is without the need to bind it first.
7120 hideModal: function() {
7121 document.body.classList.remove('modal-overlay-active');
7126 cancelModal: function(ev) {
7127 if (ev.key == 'Escape') {
7128 var btn = modalDiv.querySelector('.right
> button, .right
> .btn');
7136 showTooltip: function(ev) {
7137 var target = findParent(ev.target, '[data-tooltip]');
7142 if (tooltipTimeout !== null) {
7143 window.clearTimeout(tooltipTimeout);
7144 tooltipTimeout = null;
7147 var rect = target.getBoundingClientRect(),
7148 x = rect.left + window.pageXOffset,
7149 y = rect.top + rect.height + window.pageYOffset,
7152 tooltipDiv.className = 'cbi-tooltip';
7153 tooltipDiv.innerHTML = '▲ ';
7154 tooltipDiv.firstChild.data += target.getAttribute('data-tooltip');
7156 if (target.hasAttribute('data-tooltip-style'))
7157 tooltipDiv.classList.add(target.getAttribute('data-tooltip-style'));
7159 if ((y + tooltipDiv.offsetHeight)
> (window.innerHeight + window.pageYOffset))
7162 var dropdown = target.querySelector('ul.dropdown[style]:first-child');
7164 if (dropdown
&& dropdown.style.top)
7168 y -= (tooltipDiv.offsetHeight + target.offsetHeight);
7169 tooltipDiv.firstChild.data = '▼ ' + tooltipDiv.firstChild.data.substr(
2);
7172 tooltipDiv.style.top = y + 'px';
7173 tooltipDiv.style.left = x + 'px';
7174 tooltipDiv.style.opacity =
1;
7176 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-open', {
7178 detail: { target: target }
7183 hideTooltip: function(ev) {
7184 if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv ||
7185 tooltipDiv.contains(ev.target) || tooltipDiv.contains(ev.relatedTarget))
7188 if (tooltipTimeout !== null) {
7189 window.clearTimeout(tooltipTimeout);
7190 tooltipTimeout = null;
7193 tooltipDiv.style.opacity =
0;
7194 tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); },
250);
7196 tooltipDiv.dispatchEvent(new CustomEvent('tooltip-close', { bubbles: true }));
7200 * Add a notification banner at the top of the current view.
7202 * A notification banner is an alert message usually displayed at the
7203 * top of the current view, spanning the entire available width.
7204 * Notification banners will stay in place until dismissed by the user.
7205 * Multiple banners may be shown at the same time.
7207 * Additional CSS class names may be passed to influence the appearance of
7208 * the banner. Valid values for the classes depend on the underlying theme.
7210 * @see LuCI.dom.content
7212 * @param {string} [title]
7213 * The title of the notification banner. If `null`, no title element
7216 * @param {*} children
7217 * The contents to add to the notification banner. This should be a DOM
7218 * node or a document fragment in most cases. The value is passed as-is
7219 * to the `dom.content()` function - refer to its documentation for
7220 * applicable values.
7222 * @param {...string} [classes]
7223 * A number of extra CSS class names which are set on the notification
7227 * Returns a DOM Node representing the notification banner element.
7229 addNotification: function(title, children /*, ... */) {
7230 var mc = document.querySelector('#maincontent') || document.body;
7231 var msg = E('div', {
7232 'class': 'alert-message fade-in',
7233 'style': 'display:flex',
7234 'transitionend': function(ev) {
7235 var node = ev.currentTarget;
7236 if (node.parentNode
&& node.classList.contains('fade-out'))
7237 node.parentNode.removeChild(node);
7240 E('div', { 'style': 'flex:
10' }),
7241 E('div', { 'style': 'flex:
1 1 auto; display:flex' }, [
7244 'style': 'margin-left:auto; margin-top:auto',
7245 'click': function(ev) {
7246 dom.parent(ev.target, '.alert-message').classList.add('fade-out');
7249 }, [ _('Dismiss') ])
7254 dom.append(msg.firstElementChild, E('h4', {}, title));
7256 dom.append(msg.firstElementChild, children);
7258 for (var i =
2; i
< arguments.length; i++)
7259 msg.classList.add(arguments[i]);
7261 mc.insertBefore(msg, mc.firstElementChild);
7267 * Display or update a header area indicator.
7269 * An indicator is a small label displayed in the header area of the screen
7270 * providing few amounts of status information such as item counts or state
7271 * toggle indicators.
7273 * Multiple indicators may be shown at the same time and indicator labels
7274 * may be made clickable to display extended information or to initiate
7277 * Indicators can either use a default `active` or a less accented `inactive`
7278 * style which is useful for indicators representing state toggles.
7280 * @param {string} id
7281 * The ID of the indicator. If an indicator with the given ID already exists,
7282 * it is updated with the given label and style.
7284 * @param {string} label
7285 * The text to display in the indicator label.
7287 * @param {function} [handler]
7288 * A handler function to invoke when the indicator label is clicked/touched
7289 * by the user. If omitted, the indicator is not clickable/touchable.
7291 * Note that this parameter only applies to new indicators, when updating
7292 * existing labels it is ignored.
7294 * @param {
"active"|
"inactive"} [style=active]
7295 * The indicator style to use. May be either `active` or `inactive`.
7297 * @returns {boolean}
7298 * Returns `true` when the indicator has been updated or `false` when no
7299 * changes were made.
7301 showIndicator: function(id, label, handler, style) {
7302 if (indicatorDiv == null) {
7303 indicatorDiv = document.body.querySelector('#indicators');
7305 if (indicatorDiv == null)
7309 var handlerFn = (typeof(handler) == 'function') ? handler : null,
7310 indicatorElem = indicatorDiv.querySelector('span[
data-indicator=
"%s"]'.format(id));
7312 if (indicatorElem == null) {
7313 var beforeElem = null;
7315 for (beforeElem = indicatorDiv.firstElementChild;
7317 beforeElem = beforeElem.nextElementSibling)
7318 if (beforeElem.getAttribute('data-indicator')
> id)
7321 indicatorElem = indicatorDiv.insertBefore(E('span', {
7322 'data-indicator': id,
7323 'data-clickable': handlerFn ? true : null,
7325 }, ['']), beforeElem);
7328 if (label == indicatorElem.firstChild.data
&& style == indicatorElem.getAttribute('data-style'))
7331 indicatorElem.firstChild.data = label;
7332 indicatorElem.setAttribute('data-style', (style == 'inactive') ? 'inactive' : 'active');
7337 * Remove a header area indicator.
7339 * This function removes the given indicator label from the header indicator
7340 * area. When the given indicator is not found, this function does nothing.
7342 * @param {string} id
7343 * The ID of the indicator to remove.
7345 * @returns {boolean}
7346 * Returns `true` when the indicator has been removed or `false` when the
7347 * requested indicator was not found.
7349 hideIndicator: function(id) {
7350 var indicatorElem = indicatorDiv ? indicatorDiv.querySelector('span[
data-indicator=
"%s"]'.format(id)) : null;
7352 if (indicatorElem == null)
7355 indicatorDiv.removeChild(indicatorElem);
7360 * Formats a series of label/value pairs into list-like markup.
7362 * This function transforms a flat array of alternating label and value
7363 * elements into a list-like markup, using the values in `separators` as
7364 * separators and appends the resulting nodes to the given parent DOM node.
7366 * Each label is suffixed with `: ` and wrapped into a `
<strong
>` tag, the
7367 * `
<strong
>` element and the value corresponding to the label are
7368 * subsequently wrapped into a `
<span
class=
"nowrap">` element.
7370 * The resulting `
<span
>` element tuples are joined by the given separators
7371 * to form the final markup which is appended to the given parent DOM node.
7373 * @param {Node} node
7374 * The parent DOM node to append the markup to. Any previous child elements
7377 * @param {Array
<*
>} items
7378 * An alternating array of labels and values. The label values will be
7379 * converted to plain strings, the values are used as-is and may be of
7380 * any type accepted by `LuCI.dom.content()`.
7382 * @param {*|Array
<*
>} [separators=[E('br')]]
7383 * A single value or an array of separator values to separate each
7384 * label/value pair with. The function will cycle through the separators
7385 * when joining the pairs. If omitted, the default separator is a sole HTML
7386 * `
<br
>` element. Separator values are used as-is and may be of any type
7387 * accepted by `LuCI.dom.content()`.
7390 * Returns the parent DOM node the formatted markup has been added to.
7392 itemlist: function(node, items, separators) {
7395 if (!Array.isArray(separators))
7396 separators = [ separators || E('br') ];
7398 for (var i =
0; i
< items.length; i +=
2) {
7399 if (items[i+
1] !== null
&& items[i+
1] !== undefined) {
7400 var sep = separators[(i/
2) % separators.length],
7403 children.push(E('span', { class: 'nowrap' }, [
7404 items[i] ? E('strong', items[i] + ': ') : '',
7408 if ((i+
2)
< items.length)
7409 children.push(dom.elem(sep) ? sep.cloneNode(true) : sep);
7413 dom.content(node, children);
7424 * The `tabs` class handles tab menu groups used throughout the view area.
7425 * It takes care of setting up tab groups, tracking their state and handling
7428 * This class is automatically instantiated as part of `LuCI.ui`. To use it
7429 * in views, use `'require ui'` and refer to `ui.tabs`. To import it in
7430 * external JavaScript, use `L.require(
"ui").then(...)` and access the
7431 * `tabs` property of the class instance value.
7433 tabs: baseclass.singleton(/* @lends LuCI.ui.tabs.prototype */ {
7436 var groups = [], prevGroup = null, currGroup = null;
7438 document.querySelectorAll('[data-tab]').forEach(function(tab) {
7439 var parent = tab.parentNode;
7441 if (dom.matches(tab, 'li')
&& dom.matches(parent, 'ul.cbi-tabmenu'))
7444 if (!parent.hasAttribute('data-tab-group'))
7445 parent.setAttribute('data-tab-group', groups.length);
7447 currGroup = +parent.getAttribute('data-tab-group');
7449 if (currGroup !== prevGroup) {
7450 prevGroup = currGroup;
7452 if (!groups[currGroup])
7453 groups[currGroup] = [];
7456 groups[currGroup].push(tab);
7459 for (var i =
0; i
< groups.length; i++)
7460 this.initTabGroup(groups[i]);
7462 document.addEventListener('dependency-update', this.updateTabs.bind(this));
7468 * Initializes a new tab group from the given tab pane collection.
7470 * This function cycles through the given tab pane DOM nodes, extracts
7471 * their tab IDs, titles and active states, renders a corresponding
7472 * tab menu and prepends it to the tab panes common parent DOM node.
7474 * The tab menu labels will be set to the value of the `data-tab-title`
7475 * attribute of each corresponding pane. The last pane with the
7476 * `data-tab-active` attribute set to `true` will be selected by default.
7478 * If no pane is marked as active, the first one will be preselected.
7481 * @memberof LuCI.ui.tabs
7482 * @param {Array
<Node
>|NodeList} panes
7483 * A collection of tab panes to build a tab group menu for. May be a
7484 * plain array of DOM nodes or a NodeList collection, such as the result
7485 * of a `querySelectorAll()` call or the `.childNodes` property of a
7488 initTabGroup: function(panes) {
7489 if (typeof(panes) != 'object' || !('length' in panes) || panes.length ===
0)
7492 var menu = E('ul', { 'class': 'cbi-tabmenu' }),
7493 group = panes[
0].parentNode,
7494 groupId = +group.getAttribute('data-tab-group'),
7497 if (group.getAttribute('data-initialized') === 'true')
7500 for (var i =
0, pane; pane = panes[i]; i++) {
7501 var name = pane.getAttribute('data-tab'),
7502 title = pane.getAttribute('data-tab-title'),
7503 active = pane.getAttribute('data-tab-active') === 'true';
7505 menu.appendChild(E('li', {
7506 'style': this.isEmptyPane(pane) ? 'display:none' : null,
7507 'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
7511 'click': this.switchTab.bind(this)
7518 group.parentNode.insertBefore(menu, group);
7519 group.setAttribute('data-initialized', true);
7521 if (selected === null) {
7522 selected = this.getActiveTabId(panes[
0]);
7524 if (selected
< 0 || selected
>= panes.length || this.isEmptyPane(panes[selected])) {
7525 for (var i =
0; i
< panes.length; i++) {
7526 if (!this.isEmptyPane(panes[i])) {
7533 menu.childNodes[selected].classList.add('cbi-tab');
7534 menu.childNodes[selected].classList.remove('cbi-tab-disabled');
7535 panes[selected].setAttribute('data-tab-active', 'true');
7537 this.setActiveTabId(panes[selected], selected);
7540 requestAnimationFrame(L.bind(function(pane) {
7541 pane.dispatchEvent(new CustomEvent('cbi-tab-active', {
7542 detail: { tab: pane.getAttribute('data-tab') }
7544 }, this, panes[selected]));
7546 this.updateTabs(group);
7550 * Checks whether the given tab pane node is empty.
7553 * @memberof LuCI.ui.tabs
7554 * @param {Node} pane
7555 * The tab pane to check.
7557 * @returns {boolean}
7558 * Returns `true` if the pane is empty, else `false`.
7560 isEmptyPane: function(pane) {
7561 return dom.isEmpty(pane, function(n) { return n.classList.contains('cbi-tab-descr') });
7565 getPathForPane: function(pane) {
7566 var path = [], node = null;
7568 for (node = pane ? pane.parentNode : null;
7569 node != null
&& node.hasAttribute != null;
7570 node = node.parentNode)
7572 if (node.hasAttribute('data-tab'))
7573 path.unshift(node.getAttribute('data-tab'));
7574 else if (node.hasAttribute('data-section-id'))
7575 path.unshift(node.getAttribute('data-section-id'));
7578 return path.join('/');
7582 getActiveTabState: function() {
7583 var page = document.body.getAttribute('data-page'),
7584 state = session.getLocalData('tab');
7586 if (L.isObject(state)
&& state.page === page
&& L.isObject(state.paths))
7589 session.setLocalData('tab', null);
7591 return { page: page, paths: {} };
7595 getActiveTabId: function(pane) {
7596 var path = this.getPathForPane(pane);
7597 return +this.getActiveTabState().paths[path] ||
0;
7601 setActiveTabId: function(pane, tabIndex) {
7602 var path = this.getPathForPane(pane),
7603 state = this.getActiveTabState();
7605 state.paths[path] = tabIndex;
7607 return session.setLocalData('tab', state);
7611 updateTabs: function(ev, root) {
7612 (root || document).querySelectorAll('[data-tab-title]').forEach(L.bind(function(pane) {
7613 var menu = pane.parentNode.previousElementSibling,
7614 tab = menu ? menu.querySelector('[
data-tab=
"%s"]'.format(pane.getAttribute('data-tab'))) : null,
7615 n_errors = pane.querySelectorAll('.cbi-input-invalid').length;
7620 if (this.isEmptyPane(pane)) {
7621 tab.style.display = 'none';
7622 tab.classList.remove('flash');
7624 else if (tab.style.display === 'none') {
7625 tab.style.display = '';
7626 requestAnimationFrame(function() { tab.classList.add('flash') });
7630 tab.setAttribute('data-errors', n_errors);
7631 tab.setAttribute('data-tooltip', _('%d invalid field(s)').format(n_errors));
7632 tab.setAttribute('data-tooltip-style', 'error');
7635 tab.removeAttribute('data-errors');
7636 tab.removeAttribute('data-tooltip');
7642 switchTab: function(ev) {
7643 var tab = ev.target.parentNode,
7644 name = tab.getAttribute('data-tab'),
7645 menu = tab.parentNode,
7646 group = menu.nextElementSibling,
7647 groupId = +group.getAttribute('data-tab-group'),
7650 ev.preventDefault();
7652 if (!tab.classList.contains('cbi-tab-disabled'))
7655 menu.querySelectorAll('[data-tab]').forEach(function(tab) {
7656 tab.classList.remove('cbi-tab');
7657 tab.classList.remove('cbi-tab-disabled');
7659 tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled');
7662 group.childNodes.forEach(function(pane) {
7663 if (dom.matches(pane, '[data-tab]')) {
7664 if (pane.getAttribute('data-tab') === name) {
7665 pane.setAttribute('data-tab-active', 'true');
7666 pane.dispatchEvent(new CustomEvent('cbi-tab-active', { detail: { tab: name } }));
7667 UI.prototype.tabs.setActiveTabId(pane, index);
7670 pane.setAttribute('data-tab-active', 'false');
7680 * @typedef {Object} FileUploadReply
7683 * @property {string} name - Name of the uploaded file without directory components
7684 * @property {number} size - Size of the uploaded file in bytes
7685 * @property {string} checksum - The MD5 checksum of the received file data
7686 * @property {string} sha256sum - The SHA256 checksum of the received file data
7690 * Display a modal file upload prompt.
7692 * This function opens a modal dialog prompting the user to select and
7693 * upload a file to a predefined remote destination path.
7695 * @param {string} path
7696 * The remote file path to upload the local file to.
7698 * @param {Node} [progressStatusNode]
7699 * An optional DOM text node whose content text is set to the progress
7700 * percentage value during file upload.
7702 * @returns {Promise
<LuCI.ui.FileUploadReply
>}
7703 * Returns a promise resolving to a file upload status object on success
7704 * or rejecting with an error in case the upload failed or has been
7705 * cancelled by the user.
7707 uploadFile: function(path, progressStatusNode) {
7708 return new Promise(function(resolveFn, rejectFn) {
7709 UI.prototype.showModal(_('Uploading file…'), [
7710 E('p', _('Please select the file to upload.')),
7711 E('div', { 'style': 'display:flex' }, [
7712 E('div', { 'class': 'left', 'style': 'flex:
1' }, [
7715 style: 'display:none',
7716 change: function(ev) {
7717 var modal = dom.parent(ev.target, '.modal'),
7718 body = modal.querySelector('p'),
7719 upload = modal.querySelector('.cbi-button-action.important'),
7720 file = ev.currentTarget.files[
0];
7727 E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]),
7728 E('li', {}, [ '%s: %
1024mB'.format(_('Size'), file.size) ])
7732 upload.disabled = false;
7738 'click': function(ev) {
7739 ev.target.previousElementSibling.click();
7741 }, [ _('Browse…') ])
7743 E('div', { 'class': 'right', 'style': 'flex:
1' }, [
7746 'click': function() {
7747 UI.prototype.hideModal();
7748 rejectFn(new Error(_('Upload has been cancelled')));
7750 }, [ _('Cancel') ]),
7753 'class': 'btn cbi-button-action important',
7755 'click': function(ev) {
7756 var input = dom.parent(ev.target, '.modal').querySelector('input[
type=
"file"]');
7758 if (!input.files[
0])
7761 var progress = E('div', { 'class': 'cbi-progressbar', 'title': '
0%' }, E('div', { 'style': 'width:
0' }));
7763 UI.prototype.showModal(_('Uploading file…'), [ progress ]);
7765 var data = new FormData();
7767 data.append('sessionid', rpc.getSessionID());
7768 data.append('filename', path);
7769 data.append('filedata', input.files[
0]);
7771 var filename = input.files[
0].name;
7773 request.post(L.env.cgi_base + '/cgi-upload', data, {
7775 progress: function(pev) {
7776 var percent = (pev.loaded / pev.total) *
100;
7778 if (progressStatusNode)
7779 progressStatusNode.data = '%
.2f%%'.format(percent);
7781 progress.setAttribute('title', '%
.2f%%'.format(percent));
7782 progress.firstElementChild.style.width = '%
.2f%%'.format(percent);
7784 }).then(function(res) {
7785 var reply = res.json();
7787 UI.prototype.hideModal();
7789 if (L.isObject(reply)
&& reply.failure) {
7790 UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message)));
7791 rejectFn(new Error(reply.failure));
7794 reply.name = filename;
7798 UI.prototype.hideModal();
7810 * Perform a device connectivity test.
7812 * Attempt to fetch a well known resource from the remote device via HTTP
7813 * in order to test connectivity. This function is mainly useful to wait
7814 * for the router to come back online after a reboot or reconfiguration.
7816 * @param {string} [proto=http]
7817 * The protocol to use for fetching the resource. May be either `http`
7818 * (the default) or `https`.
7820 * @param {string} [ipaddr=window.location.host]
7821 * Override the host address to probe. By default the current host as seen
7822 * in the address bar is probed.
7824 * @returns {Promise
<Event
>}
7825 * Returns a promise resolving to a `load` event in case the device is
7826 * reachable or rejecting with an `error` event in case it is not reachable
7827 * or rejecting with `null` when the connectivity check timed out.
7829 pingDevice: function(proto, ipaddr) {
7830 var target = '%s://%s%s?%s'.format(proto || 'http', ipaddr || window.location.host, L.resource('icons/loading.gif'), Math.random());
7832 return new Promise(function(resolveFn, rejectFn) {
7833 var img = new Image();
7835 img.onload = resolveFn;
7836 img.onerror = rejectFn;
7838 window.setTimeout(rejectFn,
1000);
7845 * Wait for device to come back online and reconnect to it.
7847 * Poll each given hostname or IP address and navigate to it as soon as
7848 * one of the addresses becomes reachable.
7850 * @param {...string} [hosts=[window.location.host]]
7851 * The list of IP addresses and host names to check for reachability.
7852 * If omitted, the current value of `window.location.host` is used by
7855 awaitReconnect: function(/* ... */) {
7856 var ipaddrs = arguments.length ? arguments : [ window.location.host ];
7858 window.setTimeout(L.bind(function() {
7859 poll.add(L.bind(function() {
7860 var tasks = [], reachable = false;
7862 for (var i =
0; i
< 2; i++)
7863 for (var j =
0; j
< ipaddrs.length; j++)
7864 tasks.push(this.pingDevice(i ? 'https' : 'http', ipaddrs[j])
7865 .then(function(ev) { reachable = ev.target.src.replace(/^(https?:\/\/[^\/]+).*$/, '$
1/') }, function() {}));
7867 return Promise.all(tasks).then(function() {
7870 window.location = reachable;
7883 * The `changes` class encapsulates logic for visualizing, applying,
7884 * confirming and reverting staged UCI changesets.
7886 * This class is automatically instantiated as part of `LuCI.ui`. To use it
7887 * in views, use `'require ui'` and refer to `ui.changes`. To import it in
7888 * external JavaScript, use `L.require(
"ui").then(...)` and access the
7889 * `changes` property of the class instance value.
7891 changes: baseclass.singleton(/* @lends LuCI.ui.changes.prototype */ {
7893 if (!L.env.sessionid)
7896 return uci.changes().then(L.bind(this.renderChangeIndicator, this));
7900 * Set the change count indicator.
7902 * This function updates or hides the UCI change count indicator,
7903 * depending on the passed change count. When the count is greater
7904 * than
0, the change indicator is displayed or updated, otherwise it
7908 * @memberof LuCI.ui.changes
7910 * The number of changes to indicate.
7912 setIndicator: function(n) {
7914 UI.prototype.showIndicator('uci-changes',
7915 '%s: %d'.format(_('Unsaved Changes'), n),
7916 L.bind(this.displayChanges, this));
7919 UI.prototype.hideIndicator('uci-changes');
7924 * Update the change count indicator.
7926 * This function updates the UCI change count indicator from the given
7927 * UCI changeset structure.
7930 * @memberof LuCI.ui.changes
7931 * @param {Object
<string, Array
<LuCI.uci.ChangeRecord
>>} changes
7932 * The UCI changeset to count.
7934 renderChangeIndicator: function(changes) {
7937 for (var config in changes)
7938 if (changes.hasOwnProperty(config))
7939 n_changes += changes[config].length;
7941 this.changes = changes;
7942 this.setIndicator(n_changes);
7947 'add-
3': '
<ins
>uci add %
0 <strong
>%
3</strong
> # =%
2</ins
>',
7948 'set-
3': '
<ins
>uci set %
0.
<strong
>%
2</strong
>=%
3</ins
>',
7949 'set-
4': '
<var
><ins
>uci set %
0.%
2.%
3=
<strong
>%
4</strong
></ins
></var
>',
7950 'remove-
2': '
<del
>uci del %
0.
<strong
>%
2</strong
></del
>',
7951 'remove-
3': '
<var
><del
>uci del %
0.%
2.
<strong
>%
3</strong
></del
></var
>',
7952 'order-
3': '
<var
>uci reorder %
0.%
2=
<strong
>%
3</strong
></var
>',
7953 'list-add-
4': '
<var
><ins
>uci add_list %
0.%
2.%
3=
<strong
>%
4</strong
></ins
></var
>',
7954 'list-del-
4': '
<var
><del
>uci del_list %
0.%
2.%
3=
<strong
>%
4</strong
></del
></var
>',
7955 'rename-
3': '
<var
>uci rename %
0.%
2=
<strong
>%
3</strong
></var
>',
7956 'rename-
4': '
<var
>uci rename %
0.%
2.%
3=
<strong
>%
4</strong
></var
>'
7960 * Display the current changelog.
7962 * Open a modal dialog visualizing the currently staged UCI changes
7963 * and offer options to revert or apply the shown changes.
7966 * @memberof LuCI.ui.changes
7968 displayChanges: function() {
7969 var list = E('div', { 'class': 'uci-change-list' }),
7970 dlg = UI.prototype.showModal(_('Configuration') + ' / ' + _('Changes'), [
7971 E('div', { 'class': 'cbi-section' }, [
7972 E('strong', _('Legend:')),
7973 E('div', { 'class': 'uci-change-legend' }, [
7974 E('div', { 'class': 'uci-change-legend-label' }, [
7975 E('ins', '
&#
160;'), ' ', _('Section added') ]),
7976 E('div', { 'class': 'uci-change-legend-label' }, [
7977 E('del', '
&#
160;'), ' ', _('Section removed') ]),
7978 E('div', { 'class': 'uci-change-legend-label' }, [
7979 E('var', {}, E('ins', '
&#
160;')), ' ', _('Option changed') ]),
7980 E('div', { 'class': 'uci-change-legend-label' }, [
7981 E('var', {}, E('del', '
&#
160;')), ' ', _('Option removed') ])]),
7983 E('div', { 'class': 'right' }, [
7986 'click': UI.prototype.hideModal
7987 }, [ _('Close') ]), ' ',
7988 new UIComboButton('
0', {
7989 0: [ _('Save
& Apply') ],
7990 1: [ _('Apply unchecked') ]
7993 0: 'btn cbi-button cbi-button-positive important',
7994 1: 'btn cbi-button cbi-button-negative important'
7996 click: L.bind(function(ev, mode) { this.apply(mode == '
0') }, this)
7999 'class': 'cbi-button cbi-button-reset',
8000 'click': L.bind(this.revert, this)
8001 }, [ _('Revert') ])])])
8004 for (var config in this.changes) {
8005 if (!this.changes.hasOwnProperty(config))
8008 list.appendChild(E('h5', '# /etc/config/%s'.format(config)));
8010 for (var i =
0, added = null; i
< this.changes[config].length; i++) {
8011 var chg = this.changes[config][i],
8012 tpl = this.changeTemplates['%s-%d'.format(chg[
0], chg.length)];
8014 list.appendChild(E(tpl.replace(/%([
01234])/g, function(m0, m1) {
8020 if (added != null
&& chg[
1] == added[
0])
8021 return '@' + added[
1] + '[-
1]';
8026 return
"'%h'".format(chg[
3].replace(/'/g,
"'\"'\
"'"));
8033 if (chg[
0] == 'add')
8034 added = [ chg[
1], chg[
2] ];
8038 list.appendChild(E('br'));
8039 dlg.classList.add('uci-dialog');
8043 displayStatus: function(type, content) {
8045 var message = UI.prototype.showModal('', '');
8047 message.classList.add('alert-message');
8048 DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
8051 dom.content(message, content);
8053 if (!this.was_polling) {
8054 this.was_polling = request.poll.active();
8055 request.poll.stop();
8059 UI.prototype.hideModal();
8061 if (this.was_polling)
8062 request.poll.start();
8067 checkConnectivityAffected: function() {
8068 return L.resolveDefault(fs.exec_direct('/usr/libexec/luci-peeraddr', null, 'json')).then(L.bind(function(info) {
8069 if (L.isObject(info)
&& Array.isArray(info.inbound_interfaces)) {
8070 for (var i =
0; i
< info.inbound_interfaces.length; i++) {
8071 var iif = info.inbound_interfaces[i];
8073 for (var j =
0; this.changes
&& this.changes.network
&& j
< this.changes.network.length; j++) {
8074 var chg = this.changes.network[j];
8076 if (chg[
0] == 'set'
&& chg[
1] == iif
&& (chg[
2] == 'proto' || chg[
2] == 'ipaddr' || chg[
2] == 'netmask'))
8087 rollback: function(checked) {
8089 this.displayStatus('warning spinning',
8090 E('p', _('Failed to confirm apply within %ds, waiting for rollback…')
8091 .format(L.env.apply_rollback)));
8093 var call = function(r, data, duration) {
8094 if (r.status ===
204) {
8095 UI.prototype.changes.displayStatus('warning', [
8096 E('h4', _('Configuration changes have been rolled back!')),
8097 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)),
8098 E('div', { 'class': 'right' }, [
8101 'click': L.bind(UI.prototype.changes.displayStatus, UI.prototype.changes, false)
8102 }, [ _('Dismiss') ]), ' ',
8104 'class': 'btn cbi-button-action important',
8105 'click': L.bind(UI.prototype.changes.revert, UI.prototype.changes)
8106 }, [ _('Revert changes') ]), ' ',
8108 'class': 'btn cbi-button-negative important',
8109 'click': L.bind(UI.prototype.changes.apply, UI.prototype.changes, false)
8110 }, [ _('Apply unchecked') ])
8117 var delay = isNaN(duration) ?
0 : Math.max(
1000 - duration,
0);
8118 window.setTimeout(function() {
8119 request.request(L.url('admin/uci/confirm'), {
8121 timeout: L.env.apply_timeout *
1000,
8122 query: { sid: L.env.sessionid, token: L.env.token }
8123 }).then(call, call.bind(null, { status:
0 }, null,
0));
8127 call({ status:
0 });
8130 this.displayStatus('warning', [
8131 E('h4', _('Device unreachable!')),
8132 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.'))
8138 confirm: function(checked, deadline, override_token) {
8140 var ts = Date.now();
8142 this.displayStatus('notice');
8145 this.confirm_auth = { token: override_token };
8147 var call = function(r, data, duration) {
8148 if (Date.now()
>= deadline) {
8149 window.clearTimeout(tt);
8150 UI.prototype.changes.rollback(checked);
8153 else if (r
&& (r.status ===
200 || r.status ===
204)) {
8154 document.dispatchEvent(new CustomEvent('uci-applied'));
8156 UI.prototype.changes.setIndicator(
0);
8157 UI.prototype.changes.displayStatus('notice',
8158 E('p', _('Configuration changes applied.')));
8160 window.clearTimeout(tt);
8161 window.setTimeout(function() {
8162 //UI.prototype.changes.displayStatus(false);
8163 window.location = window.location.href.split('#')[
0];
8164 }, L.env.apply_display *
1000);
8169 var delay = isNaN(duration) ?
0 : Math.max(
1000 - duration,
0);
8170 window.setTimeout(function() {
8171 request.request(L.url('admin/uci/confirm'), {
8173 timeout: L.env.apply_timeout *
1000,
8174 query: UI.prototype.changes.confirm_auth
8175 }).then(call, call);
8179 var tick = function() {
8180 var now = Date.now();
8182 UI.prototype.changes.displayStatus('notice spinning',
8183 E('p', _('Applying configuration changes… %ds')
8184 .format(Math.max(Math.floor((deadline - Date.now()) /
1000),
0))));
8186 if (now
>= deadline)
8189 tt = window.setTimeout(tick,
1000 - (now - ts));
8195 /* wait a few seconds for the settings to become effective */
8196 window.setTimeout(call, Math.max(L.env.apply_holdoff *
1000 - ((ts + L.env.apply_rollback *
1000) - deadline),
1));
8200 * Apply the staged configuration changes.
8202 * Start applying staged configuration changes and open a modal dialog
8203 * with a progress indication to prevent interaction with the view
8204 * during the apply process. The modal dialog will be automatically
8205 * closed and the current view reloaded once the apply process is
8209 * @memberof LuCI.ui.changes
8210 * @param {boolean} [checked=false]
8211 * Whether to perform a checked (`true`) configuration apply or an
8212 * unchecked (`false`) one.
8214 * In case of a checked apply, the configuration changes must be
8215 * confirmed within a specific time interval, otherwise the device
8216 * will begin to roll back the changes in order to restore the previous
8219 apply: function(checked) {
8220 this.displayStatus('notice spinning',
8221 E('p', _('Starting configuration apply…')));
8223 (new Promise(function(resolveFn, rejectFn) {
8225 return resolveFn(false);
8227 UI.prototype.changes.checkConnectivityAffected().then(function(affected) {
8229 return resolveFn(true);
8231 UI.prototype.changes.displayStatus('warning', [
8232 E('h4', _('Connectivity change')),
8233 E('p', _('The network access to this device could be interrupted by changing settings of the
"%h" interface.').format(affected)),
8234 E('p', _('If the IP address used to access LuCI changes, a
<strong
>manual reconnect to the new IP
</strong
> is required within %d seconds to confirm the settings, otherwise modifications will be reverted.').format(L.env.apply_rollback)),
8235 E('div', { 'class': 'right' }, [
8239 }, [ _('Cancel') ]), ' ',
8241 'class': 'btn cbi-button-action important',
8242 'click': resolveFn.bind(null, true)
8243 }, [ _('Apply with revert after connectivity loss') ]), ' ',
8245 'class': 'btn cbi-button-negative important',
8246 'click': resolveFn.bind(null, false)
8247 }, [ _('Apply and keep settings') ])
8251 })).then(function(checked) {
8252 request.request(L.url('admin/uci', checked ? 'apply_rollback' : 'apply_unchecked'), {
8254 query: { sid: L.env.sessionid, token: L.env.token }
8255 }).then(function(r) {
8256 if (r.status === (checked ?
200 :
204)) {
8257 var tok = null; try { tok = r.json(); } catch(e) {}
8258 if (checked
&& tok !== null
&& typeof(tok) === 'object'
&& typeof(tok.token) === 'string')
8259 UI.prototype.changes.confirm_auth = tok;
8261 UI.prototype.changes.confirm(checked, Date.now() + L.env.apply_rollback *
1000);
8263 else if (checked
&& r.status ===
204) {
8264 UI.prototype.changes.displayStatus('notice',
8265 E('p', _('There are no changes to apply')));
8267 window.setTimeout(function() {
8268 UI.prototype.changes.displayStatus(false);
8269 }, L.env.apply_display *
1000);
8272 UI.prototype.changes.displayStatus('warning',
8273 E('p', _('Apply request failed with status
<code
>%h
</code
>')
8274 .format(r.responseText || r.statusText || r.status)));
8276 window.setTimeout(function() {
8277 UI.prototype.changes.displayStatus(false);
8278 }, L.env.apply_display *
1000);
8281 }, this.displayStatus.bind(this, false));
8285 * Revert the staged configuration changes.
8287 * Start reverting staged configuration changes and open a modal dialog
8288 * with a progress indication to prevent interaction with the view
8289 * during the revert process. The modal dialog will be automatically
8290 * closed and the current view reloaded once the revert process is
8294 * @memberof LuCI.ui.changes
8296 revert: function() {
8297 this.displayStatus('notice spinning',
8298 E('p', _('Reverting configuration…')));
8300 request.request(L.url('admin/uci/revert'), {
8302 query: { sid: L.env.sessionid, token: L.env.token }
8303 }).then(function(r) {
8304 if (r.status ===
200) {
8305 document.dispatchEvent(new CustomEvent('uci-reverted'));
8307 UI.prototype.changes.setIndicator(
0);
8308 UI.prototype.changes.displayStatus('notice',
8309 E('p', _('Changes have been reverted.')));
8311 window.setTimeout(function() {
8312 //UI.prototype.changes.displayStatus(false);
8313 window.location = window.location.href.split('#')[
0];
8314 }, L.env.apply_display *
1000);
8317 UI.prototype.changes.displayStatus('warning',
8318 E('p', _('Revert request failed with status
<code
>%h
</code
>')
8319 .format(r.statusText || r.status)));
8321 window.setTimeout(function() {
8322 UI.prototype.changes.displayStatus(false);
8323 }, L.env.apply_display *
1000);
8330 * Add validation constraints to an input element.
8332 * Compile the given type expression and optional validator function into
8333 * a validation function and bind it to the specified input element events.
8335 * @param {Node} field
8336 * The DOM input element node to bind the validation constraints to.
8338 * @param {string} type
8339 * The datatype specification to describe validation constraints.
8340 * Refer to the `LuCI.validation` class documentation for details.
8342 * @param {boolean} [optional=false]
8343 * Specifies whether empty values are allowed (`true`) or not (`false`).
8344 * If an input element is not marked optional it must not be empty,
8345 * otherwise it will be marked as invalid.
8347 * @param {function} [vfunc]
8348 * Specifies a custom validation function which is invoked after the
8349 * other validation constraints are applied. The validation must return
8350 * `true` to accept the passed value. Any other return type is converted
8351 * to a string and treated as validation error message.
8353 * @param {...string} [events=blur, keyup]
8354 * The list of events to bind. Each received event will trigger a field
8355 * validation. If omitted, the `keyup` and `blur` events are bound by
8358 * @returns {function}
8359 * Returns the compiled validator function which can be used to manually
8360 * trigger field validation or to bind it to further events.
8362 * @see LuCI.validation
8364 addValidator: function(field, type, optional, vfunc /*, ... */) {
8368 var events = this.varargs(arguments,
3);
8369 if (events.length ==
0)
8370 events.push('blur', 'keyup');
8373 var cbiValidator = validation.create(field, type, optional, vfunc),
8374 validatorFn = cbiValidator.validate.bind(cbiValidator);
8376 for (var i =
0; i
< events.length; i++)
8377 field.addEventListener(events[i], validatorFn);
8387 * Create a pre-bound event handler function.
8389 * Generate and bind a function suitable for use in event handlers. The
8390 * generated function automatically disables the event source element
8391 * and adds an active indication to it by adding appropriate CSS classes.
8393 * It will also await any promises returned by the wrapped function and
8394 * re-enable the source element after the promises ran to completion.
8397 * The `this` context to use for the wrapped function.
8399 * @param {function|string} fn
8400 * Specifies the function to wrap. In case of a function value, the
8401 * function is used as-is. If a string is specified instead, it is looked
8402 * up in `ctx` to obtain the function to wrap. In both cases the bound
8403 * function will be invoked with `ctx` as `this` context
8405 * @param {...*} extra_args
8406 * Any further parameter as passed as-is to the bound event handler
8407 * function in the same order as passed to `createHandlerFn()`.
8409 * @returns {function|null}
8410 * Returns the pre-bound handler function which is suitable to be passed
8411 * to `addEventListener()`. Returns `null` if the given `fn` argument is
8412 * a string which could not be found in `ctx` or if `ctx[fn]` is not a
8413 * valid function value.
8415 createHandlerFn: function(ctx, fn /*, ... */) {
8416 if (typeof(fn) == 'string')
8419 if (typeof(fn) != 'function')
8422 var arg_offset = arguments.length -
2;
8424 return Function.prototype.bind.apply(function() {
8425 var t = arguments[arg_offset].currentTarget;
8427 t.classList.add('spinning');
8433 Promise.resolve(fn.apply(ctx, arguments)).finally(function() {
8434 t.classList.remove('spinning');
8437 }, this.varargs(arguments,
2, ctx));
8441 * Load specified view class path and set it up.
8443 * Transforms the given view path into a class name, requires it
8444 * using [LuCI.require()]{@link LuCI#require} and asserts that the
8445 * resulting class instance is a descendant of
8446 * [LuCI.view]{@link LuCI.view}.
8448 * By instantiating the view class, its corresponding contents are
8449 * rendered and included into the view area. Any runtime errors are
8450 * caught and rendered using [LuCI.error()]{@link LuCI#error}.
8452 * @param {string} path
8453 * The view path to render.
8455 * @returns {Promise
<LuCI.view
>}
8456 * Returns a promise resolving to the loaded view instance.
8458 instantiateView: function(path) {
8459 var className = 'view.%s'.format(path.replace(/\//g, '.'));
8461 return L.require(className).then(function(view) {
8462 if (!(view instanceof View))
8463 throw new TypeError('Loaded class %s is not a descendant of View'.format(className));
8466 }).catch(function(err) {
8467 dom.content(document.querySelector('#view'), null);
8476 AbstractElement: UIElement,
8479 Textfield: UITextfield,
8480 Textarea: UITextarea,
8481 Checkbox: UICheckbox,
8483 Dropdown: UIDropdown,
8484 DynamicList: UIDynamicList,
8485 Combobox: UICombobox,
8486 ComboButton: UIComboButton,
8487 Hiddenfield: UIHiddenfield,
8488 FileUpload: UIFileUpload
8504 Documentation generated by
<a href=
"https://github.com/jsdoc3/jsdoc">JSDoc
3.6.11</a> on Sat Jan
06 2024 20:
05:
46 GMT+
0000 (Coordinated Universal Time)
8508 <script>prettyPrint();
</script>
8509 <script src=
"scripts/jaguar.js"></script>