ui.js.html 336 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Source: ui.js</title>
  6. <script src="scripts/prettify/prettify.js"></script>
  7. <script src="scripts/prettify/lang-css.js"></script>
  8. <script src="scripts/jquery.min.js"></script>
  9. <!--[if lt IE 9]>
  10. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  11. <![endif]-->
  12. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  13. <link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
  14. <link type="text/css" rel="stylesheet" href="styles/jaguar.css">
  15. <script>
  16. var config = {"monospaceLinks":true,"cleverLinks":true,"default":{"outputSourceFiles":true}};
  17. </script>
  18. </head>
  19. <body>
  20. <div id="wrap" class="clearfix">
  21. <div class="navigation">
  22. <h3 class="applicationName"><a href="index.html"></a></h3>
  23. <div class="search">
  24. <input id="search" type="text" class="form-control input-sm" placeholder="Search Documentations">
  25. </div>
  26. <ul class="list">
  27. <li class="item" data-name="LuCI">
  28. <span class="title">
  29. <a href="LuCI.html">LuCI</a>
  30. </span>
  31. <ul class="members itemMembers">
  32. <span class="subtitle">Members</span>
  33. <li data-name="LuCI#Class"><a href="LuCI.html#Class">Class</a></li>
  34. <li data-name="LuCI#dom"><a href="LuCI.html#dom">dom</a></li>
  35. <li data-name="LuCI#env"><a href="LuCI.html#env">env</a></li>
  36. <li data-name="LuCI#naturalCompare"><a href="LuCI.html#naturalCompare">naturalCompare</a></li>
  37. <li data-name="LuCI#Poll"><a href="LuCI.html#Poll">Poll</a></li>
  38. <li data-name="LuCI#Request"><a href="LuCI.html#Request">Request</a></li>
  39. <li data-name="LuCI#view"><a href="LuCI.html#view">view</a></li>
  40. </ul>
  41. <ul class="typedefs itemMembers">
  42. <span class="subtitle">Typedefs</span>
  43. <li data-name="LuCI.requestCallbackFn"><a href="LuCI.html#.requestCallbackFn">requestCallbackFn</a></li>
  44. </ul>
  45. <ul class="typedefs itemMembers">
  46. </ul>
  47. <ul class="methods itemMembers">
  48. <span class="subtitle">Methods</span>
  49. <li data-name="LuCI#bind"><a href="LuCI.html#bind">bind</a></li>
  50. <li data-name="LuCI#error"><a href="LuCI.html#error">error</a></li>
  51. <li data-name="LuCI#fspath"><a href="LuCI.html#fspath">fspath</a></li>
  52. <li data-name="LuCI#get"><a href="LuCI.html#get">get</a></li>
  53. <li data-name="LuCI#halt"><a href="LuCI.html#halt">halt</a></li>
  54. <li data-name="LuCI#hasSystemFeature"><a href="LuCI.html#hasSystemFeature">hasSystemFeature</a></li>
  55. <li data-name="LuCI#hasViewPermission"><a href="LuCI.html#hasViewPermission">hasViewPermission</a></li>
  56. <li data-name="LuCI#isObject"><a href="LuCI.html#isObject">isObject</a></li>
  57. <li data-name="LuCI#location"><a href="LuCI.html#location">location</a></li>
  58. <li data-name="LuCI#media"><a href="LuCI.html#media">media</a></li>
  59. <li data-name="LuCI#path"><a href="LuCI.html#path">path</a></li>
  60. <li data-name="LuCI#poll"><a href="LuCI.html#poll">poll</a></li>
  61. <li data-name="LuCI#post"><a href="LuCI.html#post">post</a></li>
  62. <li data-name="LuCI#raise"><a href="LuCI.html#raise">raise</a></li>
  63. <li data-name="LuCI#require"><a href="LuCI.html#require">require</a></li>
  64. <li data-name="LuCI#resolveDefault"><a href="LuCI.html#resolveDefault">resolveDefault</a></li>
  65. <li data-name="LuCI#resource"><a href="LuCI.html#resource">resource</a></li>
  66. <li data-name="LuCI#run"><a href="LuCI.html#run">run</a></li>
  67. <li data-name="LuCI#sortedArray"><a href="LuCI.html#sortedArray">sortedArray</a></li>
  68. <li data-name="LuCI#sortedKeys"><a href="LuCI.html#sortedKeys">sortedKeys</a></li>
  69. <li data-name="LuCI#stop"><a href="LuCI.html#stop">stop</a></li>
  70. <li data-name="LuCI#toArray"><a href="LuCI.html#toArray">toArray</a></li>
  71. <li data-name="LuCI#url"><a href="LuCI.html#url">url</a></li>
  72. </ul>
  73. <ul class="events itemMembers">
  74. </ul>
  75. </li>
  76. <li class="item" data-name="LuCI.baseclass">
  77. <span class="title">
  78. <a href="LuCI.baseclass.html">LuCI.baseclass</a>
  79. </span>
  80. <ul class="members itemMembers">
  81. </ul>
  82. <ul class="typedefs itemMembers">
  83. </ul>
  84. <ul class="typedefs itemMembers">
  85. </ul>
  86. <ul class="methods itemMembers">
  87. <span class="subtitle">Methods</span>
  88. <li data-name="LuCI.baseclass.extend"><a href="LuCI.baseclass.html#.extend">extend</a></li>
  89. <li data-name="LuCI.baseclass.instantiate"><a href="LuCI.baseclass.html#.instantiate">instantiate</a></li>
  90. <li data-name="LuCI.baseclass.isSubclass"><a href="LuCI.baseclass.html#.isSubclass">isSubclass</a></li>
  91. <li data-name="LuCI.baseclass.singleton"><a href="LuCI.baseclass.html#.singleton">singleton</a></li>
  92. <li data-name="LuCI.baseclass#super"><a href="LuCI.baseclass.html#super">super</a></li>
  93. <li data-name="LuCI.baseclass#varargs"><a href="LuCI.baseclass.html#varargs">varargs</a></li>
  94. </ul>
  95. <ul class="events itemMembers">
  96. </ul>
  97. </li>
  98. <li class="item" data-name="LuCI.dom">
  99. <span class="title">
  100. <a href="LuCI.dom.html">LuCI.dom</a>
  101. </span>
  102. <ul class="members itemMembers">
  103. </ul>
  104. <ul class="typedefs itemMembers">
  105. <span class="subtitle">Typedefs</span>
  106. <li data-name="LuCI.dom~ignoreCallbackFn"><a href="LuCI.dom.html#~ignoreCallbackFn">ignoreCallbackFn</a></li>
  107. </ul>
  108. <ul class="typedefs itemMembers">
  109. </ul>
  110. <ul class="methods itemMembers">
  111. <span class="subtitle">Methods</span>
  112. <li data-name="LuCI.dom#append"><a href="LuCI.dom.html#append">append</a></li>
  113. <li data-name="LuCI.dom#attr"><a href="LuCI.dom.html#attr">attr</a></li>
  114. <li data-name="LuCI.dom#bindClassInstance"><a href="LuCI.dom.html#bindClassInstance">bindClassInstance</a></li>
  115. <li data-name="LuCI.dom#callClassMethod"><a href="LuCI.dom.html#callClassMethod">callClassMethod</a></li>
  116. <li data-name="LuCI.dom#content"><a href="LuCI.dom.html#content">content</a></li>
  117. <li data-name="LuCI.dom#create"><a href="LuCI.dom.html#create">create</a></li>
  118. <li data-name="LuCI.dom#data"><a href="LuCI.dom.html#data">data</a></li>
  119. <li data-name="LuCI.dom#elem"><a href="LuCI.dom.html#elem">elem</a></li>
  120. <li data-name="LuCI.dom#findClassInstance"><a href="LuCI.dom.html#findClassInstance">findClassInstance</a></li>
  121. <li data-name="LuCI.dom#isEmpty"><a href="LuCI.dom.html#isEmpty">isEmpty</a></li>
  122. <li data-name="LuCI.dom#matches"><a href="LuCI.dom.html#matches">matches</a></li>
  123. <li data-name="LuCI.dom#parent"><a href="LuCI.dom.html#parent">parent</a></li>
  124. <li data-name="LuCI.dom#parse"><a href="LuCI.dom.html#parse">parse</a></li>
  125. </ul>
  126. <ul class="events itemMembers">
  127. </ul>
  128. </li>
  129. <li class="item" data-name="LuCI.form">
  130. <span class="title">
  131. <a href="LuCI.form.html">LuCI.form</a>
  132. </span>
  133. <ul class="members itemMembers">
  134. </ul>
  135. <ul class="typedefs itemMembers">
  136. </ul>
  137. <ul class="typedefs itemMembers">
  138. </ul>
  139. <ul class="methods itemMembers">
  140. </ul>
  141. <ul class="events itemMembers">
  142. </ul>
  143. </li>
  144. <li class="item" data-name="LuCI.form.AbstractElement">
  145. <span class="title">
  146. <a href="LuCI.form.AbstractElement.html">LuCI.form.AbstractElement</a>
  147. </span>
  148. <ul class="members itemMembers">
  149. </ul>
  150. <ul class="typedefs itemMembers">
  151. </ul>
  152. <ul class="typedefs itemMembers">
  153. </ul>
  154. <ul class="methods itemMembers">
  155. <span class="subtitle">Methods</span>
  156. <li data-name="LuCI.form.AbstractElement#append"><a href="LuCI.form.AbstractElement.html#append">append</a></li>
  157. <li data-name="LuCI.form.AbstractElement#parse"><a href="LuCI.form.AbstractElement.html#parse">parse</a></li>
  158. <li data-name="LuCI.form.AbstractElement#render"><a href="LuCI.form.AbstractElement.html#render">render</a></li>
  159. <li data-name="LuCI.form.AbstractElement#stripTags"><a href="LuCI.form.AbstractElement.html#stripTags">stripTags</a></li>
  160. <li data-name="LuCI.form.AbstractElement#titleFn"><a href="LuCI.form.AbstractElement.html#titleFn">titleFn</a></li>
  161. </ul>
  162. <ul class="events itemMembers">
  163. </ul>
  164. </li>
  165. <li class="item" data-name="LuCI.form.AbstractSection">
  166. <span class="title">
  167. <a href="LuCI.form.AbstractSection.html">LuCI.form.AbstractSection</a>
  168. </span>
  169. <ul class="members itemMembers">
  170. <span class="subtitle">Members</span>
  171. <li data-name="LuCI.form.AbstractSection##parentoption"><a href="LuCI.form.AbstractSection.html#parentoption">parentoption</a></li>
  172. </ul>
  173. <ul class="typedefs itemMembers">
  174. </ul>
  175. <ul class="typedefs itemMembers">
  176. </ul>
  177. <ul class="methods itemMembers">
  178. <span class="subtitle">Methods</span>
  179. <li data-name="LuCI.form.AbstractSection#append"><a href="LuCI.form.AbstractSection.html#append">append</a></li>
  180. <li data-name="LuCI.form.AbstractSection#cfgsections"><a href="LuCI.form.AbstractSection.html#cfgsections">cfgsections</a></li>
  181. <li data-name="LuCI.form.AbstractSection#cfgvalue"><a href="LuCI.form.AbstractSection.html#cfgvalue">cfgvalue</a></li>
  182. <li data-name="LuCI.form.AbstractSection#filter"><a href="LuCI.form.AbstractSection.html#filter">filter</a></li>
  183. <li data-name="LuCI.form.AbstractSection#formvalue"><a href="LuCI.form.AbstractSection.html#formvalue">formvalue</a></li>
  184. <li data-name="LuCI.form.AbstractSection#getOption"><a href="LuCI.form.AbstractSection.html#getOption">getOption</a></li>
  185. <li data-name="LuCI.form.AbstractSection#getUIElement"><a href="LuCI.form.AbstractSection.html#getUIElement">getUIElement</a></li>
  186. <li data-name="LuCI.form.AbstractSection#load"><a href="LuCI.form.AbstractSection.html#load">load</a></li>
  187. <li data-name="LuCI.form.AbstractSection#option"><a href="LuCI.form.AbstractSection.html#option">option</a></li>
  188. <li data-name="LuCI.form.AbstractSection#parse"><a href="LuCI.form.AbstractSection.html#parse">parse</a></li>
  189. <li data-name="LuCI.form.AbstractSection#render"><a href="LuCI.form.AbstractSection.html#render">render</a></li>
  190. <li data-name="LuCI.form.AbstractSection#stripTags"><a href="LuCI.form.AbstractSection.html#stripTags">stripTags</a></li>
  191. <li data-name="LuCI.form.AbstractSection#tab"><a href="LuCI.form.AbstractSection.html#tab">tab</a></li>
  192. <li data-name="LuCI.form.AbstractSection#taboption"><a href="LuCI.form.AbstractSection.html#taboption">taboption</a></li>
  193. <li data-name="LuCI.form.AbstractSection#titleFn"><a href="LuCI.form.AbstractSection.html#titleFn">titleFn</a></li>
  194. </ul>
  195. <ul class="events itemMembers">
  196. </ul>
  197. </li>
  198. <li class="item" data-name="LuCI.form.AbstractValue">
  199. <span class="title">
  200. <a href="LuCI.form.AbstractValue.html">LuCI.form.AbstractValue</a>
  201. </span>
  202. <ul class="members itemMembers">
  203. <span class="subtitle">Members</span>
  204. <li data-name="LuCI.form.AbstractValue##datatype"><a href="LuCI.form.AbstractValue.html#datatype">datatype</a></li>
  205. <li data-name="LuCI.form.AbstractValue##default"><a href="LuCI.form.AbstractValue.html#default">default</a></li>
  206. <li data-name="LuCI.form.AbstractValue##editable"><a href="LuCI.form.AbstractValue.html#editable">editable</a></li>
  207. <li data-name="LuCI.form.AbstractValue##modalonly"><a href="LuCI.form.AbstractValue.html#modalonly">modalonly</a></li>
  208. <li data-name="LuCI.form.AbstractValue##onchange"><a href="LuCI.form.AbstractValue.html#onchange">onchange</a></li>
  209. <li data-name="LuCI.form.AbstractValue##optional"><a href="LuCI.form.AbstractValue.html#optional">optional</a></li>
  210. <li data-name="LuCI.form.AbstractValue##readonly"><a href="LuCI.form.AbstractValue.html#readonly">readonly</a></li>
  211. <li data-name="LuCI.form.AbstractValue##retain"><a href="LuCI.form.AbstractValue.html#retain">retain</a></li>
  212. <li data-name="LuCI.form.AbstractValue##rmempty"><a href="LuCI.form.AbstractValue.html#rmempty">rmempty</a></li>
  213. <li data-name="LuCI.form.AbstractValue##uciconfig"><a href="LuCI.form.AbstractValue.html#uciconfig">uciconfig</a></li>
  214. <li data-name="LuCI.form.AbstractValue##ucioption"><a href="LuCI.form.AbstractValue.html#ucioption">ucioption</a></li>
  215. <li data-name="LuCI.form.AbstractValue##ucisection"><a href="LuCI.form.AbstractValue.html#ucisection">ucisection</a></li>
  216. <li data-name="LuCI.form.AbstractValue##validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
  217. <li data-name="LuCI.form.AbstractValue##width"><a href="LuCI.form.AbstractValue.html#width">width</a></li>
  218. </ul>
  219. <ul class="typedefs itemMembers">
  220. </ul>
  221. <ul class="typedefs itemMembers">
  222. </ul>
  223. <ul class="methods itemMembers">
  224. <span class="subtitle">Methods</span>
  225. <li data-name="LuCI.form.AbstractValue#append"><a href="LuCI.form.AbstractValue.html#append">append</a></li>
  226. <li data-name="LuCI.form.AbstractValue#cbid"><a href="LuCI.form.AbstractValue.html#cbid">cbid</a></li>
  227. <li data-name="LuCI.form.AbstractValue#cfgvalue"><a href="LuCI.form.AbstractValue.html#cfgvalue">cfgvalue</a></li>
  228. <li data-name="LuCI.form.AbstractValue#depends"><a href="LuCI.form.AbstractValue.html#depends">depends</a></li>
  229. <li data-name="LuCI.form.AbstractValue#formvalue"><a href="LuCI.form.AbstractValue.html#formvalue">formvalue</a></li>
  230. <li data-name="LuCI.form.AbstractValue#getUIElement"><a href="LuCI.form.AbstractValue.html#getUIElement">getUIElement</a></li>
  231. <li data-name="LuCI.form.AbstractValue#getValidationError"><a href="LuCI.form.AbstractValue.html#getValidationError">getValidationError</a></li>
  232. <li data-name="LuCI.form.AbstractValue#isActive"><a href="LuCI.form.AbstractValue.html#isActive">isActive</a></li>
  233. <li data-name="LuCI.form.AbstractValue#isValid"><a href="LuCI.form.AbstractValue.html#isValid">isValid</a></li>
  234. <li data-name="LuCI.form.AbstractValue#load"><a href="LuCI.form.AbstractValue.html#load">load</a></li>
  235. <li data-name="LuCI.form.AbstractValue#parse"><a href="LuCI.form.AbstractValue.html#parse">parse</a></li>
  236. <li data-name="LuCI.form.AbstractValue#remove"><a href="LuCI.form.AbstractValue.html#remove">remove</a></li>
  237. <li data-name="LuCI.form.AbstractValue#render"><a href="LuCI.form.AbstractValue.html#render">render</a></li>
  238. <li data-name="LuCI.form.AbstractValue#stripTags"><a href="LuCI.form.AbstractValue.html#stripTags">stripTags</a></li>
  239. <li data-name="LuCI.form.AbstractValue#textvalue"><a href="LuCI.form.AbstractValue.html#textvalue">textvalue</a></li>
  240. <li data-name="LuCI.form.AbstractValue#titleFn"><a href="LuCI.form.AbstractValue.html#titleFn">titleFn</a></li>
  241. <li data-name="LuCI.form.AbstractValue#validate"><a href="LuCI.form.AbstractValue.html#validate">validate</a></li>
  242. <li data-name="LuCI.form.AbstractValue#write"><a href="LuCI.form.AbstractValue.html#write">write</a></li>
  243. </ul>
  244. <ul class="events itemMembers">
  245. </ul>
  246. </li>
  247. <li class="item" data-name="LuCI.form.ButtonValue">
  248. <span class="title">
  249. <a href="LuCI.form.ButtonValue.html">LuCI.form.ButtonValue</a>
  250. </span>
  251. <ul class="members itemMembers">
  252. <span class="subtitle">Members</span>
  253. <li data-name="LuCI.form.ButtonValue##inputstyle"><a href="LuCI.form.ButtonValue.html#inputstyle">inputstyle</a></li>
  254. <li data-name="LuCI.form.ButtonValue##inputtitle"><a href="LuCI.form.ButtonValue.html#inputtitle">inputtitle</a></li>
  255. <li data-name="LuCI.form.ButtonValue##onclick"><a href="LuCI.form.ButtonValue.html#onclick">onclick</a></li>
  256. <li data-name="LuCI.form.ButtonValue#datatype"><a href="LuCI.form.ButtonValue.html#datatype">datatype</a></li>
  257. <li data-name="LuCI.form.ButtonValue#default"><a href="LuCI.form.ButtonValue.html#default">default</a></li>
  258. <li data-name="LuCI.form.ButtonValue#editable"><a href="LuCI.form.ButtonValue.html#editable">editable</a></li>
  259. <li data-name="LuCI.form.ButtonValue#modalonly"><a href="LuCI.form.ButtonValue.html#modalonly">modalonly</a></li>
  260. <li data-name="LuCI.form.ButtonValue#onchange"><a href="LuCI.form.ButtonValue.html#onchange">onchange</a></li>
  261. <li data-name="LuCI.form.ButtonValue#optional"><a href="LuCI.form.ButtonValue.html#optional">optional</a></li>
  262. <li data-name="LuCI.form.ButtonValue#password"><a href="LuCI.form.ButtonValue.html#password">password</a></li>
  263. <li data-name="LuCI.form.ButtonValue#placeholder"><a href="LuCI.form.ButtonValue.html#placeholder">placeholder</a></li>
  264. <li data-name="LuCI.form.ButtonValue#readonly"><a href="LuCI.form.ButtonValue.html#readonly">readonly</a></li>
  265. <li data-name="LuCI.form.ButtonValue#retain"><a href="LuCI.form.ButtonValue.html#retain">retain</a></li>
  266. <li data-name="LuCI.form.ButtonValue#rmempty"><a href="LuCI.form.ButtonValue.html#rmempty">rmempty</a></li>
  267. <li data-name="LuCI.form.ButtonValue#uciconfig"><a href="LuCI.form.ButtonValue.html#uciconfig">uciconfig</a></li>
  268. <li data-name="LuCI.form.ButtonValue#ucioption"><a href="LuCI.form.ButtonValue.html#ucioption">ucioption</a></li>
  269. <li data-name="LuCI.form.ButtonValue#ucisection"><a href="LuCI.form.ButtonValue.html#ucisection">ucisection</a></li>
  270. <li data-name="LuCI.form.ButtonValue#validate"><a href="LuCI.form.ButtonValue.html#validate">validate</a></li>
  271. <li data-name="LuCI.form.ButtonValue#width"><a href="LuCI.form.ButtonValue.html#width">width</a></li>
  272. </ul>
  273. <ul class="typedefs itemMembers">
  274. </ul>
  275. <ul class="typedefs itemMembers">
  276. </ul>
  277. <ul class="methods itemMembers">
  278. <span class="subtitle">Methods</span>
  279. <li data-name="LuCI.form.ButtonValue#append"><a href="LuCI.form.ButtonValue.html#append">append</a></li>
  280. <li data-name="LuCI.form.ButtonValue#cbid"><a href="LuCI.form.ButtonValue.html#cbid">cbid</a></li>
  281. <li data-name="LuCI.form.ButtonValue#cfgvalue"><a href="LuCI.form.ButtonValue.html#cfgvalue">cfgvalue</a></li>
  282. <li data-name="LuCI.form.ButtonValue#depends"><a href="LuCI.form.ButtonValue.html#depends">depends</a></li>
  283. <li data-name="LuCI.form.ButtonValue#formvalue"><a href="LuCI.form.ButtonValue.html#formvalue">formvalue</a></li>
  284. <li data-name="LuCI.form.ButtonValue#getUIElement"><a href="LuCI.form.ButtonValue.html#getUIElement">getUIElement</a></li>
  285. <li data-name="LuCI.form.ButtonValue#getValidationError"><a href="LuCI.form.ButtonValue.html#getValidationError">getValidationError</a></li>
  286. <li data-name="LuCI.form.ButtonValue#isActive"><a href="LuCI.form.ButtonValue.html#isActive">isActive</a></li>
  287. <li data-name="LuCI.form.ButtonValue#isValid"><a href="LuCI.form.ButtonValue.html#isValid">isValid</a></li>
  288. <li data-name="LuCI.form.ButtonValue#load"><a href="LuCI.form.ButtonValue.html#load">load</a></li>
  289. <li data-name="LuCI.form.ButtonValue#parse"><a href="LuCI.form.ButtonValue.html#parse">parse</a></li>
  290. <li data-name="LuCI.form.ButtonValue#remove"><a href="LuCI.form.ButtonValue.html#remove">remove</a></li>
  291. <li data-name="LuCI.form.ButtonValue#stripTags"><a href="LuCI.form.ButtonValue.html#stripTags">stripTags</a></li>
  292. <li data-name="LuCI.form.ButtonValue#textvalue"><a href="LuCI.form.ButtonValue.html#textvalue">textvalue</a></li>
  293. <li data-name="LuCI.form.ButtonValue#titleFn"><a href="LuCI.form.ButtonValue.html#titleFn">titleFn</a></li>
  294. <li data-name="LuCI.form.ButtonValue#value"><a href="LuCI.form.ButtonValue.html#value">value</a></li>
  295. <li data-name="LuCI.form.ButtonValue#write"><a href="LuCI.form.ButtonValue.html#write">write</a></li>
  296. </ul>
  297. <ul class="events itemMembers">
  298. </ul>
  299. </li>
  300. <li class="item" data-name="LuCI.form.DummyValue">
  301. <span class="title">
  302. <a href="LuCI.form.DummyValue.html">LuCI.form.DummyValue</a>
  303. </span>
  304. <ul class="members itemMembers">
  305. <span class="subtitle">Members</span>
  306. <li data-name="LuCI.form.DummyValue##hidden"><a href="LuCI.form.DummyValue.html#hidden">hidden</a></li>
  307. <li data-name="LuCI.form.DummyValue##href"><a href="LuCI.form.DummyValue.html#href">href</a></li>
  308. <li data-name="LuCI.form.DummyValue##rawhtml"><a href="LuCI.form.DummyValue.html#rawhtml">rawhtml</a></li>
  309. <li data-name="LuCI.form.DummyValue#datatype"><a href="LuCI.form.DummyValue.html#datatype">datatype</a></li>
  310. <li data-name="LuCI.form.DummyValue#default"><a href="LuCI.form.DummyValue.html#default">default</a></li>
  311. <li data-name="LuCI.form.DummyValue#editable"><a href="LuCI.form.DummyValue.html#editable">editable</a></li>
  312. <li data-name="LuCI.form.DummyValue#modalonly"><a href="LuCI.form.DummyValue.html#modalonly">modalonly</a></li>
  313. <li data-name="LuCI.form.DummyValue#onchange"><a href="LuCI.form.DummyValue.html#onchange">onchange</a></li>
  314. <li data-name="LuCI.form.DummyValue#optional"><a href="LuCI.form.DummyValue.html#optional">optional</a></li>
  315. <li data-name="LuCI.form.DummyValue#password"><a href="LuCI.form.DummyValue.html#password">password</a></li>
  316. <li data-name="LuCI.form.DummyValue#placeholder"><a href="LuCI.form.DummyValue.html#placeholder">placeholder</a></li>
  317. <li data-name="LuCI.form.DummyValue#readonly"><a href="LuCI.form.DummyValue.html#readonly">readonly</a></li>
  318. <li data-name="LuCI.form.DummyValue#retain"><a href="LuCI.form.DummyValue.html#retain">retain</a></li>
  319. <li data-name="LuCI.form.DummyValue#rmempty"><a href="LuCI.form.DummyValue.html#rmempty">rmempty</a></li>
  320. <li data-name="LuCI.form.DummyValue#uciconfig"><a href="LuCI.form.DummyValue.html#uciconfig">uciconfig</a></li>
  321. <li data-name="LuCI.form.DummyValue#ucioption"><a href="LuCI.form.DummyValue.html#ucioption">ucioption</a></li>
  322. <li data-name="LuCI.form.DummyValue#ucisection"><a href="LuCI.form.DummyValue.html#ucisection">ucisection</a></li>
  323. <li data-name="LuCI.form.DummyValue#validate"><a href="LuCI.form.DummyValue.html#validate">validate</a></li>
  324. <li data-name="LuCI.form.DummyValue#width"><a href="LuCI.form.DummyValue.html#width">width</a></li>
  325. </ul>
  326. <ul class="typedefs itemMembers">
  327. </ul>
  328. <ul class="typedefs itemMembers">
  329. </ul>
  330. <ul class="methods itemMembers">
  331. <span class="subtitle">Methods</span>
  332. <li data-name="LuCI.form.DummyValue#append"><a href="LuCI.form.DummyValue.html#append">append</a></li>
  333. <li data-name="LuCI.form.DummyValue#cbid"><a href="LuCI.form.DummyValue.html#cbid">cbid</a></li>
  334. <li data-name="LuCI.form.DummyValue#cfgvalue"><a href="LuCI.form.DummyValue.html#cfgvalue">cfgvalue</a></li>
  335. <li data-name="LuCI.form.DummyValue#depends"><a href="LuCI.form.DummyValue.html#depends">depends</a></li>
  336. <li data-name="LuCI.form.DummyValue#formvalue"><a href="LuCI.form.DummyValue.html#formvalue">formvalue</a></li>
  337. <li data-name="LuCI.form.DummyValue#getUIElement"><a href="LuCI.form.DummyValue.html#getUIElement">getUIElement</a></li>
  338. <li data-name="LuCI.form.DummyValue#getValidationError"><a href="LuCI.form.DummyValue.html#getValidationError">getValidationError</a></li>
  339. <li data-name="LuCI.form.DummyValue#isActive"><a href="LuCI.form.DummyValue.html#isActive">isActive</a></li>
  340. <li data-name="LuCI.form.DummyValue#isValid"><a href="LuCI.form.DummyValue.html#isValid">isValid</a></li>
  341. <li data-name="LuCI.form.DummyValue#load"><a href="LuCI.form.DummyValue.html#load">load</a></li>
  342. <li data-name="LuCI.form.DummyValue#parse"><a href="LuCI.form.DummyValue.html#parse">parse</a></li>
  343. <li data-name="LuCI.form.DummyValue#remove"><a href="LuCI.form.DummyValue.html#remove">remove</a></li>
  344. <li data-name="LuCI.form.DummyValue#stripTags"><a href="LuCI.form.DummyValue.html#stripTags">stripTags</a></li>
  345. <li data-name="LuCI.form.DummyValue#textvalue"><a href="LuCI.form.DummyValue.html#textvalue">textvalue</a></li>
  346. <li data-name="LuCI.form.DummyValue#titleFn"><a href="LuCI.form.DummyValue.html#titleFn">titleFn</a></li>
  347. <li data-name="LuCI.form.DummyValue#value"><a href="LuCI.form.DummyValue.html#value">value</a></li>
  348. <li data-name="LuCI.form.DummyValue#write"><a href="LuCI.form.DummyValue.html#write">write</a></li>
  349. </ul>
  350. <ul class="events itemMembers">
  351. </ul>
  352. </li>
  353. <li class="item" data-name="LuCI.form.DynamicList">
  354. <span class="title">
  355. <a href="LuCI.form.DynamicList.html">LuCI.form.DynamicList</a>
  356. </span>
  357. <ul class="members itemMembers">
  358. <span class="subtitle">Members</span>
  359. <li data-name="LuCI.form.DynamicList#datatype"><a href="LuCI.form.DynamicList.html#datatype">datatype</a></li>
  360. <li data-name="LuCI.form.DynamicList#default"><a href="LuCI.form.DynamicList.html#default">default</a></li>
  361. <li data-name="LuCI.form.DynamicList#editable"><a href="LuCI.form.DynamicList.html#editable">editable</a></li>
  362. <li data-name="LuCI.form.DynamicList#modalonly"><a href="LuCI.form.DynamicList.html#modalonly">modalonly</a></li>
  363. <li data-name="LuCI.form.DynamicList#onchange"><a href="LuCI.form.DynamicList.html#onchange">onchange</a></li>
  364. <li data-name="LuCI.form.DynamicList#optional"><a href="LuCI.form.DynamicList.html#optional">optional</a></li>
  365. <li data-name="LuCI.form.DynamicList#password"><a href="LuCI.form.DynamicList.html#password">password</a></li>
  366. <li data-name="LuCI.form.DynamicList#placeholder"><a href="LuCI.form.DynamicList.html#placeholder">placeholder</a></li>
  367. <li data-name="LuCI.form.DynamicList#readonly"><a href="LuCI.form.DynamicList.html#readonly">readonly</a></li>
  368. <li data-name="LuCI.form.DynamicList#retain"><a href="LuCI.form.DynamicList.html#retain">retain</a></li>
  369. <li data-name="LuCI.form.DynamicList#rmempty"><a href="LuCI.form.DynamicList.html#rmempty">rmempty</a></li>
  370. <li data-name="LuCI.form.DynamicList#uciconfig"><a href="LuCI.form.DynamicList.html#uciconfig">uciconfig</a></li>
  371. <li data-name="LuCI.form.DynamicList#ucioption"><a href="LuCI.form.DynamicList.html#ucioption">ucioption</a></li>
  372. <li data-name="LuCI.form.DynamicList#ucisection"><a href="LuCI.form.DynamicList.html#ucisection">ucisection</a></li>
  373. <li data-name="LuCI.form.DynamicList#validate"><a href="LuCI.form.DynamicList.html#validate">validate</a></li>
  374. <li data-name="LuCI.form.DynamicList#width"><a href="LuCI.form.DynamicList.html#width">width</a></li>
  375. </ul>
  376. <ul class="typedefs itemMembers">
  377. </ul>
  378. <ul class="typedefs itemMembers">
  379. </ul>
  380. <ul class="methods itemMembers">
  381. <span class="subtitle">Methods</span>
  382. <li data-name="LuCI.form.DynamicList#append"><a href="LuCI.form.DynamicList.html#append">append</a></li>
  383. <li data-name="LuCI.form.DynamicList#cbid"><a href="LuCI.form.DynamicList.html#cbid">cbid</a></li>
  384. <li data-name="LuCI.form.DynamicList#cfgvalue"><a href="LuCI.form.DynamicList.html#cfgvalue">cfgvalue</a></li>
  385. <li data-name="LuCI.form.DynamicList#depends"><a href="LuCI.form.DynamicList.html#depends">depends</a></li>
  386. <li data-name="LuCI.form.DynamicList#formvalue"><a href="LuCI.form.DynamicList.html#formvalue">formvalue</a></li>
  387. <li data-name="LuCI.form.DynamicList#getUIElement"><a href="LuCI.form.DynamicList.html#getUIElement">getUIElement</a></li>
  388. <li data-name="LuCI.form.DynamicList#getValidationError"><a href="LuCI.form.DynamicList.html#getValidationError">getValidationError</a></li>
  389. <li data-name="LuCI.form.DynamicList#isActive"><a href="LuCI.form.DynamicList.html#isActive">isActive</a></li>
  390. <li data-name="LuCI.form.DynamicList#isValid"><a href="LuCI.form.DynamicList.html#isValid">isValid</a></li>
  391. <li data-name="LuCI.form.DynamicList#load"><a href="LuCI.form.DynamicList.html#load">load</a></li>
  392. <li data-name="LuCI.form.DynamicList#parse"><a href="LuCI.form.DynamicList.html#parse">parse</a></li>
  393. <li data-name="LuCI.form.DynamicList#remove"><a href="LuCI.form.DynamicList.html#remove">remove</a></li>
  394. <li data-name="LuCI.form.DynamicList#stripTags"><a href="LuCI.form.DynamicList.html#stripTags">stripTags</a></li>
  395. <li data-name="LuCI.form.DynamicList#textvalue"><a href="LuCI.form.DynamicList.html#textvalue">textvalue</a></li>
  396. <li data-name="LuCI.form.DynamicList#titleFn"><a href="LuCI.form.DynamicList.html#titleFn">titleFn</a></li>
  397. <li data-name="LuCI.form.DynamicList#value"><a href="LuCI.form.DynamicList.html#value">value</a></li>
  398. <li data-name="LuCI.form.DynamicList#write"><a href="LuCI.form.DynamicList.html#write">write</a></li>
  399. </ul>
  400. <ul class="events itemMembers">
  401. </ul>
  402. </li>
  403. <li class="item" data-name="LuCI.form.FileUpload">
  404. <span class="title">
  405. <a href="LuCI.form.FileUpload.html">LuCI.form.FileUpload</a>
  406. </span>
  407. <ul class="members itemMembers">
  408. <span class="subtitle">Members</span>
  409. <li data-name="LuCI.form.FileUpload##browser"><a href="LuCI.form.FileUpload.html#browser">browser</a></li>
  410. <li data-name="LuCI.form.FileUpload##enable_download"><a href="LuCI.form.FileUpload.html#enable_download">enable_download</a></li>
  411. <li data-name="LuCI.form.FileUpload##enable_remove"><a href="LuCI.form.FileUpload.html#enable_remove">enable_remove</a></li>
  412. <li data-name="LuCI.form.FileUpload##enable_upload"><a href="LuCI.form.FileUpload.html#enable_upload">enable_upload</a></li>
  413. <li data-name="LuCI.form.FileUpload##root_directory"><a href="LuCI.form.FileUpload.html#root_directory">root_directory</a></li>
  414. <li data-name="LuCI.form.FileUpload##show_hidden"><a href="LuCI.form.FileUpload.html#show_hidden">show_hidden</a></li>
  415. <li data-name="LuCI.form.FileUpload#datatype"><a href="LuCI.form.FileUpload.html#datatype">datatype</a></li>
  416. <li data-name="LuCI.form.FileUpload#default"><a href="LuCI.form.FileUpload.html#default">default</a></li>
  417. <li data-name="LuCI.form.FileUpload#editable"><a href="LuCI.form.FileUpload.html#editable">editable</a></li>
  418. <li data-name="LuCI.form.FileUpload#modalonly"><a href="LuCI.form.FileUpload.html#modalonly">modalonly</a></li>
  419. <li data-name="LuCI.form.FileUpload#onchange"><a href="LuCI.form.FileUpload.html#onchange">onchange</a></li>
  420. <li data-name="LuCI.form.FileUpload#optional"><a href="LuCI.form.FileUpload.html#optional">optional</a></li>
  421. <li data-name="LuCI.form.FileUpload#password"><a href="LuCI.form.FileUpload.html#password">password</a></li>
  422. <li data-name="LuCI.form.FileUpload#placeholder"><a href="LuCI.form.FileUpload.html#placeholder">placeholder</a></li>
  423. <li data-name="LuCI.form.FileUpload#readonly"><a href="LuCI.form.FileUpload.html#readonly">readonly</a></li>
  424. <li data-name="LuCI.form.FileUpload#retain"><a href="LuCI.form.FileUpload.html#retain">retain</a></li>
  425. <li data-name="LuCI.form.FileUpload#rmempty"><a href="LuCI.form.FileUpload.html#rmempty">rmempty</a></li>
  426. <li data-name="LuCI.form.FileUpload#uciconfig"><a href="LuCI.form.FileUpload.html#uciconfig">uciconfig</a></li>
  427. <li data-name="LuCI.form.FileUpload#ucioption"><a href="LuCI.form.FileUpload.html#ucioption">ucioption</a></li>
  428. <li data-name="LuCI.form.FileUpload#ucisection"><a href="LuCI.form.FileUpload.html#ucisection">ucisection</a></li>
  429. <li data-name="LuCI.form.FileUpload#validate"><a href="LuCI.form.FileUpload.html#validate">validate</a></li>
  430. <li data-name="LuCI.form.FileUpload#width"><a href="LuCI.form.FileUpload.html#width">width</a></li>
  431. </ul>
  432. <ul class="typedefs itemMembers">
  433. </ul>
  434. <ul class="typedefs itemMembers">
  435. </ul>
  436. <ul class="methods itemMembers">
  437. <span class="subtitle">Methods</span>
  438. <li data-name="LuCI.form.FileUpload#append"><a href="LuCI.form.FileUpload.html#append">append</a></li>
  439. <li data-name="LuCI.form.FileUpload#cbid"><a href="LuCI.form.FileUpload.html#cbid">cbid</a></li>
  440. <li data-name="LuCI.form.FileUpload#cfgvalue"><a href="LuCI.form.FileUpload.html#cfgvalue">cfgvalue</a></li>
  441. <li data-name="LuCI.form.FileUpload#depends"><a href="LuCI.form.FileUpload.html#depends">depends</a></li>
  442. <li data-name="LuCI.form.FileUpload#formvalue"><a href="LuCI.form.FileUpload.html#formvalue">formvalue</a></li>
  443. <li data-name="LuCI.form.FileUpload#getUIElement"><a href="LuCI.form.FileUpload.html#getUIElement">getUIElement</a></li>
  444. <li data-name="LuCI.form.FileUpload#getValidationError"><a href="LuCI.form.FileUpload.html#getValidationError">getValidationError</a></li>
  445. <li data-name="LuCI.form.FileUpload#isActive"><a href="LuCI.form.FileUpload.html#isActive">isActive</a></li>
  446. <li data-name="LuCI.form.FileUpload#isValid"><a href="LuCI.form.FileUpload.html#isValid">isValid</a></li>
  447. <li data-name="LuCI.form.FileUpload#load"><a href="LuCI.form.FileUpload.html#load">load</a></li>
  448. <li data-name="LuCI.form.FileUpload#parse"><a href="LuCI.form.FileUpload.html#parse">parse</a></li>
  449. <li data-name="LuCI.form.FileUpload#remove"><a href="LuCI.form.FileUpload.html#remove">remove</a></li>
  450. <li data-name="LuCI.form.FileUpload#stripTags"><a href="LuCI.form.FileUpload.html#stripTags">stripTags</a></li>
  451. <li data-name="LuCI.form.FileUpload#textvalue"><a href="LuCI.form.FileUpload.html#textvalue">textvalue</a></li>
  452. <li data-name="LuCI.form.FileUpload#titleFn"><a href="LuCI.form.FileUpload.html#titleFn">titleFn</a></li>
  453. <li data-name="LuCI.form.FileUpload#value"><a href="LuCI.form.FileUpload.html#value">value</a></li>
  454. <li data-name="LuCI.form.FileUpload#write"><a href="LuCI.form.FileUpload.html#write">write</a></li>
  455. </ul>
  456. <ul class="events itemMembers">
  457. </ul>
  458. </li>
  459. <li class="item" data-name="LuCI.form.FlagValue">
  460. <span class="title">
  461. <a href="LuCI.form.FlagValue.html">LuCI.form.FlagValue</a>
  462. </span>
  463. <ul class="members itemMembers">
  464. <span class="subtitle">Members</span>
  465. <li data-name="LuCI.form.FlagValue##disabled"><a href="LuCI.form.FlagValue.html#disabled">disabled</a></li>
  466. <li data-name="LuCI.form.FlagValue##enabled"><a href="LuCI.form.FlagValue.html#enabled">enabled</a></li>
  467. <li data-name="LuCI.form.FlagValue##tooltip"><a href="LuCI.form.FlagValue.html#tooltip">tooltip</a></li>
  468. <li data-name="LuCI.form.FlagValue##tooltipicon"><a href="LuCI.form.FlagValue.html#tooltipicon">tooltipicon</a></li>
  469. <li data-name="LuCI.form.FlagValue#datatype"><a href="LuCI.form.FlagValue.html#datatype">datatype</a></li>
  470. <li data-name="LuCI.form.FlagValue#default"><a href="LuCI.form.FlagValue.html#default">default</a></li>
  471. <li data-name="LuCI.form.FlagValue#editable"><a href="LuCI.form.FlagValue.html#editable">editable</a></li>
  472. <li data-name="LuCI.form.FlagValue#modalonly"><a href="LuCI.form.FlagValue.html#modalonly">modalonly</a></li>
  473. <li data-name="LuCI.form.FlagValue#onchange"><a href="LuCI.form.FlagValue.html#onchange">onchange</a></li>
  474. <li data-name="LuCI.form.FlagValue#optional"><a href="LuCI.form.FlagValue.html#optional">optional</a></li>
  475. <li data-name="LuCI.form.FlagValue#password"><a href="LuCI.form.FlagValue.html#password">password</a></li>
  476. <li data-name="LuCI.form.FlagValue#placeholder"><a href="LuCI.form.FlagValue.html#placeholder">placeholder</a></li>
  477. <li data-name="LuCI.form.FlagValue#readonly"><a href="LuCI.form.FlagValue.html#readonly">readonly</a></li>
  478. <li data-name="LuCI.form.FlagValue#retain"><a href="LuCI.form.FlagValue.html#retain">retain</a></li>
  479. <li data-name="LuCI.form.FlagValue#rmempty"><a href="LuCI.form.FlagValue.html#rmempty">rmempty</a></li>
  480. <li data-name="LuCI.form.FlagValue#uciconfig"><a href="LuCI.form.FlagValue.html#uciconfig">uciconfig</a></li>
  481. <li data-name="LuCI.form.FlagValue#ucioption"><a href="LuCI.form.FlagValue.html#ucioption">ucioption</a></li>
  482. <li data-name="LuCI.form.FlagValue#ucisection"><a href="LuCI.form.FlagValue.html#ucisection">ucisection</a></li>
  483. <li data-name="LuCI.form.FlagValue#validate"><a href="LuCI.form.FlagValue.html#validate">validate</a></li>
  484. <li data-name="LuCI.form.FlagValue#width"><a href="LuCI.form.FlagValue.html#width">width</a></li>
  485. </ul>
  486. <ul class="typedefs itemMembers">
  487. </ul>
  488. <ul class="typedefs itemMembers">
  489. </ul>
  490. <ul class="methods itemMembers">
  491. <span class="subtitle">Methods</span>
  492. <li data-name="LuCI.form.FlagValue#append"><a href="LuCI.form.FlagValue.html#append">append</a></li>
  493. <li data-name="LuCI.form.FlagValue#cbid"><a href="LuCI.form.FlagValue.html#cbid">cbid</a></li>
  494. <li data-name="LuCI.form.FlagValue#cfgvalue"><a href="LuCI.form.FlagValue.html#cfgvalue">cfgvalue</a></li>
  495. <li data-name="LuCI.form.FlagValue#depends"><a href="LuCI.form.FlagValue.html#depends">depends</a></li>
  496. <li data-name="LuCI.form.FlagValue#formvalue"><a href="LuCI.form.FlagValue.html#formvalue">formvalue</a></li>
  497. <li data-name="LuCI.form.FlagValue#getUIElement"><a href="LuCI.form.FlagValue.html#getUIElement">getUIElement</a></li>
  498. <li data-name="LuCI.form.FlagValue#getValidationError"><a href="LuCI.form.FlagValue.html#getValidationError">getValidationError</a></li>
  499. <li data-name="LuCI.form.FlagValue#isActive"><a href="LuCI.form.FlagValue.html#isActive">isActive</a></li>
  500. <li data-name="LuCI.form.FlagValue#isValid"><a href="LuCI.form.FlagValue.html#isValid">isValid</a></li>
  501. <li data-name="LuCI.form.FlagValue#load"><a href="LuCI.form.FlagValue.html#load">load</a></li>
  502. <li data-name="LuCI.form.FlagValue#parse"><a href="LuCI.form.FlagValue.html#parse">parse</a></li>
  503. <li data-name="LuCI.form.FlagValue#remove"><a href="LuCI.form.FlagValue.html#remove">remove</a></li>
  504. <li data-name="LuCI.form.FlagValue#stripTags"><a href="LuCI.form.FlagValue.html#stripTags">stripTags</a></li>
  505. <li data-name="LuCI.form.FlagValue#textvalue"><a href="LuCI.form.FlagValue.html#textvalue">textvalue</a></li>
  506. <li data-name="LuCI.form.FlagValue#titleFn"><a href="LuCI.form.FlagValue.html#titleFn">titleFn</a></li>
  507. <li data-name="LuCI.form.FlagValue#value"><a href="LuCI.form.FlagValue.html#value">value</a></li>
  508. <li data-name="LuCI.form.FlagValue#write"><a href="LuCI.form.FlagValue.html#write">write</a></li>
  509. </ul>
  510. <ul class="events itemMembers">
  511. </ul>
  512. </li>
  513. <li class="item" data-name="LuCI.form.GridSection">
  514. <span class="title">
  515. <a href="LuCI.form.GridSection.html">LuCI.form.GridSection</a>
  516. </span>
  517. <ul class="members itemMembers">
  518. <span class="subtitle">Members</span>
  519. <li data-name="LuCI.form.GridSection#addbtntitle"><a href="LuCI.form.GridSection.html#addbtntitle">addbtntitle</a></li>
  520. <li data-name="LuCI.form.GridSection#addremove"><a href="LuCI.form.GridSection.html#addremove">addremove</a></li>
  521. <li data-name="LuCI.form.GridSection#anonymous"><a href="LuCI.form.GridSection.html#anonymous">anonymous</a></li>
  522. <li data-name="LuCI.form.GridSection#cloneable"><a href="LuCI.form.GridSection.html#cloneable">cloneable</a></li>
  523. <li data-name="LuCI.form.GridSection#extedit"><a href="LuCI.form.GridSection.html#extedit">extedit</a></li>
  524. <li data-name="LuCI.form.GridSection#max_cols"><a href="LuCI.form.GridSection.html#max_cols">max_cols</a></li>
  525. <li data-name="LuCI.form.GridSection#modaltitle"><a href="LuCI.form.GridSection.html#modaltitle">modaltitle</a></li>
  526. <li data-name="LuCI.form.GridSection#nodescriptions"><a href="LuCI.form.GridSection.html#nodescriptions">nodescriptions</a></li>
  527. <li data-name="LuCI.form.GridSection#parentoption"><a href="LuCI.form.GridSection.html#parentoption">parentoption</a></li>
  528. <li data-name="LuCI.form.GridSection#rowcolors"><a href="LuCI.form.GridSection.html#rowcolors">rowcolors</a></li>
  529. <li data-name="LuCI.form.GridSection#sectiontitle"><a href="LuCI.form.GridSection.html#sectiontitle">sectiontitle</a></li>
  530. <li data-name="LuCI.form.GridSection#sortable"><a href="LuCI.form.GridSection.html#sortable">sortable</a></li>
  531. <li data-name="LuCI.form.GridSection#tabbed"><a href="LuCI.form.GridSection.html#tabbed">tabbed</a></li>
  532. <li data-name="LuCI.form.GridSection#uciconfig"><a href="LuCI.form.GridSection.html#uciconfig">uciconfig</a></li>
  533. </ul>
  534. <ul class="typedefs itemMembers">
  535. </ul>
  536. <ul class="typedefs itemMembers">
  537. </ul>
  538. <ul class="methods itemMembers">
  539. <span class="subtitle">Methods</span>
  540. <li data-name="LuCI.form.GridSection#addModalOptions"><a href="LuCI.form.GridSection.html#addModalOptions">addModalOptions</a></li>
  541. <li data-name="LuCI.form.GridSection#append"><a href="LuCI.form.GridSection.html#append">append</a></li>
  542. <li data-name="LuCI.form.GridSection#cfgvalue"><a href="LuCI.form.GridSection.html#cfgvalue">cfgvalue</a></li>
  543. <li data-name="LuCI.form.GridSection#filter"><a href="LuCI.form.GridSection.html#filter">filter</a></li>
  544. <li data-name="LuCI.form.GridSection#formvalue"><a href="LuCI.form.GridSection.html#formvalue">formvalue</a></li>
  545. <li data-name="LuCI.form.GridSection#getOption"><a href="LuCI.form.GridSection.html#getOption">getOption</a></li>
  546. <li data-name="LuCI.form.GridSection#getUIElement"><a href="LuCI.form.GridSection.html#getUIElement">getUIElement</a></li>
  547. <li data-name="LuCI.form.GridSection#load"><a href="LuCI.form.GridSection.html#load">load</a></li>
  548. <li data-name="LuCI.form.GridSection#option"><a href="LuCI.form.GridSection.html#option">option</a></li>
  549. <li data-name="LuCI.form.GridSection#parse"><a href="LuCI.form.GridSection.html#parse">parse</a></li>
  550. <li data-name="LuCI.form.GridSection#stripTags"><a href="LuCI.form.GridSection.html#stripTags">stripTags</a></li>
  551. <li data-name="LuCI.form.GridSection#tab"><a href="LuCI.form.GridSection.html#tab">tab</a></li>
  552. <li data-name="LuCI.form.GridSection#taboption"><a href="LuCI.form.GridSection.html#taboption">taboption</a></li>
  553. <li data-name="LuCI.form.GridSection#titleFn"><a href="LuCI.form.GridSection.html#titleFn">titleFn</a></li>
  554. </ul>
  555. <ul class="events itemMembers">
  556. </ul>
  557. </li>
  558. <li class="item" data-name="LuCI.form.HiddenValue">
  559. <span class="title">
  560. <a href="LuCI.form.HiddenValue.html">LuCI.form.HiddenValue</a>
  561. </span>
  562. <ul class="members itemMembers">
  563. <span class="subtitle">Members</span>
  564. <li data-name="LuCI.form.HiddenValue#datatype"><a href="LuCI.form.HiddenValue.html#datatype">datatype</a></li>
  565. <li data-name="LuCI.form.HiddenValue#default"><a href="LuCI.form.HiddenValue.html#default">default</a></li>
  566. <li data-name="LuCI.form.HiddenValue#editable"><a href="LuCI.form.HiddenValue.html#editable">editable</a></li>
  567. <li data-name="LuCI.form.HiddenValue#modalonly"><a href="LuCI.form.HiddenValue.html#modalonly">modalonly</a></li>
  568. <li data-name="LuCI.form.HiddenValue#onchange"><a href="LuCI.form.HiddenValue.html#onchange">onchange</a></li>
  569. <li data-name="LuCI.form.HiddenValue#optional"><a href="LuCI.form.HiddenValue.html#optional">optional</a></li>
  570. <li data-name="LuCI.form.HiddenValue#password"><a href="LuCI.form.HiddenValue.html#password">password</a></li>
  571. <li data-name="LuCI.form.HiddenValue#placeholder"><a href="LuCI.form.HiddenValue.html#placeholder">placeholder</a></li>
  572. <li data-name="LuCI.form.HiddenValue#readonly"><a href="LuCI.form.HiddenValue.html#readonly">readonly</a></li>
  573. <li data-name="LuCI.form.HiddenValue#retain"><a href="LuCI.form.HiddenValue.html#retain">retain</a></li>
  574. <li data-name="LuCI.form.HiddenValue#rmempty"><a href="LuCI.form.HiddenValue.html#rmempty">rmempty</a></li>
  575. <li data-name="LuCI.form.HiddenValue#uciconfig"><a href="LuCI.form.HiddenValue.html#uciconfig">uciconfig</a></li>
  576. <li data-name="LuCI.form.HiddenValue#ucioption"><a href="LuCI.form.HiddenValue.html#ucioption">ucioption</a></li>
  577. <li data-name="LuCI.form.HiddenValue#ucisection"><a href="LuCI.form.HiddenValue.html#ucisection">ucisection</a></li>
  578. <li data-name="LuCI.form.HiddenValue#validate"><a href="LuCI.form.HiddenValue.html#validate">validate</a></li>
  579. <li data-name="LuCI.form.HiddenValue#width"><a href="LuCI.form.HiddenValue.html#width">width</a></li>
  580. </ul>
  581. <ul class="typedefs itemMembers">
  582. </ul>
  583. <ul class="typedefs itemMembers">
  584. </ul>
  585. <ul class="methods itemMembers">
  586. <span class="subtitle">Methods</span>
  587. <li data-name="LuCI.form.HiddenValue#append"><a href="LuCI.form.HiddenValue.html#append">append</a></li>
  588. <li data-name="LuCI.form.HiddenValue#cbid"><a href="LuCI.form.HiddenValue.html#cbid">cbid</a></li>
  589. <li data-name="LuCI.form.HiddenValue#cfgvalue"><a href="LuCI.form.HiddenValue.html#cfgvalue">cfgvalue</a></li>
  590. <li data-name="LuCI.form.HiddenValue#depends"><a href="LuCI.form.HiddenValue.html#depends">depends</a></li>
  591. <li data-name="LuCI.form.HiddenValue#formvalue"><a href="LuCI.form.HiddenValue.html#formvalue">formvalue</a></li>
  592. <li data-name="LuCI.form.HiddenValue#getUIElement"><a href="LuCI.form.HiddenValue.html#getUIElement">getUIElement</a></li>
  593. <li data-name="LuCI.form.HiddenValue#getValidationError"><a href="LuCI.form.HiddenValue.html#getValidationError">getValidationError</a></li>
  594. <li data-name="LuCI.form.HiddenValue#isActive"><a href="LuCI.form.HiddenValue.html#isActive">isActive</a></li>
  595. <li data-name="LuCI.form.HiddenValue#isValid"><a href="LuCI.form.HiddenValue.html#isValid">isValid</a></li>
  596. <li data-name="LuCI.form.HiddenValue#load"><a href="LuCI.form.HiddenValue.html#load">load</a></li>
  597. <li data-name="LuCI.form.HiddenValue#parse"><a href="LuCI.form.HiddenValue.html#parse">parse</a></li>
  598. <li data-name="LuCI.form.HiddenValue#remove"><a href="LuCI.form.HiddenValue.html#remove">remove</a></li>
  599. <li data-name="LuCI.form.HiddenValue#stripTags"><a href="LuCI.form.HiddenValue.html#stripTags">stripTags</a></li>
  600. <li data-name="LuCI.form.HiddenValue#textvalue"><a href="LuCI.form.HiddenValue.html#textvalue">textvalue</a></li>
  601. <li data-name="LuCI.form.HiddenValue#titleFn"><a href="LuCI.form.HiddenValue.html#titleFn">titleFn</a></li>
  602. <li data-name="LuCI.form.HiddenValue#value"><a href="LuCI.form.HiddenValue.html#value">value</a></li>
  603. <li data-name="LuCI.form.HiddenValue#write"><a href="LuCI.form.HiddenValue.html#write">write</a></li>
  604. </ul>
  605. <ul class="events itemMembers">
  606. </ul>
  607. </li>
  608. <li class="item" data-name="LuCI.form.JSONMap">
  609. <span class="title">
  610. <a href="LuCI.form.JSONMap.html">LuCI.form.JSONMap</a>
  611. </span>
  612. <ul class="members itemMembers">
  613. <span class="subtitle">Members</span>
  614. <li data-name="LuCI.form.JSONMap#readonly"><a href="LuCI.form.JSONMap.html#readonly">readonly</a></li>
  615. </ul>
  616. <ul class="typedefs itemMembers">
  617. </ul>
  618. <ul class="typedefs itemMembers">
  619. </ul>
  620. <ul class="methods itemMembers">
  621. <span class="subtitle">Methods</span>
  622. <li data-name="LuCI.form.JSONMap#append"><a href="LuCI.form.JSONMap.html#append">append</a></li>
  623. <li data-name="LuCI.form.JSONMap#chain"><a href="LuCI.form.JSONMap.html#chain">chain</a></li>
  624. <li data-name="LuCI.form.JSONMap#findElement"><a href="LuCI.form.JSONMap.html#findElement">findElement</a></li>
  625. <li data-name="LuCI.form.JSONMap#findElements"><a href="LuCI.form.JSONMap.html#findElements">findElements</a></li>
  626. <li data-name="LuCI.form.JSONMap#load"><a href="LuCI.form.JSONMap.html#load">load</a></li>
  627. <li data-name="LuCI.form.JSONMap#lookupOption"><a href="LuCI.form.JSONMap.html#lookupOption">lookupOption</a></li>
  628. <li data-name="LuCI.form.JSONMap#parse"><a href="LuCI.form.JSONMap.html#parse">parse</a></li>
  629. <li data-name="LuCI.form.JSONMap#render"><a href="LuCI.form.JSONMap.html#render">render</a></li>
  630. <li data-name="LuCI.form.JSONMap#reset"><a href="LuCI.form.JSONMap.html#reset">reset</a></li>
  631. <li data-name="LuCI.form.JSONMap#save"><a href="LuCI.form.JSONMap.html#save">save</a></li>
  632. <li data-name="LuCI.form.JSONMap#section"><a href="LuCI.form.JSONMap.html#section">section</a></li>
  633. <li data-name="LuCI.form.JSONMap#stripTags"><a href="LuCI.form.JSONMap.html#stripTags">stripTags</a></li>
  634. <li data-name="LuCI.form.JSONMap#titleFn"><a href="LuCI.form.JSONMap.html#titleFn">titleFn</a></li>
  635. </ul>
  636. <ul class="events itemMembers">
  637. </ul>
  638. </li>
  639. <li class="item" data-name="LuCI.form.ListValue">
  640. <span class="title">
  641. <a href="LuCI.form.ListValue.html">LuCI.form.ListValue</a>
  642. </span>
  643. <ul class="members itemMembers">
  644. <span class="subtitle">Members</span>
  645. <li data-name="LuCI.form.ListValue##orientation"><a href="LuCI.form.ListValue.html#orientation">orientation</a></li>
  646. <li data-name="LuCI.form.ListValue##size"><a href="LuCI.form.ListValue.html#size">size</a></li>
  647. <li data-name="LuCI.form.ListValue##widget"><a href="LuCI.form.ListValue.html#widget">widget</a></li>
  648. <li data-name="LuCI.form.ListValue#datatype"><a href="LuCI.form.ListValue.html#datatype">datatype</a></li>
  649. <li data-name="LuCI.form.ListValue#default"><a href="LuCI.form.ListValue.html#default">default</a></li>
  650. <li data-name="LuCI.form.ListValue#editable"><a href="LuCI.form.ListValue.html#editable">editable</a></li>
  651. <li data-name="LuCI.form.ListValue#modalonly"><a href="LuCI.form.ListValue.html#modalonly">modalonly</a></li>
  652. <li data-name="LuCI.form.ListValue#onchange"><a href="LuCI.form.ListValue.html#onchange">onchange</a></li>
  653. <li data-name="LuCI.form.ListValue#optional"><a href="LuCI.form.ListValue.html#optional">optional</a></li>
  654. <li data-name="LuCI.form.ListValue#password"><a href="LuCI.form.ListValue.html#password">password</a></li>
  655. <li data-name="LuCI.form.ListValue#placeholder"><a href="LuCI.form.ListValue.html#placeholder">placeholder</a></li>
  656. <li data-name="LuCI.form.ListValue#readonly"><a href="LuCI.form.ListValue.html#readonly">readonly</a></li>
  657. <li data-name="LuCI.form.ListValue#retain"><a href="LuCI.form.ListValue.html#retain">retain</a></li>
  658. <li data-name="LuCI.form.ListValue#rmempty"><a href="LuCI.form.ListValue.html#rmempty">rmempty</a></li>
  659. <li data-name="LuCI.form.ListValue#uciconfig"><a href="LuCI.form.ListValue.html#uciconfig">uciconfig</a></li>
  660. <li data-name="LuCI.form.ListValue#ucioption"><a href="LuCI.form.ListValue.html#ucioption">ucioption</a></li>
  661. <li data-name="LuCI.form.ListValue#ucisection"><a href="LuCI.form.ListValue.html#ucisection">ucisection</a></li>
  662. <li data-name="LuCI.form.ListValue#validate"><a href="LuCI.form.ListValue.html#validate">validate</a></li>
  663. <li data-name="LuCI.form.ListValue#width"><a href="LuCI.form.ListValue.html#width">width</a></li>
  664. </ul>
  665. <ul class="typedefs itemMembers">
  666. </ul>
  667. <ul class="typedefs itemMembers">
  668. </ul>
  669. <ul class="methods itemMembers">
  670. <span class="subtitle">Methods</span>
  671. <li data-name="LuCI.form.ListValue#append"><a href="LuCI.form.ListValue.html#append">append</a></li>
  672. <li data-name="LuCI.form.ListValue#cbid"><a href="LuCI.form.ListValue.html#cbid">cbid</a></li>
  673. <li data-name="LuCI.form.ListValue#cfgvalue"><a href="LuCI.form.ListValue.html#cfgvalue">cfgvalue</a></li>
  674. <li data-name="LuCI.form.ListValue#depends"><a href="LuCI.form.ListValue.html#depends">depends</a></li>
  675. <li data-name="LuCI.form.ListValue#formvalue"><a href="LuCI.form.ListValue.html#formvalue">formvalue</a></li>
  676. <li data-name="LuCI.form.ListValue#getUIElement"><a href="LuCI.form.ListValue.html#getUIElement">getUIElement</a></li>
  677. <li data-name="LuCI.form.ListValue#getValidationError"><a href="LuCI.form.ListValue.html#getValidationError">getValidationError</a></li>
  678. <li data-name="LuCI.form.ListValue#isActive"><a href="LuCI.form.ListValue.html#isActive">isActive</a></li>
  679. <li data-name="LuCI.form.ListValue#isValid"><a href="LuCI.form.ListValue.html#isValid">isValid</a></li>
  680. <li data-name="LuCI.form.ListValue#load"><a href="LuCI.form.ListValue.html#load">load</a></li>
  681. <li data-name="LuCI.form.ListValue#parse"><a href="LuCI.form.ListValue.html#parse">parse</a></li>
  682. <li data-name="LuCI.form.ListValue#remove"><a href="LuCI.form.ListValue.html#remove">remove</a></li>
  683. <li data-name="LuCI.form.ListValue#stripTags"><a href="LuCI.form.ListValue.html#stripTags">stripTags</a></li>
  684. <li data-name="LuCI.form.ListValue#textvalue"><a href="LuCI.form.ListValue.html#textvalue">textvalue</a></li>
  685. <li data-name="LuCI.form.ListValue#titleFn"><a href="LuCI.form.ListValue.html#titleFn">titleFn</a></li>
  686. <li data-name="LuCI.form.ListValue#value"><a href="LuCI.form.ListValue.html#value">value</a></li>
  687. <li data-name="LuCI.form.ListValue#write"><a href="LuCI.form.ListValue.html#write">write</a></li>
  688. </ul>
  689. <ul class="events itemMembers">
  690. </ul>
  691. </li>
  692. <li class="item" data-name="LuCI.form.Map">
  693. <span class="title">
  694. <a href="LuCI.form.Map.html">LuCI.form.Map</a>
  695. </span>
  696. <ul class="members itemMembers">
  697. <span class="subtitle">Members</span>
  698. <li data-name="LuCI.form.Map##readonly"><a href="LuCI.form.Map.html#readonly">readonly</a></li>
  699. </ul>
  700. <ul class="typedefs itemMembers">
  701. </ul>
  702. <ul class="typedefs itemMembers">
  703. </ul>
  704. <ul class="methods itemMembers">
  705. <span class="subtitle">Methods</span>
  706. <li data-name="LuCI.form.Map#append"><a href="LuCI.form.Map.html#append">append</a></li>
  707. <li data-name="LuCI.form.Map#chain"><a href="LuCI.form.Map.html#chain">chain</a></li>
  708. <li data-name="LuCI.form.Map#findElement"><a href="LuCI.form.Map.html#findElement">findElement</a></li>
  709. <li data-name="LuCI.form.Map#findElements"><a href="LuCI.form.Map.html#findElements">findElements</a></li>
  710. <li data-name="LuCI.form.Map#load"><a href="LuCI.form.Map.html#load">load</a></li>
  711. <li data-name="LuCI.form.Map#lookupOption"><a href="LuCI.form.Map.html#lookupOption">lookupOption</a></li>
  712. <li data-name="LuCI.form.Map#parse"><a href="LuCI.form.Map.html#parse">parse</a></li>
  713. <li data-name="LuCI.form.Map#render"><a href="LuCI.form.Map.html#render">render</a></li>
  714. <li data-name="LuCI.form.Map#reset"><a href="LuCI.form.Map.html#reset">reset</a></li>
  715. <li data-name="LuCI.form.Map#save"><a href="LuCI.form.Map.html#save">save</a></li>
  716. <li data-name="LuCI.form.Map#section"><a href="LuCI.form.Map.html#section">section</a></li>
  717. <li data-name="LuCI.form.Map#stripTags"><a href="LuCI.form.Map.html#stripTags">stripTags</a></li>
  718. <li data-name="LuCI.form.Map#titleFn"><a href="LuCI.form.Map.html#titleFn">titleFn</a></li>
  719. </ul>
  720. <ul class="events itemMembers">
  721. </ul>
  722. </li>
  723. <li class="item" data-name="LuCI.form.MultiValue">
  724. <span class="title">
  725. <a href="LuCI.form.MultiValue.html">LuCI.form.MultiValue</a>
  726. </span>
  727. <ul class="members itemMembers">
  728. <span class="subtitle">Members</span>
  729. <li data-name="LuCI.form.MultiValue##create"><a href="LuCI.form.MultiValue.html#create">create</a></li>
  730. <li data-name="LuCI.form.MultiValue##display_size"><a href="LuCI.form.MultiValue.html#display_size">display_size</a></li>
  731. <li data-name="LuCI.form.MultiValue##dropdown_size"><a href="LuCI.form.MultiValue.html#dropdown_size">dropdown_size</a></li>
  732. <li data-name="LuCI.form.MultiValue#datatype"><a href="LuCI.form.MultiValue.html#datatype">datatype</a></li>
  733. <li data-name="LuCI.form.MultiValue#default"><a href="LuCI.form.MultiValue.html#default">default</a></li>
  734. <li data-name="LuCI.form.MultiValue#editable"><a href="LuCI.form.MultiValue.html#editable">editable</a></li>
  735. <li data-name="LuCI.form.MultiValue#modalonly"><a href="LuCI.form.MultiValue.html#modalonly">modalonly</a></li>
  736. <li data-name="LuCI.form.MultiValue#onchange"><a href="LuCI.form.MultiValue.html#onchange">onchange</a></li>
  737. <li data-name="LuCI.form.MultiValue#optional"><a href="LuCI.form.MultiValue.html#optional">optional</a></li>
  738. <li data-name="LuCI.form.MultiValue#password"><a href="LuCI.form.MultiValue.html#password">password</a></li>
  739. <li data-name="LuCI.form.MultiValue#placeholder"><a href="LuCI.form.MultiValue.html#placeholder">placeholder</a></li>
  740. <li data-name="LuCI.form.MultiValue#readonly"><a href="LuCI.form.MultiValue.html#readonly">readonly</a></li>
  741. <li data-name="LuCI.form.MultiValue#retain"><a href="LuCI.form.MultiValue.html#retain">retain</a></li>
  742. <li data-name="LuCI.form.MultiValue#rmempty"><a href="LuCI.form.MultiValue.html#rmempty">rmempty</a></li>
  743. <li data-name="LuCI.form.MultiValue#uciconfig"><a href="LuCI.form.MultiValue.html#uciconfig">uciconfig</a></li>
  744. <li data-name="LuCI.form.MultiValue#ucioption"><a href="LuCI.form.MultiValue.html#ucioption">ucioption</a></li>
  745. <li data-name="LuCI.form.MultiValue#ucisection"><a href="LuCI.form.MultiValue.html#ucisection">ucisection</a></li>
  746. <li data-name="LuCI.form.MultiValue#validate"><a href="LuCI.form.MultiValue.html#validate">validate</a></li>
  747. <li data-name="LuCI.form.MultiValue#width"><a href="LuCI.form.MultiValue.html#width">width</a></li>
  748. </ul>
  749. <ul class="typedefs itemMembers">
  750. </ul>
  751. <ul class="typedefs itemMembers">
  752. </ul>
  753. <ul class="methods itemMembers">
  754. <span class="subtitle">Methods</span>
  755. <li data-name="LuCI.form.MultiValue#append"><a href="LuCI.form.MultiValue.html#append">append</a></li>
  756. <li data-name="LuCI.form.MultiValue#cbid"><a href="LuCI.form.MultiValue.html#cbid">cbid</a></li>
  757. <li data-name="LuCI.form.MultiValue#cfgvalue"><a href="LuCI.form.MultiValue.html#cfgvalue">cfgvalue</a></li>
  758. <li data-name="LuCI.form.MultiValue#depends"><a href="LuCI.form.MultiValue.html#depends">depends</a></li>
  759. <li data-name="LuCI.form.MultiValue#formvalue"><a href="LuCI.form.MultiValue.html#formvalue">formvalue</a></li>
  760. <li data-name="LuCI.form.MultiValue#getUIElement"><a href="LuCI.form.MultiValue.html#getUIElement">getUIElement</a></li>
  761. <li data-name="LuCI.form.MultiValue#getValidationError"><a href="LuCI.form.MultiValue.html#getValidationError">getValidationError</a></li>
  762. <li data-name="LuCI.form.MultiValue#isActive"><a href="LuCI.form.MultiValue.html#isActive">isActive</a></li>
  763. <li data-name="LuCI.form.MultiValue#isValid"><a href="LuCI.form.MultiValue.html#isValid">isValid</a></li>
  764. <li data-name="LuCI.form.MultiValue#load"><a href="LuCI.form.MultiValue.html#load">load</a></li>
  765. <li data-name="LuCI.form.MultiValue#parse"><a href="LuCI.form.MultiValue.html#parse">parse</a></li>
  766. <li data-name="LuCI.form.MultiValue#remove"><a href="LuCI.form.MultiValue.html#remove">remove</a></li>
  767. <li data-name="LuCI.form.MultiValue#stripTags"><a href="LuCI.form.MultiValue.html#stripTags">stripTags</a></li>
  768. <li data-name="LuCI.form.MultiValue#textvalue"><a href="LuCI.form.MultiValue.html#textvalue">textvalue</a></li>
  769. <li data-name="LuCI.form.MultiValue#titleFn"><a href="LuCI.form.MultiValue.html#titleFn">titleFn</a></li>
  770. <li data-name="LuCI.form.MultiValue#value"><a href="LuCI.form.MultiValue.html#value">value</a></li>
  771. <li data-name="LuCI.form.MultiValue#write"><a href="LuCI.form.MultiValue.html#write">write</a></li>
  772. </ul>
  773. <ul class="events itemMembers">
  774. </ul>
  775. </li>
  776. <li class="item" data-name="LuCI.form.NamedSection">
  777. <span class="title">
  778. <a href="LuCI.form.NamedSection.html">LuCI.form.NamedSection</a>
  779. </span>
  780. <ul class="members itemMembers">
  781. <span class="subtitle">Members</span>
  782. <li data-name="LuCI.form.NamedSection##addremove"><a href="LuCI.form.NamedSection.html#addremove">addremove</a></li>
  783. <li data-name="LuCI.form.NamedSection##uciconfig"><a href="LuCI.form.NamedSection.html#uciconfig">uciconfig</a></li>
  784. <li data-name="LuCI.form.NamedSection#parentoption"><a href="LuCI.form.NamedSection.html#parentoption">parentoption</a></li>
  785. </ul>
  786. <ul class="typedefs itemMembers">
  787. </ul>
  788. <ul class="typedefs itemMembers">
  789. </ul>
  790. <ul class="methods itemMembers">
  791. <span class="subtitle">Methods</span>
  792. <li data-name="LuCI.form.NamedSection#append"><a href="LuCI.form.NamedSection.html#append">append</a></li>
  793. <li data-name="LuCI.form.NamedSection#cfgsections"><a href="LuCI.form.NamedSection.html#cfgsections">cfgsections</a></li>
  794. <li data-name="LuCI.form.NamedSection#cfgvalue"><a href="LuCI.form.NamedSection.html#cfgvalue">cfgvalue</a></li>
  795. <li data-name="LuCI.form.NamedSection#filter"><a href="LuCI.form.NamedSection.html#filter">filter</a></li>
  796. <li data-name="LuCI.form.NamedSection#formvalue"><a href="LuCI.form.NamedSection.html#formvalue">formvalue</a></li>
  797. <li data-name="LuCI.form.NamedSection#getOption"><a href="LuCI.form.NamedSection.html#getOption">getOption</a></li>
  798. <li data-name="LuCI.form.NamedSection#getUIElement"><a href="LuCI.form.NamedSection.html#getUIElement">getUIElement</a></li>
  799. <li data-name="LuCI.form.NamedSection#load"><a href="LuCI.form.NamedSection.html#load">load</a></li>
  800. <li data-name="LuCI.form.NamedSection#option"><a href="LuCI.form.NamedSection.html#option">option</a></li>
  801. <li data-name="LuCI.form.NamedSection#parse"><a href="LuCI.form.NamedSection.html#parse">parse</a></li>
  802. <li data-name="LuCI.form.NamedSection#render"><a href="LuCI.form.NamedSection.html#render">render</a></li>
  803. <li data-name="LuCI.form.NamedSection#stripTags"><a href="LuCI.form.NamedSection.html#stripTags">stripTags</a></li>
  804. <li data-name="LuCI.form.NamedSection#tab"><a href="LuCI.form.NamedSection.html#tab">tab</a></li>
  805. <li data-name="LuCI.form.NamedSection#taboption"><a href="LuCI.form.NamedSection.html#taboption">taboption</a></li>
  806. <li data-name="LuCI.form.NamedSection#titleFn"><a href="LuCI.form.NamedSection.html#titleFn">titleFn</a></li>
  807. </ul>
  808. <ul class="events itemMembers">
  809. </ul>
  810. </li>
  811. <li class="item" data-name="LuCI.form.RichListValue">
  812. <span class="title">
  813. <a href="LuCI.form.RichListValue.html">LuCI.form.RichListValue</a>
  814. </span>
  815. <ul class="members itemMembers">
  816. <span class="subtitle">Members</span>
  817. <li data-name="LuCI.form.RichListValue##orientation"><a href="LuCI.form.RichListValue.html#orientation">orientation</a></li>
  818. <li data-name="LuCI.form.RichListValue##size"><a href="LuCI.form.RichListValue.html#size">size</a></li>
  819. <li data-name="LuCI.form.RichListValue##widget"><a href="LuCI.form.RichListValue.html#widget">widget</a></li>
  820. <li data-name="LuCI.form.RichListValue#datatype"><a href="LuCI.form.RichListValue.html#datatype">datatype</a></li>
  821. <li data-name="LuCI.form.RichListValue#default"><a href="LuCI.form.RichListValue.html#default">default</a></li>
  822. <li data-name="LuCI.form.RichListValue#editable"><a href="LuCI.form.RichListValue.html#editable">editable</a></li>
  823. <li data-name="LuCI.form.RichListValue#modalonly"><a href="LuCI.form.RichListValue.html#modalonly">modalonly</a></li>
  824. <li data-name="LuCI.form.RichListValue#onchange"><a href="LuCI.form.RichListValue.html#onchange">onchange</a></li>
  825. <li data-name="LuCI.form.RichListValue#optional"><a href="LuCI.form.RichListValue.html#optional">optional</a></li>
  826. <li data-name="LuCI.form.RichListValue#orientation"><a href="LuCI.form.RichListValue.html#orientation">orientation</a></li>
  827. <li data-name="LuCI.form.RichListValue#password"><a href="LuCI.form.RichListValue.html#password">password</a></li>
  828. <li data-name="LuCI.form.RichListValue#placeholder"><a href="LuCI.form.RichListValue.html#placeholder">placeholder</a></li>
  829. <li data-name="LuCI.form.RichListValue#readonly"><a href="LuCI.form.RichListValue.html#readonly">readonly</a></li>
  830. <li data-name="LuCI.form.RichListValue#retain"><a href="LuCI.form.RichListValue.html#retain">retain</a></li>
  831. <li data-name="LuCI.form.RichListValue#rmempty"><a href="LuCI.form.RichListValue.html#rmempty">rmempty</a></li>
  832. <li data-name="LuCI.form.RichListValue#size"><a href="LuCI.form.RichListValue.html#size">size</a></li>
  833. <li data-name="LuCI.form.RichListValue#uciconfig"><a href="LuCI.form.RichListValue.html#uciconfig">uciconfig</a></li>
  834. <li data-name="LuCI.form.RichListValue#ucioption"><a href="LuCI.form.RichListValue.html#ucioption">ucioption</a></li>
  835. <li data-name="LuCI.form.RichListValue#ucisection"><a href="LuCI.form.RichListValue.html#ucisection">ucisection</a></li>
  836. <li data-name="LuCI.form.RichListValue#validate"><a href="LuCI.form.RichListValue.html#validate">validate</a></li>
  837. <li data-name="LuCI.form.RichListValue#widget"><a href="LuCI.form.RichListValue.html#widget">widget</a></li>
  838. <li data-name="LuCI.form.RichListValue#width"><a href="LuCI.form.RichListValue.html#width">width</a></li>
  839. </ul>
  840. <ul class="typedefs itemMembers">
  841. </ul>
  842. <ul class="typedefs itemMembers">
  843. </ul>
  844. <ul class="methods itemMembers">
  845. <span class="subtitle">Methods</span>
  846. <li data-name="LuCI.form.RichListValue#append"><a href="LuCI.form.RichListValue.html#append">append</a></li>
  847. <li data-name="LuCI.form.RichListValue#cbid"><a href="LuCI.form.RichListValue.html#cbid">cbid</a></li>
  848. <li data-name="LuCI.form.RichListValue#cfgvalue"><a href="LuCI.form.RichListValue.html#cfgvalue">cfgvalue</a></li>
  849. <li data-name="LuCI.form.RichListValue#depends"><a href="LuCI.form.RichListValue.html#depends">depends</a></li>
  850. <li data-name="LuCI.form.RichListValue#formvalue"><a href="LuCI.form.RichListValue.html#formvalue">formvalue</a></li>
  851. <li data-name="LuCI.form.RichListValue#getUIElement"><a href="LuCI.form.RichListValue.html#getUIElement">getUIElement</a></li>
  852. <li data-name="LuCI.form.RichListValue#getValidationError"><a href="LuCI.form.RichListValue.html#getValidationError">getValidationError</a></li>
  853. <li data-name="LuCI.form.RichListValue#isActive"><a href="LuCI.form.RichListValue.html#isActive">isActive</a></li>
  854. <li data-name="LuCI.form.RichListValue#isValid"><a href="LuCI.form.RichListValue.html#isValid">isValid</a></li>
  855. <li data-name="LuCI.form.RichListValue#load"><a href="LuCI.form.RichListValue.html#load">load</a></li>
  856. <li data-name="LuCI.form.RichListValue#parse"><a href="LuCI.form.RichListValue.html#parse">parse</a></li>
  857. <li data-name="LuCI.form.RichListValue#remove"><a href="LuCI.form.RichListValue.html#remove">remove</a></li>
  858. <li data-name="LuCI.form.RichListValue#stripTags"><a href="LuCI.form.RichListValue.html#stripTags">stripTags</a></li>
  859. <li data-name="LuCI.form.RichListValue#textvalue"><a href="LuCI.form.RichListValue.html#textvalue">textvalue</a></li>
  860. <li data-name="LuCI.form.RichListValue#titleFn"><a href="LuCI.form.RichListValue.html#titleFn">titleFn</a></li>
  861. <li data-name="LuCI.form.RichListValue#value"><a href="LuCI.form.RichListValue.html#value">value</a></li>
  862. <li data-name="LuCI.form.RichListValue#write"><a href="LuCI.form.RichListValue.html#write">write</a></li>
  863. </ul>
  864. <ul class="events itemMembers">
  865. </ul>
  866. </li>
  867. <li class="item" data-name="LuCI.form.SectionValue">
  868. <span class="title">
  869. <a href="LuCI.form.SectionValue.html">LuCI.form.SectionValue</a>
  870. </span>
  871. <ul class="members itemMembers">
  872. <span class="subtitle">Members</span>
  873. <li data-name="LuCI.form.SectionValue##subsection"><a href="LuCI.form.SectionValue.html#subsection">subsection</a></li>
  874. <li data-name="LuCI.form.SectionValue#datatype"><a href="LuCI.form.SectionValue.html#datatype">datatype</a></li>
  875. <li data-name="LuCI.form.SectionValue#default"><a href="LuCI.form.SectionValue.html#default">default</a></li>
  876. <li data-name="LuCI.form.SectionValue#editable"><a href="LuCI.form.SectionValue.html#editable">editable</a></li>
  877. <li data-name="LuCI.form.SectionValue#modalonly"><a href="LuCI.form.SectionValue.html#modalonly">modalonly</a></li>
  878. <li data-name="LuCI.form.SectionValue#onchange"><a href="LuCI.form.SectionValue.html#onchange">onchange</a></li>
  879. <li data-name="LuCI.form.SectionValue#optional"><a href="LuCI.form.SectionValue.html#optional">optional</a></li>
  880. <li data-name="LuCI.form.SectionValue#password"><a href="LuCI.form.SectionValue.html#password">password</a></li>
  881. <li data-name="LuCI.form.SectionValue#placeholder"><a href="LuCI.form.SectionValue.html#placeholder">placeholder</a></li>
  882. <li data-name="LuCI.form.SectionValue#readonly"><a href="LuCI.form.SectionValue.html#readonly">readonly</a></li>
  883. <li data-name="LuCI.form.SectionValue#retain"><a href="LuCI.form.SectionValue.html#retain">retain</a></li>
  884. <li data-name="LuCI.form.SectionValue#rmempty"><a href="LuCI.form.SectionValue.html#rmempty">rmempty</a></li>
  885. <li data-name="LuCI.form.SectionValue#uciconfig"><a href="LuCI.form.SectionValue.html#uciconfig">uciconfig</a></li>
  886. <li data-name="LuCI.form.SectionValue#ucioption"><a href="LuCI.form.SectionValue.html#ucioption">ucioption</a></li>
  887. <li data-name="LuCI.form.SectionValue#ucisection"><a href="LuCI.form.SectionValue.html#ucisection">ucisection</a></li>
  888. <li data-name="LuCI.form.SectionValue#validate"><a href="LuCI.form.SectionValue.html#validate">validate</a></li>
  889. <li data-name="LuCI.form.SectionValue#width"><a href="LuCI.form.SectionValue.html#width">width</a></li>
  890. </ul>
  891. <ul class="typedefs itemMembers">
  892. </ul>
  893. <ul class="typedefs itemMembers">
  894. </ul>
  895. <ul class="methods itemMembers">
  896. <span class="subtitle">Methods</span>
  897. <li data-name="LuCI.form.SectionValue#append"><a href="LuCI.form.SectionValue.html#append">append</a></li>
  898. <li data-name="LuCI.form.SectionValue#cbid"><a href="LuCI.form.SectionValue.html#cbid">cbid</a></li>
  899. <li data-name="LuCI.form.SectionValue#cfgvalue"><a href="LuCI.form.SectionValue.html#cfgvalue">cfgvalue</a></li>
  900. <li data-name="LuCI.form.SectionValue#depends"><a href="LuCI.form.SectionValue.html#depends">depends</a></li>
  901. <li data-name="LuCI.form.SectionValue#formvalue"><a href="LuCI.form.SectionValue.html#formvalue">formvalue</a></li>
  902. <li data-name="LuCI.form.SectionValue#getUIElement"><a href="LuCI.form.SectionValue.html#getUIElement">getUIElement</a></li>
  903. <li data-name="LuCI.form.SectionValue#getValidationError"><a href="LuCI.form.SectionValue.html#getValidationError">getValidationError</a></li>
  904. <li data-name="LuCI.form.SectionValue#isActive"><a href="LuCI.form.SectionValue.html#isActive">isActive</a></li>
  905. <li data-name="LuCI.form.SectionValue#isValid"><a href="LuCI.form.SectionValue.html#isValid">isValid</a></li>
  906. <li data-name="LuCI.form.SectionValue#load"><a href="LuCI.form.SectionValue.html#load">load</a></li>
  907. <li data-name="LuCI.form.SectionValue#parse"><a href="LuCI.form.SectionValue.html#parse">parse</a></li>
  908. <li data-name="LuCI.form.SectionValue#remove"><a href="LuCI.form.SectionValue.html#remove">remove</a></li>
  909. <li data-name="LuCI.form.SectionValue#stripTags"><a href="LuCI.form.SectionValue.html#stripTags">stripTags</a></li>
  910. <li data-name="LuCI.form.SectionValue#textvalue"><a href="LuCI.form.SectionValue.html#textvalue">textvalue</a></li>
  911. <li data-name="LuCI.form.SectionValue#titleFn"><a href="LuCI.form.SectionValue.html#titleFn">titleFn</a></li>
  912. <li data-name="LuCI.form.SectionValue#value"><a href="LuCI.form.SectionValue.html#value">value</a></li>
  913. <li data-name="LuCI.form.SectionValue#write"><a href="LuCI.form.SectionValue.html#write">write</a></li>
  914. </ul>
  915. <ul class="events itemMembers">
  916. </ul>
  917. </li>
  918. <li class="item" data-name="LuCI.form.TableSection">
  919. <span class="title">
  920. <a href="LuCI.form.TableSection.html">LuCI.form.TableSection</a>
  921. </span>
  922. <ul class="members itemMembers">
  923. <span class="subtitle">Members</span>
  924. <li data-name="LuCI.form.TableSection##extedit"><a href="LuCI.form.TableSection.html#extedit">extedit</a></li>
  925. <li data-name="LuCI.form.TableSection##max_cols"><a href="LuCI.form.TableSection.html#max_cols">max_cols</a></li>
  926. <li data-name="LuCI.form.TableSection##modaltitle"><a href="LuCI.form.TableSection.html#modaltitle">modaltitle</a></li>
  927. <li data-name="LuCI.form.TableSection##nodescriptions"><a href="LuCI.form.TableSection.html#nodescriptions">nodescriptions</a></li>
  928. <li data-name="LuCI.form.TableSection##rowcolors"><a href="LuCI.form.TableSection.html#rowcolors">rowcolors</a></li>
  929. <li data-name="LuCI.form.TableSection##sectiontitle"><a href="LuCI.form.TableSection.html#sectiontitle">sectiontitle</a></li>
  930. <li data-name="LuCI.form.TableSection##sortable"><a href="LuCI.form.TableSection.html#sortable">sortable</a></li>
  931. <li data-name="LuCI.form.TableSection#addbtntitle"><a href="LuCI.form.TableSection.html#addbtntitle">addbtntitle</a></li>
  932. <li data-name="LuCI.form.TableSection#addremove"><a href="LuCI.form.TableSection.html#addremove">addremove</a></li>
  933. <li data-name="LuCI.form.TableSection#anonymous"><a href="LuCI.form.TableSection.html#anonymous">anonymous</a></li>
  934. <li data-name="LuCI.form.TableSection#cloneable"><a href="LuCI.form.TableSection.html#cloneable">cloneable</a></li>
  935. <li data-name="LuCI.form.TableSection#parentoption"><a href="LuCI.form.TableSection.html#parentoption">parentoption</a></li>
  936. <li data-name="LuCI.form.TableSection#tabbed"><a href="LuCI.form.TableSection.html#tabbed">tabbed</a></li>
  937. <li data-name="LuCI.form.TableSection#uciconfig"><a href="LuCI.form.TableSection.html#uciconfig">uciconfig</a></li>
  938. </ul>
  939. <ul class="typedefs itemMembers">
  940. </ul>
  941. <ul class="typedefs itemMembers">
  942. </ul>
  943. <ul class="methods itemMembers">
  944. <span class="subtitle">Methods</span>
  945. <li data-name="LuCI.form.TableSection#addModalOptions"><a href="LuCI.form.TableSection.html#addModalOptions">addModalOptions</a></li>
  946. <li data-name="LuCI.form.TableSection#append"><a href="LuCI.form.TableSection.html#append">append</a></li>
  947. <li data-name="LuCI.form.TableSection#cfgvalue"><a href="LuCI.form.TableSection.html#cfgvalue">cfgvalue</a></li>
  948. <li data-name="LuCI.form.TableSection#filter"><a href="LuCI.form.TableSection.html#filter">filter</a></li>
  949. <li data-name="LuCI.form.TableSection#formvalue"><a href="LuCI.form.TableSection.html#formvalue">formvalue</a></li>
  950. <li data-name="LuCI.form.TableSection#getOption"><a href="LuCI.form.TableSection.html#getOption">getOption</a></li>
  951. <li data-name="LuCI.form.TableSection#getUIElement"><a href="LuCI.form.TableSection.html#getUIElement">getUIElement</a></li>
  952. <li data-name="LuCI.form.TableSection#load"><a href="LuCI.form.TableSection.html#load">load</a></li>
  953. <li data-name="LuCI.form.TableSection#option"><a href="LuCI.form.TableSection.html#option">option</a></li>
  954. <li data-name="LuCI.form.TableSection#parse"><a href="LuCI.form.TableSection.html#parse">parse</a></li>
  955. <li data-name="LuCI.form.TableSection#stripTags"><a href="LuCI.form.TableSection.html#stripTags">stripTags</a></li>
  956. <li data-name="LuCI.form.TableSection#tab"><a href="LuCI.form.TableSection.html#tab">tab</a></li>
  957. <li data-name="LuCI.form.TableSection#taboption"><a href="LuCI.form.TableSection.html#taboption">taboption</a></li>
  958. <li data-name="LuCI.form.TableSection#titleFn"><a href="LuCI.form.TableSection.html#titleFn">titleFn</a></li>
  959. </ul>
  960. <ul class="events itemMembers">
  961. </ul>
  962. </li>
  963. <li class="item" data-name="LuCI.form.TextValue">
  964. <span class="title">
  965. <a href="LuCI.form.TextValue.html">LuCI.form.TextValue</a>
  966. </span>
  967. <ul class="members itemMembers">
  968. <span class="subtitle">Members</span>
  969. <li data-name="LuCI.form.TextValue##cols"><a href="LuCI.form.TextValue.html#cols">cols</a></li>
  970. <li data-name="LuCI.form.TextValue##monospace"><a href="LuCI.form.TextValue.html#monospace">monospace</a></li>
  971. <li data-name="LuCI.form.TextValue##rows"><a href="LuCI.form.TextValue.html#rows">rows</a></li>
  972. <li data-name="LuCI.form.TextValue##wrap"><a href="LuCI.form.TextValue.html#wrap">wrap</a></li>
  973. <li data-name="LuCI.form.TextValue#datatype"><a href="LuCI.form.TextValue.html#datatype">datatype</a></li>
  974. <li data-name="LuCI.form.TextValue#default"><a href="LuCI.form.TextValue.html#default">default</a></li>
  975. <li data-name="LuCI.form.TextValue#editable"><a href="LuCI.form.TextValue.html#editable">editable</a></li>
  976. <li data-name="LuCI.form.TextValue#modalonly"><a href="LuCI.form.TextValue.html#modalonly">modalonly</a></li>
  977. <li data-name="LuCI.form.TextValue#onchange"><a href="LuCI.form.TextValue.html#onchange">onchange</a></li>
  978. <li data-name="LuCI.form.TextValue#optional"><a href="LuCI.form.TextValue.html#optional">optional</a></li>
  979. <li data-name="LuCI.form.TextValue#password"><a href="LuCI.form.TextValue.html#password">password</a></li>
  980. <li data-name="LuCI.form.TextValue#placeholder"><a href="LuCI.form.TextValue.html#placeholder">placeholder</a></li>
  981. <li data-name="LuCI.form.TextValue#readonly"><a href="LuCI.form.TextValue.html#readonly">readonly</a></li>
  982. <li data-name="LuCI.form.TextValue#retain"><a href="LuCI.form.TextValue.html#retain">retain</a></li>
  983. <li data-name="LuCI.form.TextValue#rmempty"><a href="LuCI.form.TextValue.html#rmempty">rmempty</a></li>
  984. <li data-name="LuCI.form.TextValue#uciconfig"><a href="LuCI.form.TextValue.html#uciconfig">uciconfig</a></li>
  985. <li data-name="LuCI.form.TextValue#ucioption"><a href="LuCI.form.TextValue.html#ucioption">ucioption</a></li>
  986. <li data-name="LuCI.form.TextValue#ucisection"><a href="LuCI.form.TextValue.html#ucisection">ucisection</a></li>
  987. <li data-name="LuCI.form.TextValue#validate"><a href="LuCI.form.TextValue.html#validate">validate</a></li>
  988. <li data-name="LuCI.form.TextValue#width"><a href="LuCI.form.TextValue.html#width">width</a></li>
  989. </ul>
  990. <ul class="typedefs itemMembers">
  991. </ul>
  992. <ul class="typedefs itemMembers">
  993. </ul>
  994. <ul class="methods itemMembers">
  995. <span class="subtitle">Methods</span>
  996. <li data-name="LuCI.form.TextValue#append"><a href="LuCI.form.TextValue.html#append">append</a></li>
  997. <li data-name="LuCI.form.TextValue#cbid"><a href="LuCI.form.TextValue.html#cbid">cbid</a></li>
  998. <li data-name="LuCI.form.TextValue#cfgvalue"><a href="LuCI.form.TextValue.html#cfgvalue">cfgvalue</a></li>
  999. <li data-name="LuCI.form.TextValue#depends"><a href="LuCI.form.TextValue.html#depends">depends</a></li>
  1000. <li data-name="LuCI.form.TextValue#formvalue"><a href="LuCI.form.TextValue.html#formvalue">formvalue</a></li>
  1001. <li data-name="LuCI.form.TextValue#getUIElement"><a href="LuCI.form.TextValue.html#getUIElement">getUIElement</a></li>
  1002. <li data-name="LuCI.form.TextValue#getValidationError"><a href="LuCI.form.TextValue.html#getValidationError">getValidationError</a></li>
  1003. <li data-name="LuCI.form.TextValue#isActive"><a href="LuCI.form.TextValue.html#isActive">isActive</a></li>
  1004. <li data-name="LuCI.form.TextValue#isValid"><a href="LuCI.form.TextValue.html#isValid">isValid</a></li>
  1005. <li data-name="LuCI.form.TextValue#load"><a href="LuCI.form.TextValue.html#load">load</a></li>
  1006. <li data-name="LuCI.form.TextValue#parse"><a href="LuCI.form.TextValue.html#parse">parse</a></li>
  1007. <li data-name="LuCI.form.TextValue#remove"><a href="LuCI.form.TextValue.html#remove">remove</a></li>
  1008. <li data-name="LuCI.form.TextValue#stripTags"><a href="LuCI.form.TextValue.html#stripTags">stripTags</a></li>
  1009. <li data-name="LuCI.form.TextValue#textvalue"><a href="LuCI.form.TextValue.html#textvalue">textvalue</a></li>
  1010. <li data-name="LuCI.form.TextValue#titleFn"><a href="LuCI.form.TextValue.html#titleFn">titleFn</a></li>
  1011. <li data-name="LuCI.form.TextValue#write"><a href="LuCI.form.TextValue.html#write">write</a></li>
  1012. </ul>
  1013. <ul class="events itemMembers">
  1014. </ul>
  1015. </li>
  1016. <li class="item" data-name="LuCI.form.TypedSection">
  1017. <span class="title">
  1018. <a href="LuCI.form.TypedSection.html">LuCI.form.TypedSection</a>
  1019. </span>
  1020. <ul class="members itemMembers">
  1021. <span class="subtitle">Members</span>
  1022. <li data-name="LuCI.form.TypedSection##addbtntitle"><a href="LuCI.form.TypedSection.html#addbtntitle">addbtntitle</a></li>
  1023. <li data-name="LuCI.form.TypedSection##addremove"><a href="LuCI.form.TypedSection.html#addremove">addremove</a></li>
  1024. <li data-name="LuCI.form.TypedSection##anonymous"><a href="LuCI.form.TypedSection.html#anonymous">anonymous</a></li>
  1025. <li data-name="LuCI.form.TypedSection##cloneable"><a href="LuCI.form.TypedSection.html#cloneable">cloneable</a></li>
  1026. <li data-name="LuCI.form.TypedSection##tabbed"><a href="LuCI.form.TypedSection.html#tabbed">tabbed</a></li>
  1027. <li data-name="LuCI.form.TypedSection##uciconfig"><a href="LuCI.form.TypedSection.html#uciconfig">uciconfig</a></li>
  1028. <li data-name="LuCI.form.TypedSection#parentoption"><a href="LuCI.form.TypedSection.html#parentoption">parentoption</a></li>
  1029. </ul>
  1030. <ul class="typedefs itemMembers">
  1031. </ul>
  1032. <ul class="typedefs itemMembers">
  1033. </ul>
  1034. <ul class="methods itemMembers">
  1035. <span class="subtitle">Methods</span>
  1036. <li data-name="LuCI.form.TypedSection#append"><a href="LuCI.form.TypedSection.html#append">append</a></li>
  1037. <li data-name="LuCI.form.TypedSection#cfgsections"><a href="LuCI.form.TypedSection.html#cfgsections">cfgsections</a></li>
  1038. <li data-name="LuCI.form.TypedSection#cfgvalue"><a href="LuCI.form.TypedSection.html#cfgvalue">cfgvalue</a></li>
  1039. <li data-name="LuCI.form.TypedSection#filter"><a href="LuCI.form.TypedSection.html#filter">filter</a></li>
  1040. <li data-name="LuCI.form.TypedSection#formvalue"><a href="LuCI.form.TypedSection.html#formvalue">formvalue</a></li>
  1041. <li data-name="LuCI.form.TypedSection#getOption"><a href="LuCI.form.TypedSection.html#getOption">getOption</a></li>
  1042. <li data-name="LuCI.form.TypedSection#getUIElement"><a href="LuCI.form.TypedSection.html#getUIElement">getUIElement</a></li>
  1043. <li data-name="LuCI.form.TypedSection#load"><a href="LuCI.form.TypedSection.html#load">load</a></li>
  1044. <li data-name="LuCI.form.TypedSection#option"><a href="LuCI.form.TypedSection.html#option">option</a></li>
  1045. <li data-name="LuCI.form.TypedSection#parse"><a href="LuCI.form.TypedSection.html#parse">parse</a></li>
  1046. <li data-name="LuCI.form.TypedSection#render"><a href="LuCI.form.TypedSection.html#render">render</a></li>
  1047. <li data-name="LuCI.form.TypedSection#stripTags"><a href="LuCI.form.TypedSection.html#stripTags">stripTags</a></li>
  1048. <li data-name="LuCI.form.TypedSection#tab"><a href="LuCI.form.TypedSection.html#tab">tab</a></li>
  1049. <li data-name="LuCI.form.TypedSection#taboption"><a href="LuCI.form.TypedSection.html#taboption">taboption</a></li>
  1050. <li data-name="LuCI.form.TypedSection#titleFn"><a href="LuCI.form.TypedSection.html#titleFn">titleFn</a></li>
  1051. </ul>
  1052. <ul class="events itemMembers">
  1053. </ul>
  1054. </li>
  1055. <li class="item" data-name="LuCI.form.Value">
  1056. <span class="title">
  1057. <a href="LuCI.form.Value.html">LuCI.form.Value</a>
  1058. </span>
  1059. <ul class="members itemMembers">
  1060. <span class="subtitle">Members</span>
  1061. <li data-name="LuCI.form.Value##password"><a href="LuCI.form.Value.html#password">password</a></li>
  1062. <li data-name="LuCI.form.Value##placeholder"><a href="LuCI.form.Value.html#placeholder">placeholder</a></li>
  1063. <li data-name="LuCI.form.Value#datatype"><a href="LuCI.form.Value.html#datatype">datatype</a></li>
  1064. <li data-name="LuCI.form.Value#default"><a href="LuCI.form.Value.html#default">default</a></li>
  1065. <li data-name="LuCI.form.Value#editable"><a href="LuCI.form.Value.html#editable">editable</a></li>
  1066. <li data-name="LuCI.form.Value#modalonly"><a href="LuCI.form.Value.html#modalonly">modalonly</a></li>
  1067. <li data-name="LuCI.form.Value#onchange"><a href="LuCI.form.Value.html#onchange">onchange</a></li>
  1068. <li data-name="LuCI.form.Value#optional"><a href="LuCI.form.Value.html#optional">optional</a></li>
  1069. <li data-name="LuCI.form.Value#readonly"><a href="LuCI.form.Value.html#readonly">readonly</a></li>
  1070. <li data-name="LuCI.form.Value#retain"><a href="LuCI.form.Value.html#retain">retain</a></li>
  1071. <li data-name="LuCI.form.Value#rmempty"><a href="LuCI.form.Value.html#rmempty">rmempty</a></li>
  1072. <li data-name="LuCI.form.Value#uciconfig"><a href="LuCI.form.Value.html#uciconfig">uciconfig</a></li>
  1073. <li data-name="LuCI.form.Value#ucioption"><a href="LuCI.form.Value.html#ucioption">ucioption</a></li>
  1074. <li data-name="LuCI.form.Value#ucisection"><a href="LuCI.form.Value.html#ucisection">ucisection</a></li>
  1075. <li data-name="LuCI.form.Value#validate"><a href="LuCI.form.Value.html#validate">validate</a></li>
  1076. <li data-name="LuCI.form.Value#width"><a href="LuCI.form.Value.html#width">width</a></li>
  1077. </ul>
  1078. <ul class="typedefs itemMembers">
  1079. </ul>
  1080. <ul class="typedefs itemMembers">
  1081. </ul>
  1082. <ul class="methods itemMembers">
  1083. <span class="subtitle">Methods</span>
  1084. <li data-name="LuCI.form.Value#append"><a href="LuCI.form.Value.html#append">append</a></li>
  1085. <li data-name="LuCI.form.Value#cbid"><a href="LuCI.form.Value.html#cbid">cbid</a></li>
  1086. <li data-name="LuCI.form.Value#cfgvalue"><a href="LuCI.form.Value.html#cfgvalue">cfgvalue</a></li>
  1087. <li data-name="LuCI.form.Value#depends"><a href="LuCI.form.Value.html#depends">depends</a></li>
  1088. <li data-name="LuCI.form.Value#formvalue"><a href="LuCI.form.Value.html#formvalue">formvalue</a></li>
  1089. <li data-name="LuCI.form.Value#getUIElement"><a href="LuCI.form.Value.html#getUIElement">getUIElement</a></li>
  1090. <li data-name="LuCI.form.Value#getValidationError"><a href="LuCI.form.Value.html#getValidationError">getValidationError</a></li>
  1091. <li data-name="LuCI.form.Value#isActive"><a href="LuCI.form.Value.html#isActive">isActive</a></li>
  1092. <li data-name="LuCI.form.Value#isValid"><a href="LuCI.form.Value.html#isValid">isValid</a></li>
  1093. <li data-name="LuCI.form.Value#load"><a href="LuCI.form.Value.html#load">load</a></li>
  1094. <li data-name="LuCI.form.Value#parse"><a href="LuCI.form.Value.html#parse">parse</a></li>
  1095. <li data-name="LuCI.form.Value#remove"><a href="LuCI.form.Value.html#remove">remove</a></li>
  1096. <li data-name="LuCI.form.Value#render"><a href="LuCI.form.Value.html#render">render</a></li>
  1097. <li data-name="LuCI.form.Value#stripTags"><a href="LuCI.form.Value.html#stripTags">stripTags</a></li>
  1098. <li data-name="LuCI.form.Value#textvalue"><a href="LuCI.form.Value.html#textvalue">textvalue</a></li>
  1099. <li data-name="LuCI.form.Value#titleFn"><a href="LuCI.form.Value.html#titleFn">titleFn</a></li>
  1100. <li data-name="LuCI.form.Value#value"><a href="LuCI.form.Value.html#value">value</a></li>
  1101. <li data-name="LuCI.form.Value#write"><a href="LuCI.form.Value.html#write">write</a></li>
  1102. </ul>
  1103. <ul class="events itemMembers">
  1104. </ul>
  1105. </li>
  1106. <li class="item" data-name="LuCI.fs">
  1107. <span class="title">
  1108. <a href="LuCI.fs.html">LuCI.fs</a>
  1109. </span>
  1110. <ul class="members itemMembers">
  1111. </ul>
  1112. <ul class="typedefs itemMembers">
  1113. <span class="subtitle">Typedefs</span>
  1114. <li data-name="LuCI.fs.FileExecResult"><a href="LuCI.fs.html#.FileExecResult">FileExecResult</a></li>
  1115. <li data-name="LuCI.fs.FileStatEntry"><a href="LuCI.fs.html#.FileStatEntry">FileStatEntry</a></li>
  1116. </ul>
  1117. <ul class="typedefs itemMembers">
  1118. </ul>
  1119. <ul class="methods itemMembers">
  1120. <span class="subtitle">Methods</span>
  1121. <li data-name="LuCI.fs#exec"><a href="LuCI.fs.html#exec">exec</a></li>
  1122. <li data-name="LuCI.fs#exec_direct"><a href="LuCI.fs.html#exec_direct">exec_direct</a></li>
  1123. <li data-name="LuCI.fs#lines"><a href="LuCI.fs.html#lines">lines</a></li>
  1124. <li data-name="LuCI.fs#list"><a href="LuCI.fs.html#list">list</a></li>
  1125. <li data-name="LuCI.fs#read"><a href="LuCI.fs.html#read">read</a></li>
  1126. <li data-name="LuCI.fs#read_direct"><a href="LuCI.fs.html#read_direct">read_direct</a></li>
  1127. <li data-name="LuCI.fs#remove"><a href="LuCI.fs.html#remove">remove</a></li>
  1128. <li data-name="LuCI.fs#stat"><a href="LuCI.fs.html#stat">stat</a></li>
  1129. <li data-name="LuCI.fs#trimmed"><a href="LuCI.fs.html#trimmed">trimmed</a></li>
  1130. <li data-name="LuCI.fs#write"><a href="LuCI.fs.html#write">write</a></li>
  1131. </ul>
  1132. <ul class="events itemMembers">
  1133. </ul>
  1134. </li>
  1135. <li class="item" data-name="LuCI.headers">
  1136. <span class="title">
  1137. <a href="LuCI.headers.html">LuCI.headers</a>
  1138. </span>
  1139. <ul class="members itemMembers">
  1140. </ul>
  1141. <ul class="typedefs itemMembers">
  1142. </ul>
  1143. <ul class="typedefs itemMembers">
  1144. </ul>
  1145. <ul class="methods itemMembers">
  1146. <span class="subtitle">Methods</span>
  1147. <li data-name="LuCI.headers#get"><a href="LuCI.headers.html#get">get</a></li>
  1148. <li data-name="LuCI.headers#has"><a href="LuCI.headers.html#has">has</a></li>
  1149. </ul>
  1150. <ul class="events itemMembers">
  1151. </ul>
  1152. </li>
  1153. <li class="item" data-name="LuCI.network">
  1154. <span class="title">
  1155. <a href="LuCI.network.html">LuCI.network</a>
  1156. </span>
  1157. <ul class="members itemMembers">
  1158. </ul>
  1159. <ul class="typedefs itemMembers">
  1160. <span class="subtitle">Typedefs</span>
  1161. <li data-name="LuCI.network.SwitchTopology"><a href="LuCI.network.html#.SwitchTopology">SwitchTopology</a></li>
  1162. <li data-name="LuCI.network.WifiEncryption"><a href="LuCI.network.html#.WifiEncryption">WifiEncryption</a></li>
  1163. <li data-name="LuCI.network.WifiPeerEntry"><a href="LuCI.network.html#.WifiPeerEntry">WifiPeerEntry</a></li>
  1164. <li data-name="LuCI.network.WifiRateEntry"><a href="LuCI.network.html#.WifiRateEntry">WifiRateEntry</a></li>
  1165. <li data-name="LuCI.network.WifiScanResult"><a href="LuCI.network.html#.WifiScanResult">WifiScanResult</a></li>
  1166. </ul>
  1167. <ul class="typedefs itemMembers">
  1168. </ul>
  1169. <ul class="methods itemMembers">
  1170. <span class="subtitle">Methods</span>
  1171. <li data-name="LuCI.network#addNetwork"><a href="LuCI.network.html#addNetwork">addNetwork</a></li>
  1172. <li data-name="LuCI.network#addWifiNetwork"><a href="LuCI.network.html#addWifiNetwork">addWifiNetwork</a></li>
  1173. <li data-name="LuCI.network#deleteNetwork"><a href="LuCI.network.html#deleteNetwork">deleteNetwork</a></li>
  1174. <li data-name="LuCI.network#deleteWifiNetwork"><a href="LuCI.network.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
  1175. <li data-name="LuCI.network#flushCache"><a href="LuCI.network.html#flushCache">flushCache</a></li>
  1176. <li data-name="LuCI.network#formatWifiEncryption"><a href="LuCI.network.html#formatWifiEncryption">formatWifiEncryption</a></li>
  1177. <li data-name="LuCI.network#getDevice"><a href="LuCI.network.html#getDevice">getDevice</a></li>
  1178. <li data-name="LuCI.network#getDevices"><a href="LuCI.network.html#getDevices">getDevices</a></li>
  1179. <li data-name="LuCI.network#getDSLModemType"><a href="LuCI.network.html#getDSLModemType">getDSLModemType</a></li>
  1180. <li data-name="LuCI.network#getHostHints"><a href="LuCI.network.html#getHostHints">getHostHints</a></li>
  1181. <li data-name="LuCI.network#getIfnameOf"><a href="LuCI.network.html#getIfnameOf">getIfnameOf</a></li>
  1182. <li data-name="LuCI.network#getNetwork"><a href="LuCI.network.html#getNetwork">getNetwork</a></li>
  1183. <li data-name="LuCI.network#getNetworks"><a href="LuCI.network.html#getNetworks">getNetworks</a></li>
  1184. <li data-name="LuCI.network#getProtocol"><a href="LuCI.network.html#getProtocol">getProtocol</a></li>
  1185. <li data-name="LuCI.network#getProtocols"><a href="LuCI.network.html#getProtocols">getProtocols</a></li>
  1186. <li data-name="LuCI.network#getSwitchTopologies"><a href="LuCI.network.html#getSwitchTopologies">getSwitchTopologies</a></li>
  1187. <li data-name="LuCI.network#getWAN6Networks"><a href="LuCI.network.html#getWAN6Networks">getWAN6Networks</a></li>
  1188. <li data-name="LuCI.network#getWANNetworks"><a href="LuCI.network.html#getWANNetworks">getWANNetworks</a></li>
  1189. <li data-name="LuCI.network#getWifiDevice"><a href="LuCI.network.html#getWifiDevice">getWifiDevice</a></li>
  1190. <li data-name="LuCI.network#getWifiDevices"><a href="LuCI.network.html#getWifiDevices">getWifiDevices</a></li>
  1191. <li data-name="LuCI.network#getWifiNetwork"><a href="LuCI.network.html#getWifiNetwork">getWifiNetwork</a></li>
  1192. <li data-name="LuCI.network#getWifiNetworks"><a href="LuCI.network.html#getWifiNetworks">getWifiNetworks</a></li>
  1193. <li data-name="LuCI.network#isIgnoredDevice"><a href="LuCI.network.html#isIgnoredDevice">isIgnoredDevice</a></li>
  1194. <li data-name="LuCI.network#maskToPrefix"><a href="LuCI.network.html#maskToPrefix">maskToPrefix</a></li>
  1195. <li data-name="LuCI.network#prefixToMask"><a href="LuCI.network.html#prefixToMask">prefixToMask</a></li>
  1196. <li data-name="LuCI.network#registerErrorCode"><a href="LuCI.network.html#registerErrorCode">registerErrorCode</a></li>
  1197. <li data-name="LuCI.network#registerPatternVirtual"><a href="LuCI.network.html#registerPatternVirtual">registerPatternVirtual</a></li>
  1198. <li data-name="LuCI.network#registerProtocol"><a href="LuCI.network.html#registerProtocol">registerProtocol</a></li>
  1199. <li data-name="LuCI.network#renameNetwork"><a href="LuCI.network.html#renameNetwork">renameNetwork</a></li>
  1200. </ul>
  1201. <ul class="events itemMembers">
  1202. </ul>
  1203. </li>
  1204. <li class="item" data-name="LuCI.network.Device">
  1205. <span class="title">
  1206. <a href="LuCI.network.Device.html">LuCI.network.Device</a>
  1207. </span>
  1208. <ul class="members itemMembers">
  1209. </ul>
  1210. <ul class="typedefs itemMembers">
  1211. </ul>
  1212. <ul class="typedefs itemMembers">
  1213. </ul>
  1214. <ul class="methods itemMembers">
  1215. <span class="subtitle">Methods</span>
  1216. <li data-name="LuCI.network.Device#getBridgeID"><a href="LuCI.network.Device.html#getBridgeID">getBridgeID</a></li>
  1217. <li data-name="LuCI.network.Device#getBridgeSTP"><a href="LuCI.network.Device.html#getBridgeSTP">getBridgeSTP</a></li>
  1218. <li data-name="LuCI.network.Device#getCarrier"><a href="LuCI.network.Device.html#getCarrier">getCarrier</a></li>
  1219. <li data-name="LuCI.network.Device#getDuplex"><a href="LuCI.network.Device.html#getDuplex">getDuplex</a></li>
  1220. <li data-name="LuCI.network.Device#getI18n"><a href="LuCI.network.Device.html#getI18n">getI18n</a></li>
  1221. <li data-name="LuCI.network.Device#getIP6Addrs"><a href="LuCI.network.Device.html#getIP6Addrs">getIP6Addrs</a></li>
  1222. <li data-name="LuCI.network.Device#getIPAddrs"><a href="LuCI.network.Device.html#getIPAddrs">getIPAddrs</a></li>
  1223. <li data-name="LuCI.network.Device#getMAC"><a href="LuCI.network.Device.html#getMAC">getMAC</a></li>
  1224. <li data-name="LuCI.network.Device#getMTU"><a href="LuCI.network.Device.html#getMTU">getMTU</a></li>
  1225. <li data-name="LuCI.network.Device#getName"><a href="LuCI.network.Device.html#getName">getName</a></li>
  1226. <li data-name="LuCI.network.Device#getNetwork"><a href="LuCI.network.Device.html#getNetwork">getNetwork</a></li>
  1227. <li data-name="LuCI.network.Device#getNetworks"><a href="LuCI.network.Device.html#getNetworks">getNetworks</a></li>
  1228. <li data-name="LuCI.network.Device#getParent"><a href="LuCI.network.Device.html#getParent">getParent</a></li>
  1229. <li data-name="LuCI.network.Device#getPorts"><a href="LuCI.network.Device.html#getPorts">getPorts</a></li>
  1230. <li data-name="LuCI.network.Device#getRXBytes"><a href="LuCI.network.Device.html#getRXBytes">getRXBytes</a></li>
  1231. <li data-name="LuCI.network.Device#getRXPackets"><a href="LuCI.network.Device.html#getRXPackets">getRXPackets</a></li>
  1232. <li data-name="LuCI.network.Device#getShortName"><a href="LuCI.network.Device.html#getShortName">getShortName</a></li>
  1233. <li data-name="LuCI.network.Device#getSpeed"><a href="LuCI.network.Device.html#getSpeed">getSpeed</a></li>
  1234. <li data-name="LuCI.network.Device#getTXBytes"><a href="LuCI.network.Device.html#getTXBytes">getTXBytes</a></li>
  1235. <li data-name="LuCI.network.Device#getTXPackets"><a href="LuCI.network.Device.html#getTXPackets">getTXPackets</a></li>
  1236. <li data-name="LuCI.network.Device#getType"><a href="LuCI.network.Device.html#getType">getType</a></li>
  1237. <li data-name="LuCI.network.Device#getTypeI18n"><a href="LuCI.network.Device.html#getTypeI18n">getTypeI18n</a></li>
  1238. <li data-name="LuCI.network.Device#getWifiNetwork"><a href="LuCI.network.Device.html#getWifiNetwork">getWifiNetwork</a></li>
  1239. <li data-name="LuCI.network.Device#isBridge"><a href="LuCI.network.Device.html#isBridge">isBridge</a></li>
  1240. <li data-name="LuCI.network.Device#isBridgePort"><a href="LuCI.network.Device.html#isBridgePort">isBridgePort</a></li>
  1241. <li data-name="LuCI.network.Device#isUp"><a href="LuCI.network.Device.html#isUp">isUp</a></li>
  1242. </ul>
  1243. <ul class="events itemMembers">
  1244. </ul>
  1245. </li>
  1246. <li class="item" data-name="LuCI.network.Hosts">
  1247. <span class="title">
  1248. <a href="LuCI.network.Hosts.html">LuCI.network.Hosts</a>
  1249. </span>
  1250. <ul class="members itemMembers">
  1251. </ul>
  1252. <ul class="typedefs itemMembers">
  1253. </ul>
  1254. <ul class="typedefs itemMembers">
  1255. </ul>
  1256. <ul class="methods itemMembers">
  1257. <span class="subtitle">Methods</span>
  1258. <li data-name="LuCI.network.Hosts#getHostnameByIP6Addr"><a href="LuCI.network.Hosts.html#getHostnameByIP6Addr">getHostnameByIP6Addr</a></li>
  1259. <li data-name="LuCI.network.Hosts#getHostnameByIPAddr"><a href="LuCI.network.Hosts.html#getHostnameByIPAddr">getHostnameByIPAddr</a></li>
  1260. <li data-name="LuCI.network.Hosts#getHostnameByMACAddr"><a href="LuCI.network.Hosts.html#getHostnameByMACAddr">getHostnameByMACAddr</a></li>
  1261. <li data-name="LuCI.network.Hosts#getIP6AddrByMACAddr"><a href="LuCI.network.Hosts.html#getIP6AddrByMACAddr">getIP6AddrByMACAddr</a></li>
  1262. <li data-name="LuCI.network.Hosts#getIPAddrByMACAddr"><a href="LuCI.network.Hosts.html#getIPAddrByMACAddr">getIPAddrByMACAddr</a></li>
  1263. <li data-name="LuCI.network.Hosts#getMACAddrByIP6Addr"><a href="LuCI.network.Hosts.html#getMACAddrByIP6Addr">getMACAddrByIP6Addr</a></li>
  1264. <li data-name="LuCI.network.Hosts#getMACAddrByIPAddr"><a href="LuCI.network.Hosts.html#getMACAddrByIPAddr">getMACAddrByIPAddr</a></li>
  1265. <li data-name="LuCI.network.Hosts#getMACHints"><a href="LuCI.network.Hosts.html#getMACHints">getMACHints</a></li>
  1266. </ul>
  1267. <ul class="events itemMembers">
  1268. </ul>
  1269. </li>
  1270. <li class="item" data-name="LuCI.network.Protocol">
  1271. <span class="title">
  1272. <a href="LuCI.network.Protocol.html">LuCI.network.Protocol</a>
  1273. </span>
  1274. <ul class="members itemMembers">
  1275. </ul>
  1276. <ul class="typedefs itemMembers">
  1277. </ul>
  1278. <ul class="typedefs itemMembers">
  1279. </ul>
  1280. <ul class="methods itemMembers">
  1281. <span class="subtitle">Methods</span>
  1282. <li data-name="LuCI.network.Protocol#addDevice"><a href="LuCI.network.Protocol.html#addDevice">addDevice</a></li>
  1283. <li data-name="LuCI.network.Protocol#containsDevice"><a href="LuCI.network.Protocol.html#containsDevice">containsDevice</a></li>
  1284. <li data-name="LuCI.network.Protocol#deleteConfiguration"><a href="LuCI.network.Protocol.html#deleteConfiguration">deleteConfiguration</a></li>
  1285. <li data-name="LuCI.network.Protocol#deleteDevice"><a href="LuCI.network.Protocol.html#deleteDevice">deleteDevice</a></li>
  1286. <li data-name="LuCI.network.Protocol#get"><a href="LuCI.network.Protocol.html#get">get</a></li>
  1287. <li data-name="LuCI.network.Protocol#getDevice"><a href="LuCI.network.Protocol.html#getDevice">getDevice</a></li>
  1288. <li data-name="LuCI.network.Protocol#getDevices"><a href="LuCI.network.Protocol.html#getDevices">getDevices</a></li>
  1289. <li data-name="LuCI.network.Protocol#getDNS6Addrs"><a href="LuCI.network.Protocol.html#getDNS6Addrs">getDNS6Addrs</a></li>
  1290. <li data-name="LuCI.network.Protocol#getDNSAddrs"><a href="LuCI.network.Protocol.html#getDNSAddrs">getDNSAddrs</a></li>
  1291. <li data-name="LuCI.network.Protocol#getErrors"><a href="LuCI.network.Protocol.html#getErrors">getErrors</a></li>
  1292. <li data-name="LuCI.network.Protocol#getExpiry"><a href="LuCI.network.Protocol.html#getExpiry">getExpiry</a></li>
  1293. <li data-name="LuCI.network.Protocol#getGateway6Addr"><a href="LuCI.network.Protocol.html#getGateway6Addr">getGateway6Addr</a></li>
  1294. <li data-name="LuCI.network.Protocol#getGatewayAddr"><a href="LuCI.network.Protocol.html#getGatewayAddr">getGatewayAddr</a></li>
  1295. <li data-name="LuCI.network.Protocol#getI18n"><a href="LuCI.network.Protocol.html#getI18n">getI18n</a></li>
  1296. <li data-name="LuCI.network.Protocol#getIfname"><a href="LuCI.network.Protocol.html#getIfname">getIfname</a></li>
  1297. <li data-name="LuCI.network.Protocol#getIP6Addr"><a href="LuCI.network.Protocol.html#getIP6Addr">getIP6Addr</a></li>
  1298. <li data-name="LuCI.network.Protocol#getIP6Addrs"><a href="LuCI.network.Protocol.html#getIP6Addrs">getIP6Addrs</a></li>
  1299. <li data-name="LuCI.network.Protocol#getIP6Prefix"><a href="LuCI.network.Protocol.html#getIP6Prefix">getIP6Prefix</a></li>
  1300. <li data-name="LuCI.network.Protocol#getIP6Prefixes"><a href="LuCI.network.Protocol.html#getIP6Prefixes">getIP6Prefixes</a></li>
  1301. <li data-name="LuCI.network.Protocol#getIPAddr"><a href="LuCI.network.Protocol.html#getIPAddr">getIPAddr</a></li>
  1302. <li data-name="LuCI.network.Protocol#getIPAddrs"><a href="LuCI.network.Protocol.html#getIPAddrs">getIPAddrs</a></li>
  1303. <li data-name="LuCI.network.Protocol#getL2Device"><a href="LuCI.network.Protocol.html#getL2Device">getL2Device</a></li>
  1304. <li data-name="LuCI.network.Protocol#getL3Device"><a href="LuCI.network.Protocol.html#getL3Device">getL3Device</a></li>
  1305. <li data-name="LuCI.network.Protocol#getMetric"><a href="LuCI.network.Protocol.html#getMetric">getMetric</a></li>
  1306. <li data-name="LuCI.network.Protocol#getName"><a href="LuCI.network.Protocol.html#getName">getName</a></li>
  1307. <li data-name="LuCI.network.Protocol#getNetmask"><a href="LuCI.network.Protocol.html#getNetmask">getNetmask</a></li>
  1308. <li data-name="LuCI.network.Protocol#getOpkgPackage"><a href="LuCI.network.Protocol.html#getOpkgPackage">getOpkgPackage</a></li>
  1309. <li data-name="LuCI.network.Protocol#getProtocol"><a href="LuCI.network.Protocol.html#getProtocol">getProtocol</a></li>
  1310. <li data-name="LuCI.network.Protocol#getType"><a href="LuCI.network.Protocol.html#getType">getType</a></li>
  1311. <li data-name="LuCI.network.Protocol#getUptime"><a href="LuCI.network.Protocol.html#getUptime">getUptime</a></li>
  1312. <li data-name="LuCI.network.Protocol#getZoneName"><a href="LuCI.network.Protocol.html#getZoneName">getZoneName</a></li>
  1313. <li data-name="LuCI.network.Protocol#isAlias"><a href="LuCI.network.Protocol.html#isAlias">isAlias</a></li>
  1314. <li data-name="LuCI.network.Protocol#isBridge"><a href="LuCI.network.Protocol.html#isBridge">isBridge</a></li>
  1315. <li data-name="LuCI.network.Protocol#isCreateable"><a href="LuCI.network.Protocol.html#isCreateable">isCreateable</a></li>
  1316. <li data-name="LuCI.network.Protocol#isDynamic"><a href="LuCI.network.Protocol.html#isDynamic">isDynamic</a></li>
  1317. <li data-name="LuCI.network.Protocol#isEmpty"><a href="LuCI.network.Protocol.html#isEmpty">isEmpty</a></li>
  1318. <li data-name="LuCI.network.Protocol#isFloating"><a href="LuCI.network.Protocol.html#isFloating">isFloating</a></li>
  1319. <li data-name="LuCI.network.Protocol#isInstalled"><a href="LuCI.network.Protocol.html#isInstalled">isInstalled</a></li>
  1320. <li data-name="LuCI.network.Protocol#isUp"><a href="LuCI.network.Protocol.html#isUp">isUp</a></li>
  1321. <li data-name="LuCI.network.Protocol#isVirtual"><a href="LuCI.network.Protocol.html#isVirtual">isVirtual</a></li>
  1322. <li data-name="LuCI.network.Protocol#set"><a href="LuCI.network.Protocol.html#set">set</a></li>
  1323. </ul>
  1324. <ul class="events itemMembers">
  1325. </ul>
  1326. </li>
  1327. <li class="item" data-name="LuCI.network.WifiDevice">
  1328. <span class="title">
  1329. <a href="LuCI.network.WifiDevice.html">LuCI.network.WifiDevice</a>
  1330. </span>
  1331. <ul class="members itemMembers">
  1332. </ul>
  1333. <ul class="typedefs itemMembers">
  1334. </ul>
  1335. <ul class="typedefs itemMembers">
  1336. </ul>
  1337. <ul class="methods itemMembers">
  1338. <span class="subtitle">Methods</span>
  1339. <li data-name="LuCI.network.WifiDevice#addWifiNetwork"><a href="LuCI.network.WifiDevice.html#addWifiNetwork">addWifiNetwork</a></li>
  1340. <li data-name="LuCI.network.WifiDevice#deleteWifiNetwork"><a href="LuCI.network.WifiDevice.html#deleteWifiNetwork">deleteWifiNetwork</a></li>
  1341. <li data-name="LuCI.network.WifiDevice#get"><a href="LuCI.network.WifiDevice.html#get">get</a></li>
  1342. <li data-name="LuCI.network.WifiDevice#getHTModes"><a href="LuCI.network.WifiDevice.html#getHTModes">getHTModes</a></li>
  1343. <li data-name="LuCI.network.WifiDevice#getHWModes"><a href="LuCI.network.WifiDevice.html#getHWModes">getHWModes</a></li>
  1344. <li data-name="LuCI.network.WifiDevice#getI18n"><a href="LuCI.network.WifiDevice.html#getI18n">getI18n</a></li>
  1345. <li data-name="LuCI.network.WifiDevice#getName"><a href="LuCI.network.WifiDevice.html#getName">getName</a></li>
  1346. <li data-name="LuCI.network.WifiDevice#getScanList"><a href="LuCI.network.WifiDevice.html#getScanList">getScanList</a></li>
  1347. <li data-name="LuCI.network.WifiDevice#getWifiNetwork"><a href="LuCI.network.WifiDevice.html#getWifiNetwork">getWifiNetwork</a></li>
  1348. <li data-name="LuCI.network.WifiDevice#getWifiNetworks"><a href="LuCI.network.WifiDevice.html#getWifiNetworks">getWifiNetworks</a></li>
  1349. <li data-name="LuCI.network.WifiDevice#isDisabled"><a href="LuCI.network.WifiDevice.html#isDisabled">isDisabled</a></li>
  1350. <li data-name="LuCI.network.WifiDevice#isUp"><a href="LuCI.network.WifiDevice.html#isUp">isUp</a></li>
  1351. <li data-name="LuCI.network.WifiDevice#set"><a href="LuCI.network.WifiDevice.html#set">set</a></li>
  1352. </ul>
  1353. <ul class="events itemMembers">
  1354. </ul>
  1355. </li>
  1356. <li class="item" data-name="LuCI.network.WifiNetwork">
  1357. <span class="title">
  1358. <a href="LuCI.network.WifiNetwork.html">LuCI.network.WifiNetwork</a>
  1359. </span>
  1360. <ul class="members itemMembers">
  1361. </ul>
  1362. <ul class="typedefs itemMembers">
  1363. </ul>
  1364. <ul class="typedefs itemMembers">
  1365. </ul>
  1366. <ul class="methods itemMembers">
  1367. <span class="subtitle">Methods</span>
  1368. <li data-name="LuCI.network.WifiNetwork#disconnectClient"><a href="LuCI.network.WifiNetwork.html#disconnectClient">disconnectClient</a></li>
  1369. <li data-name="LuCI.network.WifiNetwork#get"><a href="LuCI.network.WifiNetwork.html#get">get</a></li>
  1370. <li data-name="LuCI.network.WifiNetwork#getActiveBSSID"><a href="LuCI.network.WifiNetwork.html#getActiveBSSID">getActiveBSSID</a></li>
  1371. <li data-name="LuCI.network.WifiNetwork#getActiveEncryption"><a href="LuCI.network.WifiNetwork.html#getActiveEncryption">getActiveEncryption</a></li>
  1372. <li data-name="LuCI.network.WifiNetwork#getActiveMode"><a href="LuCI.network.WifiNetwork.html#getActiveMode">getActiveMode</a></li>
  1373. <li data-name="LuCI.network.WifiNetwork#getActiveModeI18n"><a href="LuCI.network.WifiNetwork.html#getActiveModeI18n">getActiveModeI18n</a></li>
  1374. <li data-name="LuCI.network.WifiNetwork#getActiveSSID"><a href="LuCI.network.WifiNetwork.html#getActiveSSID">getActiveSSID</a></li>
  1375. <li data-name="LuCI.network.WifiNetwork#getAssocList"><a href="LuCI.network.WifiNetwork.html#getAssocList">getAssocList</a></li>
  1376. <li data-name="LuCI.network.WifiNetwork#getBitRate"><a href="LuCI.network.WifiNetwork.html#getBitRate">getBitRate</a></li>
  1377. <li data-name="LuCI.network.WifiNetwork#getBSSID"><a href="LuCI.network.WifiNetwork.html#getBSSID">getBSSID</a></li>
  1378. <li data-name="LuCI.network.WifiNetwork#getChannel"><a href="LuCI.network.WifiNetwork.html#getChannel">getChannel</a></li>
  1379. <li data-name="LuCI.network.WifiNetwork#getCountryCode"><a href="LuCI.network.WifiNetwork.html#getCountryCode">getCountryCode</a></li>
  1380. <li data-name="LuCI.network.WifiNetwork#getDevice"><a href="LuCI.network.WifiNetwork.html#getDevice">getDevice</a></li>
  1381. <li data-name="LuCI.network.WifiNetwork#getFrequency"><a href="LuCI.network.WifiNetwork.html#getFrequency">getFrequency</a></li>
  1382. <li data-name="LuCI.network.WifiNetwork#getI18n"><a href="LuCI.network.WifiNetwork.html#getI18n">getI18n</a></li>
  1383. <li data-name="LuCI.network.WifiNetwork#getID"><a href="LuCI.network.WifiNetwork.html#getID">getID</a></li>
  1384. <li data-name="LuCI.network.WifiNetwork#getIfname"><a href="LuCI.network.WifiNetwork.html#getIfname">getIfname</a></li>
  1385. <li data-name="LuCI.network.WifiNetwork#getMeshID"><a href="LuCI.network.WifiNetwork.html#getMeshID">getMeshID</a></li>
  1386. <li data-name="LuCI.network.WifiNetwork#getMode"><a href="LuCI.network.WifiNetwork.html#getMode">getMode</a></li>
  1387. <li data-name="LuCI.network.WifiNetwork#getName"><a href="LuCI.network.WifiNetwork.html#getName">getName</a></li>
  1388. <li data-name="LuCI.network.WifiNetwork#getNetwork"><a href="LuCI.network.WifiNetwork.html#getNetwork">getNetwork</a></li>
  1389. <li data-name="LuCI.network.WifiNetwork#getNetworkNames"><a href="LuCI.network.WifiNetwork.html#getNetworkNames">getNetworkNames</a></li>
  1390. <li data-name="LuCI.network.WifiNetwork#getNetworks"><a href="LuCI.network.WifiNetwork.html#getNetworks">getNetworks</a></li>
  1391. <li data-name="LuCI.network.WifiNetwork#getNoise"><a href="LuCI.network.WifiNetwork.html#getNoise">getNoise</a></li>
  1392. <li data-name="LuCI.network.WifiNetwork#getShortName"><a href="LuCI.network.WifiNetwork.html#getShortName">getShortName</a></li>
  1393. <li data-name="LuCI.network.WifiNetwork#getSignal"><a href="LuCI.network.WifiNetwork.html#getSignal">getSignal</a></li>
  1394. <li data-name="LuCI.network.WifiNetwork#getSignalLevel"><a href="LuCI.network.WifiNetwork.html#getSignalLevel">getSignalLevel</a></li>
  1395. <li data-name="LuCI.network.WifiNetwork#getSignalPercent"><a href="LuCI.network.WifiNetwork.html#getSignalPercent">getSignalPercent</a></li>
  1396. <li data-name="LuCI.network.WifiNetwork#getSSID"><a href="LuCI.network.WifiNetwork.html#getSSID">getSSID</a></li>
  1397. <li data-name="LuCI.network.WifiNetwork#getTXPower"><a href="LuCI.network.WifiNetwork.html#getTXPower">getTXPower</a></li>
  1398. <li data-name="LuCI.network.WifiNetwork#getTXPowerOffset"><a href="LuCI.network.WifiNetwork.html#getTXPowerOffset">getTXPowerOffset</a></li>
  1399. <li data-name="LuCI.network.WifiNetwork#getVlanIfnames"><a href="LuCI.network.WifiNetwork.html#getVlanIfnames">getVlanIfnames</a></li>
  1400. <li data-name="LuCI.network.WifiNetwork#getWifiDevice"><a href="LuCI.network.WifiNetwork.html#getWifiDevice">getWifiDevice</a></li>
  1401. <li data-name="LuCI.network.WifiNetwork#getWifiDeviceName"><a href="LuCI.network.WifiNetwork.html#getWifiDeviceName">getWifiDeviceName</a></li>
  1402. <li data-name="LuCI.network.WifiNetwork#isClientDisconnectSupported"><a href="LuCI.network.WifiNetwork.html#isClientDisconnectSupported">isClientDisconnectSupported</a></li>
  1403. <li data-name="LuCI.network.WifiNetwork#isDisabled"><a href="LuCI.network.WifiNetwork.html#isDisabled">isDisabled</a></li>
  1404. <li data-name="LuCI.network.WifiNetwork#isUp"><a href="LuCI.network.WifiNetwork.html#isUp">isUp</a></li>
  1405. <li data-name="LuCI.network.WifiNetwork#set"><a href="LuCI.network.WifiNetwork.html#set">set</a></li>
  1406. </ul>
  1407. <ul class="events itemMembers">
  1408. </ul>
  1409. </li>
  1410. <li class="item" data-name="LuCI.poll">
  1411. <span class="title">
  1412. <a href="LuCI.poll.html">LuCI.poll</a>
  1413. </span>
  1414. <ul class="members itemMembers">
  1415. </ul>
  1416. <ul class="typedefs itemMembers">
  1417. </ul>
  1418. <ul class="typedefs itemMembers">
  1419. </ul>
  1420. <ul class="methods itemMembers">
  1421. <span class="subtitle">Methods</span>
  1422. <li data-name="LuCI.poll#active"><a href="LuCI.poll.html#active">active</a></li>
  1423. <li data-name="LuCI.poll#add"><a href="LuCI.poll.html#add">add</a></li>
  1424. <li data-name="LuCI.poll#remove"><a href="LuCI.poll.html#remove">remove</a></li>
  1425. <li data-name="LuCI.poll#start"><a href="LuCI.poll.html#start">start</a></li>
  1426. <li data-name="LuCI.poll#stop"><a href="LuCI.poll.html#stop">stop</a></li>
  1427. </ul>
  1428. <ul class="events itemMembers">
  1429. </ul>
  1430. </li>
  1431. <li class="item" data-name="LuCI.request">
  1432. <span class="title">
  1433. <a href="LuCI.request.html">LuCI.request</a>
  1434. </span>
  1435. <ul class="members itemMembers">
  1436. </ul>
  1437. <ul class="typedefs itemMembers">
  1438. <span class="subtitle">Typedefs</span>
  1439. <li data-name="LuCI.request.interceptorFn"><a href="LuCI.request.html#.interceptorFn">interceptorFn</a></li>
  1440. <li data-name="LuCI.request.RequestOptions"><a href="LuCI.request.html#.RequestOptions">RequestOptions</a></li>
  1441. </ul>
  1442. <ul class="typedefs itemMembers">
  1443. </ul>
  1444. <ul class="methods itemMembers">
  1445. <span class="subtitle">Methods</span>
  1446. <li data-name="LuCI.request#addInterceptor"><a href="LuCI.request.html#addInterceptor">addInterceptor</a></li>
  1447. <li data-name="LuCI.request#expandURL"><a href="LuCI.request.html#expandURL">expandURL</a></li>
  1448. <li data-name="LuCI.request#get"><a href="LuCI.request.html#get">get</a></li>
  1449. <li data-name="LuCI.request#post"><a href="LuCI.request.html#post">post</a></li>
  1450. <li data-name="LuCI.request#removeInterceptor"><a href="LuCI.request.html#removeInterceptor">removeInterceptor</a></li>
  1451. <li data-name="LuCI.request#request"><a href="LuCI.request.html#request">request</a></li>
  1452. </ul>
  1453. <ul class="events itemMembers">
  1454. </ul>
  1455. </li>
  1456. <li class="item" data-name="LuCI.request.poll">
  1457. <span class="title">
  1458. <a href="LuCI.request.poll.html">LuCI.request.poll</a>
  1459. </span>
  1460. <ul class="members itemMembers">
  1461. </ul>
  1462. <ul class="typedefs itemMembers">
  1463. <span class="subtitle">Typedefs</span>
  1464. <li data-name="LuCI.request.poll~callbackFn"><a href="LuCI.request.poll.html#~callbackFn">callbackFn</a></li>
  1465. </ul>
  1466. <ul class="typedefs itemMembers">
  1467. </ul>
  1468. <ul class="methods itemMembers">
  1469. <span class="subtitle">Methods</span>
  1470. <li data-name="LuCI.request.poll#active"><a href="LuCI.request.poll.html#active">active</a></li>
  1471. <li data-name="LuCI.request.poll#add"><a href="LuCI.request.poll.html#add">add</a></li>
  1472. <li data-name="LuCI.request.poll#remove"><a href="LuCI.request.poll.html#remove">remove</a></li>
  1473. <li data-name="LuCI.request.poll#start"><a href="LuCI.request.poll.html#start">start</a></li>
  1474. <li data-name="LuCI.request.poll#stop"><a href="LuCI.request.poll.html#stop">stop</a></li>
  1475. </ul>
  1476. <ul class="events itemMembers">
  1477. </ul>
  1478. </li>
  1479. <li class="item" data-name="LuCI.response">
  1480. <span class="title">
  1481. <a href="LuCI.response.html">LuCI.response</a>
  1482. </span>
  1483. <ul class="members itemMembers">
  1484. <span class="subtitle">Members</span>
  1485. <li data-name="LuCI.response#duration"><a href="LuCI.response.html#duration">duration</a></li>
  1486. <li data-name="LuCI.response#headers"><a href="LuCI.response.html#headers">headers</a></li>
  1487. <li data-name="LuCI.response#ok"><a href="LuCI.response.html#ok">ok</a></li>
  1488. <li data-name="LuCI.response#status"><a href="LuCI.response.html#status">status</a></li>
  1489. <li data-name="LuCI.response#statusText"><a href="LuCI.response.html#statusText">statusText</a></li>
  1490. <li data-name="LuCI.response#url"><a href="LuCI.response.html#url">url</a></li>
  1491. </ul>
  1492. <ul class="typedefs itemMembers">
  1493. </ul>
  1494. <ul class="typedefs itemMembers">
  1495. </ul>
  1496. <ul class="methods itemMembers">
  1497. <span class="subtitle">Methods</span>
  1498. <li data-name="LuCI.response#blob"><a href="LuCI.response.html#blob">blob</a></li>
  1499. <li data-name="LuCI.response#clone"><a href="LuCI.response.html#clone">clone</a></li>
  1500. <li data-name="LuCI.response#json"><a href="LuCI.response.html#json">json</a></li>
  1501. <li data-name="LuCI.response#text"><a href="LuCI.response.html#text">text</a></li>
  1502. </ul>
  1503. <ul class="events itemMembers">
  1504. </ul>
  1505. </li>
  1506. <li class="item" data-name="LuCI.rpc">
  1507. <span class="title">
  1508. <a href="LuCI.rpc.html">LuCI.rpc</a>
  1509. </span>
  1510. <ul class="members itemMembers">
  1511. </ul>
  1512. <ul class="typedefs itemMembers">
  1513. <span class="subtitle">Typedefs</span>
  1514. <li data-name="LuCI.rpc.DeclareOptions"><a href="LuCI.rpc.html#.DeclareOptions">DeclareOptions</a></li>
  1515. <li data-name="LuCI.rpc~filterFn"><a href="LuCI.rpc.html#~filterFn">filterFn</a></li>
  1516. <li data-name="LuCI.rpc~interceptorFn"><a href="LuCI.rpc.html#~interceptorFn">interceptorFn</a></li>
  1517. <li data-name="LuCI.rpc~invokeFn"><a href="LuCI.rpc.html#~invokeFn">invokeFn</a></li>
  1518. </ul>
  1519. <ul class="typedefs itemMembers">
  1520. </ul>
  1521. <ul class="methods itemMembers">
  1522. <span class="subtitle">Methods</span>
  1523. <li data-name="LuCI.rpc#addInterceptor"><a href="LuCI.rpc.html#addInterceptor">addInterceptor</a></li>
  1524. <li data-name="LuCI.rpc#declare"><a href="LuCI.rpc.html#declare">declare</a></li>
  1525. <li data-name="LuCI.rpc#getBaseURL"><a href="LuCI.rpc.html#getBaseURL">getBaseURL</a></li>
  1526. <li data-name="LuCI.rpc#getSessionID"><a href="LuCI.rpc.html#getSessionID">getSessionID</a></li>
  1527. <li data-name="LuCI.rpc#getStatusText"><a href="LuCI.rpc.html#getStatusText">getStatusText</a></li>
  1528. <li data-name="LuCI.rpc#list"><a href="LuCI.rpc.html#list">list</a></li>
  1529. <li data-name="LuCI.rpc#removeInterceptor"><a href="LuCI.rpc.html#removeInterceptor">removeInterceptor</a></li>
  1530. <li data-name="LuCI.rpc#setBaseURL"><a href="LuCI.rpc.html#setBaseURL">setBaseURL</a></li>
  1531. <li data-name="LuCI.rpc#setSessionID"><a href="LuCI.rpc.html#setSessionID">setSessionID</a></li>
  1532. </ul>
  1533. <ul class="events itemMembers">
  1534. </ul>
  1535. </li>
  1536. <li class="item" data-name="LuCI.session">
  1537. <span class="title">
  1538. <a href="LuCI.session.html">LuCI.session</a>
  1539. </span>
  1540. <ul class="members itemMembers">
  1541. </ul>
  1542. <ul class="typedefs itemMembers">
  1543. </ul>
  1544. <ul class="typedefs itemMembers">
  1545. </ul>
  1546. <ul class="methods itemMembers">
  1547. <span class="subtitle">Methods</span>
  1548. <li data-name="LuCI.session#getID"><a href="LuCI.session.html#getID">getID</a></li>
  1549. <li data-name="LuCI.session#getLocalData"><a href="LuCI.session.html#getLocalData">getLocalData</a></li>
  1550. <li data-name="LuCI.session#getToken"><a href="LuCI.session.html#getToken">getToken</a></li>
  1551. <li data-name="LuCI.session#setLocalData"><a href="LuCI.session.html#setLocalData">setLocalData</a></li>
  1552. </ul>
  1553. <ul class="events itemMembers">
  1554. </ul>
  1555. </li>
  1556. <li class="item" data-name="LuCI.uci">
  1557. <span class="title">
  1558. <a href="LuCI.uci.html">LuCI.uci</a>
  1559. </span>
  1560. <ul class="members itemMembers">
  1561. </ul>
  1562. <ul class="typedefs itemMembers">
  1563. <span class="subtitle">Typedefs</span>
  1564. <li data-name="LuCI.uci.ChangeRecord"><a href="LuCI.uci.html#.ChangeRecord">ChangeRecord</a></li>
  1565. <li data-name="LuCI.uci.SectionObject"><a href="LuCI.uci.html#.SectionObject">SectionObject</a></li>
  1566. <li data-name="LuCI.uci~sectionsFn"><a href="LuCI.uci.html#~sectionsFn">sectionsFn</a></li>
  1567. </ul>
  1568. <ul class="typedefs itemMembers">
  1569. </ul>
  1570. <ul class="methods itemMembers">
  1571. <span class="subtitle">Methods</span>
  1572. <li data-name="LuCI.uci#add"><a href="LuCI.uci.html#add">add</a></li>
  1573. <li data-name="LuCI.uci#apply"><a href="LuCI.uci.html#apply">apply</a></li>
  1574. <li data-name="LuCI.uci#changes"><a href="LuCI.uci.html#changes">changes</a></li>
  1575. <li data-name="LuCI.uci#clone"><a href="LuCI.uci.html#clone">clone</a></li>
  1576. <li data-name="LuCI.uci#createSID"><a href="LuCI.uci.html#createSID">createSID</a></li>
  1577. <li data-name="LuCI.uci#get"><a href="LuCI.uci.html#get">get</a></li>
  1578. <li data-name="LuCI.uci#get_first"><a href="LuCI.uci.html#get_first">get_first</a></li>
  1579. <li data-name="LuCI.uci#load"><a href="LuCI.uci.html#load">load</a></li>
  1580. <li data-name="LuCI.uci#move"><a href="LuCI.uci.html#move">move</a></li>
  1581. <li data-name="LuCI.uci#remove"><a href="LuCI.uci.html#remove">remove</a></li>
  1582. <li data-name="LuCI.uci#resolveSID"><a href="LuCI.uci.html#resolveSID">resolveSID</a></li>
  1583. <li data-name="LuCI.uci#save"><a href="LuCI.uci.html#save">save</a></li>
  1584. <li data-name="LuCI.uci#sections"><a href="LuCI.uci.html#sections">sections</a></li>
  1585. <li data-name="LuCI.uci#set"><a href="LuCI.uci.html#set">set</a></li>
  1586. <li data-name="LuCI.uci#set_first"><a href="LuCI.uci.html#set_first">set_first</a></li>
  1587. <li data-name="LuCI.uci#unload"><a href="LuCI.uci.html#unload">unload</a></li>
  1588. <li data-name="LuCI.uci#unset"><a href="LuCI.uci.html#unset">unset</a></li>
  1589. <li data-name="LuCI.uci#unset_first"><a href="LuCI.uci.html#unset_first">unset_first</a></li>
  1590. </ul>
  1591. <ul class="events itemMembers">
  1592. </ul>
  1593. </li>
  1594. <li class="item" data-name="LuCI.ui">
  1595. <span class="title">
  1596. <a href="LuCI.ui.html">LuCI.ui</a>
  1597. </span>
  1598. <ul class="members itemMembers">
  1599. </ul>
  1600. <ul class="typedefs itemMembers">
  1601. <span class="subtitle">Typedefs</span>
  1602. <li data-name="LuCI.ui.FileUploadReply"><a href="LuCI.ui.html#.FileUploadReply">FileUploadReply</a></li>
  1603. </ul>
  1604. <ul class="typedefs itemMembers">
  1605. </ul>
  1606. <ul class="methods itemMembers">
  1607. <span class="subtitle">Methods</span>
  1608. <li data-name="LuCI.ui#addNotification"><a href="LuCI.ui.html#addNotification">addNotification</a></li>
  1609. <li data-name="LuCI.ui#addValidator"><a href="LuCI.ui.html#addValidator">addValidator</a></li>
  1610. <li data-name="LuCI.ui#awaitReconnect"><a href="LuCI.ui.html#awaitReconnect">awaitReconnect</a></li>
  1611. <li data-name="LuCI.ui#createHandlerFn"><a href="LuCI.ui.html#createHandlerFn">createHandlerFn</a></li>
  1612. <li data-name="LuCI.ui#hideIndicator"><a href="LuCI.ui.html#hideIndicator">hideIndicator</a></li>
  1613. <li data-name="LuCI.ui#hideModal"><a href="LuCI.ui.html#hideModal">hideModal</a></li>
  1614. <li data-name="LuCI.ui#instantiateView"><a href="LuCI.ui.html#instantiateView">instantiateView</a></li>
  1615. <li data-name="LuCI.ui#itemlist"><a href="LuCI.ui.html#itemlist">itemlist</a></li>
  1616. <li data-name="LuCI.ui#pingDevice"><a href="LuCI.ui.html#pingDevice">pingDevice</a></li>
  1617. <li data-name="LuCI.ui#showIndicator"><a href="LuCI.ui.html#showIndicator">showIndicator</a></li>
  1618. <li data-name="LuCI.ui#showModal"><a href="LuCI.ui.html#showModal">showModal</a></li>
  1619. <li data-name="LuCI.ui#uploadFile"><a href="LuCI.ui.html#uploadFile">uploadFile</a></li>
  1620. </ul>
  1621. <ul class="events itemMembers">
  1622. </ul>
  1623. </li>
  1624. <li class="item" data-name="LuCI.ui.AbstractElement">
  1625. <span class="title">
  1626. <a href="LuCI.ui.AbstractElement.html">LuCI.ui.AbstractElement</a>
  1627. </span>
  1628. <ul class="members itemMembers">
  1629. </ul>
  1630. <ul class="typedefs itemMembers">
  1631. <span class="subtitle">Typedefs</span>
  1632. <li data-name="LuCI.ui.AbstractElement.InitOptions"><a href="LuCI.ui.AbstractElement.html#.InitOptions">InitOptions</a></li>
  1633. </ul>
  1634. <ul class="typedefs itemMembers">
  1635. </ul>
  1636. <ul class="methods itemMembers">
  1637. <span class="subtitle">Methods</span>
  1638. <li data-name="LuCI.ui.AbstractElement#getValidationError"><a href="LuCI.ui.AbstractElement.html#getValidationError">getValidationError</a></li>
  1639. <li data-name="LuCI.ui.AbstractElement#getValue"><a href="LuCI.ui.AbstractElement.html#getValue">getValue</a></li>
  1640. <li data-name="LuCI.ui.AbstractElement#isChanged"><a href="LuCI.ui.AbstractElement.html#isChanged">isChanged</a></li>
  1641. <li data-name="LuCI.ui.AbstractElement#isValid"><a href="LuCI.ui.AbstractElement.html#isValid">isValid</a></li>
  1642. <li data-name="LuCI.ui.AbstractElement#registerEvents"><a href="LuCI.ui.AbstractElement.html#registerEvents">registerEvents</a></li>
  1643. <li data-name="LuCI.ui.AbstractElement#render"><a href="LuCI.ui.AbstractElement.html#render">render</a></li>
  1644. <li data-name="LuCI.ui.AbstractElement#setChangeEvents"><a href="LuCI.ui.AbstractElement.html#setChangeEvents">setChangeEvents</a></li>
  1645. <li data-name="LuCI.ui.AbstractElement#setPlaceholder"><a href="LuCI.ui.AbstractElement.html#setPlaceholder">setPlaceholder</a></li>
  1646. <li data-name="LuCI.ui.AbstractElement#setUpdateEvents"><a href="LuCI.ui.AbstractElement.html#setUpdateEvents">setUpdateEvents</a></li>
  1647. <li data-name="LuCI.ui.AbstractElement#setValue"><a href="LuCI.ui.AbstractElement.html#setValue">setValue</a></li>
  1648. <li data-name="LuCI.ui.AbstractElement#triggerValidation"><a href="LuCI.ui.AbstractElement.html#triggerValidation">triggerValidation</a></li>
  1649. </ul>
  1650. <ul class="events itemMembers">
  1651. </ul>
  1652. </li>
  1653. <li class="item" data-name="LuCI.ui.changes">
  1654. <span class="title">
  1655. <a href="LuCI.ui.changes.html">LuCI.ui.changes</a>
  1656. </span>
  1657. <ul class="members itemMembers">
  1658. </ul>
  1659. <ul class="typedefs itemMembers">
  1660. </ul>
  1661. <ul class="typedefs itemMembers">
  1662. </ul>
  1663. <ul class="methods itemMembers">
  1664. <span class="subtitle">Methods</span>
  1665. <li data-name="LuCI.ui.changes#apply"><a href="LuCI.ui.changes.html#apply">apply</a></li>
  1666. <li data-name="LuCI.ui.changes#displayChanges"><a href="LuCI.ui.changes.html#displayChanges">displayChanges</a></li>
  1667. <li data-name="LuCI.ui.changes#renderChangeIndicator"><a href="LuCI.ui.changes.html#renderChangeIndicator">renderChangeIndicator</a></li>
  1668. <li data-name="LuCI.ui.changes#revert"><a href="LuCI.ui.changes.html#revert">revert</a></li>
  1669. <li data-name="LuCI.ui.changes#setIndicator"><a href="LuCI.ui.changes.html#setIndicator">setIndicator</a></li>
  1670. </ul>
  1671. <ul class="events itemMembers">
  1672. </ul>
  1673. </li>
  1674. <li class="item" data-name="LuCI.ui.Checkbox">
  1675. <span class="title">
  1676. <a href="LuCI.ui.Checkbox.html">LuCI.ui.Checkbox</a>
  1677. </span>
  1678. <ul class="members itemMembers">
  1679. </ul>
  1680. <ul class="typedefs itemMembers">
  1681. <span class="subtitle">Typedefs</span>
  1682. <li data-name="LuCI.ui.Checkbox.InitOptions"><a href="LuCI.ui.Checkbox.html#.InitOptions">InitOptions</a></li>
  1683. </ul>
  1684. <ul class="typedefs itemMembers">
  1685. </ul>
  1686. <ul class="methods itemMembers">
  1687. <span class="subtitle">Methods</span>
  1688. <li data-name="LuCI.ui.Checkbox#getValidationError"><a href="LuCI.ui.Checkbox.html#getValidationError">getValidationError</a></li>
  1689. <li data-name="LuCI.ui.Checkbox#getValue"><a href="LuCI.ui.Checkbox.html#getValue">getValue</a></li>
  1690. <li data-name="LuCI.ui.Checkbox#isChanged"><a href="LuCI.ui.Checkbox.html#isChanged">isChanged</a></li>
  1691. <li data-name="LuCI.ui.Checkbox#isChecked"><a href="LuCI.ui.Checkbox.html#isChecked">isChecked</a></li>
  1692. <li data-name="LuCI.ui.Checkbox#isValid"><a href="LuCI.ui.Checkbox.html#isValid">isValid</a></li>
  1693. <li data-name="LuCI.ui.Checkbox#registerEvents"><a href="LuCI.ui.Checkbox.html#registerEvents">registerEvents</a></li>
  1694. <li data-name="LuCI.ui.Checkbox#render"><a href="LuCI.ui.Checkbox.html#render">render</a></li>
  1695. <li data-name="LuCI.ui.Checkbox#setChangeEvents"><a href="LuCI.ui.Checkbox.html#setChangeEvents">setChangeEvents</a></li>
  1696. <li data-name="LuCI.ui.Checkbox#setPlaceholder"><a href="LuCI.ui.Checkbox.html#setPlaceholder">setPlaceholder</a></li>
  1697. <li data-name="LuCI.ui.Checkbox#setUpdateEvents"><a href="LuCI.ui.Checkbox.html#setUpdateEvents">setUpdateEvents</a></li>
  1698. <li data-name="LuCI.ui.Checkbox#setValue"><a href="LuCI.ui.Checkbox.html#setValue">setValue</a></li>
  1699. <li data-name="LuCI.ui.Checkbox#triggerValidation"><a href="LuCI.ui.Checkbox.html#triggerValidation">triggerValidation</a></li>
  1700. </ul>
  1701. <ul class="events itemMembers">
  1702. </ul>
  1703. </li>
  1704. <li class="item" data-name="LuCI.ui.Combobox">
  1705. <span class="title">
  1706. <a href="LuCI.ui.Combobox.html">LuCI.ui.Combobox</a>
  1707. </span>
  1708. <ul class="members itemMembers">
  1709. </ul>
  1710. <ul class="typedefs itemMembers">
  1711. <span class="subtitle">Typedefs</span>
  1712. <li data-name="LuCI.ui.Combobox.InitOptions"><a href="LuCI.ui.Combobox.html#.InitOptions">InitOptions</a></li>
  1713. </ul>
  1714. <ul class="typedefs itemMembers">
  1715. </ul>
  1716. <ul class="methods itemMembers">
  1717. <span class="subtitle">Methods</span>
  1718. <li data-name="LuCI.ui.Combobox#addChoices"><a href="LuCI.ui.Combobox.html#addChoices">addChoices</a></li>
  1719. <li data-name="LuCI.ui.Combobox#clearChoices"><a href="LuCI.ui.Combobox.html#clearChoices">clearChoices</a></li>
  1720. <li data-name="LuCI.ui.Combobox#closeAllDropdowns"><a href="LuCI.ui.Combobox.html#closeAllDropdowns">closeAllDropdowns</a></li>
  1721. <li data-name="LuCI.ui.Combobox#getValidationError"><a href="LuCI.ui.Combobox.html#getValidationError">getValidationError</a></li>
  1722. <li data-name="LuCI.ui.Combobox#isChanged"><a href="LuCI.ui.Combobox.html#isChanged">isChanged</a></li>
  1723. <li data-name="LuCI.ui.Combobox#isValid"><a href="LuCI.ui.Combobox.html#isValid">isValid</a></li>
  1724. <li data-name="LuCI.ui.Combobox#registerEvents"><a href="LuCI.ui.Combobox.html#registerEvents">registerEvents</a></li>
  1725. <li data-name="LuCI.ui.Combobox#setChangeEvents"><a href="LuCI.ui.Combobox.html#setChangeEvents">setChangeEvents</a></li>
  1726. <li data-name="LuCI.ui.Combobox#setPlaceholder"><a href="LuCI.ui.Combobox.html#setPlaceholder">setPlaceholder</a></li>
  1727. <li data-name="LuCI.ui.Combobox#setUpdateEvents"><a href="LuCI.ui.Combobox.html#setUpdateEvents">setUpdateEvents</a></li>
  1728. <li data-name="LuCI.ui.Combobox#triggerValidation"><a href="LuCI.ui.Combobox.html#triggerValidation">triggerValidation</a></li>
  1729. </ul>
  1730. <ul class="events itemMembers">
  1731. </ul>
  1732. </li>
  1733. <li class="item" data-name="LuCI.ui.ComboButton">
  1734. <span class="title">
  1735. <a href="LuCI.ui.ComboButton.html">LuCI.ui.ComboButton</a>
  1736. </span>
  1737. <ul class="members itemMembers">
  1738. </ul>
  1739. <ul class="typedefs itemMembers">
  1740. <span class="subtitle">Typedefs</span>
  1741. <li data-name="LuCI.ui.ComboButton.InitOptions"><a href="LuCI.ui.ComboButton.html#.InitOptions">InitOptions</a></li>
  1742. </ul>
  1743. <ul class="typedefs itemMembers">
  1744. </ul>
  1745. <ul class="methods itemMembers">
  1746. <span class="subtitle">Methods</span>
  1747. <li data-name="LuCI.ui.ComboButton#addChoices"><a href="LuCI.ui.ComboButton.html#addChoices">addChoices</a></li>
  1748. <li data-name="LuCI.ui.ComboButton#clearChoices"><a href="LuCI.ui.ComboButton.html#clearChoices">clearChoices</a></li>
  1749. <li data-name="LuCI.ui.ComboButton#closeAllDropdowns"><a href="LuCI.ui.ComboButton.html#closeAllDropdowns">closeAllDropdowns</a></li>
  1750. <li data-name="LuCI.ui.ComboButton#getValidationError"><a href="LuCI.ui.ComboButton.html#getValidationError">getValidationError</a></li>
  1751. <li data-name="LuCI.ui.ComboButton#isChanged"><a href="LuCI.ui.ComboButton.html#isChanged">isChanged</a></li>
  1752. <li data-name="LuCI.ui.ComboButton#isValid"><a href="LuCI.ui.ComboButton.html#isValid">isValid</a></li>
  1753. <li data-name="LuCI.ui.ComboButton#registerEvents"><a href="LuCI.ui.ComboButton.html#registerEvents">registerEvents</a></li>
  1754. <li data-name="LuCI.ui.ComboButton#setChangeEvents"><a href="LuCI.ui.ComboButton.html#setChangeEvents">setChangeEvents</a></li>
  1755. <li data-name="LuCI.ui.ComboButton#setPlaceholder"><a href="LuCI.ui.ComboButton.html#setPlaceholder">setPlaceholder</a></li>
  1756. <li data-name="LuCI.ui.ComboButton#setUpdateEvents"><a href="LuCI.ui.ComboButton.html#setUpdateEvents">setUpdateEvents</a></li>
  1757. <li data-name="LuCI.ui.ComboButton#triggerValidation"><a href="LuCI.ui.ComboButton.html#triggerValidation">triggerValidation</a></li>
  1758. </ul>
  1759. <ul class="events itemMembers">
  1760. </ul>
  1761. </li>
  1762. <li class="item" data-name="LuCI.ui.Dropdown">
  1763. <span class="title">
  1764. <a href="LuCI.ui.Dropdown.html">LuCI.ui.Dropdown</a>
  1765. </span>
  1766. <ul class="members itemMembers">
  1767. </ul>
  1768. <ul class="typedefs itemMembers">
  1769. <span class="subtitle">Typedefs</span>
  1770. <li data-name="LuCI.ui.Dropdown.InitOptions"><a href="LuCI.ui.Dropdown.html#.InitOptions">InitOptions</a></li>
  1771. </ul>
  1772. <ul class="typedefs itemMembers">
  1773. </ul>
  1774. <ul class="methods itemMembers">
  1775. <span class="subtitle">Methods</span>
  1776. <li data-name="LuCI.ui.Dropdown#addChoices"><a href="LuCI.ui.Dropdown.html#addChoices">addChoices</a></li>
  1777. <li data-name="LuCI.ui.Dropdown#clearChoices"><a href="LuCI.ui.Dropdown.html#clearChoices">clearChoices</a></li>
  1778. <li data-name="LuCI.ui.Dropdown#closeAllDropdowns"><a href="LuCI.ui.Dropdown.html#closeAllDropdowns">closeAllDropdowns</a></li>
  1779. <li data-name="LuCI.ui.Dropdown#getValidationError"><a href="LuCI.ui.Dropdown.html#getValidationError">getValidationError</a></li>
  1780. <li data-name="LuCI.ui.Dropdown#getValue"><a href="LuCI.ui.Dropdown.html#getValue">getValue</a></li>
  1781. <li data-name="LuCI.ui.Dropdown#isChanged"><a href="LuCI.ui.Dropdown.html#isChanged">isChanged</a></li>
  1782. <li data-name="LuCI.ui.Dropdown#isValid"><a href="LuCI.ui.Dropdown.html#isValid">isValid</a></li>
  1783. <li data-name="LuCI.ui.Dropdown#registerEvents"><a href="LuCI.ui.Dropdown.html#registerEvents">registerEvents</a></li>
  1784. <li data-name="LuCI.ui.Dropdown#render"><a href="LuCI.ui.Dropdown.html#render">render</a></li>
  1785. <li data-name="LuCI.ui.Dropdown#setChangeEvents"><a href="LuCI.ui.Dropdown.html#setChangeEvents">setChangeEvents</a></li>
  1786. <li data-name="LuCI.ui.Dropdown#setPlaceholder"><a href="LuCI.ui.Dropdown.html#setPlaceholder">setPlaceholder</a></li>
  1787. <li data-name="LuCI.ui.Dropdown#setUpdateEvents"><a href="LuCI.ui.Dropdown.html#setUpdateEvents">setUpdateEvents</a></li>
  1788. <li data-name="LuCI.ui.Dropdown#setValue"><a href="LuCI.ui.Dropdown.html#setValue">setValue</a></li>
  1789. <li data-name="LuCI.ui.Dropdown#triggerValidation"><a href="LuCI.ui.Dropdown.html#triggerValidation">triggerValidation</a></li>
  1790. </ul>
  1791. <ul class="events itemMembers">
  1792. </ul>
  1793. </li>
  1794. <li class="item" data-name="LuCI.ui.DynamicList">
  1795. <span class="title">
  1796. <a href="LuCI.ui.DynamicList.html">LuCI.ui.DynamicList</a>
  1797. </span>
  1798. <ul class="members itemMembers">
  1799. </ul>
  1800. <ul class="typedefs itemMembers">
  1801. <span class="subtitle">Typedefs</span>
  1802. <li data-name="LuCI.ui.DynamicList.InitOptions"><a href="LuCI.ui.DynamicList.html#.InitOptions">InitOptions</a></li>
  1803. </ul>
  1804. <ul class="typedefs itemMembers">
  1805. </ul>
  1806. <ul class="methods itemMembers">
  1807. <span class="subtitle">Methods</span>
  1808. <li data-name="LuCI.ui.DynamicList#addChoices"><a href="LuCI.ui.DynamicList.html#addChoices">addChoices</a></li>
  1809. <li data-name="LuCI.ui.DynamicList#clearChoices"><a href="LuCI.ui.DynamicList.html#clearChoices">clearChoices</a></li>
  1810. <li data-name="LuCI.ui.DynamicList#getValidationError"><a href="LuCI.ui.DynamicList.html#getValidationError">getValidationError</a></li>
  1811. <li data-name="LuCI.ui.DynamicList#getValue"><a href="LuCI.ui.DynamicList.html#getValue">getValue</a></li>
  1812. <li data-name="LuCI.ui.DynamicList#isChanged"><a href="LuCI.ui.DynamicList.html#isChanged">isChanged</a></li>
  1813. <li data-name="LuCI.ui.DynamicList#isValid"><a href="LuCI.ui.DynamicList.html#isValid">isValid</a></li>
  1814. <li data-name="LuCI.ui.DynamicList#registerEvents"><a href="LuCI.ui.DynamicList.html#registerEvents">registerEvents</a></li>
  1815. <li data-name="LuCI.ui.DynamicList#render"><a href="LuCI.ui.DynamicList.html#render">render</a></li>
  1816. <li data-name="LuCI.ui.DynamicList#setChangeEvents"><a href="LuCI.ui.DynamicList.html#setChangeEvents">setChangeEvents</a></li>
  1817. <li data-name="LuCI.ui.DynamicList#setPlaceholder"><a href="LuCI.ui.DynamicList.html#setPlaceholder">setPlaceholder</a></li>
  1818. <li data-name="LuCI.ui.DynamicList#setUpdateEvents"><a href="LuCI.ui.DynamicList.html#setUpdateEvents">setUpdateEvents</a></li>
  1819. <li data-name="LuCI.ui.DynamicList#setValue"><a href="LuCI.ui.DynamicList.html#setValue">setValue</a></li>
  1820. <li data-name="LuCI.ui.DynamicList#triggerValidation"><a href="LuCI.ui.DynamicList.html#triggerValidation">triggerValidation</a></li>
  1821. </ul>
  1822. <ul class="events itemMembers">
  1823. </ul>
  1824. </li>
  1825. <li class="item" data-name="LuCI.ui.FileUpload">
  1826. <span class="title">
  1827. <a href="LuCI.ui.FileUpload.html">LuCI.ui.FileUpload</a>
  1828. </span>
  1829. <ul class="members itemMembers">
  1830. </ul>
  1831. <ul class="typedefs itemMembers">
  1832. <span class="subtitle">Typedefs</span>
  1833. <li data-name="LuCI.ui.FileUpload.InitOptions"><a href="LuCI.ui.FileUpload.html#.InitOptions">InitOptions</a></li>
  1834. </ul>
  1835. <ul class="typedefs itemMembers">
  1836. </ul>
  1837. <ul class="methods itemMembers">
  1838. <span class="subtitle">Methods</span>
  1839. <li data-name="LuCI.ui.FileUpload#getValidationError"><a href="LuCI.ui.FileUpload.html#getValidationError">getValidationError</a></li>
  1840. <li data-name="LuCI.ui.FileUpload#getValue"><a href="LuCI.ui.FileUpload.html#getValue">getValue</a></li>
  1841. <li data-name="LuCI.ui.FileUpload#isChanged"><a href="LuCI.ui.FileUpload.html#isChanged">isChanged</a></li>
  1842. <li data-name="LuCI.ui.FileUpload#isValid"><a href="LuCI.ui.FileUpload.html#isValid">isValid</a></li>
  1843. <li data-name="LuCI.ui.FileUpload#registerEvents"><a href="LuCI.ui.FileUpload.html#registerEvents">registerEvents</a></li>
  1844. <li data-name="LuCI.ui.FileUpload#render"><a href="LuCI.ui.FileUpload.html#render">render</a></li>
  1845. <li data-name="LuCI.ui.FileUpload#setChangeEvents"><a href="LuCI.ui.FileUpload.html#setChangeEvents">setChangeEvents</a></li>
  1846. <li data-name="LuCI.ui.FileUpload#setPlaceholder"><a href="LuCI.ui.FileUpload.html#setPlaceholder">setPlaceholder</a></li>
  1847. <li data-name="LuCI.ui.FileUpload#setUpdateEvents"><a href="LuCI.ui.FileUpload.html#setUpdateEvents">setUpdateEvents</a></li>
  1848. <li data-name="LuCI.ui.FileUpload#setValue"><a href="LuCI.ui.FileUpload.html#setValue">setValue</a></li>
  1849. <li data-name="LuCI.ui.FileUpload#triggerValidation"><a href="LuCI.ui.FileUpload.html#triggerValidation">triggerValidation</a></li>
  1850. </ul>
  1851. <ul class="events itemMembers">
  1852. </ul>
  1853. </li>
  1854. <li class="item" data-name="LuCI.ui.Hiddenfield">
  1855. <span class="title">
  1856. <a href="LuCI.ui.Hiddenfield.html">LuCI.ui.Hiddenfield</a>
  1857. </span>
  1858. <ul class="members itemMembers">
  1859. </ul>
  1860. <ul class="typedefs itemMembers">
  1861. </ul>
  1862. <ul class="typedefs itemMembers">
  1863. </ul>
  1864. <ul class="methods itemMembers">
  1865. <span class="subtitle">Methods</span>
  1866. <li data-name="LuCI.ui.Hiddenfield#getValidationError"><a href="LuCI.ui.Hiddenfield.html#getValidationError">getValidationError</a></li>
  1867. <li data-name="LuCI.ui.Hiddenfield#getValue"><a href="LuCI.ui.Hiddenfield.html#getValue">getValue</a></li>
  1868. <li data-name="LuCI.ui.Hiddenfield#isChanged"><a href="LuCI.ui.Hiddenfield.html#isChanged">isChanged</a></li>
  1869. <li data-name="LuCI.ui.Hiddenfield#isValid"><a href="LuCI.ui.Hiddenfield.html#isValid">isValid</a></li>
  1870. <li data-name="LuCI.ui.Hiddenfield#registerEvents"><a href="LuCI.ui.Hiddenfield.html#registerEvents">registerEvents</a></li>
  1871. <li data-name="LuCI.ui.Hiddenfield#render"><a href="LuCI.ui.Hiddenfield.html#render">render</a></li>
  1872. <li data-name="LuCI.ui.Hiddenfield#setChangeEvents"><a href="LuCI.ui.Hiddenfield.html#setChangeEvents">setChangeEvents</a></li>
  1873. <li data-name="LuCI.ui.Hiddenfield#setPlaceholder"><a href="LuCI.ui.Hiddenfield.html#setPlaceholder">setPlaceholder</a></li>
  1874. <li data-name="LuCI.ui.Hiddenfield#setUpdateEvents"><a href="LuCI.ui.Hiddenfield.html#setUpdateEvents">setUpdateEvents</a></li>
  1875. <li data-name="LuCI.ui.Hiddenfield#setValue"><a href="LuCI.ui.Hiddenfield.html#setValue">setValue</a></li>
  1876. <li data-name="LuCI.ui.Hiddenfield#triggerValidation"><a href="LuCI.ui.Hiddenfield.html#triggerValidation">triggerValidation</a></li>
  1877. </ul>
  1878. <ul class="events itemMembers">
  1879. </ul>
  1880. </li>
  1881. <li class="item" data-name="LuCI.ui.menu">
  1882. <span class="title">
  1883. <a href="LuCI.ui.menu.html">LuCI.ui.menu</a>
  1884. </span>
  1885. <ul class="members itemMembers">
  1886. </ul>
  1887. <ul class="typedefs itemMembers">
  1888. <span class="subtitle">Typedefs</span>
  1889. <li data-name="LuCI.ui.menu.MenuNode"><a href="LuCI.ui.menu.html#.MenuNode">MenuNode</a></li>
  1890. </ul>
  1891. <ul class="typedefs itemMembers">
  1892. </ul>
  1893. <ul class="methods itemMembers">
  1894. <span class="subtitle">Methods</span>
  1895. <li data-name="LuCI.ui.menu#flushCache"><a href="LuCI.ui.menu.html#flushCache">flushCache</a></li>
  1896. <li data-name="LuCI.ui.menu#getChildren"><a href="LuCI.ui.menu.html#getChildren">getChildren</a></li>
  1897. <li data-name="LuCI.ui.menu#load"><a href="LuCI.ui.menu.html#load">load</a></li>
  1898. </ul>
  1899. <ul class="events itemMembers">
  1900. </ul>
  1901. </li>
  1902. <li class="item" data-name="LuCI.ui.Select">
  1903. <span class="title">
  1904. <a href="LuCI.ui.Select.html">LuCI.ui.Select</a>
  1905. </span>
  1906. <ul class="members itemMembers">
  1907. </ul>
  1908. <ul class="typedefs itemMembers">
  1909. <span class="subtitle">Typedefs</span>
  1910. <li data-name="LuCI.ui.Select.InitOptions"><a href="LuCI.ui.Select.html#.InitOptions">InitOptions</a></li>
  1911. </ul>
  1912. <ul class="typedefs itemMembers">
  1913. </ul>
  1914. <ul class="methods itemMembers">
  1915. <span class="subtitle">Methods</span>
  1916. <li data-name="LuCI.ui.Select#getValidationError"><a href="LuCI.ui.Select.html#getValidationError">getValidationError</a></li>
  1917. <li data-name="LuCI.ui.Select#getValue"><a href="LuCI.ui.Select.html#getValue">getValue</a></li>
  1918. <li data-name="LuCI.ui.Select#isChanged"><a href="LuCI.ui.Select.html#isChanged">isChanged</a></li>
  1919. <li data-name="LuCI.ui.Select#isValid"><a href="LuCI.ui.Select.html#isValid">isValid</a></li>
  1920. <li data-name="LuCI.ui.Select#registerEvents"><a href="LuCI.ui.Select.html#registerEvents">registerEvents</a></li>
  1921. <li data-name="LuCI.ui.Select#render"><a href="LuCI.ui.Select.html#render">render</a></li>
  1922. <li data-name="LuCI.ui.Select#setChangeEvents"><a href="LuCI.ui.Select.html#setChangeEvents">setChangeEvents</a></li>
  1923. <li data-name="LuCI.ui.Select#setPlaceholder"><a href="LuCI.ui.Select.html#setPlaceholder">setPlaceholder</a></li>
  1924. <li data-name="LuCI.ui.Select#setUpdateEvents"><a href="LuCI.ui.Select.html#setUpdateEvents">setUpdateEvents</a></li>
  1925. <li data-name="LuCI.ui.Select#setValue"><a href="LuCI.ui.Select.html#setValue">setValue</a></li>
  1926. <li data-name="LuCI.ui.Select#triggerValidation"><a href="LuCI.ui.Select.html#triggerValidation">triggerValidation</a></li>
  1927. </ul>
  1928. <ul class="events itemMembers">
  1929. </ul>
  1930. </li>
  1931. <li class="item" data-name="LuCI.ui.tabs">
  1932. <span class="title">
  1933. <a href="LuCI.ui.tabs.html">LuCI.ui.tabs</a>
  1934. </span>
  1935. <ul class="members itemMembers">
  1936. </ul>
  1937. <ul class="typedefs itemMembers">
  1938. </ul>
  1939. <ul class="typedefs itemMembers">
  1940. </ul>
  1941. <ul class="methods itemMembers">
  1942. <span class="subtitle">Methods</span>
  1943. <li data-name="LuCI.ui.tabs#initTabGroup"><a href="LuCI.ui.tabs.html#initTabGroup">initTabGroup</a></li>
  1944. <li data-name="LuCI.ui.tabs#isEmptyPane"><a href="LuCI.ui.tabs.html#isEmptyPane">isEmptyPane</a></li>
  1945. </ul>
  1946. <ul class="events itemMembers">
  1947. </ul>
  1948. </li>
  1949. <li class="item" data-name="LuCI.ui.Textarea">
  1950. <span class="title">
  1951. <a href="LuCI.ui.Textarea.html">LuCI.ui.Textarea</a>
  1952. </span>
  1953. <ul class="members itemMembers">
  1954. </ul>
  1955. <ul class="typedefs itemMembers">
  1956. <span class="subtitle">Typedefs</span>
  1957. <li data-name="LuCI.ui.Textarea.InitOptions"><a href="LuCI.ui.Textarea.html#.InitOptions">InitOptions</a></li>
  1958. </ul>
  1959. <ul class="typedefs itemMembers">
  1960. </ul>
  1961. <ul class="methods itemMembers">
  1962. <span class="subtitle">Methods</span>
  1963. <li data-name="LuCI.ui.Textarea#getValidationError"><a href="LuCI.ui.Textarea.html#getValidationError">getValidationError</a></li>
  1964. <li data-name="LuCI.ui.Textarea#getValue"><a href="LuCI.ui.Textarea.html#getValue">getValue</a></li>
  1965. <li data-name="LuCI.ui.Textarea#isChanged"><a href="LuCI.ui.Textarea.html#isChanged">isChanged</a></li>
  1966. <li data-name="LuCI.ui.Textarea#isValid"><a href="LuCI.ui.Textarea.html#isValid">isValid</a></li>
  1967. <li data-name="LuCI.ui.Textarea#registerEvents"><a href="LuCI.ui.Textarea.html#registerEvents">registerEvents</a></li>
  1968. <li data-name="LuCI.ui.Textarea#render"><a href="LuCI.ui.Textarea.html#render">render</a></li>
  1969. <li data-name="LuCI.ui.Textarea#setChangeEvents"><a href="LuCI.ui.Textarea.html#setChangeEvents">setChangeEvents</a></li>
  1970. <li data-name="LuCI.ui.Textarea#setPlaceholder"><a href="LuCI.ui.Textarea.html#setPlaceholder">setPlaceholder</a></li>
  1971. <li data-name="LuCI.ui.Textarea#setUpdateEvents"><a href="LuCI.ui.Textarea.html#setUpdateEvents">setUpdateEvents</a></li>
  1972. <li data-name="LuCI.ui.Textarea#setValue"><a href="LuCI.ui.Textarea.html#setValue">setValue</a></li>
  1973. <li data-name="LuCI.ui.Textarea#triggerValidation"><a href="LuCI.ui.Textarea.html#triggerValidation">triggerValidation</a></li>
  1974. </ul>
  1975. <ul class="events itemMembers">
  1976. </ul>
  1977. </li>
  1978. <li class="item" data-name="LuCI.ui.Textfield">
  1979. <span class="title">
  1980. <a href="LuCI.ui.Textfield.html">LuCI.ui.Textfield</a>
  1981. </span>
  1982. <ul class="members itemMembers">
  1983. </ul>
  1984. <ul class="typedefs itemMembers">
  1985. <span class="subtitle">Typedefs</span>
  1986. <li data-name="LuCI.ui.Textfield.InitOptions"><a href="LuCI.ui.Textfield.html#.InitOptions">InitOptions</a></li>
  1987. </ul>
  1988. <ul class="typedefs itemMembers">
  1989. </ul>
  1990. <ul class="methods itemMembers">
  1991. <span class="subtitle">Methods</span>
  1992. <li data-name="LuCI.ui.Textfield#getValidationError"><a href="LuCI.ui.Textfield.html#getValidationError">getValidationError</a></li>
  1993. <li data-name="LuCI.ui.Textfield#getValue"><a href="LuCI.ui.Textfield.html#getValue">getValue</a></li>
  1994. <li data-name="LuCI.ui.Textfield#isChanged"><a href="LuCI.ui.Textfield.html#isChanged">isChanged</a></li>
  1995. <li data-name="LuCI.ui.Textfield#isValid"><a href="LuCI.ui.Textfield.html#isValid">isValid</a></li>
  1996. <li data-name="LuCI.ui.Textfield#registerEvents"><a href="LuCI.ui.Textfield.html#registerEvents">registerEvents</a></li>
  1997. <li data-name="LuCI.ui.Textfield#render"><a href="LuCI.ui.Textfield.html#render">render</a></li>
  1998. <li data-name="LuCI.ui.Textfield#setChangeEvents"><a href="LuCI.ui.Textfield.html#setChangeEvents">setChangeEvents</a></li>
  1999. <li data-name="LuCI.ui.Textfield#setPlaceholder"><a href="LuCI.ui.Textfield.html#setPlaceholder">setPlaceholder</a></li>
  2000. <li data-name="LuCI.ui.Textfield#setUpdateEvents"><a href="LuCI.ui.Textfield.html#setUpdateEvents">setUpdateEvents</a></li>
  2001. <li data-name="LuCI.ui.Textfield#setValue"><a href="LuCI.ui.Textfield.html#setValue">setValue</a></li>
  2002. <li data-name="LuCI.ui.Textfield#triggerValidation"><a href="LuCI.ui.Textfield.html#triggerValidation">triggerValidation</a></li>
  2003. </ul>
  2004. <ul class="events itemMembers">
  2005. </ul>
  2006. </li>
  2007. <li class="item" data-name="LuCI.view">
  2008. <span class="title">
  2009. <a href="LuCI.view.html">LuCI.view</a>
  2010. </span>
  2011. <ul class="members itemMembers">
  2012. </ul>
  2013. <ul class="typedefs itemMembers">
  2014. </ul>
  2015. <ul class="typedefs itemMembers">
  2016. </ul>
  2017. <ul class="methods itemMembers">
  2018. <span class="subtitle">Methods</span>
  2019. <li data-name="LuCI.view#addFooter"><a href="LuCI.view.html#addFooter">addFooter</a></li>
  2020. <li data-name="LuCI.view#handleReset"><a href="LuCI.view.html#handleReset">handleReset</a></li>
  2021. <li data-name="LuCI.view#handleSave"><a href="LuCI.view.html#handleSave">handleSave</a></li>
  2022. <li data-name="LuCI.view#handleSaveApply"><a href="LuCI.view.html#handleSaveApply">handleSaveApply</a></li>
  2023. <li data-name="LuCI.view#load"><a href="LuCI.view.html#load">load</a></li>
  2024. <li data-name="LuCI.view#render"><a href="LuCI.view.html#render">render</a></li>
  2025. </ul>
  2026. <ul class="events itemMembers">
  2027. </ul>
  2028. </li>
  2029. <li class="item" data-name="LuCI.xhr">
  2030. <span class="title">
  2031. <a href="LuCI.xhr.html">LuCI.xhr</a>
  2032. </span>
  2033. <ul class="members itemMembers">
  2034. </ul>
  2035. <ul class="typedefs itemMembers">
  2036. </ul>
  2037. <ul class="typedefs itemMembers">
  2038. </ul>
  2039. <ul class="methods itemMembers">
  2040. <span class="subtitle">Methods</span>
  2041. <li data-name="LuCI.xhr#abort"><a href="LuCI.xhr.html#abort">abort</a></li>
  2042. <li data-name="LuCI.xhr#busy"><a href="LuCI.xhr.html#busy">busy</a></li>
  2043. <li data-name="LuCI.xhr#cancel"><a href="LuCI.xhr.html#cancel">cancel</a></li>
  2044. <li data-name="LuCI.xhr#get"><a href="LuCI.xhr.html#get">get</a></li>
  2045. <li data-name="LuCI.xhr#post"><a href="LuCI.xhr.html#post">post</a></li>
  2046. <li data-name="LuCI.xhr#send_form"><a href="LuCI.xhr.html#send_form">send_form</a></li>
  2047. </ul>
  2048. <ul class="events itemMembers">
  2049. </ul>
  2050. </li>
  2051. </ul>
  2052. </div>
  2053. <div class="main">
  2054. <h1 class="page-title" data-filename="ui.js.html">Source: ui.js</h1>
  2055. <section>
  2056. <article>
  2057. <pre id="source-code" class="prettyprint source "><code>'use strict';
  2058. 'require validation';
  2059. 'require baseclass';
  2060. 'require request';
  2061. 'require session';
  2062. 'require poll';
  2063. 'require dom';
  2064. 'require rpc';
  2065. 'require uci';
  2066. 'require fs';
  2067. var modalDiv = null,
  2068. tooltipDiv = null,
  2069. indicatorDiv = null,
  2070. tooltipTimeout = null;
  2071. /**
  2072. * @class AbstractElement
  2073. * @memberof LuCI.ui
  2074. * @hideconstructor
  2075. * @classdesc
  2076. *
  2077. * The `AbstractElement` class serves as abstract base for the different widgets
  2078. * implemented by `LuCI.ui`. It provides the common logic for getting and
  2079. * setting values, for checking the validity state and for wiring up required
  2080. * events.
  2081. *
  2082. * UI widget instances are usually not supposed to be created by view code
  2083. * directly, instead they're implicitly created by `LuCI.form` when
  2084. * instantiating CBI forms.
  2085. *
  2086. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  2087. * in views, use `'require ui'` and refer to `ui.AbstractElement`. To import
  2088. * it in external JavaScript, use `L.require("ui").then(...)` and access the
  2089. * `AbstractElement` property of the class instance value.
  2090. */
  2091. var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ {
  2092. /**
  2093. * @typedef {Object} InitOptions
  2094. * @memberof LuCI.ui.AbstractElement
  2095. *
  2096. * @property {string} [id]
  2097. * Specifies the widget ID to use. It will be used as HTML `id` attribute
  2098. * on the toplevel widget DOM node.
  2099. *
  2100. * @property {string} [name]
  2101. * Specifies the widget name which is set as HTML `name` attribute on the
  2102. * corresponding `&lt;input>` element.
  2103. *
  2104. * @property {boolean} [optional=true]
  2105. * Specifies whether the input field allows empty values.
  2106. *
  2107. * @property {string} [datatype=string]
  2108. * An expression describing the input data validation constraints.
  2109. * It defaults to `string` which will allow any value.
  2110. * See {@link LuCI.validation} for details on the expression format.
  2111. *
  2112. * @property {function} [validator]
  2113. * Specifies a custom validator function which is invoked after the
  2114. * standard validation constraints are checked. The function should return
  2115. * `true` to accept the given input value. Any other return value type is
  2116. * converted to a string and treated as validation error message.
  2117. *
  2118. * @property {boolean} [disabled=false]
  2119. * Specifies whether the widget should be rendered in disabled state
  2120. * (`true`) or not (`false`). Disabled widgets cannot be interacted with
  2121. * and are displayed in a slightly faded style.
  2122. */
  2123. /**
  2124. * Read the current value of the input widget.
  2125. *
  2126. * @instance
  2127. * @memberof LuCI.ui.AbstractElement
  2128. * @returns {string|string[]|null}
  2129. * The current value of the input element. For simple inputs like text
  2130. * fields or selects, the return value type will be a - possibly empty -
  2131. * string. Complex widgets such as `DynamicList` instances may result in
  2132. * an array of strings or `null` for unset values.
  2133. */
  2134. getValue: function() {
  2135. if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
  2136. return this.node.value;
  2137. return null;
  2138. },
  2139. /**
  2140. * Set the current value of the input widget.
  2141. *
  2142. * @instance
  2143. * @memberof LuCI.ui.AbstractElement
  2144. * @param {string|string[]|null} value
  2145. * The value to set the input element to. For simple inputs like text
  2146. * fields or selects, the value should be a - possibly empty - string.
  2147. * Complex widgets such as `DynamicList` instances may accept string array
  2148. * or `null` values.
  2149. */
  2150. setValue: function(value) {
  2151. if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input'))
  2152. this.node.value = value;
  2153. },
  2154. /**
  2155. * Set the current placeholder value of the input widget.
  2156. *
  2157. * @instance
  2158. * @memberof LuCI.ui.AbstractElement
  2159. * @param {string|string[]|null} value
  2160. * The placeholder to set for the input element. Only applicable to text
  2161. * inputs, not to radio buttons, selects or similar.
  2162. */
  2163. setPlaceholder: function(value) {
  2164. var node = this.node ? this.node.querySelector('input,textarea') : null;
  2165. if (node) {
  2166. switch (node.getAttribute('type') || 'text') {
  2167. case 'password':
  2168. case 'search':
  2169. case 'tel':
  2170. case 'text':
  2171. case 'url':
  2172. if (value != null &amp;&amp; value != '')
  2173. node.setAttribute('placeholder', value);
  2174. else
  2175. node.removeAttribute('placeholder');
  2176. }
  2177. }
  2178. },
  2179. /**
  2180. * Check whether the input value was altered by the user.
  2181. *
  2182. * @instance
  2183. * @memberof LuCI.ui.AbstractElement
  2184. * @returns {boolean}
  2185. * Returns `true` if the input value has been altered by the user or
  2186. * `false` if it is unchanged. Note that if the user modifies the initial
  2187. * value and changes it back to the original state, it is still reported
  2188. * as changed.
  2189. */
  2190. isChanged: function() {
  2191. return (this.node ? this.node.getAttribute('data-changed') : null) == 'true';
  2192. },
  2193. /**
  2194. * Check whether the current input value is valid.
  2195. *
  2196. * @instance
  2197. * @memberof LuCI.ui.AbstractElement
  2198. * @returns {boolean}
  2199. * Returns `true` if the current input value is valid or `false` if it does
  2200. * not meet the validation constraints.
  2201. */
  2202. isValid: function() {
  2203. return (this.validState !== false);
  2204. },
  2205. /**
  2206. * Returns the current validation error
  2207. *
  2208. * @instance
  2209. * @memberof LuCI.ui.AbstractElement
  2210. * @returns {string}
  2211. * The validation error at this time
  2212. */
  2213. getValidationError: function() {
  2214. return this.validationError || '';
  2215. },
  2216. /**
  2217. * Force validation of the current input value.
  2218. *
  2219. * Usually input validation is automatically triggered by various DOM events
  2220. * bound to the input widget. In some cases it is required though to manually
  2221. * trigger validation runs, e.g. when programmatically altering values.
  2222. *
  2223. * @instance
  2224. * @memberof LuCI.ui.AbstractElement
  2225. */
  2226. triggerValidation: function() {
  2227. if (typeof(this.vfunc) != 'function')
  2228. return false;
  2229. var wasValid = this.isValid();
  2230. this.vfunc();
  2231. return (wasValid != this.isValid());
  2232. },
  2233. /**
  2234. * Dispatch a custom (synthetic) event in response to received events.
  2235. *
  2236. * Sets up event handlers on the given target DOM node for the given event
  2237. * names that dispatch a custom event of the given type to the widget root
  2238. * DOM node.
  2239. *
  2240. * The primary purpose of this function is to set up a series of custom
  2241. * uniform standard events such as `widget-update`, `validation-success`,
  2242. * `validation-failure` etc. which are triggered by various different
  2243. * widget specific native DOM events.
  2244. *
  2245. * @instance
  2246. * @memberof LuCI.ui.AbstractElement
  2247. * @param {Node} targetNode
  2248. * Specifies the DOM node on which the native event listeners should be
  2249. * registered.
  2250. *
  2251. * @param {string} synevent
  2252. * The name of the custom event to dispatch to the widget root DOM node.
  2253. *
  2254. * @param {string[]} events
  2255. * The native DOM events for which event handlers should be registered.
  2256. */
  2257. registerEvents: function(targetNode, synevent, events) {
  2258. var dispatchFn = L.bind(function(ev) {
  2259. this.node.dispatchEvent(new CustomEvent(synevent, { bubbles: true }));
  2260. }, this);
  2261. for (var i = 0; i &lt; events.length; i++)
  2262. targetNode.addEventListener(events[i], dispatchFn);
  2263. },
  2264. /**
  2265. * Set up listeners for native DOM events that may update the widget value.
  2266. *
  2267. * Sets up event handlers on the given target DOM node for the given event
  2268. * names which may cause the input value to update, such as `keyup` or
  2269. * `onclick` events. In contrast to change events, such update events will
  2270. * trigger input value validation.
  2271. *
  2272. * @instance
  2273. * @memberof LuCI.ui.AbstractElement
  2274. * @param {Node} targetNode
  2275. * Specifies the DOM node on which the event listeners should be registered.
  2276. *
  2277. * @param {...string} events
  2278. * The DOM events for which event handlers should be registered.
  2279. */
  2280. setUpdateEvents: function(targetNode /*, ... */) {
  2281. var datatype = this.options.datatype,
  2282. optional = this.options.hasOwnProperty('optional') ? this.options.optional : true,
  2283. validate = this.options.validate,
  2284. events = this.varargs(arguments, 1);
  2285. this.registerEvents(targetNode, 'widget-update', events);
  2286. if (!datatype &amp;&amp; !validate)
  2287. return;
  2288. this.vfunc = UI.prototype.addValidator.apply(UI.prototype, [
  2289. targetNode, datatype || 'string',
  2290. optional, validate
  2291. ].concat(events));
  2292. this.node.addEventListener('validation-success', L.bind(function(ev) {
  2293. this.validState = true;
  2294. this.validationError = '';
  2295. }, this));
  2296. this.node.addEventListener('validation-failure', L.bind(function(ev) {
  2297. this.validState = false;
  2298. this.validationError = ev.detail.message;
  2299. }, this));
  2300. },
  2301. /**
  2302. * Set up listeners for native DOM events that may change the widget value.
  2303. *
  2304. * Sets up event handlers on the given target DOM node for the given event
  2305. * names which may cause the input value to change completely, such as
  2306. * `change` events in a select menu. In contrast to update events, such
  2307. * change events will not trigger input value validation but they may cause
  2308. * field dependencies to get re-evaluated and will mark the input widget
  2309. * as dirty.
  2310. *
  2311. * @instance
  2312. * @memberof LuCI.ui.AbstractElement
  2313. * @param {Node} targetNode
  2314. * Specifies the DOM node on which the event listeners should be registered.
  2315. *
  2316. * @param {...string} events
  2317. * The DOM events for which event handlers should be registered.
  2318. */
  2319. setChangeEvents: function(targetNode /*, ... */) {
  2320. var tag_changed = L.bind(function(ev) { this.setAttribute('data-changed', true) }, this.node);
  2321. for (var i = 1; i &lt; arguments.length; i++)
  2322. targetNode.addEventListener(arguments[i], tag_changed);
  2323. this.registerEvents(targetNode, 'widget-change', this.varargs(arguments, 1));
  2324. },
  2325. /**
  2326. * Render the widget, set up event listeners and return resulting markup.
  2327. *
  2328. * @instance
  2329. * @memberof LuCI.ui.AbstractElement
  2330. *
  2331. * @returns {Node}
  2332. * Returns a DOM Node or DocumentFragment containing the rendered
  2333. * widget markup.
  2334. */
  2335. render: function() {}
  2336. });
  2337. /**
  2338. * Instantiate a text input widget.
  2339. *
  2340. * @constructor Textfield
  2341. * @memberof LuCI.ui
  2342. * @augments LuCI.ui.AbstractElement
  2343. *
  2344. * @classdesc
  2345. *
  2346. * The `Textfield` class implements a standard single line text input field.
  2347. *
  2348. * UI widget instances are usually not supposed to be created by view code
  2349. * directly, instead they're implicitly created by `LuCI.form` when
  2350. * instantiating CBI forms.
  2351. *
  2352. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  2353. * in views, use `'require ui'` and refer to `ui.Textfield`. To import it in
  2354. * external JavaScript, use `L.require("ui").then(...)` and access the
  2355. * `Textfield` property of the class instance value.
  2356. *
  2357. * @param {string} [value=null]
  2358. * The initial input value.
  2359. *
  2360. * @param {LuCI.ui.Textfield.InitOptions} [options]
  2361. * Object describing the widget specific options to initialize the input.
  2362. */
  2363. var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ {
  2364. /**
  2365. * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
  2366. * the following properties are recognized:
  2367. *
  2368. * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
  2369. * @memberof LuCI.ui.Textfield
  2370. *
  2371. * @property {boolean} [password=false]
  2372. * Specifies whether the input should be rendered as concealed password field.
  2373. *
  2374. * @property {boolean} [readonly=false]
  2375. * Specifies whether the input widget should be rendered readonly.
  2376. *
  2377. * @property {number} [maxlength]
  2378. * Specifies the HTML `maxlength` attribute to set on the corresponding
  2379. * `&lt;input>` element. Note that this a legacy property that exists for
  2380. * compatibility reasons. It is usually better to `maxlength(N)` validation
  2381. * expression.
  2382. *
  2383. * @property {string} [placeholder]
  2384. * Specifies the HTML `placeholder` attribute which is displayed when the
  2385. * corresponding `&lt;input>` element is empty.
  2386. */
  2387. __init__: function(value, options) {
  2388. this.value = value;
  2389. this.options = Object.assign({
  2390. optional: true,
  2391. password: false
  2392. }, options);
  2393. },
  2394. /** @override */
  2395. render: function() {
  2396. var frameEl = E('div', { 'id': this.options.id });
  2397. var inputEl = E('input', {
  2398. 'id': this.options.id ? 'widget.' + this.options.id : null,
  2399. 'name': this.options.name,
  2400. 'type': 'text',
  2401. 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text',
  2402. 'readonly': this.options.readonly ? '' : null,
  2403. 'disabled': this.options.disabled ? '' : null,
  2404. 'maxlength': this.options.maxlength,
  2405. 'placeholder': this.options.placeholder,
  2406. 'autocomplete': this.options.password ? 'new-password' : null,
  2407. 'value': this.value,
  2408. });
  2409. if (this.options.password) {
  2410. frameEl.appendChild(E('div', { 'class': 'control-group' }, [
  2411. inputEl,
  2412. E('button', {
  2413. 'class': 'cbi-button cbi-button-neutral',
  2414. 'title': _('Reveal/hide password'),
  2415. 'aria-label': _('Reveal/hide password'),
  2416. 'click': function(ev) {
  2417. var e = this.previousElementSibling;
  2418. e.type = (e.type === 'password') ? 'text' : 'password';
  2419. ev.preventDefault();
  2420. }
  2421. }, '∗')
  2422. ]));
  2423. window.requestAnimationFrame(function() { inputEl.type = 'password' });
  2424. }
  2425. else {
  2426. frameEl.appendChild(inputEl);
  2427. }
  2428. return this.bind(frameEl);
  2429. },
  2430. /** @private */
  2431. bind: function(frameEl) {
  2432. var inputEl = frameEl.querySelector('input');
  2433. this.node = frameEl;
  2434. this.setUpdateEvents(inputEl, 'keyup', 'blur');
  2435. this.setChangeEvents(inputEl, 'change');
  2436. dom.bindClassInstance(frameEl, this);
  2437. return frameEl;
  2438. },
  2439. /** @override */
  2440. getValue: function() {
  2441. var inputEl = this.node.querySelector('input');
  2442. return inputEl.value;
  2443. },
  2444. /** @override */
  2445. setValue: function(value) {
  2446. var inputEl = this.node.querySelector('input');
  2447. inputEl.value = value;
  2448. }
  2449. });
  2450. /**
  2451. * Instantiate a textarea widget.
  2452. *
  2453. * @constructor Textarea
  2454. * @memberof LuCI.ui
  2455. * @augments LuCI.ui.AbstractElement
  2456. *
  2457. * @classdesc
  2458. *
  2459. * The `Textarea` class implements a multiline text area input field.
  2460. *
  2461. * UI widget instances are usually not supposed to be created by view code
  2462. * directly, instead they're implicitly created by `LuCI.form` when
  2463. * instantiating CBI forms.
  2464. *
  2465. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  2466. * in views, use `'require ui'` and refer to `ui.Textarea`. To import it in
  2467. * external JavaScript, use `L.require("ui").then(...)` and access the
  2468. * `Textarea` property of the class instance value.
  2469. *
  2470. * @param {string} [value=null]
  2471. * The initial input value.
  2472. *
  2473. * @param {LuCI.ui.Textarea.InitOptions} [options]
  2474. * Object describing the widget specific options to initialize the input.
  2475. */
  2476. var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ {
  2477. /**
  2478. * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
  2479. * the following properties are recognized:
  2480. *
  2481. * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
  2482. * @memberof LuCI.ui.Textarea
  2483. *
  2484. * @property {boolean} [readonly=false]
  2485. * Specifies whether the input widget should be rendered readonly.
  2486. *
  2487. * @property {string} [placeholder]
  2488. * Specifies the HTML `placeholder` attribute which is displayed when the
  2489. * corresponding `&lt;textarea>` element is empty.
  2490. *
  2491. * @property {boolean} [monospace=false]
  2492. * Specifies whether a monospace font should be forced for the textarea
  2493. * contents.
  2494. *
  2495. * @property {number} [cols]
  2496. * Specifies the HTML `cols` attribute to set on the corresponding
  2497. * `&lt;textarea>` element.
  2498. *
  2499. * @property {number} [rows]
  2500. * Specifies the HTML `rows` attribute to set on the corresponding
  2501. * `&lt;textarea>` element.
  2502. *
  2503. * @property {boolean} [wrap=false]
  2504. * Specifies whether the HTML `wrap` attribute should be set.
  2505. */
  2506. __init__: function(value, options) {
  2507. this.value = value;
  2508. this.options = Object.assign({
  2509. optional: true,
  2510. wrap: false,
  2511. cols: null,
  2512. rows: null
  2513. }, options);
  2514. },
  2515. /** @override */
  2516. render: function() {
  2517. var style = !this.options.cols ? 'width:100%' : null,
  2518. frameEl = E('div', { 'id': this.options.id, 'style': style }),
  2519. value = (this.value != null) ? String(this.value) : '';
  2520. frameEl.appendChild(E('textarea', {
  2521. 'id': this.options.id ? 'widget.' + this.options.id : null,
  2522. 'name': this.options.name,
  2523. 'class': 'cbi-input-textarea',
  2524. 'readonly': this.options.readonly ? '' : null,
  2525. 'disabled': this.options.disabled ? '' : null,
  2526. 'placeholder': this.options.placeholder,
  2527. 'style': style,
  2528. 'cols': this.options.cols,
  2529. 'rows': this.options.rows,
  2530. 'wrap': this.options.wrap ? 'soft' : 'off'
  2531. }, [ value ]));
  2532. if (this.options.monospace)
  2533. frameEl.firstElementChild.style.fontFamily = 'monospace';
  2534. return this.bind(frameEl);
  2535. },
  2536. /** @private */
  2537. bind: function(frameEl) {
  2538. var inputEl = frameEl.firstElementChild;
  2539. this.node = frameEl;
  2540. this.setUpdateEvents(inputEl, 'keyup', 'blur');
  2541. this.setChangeEvents(inputEl, 'change');
  2542. dom.bindClassInstance(frameEl, this);
  2543. return frameEl;
  2544. },
  2545. /** @override */
  2546. getValue: function() {
  2547. return this.node.firstElementChild.value;
  2548. },
  2549. /** @override */
  2550. setValue: function(value) {
  2551. this.node.firstElementChild.value = value;
  2552. }
  2553. });
  2554. /**
  2555. * Instantiate a checkbox widget.
  2556. *
  2557. * @constructor Checkbox
  2558. * @memberof LuCI.ui
  2559. * @augments LuCI.ui.AbstractElement
  2560. *
  2561. * @classdesc
  2562. *
  2563. * The `Checkbox` class implements a simple checkbox input field.
  2564. *
  2565. * UI widget instances are usually not supposed to be created by view code
  2566. * directly, instead they're implicitly created by `LuCI.form` when
  2567. * instantiating CBI forms.
  2568. *
  2569. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  2570. * in views, use `'require ui'` and refer to `ui.Checkbox`. To import it in
  2571. * external JavaScript, use `L.require("ui").then(...)` and access the
  2572. * `Checkbox` property of the class instance value.
  2573. *
  2574. * @param {string} [value=null]
  2575. * The initial input value.
  2576. *
  2577. * @param {LuCI.ui.Checkbox.InitOptions} [options]
  2578. * Object describing the widget specific options to initialize the input.
  2579. */
  2580. var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ {
  2581. /**
  2582. * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
  2583. * the following properties are recognized:
  2584. *
  2585. * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
  2586. * @memberof LuCI.ui.Checkbox
  2587. *
  2588. * @property {string} [value_enabled=1]
  2589. * Specifies the value corresponding to a checked checkbox.
  2590. *
  2591. * @property {string} [value_disabled=0]
  2592. * Specifies the value corresponding to an unchecked checkbox.
  2593. *
  2594. * @property {string} [hiddenname]
  2595. * Specifies the HTML `name` attribute of the hidden input backing the
  2596. * checkbox. This is a legacy property existing for compatibility reasons,
  2597. * it is required for HTML based form submissions.
  2598. */
  2599. __init__: function(value, options) {
  2600. this.value = value;
  2601. this.options = Object.assign({
  2602. value_enabled: '1',
  2603. value_disabled: '0'
  2604. }, options);
  2605. },
  2606. /** @override */
  2607. render: function() {
  2608. var id = 'cb%08x'.format(Math.random() * 0xffffffff);
  2609. var frameEl = E('div', {
  2610. 'id': this.options.id,
  2611. 'class': 'cbi-checkbox'
  2612. });
  2613. if (this.options.hiddenname)
  2614. frameEl.appendChild(E('input', {
  2615. 'type': 'hidden',
  2616. 'name': this.options.hiddenname,
  2617. 'value': 1
  2618. }));
  2619. frameEl.appendChild(E('input', {
  2620. 'id': id,
  2621. 'name': this.options.name,
  2622. 'type': 'checkbox',
  2623. 'value': this.options.value_enabled,
  2624. 'checked': (this.value == this.options.value_enabled) ? '' : null,
  2625. 'disabled': this.options.disabled ? '' : null,
  2626. 'data-widget-id': this.options.id ? 'widget.' + this.options.id : null
  2627. }));
  2628. frameEl.appendChild(E('label', { 'for': id }));
  2629. if (this.options.tooltip != null) {
  2630. var icon = "⚠️";
  2631. if (this.options.tooltipicon != null)
  2632. icon = this.options.tooltipicon;
  2633. frameEl.appendChild(
  2634. E('label', { 'class': 'cbi-tooltip-container' },[
  2635. icon,
  2636. E('div', { 'class': 'cbi-tooltip' },
  2637. this.options.tooltip
  2638. )
  2639. ])
  2640. );
  2641. }
  2642. return this.bind(frameEl);
  2643. },
  2644. /** @private */
  2645. bind: function(frameEl) {
  2646. this.node = frameEl;
  2647. var input = frameEl.querySelector('input[type="checkbox"]');
  2648. this.setUpdateEvents(input, 'click', 'blur');
  2649. this.setChangeEvents(input, 'change');
  2650. dom.bindClassInstance(frameEl, this);
  2651. return frameEl;
  2652. },
  2653. /**
  2654. * Test whether the checkbox is currently checked.
  2655. *
  2656. * @instance
  2657. * @memberof LuCI.ui.Checkbox
  2658. * @returns {boolean}
  2659. * Returns `true` when the checkbox is currently checked, otherwise `false`.
  2660. */
  2661. isChecked: function() {
  2662. return this.node.querySelector('input[type="checkbox"]').checked;
  2663. },
  2664. /** @override */
  2665. getValue: function() {
  2666. return this.isChecked()
  2667. ? this.options.value_enabled
  2668. : this.options.value_disabled;
  2669. },
  2670. /** @override */
  2671. setValue: function(value) {
  2672. this.node.querySelector('input[type="checkbox"]').checked = (value == this.options.value_enabled);
  2673. }
  2674. });
  2675. /**
  2676. * Instantiate a select dropdown or checkbox/radiobutton group.
  2677. *
  2678. * @constructor Select
  2679. * @memberof LuCI.ui
  2680. * @augments LuCI.ui.AbstractElement
  2681. *
  2682. * @classdesc
  2683. *
  2684. * The `Select` class implements either a traditional HTML `&lt;select>` element
  2685. * or a group of checkboxes or radio buttons, depending on whether multiple
  2686. * values are enabled or not.
  2687. *
  2688. * UI widget instances are usually not supposed to be created by view code
  2689. * directly, instead they're implicitly created by `LuCI.form` when
  2690. * instantiating CBI forms.
  2691. *
  2692. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  2693. * in views, use `'require ui'` and refer to `ui.Select`. To import it in
  2694. * external JavaScript, use `L.require("ui").then(...)` and access the
  2695. * `Select` property of the class instance value.
  2696. *
  2697. * @param {string|string[]} [value=null]
  2698. * The initial input value(s).
  2699. *
  2700. * @param {Object&lt;string, string>} choices
  2701. * Object containing the selectable choices of the widget. The object keys
  2702. * serve as values for the different choices while the values are used as
  2703. * choice labels.
  2704. *
  2705. * @param {LuCI.ui.Select.InitOptions} [options]
  2706. * Object describing the widget specific options to initialize the inputs.
  2707. */
  2708. var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ {
  2709. /**
  2710. * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
  2711. * the following properties are recognized:
  2712. *
  2713. * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
  2714. * @memberof LuCI.ui.Select
  2715. *
  2716. * @property {boolean} [multiple=false]
  2717. * Specifies whether multiple choice values may be selected.
  2718. *
  2719. * @property {"select"|"individual"} [widget=select]
  2720. * Specifies the kind of widget to render. May be either `select` or
  2721. * `individual`. When set to `select` an HTML `&lt;select>` element will be
  2722. * used, otherwise a group of checkbox or radio button elements is created,
  2723. * depending on the value of the `multiple` option.
  2724. *
  2725. * @property {string} [orientation=horizontal]
  2726. * Specifies whether checkbox / radio button groups should be rendered
  2727. * in a `horizontal` or `vertical` manner. Does not apply to the `select`
  2728. * widget type.
  2729. *
  2730. * @property {boolean|string[]} [sort=false]
  2731. * Specifies if and how to sort choice values. If set to `true`, the choice
  2732. * values will be sorted alphabetically. If set to an array of strings, the
  2733. * choice sort order is derived from the array.
  2734. *
  2735. * @property {number} [size]
  2736. * Specifies the HTML `size` attribute to set on the `&lt;select>` element.
  2737. * Only applicable to the `select` widget type.
  2738. *
  2739. * @property {string} [placeholder=-- Please choose --]
  2740. * Specifies a placeholder text which is displayed when no choice is
  2741. * selected yet. Only applicable to the `select` widget type.
  2742. */
  2743. __init__: function(value, choices, options) {
  2744. if (!L.isObject(choices))
  2745. choices = {};
  2746. if (!Array.isArray(value))
  2747. value = (value != null &amp;&amp; value != '') ? [ value ] : [];
  2748. if (!options.multiple &amp;&amp; value.length > 1)
  2749. value.length = 1;
  2750. this.values = value;
  2751. this.choices = choices;
  2752. this.options = Object.assign({
  2753. multiple: false,
  2754. widget: 'select',
  2755. orientation: 'horizontal'
  2756. }, options);
  2757. if (this.choices.hasOwnProperty(''))
  2758. this.options.optional = true;
  2759. },
  2760. /** @override */
  2761. render: function() {
  2762. var frameEl = E('div', { 'id': this.options.id }),
  2763. keys = Object.keys(this.choices);
  2764. if (this.options.sort === true)
  2765. keys.sort(L.naturalCompare);
  2766. else if (Array.isArray(this.options.sort))
  2767. keys = this.options.sort;
  2768. if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox') {
  2769. frameEl.appendChild(E('select', {
  2770. 'id': this.options.id ? 'widget.' + this.options.id : null,
  2771. 'name': this.options.name,
  2772. 'size': this.options.size,
  2773. 'class': 'cbi-input-select',
  2774. 'multiple': this.options.multiple ? '' : null,
  2775. 'disabled': this.options.disabled ? '' : null
  2776. }));
  2777. if (this.options.optional)
  2778. frameEl.lastChild.appendChild(E('option', {
  2779. 'value': '',
  2780. 'selected': (this.values.length == 0 || this.values[0] == '') ? '' : null
  2781. }, [ this.choices[''] || this.options.placeholder || _('-- Please choose --') ]));
  2782. for (var i = 0; i &lt; keys.length; i++) {
  2783. if (keys[i] == null || keys[i] == '')
  2784. continue;
  2785. frameEl.lastChild.appendChild(E('option', {
  2786. 'value': keys[i],
  2787. 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
  2788. }, [ this.choices[keys[i]] || keys[i] ]));
  2789. }
  2790. }
  2791. else {
  2792. var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' \xa0 ') : E('br');
  2793. for (var i = 0; i &lt; keys.length; i++) {
  2794. frameEl.appendChild(E('span', {
  2795. 'class': 'cbi-%s'.format(this.options.multiple ? 'checkbox' : 'radio')
  2796. }, [
  2797. E('input', {
  2798. 'id': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null,
  2799. 'name': this.options.id || this.options.name,
  2800. 'type': this.options.multiple ? 'checkbox' : 'radio',
  2801. 'class': this.options.multiple ? 'cbi-input-checkbox' : 'cbi-input-radio',
  2802. 'value': keys[i],
  2803. 'checked': (this.values.indexOf(keys[i]) > -1) ? '' : null,
  2804. 'disabled': this.options.disabled ? '' : null
  2805. }),
  2806. E('label', { 'for': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null }),
  2807. E('span', {
  2808. 'click': function(ev) {
  2809. ev.currentTarget.previousElementSibling.previousElementSibling.click();
  2810. }
  2811. }, [ this.choices[keys[i]] || keys[i] ])
  2812. ]));
  2813. frameEl.appendChild(brEl.cloneNode());
  2814. }
  2815. }
  2816. return this.bind(frameEl);
  2817. },
  2818. /** @private */
  2819. bind: function(frameEl) {
  2820. this.node = frameEl;
  2821. if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox') {
  2822. this.setUpdateEvents(frameEl.firstChild, 'change', 'click', 'blur');
  2823. this.setChangeEvents(frameEl.firstChild, 'change');
  2824. }
  2825. else {
  2826. var radioEls = frameEl.querySelectorAll('input[type="radio"]');
  2827. for (var i = 0; i &lt; radioEls.length; i++) {
  2828. this.setUpdateEvents(radioEls[i], 'change', 'click', 'blur');
  2829. this.setChangeEvents(radioEls[i], 'change', 'click', 'blur');
  2830. }
  2831. }
  2832. dom.bindClassInstance(frameEl, this);
  2833. return frameEl;
  2834. },
  2835. /** @override */
  2836. getValue: function() {
  2837. if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox')
  2838. return this.node.firstChild.value;
  2839. var radioEls = this.node.querySelectorAll('input[type="radio"]');
  2840. for (var i = 0; i &lt; radioEls.length; i++)
  2841. if (radioEls[i].checked)
  2842. return radioEls[i].value;
  2843. return null;
  2844. },
  2845. /** @override */
  2846. setValue: function(value) {
  2847. if (this.options.widget != 'radio' &amp;&amp; this.options.widget != 'checkbox') {
  2848. if (value == null)
  2849. value = '';
  2850. for (var i = 0; i &lt; this.node.firstChild.options.length; i++)
  2851. this.node.firstChild.options[i].selected = (this.node.firstChild.options[i].value == value);
  2852. return;
  2853. }
  2854. var radioEls = frameEl.querySelectorAll('input[type="radio"]');
  2855. for (var i = 0; i &lt; radioEls.length; i++)
  2856. radioEls[i].checked = (radioEls[i].value == value);
  2857. }
  2858. });
  2859. /**
  2860. * Instantiate a rich dropdown choice widget.
  2861. *
  2862. * @constructor Dropdown
  2863. * @memberof LuCI.ui
  2864. * @augments LuCI.ui.AbstractElement
  2865. *
  2866. * @classdesc
  2867. *
  2868. * The `Dropdown` class implements a rich, stylable dropdown menu which
  2869. * supports non-text choice labels.
  2870. *
  2871. * UI widget instances are usually not supposed to be created by view code
  2872. * directly, instead they're implicitly created by `LuCI.form` when
  2873. * instantiating CBI forms.
  2874. *
  2875. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  2876. * in views, use `'require ui'` and refer to `ui.Dropdown`. To import it in
  2877. * external JavaScript, use `L.require("ui").then(...)` and access the
  2878. * `Dropdown` property of the class instance value.
  2879. *
  2880. * @param {string|string[]} [value=null]
  2881. * The initial input value(s).
  2882. *
  2883. * @param {Object&lt;string, *>} choices
  2884. * Object containing the selectable choices of the widget. The object keys
  2885. * serve as values for the different choices while the values are used as
  2886. * choice labels.
  2887. *
  2888. * @param {LuCI.ui.Dropdown.InitOptions} [options]
  2889. * Object describing the widget specific options to initialize the dropdown.
  2890. */
  2891. var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
  2892. /**
  2893. * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
  2894. * the following properties are recognized:
  2895. *
  2896. * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
  2897. * @memberof LuCI.ui.Dropdown
  2898. *
  2899. * @property {boolean} [optional=true]
  2900. * Specifies whether the dropdown selection is optional. In contrast to
  2901. * other widgets, the `optional` constraint of dropdowns works differently;
  2902. * instead of marking the widget invalid on empty values when set to `false`,
  2903. * the user is not allowed to deselect all choices.
  2904. *
  2905. * For single value dropdowns that means that no empty "please select"
  2906. * choice is offered and for multi value dropdowns, the last selected choice
  2907. * may not be deselected without selecting another choice first.
  2908. *
  2909. * @property {boolean} [multiple]
  2910. * Specifies whether multiple choice values may be selected. It defaults
  2911. * to `true` when an array is passed as input value to the constructor.
  2912. *
  2913. * @property {boolean|string[]} [sort=false]
  2914. * Specifies if and how to sort choice values. If set to `true`, the choice
  2915. * values will be sorted alphabetically. If set to an array of strings, the
  2916. * choice sort order is derived from the array.
  2917. *
  2918. * @property {string} [select_placeholder=-- Please choose --]
  2919. * Specifies a placeholder text which is displayed when no choice is
  2920. * selected yet.
  2921. *
  2922. * @property {string} [custom_placeholder=-- custom --]
  2923. * Specifies a placeholder text which is displayed in the text input
  2924. * field allowing to enter custom choice values. Only applicable if the
  2925. * `create` option is set to `true`.
  2926. *
  2927. * @property {boolean} [create=false]
  2928. * Specifies whether custom choices may be entered into the dropdown
  2929. * widget.
  2930. *
  2931. * @property {string} [create_query=.create-item-input]
  2932. * Specifies a CSS selector expression used to find the input element
  2933. * which is used to enter custom choice values. This should not normally
  2934. * be used except by widgets derived from the Dropdown class.
  2935. *
  2936. * @property {string} [create_template=script[type="item-template"]]
  2937. * Specifies a CSS selector expression used to find an HTML element
  2938. * serving as template for newly added custom choice values.
  2939. *
  2940. * Any `{{value}}` placeholder string within the template elements text
  2941. * content will be replaced by the user supplied choice value, the
  2942. * resulting string is parsed as HTML and appended to the end of the
  2943. * choice list. The template markup may specify one HTML element with a
  2944. * `data-label-placeholder` attribute which is replaced by a matching
  2945. * label value from the `choices` object or with the user supplied value
  2946. * itself in case `choices` contains no matching choice label.
  2947. *
  2948. * If the template element is not found or if no `create_template` selector
  2949. * expression is specified, the default markup for newly created elements is
  2950. * `&lt;li data-value="{{value}}">&lt;span data-label-placeholder="true" />&lt;/li>`.
  2951. *
  2952. * @property {string} [create_markup]
  2953. * This property allows specifying the markup for custom choices directly
  2954. * instead of referring to a template element through CSS selectors.
  2955. *
  2956. * Apart from that it works exactly like `create_template`.
  2957. *
  2958. * @property {number} [display_items=3]
  2959. * Specifies the maximum amount of choice labels that should be shown in
  2960. * collapsed dropdown state before further selected choices are cut off.
  2961. *
  2962. * Only applicable when `multiple` is `true`.
  2963. *
  2964. * @property {number} [dropdown_items=-1]
  2965. * Specifies the maximum amount of choices that should be shown when the
  2966. * dropdown is open. If the amount of available choices exceeds this number,
  2967. * the dropdown area must be scrolled to reach further items.
  2968. *
  2969. * If set to `-1`, the dropdown menu will attempt to show all choice values
  2970. * and only resort to scrolling if the amount of choices exceeds the available
  2971. * screen space above and below the dropdown widget.
  2972. *
  2973. * @property {string} [placeholder]
  2974. * This property serves as a shortcut to set both `select_placeholder` and
  2975. * `custom_placeholder`. Either of these properties will fallback to
  2976. * `placeholder` if not specified.
  2977. *
  2978. * @property {boolean} [readonly=false]
  2979. * Specifies whether the custom choice input field should be rendered
  2980. * readonly. Only applicable when `create` is `true`.
  2981. *
  2982. * @property {number} [maxlength]
  2983. * Specifies the HTML `maxlength` attribute to set on the custom choice
  2984. * `&lt;input>` element. Note that this a legacy property that exists for
  2985. * compatibility reasons. It is usually better to `maxlength(N)` validation
  2986. * expression. Only applicable when `create` is `true`.
  2987. */
  2988. __init__: function(value, choices, options) {
  2989. if (typeof(choices) != 'object')
  2990. choices = {};
  2991. if (!Array.isArray(value))
  2992. this.values = (value != null &amp;&amp; value != '') ? [ value ] : [];
  2993. else
  2994. this.values = value;
  2995. this.choices = choices;
  2996. this.options = Object.assign({
  2997. sort: true,
  2998. multiple: Array.isArray(value),
  2999. optional: true,
  3000. select_placeholder: _('-- Please choose --'),
  3001. custom_placeholder: _('-- custom --'),
  3002. display_items: 3,
  3003. dropdown_items: -1,
  3004. create: false,
  3005. create_query: '.create-item-input',
  3006. create_template: 'script[type="item-template"]'
  3007. }, options);
  3008. },
  3009. /** @override */
  3010. render: function() {
  3011. var sb = E('div', {
  3012. 'id': this.options.id,
  3013. 'class': 'cbi-dropdown',
  3014. 'multiple': this.options.multiple ? '' : null,
  3015. 'optional': this.options.optional ? '' : null,
  3016. 'disabled': this.options.disabled ? '' : null,
  3017. 'tabindex': -1
  3018. }, E('ul'));
  3019. var keys = Object.keys(this.choices);
  3020. if (this.options.sort === true)
  3021. keys.sort(L.naturalCompare);
  3022. else if (Array.isArray(this.options.sort))
  3023. keys = this.options.sort;
  3024. if (this.options.create)
  3025. for (var i = 0; i &lt; this.values.length; i++)
  3026. if (!this.choices.hasOwnProperty(this.values[i]))
  3027. keys.push(this.values[i]);
  3028. for (var i = 0; i &lt; keys.length; i++) {
  3029. var label = this.choices[keys[i]];
  3030. if (dom.elem(label))
  3031. label = label.cloneNode(true);
  3032. sb.lastElementChild.appendChild(E('li', {
  3033. 'data-value': keys[i],
  3034. 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
  3035. }, [ label || keys[i] ]));
  3036. }
  3037. if (this.options.create) {
  3038. var createEl = E('input', {
  3039. 'type': 'text',
  3040. 'class': 'create-item-input',
  3041. 'readonly': this.options.readonly ? '' : null,
  3042. 'maxlength': this.options.maxlength,
  3043. 'placeholder': this.options.custom_placeholder || this.options.placeholder
  3044. });
  3045. if (this.options.datatype || this.options.validate)
  3046. UI.prototype.addValidator(createEl, this.options.datatype || 'string',
  3047. true, this.options.validate, 'blur', 'keyup');
  3048. sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl));
  3049. }
  3050. if (this.options.create_markup)
  3051. sb.appendChild(E('script', { type: 'item-template' },
  3052. this.options.create_markup));
  3053. return this.bind(sb);
  3054. },
  3055. /** @private */
  3056. bind: function(sb) {
  3057. var o = this.options;
  3058. o.multiple = sb.hasAttribute('multiple');
  3059. o.optional = sb.hasAttribute('optional');
  3060. o.placeholder = sb.getAttribute('placeholder') || o.placeholder;
  3061. o.display_items = parseInt(sb.getAttribute('display-items') || o.display_items);
  3062. o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') || o.dropdown_items);
  3063. o.create_query = sb.getAttribute('item-create') || o.create_query;
  3064. o.create_template = sb.getAttribute('item-template') || o.create_template;
  3065. var ul = sb.querySelector('ul'),
  3066. more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')),
  3067. open = sb.appendChild(E('span', { class: 'open', tabindex: -1 }, '▾')),
  3068. canary = sb.appendChild(E('div')),
  3069. create = sb.querySelector(this.options.create_query),
  3070. ndisplay = this.options.display_items,
  3071. n = 0;
  3072. if (this.options.multiple) {
  3073. var items = ul.querySelectorAll('li');
  3074. for (var i = 0; i &lt; items.length; i++) {
  3075. this.transformItem(sb, items[i]);
  3076. if (items[i].hasAttribute('selected') &amp;&amp; ndisplay-- > 0)
  3077. items[i].setAttribute('display', n++);
  3078. }
  3079. }
  3080. else {
  3081. if (this.options.optional &amp;&amp; !ul.querySelector('li[data-value=""]')) {
  3082. var placeholder = E('li', { placeholder: '' },
  3083. this.options.select_placeholder || this.options.placeholder);
  3084. ul.firstChild
  3085. ? ul.insertBefore(placeholder, ul.firstChild)
  3086. : ul.appendChild(placeholder);
  3087. }
  3088. var items = ul.querySelectorAll('li'),
  3089. sel = sb.querySelectorAll('[selected]');
  3090. sel.forEach(function(s) {
  3091. s.removeAttribute('selected');
  3092. });
  3093. var s = sel[0] || items[0];
  3094. if (s) {
  3095. s.setAttribute('selected', '');
  3096. s.setAttribute('display', n++);
  3097. }
  3098. ndisplay--;
  3099. }
  3100. this.saveValues(sb, ul);
  3101. ul.setAttribute('tabindex', -1);
  3102. sb.setAttribute('tabindex', 0);
  3103. if (ndisplay &lt; 0)
  3104. sb.setAttribute('more', '')
  3105. else
  3106. sb.removeAttribute('more');
  3107. if (ndisplay == this.options.display_items)
  3108. sb.setAttribute('empty', '')
  3109. else
  3110. sb.removeAttribute('empty');
  3111. dom.content(more, (ndisplay == this.options.display_items)
  3112. ? (this.options.select_placeholder || this.options.placeholder) : '···');
  3113. sb.addEventListener('click', this.handleClick.bind(this));
  3114. sb.addEventListener('keydown', this.handleKeydown.bind(this));
  3115. sb.addEventListener('cbi-dropdown-close', this.handleDropdownClose.bind(this));
  3116. sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this));
  3117. if ('ontouchstart' in window) {
  3118. sb.addEventListener('touchstart', function(ev) { ev.stopPropagation(); });
  3119. window.addEventListener('touchstart', this.closeAllDropdowns);
  3120. }
  3121. else {
  3122. sb.addEventListener('focus', this.handleFocus.bind(this));
  3123. canary.addEventListener('focus', this.handleCanaryFocus.bind(this));
  3124. window.addEventListener('click', this.closeAllDropdowns);
  3125. }
  3126. if (create) {
  3127. create.addEventListener('keydown', this.handleCreateKeydown.bind(this));
  3128. create.addEventListener('focus', this.handleCreateFocus.bind(this));
  3129. create.addEventListener('blur', this.handleCreateBlur.bind(this));
  3130. var li = findParent(create, 'li');
  3131. li.setAttribute('unselectable', '');
  3132. li.addEventListener('click', this.handleCreateClick.bind(this));
  3133. }
  3134. this.node = sb;
  3135. this.setUpdateEvents(sb, 'cbi-dropdown-open', 'cbi-dropdown-close');
  3136. this.setChangeEvents(sb, 'cbi-dropdown-change', 'cbi-dropdown-close');
  3137. dom.bindClassInstance(sb, this);
  3138. return sb;
  3139. },
  3140. /** @private */
  3141. getScrollParent: function(element) {
  3142. var parent = element,
  3143. style = getComputedStyle(element),
  3144. excludeStaticParent = (style.position === 'absolute');
  3145. if (style.position === 'fixed')
  3146. return document.body;
  3147. while ((parent = parent.parentElement) != null) {
  3148. style = getComputedStyle(parent);
  3149. if (excludeStaticParent &amp;&amp; style.position === 'static')
  3150. continue;
  3151. if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX))
  3152. return parent;
  3153. }
  3154. return document.body;
  3155. },
  3156. /** @private */
  3157. openDropdown: function(sb) {
  3158. var st = window.getComputedStyle(sb, null),
  3159. ul = sb.querySelector('ul'),
  3160. li = ul.querySelectorAll('li'),
  3161. fl = findParent(sb, '.cbi-value-field'),
  3162. sel = ul.querySelector('[selected]'),
  3163. rect = sb.getBoundingClientRect(),
  3164. items = Math.min(this.options.dropdown_items, li.length),
  3165. scrollParent = this.getScrollParent(sb);
  3166. document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
  3167. s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
  3168. });
  3169. sb.setAttribute('open', '');
  3170. var pv = ul.cloneNode(true);
  3171. pv.classList.add('preview');
  3172. if (fl)
  3173. fl.classList.add('cbi-dropdown-open');
  3174. if ('ontouchstart' in window) {
  3175. var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
  3176. vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
  3177. start = null;
  3178. ul.style.top = sb.offsetHeight + 'px';
  3179. ul.style.left = -rect.left + 'px';
  3180. ul.style.right = (rect.right - vpWidth) + 'px';
  3181. ul.style.maxHeight = (vpHeight * 0.5) + 'px';
  3182. ul.style.WebkitOverflowScrolling = 'touch';
  3183. var scrollFrom = scrollParent.scrollTop,
  3184. scrollTo = scrollFrom + rect.top - vpHeight * 0.5;
  3185. var scrollStep = function(timestamp) {
  3186. if (!start) {
  3187. start = timestamp;
  3188. ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
  3189. }
  3190. var duration = Math.max(timestamp - start, 1);
  3191. if (duration &lt; 100) {
  3192. scrollParent.scrollTop = scrollFrom + (scrollTo - scrollFrom) * (duration / 100);
  3193. window.requestAnimationFrame(scrollStep);
  3194. }
  3195. else {
  3196. scrollParent.scrollTop = scrollTo;
  3197. }
  3198. };
  3199. window.requestAnimationFrame(scrollStep);
  3200. }
  3201. else {
  3202. ul.style.maxHeight = '1px';
  3203. ul.style.top = ul.style.bottom = '';
  3204. window.requestAnimationFrame(function() {
  3205. var containerRect = scrollParent.getBoundingClientRect(),
  3206. itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height,
  3207. fullHeight = 0,
  3208. spaceAbove = rect.top - containerRect.top,
  3209. spaceBelow = containerRect.bottom - rect.bottom;
  3210. for (var i = 0; i &lt; (items == -1 ? li.length : items); i++)
  3211. fullHeight += li[i].getBoundingClientRect().height;
  3212. if (fullHeight &lt;= spaceBelow) {
  3213. ul.style.top = rect.height + 'px';
  3214. ul.style.maxHeight = spaceBelow + 'px';
  3215. }
  3216. else if (fullHeight &lt;= spaceAbove) {
  3217. ul.style.bottom = rect.height + 'px';
  3218. ul.style.maxHeight = spaceAbove + 'px';
  3219. }
  3220. else if (spaceBelow >= spaceAbove) {
  3221. ul.style.top = rect.height + 'px';
  3222. ul.style.maxHeight = (spaceBelow - (spaceBelow % itemHeight)) + 'px';
  3223. }
  3224. else {
  3225. ul.style.bottom = rect.height + 'px';
  3226. ul.style.maxHeight = (spaceAbove - (spaceAbove % itemHeight)) + 'px';
  3227. }
  3228. ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
  3229. });
  3230. }
  3231. var cboxes = ul.querySelectorAll('[selected] input[type="checkbox"]');
  3232. for (var i = 0; i &lt; cboxes.length; i++) {
  3233. cboxes[i].checked = true;
  3234. cboxes[i].disabled = (cboxes.length == 1 &amp;&amp; !this.options.optional);
  3235. };
  3236. ul.classList.add('dropdown');
  3237. sb.insertBefore(pv, ul.nextElementSibling);
  3238. li.forEach(function(l) {
  3239. if (!l.hasAttribute('unselectable'))
  3240. l.setAttribute('tabindex', 0);
  3241. });
  3242. sb.lastElementChild.setAttribute('tabindex', 0);
  3243. var focusFn = L.bind(function(el) {
  3244. this.setFocus(sb, el, true);
  3245. ul.removeEventListener('transitionend', focusFn);
  3246. }, this, sel || li[0]);
  3247. ul.addEventListener('transitionend', focusFn);
  3248. },
  3249. /** @private */
  3250. closeDropdown: function(sb, no_focus) {
  3251. if (!sb.hasAttribute('open'))
  3252. return;
  3253. var pv = sb.querySelector('ul.preview'),
  3254. ul = sb.querySelector('ul.dropdown'),
  3255. li = ul.querySelectorAll('li'),
  3256. fl = findParent(sb, '.cbi-value-field');
  3257. li.forEach(function(l) { l.removeAttribute('tabindex'); });
  3258. sb.lastElementChild.removeAttribute('tabindex');
  3259. sb.removeChild(pv);
  3260. sb.removeAttribute('open');
  3261. sb.style.width = sb.style.height = '';
  3262. ul.classList.remove('dropdown');
  3263. ul.style.top = ul.style.bottom = ul.style.maxHeight = '';
  3264. if (fl)
  3265. fl.classList.remove('cbi-dropdown-open');
  3266. if (!no_focus)
  3267. this.setFocus(sb, sb);
  3268. this.saveValues(sb, ul);
  3269. },
  3270. /** @private */
  3271. toggleItem: function(sb, li, force_state) {
  3272. var ul = li.parentNode;
  3273. if (li.hasAttribute('unselectable'))
  3274. return;
  3275. if (this.options.multiple) {
  3276. var cbox = li.querySelector('input[type="checkbox"]'),
  3277. items = li.parentNode.querySelectorAll('li'),
  3278. label = sb.querySelector('ul.preview'),
  3279. sel = li.parentNode.querySelectorAll('[selected]').length,
  3280. more = sb.querySelector('.more'),
  3281. ndisplay = this.options.display_items,
  3282. n = 0;
  3283. if (li.hasAttribute('selected')) {
  3284. if (force_state !== true) {
  3285. if (sel > 1 || this.options.optional) {
  3286. li.removeAttribute('selected');
  3287. cbox.checked = cbox.disabled = false;
  3288. sel--;
  3289. }
  3290. else {
  3291. cbox.disabled = true;
  3292. }
  3293. }
  3294. }
  3295. else {
  3296. if (force_state !== false) {
  3297. li.setAttribute('selected', '');
  3298. cbox.checked = true;
  3299. cbox.disabled = false;
  3300. sel++;
  3301. }
  3302. }
  3303. while (label &amp;&amp; label.firstElementChild)
  3304. label.removeChild(label.firstElementChild);
  3305. for (var i = 0; i &lt; items.length; i++) {
  3306. items[i].removeAttribute('display');
  3307. if (items[i].hasAttribute('selected')) {
  3308. if (ndisplay-- > 0) {
  3309. items[i].setAttribute('display', n++);
  3310. if (label)
  3311. label.appendChild(items[i].cloneNode(true));
  3312. }
  3313. var c = items[i].querySelector('input[type="checkbox"]');
  3314. if (c)
  3315. c.disabled = (sel == 1 &amp;&amp; !this.options.optional);
  3316. }
  3317. }
  3318. if (ndisplay &lt; 0)
  3319. sb.setAttribute('more', '');
  3320. else
  3321. sb.removeAttribute('more');
  3322. if (ndisplay === this.options.display_items)
  3323. sb.setAttribute('empty', '');
  3324. else
  3325. sb.removeAttribute('empty');
  3326. dom.content(more, (ndisplay === this.options.display_items)
  3327. ? (this.options.select_placeholder || this.options.placeholder) : '···');
  3328. }
  3329. else {
  3330. var sel = li.parentNode.querySelector('[selected]');
  3331. if (sel) {
  3332. sel.removeAttribute('display');
  3333. sel.removeAttribute('selected');
  3334. }
  3335. li.setAttribute('display', 0);
  3336. li.setAttribute('selected', '');
  3337. this.closeDropdown(sb);
  3338. }
  3339. this.saveValues(sb, ul);
  3340. },
  3341. /** @private */
  3342. transformItem: function(sb, li) {
  3343. var cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -1, onclick: 'event.preventDefault()' })),
  3344. label = E('label');
  3345. while (li.firstChild)
  3346. label.appendChild(li.firstChild);
  3347. li.appendChild(cbox);
  3348. li.appendChild(label);
  3349. },
  3350. /** @private */
  3351. saveValues: function(sb, ul) {
  3352. var sel = ul.querySelectorAll('li[selected]'),
  3353. div = sb.lastElementChild,
  3354. name = this.options.name,
  3355. strval = '',
  3356. values = [];
  3357. while (div.lastElementChild)
  3358. div.removeChild(div.lastElementChild);
  3359. sel.forEach(function (s) {
  3360. if (s.hasAttribute('placeholder'))
  3361. return;
  3362. var v = {
  3363. text: s.innerText,
  3364. value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText,
  3365. element: s
  3366. };
  3367. div.appendChild(E('input', {
  3368. type: 'hidden',
  3369. name: name,
  3370. value: v.value
  3371. }));
  3372. values.push(v);
  3373. strval += strval.length ? ' ' + v.value : v.value;
  3374. });
  3375. var detail = {
  3376. instance: this,
  3377. element: sb
  3378. };
  3379. if (this.options.multiple)
  3380. detail.values = values;
  3381. else
  3382. detail.value = values.length ? values[0] : null;
  3383. sb.value = strval;
  3384. sb.dispatchEvent(new CustomEvent('cbi-dropdown-change', {
  3385. bubbles: true,
  3386. detail: detail
  3387. }));
  3388. },
  3389. /** @private */
  3390. setValues: function(sb, values) {
  3391. var ul = sb.querySelector('ul');
  3392. if (this.options.create) {
  3393. for (var value in values) {
  3394. this.createItems(sb, value);
  3395. if (!this.options.multiple)
  3396. break;
  3397. }
  3398. }
  3399. if (this.options.multiple) {
  3400. var lis = ul.querySelectorAll('li[data-value]');
  3401. for (var i = 0; i &lt; lis.length; i++) {
  3402. var value = lis[i].getAttribute('data-value');
  3403. if (values === null || !(value in values))
  3404. this.toggleItem(sb, lis[i], false);
  3405. else
  3406. this.toggleItem(sb, lis[i], true);
  3407. }
  3408. }
  3409. else {
  3410. var ph = ul.querySelector('li[placeholder]');
  3411. if (ph)
  3412. this.toggleItem(sb, ph);
  3413. var lis = ul.querySelectorAll('li[data-value]');
  3414. for (var i = 0; i &lt; lis.length; i++) {
  3415. var value = lis[i].getAttribute('data-value');
  3416. if (values !== null &amp;&amp; (value in values))
  3417. this.toggleItem(sb, lis[i]);
  3418. }
  3419. }
  3420. },
  3421. /** @private */
  3422. setFocus: function(sb, elem, scroll) {
  3423. if (sb.hasAttribute('locked-in'))
  3424. return;
  3425. sb.querySelectorAll('.focus').forEach(function(e) {
  3426. e.classList.remove('focus');
  3427. });
  3428. elem.classList.add('focus');
  3429. if (scroll)
  3430. elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop;
  3431. elem.focus();
  3432. },
  3433. /** @private */
  3434. createChoiceElement: function(sb, value, label) {
  3435. var tpl = sb.querySelector(this.options.create_template),
  3436. markup = null;
  3437. if (tpl)
  3438. markup = (tpl.textContent || tpl.innerHTML || tpl.firstChild.data).replace(/^&lt;!--|--!?>$/, '').trim();
  3439. else
  3440. markup = '&lt;li data-value="{{value}}">&lt;span data-label-placeholder="true" />&lt;/li>';
  3441. var new_item = E(markup.replace(/{{value}}/g, '%h'.format(value))),
  3442. placeholder = new_item.querySelector('[data-label-placeholder]');
  3443. if (placeholder) {
  3444. var content = E('span', {}, label || this.choices[value] || [ value ]);
  3445. while (content.firstChild)
  3446. placeholder.parentNode.insertBefore(content.firstChild, placeholder);
  3447. placeholder.parentNode.removeChild(placeholder);
  3448. }
  3449. if (this.options.multiple)
  3450. this.transformItem(sb, new_item);
  3451. if (!new_item.hasAttribute('unselectable'))
  3452. new_item.setAttribute('tabindex', 0);
  3453. return new_item;
  3454. },
  3455. /** @private */
  3456. createItems: function(sb, value) {
  3457. var sbox = this,
  3458. val = (value || '').trim(),
  3459. ul = sb.querySelector('ul');
  3460. if (!sbox.options.multiple)
  3461. val = val.length ? [ val ] : [];
  3462. else
  3463. val = val.length ? val.split(/\s+/) : [];
  3464. val.forEach(function(item) {
  3465. var new_item = null;
  3466. ul.childNodes.forEach(function(li) {
  3467. if (li.getAttribute &amp;&amp; li.getAttribute('data-value') === item)
  3468. new_item = li;
  3469. });
  3470. if (!new_item) {
  3471. new_item = sbox.createChoiceElement(sb, item);
  3472. if (!sbox.options.multiple) {
  3473. var old = ul.querySelector('li[created]');
  3474. if (old)
  3475. ul.removeChild(old);
  3476. new_item.setAttribute('created', '');
  3477. }
  3478. new_item = ul.insertBefore(new_item, ul.lastElementChild);
  3479. }
  3480. sbox.toggleItem(sb, new_item, true);
  3481. sbox.setFocus(sb, new_item, true);
  3482. });
  3483. },
  3484. /**
  3485. * Remove all existing choices from the dropdown menu.
  3486. *
  3487. * This function removes all preexisting dropdown choices from the widget,
  3488. * keeping only choices currently being selected unless `reset_values` is
  3489. * given, in which case all choices and deselected and removed.
  3490. *
  3491. * @instance
  3492. * @memberof LuCI.ui.Dropdown
  3493. * @param {boolean} [reset_value=false]
  3494. * If set to `true`, deselect and remove selected choices as well instead
  3495. * of keeping them.
  3496. */
  3497. clearChoices: function(reset_value) {
  3498. var ul = this.node.querySelector('ul'),
  3499. lis = ul ? ul.querySelectorAll('li[data-value]') : [],
  3500. len = lis.length - (this.options.create ? 1 : 0),
  3501. val = reset_value ? null : this.getValue();
  3502. for (var i = 0; i &lt; len; i++) {
  3503. var lival = lis[i].getAttribute('data-value');
  3504. if (val == null ||
  3505. (!this.options.multiple &amp;&amp; val != lival) ||
  3506. (this.options.multiple &amp;&amp; val.indexOf(lival) == -1))
  3507. ul.removeChild(lis[i]);
  3508. }
  3509. if (reset_value)
  3510. this.setValues(this.node, {});
  3511. },
  3512. /**
  3513. * Add new choices to the dropdown menu.
  3514. *
  3515. * This function adds further choices to an existing dropdown menu,
  3516. * ignoring choice values which are already present.
  3517. *
  3518. * @instance
  3519. * @memberof LuCI.ui.Dropdown
  3520. * @param {string[]} values
  3521. * The choice values to add to the dropdown widget.
  3522. *
  3523. * @param {Object&lt;string, *>} labels
  3524. * The choice label values to use when adding dropdown choices. If no
  3525. * label is found for a particular choice value, the value itself is used
  3526. * as label text. Choice labels may be any valid value accepted by
  3527. * {@link LuCI.dom#content}.
  3528. */
  3529. addChoices: function(values, labels) {
  3530. var sb = this.node,
  3531. ul = sb.querySelector('ul'),
  3532. lis = ul ? ul.querySelectorAll('li[data-value]') : [];
  3533. if (!Array.isArray(values))
  3534. values = L.toArray(values);
  3535. if (!L.isObject(labels))
  3536. labels = {};
  3537. for (var i = 0; i &lt; values.length; i++) {
  3538. var found = false;
  3539. for (var j = 0; j &lt; lis.length; j++) {
  3540. if (lis[j].getAttribute('data-value') === values[i]) {
  3541. found = true;
  3542. break;
  3543. }
  3544. }
  3545. if (found)
  3546. continue;
  3547. ul.insertBefore(
  3548. this.createChoiceElement(sb, values[i], labels[values[i]]),
  3549. ul.lastElementChild);
  3550. }
  3551. },
  3552. /**
  3553. * Close all open dropdown widgets in the current document.
  3554. */
  3555. closeAllDropdowns: function() {
  3556. document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
  3557. s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
  3558. });
  3559. },
  3560. /** @private */
  3561. handleClick: function(ev) {
  3562. var sb = ev.currentTarget;
  3563. if (!sb.hasAttribute('open')) {
  3564. if (!matchesElem(ev.target, 'input'))
  3565. this.openDropdown(sb);
  3566. }
  3567. else {
  3568. var li = findParent(ev.target, 'li');
  3569. if (li &amp;&amp; li.parentNode.classList.contains('dropdown'))
  3570. this.toggleItem(sb, li);
  3571. else if (li &amp;&amp; li.parentNode.classList.contains('preview'))
  3572. this.closeDropdown(sb);
  3573. else if (matchesElem(ev.target, 'span.open, span.more'))
  3574. this.closeDropdown(sb);
  3575. }
  3576. ev.preventDefault();
  3577. ev.stopPropagation();
  3578. },
  3579. /** @private */
  3580. handleKeydown: function(ev) {
  3581. var sb = ev.currentTarget,
  3582. ul = sb.querySelector('ul.dropdown');
  3583. if (matchesElem(ev.target, 'input'))
  3584. return;
  3585. if (!sb.hasAttribute('open')) {
  3586. switch (ev.keyCode) {
  3587. case 37:
  3588. case 38:
  3589. case 39:
  3590. case 40:
  3591. this.openDropdown(sb);
  3592. ev.preventDefault();
  3593. }
  3594. }
  3595. else {
  3596. var active = findParent(document.activeElement, 'li');
  3597. switch (ev.keyCode) {
  3598. case 27:
  3599. this.closeDropdown(sb);
  3600. ev.stopPropagation();
  3601. break;
  3602. case 13:
  3603. if (active) {
  3604. if (!active.hasAttribute('selected'))
  3605. this.toggleItem(sb, active);
  3606. this.closeDropdown(sb);
  3607. ev.preventDefault();
  3608. }
  3609. break;
  3610. case 32:
  3611. if (active) {
  3612. this.toggleItem(sb, active);
  3613. ev.preventDefault();
  3614. }
  3615. break;
  3616. case 38:
  3617. if (active &amp;&amp; active.previousElementSibling) {
  3618. this.setFocus(sb, active.previousElementSibling);
  3619. ev.preventDefault();
  3620. }
  3621. else if (document.activeElement === ul) {
  3622. this.setFocus(sb, ul.lastElementChild);
  3623. ev.preventDefault();
  3624. }
  3625. break;
  3626. case 40:
  3627. if (active &amp;&amp; active.nextElementSibling) {
  3628. var li = active.nextElementSibling;
  3629. this.setFocus(sb, li);
  3630. if (this.options.create &amp;&amp; li == li.parentNode.lastElementChild) {
  3631. var input = li.querySelector('input:not([type="hidden"]):not([type="checkbox"]');
  3632. if (input) input.focus();
  3633. }
  3634. ev.preventDefault();
  3635. }
  3636. else if (document.activeElement === ul) {
  3637. this.setFocus(sb, ul.firstElementChild);
  3638. ev.preventDefault();
  3639. }
  3640. break;
  3641. }
  3642. }
  3643. },
  3644. /** @private */
  3645. handleDropdownClose: function(ev) {
  3646. var sb = ev.currentTarget;
  3647. this.closeDropdown(sb, true);
  3648. },
  3649. /** @private */
  3650. handleDropdownSelect: function(ev) {
  3651. var sb = ev.currentTarget,
  3652. li = findParent(ev.target, 'li');
  3653. if (!li)
  3654. return;
  3655. this.toggleItem(sb, li);
  3656. this.closeDropdown(sb, true);
  3657. },
  3658. /** @private */
  3659. handleFocus: function(ev) {
  3660. var sb = ev.currentTarget;
  3661. document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
  3662. if (s !== sb || sb.hasAttribute('open'))
  3663. s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
  3664. });
  3665. },
  3666. /** @private */
  3667. handleCanaryFocus: function(ev) {
  3668. this.closeDropdown(ev.currentTarget.parentNode);
  3669. },
  3670. /** @private */
  3671. handleCreateKeydown: function(ev) {
  3672. var input = ev.currentTarget,
  3673. li = findParent(input, 'li'),
  3674. sb = findParent(li, '.cbi-dropdown');
  3675. switch (ev.keyCode) {
  3676. case 13:
  3677. ev.preventDefault();
  3678. if (input.classList.contains('cbi-input-invalid'))
  3679. return;
  3680. this.handleCreateBlur(ev);
  3681. this.createItems(sb, input.value);
  3682. input.value = '';
  3683. break;
  3684. case 27:
  3685. this.handleCreateBlur(ev);
  3686. this.closeDropdown(sb);
  3687. ev.stopPropagation();
  3688. input.value = '';
  3689. break;
  3690. case 38:
  3691. if (li.previousElementSibling) {
  3692. this.handleCreateBlur(ev);
  3693. this.setFocus(sb, li.previousElementSibling, true);
  3694. }
  3695. break;
  3696. }
  3697. },
  3698. /** @private */
  3699. handleCreateFocus: function(ev) {
  3700. var input = ev.currentTarget,
  3701. li = findParent(input, 'li'),
  3702. cbox = li.querySelector('input[type="checkbox"]'),
  3703. sb = findParent(input, '.cbi-dropdown');
  3704. if (cbox)
  3705. cbox.checked = true;
  3706. sb.setAttribute('locked-in', '');
  3707. this.setFocus(sb, li, true);
  3708. },
  3709. /** @private */
  3710. handleCreateBlur: function(ev) {
  3711. var input = ev.currentTarget,
  3712. cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'),
  3713. sb = findParent(input, '.cbi-dropdown');
  3714. if (cbox)
  3715. cbox.checked = false;
  3716. sb.removeAttribute('locked-in');
  3717. },
  3718. /** @private */
  3719. handleCreateClick: function(ev) {
  3720. ev.currentTarget.querySelector(this.options.create_query).focus();
  3721. },
  3722. /** @override */
  3723. setValue: function(values) {
  3724. if (this.options.multiple) {
  3725. if (!Array.isArray(values))
  3726. values = (values != null &amp;&amp; values != '') ? [ values ] : [];
  3727. var v = {};
  3728. for (var i = 0; i &lt; values.length; i++)
  3729. v[values[i]] = true;
  3730. this.setValues(this.node, v);
  3731. }
  3732. else {
  3733. var v = {};
  3734. if (values != null) {
  3735. if (Array.isArray(values))
  3736. v[values[0]] = true;
  3737. else
  3738. v[values] = true;
  3739. }
  3740. this.setValues(this.node, v);
  3741. }
  3742. },
  3743. /** @override */
  3744. getValue: function() {
  3745. var div = this.node.lastElementChild,
  3746. h = div.querySelectorAll('input[type="hidden"]'),
  3747. v = [];
  3748. for (var i = 0; i &lt; h.length; i++)
  3749. v.push(h[i].value);
  3750. return this.options.multiple ? v : v[0];
  3751. }
  3752. });
  3753. /**
  3754. * Instantiate a rich dropdown choice widget allowing custom values.
  3755. *
  3756. * @constructor Combobox
  3757. * @memberof LuCI.ui
  3758. * @augments LuCI.ui.Dropdown
  3759. *
  3760. * @classdesc
  3761. *
  3762. * The `Combobox` class implements a rich, stylable dropdown menu which allows
  3763. * to enter custom values. Historically, comboboxes used to be a dedicated
  3764. * widget type in LuCI but nowadays they are direct aliases of dropdown widgets
  3765. * with a set of enforced default properties for easier instantiation.
  3766. *
  3767. * UI widget instances are usually not supposed to be created by view code
  3768. * directly, instead they're implicitly created by `LuCI.form` when
  3769. * instantiating CBI forms.
  3770. *
  3771. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  3772. * in views, use `'require ui'` and refer to `ui.Combobox`. To import it in
  3773. * external JavaScript, use `L.require("ui").then(...)` and access the
  3774. * `Combobox` property of the class instance value.
  3775. *
  3776. * @param {string|string[]} [value=null]
  3777. * The initial input value(s).
  3778. *
  3779. * @param {Object&lt;string, *>} choices
  3780. * Object containing the selectable choices of the widget. The object keys
  3781. * serve as values for the different choices while the values are used as
  3782. * choice labels.
  3783. *
  3784. * @param {LuCI.ui.Combobox.InitOptions} [options]
  3785. * Object describing the widget specific options to initialize the dropdown.
  3786. */
  3787. var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ {
  3788. /**
  3789. * Comboboxes support the same properties as
  3790. * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
  3791. * specific values for the following properties:
  3792. *
  3793. * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
  3794. * @memberof LuCI.ui.Combobox
  3795. *
  3796. * @property {boolean} multiple=false
  3797. * Since Comboboxes never allow selecting multiple values, this property
  3798. * is forcibly set to `false`.
  3799. *
  3800. * @property {boolean} create=true
  3801. * Since Comboboxes always allow custom choice values, this property is
  3802. * forcibly set to `true`.
  3803. *
  3804. * @property {boolean} optional=true
  3805. * Since Comboboxes are always optional, this property is forcibly set to
  3806. * `true`.
  3807. */
  3808. __init__: function(value, choices, options) {
  3809. this.super('__init__', [ value, choices, Object.assign({
  3810. select_placeholder: _('-- Please choose --'),
  3811. custom_placeholder: _('-- custom --'),
  3812. dropdown_items: -1,
  3813. sort: true
  3814. }, options, {
  3815. multiple: false,
  3816. create: true,
  3817. optional: true
  3818. }) ]);
  3819. }
  3820. });
  3821. /**
  3822. * Instantiate a combo button widget offering multiple action choices.
  3823. *
  3824. * @constructor ComboButton
  3825. * @memberof LuCI.ui
  3826. * @augments LuCI.ui.Dropdown
  3827. *
  3828. * @classdesc
  3829. *
  3830. * The `ComboButton` class implements a button element which can be expanded
  3831. * into a dropdown to chose from a set of different action choices.
  3832. *
  3833. * UI widget instances are usually not supposed to be created by view code
  3834. * directly, instead they're implicitly created by `LuCI.form` when
  3835. * instantiating CBI forms.
  3836. *
  3837. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  3838. * in views, use `'require ui'` and refer to `ui.ComboButton`. To import it in
  3839. * external JavaScript, use `L.require("ui").then(...)` and access the
  3840. * `ComboButton` property of the class instance value.
  3841. *
  3842. * @param {string|string[]} [value=null]
  3843. * The initial input value(s).
  3844. *
  3845. * @param {Object&lt;string, *>} choices
  3846. * Object containing the selectable choices of the widget. The object keys
  3847. * serve as values for the different choices while the values are used as
  3848. * choice labels.
  3849. *
  3850. * @param {LuCI.ui.ComboButton.InitOptions} [options]
  3851. * Object describing the widget specific options to initialize the button.
  3852. */
  3853. var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype */ {
  3854. /**
  3855. * ComboButtons support the same properties as
  3856. * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce
  3857. * specific values for some properties and add additional button specific
  3858. * properties.
  3859. *
  3860. * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
  3861. * @memberof LuCI.ui.ComboButton
  3862. *
  3863. * @property {boolean} multiple=false
  3864. * Since ComboButtons never allow selecting multiple actions, this property
  3865. * is forcibly set to `false`.
  3866. *
  3867. * @property {boolean} create=false
  3868. * Since ComboButtons never allow creating custom choices, this property
  3869. * is forcibly set to `false`.
  3870. *
  3871. * @property {boolean} optional=false
  3872. * Since ComboButtons must always select one action, this property is
  3873. * forcibly set to `false`.
  3874. *
  3875. * @property {Object&lt;string, string>} [classes]
  3876. * Specifies a mapping of choice values to CSS class names. If an action
  3877. * choice is selected by the user and if a corresponding entry exists in
  3878. * the `classes` object, the class names corresponding to the selected
  3879. * value are set on the button element.
  3880. *
  3881. * This is useful to apply different button styles, such as colors, to the
  3882. * combined button depending on the selected action.
  3883. *
  3884. * @property {function} [click]
  3885. * Specifies a handler function to invoke when the user clicks the button.
  3886. * This function will be called with the button DOM node as `this` context
  3887. * and receive the DOM click event as first as well as the selected action
  3888. * choice value as second argument.
  3889. */
  3890. __init__: function(value, choices, options) {
  3891. this.super('__init__', [ value, choices, Object.assign({
  3892. sort: true
  3893. }, options, {
  3894. multiple: false,
  3895. create: false,
  3896. optional: false
  3897. }) ]);
  3898. },
  3899. /** @override */
  3900. render: function(/* ... */) {
  3901. var node = UIDropdown.prototype.render.apply(this, arguments),
  3902. val = this.getValue();
  3903. if (L.isObject(this.options.classes) &amp;&amp; this.options.classes.hasOwnProperty(val))
  3904. node.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
  3905. return node;
  3906. },
  3907. /** @private */
  3908. handleClick: function(ev) {
  3909. var sb = ev.currentTarget,
  3910. t = ev.target;
  3911. if (sb.hasAttribute('open') || dom.matches(t, '.cbi-dropdown > span.open'))
  3912. return UIDropdown.prototype.handleClick.apply(this, arguments);
  3913. if (this.options.click)
  3914. return this.options.click.call(sb, ev, this.getValue());
  3915. },
  3916. /** @private */
  3917. toggleItem: function(sb /*, ... */) {
  3918. var rv = UIDropdown.prototype.toggleItem.apply(this, arguments),
  3919. val = this.getValue();
  3920. if (L.isObject(this.options.classes) &amp;&amp; this.options.classes.hasOwnProperty(val))
  3921. sb.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]);
  3922. else
  3923. sb.setAttribute('class', 'cbi-dropdown');
  3924. return rv;
  3925. }
  3926. });
  3927. /**
  3928. * Instantiate a dynamic list widget.
  3929. *
  3930. * @constructor DynamicList
  3931. * @memberof LuCI.ui
  3932. * @augments LuCI.ui.AbstractElement
  3933. *
  3934. * @classdesc
  3935. *
  3936. * The `DynamicList` class implements a widget which allows the user to specify
  3937. * an arbitrary amount of input values, either from free formed text input or
  3938. * from a set of predefined choices.
  3939. *
  3940. * UI widget instances are usually not supposed to be created by view code
  3941. * directly, instead they're implicitly created by `LuCI.form` when
  3942. * instantiating CBI forms.
  3943. *
  3944. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  3945. * in views, use `'require ui'` and refer to `ui.DynamicList`. To import it in
  3946. * external JavaScript, use `L.require("ui").then(...)` and access the
  3947. * `DynamicList` property of the class instance value.
  3948. *
  3949. * @param {string|string[]} [value=null]
  3950. * The initial input value(s).
  3951. *
  3952. * @param {Object&lt;string, *>} [choices]
  3953. * Object containing the selectable choices of the widget. The object keys
  3954. * serve as values for the different choices while the values are used as
  3955. * choice labels. If omitted, no default choices are presented to the user,
  3956. * instead a plain text input field is rendered allowing the user to add
  3957. * arbitrary values to the dynamic list.
  3958. *
  3959. * @param {LuCI.ui.DynamicList.InitOptions} [options]
  3960. * Object describing the widget specific options to initialize the dynamic list.
  3961. */
  3962. var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ {
  3963. /**
  3964. * In case choices are passed to the dynamic list constructor, the widget
  3965. * supports the same properties as [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions}
  3966. * but enforces specific values for some dropdown properties.
  3967. *
  3968. * @typedef {LuCI.ui.Dropdown.InitOptions} InitOptions
  3969. * @memberof LuCI.ui.DynamicList
  3970. *
  3971. * @property {boolean} multiple=false
  3972. * Since dynamic lists never allow selecting multiple choices when adding
  3973. * another list item, this property is forcibly set to `false`.
  3974. *
  3975. * @property {boolean} optional=true
  3976. * Since dynamic lists use an embedded dropdown to present a list of
  3977. * predefined choice values, the dropdown must be made optional to allow
  3978. * it to remain unselected.
  3979. */
  3980. __init__: function(values, choices, options) {
  3981. if (!Array.isArray(values))
  3982. values = (values != null &amp;&amp; values != '') ? [ values ] : [];
  3983. if (typeof(choices) != 'object')
  3984. choices = null;
  3985. this.values = values;
  3986. this.choices = choices;
  3987. this.options = Object.assign({}, options, {
  3988. multiple: false,
  3989. optional: true
  3990. });
  3991. },
  3992. /** @override */
  3993. render: function() {
  3994. var dl = E('div', {
  3995. 'id': this.options.id,
  3996. 'class': 'cbi-dynlist',
  3997. 'disabled': this.options.disabled ? '' : null
  3998. }, E('div', { 'class': 'add-item control-group' }));
  3999. if (this.choices) {
  4000. if (this.options.placeholder != null)
  4001. this.options.select_placeholder = this.options.placeholder;
  4002. var cbox = new UICombobox(null, this.choices, this.options);
  4003. dl.lastElementChild.appendChild(cbox.render());
  4004. }
  4005. else {
  4006. var inputEl = E('input', {
  4007. 'id': this.options.id ? 'widget.' + this.options.id : null,
  4008. 'type': 'text',
  4009. 'class': 'cbi-input-text',
  4010. 'placeholder': this.options.placeholder,
  4011. 'disabled': this.options.disabled ? '' : null
  4012. });
  4013. dl.lastElementChild.appendChild(inputEl);
  4014. dl.lastElementChild.appendChild(E('div', { 'class': 'btn cbi-button cbi-button-add' }, '+'));
  4015. if (this.options.datatype || this.options.validate)
  4016. UI.prototype.addValidator(inputEl, this.options.datatype || 'string',
  4017. true, this.options.validate, 'blur', 'keyup');
  4018. }
  4019. for (var i = 0; i &lt; this.values.length; i++) {
  4020. var label = this.choices ? this.choices[this.values[i]] : null;
  4021. if (dom.elem(label))
  4022. label = label.cloneNode(true);
  4023. this.addItem(dl, this.values[i], label);
  4024. }
  4025. this.initDragAndDrop(dl);
  4026. return this.bind(dl);
  4027. },
  4028. /** @private */
  4029. initDragAndDrop: function(dl) {
  4030. let draggedItem = null;
  4031. let placeholder = null;
  4032. dl.addEventListener('dragstart', (e) => {
  4033. if (e.target.classList.contains('item')) {
  4034. draggedItem = e.target;
  4035. e.target.classList.add('dragging');
  4036. }
  4037. });
  4038. dl.addEventListener('dragend', (e) => e.target.classList.remove('dragging'));
  4039. dl.addEventListener('dragover', (e) => e.preventDefault());
  4040. dl.addEventListener('dragenter', (e) => e.target.classList.add('drag-over'));
  4041. dl.addEventListener('dragleave', (e) => e.target.classList.remove('drag-over'));
  4042. dl.addEventListener('drop', (e) => {
  4043. e.preventDefault();
  4044. e.target.classList.remove('drag-over');
  4045. const target = e.target.classList.contains('item') ? e.target : dl.querySelector('.add-item');
  4046. dl.insertBefore(draggedItem, target);
  4047. });
  4048. dl.addEventListener('click', (e) => {
  4049. if (e.target.closest('.item')) {
  4050. const span = e.target.closest('.item').querySelector('SPAN');
  4051. if (span) {
  4052. const range = document.createRange();
  4053. range.selectNodeContents(span);
  4054. const selection = window.getSelection();
  4055. if (selection.rangeCount === 0 || selection.toString().length === 0) {
  4056. selection.removeAllRanges();
  4057. selection.addRange(range);
  4058. } else selection.removeAllRanges();
  4059. }
  4060. }
  4061. });
  4062. dl.addEventListener('touchstart', (e) => {
  4063. const touch = e.touches[0];
  4064. const target = e.target.closest('.item');
  4065. if (target) {
  4066. draggedItem = target;
  4067. placeholder = draggedItem.cloneNode(true);
  4068. placeholder.className = 'placeholder';
  4069. placeholder.style.height = `${draggedItem.offsetHeight}px`;
  4070. draggedItem.parentNode.insertBefore(placeholder, draggedItem.nextSibling);
  4071. draggedItem.classList.add('dragging')
  4072. }
  4073. });
  4074. dl.addEventListener('touchmove', (e) => {
  4075. if (draggedItem) {
  4076. const touch = e.touches[0];
  4077. const currentY = touch.clientY;
  4078. const items = Array.from(dl.querySelectorAll('.item'));
  4079. const target = items.find(item => {
  4080. const rect = item.getBoundingClientRect();
  4081. return currentY > rect.top &amp;&amp; currentY &lt; rect.bottom;
  4082. });
  4083. if (target &amp;&amp; target !== draggedItem) {
  4084. const insertBefore = currentY &lt; target.getBoundingClientRect().top + target.offsetHeight / 2;
  4085. dl.insertBefore(placeholder, insertBefore ? target : target.nextSibling);
  4086. }
  4087. e.preventDefault();
  4088. }
  4089. });
  4090. dl.addEventListener('touchend', (e) => {
  4091. if (draggedItem &amp;&amp; placeholder) {
  4092. dl.insertBefore(draggedItem, placeholder);
  4093. draggedItem.classList.remove('dragging')
  4094. placeholder.parentNode.removeChild(placeholder);
  4095. placeholder = null;
  4096. draggedItem = null;
  4097. }
  4098. });
  4099. },
  4100. /** @private */
  4101. bind: function(dl) {
  4102. dl.addEventListener('click', L.bind(this.handleClick, this));
  4103. dl.addEventListener('keydown', L.bind(this.handleKeydown, this));
  4104. dl.addEventListener('cbi-dropdown-change', L.bind(this.handleDropdownChange, this));
  4105. this.node = dl;
  4106. this.setUpdateEvents(dl, 'cbi-dynlist-change');
  4107. this.setChangeEvents(dl, 'cbi-dynlist-change');
  4108. dom.bindClassInstance(dl, this);
  4109. return dl;
  4110. },
  4111. /** @private */
  4112. addItem: function(dl, value, text, flash) {
  4113. var exists = false,
  4114. new_item = E('div', { 'class': flash ? 'item flash' : 'item', 'tabindex': 0, 'draggable': true }, [
  4115. E('span', {}, [ text || value ]),
  4116. E('input', {
  4117. 'type': 'hidden',
  4118. 'name': this.options.name,
  4119. 'value': value })]);
  4120. dl.querySelectorAll('.item').forEach(function(item) {
  4121. if (exists)
  4122. return;
  4123. var hidden = item.querySelector('input[type="hidden"]');
  4124. if (hidden &amp;&amp; hidden.parentNode !== item)
  4125. hidden = null;
  4126. if (hidden &amp;&amp; hidden.value === value)
  4127. exists = true;
  4128. });
  4129. if (!exists) {
  4130. var ai = dl.querySelector('.add-item');
  4131. ai.parentNode.insertBefore(new_item, ai);
  4132. }
  4133. dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
  4134. bubbles: true,
  4135. detail: {
  4136. instance: this,
  4137. element: dl,
  4138. value: value,
  4139. add: true
  4140. }
  4141. }));
  4142. },
  4143. /** @private */
  4144. removeItem: function(dl, item) {
  4145. var value = item.querySelector('input[type="hidden"]').value;
  4146. var sb = dl.querySelector('.cbi-dropdown');
  4147. if (sb)
  4148. sb.querySelectorAll('ul > li').forEach(function(li) {
  4149. if (li.getAttribute('data-value') === value) {
  4150. if (li.hasAttribute('dynlistcustom'))
  4151. li.parentNode.removeChild(li);
  4152. else
  4153. li.removeAttribute('unselectable');
  4154. }
  4155. });
  4156. item.parentNode.removeChild(item);
  4157. dl.dispatchEvent(new CustomEvent('cbi-dynlist-change', {
  4158. bubbles: true,
  4159. detail: {
  4160. instance: this,
  4161. element: dl,
  4162. value: value,
  4163. remove: true
  4164. }
  4165. }));
  4166. },
  4167. /** @private */
  4168. handleClick: function(ev) {
  4169. var dl = ev.currentTarget,
  4170. item = findParent(ev.target, '.item');
  4171. if (this.options.disabled)
  4172. return;
  4173. if (item) {
  4174. // Get bounding rectangle of the item
  4175. var rect = item.getBoundingClientRect();
  4176. // Get computed styles for the ::after pseudo-element
  4177. var afterStyles = window.getComputedStyle(item, '::after');
  4178. var afterWidth = parseFloat(afterStyles.width) || 0;
  4179. // Check if the click is within the ::after region
  4180. if (rect.right - ev.clientX &lt;= afterWidth) {
  4181. this.removeItem(dl, item);
  4182. }
  4183. }
  4184. else if (matchesElem(ev.target, '.cbi-button-add')) {
  4185. var input = ev.target.previousElementSibling;
  4186. if (input.value.length &amp;&amp; !input.classList.contains('cbi-input-invalid')) {
  4187. this.addItem(dl, input.value, null, true);
  4188. input.value = '';
  4189. }
  4190. }
  4191. },
  4192. /** @private */
  4193. handleDropdownChange: function(ev) {
  4194. var dl = ev.currentTarget,
  4195. sbIn = ev.detail.instance,
  4196. sbEl = ev.detail.element,
  4197. sbVal = ev.detail.value;
  4198. if (sbVal === null)
  4199. return;
  4200. sbIn.setValues(sbEl, null);
  4201. sbVal.element.setAttribute('unselectable', '');
  4202. if (sbVal.element.hasAttribute('created')) {
  4203. sbVal.element.removeAttribute('created');
  4204. sbVal.element.setAttribute('dynlistcustom', '');
  4205. }
  4206. var label = sbVal.text;
  4207. if (sbVal.element) {
  4208. label = E([]);
  4209. for (var i = 0; i &lt; sbVal.element.childNodes.length; i++)
  4210. label.appendChild(sbVal.element.childNodes[i].cloneNode(true));
  4211. }
  4212. this.addItem(dl, sbVal.value, label, true);
  4213. },
  4214. /** @private */
  4215. handleKeydown: function(ev) {
  4216. var dl = ev.currentTarget,
  4217. item = findParent(ev.target, '.item');
  4218. if (item) {
  4219. switch (ev.keyCode) {
  4220. case 8: /* backspace */
  4221. if (item.previousElementSibling)
  4222. item.previousElementSibling.focus();
  4223. this.removeItem(dl, item);
  4224. break;
  4225. case 46: /* delete */
  4226. if (item.nextElementSibling) {
  4227. if (item.nextElementSibling.classList.contains('item'))
  4228. item.nextElementSibling.focus();
  4229. else
  4230. item.nextElementSibling.firstElementChild.focus();
  4231. }
  4232. this.removeItem(dl, item);
  4233. break;
  4234. }
  4235. }
  4236. else if (matchesElem(ev.target, '.cbi-input-text')) {
  4237. switch (ev.keyCode) {
  4238. case 13: /* enter */
  4239. if (ev.target.value.length &amp;&amp; !ev.target.classList.contains('cbi-input-invalid')) {
  4240. this.addItem(dl, ev.target.value, null, true);
  4241. ev.target.value = '';
  4242. ev.target.blur();
  4243. ev.target.focus();
  4244. }
  4245. ev.preventDefault();
  4246. break;
  4247. }
  4248. }
  4249. },
  4250. /** @override */
  4251. getValue: function() {
  4252. var items = this.node.querySelectorAll('.item > input[type="hidden"]'),
  4253. input = this.node.querySelector('.add-item > input[type="text"]'),
  4254. v = [];
  4255. for (var i = 0; i &lt; items.length; i++)
  4256. v.push(items[i].value);
  4257. if (input &amp;&amp; input.value != null &amp;&amp; input.value.match(/\S/) &amp;&amp;
  4258. input.classList.contains('cbi-input-invalid') == false &amp;&amp;
  4259. v.filter(function(s) { return s == input.value }).length == 0)
  4260. v.push(input.value);
  4261. return v;
  4262. },
  4263. /** @override */
  4264. setValue: function(values) {
  4265. if (!Array.isArray(values))
  4266. values = (values != null &amp;&amp; values != '') ? [ values ] : [];
  4267. var items = this.node.querySelectorAll('.item');
  4268. for (var i = 0; i &lt; items.length; i++)
  4269. if (items[i].parentNode === this.node)
  4270. this.removeItem(this.node, items[i]);
  4271. for (var i = 0; i &lt; values.length; i++)
  4272. this.addItem(this.node, values[i],
  4273. this.choices ? this.choices[values[i]] : null);
  4274. },
  4275. /**
  4276. * Add new suggested choices to the dynamic list.
  4277. *
  4278. * This function adds further choices to an existing dynamic list,
  4279. * ignoring choice values which are already present.
  4280. *
  4281. * @instance
  4282. * @memberof LuCI.ui.DynamicList
  4283. * @param {string[]} values
  4284. * The choice values to add to the dynamic lists suggestion dropdown.
  4285. *
  4286. * @param {Object&lt;string, *>} labels
  4287. * The choice label values to use when adding suggested choices. If no
  4288. * label is found for a particular choice value, the value itself is used
  4289. * as label text. Choice labels may be any valid value accepted by
  4290. * {@link LuCI.dom#content}.
  4291. */
  4292. addChoices: function(values, labels) {
  4293. var dl = this.node.lastElementChild.firstElementChild;
  4294. dom.callClassMethod(dl, 'addChoices', values, labels);
  4295. },
  4296. /**
  4297. * Remove all existing choices from the dynamic list.
  4298. *
  4299. * This function removes all preexisting suggested choices from the widget.
  4300. *
  4301. * @instance
  4302. * @memberof LuCI.ui.DynamicList
  4303. */
  4304. clearChoices: function() {
  4305. var dl = this.node.lastElementChild.firstElementChild;
  4306. dom.callClassMethod(dl, 'clearChoices');
  4307. }
  4308. });
  4309. /**
  4310. * Instantiate a hidden input field widget.
  4311. *
  4312. * @constructor Hiddenfield
  4313. * @memberof LuCI.ui
  4314. * @augments LuCI.ui.AbstractElement
  4315. *
  4316. * @classdesc
  4317. *
  4318. * The `Hiddenfield` class implements an HTML `&lt;input type="hidden">` field
  4319. * which allows to store form data without exposing it to the user.
  4320. *
  4321. * UI widget instances are usually not supposed to be created by view code
  4322. * directly, instead they're implicitly created by `LuCI.form` when
  4323. * instantiating CBI forms.
  4324. *
  4325. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  4326. * in views, use `'require ui'` and refer to `ui.Hiddenfield`. To import it in
  4327. * external JavaScript, use `L.require("ui").then(...)` and access the
  4328. * `Hiddenfield` property of the class instance value.
  4329. *
  4330. * @param {string|string[]} [value=null]
  4331. * The initial input value.
  4332. *
  4333. * @param {LuCI.ui.AbstractElement.InitOptions} [options]
  4334. * Object describing the widget specific options to initialize the hidden input.
  4335. */
  4336. var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ {
  4337. __init__: function(value, options) {
  4338. this.value = value;
  4339. this.options = Object.assign({
  4340. }, options);
  4341. },
  4342. /** @override */
  4343. render: function() {
  4344. var hiddenEl = E('input', {
  4345. 'id': this.options.id,
  4346. 'type': 'hidden',
  4347. 'value': this.value
  4348. });
  4349. return this.bind(hiddenEl);
  4350. },
  4351. /** @private */
  4352. bind: function(hiddenEl) {
  4353. this.node = hiddenEl;
  4354. dom.bindClassInstance(hiddenEl, this);
  4355. return hiddenEl;
  4356. },
  4357. /** @override */
  4358. getValue: function() {
  4359. return this.node.value;
  4360. },
  4361. /** @override */
  4362. setValue: function(value) {
  4363. this.node.value = value;
  4364. }
  4365. });
  4366. /**
  4367. * Instantiate a file upload widget.
  4368. *
  4369. * @constructor FileUpload
  4370. * @memberof LuCI.ui
  4371. * @augments LuCI.ui.AbstractElement
  4372. *
  4373. * @classdesc
  4374. *
  4375. * The `FileUpload` class implements a widget which allows the user to upload,
  4376. * browse, select and delete files beneath a predefined remote directory.
  4377. *
  4378. * UI widget instances are usually not supposed to be created by view code
  4379. * directly, instead they're implicitly created by `LuCI.form` when
  4380. * instantiating CBI forms.
  4381. *
  4382. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  4383. * in views, use `'require ui'` and refer to `ui.FileUpload`. To import it in
  4384. * external JavaScript, use `L.require("ui").then(...)` and access the
  4385. * `FileUpload` property of the class instance value.
  4386. *
  4387. * @param {string|string[]} [value=null]
  4388. * The initial input value.
  4389. *
  4390. * @param {LuCI.ui.DynamicList.InitOptions} [options]
  4391. * Object describing the widget specific options to initialize the file
  4392. * upload control.
  4393. */
  4394. var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
  4395. /**
  4396. * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions}
  4397. * the following properties are recognized:
  4398. *
  4399. * @typedef {LuCI.ui.AbstractElement.InitOptions} InitOptions
  4400. * @memberof LuCI.ui.FileUpload
  4401. *
  4402. * @property {boolean} [browser=false]
  4403. * Use a file browser mode.
  4404. *
  4405. * @property {boolean} [show_hidden=false]
  4406. * Specifies whether hidden files should be displayed when browsing remote
  4407. * files. Note that this is not a security feature, hidden files are always
  4408. * present in the remote file listings received, this option merely controls
  4409. * whether they're displayed or not.
  4410. *
  4411. * @property {boolean} [enable_upload=true]
  4412. * Specifies whether the widget allows the user to upload files. If set to
  4413. * `false`, only existing files may be selected. Note that this is not a
  4414. * security feature. Whether file upload requests are accepted remotely
  4415. * depends on the ACL setup for the current session. This option merely
  4416. * controls whether the upload controls are rendered or not.
  4417. *
  4418. * @property {boolean} [enable_remove=true]
  4419. * Specifies whether the widget allows the user to delete remove files.
  4420. * If set to `false`, existing files may not be removed. Note that this is
  4421. * not a security feature. Whether file delete requests are accepted
  4422. * remotely depends on the ACL setup for the current session. This option
  4423. * merely controls whether the file remove controls are rendered or not.
  4424. *
  4425. * @property {boolean} [enable_download=false]
  4426. * Specifies whether the widget allows the user to download files.
  4427. *
  4428. * @property {string} [root_directory=/etc/luci-uploads]
  4429. * Specifies the remote directory the upload and file browsing actions take
  4430. * place in. Browsing to directories outside the root directory is
  4431. * prevented by the widget. Note that this is not a security feature.
  4432. * Whether remote directories are browsable or not solely depends on the
  4433. * ACL setup for the current session.
  4434. */
  4435. __init__: function(value, options) {
  4436. this.value = value;
  4437. this.options = Object.assign({
  4438. browser: false,
  4439. show_hidden: false,
  4440. enable_upload: true,
  4441. enable_remove: true,
  4442. enable_download: false,
  4443. root_directory: '/etc/luci-uploads'
  4444. }, options);
  4445. },
  4446. /** @private */
  4447. bind: function(browserEl) {
  4448. this.node = browserEl;
  4449. this.setUpdateEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
  4450. this.setChangeEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel');
  4451. dom.bindClassInstance(browserEl, this);
  4452. return browserEl;
  4453. },
  4454. /** @override */
  4455. render: function() {
  4456. var renderFileBrowser = L.resolveDefault(this.value != null ? fs.stat(this.value) : null).then(L.bind(function(stat) {
  4457. var label;
  4458. if (L.isObject(stat) &amp;&amp; stat.type != 'directory')
  4459. this.stat = stat;
  4460. if (this.stat != null)
  4461. label = [ this.iconForType(this.stat.type), ' %s (%1000mB)'.format(this.truncatePath(this.stat.path), this.stat.size) ];
  4462. else if (this.value != null)
  4463. label = [ this.iconForType('file'), ' %s (%s)'.format(this.truncatePath(this.value), _('File not accessible')) ];
  4464. else
  4465. label = [ _('Select file…') ];
  4466. let btnOpenFileBrowser = E('button', {
  4467. 'class': 'btn open-file-browser',
  4468. 'click': UI.prototype.createHandlerFn(this, 'handleFileBrowser'),
  4469. 'disabled': this.options.disabled ? '' : null
  4470. }, label);
  4471. var fileBrowserEl = E('div', { 'id': this.options.id }, [
  4472. btnOpenFileBrowser,
  4473. E('div', {
  4474. 'class': 'cbi-filebrowser'
  4475. }),
  4476. E('input', {
  4477. 'type': 'hidden',
  4478. 'name': this.options.name,
  4479. 'value': this.value
  4480. })
  4481. ]);
  4482. return this.bind(fileBrowserEl);
  4483. }, this));
  4484. // in a browser mode open dir listing after render by clicking on a Select button
  4485. if (this.options.browser) {
  4486. return renderFileBrowser.then(function (fileBrowserEl) {
  4487. var btnOpenFileBrowser = fileBrowserEl.getElementsByClassName('open-file-browser').item(0);
  4488. btnOpenFileBrowser.click();
  4489. return fileBrowserEl;
  4490. });
  4491. }
  4492. return renderFileBrowser
  4493. },
  4494. /** @private */
  4495. truncatePath: function(path) {
  4496. if (path.length > 50)
  4497. path = path.substring(0, 25) + '…' + path.substring(path.length - 25);
  4498. return path;
  4499. },
  4500. /** @private */
  4501. iconForType: function(type) {
  4502. switch (type) {
  4503. case 'symlink':
  4504. return E('img', {
  4505. 'src': L.resource('cbi/link.svg'),
  4506. 'width': 16,
  4507. 'title': _('Symbolic link'),
  4508. 'class': 'middle'
  4509. });
  4510. case 'directory':
  4511. return E('img', {
  4512. 'src': L.resource('cbi/folder.svg'),
  4513. 'width': 16,
  4514. 'title': _('Directory'),
  4515. 'class': 'middle'
  4516. });
  4517. default:
  4518. return E('img', {
  4519. 'src': L.resource('cbi/file.svg'),
  4520. 'width': 16,
  4521. 'title': _('File'),
  4522. 'class': 'middle'
  4523. });
  4524. }
  4525. },
  4526. /** @private */
  4527. canonicalizePath: function(path) {
  4528. return path.replace(/\/{2,}/, '/')
  4529. .replace(/\/\.(\/|$)/g, '/')
  4530. .replace(/[^\/]+\/\.\.(\/|$)/g, '/')
  4531. .replace(/\/$/, '');
  4532. },
  4533. /** @private */
  4534. splitPath: function(path) {
  4535. var croot = this.canonicalizePath(this.options.root_directory || '/'),
  4536. cpath = this.canonicalizePath(path || '/');
  4537. if (cpath.length &lt;= croot.length)
  4538. return [ croot ];
  4539. if (cpath.charAt(croot.length) != '/')
  4540. return [ croot ];
  4541. var parts = cpath.substring(croot.length + 1).split(/\//);
  4542. parts.unshift(croot);
  4543. return parts;
  4544. },
  4545. /** @private */
  4546. handleUpload: function(path, list, ev) {
  4547. var form = ev.target.parentNode,
  4548. fileinput = form.querySelector('input[type="file"]'),
  4549. nameinput = form.querySelector('input[type="text"]'),
  4550. filename = (nameinput.value != null ? nameinput.value : '').trim();
  4551. ev.preventDefault();
  4552. if (filename == '' || filename.match(/\//) || fileinput.files[0] == null)
  4553. return;
  4554. var existing = list.filter(function(e) { return e.name == filename })[0];
  4555. if (existing != null &amp;&amp; existing.type == 'directory')
  4556. return alert(_('A directory with the same name already exists.'));
  4557. else if (existing != null &amp;&amp; !confirm(_('Overwrite existing file "%s" ?').format(filename)))
  4558. return;
  4559. var data = new FormData();
  4560. data.append('sessionid', L.env.sessionid);
  4561. data.append('filename', path + '/' + filename);
  4562. data.append('filedata', fileinput.files[0]);
  4563. return request.post(L.env.cgi_base + '/cgi-upload', data, {
  4564. progress: L.bind(function(btn, ev) {
  4565. btn.firstChild.data = '%.2f%%'.format((ev.loaded / ev.total) * 100);
  4566. }, this, ev.target)
  4567. }).then(L.bind(function(path, ev, res) {
  4568. var reply = res.json();
  4569. if (L.isObject(reply) &amp;&amp; reply.failure)
  4570. alert(_('Upload request failed: %s').format(reply.message));
  4571. return this.handleSelect(path, null, ev);
  4572. }, this, path, ev));
  4573. },
  4574. /** @private */
  4575. handleDelete: function(path, fileStat, ev) {
  4576. var parent = path.replace(/\/[^\/]+$/, '') || '/',
  4577. name = path.replace(/^.+\//, ''),
  4578. msg;
  4579. ev.preventDefault();
  4580. if (fileStat.type == 'directory')
  4581. msg = _('Do you really want to recursively delete the directory "%s" ?').format(name);
  4582. else
  4583. msg = _('Do you really want to delete "%s" ?').format(name);
  4584. if (confirm(msg)) {
  4585. var button = this.node.firstElementChild,
  4586. hidden = this.node.lastElementChild;
  4587. if (path == hidden.value) {
  4588. dom.content(button, _('Select file…'));
  4589. hidden.value = '';
  4590. }
  4591. return fs.remove(path).then(L.bind(function(parent, ev) {
  4592. return this.handleSelect(parent, null, ev);
  4593. }, this, parent, ev)).catch(function(err) {
  4594. alert(_('Delete request failed: %s').format(err.message));
  4595. });
  4596. }
  4597. },
  4598. /** @private */
  4599. renderUpload: function(path, list) {
  4600. if (!this.options.enable_upload)
  4601. return E([]);
  4602. return E([
  4603. E('a', {
  4604. 'href': '#',
  4605. 'class': 'btn cbi-button-positive',
  4606. 'click': function(ev) {
  4607. var uploadForm = ev.target.nextElementSibling,
  4608. fileInput = uploadForm.querySelector('input[type="file"]');
  4609. ev.target.style.display = 'none';
  4610. uploadForm.style.display = '';
  4611. fileInput.click();
  4612. }
  4613. }, _('Upload file…')),
  4614. E('div', { 'class': 'upload', 'style': 'display:none' }, [
  4615. E('input', {
  4616. 'type': 'file',
  4617. 'style': 'display:none',
  4618. 'change': function(ev) {
  4619. var nameinput = ev.target.parentNode.querySelector('input[type="text"]'),
  4620. uploadbtn = ev.target.parentNode.querySelector('button.cbi-button-save');
  4621. nameinput.value = ev.target.value.replace(/^.+[\/\\]/, '');
  4622. uploadbtn.disabled = false;
  4623. }
  4624. }),
  4625. E('button', {
  4626. 'class': 'btn',
  4627. 'click': function(ev) {
  4628. ev.preventDefault();
  4629. ev.target.previousElementSibling.click();
  4630. }
  4631. }, [ _('Browse…') ]),
  4632. E('div', {}, E('input', { 'type': 'text', 'placeholder': _('Filename') })),
  4633. E('button', {
  4634. 'class': 'btn cbi-button-save',
  4635. 'click': UI.prototype.createHandlerFn(this, 'handleUpload', path, list),
  4636. 'disabled': true
  4637. }, [ _('Upload file') ])
  4638. ])
  4639. ]);
  4640. },
  4641. /** @private */
  4642. renderListing: function(container, path, list) {
  4643. var breadcrumb = E('p'),
  4644. rows = E('ul');
  4645. list.sort(function(a, b) {
  4646. return L.naturalCompare(a.type == 'directory', b.type == 'directory') ||
  4647. L.naturalCompare(a.name, b.name);
  4648. });
  4649. for (var i = 0; i &lt; list.length; i++) {
  4650. if (!this.options.show_hidden &amp;&amp; list[i].name.charAt(0) == '.')
  4651. continue;
  4652. var entrypath = this.canonicalizePath(path + '/' + list[i].name),
  4653. selected = (entrypath == this.node.lastElementChild.value),
  4654. mtime = new Date(list[i].mtime * 1000);
  4655. rows.appendChild(E('li', [
  4656. E('div', { 'class': 'name' }, [
  4657. this.iconForType(list[i].type),
  4658. ' ',
  4659. E('a', {
  4660. 'href': '#',
  4661. 'style': selected ? 'font-weight:bold' : null,
  4662. 'click': UI.prototype.createHandlerFn(this, 'handleSelect',
  4663. entrypath, list[i].type != 'directory' ? list[i] : null)
  4664. }, '%h'.format(list[i].name))
  4665. ]),
  4666. E('div', { 'class': 'mtime hide-xs' }, [
  4667. ' %04d-%02d-%02d %02d:%02d:%02d '.format(
  4668. mtime.getFullYear(),
  4669. mtime.getMonth() + 1,
  4670. mtime.getDate(),
  4671. mtime.getHours(),
  4672. mtime.getMinutes(),
  4673. mtime.getSeconds())
  4674. ]),
  4675. E('div', [
  4676. selected ? E('button', {
  4677. 'class': 'btn',
  4678. 'click': UI.prototype.createHandlerFn(this, 'handleReset')
  4679. }, [ _('Deselect') ]) : '',
  4680. this.options.enable_download &amp;&amp; list[i].type == 'file' ? E('button', {
  4681. 'class': 'btn',
  4682. 'click': UI.prototype.createHandlerFn(this, 'handleDownload', entrypath, list[i])
  4683. }, [ _('Download') ]) : '',
  4684. this.options.enable_remove ? E('button', {
  4685. 'class': 'btn cbi-button-negative',
  4686. 'click': UI.prototype.createHandlerFn(this, 'handleDelete', entrypath, list[i])
  4687. }, [ _('Delete') ]) : ''
  4688. ])
  4689. ]));
  4690. }
  4691. if (!rows.firstElementChild)
  4692. rows.appendChild(E('em', _('No entries in this directory')));
  4693. var dirs = this.splitPath(path),
  4694. cur = '';
  4695. for (var i = 0; i &lt; dirs.length; i++) {
  4696. cur = cur ? cur + '/' + dirs[i] : dirs[i];
  4697. dom.append(breadcrumb, [
  4698. i ? ' » ' : '',
  4699. E('a', {
  4700. 'href': '#',
  4701. 'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur || '/', null)
  4702. }, dirs[i] != '' ? '%h'.format(dirs[i]) : E('em', '(root)')),
  4703. ]);
  4704. }
  4705. dom.content(container, [
  4706. breadcrumb,
  4707. rows,
  4708. E('div', { 'class': 'right' }, [
  4709. this.renderUpload(path, list),
  4710. !this.options.browser ? E('a', {
  4711. 'href': '#',
  4712. 'class': 'btn',
  4713. 'click': UI.prototype.createHandlerFn(this, 'handleCancel')
  4714. }, _('Cancel')) : ''
  4715. ]),
  4716. ]);
  4717. },
  4718. /** @private */
  4719. handleCancel: function(ev) {
  4720. var button = this.node.firstElementChild,
  4721. browser = button.nextElementSibling;
  4722. browser.classList.remove('open');
  4723. button.style.display = '';
  4724. this.node.dispatchEvent(new CustomEvent('cbi-fileupload-cancel', {}));
  4725. ev.preventDefault();
  4726. },
  4727. /** @private */
  4728. handleReset: function(ev) {
  4729. var button = this.node.firstElementChild,
  4730. hidden = this.node.lastElementChild;
  4731. hidden.value = '';
  4732. dom.content(button, _('Select file…'));
  4733. this.handleCancel(ev);
  4734. },
  4735. /** @private */
  4736. handleDownload: function(path, fileStat, ev) {
  4737. fs.read_direct(path, 'blob').then(function (blob) {
  4738. var url = window.URL.createObjectURL(blob);
  4739. var a = document.createElement('a');
  4740. a.style.display = 'none';
  4741. a.href = url;
  4742. a.download = fileStat.name;
  4743. document.body.appendChild(a);
  4744. a.click();
  4745. window.URL.revokeObjectURL(url);
  4746. }).catch(function(err) {
  4747. alert(_('Download failed: %s').format(err.message));
  4748. });
  4749. },
  4750. /** @private */
  4751. handleSelect: function(path, fileStat, ev) {
  4752. var browser = dom.parent(ev.target, '.cbi-filebrowser'),
  4753. ul = browser.querySelector('ul');
  4754. if (fileStat == null) {
  4755. dom.content(ul, E('em', { 'class': 'spinning' }, _('Loading directory contents…')));
  4756. L.resolveDefault(fs.list(path), []).then(L.bind(this.renderListing, this, browser, path));
  4757. }
  4758. else if (!this.options.browser) {
  4759. var button = this.node.firstElementChild,
  4760. hidden = this.node.lastElementChild;
  4761. path = this.canonicalizePath(path);
  4762. dom.content(button, [
  4763. this.iconForType(fileStat.type),
  4764. ' %s (%1000mB)'.format(this.truncatePath(path), fileStat.size)
  4765. ]);
  4766. browser.classList.remove('open');
  4767. button.style.display = '';
  4768. hidden.value = path;
  4769. this.stat = Object.assign({ path: path }, fileStat);
  4770. this.node.dispatchEvent(new CustomEvent('cbi-fileupload-select', { detail: this.stat }));
  4771. }
  4772. },
  4773. /** @private */
  4774. handleFileBrowser: function(ev) {
  4775. var button = ev.target,
  4776. browser = button.nextElementSibling,
  4777. path = this.stat ? this.stat.path.replace(/\/[^\/]+$/, '') : (this.options.initial_directory || this.options.root_directory);
  4778. if (path.indexOf(this.options.root_directory) != 0)
  4779. path = this.options.root_directory;
  4780. ev.preventDefault();
  4781. return L.resolveDefault(fs.list(path), []).then(L.bind(function(button, browser, path, list) {
  4782. document.querySelectorAll('.cbi-filebrowser.open').forEach(function(browserEl) {
  4783. dom.findClassInstance(browserEl).handleCancel(ev);
  4784. });
  4785. button.style.display = 'none';
  4786. browser.classList.add('open');
  4787. return this.renderListing(browser, path, list);
  4788. }, this, button, browser, path));
  4789. },
  4790. /** @override */
  4791. getValue: function() {
  4792. return this.node.lastElementChild.value;
  4793. },
  4794. /** @override */
  4795. setValue: function(value) {
  4796. this.node.lastElementChild.value = value;
  4797. }
  4798. });
  4799. function scrubMenu(node) {
  4800. var hasSatisfiedChild = false;
  4801. if (L.isObject(node.children)) {
  4802. for (var k in node.children) {
  4803. var child = scrubMenu(node.children[k]);
  4804. if (child.title &amp;&amp; !child.firstchild_ineligible)
  4805. hasSatisfiedChild = hasSatisfiedChild || child.satisfied;
  4806. }
  4807. }
  4808. if (L.isObject(node.action) &amp;&amp;
  4809. node.action.type == 'firstchild' &amp;&amp;
  4810. hasSatisfiedChild == false)
  4811. node.satisfied = false;
  4812. return node;
  4813. };
  4814. /**
  4815. * Handle menu.
  4816. *
  4817. * @constructor menu
  4818. * @memberof LuCI.ui
  4819. *
  4820. * @classdesc
  4821. *
  4822. * Handles menus.
  4823. */
  4824. var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ {
  4825. /**
  4826. * @typedef {Object} MenuNode
  4827. * @memberof LuCI.ui.menu
  4828. * @property {string} name - The internal name of the node, as used in the URL
  4829. * @property {number} order - The sort index of the menu node
  4830. * @property {string} [title] - The title of the menu node, `null` if the node should be hidden
  4831. * @property {satisfied} boolean - Boolean indicating whether the menu entries dependencies are satisfied
  4832. * @property {readonly} [boolean] - Boolean indicating whether the menu entries underlying ACLs are readonly
  4833. * @property {LuCI.ui.menu.MenuNode[]} [children] - Array of child menu nodes.
  4834. */
  4835. /**
  4836. * Load and cache current menu tree.
  4837. *
  4838. * @returns {Promise&lt;LuCI.ui.menu.MenuNode>}
  4839. * Returns a promise resolving to the root element of the menu tree.
  4840. */
  4841. load: function() {
  4842. if (this.menu == null)
  4843. this.menu = session.getLocalData('menu');
  4844. if (!L.isObject(this.menu)) {
  4845. this.menu = request.get(L.url('admin/menu')).then(L.bind(function(menu) {
  4846. this.menu = scrubMenu(menu.json());
  4847. session.setLocalData('menu', this.menu);
  4848. return this.menu;
  4849. }, this));
  4850. }
  4851. return Promise.resolve(this.menu);
  4852. },
  4853. /**
  4854. * Flush the internal menu cache to force loading a new structure on the
  4855. * next page load.
  4856. */
  4857. flushCache: function() {
  4858. session.setLocalData('menu', null);
  4859. },
  4860. /**
  4861. * @param {LuCI.ui.menu.MenuNode} [node]
  4862. * The menu node to retrieve the children for. Defaults to the menu's
  4863. * internal root node if omitted.
  4864. *
  4865. * @returns {LuCI.ui.menu.MenuNode[]}
  4866. * Returns an array of child menu nodes.
  4867. */
  4868. getChildren: function(node) {
  4869. var children = [];
  4870. if (node == null)
  4871. node = this.menu;
  4872. for (var k in node.children) {
  4873. if (!node.children.hasOwnProperty(k))
  4874. continue;
  4875. if (!node.children[k].satisfied)
  4876. continue;
  4877. if (!node.children[k].hasOwnProperty('title'))
  4878. continue;
  4879. var subnode = Object.assign(node.children[k], { name: k });
  4880. if (L.isObject(subnode.action) &amp;&amp; subnode.action.path != null &amp;&amp;
  4881. (subnode.action.type == 'alias' || subnode.action.type == 'rewrite')) {
  4882. var root = this.menu,
  4883. path = subnode.action.path.split('/');
  4884. for (var i = 0; root != null &amp;&amp; i &lt; path.length; i++)
  4885. root = L.isObject(root.children) ? root.children[path[i]] : null;
  4886. if (root)
  4887. subnode = Object.assign({}, subnode, {
  4888. children: root.children,
  4889. action: root.action
  4890. });
  4891. }
  4892. children.push(subnode);
  4893. }
  4894. return children.sort(function(a, b) {
  4895. var wA = a.order || 1000,
  4896. wB = b.order || 1000;
  4897. if (wA != wB)
  4898. return wA - wB;
  4899. return L.naturalCompare(a.name, b.name);
  4900. });
  4901. }
  4902. });
  4903. var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ {
  4904. __init__: function(captions, options, placeholder) {
  4905. if (!Array.isArray(captions)) {
  4906. this.initFromMarkup(captions);
  4907. return;
  4908. }
  4909. var id = options.id || 'table%08x'.format(Math.random() * 0xffffffff);
  4910. var table = E('table', { 'id': id, 'class': 'table' }, [
  4911. E('tr', { 'class': 'tr table-titles', 'click': UI.prototype.createHandlerFn(this, 'handleSort') })
  4912. ]);
  4913. this.id = id;
  4914. this.node = table
  4915. this.options = options;
  4916. var sorting = this.getActiveSortState();
  4917. for (var i = 0; i &lt; captions.length; i++) {
  4918. if (captions[i] == null)
  4919. continue;
  4920. var th = E('th', { 'class': 'th' }, [ captions[i] ]);
  4921. if (typeof(options.captionClasses) == 'object')
  4922. DOMTokenList.prototype.add.apply(th.classList, L.toArray(options.captionClasses[i]));
  4923. if (options.sortable !== false &amp;&amp; (typeof(options.sortable) != 'object' || options.sortable[i] !== false)) {
  4924. th.setAttribute('data-sortable-row', true);
  4925. if (sorting &amp;&amp; sorting[0] == i)
  4926. th.setAttribute('data-sort-direction', sorting[1] ? 'desc' : 'asc');
  4927. }
  4928. table.firstElementChild.appendChild(th);
  4929. }
  4930. if (placeholder) {
  4931. var trow = table.appendChild(E('tr', { 'class': 'tr placeholder' })),
  4932. td = trow.appendChild(E('td', { 'class': 'td' }, placeholder));
  4933. if (typeof(captionClasses) == 'object')
  4934. DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[0]));
  4935. }
  4936. DOMTokenList.prototype.add.apply(table.classList, L.toArray(options.classes));
  4937. },
  4938. update: function(data, placeholder) {
  4939. var placeholder = placeholder || this.options.placeholder || _('No data', 'empty table placeholder'),
  4940. sorting = this.getActiveSortState();
  4941. if (!Array.isArray(data))
  4942. return;
  4943. this.data = data;
  4944. this.placeholder = placeholder;
  4945. var n = 0,
  4946. rows = this.node.querySelectorAll('tr, .tr'),
  4947. trows = [],
  4948. headings = [].slice.call(this.node.firstElementChild.querySelectorAll('th, .th')),
  4949. captionClasses = this.options.captionClasses,
  4950. trTag = (rows[0] &amp;&amp; rows[0].nodeName == 'DIV') ? 'div' : 'tr',
  4951. tdTag = (headings[0] &amp;&amp; headings[0].nodeName == 'DIV') ? 'div' : 'td';
  4952. if (sorting) {
  4953. var list = data.map(L.bind(function(row) {
  4954. return [ this.deriveSortKey(row[sorting[0]], sorting[0]), row ];
  4955. }, this));
  4956. list.sort(function(a, b) {
  4957. return sorting[1]
  4958. ? -L.naturalCompare(a[0], b[0])
  4959. : L.naturalCompare(a[0], b[0]);
  4960. });
  4961. data.length = 0;
  4962. list.forEach(function(item) {
  4963. data.push(item[1]);
  4964. });
  4965. headings.forEach(function(th, i) {
  4966. if (i == sorting[0])
  4967. th.setAttribute('data-sort-direction', sorting[1] ? 'desc' : 'asc');
  4968. else
  4969. th.removeAttribute('data-sort-direction');
  4970. });
  4971. }
  4972. data.forEach(function(row) {
  4973. trows[n] = E(trTag, { 'class': 'tr' });
  4974. for (var i = 0; i &lt; headings.length; i++) {
  4975. var text = (headings[i].innerText || '').trim();
  4976. var raw_val = Array.isArray(row[i]) ? row[i][0] : null;
  4977. var disp_val = Array.isArray(row[i]) ? row[i][1] : row[i];
  4978. var td = trows[n].appendChild(E(tdTag, {
  4979. 'class': 'td',
  4980. 'data-title': (text !== '') ? text : null,
  4981. 'data-value': raw_val
  4982. }, (disp_val != null) ? ((disp_val instanceof DocumentFragment) ? disp_val.cloneNode(true) : disp_val) : ''));
  4983. if (typeof(captionClasses) == 'object')
  4984. DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[i]));
  4985. if (!td.classList.contains('cbi-section-actions'))
  4986. headings[i].setAttribute('data-sortable-row', true);
  4987. }
  4988. trows[n].classList.add('cbi-rowstyle-%d'.format((n++ % 2) ? 2 : 1));
  4989. });
  4990. for (var i = 0; i &lt; n; i++) {
  4991. if (rows[i+1])
  4992. this.node.replaceChild(trows[i], rows[i+1]);
  4993. else
  4994. this.node.appendChild(trows[i]);
  4995. }
  4996. while (rows[++n])
  4997. this.node.removeChild(rows[n]);
  4998. if (placeholder &amp;&amp; this.node.firstElementChild === this.node.lastElementChild) {
  4999. var trow = this.node.appendChild(E(trTag, { 'class': 'tr placeholder' })),
  5000. td = trow.appendChild(E(tdTag, { 'class': 'td' }, placeholder));
  5001. if (typeof(captionClasses) == 'object')
  5002. DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[0]));
  5003. }
  5004. return this.node;
  5005. },
  5006. render: function() {
  5007. return this.node;
  5008. },
  5009. /** @private */
  5010. initFromMarkup: function(node) {
  5011. if (!dom.elem(node))
  5012. node = document.querySelector(node);
  5013. if (!node)
  5014. throw 'Invalid table selector';
  5015. var options = {},
  5016. headrow = node.querySelector('tr, .tr');
  5017. if (!headrow)
  5018. return;
  5019. options.id = node.id;
  5020. options.classes = [].slice.call(node.classList).filter(function(c) { return c != 'table' });
  5021. options.sortable = [];
  5022. options.captionClasses = [];
  5023. headrow.querySelectorAll('th, .th').forEach(function(th, i) {
  5024. options.sortable[i] = !th.classList.contains('cbi-section-actions');
  5025. options.captionClasses[i] = [].slice.call(th.classList).filter(function(c) { return c != 'th' });
  5026. });
  5027. headrow.addEventListener('click', UI.prototype.createHandlerFn(this, 'handleSort'));
  5028. this.id = node.id;
  5029. this.node = node;
  5030. this.options = options;
  5031. },
  5032. /** @private */
  5033. deriveSortKey: function(value, index) {
  5034. var opts = this.options || {},
  5035. hint, m;
  5036. if (opts.sortable == true || opts.sortable == null)
  5037. hint = 'auto';
  5038. else if (typeof( opts.sortable) == 'object')
  5039. hint = opts.sortable[index];
  5040. if (dom.elem(value)) {
  5041. if (value.hasAttribute('data-value'))
  5042. value = value.getAttribute('data-value');
  5043. else
  5044. value = (value.innerText || '').trim();
  5045. }
  5046. switch (hint || 'auto') {
  5047. case true:
  5048. case 'auto':
  5049. m = /^([0-9a-fA-F:.]+)(?:\/([0-9a-fA-F:.]+))?$/.exec(value);
  5050. if (m) {
  5051. var addr, mask;
  5052. addr = validation.parseIPv6(m[1]);
  5053. mask = m[2] ? validation.parseIPv6(m[2]) : null;
  5054. if (addr &amp;&amp; mask != null)
  5055. return '%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x'.format(
  5056. addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
  5057. mask[0], mask[1], mask[2], mask[3], mask[4], mask[5], mask[6], mask[7]
  5058. );
  5059. else if (addr)
  5060. return '%04x%04x%04x%04x%04x%04x%04x%04x%02x'.format(
  5061. addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
  5062. m[2] ? +m[2] : 128
  5063. );
  5064. addr = validation.parseIPv4(m[1]);
  5065. mask = m[2] ? validation.parseIPv4(m[2]) : null;
  5066. if (addr &amp;&amp; mask != null)
  5067. return '%03d%03d%03d%03d%03d%03d%03d%03d'.format(
  5068. addr[0], addr[1], addr[2], addr[3],
  5069. mask[0], mask[1], mask[2], mask[3]
  5070. );
  5071. else if (addr)
  5072. return '%03d%03d%03d%03d%02d'.format(
  5073. addr[0], addr[1], addr[2], addr[3],
  5074. m[2] ? +m[2] : 32
  5075. );
  5076. }
  5077. m = /^(?:(\d+)d )?(\d+)h (\d+)m (\d+)s$/.exec(value);
  5078. if (m)
  5079. return '%05d%02d%02d%02d'.format(+m[1], +m[2], +m[3], +m[4]);
  5080. m = /^(\d+)\b(\D*)$/.exec(value);
  5081. if (m)
  5082. return '%010d%s'.format(+m[1], m[2]);
  5083. return String(value);
  5084. case 'ignorecase':
  5085. return String(value).toLowerCase();
  5086. case 'numeric':
  5087. return +value;
  5088. default:
  5089. return String(value);
  5090. }
  5091. },
  5092. /** @private */
  5093. getActiveSortState: function() {
  5094. if (this.sortState)
  5095. return this.sortState;
  5096. if (!this.options.id)
  5097. return null;
  5098. var page = document.body.getAttribute('data-page'),
  5099. key = page + '.' + this.options.id,
  5100. state = session.getLocalData('tablesort');
  5101. if (L.isObject(state) &amp;&amp; Array.isArray(state[key]))
  5102. return state[key];
  5103. return null;
  5104. },
  5105. /** @private */
  5106. setActiveSortState: function(index, descending) {
  5107. this.sortState = [ index, descending ];
  5108. if (!this.options.id)
  5109. return;
  5110. var page = document.body.getAttribute('data-page'),
  5111. key = page + '.' + this.options.id,
  5112. state = session.getLocalData('tablesort');
  5113. if (!L.isObject(state))
  5114. state = {};
  5115. state[key] = this.sortState;
  5116. session.setLocalData('tablesort', state);
  5117. },
  5118. /** @private */
  5119. handleSort: function(ev) {
  5120. if (!ev.target.matches('th[data-sortable-row]'))
  5121. return;
  5122. var index, direction;
  5123. this.node.firstElementChild.querySelectorAll('th, .th').forEach(function(th, i) {
  5124. if (th === ev.target) {
  5125. index = i;
  5126. direction = th.getAttribute('data-sort-direction') == 'asc';
  5127. }
  5128. });
  5129. this.setActiveSortState(index, direction);
  5130. this.update(this.data, this.placeholder);
  5131. }
  5132. });
  5133. /**
  5134. * @class ui
  5135. * @memberof LuCI
  5136. * @hideconstructor
  5137. * @classdesc
  5138. *
  5139. * Provides high level UI helper functionality.
  5140. * To import the class in views, use `'require ui'`, to import it in
  5141. * external JavaScript, use `L.require("ui").then(...)`.
  5142. */
  5143. var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
  5144. __init__: function() {
  5145. modalDiv = document.body.appendChild(
  5146. dom.create('div', {
  5147. id: 'modal_overlay',
  5148. tabindex: -1,
  5149. keydown: this.cancelModal
  5150. }, [
  5151. dom.create('div', {
  5152. class: 'modal',
  5153. role: 'dialog',
  5154. 'aria-modal': true
  5155. })
  5156. ]));
  5157. tooltipDiv = document.body.appendChild(
  5158. dom.create('div', { class: 'cbi-tooltip' }));
  5159. /* set up old aliases */
  5160. L.showModal = this.showModal;
  5161. L.hideModal = this.hideModal;
  5162. L.showTooltip = this.showTooltip;
  5163. L.hideTooltip = this.hideTooltip;
  5164. L.itemlist = this.itemlist;
  5165. document.addEventListener('mouseover', this.showTooltip.bind(this), true);
  5166. document.addEventListener('mouseout', this.hideTooltip.bind(this), true);
  5167. document.addEventListener('focus', this.showTooltip.bind(this), true);
  5168. document.addEventListener('blur', this.hideTooltip.bind(this), true);
  5169. document.addEventListener('luci-loaded', this.tabs.init.bind(this.tabs));
  5170. document.addEventListener('luci-loaded', this.changes.init.bind(this.changes));
  5171. document.addEventListener('uci-loaded', this.changes.init.bind(this.changes));
  5172. },
  5173. /**
  5174. * Display a modal overlay dialog with the specified contents.
  5175. *
  5176. * The modal overlay dialog covers the current view preventing interaction
  5177. * with the underlying view contents. Only one modal dialog instance can
  5178. * be opened. Invoking showModal() while a modal dialog is already open will
  5179. * replace the open dialog with a new one having the specified contents.
  5180. *
  5181. * Additional CSS class names may be passed to influence the appearance of
  5182. * the dialog. Valid values for the classes depend on the underlying theme.
  5183. *
  5184. * @see LuCI.dom.content
  5185. *
  5186. * @param {string} [title]
  5187. * The title of the dialog. If `null`, no title element will be rendered.
  5188. *
  5189. * @param {*} children
  5190. * The contents to add to the modal dialog. This should be a DOM node or
  5191. * a document fragment in most cases. The value is passed as-is to the
  5192. * `dom.content()` function - refer to its documentation for applicable
  5193. * values.
  5194. *
  5195. * @param {...string} [classes]
  5196. * A number of extra CSS class names which are set on the modal dialog
  5197. * element.
  5198. *
  5199. * @returns {Node}
  5200. * Returns a DOM Node representing the modal dialog element.
  5201. */
  5202. showModal: function(title, children /* , ... */) {
  5203. var dlg = modalDiv.firstElementChild;
  5204. dlg.setAttribute('class', 'modal');
  5205. for (var i = 2; i &lt; arguments.length; i++)
  5206. dlg.classList.add(arguments[i]);
  5207. dom.content(dlg, dom.create('h4', {}, title));
  5208. dom.append(dlg, children);
  5209. document.body.classList.add('modal-overlay-active');
  5210. modalDiv.scrollTop = 0;
  5211. modalDiv.focus();
  5212. return dlg;
  5213. },
  5214. /**
  5215. * Close the open modal overlay dialog.
  5216. *
  5217. * This function will close an open modal dialog and restore the normal view
  5218. * behaviour. It has no effect if no modal dialog is currently open.
  5219. *
  5220. * Note that this function is stand-alone, it does not rely on `this` and
  5221. * will not invoke other class functions so it is suitable to be used as event
  5222. * handler as-is without the need to bind it first.
  5223. */
  5224. hideModal: function() {
  5225. document.body.classList.remove('modal-overlay-active');
  5226. modalDiv.blur();
  5227. },
  5228. /** @private */
  5229. cancelModal: function(ev) {
  5230. if (ev.key == 'Escape') {
  5231. var btn = modalDiv.querySelector('.right > button, .right > .btn, .button-row > .btn');
  5232. if (btn)
  5233. btn.click();
  5234. }
  5235. },
  5236. /** @private */
  5237. showTooltip: function(ev) {
  5238. var target = findParent(ev.target, '[data-tooltip]');
  5239. if (!target)
  5240. return;
  5241. if (tooltipTimeout !== null) {
  5242. window.clearTimeout(tooltipTimeout);
  5243. tooltipTimeout = null;
  5244. }
  5245. var rect = target.getBoundingClientRect(),
  5246. x = rect.left + window.pageXOffset,
  5247. y = rect.top + rect.height + window.pageYOffset,
  5248. above = false;
  5249. tooltipDiv.className = 'cbi-tooltip';
  5250. tooltipDiv.innerHTML = '▲ ';
  5251. tooltipDiv.firstChild.data += target.getAttribute('data-tooltip');
  5252. if (target.hasAttribute('data-tooltip-style'))
  5253. tooltipDiv.classList.add(target.getAttribute('data-tooltip-style'));
  5254. if ((y + tooltipDiv.offsetHeight) > (window.innerHeight + window.pageYOffset))
  5255. above = true;
  5256. var dropdown = target.querySelector('ul.dropdown[style]:first-child');
  5257. if (dropdown &amp;&amp; dropdown.style.top)
  5258. above = true;
  5259. if (above) {
  5260. y -= (tooltipDiv.offsetHeight + target.offsetHeight);
  5261. tooltipDiv.firstChild.data = '▼ ' + tooltipDiv.firstChild.data.substr(2);
  5262. }
  5263. tooltipDiv.style.top = y + 'px';
  5264. tooltipDiv.style.left = x + 'px';
  5265. tooltipDiv.style.opacity = 1;
  5266. tooltipDiv.dispatchEvent(new CustomEvent('tooltip-open', {
  5267. bubbles: true,
  5268. detail: { target: target }
  5269. }));
  5270. },
  5271. /** @private */
  5272. hideTooltip: function(ev) {
  5273. if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv ||
  5274. tooltipDiv.contains(ev.target) || tooltipDiv.contains(ev.relatedTarget))
  5275. return;
  5276. if (tooltipTimeout !== null) {
  5277. window.clearTimeout(tooltipTimeout);
  5278. tooltipTimeout = null;
  5279. }
  5280. tooltipDiv.style.opacity = 0;
  5281. tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250);
  5282. tooltipDiv.dispatchEvent(new CustomEvent('tooltip-close', { bubbles: true }));
  5283. },
  5284. /**
  5285. * Add a notification banner at the top of the current view.
  5286. *
  5287. * A notification banner is an alert message usually displayed at the
  5288. * top of the current view, spanning the entire available width.
  5289. * Notification banners will stay in place until dismissed by the user.
  5290. * Multiple banners may be shown at the same time.
  5291. *
  5292. * Additional CSS class names may be passed to influence the appearance of
  5293. * the banner. Valid values for the classes depend on the underlying theme.
  5294. *
  5295. * @see LuCI.dom.content
  5296. *
  5297. * @param {string} [title]
  5298. * The title of the notification banner. If `null`, no title element
  5299. * will be rendered.
  5300. *
  5301. * @param {*} children
  5302. * The contents to add to the notification banner. This should be a DOM
  5303. * node or a document fragment in most cases. The value is passed as-is
  5304. * to the `dom.content()` function - refer to its documentation for
  5305. * applicable values.
  5306. *
  5307. * @param {int} [timeout]
  5308. * A millisecond value after which the notification will disappear
  5309. * automatically. If omitted, the notification will remain until it receives
  5310. * the click event.
  5311. *
  5312. * @param {...string} [classes]
  5313. * A number of extra CSS class names which are set on the notification
  5314. * banner element.
  5315. *
  5316. * @returns {Node}
  5317. * Returns a DOM Node representing the notification banner element.
  5318. */
  5319. addNotification: function(title, children, timeout, ...classes) {
  5320. var mc = document.querySelector('#maincontent') || document.body;
  5321. var msg = E('div', {
  5322. 'class': 'alert-message fade-in',
  5323. 'style': 'display:flex',
  5324. 'transitionend': function(ev) {
  5325. var node = ev.currentTarget;
  5326. if (node.parentNode &amp;&amp; node.classList.contains('fade-out'))
  5327. node.parentNode.removeChild(node);
  5328. }
  5329. }, [
  5330. E('div', { 'style': 'flex:10' }),
  5331. E('div', { 'style': 'flex:1 1 auto; display:flex' }, [
  5332. E('button', {
  5333. 'class': 'btn',
  5334. 'style': 'margin-left:auto; margin-top:auto',
  5335. 'click': function(ev) {
  5336. fadeOutNotification(ev.target);
  5337. },
  5338. }, [ _('Dismiss') ])
  5339. ])
  5340. ]);
  5341. if (title != null)
  5342. dom.append(msg.firstElementChild, E('h4', {}, title));
  5343. dom.append(msg.firstElementChild, children);
  5344. classes.forEach(cls => msg.classList.add(cls));
  5345. mc.insertBefore(msg, mc.firstElementChild);
  5346. function fadeOutNotification(element) {
  5347. var notification = dom.parent(element, '.alert-message');
  5348. if (notification) {
  5349. notification.classList.add('fade-out');
  5350. notification.classList.remove('fade-in');
  5351. setTimeout(() => {
  5352. if (notification.parentNode) {
  5353. notification.parentNode.removeChild(notification);
  5354. }
  5355. });
  5356. }
  5357. }
  5358. if (typeof timeout === 'number' &amp;&amp; timeout > 0) {
  5359. setTimeout(function() {
  5360. if (msg &amp;&amp; msg.parentNode) {
  5361. fadeOutNotification(msg);
  5362. }
  5363. }, timeout);
  5364. }
  5365. return msg;
  5366. },
  5367. /**
  5368. * Display or update a header area indicator.
  5369. *
  5370. * An indicator is a small label displayed in the header area of the screen
  5371. * providing few amounts of status information such as item counts or state
  5372. * toggle indicators.
  5373. *
  5374. * Multiple indicators may be shown at the same time and indicator labels
  5375. * may be made clickable to display extended information or to initiate
  5376. * further actions.
  5377. *
  5378. * Indicators can either use a default `active` or a less accented `inactive`
  5379. * style which is useful for indicators representing state toggles.
  5380. *
  5381. * @param {string} id
  5382. * The ID of the indicator. If an indicator with the given ID already exists,
  5383. * it is updated with the given label and style.
  5384. *
  5385. * @param {string} label
  5386. * The text to display in the indicator label.
  5387. *
  5388. * @param {function} [handler]
  5389. * A handler function to invoke when the indicator label is clicked/touched
  5390. * by the user. If omitted, the indicator is not clickable/touchable.
  5391. *
  5392. * Note that this parameter only applies to new indicators, when updating
  5393. * existing labels it is ignored.
  5394. *
  5395. * @param {"active"|"inactive"} [style=active]
  5396. * The indicator style to use. May be either `active` or `inactive`.
  5397. *
  5398. * @returns {boolean}
  5399. * Returns `true` when the indicator has been updated or `false` when no
  5400. * changes were made.
  5401. */
  5402. showIndicator: function(id, label, handler, style) {
  5403. if (indicatorDiv == null) {
  5404. indicatorDiv = document.body.querySelector('#indicators');
  5405. if (indicatorDiv == null)
  5406. return false;
  5407. }
  5408. var handlerFn = (typeof(handler) == 'function') ? handler : null,
  5409. indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id));
  5410. if (indicatorElem == null) {
  5411. var beforeElem = null;
  5412. for (beforeElem = indicatorDiv.firstElementChild;
  5413. beforeElem != null;
  5414. beforeElem = beforeElem.nextElementSibling)
  5415. if (beforeElem.getAttribute('data-indicator') > id)
  5416. break;
  5417. indicatorElem = indicatorDiv.insertBefore(E('span', {
  5418. 'data-indicator': id,
  5419. 'data-clickable': handlerFn ? true : null,
  5420. 'click': handlerFn
  5421. }, ['']), beforeElem);
  5422. }
  5423. if (label == indicatorElem.firstChild.data &amp;&amp; style == indicatorElem.getAttribute('data-style'))
  5424. return false;
  5425. indicatorElem.firstChild.data = label;
  5426. indicatorElem.setAttribute('data-style', (style == 'inactive') ? 'inactive' : 'active');
  5427. return true;
  5428. },
  5429. /**
  5430. * Remove a header area indicator.
  5431. *
  5432. * This function removes the given indicator label from the header indicator
  5433. * area. When the given indicator is not found, this function does nothing.
  5434. *
  5435. * @param {string} id
  5436. * The ID of the indicator to remove.
  5437. *
  5438. * @returns {boolean}
  5439. * Returns `true` when the indicator has been removed or `false` when the
  5440. * requested indicator was not found.
  5441. */
  5442. hideIndicator: function(id) {
  5443. var indicatorElem = indicatorDiv ? indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) : null;
  5444. if (indicatorElem == null)
  5445. return false;
  5446. indicatorDiv.removeChild(indicatorElem);
  5447. return true;
  5448. },
  5449. /**
  5450. * Formats a series of label/value pairs into list-like markup.
  5451. *
  5452. * This function transforms a flat array of alternating label and value
  5453. * elements into a list-like markup, using the values in `separators` as
  5454. * separators and appends the resulting nodes to the given parent DOM node.
  5455. *
  5456. * Each label is suffixed with `: ` and wrapped into a `&lt;strong>` tag, the
  5457. * `&lt;strong>` element and the value corresponding to the label are
  5458. * subsequently wrapped into a `&lt;span class="nowrap">` element.
  5459. *
  5460. * The resulting `&lt;span>` element tuples are joined by the given separators
  5461. * to form the final markup which is appended to the given parent DOM node.
  5462. *
  5463. * @param {Node} node
  5464. * The parent DOM node to append the markup to. Any previous child elements
  5465. * will be removed.
  5466. *
  5467. * @param {Array&lt;*>} items
  5468. * An alternating array of labels and values. The label values will be
  5469. * converted to plain strings, the values are used as-is and may be of
  5470. * any type accepted by `LuCI.dom.content()`.
  5471. *
  5472. * @param {*|Array&lt;*>} [separators=[E('br')]]
  5473. * A single value or an array of separator values to separate each
  5474. * label/value pair with. The function will cycle through the separators
  5475. * when joining the pairs. If omitted, the default separator is a sole HTML
  5476. * `&lt;br>` element. Separator values are used as-is and may be of any type
  5477. * accepted by `LuCI.dom.content()`.
  5478. *
  5479. * @returns {Node}
  5480. * Returns the parent DOM node the formatted markup has been added to.
  5481. */
  5482. itemlist: function(node, items, separators) {
  5483. var children = [];
  5484. if (!Array.isArray(separators))
  5485. separators = [ separators || E('br') ];
  5486. for (var i = 0; i &lt; items.length; i += 2) {
  5487. if (items[i+1] !== null &amp;&amp; items[i+1] !== undefined) {
  5488. var sep = separators[(i/2) % separators.length],
  5489. cld = [];
  5490. children.push(E('span', { class: 'nowrap' }, [
  5491. items[i] ? E('strong', items[i] + ': ') : '',
  5492. items[i+1]
  5493. ]));
  5494. if ((i+2) &lt; items.length)
  5495. children.push(dom.elem(sep) ? sep.cloneNode(true) : sep);
  5496. }
  5497. }
  5498. dom.content(node, children);
  5499. return node;
  5500. },
  5501. /**
  5502. * @class
  5503. * @memberof LuCI.ui
  5504. * @hideconstructor
  5505. * @classdesc
  5506. *
  5507. * The `tabs` class handles tab menu groups used throughout the view area.
  5508. * It takes care of setting up tab groups, tracking their state and handling
  5509. * related events.
  5510. *
  5511. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  5512. * in views, use `'require ui'` and refer to `ui.tabs`. To import it in
  5513. * external JavaScript, use `L.require("ui").then(...)` and access the
  5514. * `tabs` property of the class instance value.
  5515. */
  5516. tabs: baseclass.singleton(/* @lends LuCI.ui.tabs.prototype */ {
  5517. /** @private */
  5518. init: function() {
  5519. var groups = [], prevGroup = null, currGroup = null;
  5520. document.querySelectorAll('[data-tab]').forEach(function(tab) {
  5521. var parent = tab.parentNode;
  5522. if (dom.matches(tab, 'li') &amp;&amp; dom.matches(parent, 'ul.cbi-tabmenu'))
  5523. return;
  5524. if (!parent.hasAttribute('data-tab-group'))
  5525. parent.setAttribute('data-tab-group', groups.length);
  5526. currGroup = +parent.getAttribute('data-tab-group');
  5527. if (currGroup !== prevGroup) {
  5528. prevGroup = currGroup;
  5529. if (!groups[currGroup])
  5530. groups[currGroup] = [];
  5531. }
  5532. groups[currGroup].push(tab);
  5533. });
  5534. for (var i = 0; i &lt; groups.length; i++)
  5535. this.initTabGroup(groups[i]);
  5536. document.addEventListener('dependency-update', this.updateTabs.bind(this));
  5537. this.updateTabs();
  5538. },
  5539. /**
  5540. * Initializes a new tab group from the given tab pane collection.
  5541. *
  5542. * This function cycles through the given tab pane DOM nodes, extracts
  5543. * their tab IDs, titles and active states, renders a corresponding
  5544. * tab menu and prepends it to the tab panes common parent DOM node.
  5545. *
  5546. * The tab menu labels will be set to the value of the `data-tab-title`
  5547. * attribute of each corresponding pane. The last pane with the
  5548. * `data-tab-active` attribute set to `true` will be selected by default.
  5549. *
  5550. * If no pane is marked as active, the first one will be preselected.
  5551. *
  5552. * @instance
  5553. * @memberof LuCI.ui.tabs
  5554. * @param {Array&lt;Node>|NodeList} panes
  5555. * A collection of tab panes to build a tab group menu for. May be a
  5556. * plain array of DOM nodes or a NodeList collection, such as the result
  5557. * of a `querySelectorAll()` call or the `.childNodes` property of a
  5558. * DOM node.
  5559. */
  5560. initTabGroup: function(panes) {
  5561. if (typeof(panes) != 'object' || !('length' in panes) || panes.length === 0)
  5562. return;
  5563. var menu = E('ul', { 'class': 'cbi-tabmenu' }),
  5564. group = panes[0].parentNode,
  5565. groupId = +group.getAttribute('data-tab-group'),
  5566. selected = null;
  5567. if (group.getAttribute('data-initialized') === 'true')
  5568. return;
  5569. for (var i = 0, pane; pane = panes[i]; i++) {
  5570. var name = pane.getAttribute('data-tab'),
  5571. title = pane.getAttribute('data-tab-title'),
  5572. active = pane.getAttribute('data-tab-active') === 'true';
  5573. menu.appendChild(E('li', {
  5574. 'style': this.isEmptyPane(pane) ? 'display:none' : null,
  5575. 'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
  5576. 'data-tab': name
  5577. }, E('a', {
  5578. 'href': '#',
  5579. 'click': this.switchTab.bind(this)
  5580. }, title)));
  5581. if (active)
  5582. selected = i;
  5583. }
  5584. group.parentNode.insertBefore(menu, group);
  5585. group.setAttribute('data-initialized', true);
  5586. if (selected === null) {
  5587. selected = this.getActiveTabId(panes[0]);
  5588. if (selected &lt; 0 || selected >= panes.length || this.isEmptyPane(panes[selected])) {
  5589. for (var i = 0; i &lt; panes.length; i++) {
  5590. if (!this.isEmptyPane(panes[i])) {
  5591. selected = i;
  5592. break;
  5593. }
  5594. }
  5595. }
  5596. menu.childNodes[selected].classList.add('cbi-tab');
  5597. menu.childNodes[selected].classList.remove('cbi-tab-disabled');
  5598. panes[selected].setAttribute('data-tab-active', 'true');
  5599. this.setActiveTabId(panes[selected], selected);
  5600. }
  5601. requestAnimationFrame(L.bind(function(pane) {
  5602. pane.dispatchEvent(new CustomEvent('cbi-tab-active', {
  5603. detail: { tab: pane.getAttribute('data-tab') }
  5604. }));
  5605. }, this, panes[selected]));
  5606. this.updateTabs(group);
  5607. },
  5608. /**
  5609. * Checks whether the given tab pane node is empty.
  5610. *
  5611. * @instance
  5612. * @memberof LuCI.ui.tabs
  5613. * @param {Node} pane
  5614. * The tab pane to check.
  5615. *
  5616. * @returns {boolean}
  5617. * Returns `true` if the pane is empty, else `false`.
  5618. */
  5619. isEmptyPane: function(pane) {
  5620. return dom.isEmpty(pane, function(n) { return n.classList.contains('cbi-tab-descr') });
  5621. },
  5622. /** @private */
  5623. getPathForPane: function(pane) {
  5624. var path = [], node = null;
  5625. for (node = pane ? pane.parentNode : null;
  5626. node != null &amp;&amp; node.hasAttribute != null;
  5627. node = node.parentNode)
  5628. {
  5629. if (node.hasAttribute('data-tab'))
  5630. path.unshift(node.getAttribute('data-tab'));
  5631. else if (node.hasAttribute('data-section-id'))
  5632. path.unshift(node.getAttribute('data-section-id'));
  5633. }
  5634. return path.join('/');
  5635. },
  5636. /** @private */
  5637. getActiveTabState: function() {
  5638. var page = document.body.getAttribute('data-page'),
  5639. state = session.getLocalData('tab');
  5640. if (L.isObject(state) &amp;&amp; state.page === page &amp;&amp; L.isObject(state.paths))
  5641. return state;
  5642. session.setLocalData('tab', null);
  5643. return { page: page, paths: {} };
  5644. },
  5645. /** @private */
  5646. getActiveTabId: function(pane) {
  5647. var path = this.getPathForPane(pane);
  5648. return +this.getActiveTabState().paths[path] || 0;
  5649. },
  5650. /** @private */
  5651. setActiveTabId: function(pane, tabIndex) {
  5652. var path = this.getPathForPane(pane),
  5653. state = this.getActiveTabState();
  5654. state.paths[path] = tabIndex;
  5655. return session.setLocalData('tab', state);
  5656. },
  5657. /** @private */
  5658. updateTabs: function(ev, root) {
  5659. (root || document).querySelectorAll('[data-tab-title]').forEach(L.bind(function(pane) {
  5660. var menu = pane.parentNode.previousElementSibling,
  5661. tab = menu ? menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))) : null,
  5662. n_errors = pane.querySelectorAll('.cbi-input-invalid').length;
  5663. if (!menu || !tab)
  5664. return;
  5665. if (this.isEmptyPane(pane)) {
  5666. tab.style.display = 'none';
  5667. tab.classList.remove('flash');
  5668. }
  5669. else if (tab.style.display === 'none') {
  5670. tab.style.display = '';
  5671. requestAnimationFrame(function() { tab.classList.add('flash') });
  5672. }
  5673. if (n_errors) {
  5674. tab.setAttribute('data-errors', n_errors);
  5675. tab.setAttribute('data-tooltip', _('%d invalid field(s)').format(n_errors));
  5676. tab.setAttribute('data-tooltip-style', 'error');
  5677. }
  5678. else {
  5679. tab.removeAttribute('data-errors');
  5680. tab.removeAttribute('data-tooltip');
  5681. }
  5682. }, this));
  5683. },
  5684. /** @private */
  5685. switchTab: function(ev) {
  5686. var tab = ev.target.parentNode,
  5687. name = tab.getAttribute('data-tab'),
  5688. menu = tab.parentNode,
  5689. group = menu.nextElementSibling,
  5690. groupId = +group.getAttribute('data-tab-group'),
  5691. index = 0;
  5692. ev.preventDefault();
  5693. if (!tab.classList.contains('cbi-tab-disabled'))
  5694. return;
  5695. menu.querySelectorAll('[data-tab]').forEach(function(tab) {
  5696. tab.classList.remove('cbi-tab');
  5697. tab.classList.remove('cbi-tab-disabled');
  5698. tab.classList.add(
  5699. tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled');
  5700. });
  5701. group.childNodes.forEach(function(pane) {
  5702. if (dom.matches(pane, '[data-tab]')) {
  5703. if (pane.getAttribute('data-tab') === name) {
  5704. pane.setAttribute('data-tab-active', 'true');
  5705. pane.dispatchEvent(new CustomEvent('cbi-tab-active', { detail: { tab: name } }));
  5706. UI.prototype.tabs.setActiveTabId(pane, index);
  5707. }
  5708. else {
  5709. pane.setAttribute('data-tab-active', 'false');
  5710. }
  5711. index++;
  5712. }
  5713. });
  5714. }
  5715. }),
  5716. /**
  5717. * @typedef {Object} FileUploadReply
  5718. * @memberof LuCI.ui
  5719. * @property {string} name - Name of the uploaded file without directory components
  5720. * @property {number} size - Size of the uploaded file in bytes
  5721. * @property {string} checksum - The MD5 checksum of the received file data
  5722. * @property {string} sha256sum - The SHA256 checksum of the received file data
  5723. */
  5724. /**
  5725. * Display a modal file upload prompt.
  5726. *
  5727. * This function opens a modal dialog prompting the user to select and
  5728. * upload a file to a predefined remote destination path.
  5729. *
  5730. * @param {string} path
  5731. * The remote file path to upload the local file to.
  5732. *
  5733. * @param {Node} [progressStatusNode]
  5734. * An optional DOM text node whose content text is set to the progress
  5735. * percentage value during file upload.
  5736. *
  5737. * @returns {Promise&lt;LuCI.ui.FileUploadReply>}
  5738. * Returns a promise resolving to a file upload status object on success
  5739. * or rejecting with an error in case the upload failed or has been
  5740. * cancelled by the user.
  5741. */
  5742. uploadFile: function(path, progressStatusNode) {
  5743. return new Promise(function(resolveFn, rejectFn) {
  5744. UI.prototype.showModal(_('Uploading file…'), [
  5745. E('p', _('Please select the file to upload.')),
  5746. E('div', { 'class': 'button-row' }, [
  5747. E('button', {
  5748. 'class': 'btn cbi-button',
  5749. 'click': function() {
  5750. UI.prototype.hideModal();
  5751. rejectFn(new Error(_('Upload has been cancelled')));
  5752. }
  5753. }, [ _('Cancel') ]),
  5754. E('input', {
  5755. type: 'file',
  5756. style: 'display:none',
  5757. change: function(ev) {
  5758. var modal = dom.parent(ev.target, '.modal'),
  5759. body = modal.querySelector('p'),
  5760. upload = modal.querySelector('.cbi-button-action.important'),
  5761. file = ev.currentTarget.files[0];
  5762. if (file == null)
  5763. return;
  5764. dom.content(body, [
  5765. E('ul', {}, [
  5766. E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]),
  5767. E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ])
  5768. ])
  5769. ]);
  5770. upload.disabled = false;
  5771. upload.focus();
  5772. }
  5773. }),
  5774. E('button', {
  5775. 'class': 'btn cbi-button',
  5776. 'click': function(ev) {
  5777. ev.target.previousElementSibling.click();
  5778. }
  5779. }, [ _('Browse…') ]),
  5780. E('button', {
  5781. 'class': 'btn cbi-button-action important',
  5782. 'disabled': true,
  5783. 'click': function(ev) {
  5784. var input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]');
  5785. if (!input.files[0])
  5786. return;
  5787. var progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' }));
  5788. UI.prototype.showModal(_('Uploading file…'), [ progress ]);
  5789. var data = new FormData();
  5790. data.append('sessionid', rpc.getSessionID());
  5791. data.append('filename', path);
  5792. data.append('filedata', input.files[0]);
  5793. var filename = input.files[0].name;
  5794. request.post(L.env.cgi_base + '/cgi-upload', data, {
  5795. timeout: 0,
  5796. progress: function(pev) {
  5797. var percent = (pev.loaded / pev.total) * 100;
  5798. if (progressStatusNode)
  5799. progressStatusNode.data = '%.2f%%'.format(percent);
  5800. progress.setAttribute('title', '%.2f%%'.format(percent));
  5801. progress.firstElementChild.style.width = '%.2f%%'.format(percent);
  5802. }
  5803. }).then(function(res) {
  5804. var reply = res.json();
  5805. UI.prototype.hideModal();
  5806. if (L.isObject(reply) &amp;&amp; reply.failure) {
  5807. UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message)));
  5808. rejectFn(new Error(reply.failure));
  5809. }
  5810. else {
  5811. reply.name = filename;
  5812. resolveFn(reply);
  5813. }
  5814. }, function(err) {
  5815. UI.prototype.hideModal();
  5816. rejectFn(err);
  5817. });
  5818. }
  5819. }, [ _('Upload') ])
  5820. ])
  5821. ]);
  5822. });
  5823. },
  5824. /**
  5825. * Perform a device connectivity test.
  5826. *
  5827. * Attempt to fetch a well known resource from the remote device via HTTP
  5828. * in order to test connectivity. This function is mainly useful to wait
  5829. * for the router to come back online after a reboot or reconfiguration.
  5830. *
  5831. * @param {string} [proto=http]
  5832. * The protocol to use for fetching the resource. May be either `http`
  5833. * (the default) or `https`.
  5834. *
  5835. * @param {string} [ipaddr=window.location.host]
  5836. * Override the host address to probe. By default the current host as seen
  5837. * in the address bar is probed.
  5838. *
  5839. * @returns {Promise&lt;Event>}
  5840. * Returns a promise resolving to a `load` event in case the device is
  5841. * reachable or rejecting with an `error` event in case it is not reachable
  5842. * or rejecting with `null` when the connectivity check timed out.
  5843. */
  5844. pingDevice: function(proto, ipaddr) {
  5845. var target = '%s://%s%s?%s'.format(proto || 'http', ipaddr || window.location.host, L.resource('icons/loading.gif'), Math.random());
  5846. return new Promise(function(resolveFn, rejectFn) {
  5847. var img = new Image();
  5848. img.onload = resolveFn;
  5849. img.onerror = rejectFn;
  5850. window.setTimeout(rejectFn, 1000);
  5851. img.src = target;
  5852. });
  5853. },
  5854. /**
  5855. * Wait for device to come back online and reconnect to it.
  5856. *
  5857. * Poll each given hostname or IP address and navigate to it as soon as
  5858. * one of the addresses becomes reachable.
  5859. *
  5860. * @param {...string} [hosts=[window.location.host]]
  5861. * The list of IP addresses and host names to check for reachability.
  5862. * If omitted, the current value of `window.location.host` is used by
  5863. * default.
  5864. */
  5865. awaitReconnect: function(/* ... */) {
  5866. var ipaddrs = arguments.length ? arguments : [ window.location.host ];
  5867. window.setTimeout(L.bind(function() {
  5868. poll.add(L.bind(function() {
  5869. var tasks = [], reachable = false;
  5870. for (var i = 0; i &lt; 2; i++)
  5871. for (var j = 0; j &lt; ipaddrs.length; j++)
  5872. tasks.push(this.pingDevice(i ? 'https' : 'http', ipaddrs[j])
  5873. .then(function(ev) { reachable = ev.target.src.replace(/^(https?:\/\/[^\/]+).*$/, '$1/') }, function() {}));
  5874. return Promise.all(tasks).then(function() {
  5875. if (reachable) {
  5876. poll.stop();
  5877. window.location = reachable;
  5878. }
  5879. });
  5880. }, this));
  5881. }, this), 5000);
  5882. },
  5883. /**
  5884. * @class
  5885. * @memberof LuCI.ui
  5886. * @hideconstructor
  5887. * @classdesc
  5888. *
  5889. * The `changes` class encapsulates logic for visualizing, applying,
  5890. * confirming and reverting staged UCI changesets.
  5891. *
  5892. * This class is automatically instantiated as part of `LuCI.ui`. To use it
  5893. * in views, use `'require ui'` and refer to `ui.changes`. To import it in
  5894. * external JavaScript, use `L.require("ui").then(...)` and access the
  5895. * `changes` property of the class instance value.
  5896. */
  5897. changes: baseclass.singleton(/* @lends LuCI.ui.changes.prototype */ {
  5898. init: function() {
  5899. if (!L.env.sessionid)
  5900. return;
  5901. return uci.changes().then(L.bind(this.renderChangeIndicator, this));
  5902. },
  5903. /**
  5904. * Set the change count indicator.
  5905. *
  5906. * This function updates or hides the UCI change count indicator,
  5907. * depending on the passed change count. When the count is greater
  5908. * than 0, the change indicator is displayed or updated, otherwise it
  5909. * is removed.
  5910. *
  5911. * @instance
  5912. * @memberof LuCI.ui.changes
  5913. * @param {number} n
  5914. * The number of changes to indicate.
  5915. */
  5916. setIndicator: function(n) {
  5917. if (n > 0) {
  5918. UI.prototype.showIndicator('uci-changes',
  5919. '%s: %d'.format(_('Unsaved Changes'), n),
  5920. L.bind(this.displayChanges, this));
  5921. }
  5922. else {
  5923. UI.prototype.hideIndicator('uci-changes');
  5924. }
  5925. },
  5926. /**
  5927. * Update the change count indicator.
  5928. *
  5929. * This function updates the UCI change count indicator from the given
  5930. * UCI changeset structure.
  5931. *
  5932. * @instance
  5933. * @memberof LuCI.ui.changes
  5934. * @param {Object&lt;string, Array&lt;LuCI.uci.ChangeRecord>>} changes
  5935. * The UCI changeset to count.
  5936. */
  5937. renderChangeIndicator: function(changes) {
  5938. var n_changes = 0;
  5939. for (var config in changes)
  5940. if (changes.hasOwnProperty(config))
  5941. n_changes += changes[config].length;
  5942. this.changes = changes;
  5943. this.setIndicator(n_changes);
  5944. },
  5945. /** @private */
  5946. changeTemplates: {
  5947. 'add-3': '&lt;ins>uci add %0 &lt;strong>%3&lt;/strong> # =%2&lt;/ins>',
  5948. 'set-3': '&lt;ins>uci set %0.&lt;strong>%2&lt;/strong>=%3&lt;/ins>',
  5949. 'set-4': '&lt;var>&lt;ins>uci set %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/ins>&lt;/var>',
  5950. 'remove-2': '&lt;del>uci del %0.&lt;strong>%2&lt;/strong>&lt;/del>',
  5951. 'remove-3': '&lt;var>&lt;del>uci del %0.%2.&lt;strong>%3&lt;/strong>&lt;/del>&lt;/var>',
  5952. 'order-3': '&lt;var>uci reorder %0.%2=&lt;strong>%3&lt;/strong>&lt;/var>',
  5953. 'list-add-4': '&lt;var>&lt;ins>uci add_list %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/ins>&lt;/var>',
  5954. 'list-del-4': '&lt;var>&lt;del>uci del_list %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/del>&lt;/var>',
  5955. 'rename-3': '&lt;var>uci rename %0.%2=&lt;strong>%3&lt;/strong>&lt;/var>',
  5956. 'rename-4': '&lt;var>uci rename %0.%2.%3=&lt;strong>%4&lt;/strong>&lt;/var>'
  5957. },
  5958. /**
  5959. * Display the current changelog.
  5960. *
  5961. * Open a modal dialog visualizing the currently staged UCI changes
  5962. * and offer options to revert or apply the shown changes.
  5963. *
  5964. * @instance
  5965. * @memberof LuCI.ui.changes
  5966. */
  5967. displayChanges: function() {
  5968. var list = E('div', { 'class': 'uci-change-list' }),
  5969. dlg = UI.prototype.showModal(_('Configuration') + ' / ' + _('Changes'), [
  5970. E('div', { 'class': 'cbi-section' }, [
  5971. E('strong', _('Legend:')),
  5972. E('div', { 'class': 'uci-change-legend' }, [
  5973. E('div', { 'class': 'uci-change-legend-label' }, [
  5974. E('ins', '&amp;#160;'), ' ', _('Section added') ]),
  5975. E('div', { 'class': 'uci-change-legend-label' }, [
  5976. E('del', '&amp;#160;'), ' ', _('Section removed') ]),
  5977. E('div', { 'class': 'uci-change-legend-label' }, [
  5978. E('var', {}, E('ins', '&amp;#160;')), ' ', _('Option changed') ]),
  5979. E('div', { 'class': 'uci-change-legend-label' }, [
  5980. E('var', {}, E('del', '&amp;#160;')), ' ', _('Option removed') ])]),
  5981. E('br'),
  5982. list,
  5983. ]),
  5984. E('div', { 'class': 'button-row' }, [
  5985. E('button', {
  5986. 'class': 'btn cbi-button',
  5987. 'click': UI.prototype.hideModal
  5988. }, [ _('Close') ]), ' ',
  5989. new UIComboButton('0', {
  5990. 0: [ _('Save &amp; Apply') ],
  5991. 1: [ _('Apply unchecked') ]
  5992. }, {
  5993. classes: {
  5994. 0: 'btn cbi-button cbi-button-positive important',
  5995. 1: 'btn cbi-button cbi-button-negative important'
  5996. },
  5997. click: L.bind(function(ev, mode) { this.apply(mode == '0') }, this)
  5998. }).render(), ' ',
  5999. E('button', {
  6000. 'class': 'btn cbi-button cbi-button-reset',
  6001. 'click': L.bind(this.revert, this)
  6002. }, [ _('Revert') ])
  6003. ])
  6004. ]);
  6005. for (var config in this.changes) {
  6006. if (!this.changes.hasOwnProperty(config))
  6007. continue;
  6008. list.appendChild(E('h5', '# /etc/config/%s'.format(config)));
  6009. for (var i = 0, added = null; i &lt; this.changes[config].length; i++) {
  6010. var chg = this.changes[config][i],
  6011. tpl = this.changeTemplates['%s-%d'.format(chg[0], chg.length)];
  6012. list.appendChild(E(tpl.replace(/%([01234])/g, function(m0, m1) {
  6013. switch (+m1) {
  6014. case 0:
  6015. return config;
  6016. case 2:
  6017. if (added != null &amp;&amp; chg[1] == added[0])
  6018. return '@' + added[1] + '[-1]';
  6019. else
  6020. return chg[1];
  6021. case 4:
  6022. return "'%h'".format(chg[3].replace(/'/g, "'\"'\"'"));
  6023. default:
  6024. return chg[m1-1];
  6025. }
  6026. })));
  6027. if (chg[0] == 'add')
  6028. added = [ chg[1], chg[2] ];
  6029. }
  6030. }
  6031. list.appendChild(E('br'));
  6032. dlg.classList.add('uci-dialog');
  6033. },
  6034. /** @private */
  6035. displayStatus: function(type, content) {
  6036. if (type) {
  6037. var message = UI.prototype.showModal('', '');
  6038. message.classList.add('alert-message');
  6039. DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
  6040. if (content)
  6041. dom.content(message, content);
  6042. if (!this.was_polling) {
  6043. this.was_polling = request.poll.active();
  6044. request.poll.stop();
  6045. }
  6046. }
  6047. else {
  6048. UI.prototype.hideModal();
  6049. if (this.was_polling)
  6050. request.poll.start();
  6051. }
  6052. },
  6053. /** @private */
  6054. checkConnectivityAffected: function() {
  6055. return L.resolveDefault(fs.exec_direct('/usr/libexec/luci-peeraddr', null, 'json')).then(L.bind(function(info) {
  6056. if (L.isObject(info) &amp;&amp; Array.isArray(info.inbound_interfaces)) {
  6057. for (var i = 0; i &lt; info.inbound_interfaces.length; i++) {
  6058. var iif = info.inbound_interfaces[i];
  6059. for (var j = 0; this.changes &amp;&amp; this.changes.network &amp;&amp; j &lt; this.changes.network.length; j++) {
  6060. var chg = this.changes.network[j];
  6061. if (chg[0] == 'set' &amp;&amp; chg[1] == iif &amp;&amp;
  6062. ((chg[2] == 'disabled' &amp;&amp; chg[3] == '1') || chg[2] == 'proto' || chg[2] == 'ipaddr' || chg[2] == 'netmask'))
  6063. return iif;
  6064. }
  6065. }
  6066. }
  6067. return null;
  6068. }, this));
  6069. },
  6070. /** @private */
  6071. rollback: function(checked) {
  6072. if (checked) {
  6073. this.displayStatus('warning spinning',
  6074. E('p', _('Failed to confirm apply within %ds, waiting for rollback…')
  6075. .format(L.env.apply_rollback)));
  6076. var call = function(r) {
  6077. if (r.status === 204) {
  6078. UI.prototype.changes.displayStatus('warning', [
  6079. E('h4', _('Configuration changes have been rolled back!')),
  6080. 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)),
  6081. E('div', { 'class': 'right' }, [
  6082. E('button', {
  6083. 'class': 'btn',
  6084. 'click': L.bind(UI.prototype.changes.displayStatus, UI.prototype.changes, false)
  6085. }, [ _('Dismiss') ]), ' ',
  6086. E('button', {
  6087. 'class': 'btn cbi-button-action important',
  6088. 'click': L.bind(UI.prototype.changes.revert, UI.prototype.changes)
  6089. }, [ _('Revert changes') ]), ' ',
  6090. E('button', {
  6091. 'class': 'btn cbi-button-negative important',
  6092. 'click': L.bind(UI.prototype.changes.apply, UI.prototype.changes, false)
  6093. }, [ _('Apply unchecked') ])
  6094. ])
  6095. ]);
  6096. return;
  6097. }
  6098. var delay = isNaN(r.duration) ? 0 : Math.max(1000 - r.duration, 0);
  6099. window.setTimeout(function() {
  6100. request.request(L.url('admin/uci/confirm'), {
  6101. method: 'post',
  6102. timeout: L.env.apply_timeout * 1000,
  6103. query: { sid: L.env.sessionid, token: L.env.token }
  6104. }).then(call, call.bind(null, { status: 0, duration: 0 }));
  6105. }, delay);
  6106. };
  6107. call({ status: 0 });
  6108. }
  6109. else {
  6110. this.displayStatus('warning', [
  6111. E('h4', _('Device unreachable!')),
  6112. 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.'))
  6113. ]);
  6114. }
  6115. },
  6116. /** @private */
  6117. confirm: function(checked, deadline, override_token) {
  6118. var tt;
  6119. var ts = Date.now();
  6120. this.displayStatus('notice');
  6121. if (override_token)
  6122. this.confirm_auth = { token: override_token };
  6123. var call = function(r) {
  6124. if (Date.now() >= deadline) {
  6125. window.clearTimeout(tt);
  6126. UI.prototype.changes.rollback(checked);
  6127. return;
  6128. }
  6129. else if (r.status === 200 || r.status === 204) {
  6130. document.dispatchEvent(new CustomEvent('uci-applied'));
  6131. UI.prototype.changes.setIndicator(0);
  6132. UI.prototype.changes.displayStatus('notice',
  6133. E('p', _('Configuration changes applied.')));
  6134. window.clearTimeout(tt);
  6135. window.setTimeout(function() {
  6136. //UI.prototype.changes.displayStatus(false);
  6137. window.location = window.location.href.split('#')[0];
  6138. }, L.env.apply_display * 1000);
  6139. return;
  6140. }
  6141. var delay = isNaN(r.duration) ? 0 : Math.max(1000 - r.duration, 0);
  6142. window.setTimeout(function() {
  6143. request.request(L.url('admin/uci/confirm'), {
  6144. method: 'post',
  6145. timeout: L.env.apply_timeout * 1000,
  6146. query: UI.prototype.changes.confirm_auth
  6147. }).then(call, call.bind(null, { status: 0, duration: 0 }));
  6148. }, delay);
  6149. };
  6150. var tick = function() {
  6151. var now = Date.now();
  6152. UI.prototype.changes.displayStatus('notice spinning',
  6153. E('p', _('Applying configuration changes… %ds')
  6154. .format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0))));
  6155. if (now >= deadline)
  6156. return;
  6157. tt = window.setTimeout(tick, 1000 - (now - ts));
  6158. ts = now;
  6159. };
  6160. tick();
  6161. /* wait a few seconds for the settings to become effective */
  6162. window.setTimeout(call.bind(null, { status: 0 }), L.env.apply_holdoff * 1000);
  6163. },
  6164. /**
  6165. * Apply the staged configuration changes.
  6166. *
  6167. * Start applying staged configuration changes and open a modal dialog
  6168. * with a progress indication to prevent interaction with the view
  6169. * during the apply process. The modal dialog will be automatically
  6170. * closed and the current view reloaded once the apply process is
  6171. * complete.
  6172. *
  6173. * @instance
  6174. * @memberof LuCI.ui.changes
  6175. * @param {boolean} [checked=false]
  6176. * Whether to perform a checked (`true`) configuration apply or an
  6177. * unchecked (`false`) one.
  6178. * In case of a checked apply, the configuration changes must be
  6179. * confirmed within a specific time interval, otherwise the device
  6180. * will begin to roll back the changes in order to restore the previous
  6181. * settings.
  6182. */
  6183. apply: function(checked) {
  6184. this.displayStatus('notice spinning',
  6185. E('p', _('Starting configuration apply…')));
  6186. (new Promise(function(resolveFn, rejectFn) {
  6187. if (!checked)
  6188. return resolveFn(false);
  6189. UI.prototype.changes.checkConnectivityAffected().then(function(affected) {
  6190. if (!affected)
  6191. return resolveFn(true);
  6192. UI.prototype.changes.displayStatus('warning', [
  6193. E('h4', _('Connectivity change')),
  6194. E('p', _('Changes have been made to the existing connection via "%h". This could inhibit access to this device. Any IP change requires &lt;strong>connecting to the new IP&lt;/strong> within %d seconds to retain the changes.').format(affected, L.env.apply_rollback)),
  6195. E('div', { 'class': 'button-row' }, [
  6196. E('button', {
  6197. 'class': 'btn cbi-button',
  6198. 'click': rejectFn,
  6199. }, [ _('Cancel') ]), ' ',
  6200. E('button', {
  6201. 'class': 'btn cbi-button-action important',
  6202. 'click': resolveFn.bind(null, true)
  6203. }, [ _('Apply, reverting in case of connectivity loss') ]), ' ',
  6204. E('button', {
  6205. 'class': 'btn cbi-button-negative important',
  6206. 'click': resolveFn.bind(null, false)
  6207. }, [ _('Apply unchecked') ])
  6208. ])
  6209. ]);
  6210. });
  6211. })).then(function(checked) {
  6212. request.request(L.url('admin/uci', checked ? 'apply_rollback' : 'apply_unchecked'), {
  6213. method: 'post',
  6214. query: { sid: L.env.sessionid, token: L.env.token }
  6215. }).then(function(r) {
  6216. if (r.status === (checked ? 200 : 204)) {
  6217. var tok = null; try { tok = r.json(); } catch(e) {}
  6218. if (checked &amp;&amp; tok !== null &amp;&amp; typeof(tok) === 'object' &amp;&amp; typeof(tok.token) === 'string')
  6219. UI.prototype.changes.confirm_auth = tok;
  6220. UI.prototype.changes.confirm(checked, Date.now() + L.env.apply_rollback * 1000);
  6221. }
  6222. else if (checked &amp;&amp; r.status === 204) {
  6223. UI.prototype.changes.displayStatus('notice',
  6224. E('p', _('There are no changes to apply')));
  6225. window.setTimeout(function() {
  6226. UI.prototype.changes.displayStatus(false);
  6227. }, L.env.apply_display * 1000);
  6228. }
  6229. else {
  6230. UI.prototype.changes.displayStatus('warning',
  6231. E('p', _('Apply request failed with status &lt;code>%h&lt;/code>')
  6232. .format(r.responseText || r.statusText || r.status)));
  6233. window.setTimeout(function() {
  6234. UI.prototype.changes.displayStatus(false);
  6235. }, L.env.apply_display * 1000);
  6236. }
  6237. });
  6238. }, this.displayStatus.bind(this, false));
  6239. },
  6240. /**
  6241. * Revert the staged configuration changes.
  6242. *
  6243. * Start reverting staged configuration changes and open a modal dialog
  6244. * with a progress indication to prevent interaction with the view
  6245. * during the revert process. The modal dialog will be automatically
  6246. * closed and the current view reloaded once the revert process is
  6247. * complete.
  6248. *
  6249. * @instance
  6250. * @memberof LuCI.ui.changes
  6251. */
  6252. revert: function() {
  6253. this.displayStatus('notice spinning',
  6254. E('p', _('Reverting configuration…')));
  6255. request.request(L.url('admin/uci/revert'), {
  6256. method: 'post',
  6257. query: { sid: L.env.sessionid, token: L.env.token }
  6258. }).then(function(r) {
  6259. if (r.status === 200) {
  6260. document.dispatchEvent(new CustomEvent('uci-reverted'));
  6261. UI.prototype.changes.setIndicator(0);
  6262. UI.prototype.changes.displayStatus('notice',
  6263. E('p', _('Changes have been reverted.')));
  6264. window.setTimeout(function() {
  6265. //UI.prototype.changes.displayStatus(false);
  6266. window.location = window.location.href.split('#')[0];
  6267. }, L.env.apply_display * 1000);
  6268. }
  6269. else {
  6270. UI.prototype.changes.displayStatus('warning',
  6271. E('p', _('Revert request failed with status &lt;code>%h&lt;/code>')
  6272. .format(r.statusText || r.status)));
  6273. window.setTimeout(function() {
  6274. UI.prototype.changes.displayStatus(false);
  6275. }, L.env.apply_display * 1000);
  6276. }
  6277. });
  6278. }
  6279. }),
  6280. /**
  6281. * Add validation constraints to an input element.
  6282. *
  6283. * Compile the given type expression and optional validator function into
  6284. * a validation function and bind it to the specified input element events.
  6285. *
  6286. * @param {Node} field
  6287. * The DOM input element node to bind the validation constraints to.
  6288. *
  6289. * @param {string} type
  6290. * The datatype specification to describe validation constraints.
  6291. * Refer to the `LuCI.validation` class documentation for details.
  6292. *
  6293. * @param {boolean} [optional=false]
  6294. * Specifies whether empty values are allowed (`true`) or not (`false`).
  6295. * If an input element is not marked optional it must not be empty,
  6296. * otherwise it will be marked as invalid.
  6297. *
  6298. * @param {function} [vfunc]
  6299. * Specifies a custom validation function which is invoked after the
  6300. * other validation constraints are applied. The validation must return
  6301. * `true` to accept the passed value. Any other return type is converted
  6302. * to a string and treated as validation error message.
  6303. *
  6304. * @param {...string} [events=blur, keyup]
  6305. * The list of events to bind. Each received event will trigger a field
  6306. * validation. If omitted, the `keyup` and `blur` events are bound by
  6307. * default.
  6308. *
  6309. * @returns {function}
  6310. * Returns the compiled validator function which can be used to manually
  6311. * trigger field validation or to bind it to further events.
  6312. *
  6313. * @see LuCI.validation
  6314. */
  6315. addValidator: function(field, type, optional, vfunc /*, ... */) {
  6316. if (type == null)
  6317. return;
  6318. var events = this.varargs(arguments, 3);
  6319. if (events.length == 0)
  6320. events.push('blur', 'keyup');
  6321. try {
  6322. var cbiValidator = validation.create(field, type, optional, vfunc),
  6323. validatorFn = cbiValidator.validate.bind(cbiValidator);
  6324. for (var i = 0; i &lt; events.length; i++)
  6325. field.addEventListener(events[i], validatorFn);
  6326. validatorFn();
  6327. return validatorFn;
  6328. }
  6329. catch (e) { }
  6330. },
  6331. /**
  6332. * Create a pre-bound event handler function.
  6333. *
  6334. * Generate and bind a function suitable for use in event handlers. The
  6335. * generated function automatically disables the event source element
  6336. * and adds an active indication to it by adding appropriate CSS classes.
  6337. *
  6338. * It will also await any promises returned by the wrapped function and
  6339. * re-enable the source element after the promises ran to completion.
  6340. *
  6341. * @param {*} ctx
  6342. * The `this` context to use for the wrapped function.
  6343. *
  6344. * @param {function|string} fn
  6345. * Specifies the function to wrap. In case of a function value, the
  6346. * function is used as-is. If a string is specified instead, it is looked
  6347. * up in `ctx` to obtain the function to wrap. In both cases the bound
  6348. * function will be invoked with `ctx` as `this` context
  6349. *
  6350. * @param {...*} extra_args
  6351. * Any further parameter as passed as-is to the bound event handler
  6352. * function in the same order as passed to `createHandlerFn()`.
  6353. *
  6354. * @returns {function|null}
  6355. * Returns the pre-bound handler function which is suitable to be passed
  6356. * to `addEventListener()`. Returns `null` if the given `fn` argument is
  6357. * a string which could not be found in `ctx` or if `ctx[fn]` is not a
  6358. * valid function value.
  6359. */
  6360. createHandlerFn: function(ctx, fn /*, ... */) {
  6361. if (typeof(fn) == 'string')
  6362. fn = ctx[fn];
  6363. if (typeof(fn) != 'function')
  6364. return null;
  6365. var arg_offset = arguments.length - 2;
  6366. return Function.prototype.bind.apply(function() {
  6367. var t = arguments[arg_offset].currentTarget;
  6368. t.classList.add('spinning');
  6369. t.disabled = true;
  6370. if (t.blur)
  6371. t.blur();
  6372. Promise.resolve(fn.apply(ctx, arguments)).finally(function() {
  6373. t.classList.remove('spinning');
  6374. t.disabled = false;
  6375. });
  6376. }, this.varargs(arguments, 2, ctx));
  6377. },
  6378. /**
  6379. * Load specified view class path and set it up.
  6380. *
  6381. * Transforms the given view path into a class name, requires it
  6382. * using [LuCI.require()]{@link LuCI#require} and asserts that the
  6383. * resulting class instance is a descendant of
  6384. * [LuCI.view]{@link LuCI.view}.
  6385. *
  6386. * By instantiating the view class, its corresponding contents are
  6387. * rendered and included into the view area. Any runtime errors are
  6388. * caught and rendered using [LuCI.error()]{@link LuCI#error}.
  6389. *
  6390. * @param {string} path
  6391. * The view path to render.
  6392. *
  6393. * @returns {Promise&lt;LuCI.view>}
  6394. * Returns a promise resolving to the loaded view instance.
  6395. */
  6396. instantiateView: function(path) {
  6397. var className = 'view.%s'.format(path.replace(/\//g, '.'));
  6398. return L.require(className).then(function(view) {
  6399. if (!(view instanceof View))
  6400. throw new TypeError('Loaded class %s is not a descendant of View'.format(className));
  6401. return view;
  6402. }).catch(function(err) {
  6403. dom.content(document.querySelector('#view'), null);
  6404. L.error(err);
  6405. });
  6406. },
  6407. menu: UIMenu,
  6408. Table: UITable,
  6409. AbstractElement: UIElement,
  6410. /* Widgets */
  6411. Textfield: UITextfield,
  6412. Textarea: UITextarea,
  6413. Checkbox: UICheckbox,
  6414. Select: UISelect,
  6415. Dropdown: UIDropdown,
  6416. DynamicList: UIDynamicList,
  6417. Combobox: UICombobox,
  6418. ComboButton: UIComboButton,
  6419. Hiddenfield: UIHiddenfield,
  6420. FileUpload: UIFileUpload
  6421. });
  6422. return UI;
  6423. </code></pre>
  6424. </article>
  6425. </section>
  6426. <footer>
  6427. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a> on Wed Nov 27 2024 20:43:36 GMT+0000 (Coordinated Universal Time)
  6428. </footer>
  6429. </div>
  6430. </div>
  6431. <script>prettyPrint();</script>
  6432. <script src="scripts/jaguar.js"></script>
  6433. </body>
  6434. </html>