ux-all-debug.js 188 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251
  1. /*!
  2. * Ext JS Library 3.0.0
  3. * Copyright(c) 2006-2009 Ext JS, LLC
  4. * licensing@extjs.com
  5. * http://www.extjs.com/license
  6. */
  7. Ext.ns('Ext.ux.grid');
  8. /**
  9. * @class Ext.ux.grid.BufferView
  10. * @extends Ext.grid.GridView
  11. * A custom GridView which renders rows on an as-needed basis.
  12. */
  13. Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
  14. /**
  15. * @cfg {Number} rowHeight
  16. * The height of a row in the grid.
  17. */
  18. rowHeight: 19,
  19. /**
  20. * @cfg {Number} borderHeight
  21. * The combined height of border-top and border-bottom of a row.
  22. */
  23. borderHeight: 2,
  24. /**
  25. * @cfg {Boolean/Number} scrollDelay
  26. * The number of milliseconds before rendering rows out of the visible
  27. * viewing area. Defaults to 100. Rows will render immediately with a config
  28. * of false.
  29. */
  30. scrollDelay: 100,
  31. /**
  32. * @cfg {Number} cacheSize
  33. * The number of rows to look forward and backwards from the currently viewable
  34. * area. The cache applies only to rows that have been rendered already.
  35. */
  36. cacheSize: 20,
  37. /**
  38. * @cfg {Number} cleanDelay
  39. * The number of milliseconds to buffer cleaning of extra rows not in the
  40. * cache.
  41. */
  42. cleanDelay: 500,
  43. initTemplates : function(){
  44. Ext.ux.grid.BufferView.superclass.initTemplates.call(this);
  45. var ts = this.templates;
  46. // empty div to act as a place holder for a row
  47. ts.rowHolder = new Ext.Template(
  48. '<div class="x-grid3-row {alt}" style="{tstyle}"></div>'
  49. );
  50. ts.rowHolder.disableFormats = true;
  51. ts.rowHolder.compile();
  52. ts.rowBody = new Ext.Template(
  53. '<table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
  54. '<tbody><tr>{cells}</tr>',
  55. (this.enableRowBody ? '<tr class="x-grid3-row-body-tr" style="{bodyStyle}"><td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on"><div class="x-grid3-row-body">{body}</div></td></tr>' : ''),
  56. '</tbody></table>'
  57. );
  58. ts.rowBody.disableFormats = true;
  59. ts.rowBody.compile();
  60. },
  61. getStyleRowHeight : function(){
  62. return Ext.isBorderBox ? (this.rowHeight + this.borderHeight) : this.rowHeight;
  63. },
  64. getCalculatedRowHeight : function(){
  65. return this.rowHeight + this.borderHeight;
  66. },
  67. getVisibleRowCount : function(){
  68. var rh = this.getCalculatedRowHeight();
  69. var visibleHeight = this.scroller.dom.clientHeight;
  70. return (visibleHeight < 1) ? 0 : Math.ceil(visibleHeight / rh);
  71. },
  72. getVisibleRows: function(){
  73. var count = this.getVisibleRowCount();
  74. var sc = this.scroller.dom.scrollTop;
  75. var start = (sc == 0 ? 0 : Math.floor(sc/this.getCalculatedRowHeight())-1);
  76. return {
  77. first: Math.max(start, 0),
  78. last: Math.min(start + count + 2, this.ds.getCount()-1)
  79. };
  80. },
  81. doRender : function(cs, rs, ds, startRow, colCount, stripe, onlyBody){
  82. var ts = this.templates, ct = ts.cell, rt = ts.row, rb = ts.rowBody, last = colCount-1;
  83. var rh = this.getStyleRowHeight();
  84. var vr = this.getVisibleRows();
  85. var tstyle = 'width:'+this.getTotalWidth()+';height:'+rh+'px;';
  86. // buffers
  87. var buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r;
  88. for (var j = 0, len = rs.length; j < len; j++) {
  89. r = rs[j]; cb = [];
  90. var rowIndex = (j+startRow);
  91. var visible = rowIndex >= vr.first && rowIndex <= vr.last;
  92. if (visible) {
  93. for (var i = 0; i < colCount; i++) {
  94. c = cs[i];
  95. p.id = c.id;
  96. p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
  97. p.attr = p.cellAttr = "";
  98. p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
  99. p.style = c.style;
  100. if (p.value == undefined || p.value === "") {
  101. p.value = "&#160;";
  102. }
  103. if (r.dirty && typeof r.modified[c.name] !== 'undefined') {
  104. p.css += ' x-grid3-dirty-cell';
  105. }
  106. cb[cb.length] = ct.apply(p);
  107. }
  108. }
  109. var alt = [];
  110. if(stripe && ((rowIndex+1) % 2 == 0)){
  111. alt[0] = "x-grid3-row-alt";
  112. }
  113. if(r.dirty){
  114. alt[1] = " x-grid3-dirty-row";
  115. }
  116. rp.cols = colCount;
  117. if(this.getRowClass){
  118. alt[2] = this.getRowClass(r, rowIndex, rp, ds);
  119. }
  120. rp.alt = alt.join(" ");
  121. rp.cells = cb.join("");
  122. buf[buf.length] = !visible ? ts.rowHolder.apply(rp) : (onlyBody ? rb.apply(rp) : rt.apply(rp));
  123. }
  124. return buf.join("");
  125. },
  126. isRowRendered: function(index){
  127. var row = this.getRow(index);
  128. return row && row.childNodes.length > 0;
  129. },
  130. syncScroll: function(){
  131. Ext.ux.grid.BufferView.superclass.syncScroll.apply(this, arguments);
  132. this.update();
  133. },
  134. // a (optionally) buffered method to update contents of gridview
  135. update: function(){
  136. if (this.scrollDelay) {
  137. if (!this.renderTask) {
  138. this.renderTask = new Ext.util.DelayedTask(this.doUpdate, this);
  139. }
  140. this.renderTask.delay(this.scrollDelay);
  141. }else{
  142. this.doUpdate();
  143. }
  144. },
  145. doUpdate: function(){
  146. if (this.getVisibleRowCount() > 0) {
  147. var g = this.grid, cm = g.colModel, ds = g.store;
  148. var cs = this.getColumnData();
  149. var vr = this.getVisibleRows();
  150. for (var i = vr.first; i <= vr.last; i++) {
  151. // if row is NOT rendered and is visible, render it
  152. if(!this.isRowRendered(i)){
  153. var html = this.doRender(cs, [ds.getAt(i)], ds, i, cm.getColumnCount(), g.stripeRows, true);
  154. this.getRow(i).innerHTML = html;
  155. }
  156. }
  157. this.clean();
  158. }
  159. },
  160. // a buffered method to clean rows
  161. clean : function(){
  162. if(!this.cleanTask){
  163. this.cleanTask = new Ext.util.DelayedTask(this.doClean, this);
  164. }
  165. this.cleanTask.delay(this.cleanDelay);
  166. },
  167. doClean: function(){
  168. if (this.getVisibleRowCount() > 0) {
  169. var vr = this.getVisibleRows();
  170. vr.first -= this.cacheSize;
  171. vr.last += this.cacheSize;
  172. var i = 0, rows = this.getRows();
  173. // if first is less than 0, all rows have been rendered
  174. // so lets clean the end...
  175. if(vr.first <= 0){
  176. i = vr.last + 1;
  177. }
  178. for(var len = this.ds.getCount(); i < len; i++){
  179. // if current row is outside of first and last and
  180. // has content, update the innerHTML to nothing
  181. if ((i < vr.first || i > vr.last) && rows[i].innerHTML) {
  182. rows[i].innerHTML = '';
  183. }
  184. }
  185. }
  186. },
  187. layout: function(){
  188. Ext.ux.grid.BufferView.superclass.layout.call(this);
  189. this.update();
  190. }
  191. });
  192. // We are adding these custom layouts to a namespace that does not
  193. // exist by default in Ext, so we have to add the namespace first:
  194. Ext.ns('Ext.ux.layout');
  195. /**
  196. * @class Ext.ux.layout.CenterLayout
  197. * @extends Ext.layout.FitLayout
  198. * <p>This is a very simple layout style used to center contents within a container. This layout works within
  199. * nested containers and can also be used as expected as a Viewport layout to center the page layout.</p>
  200. * <p>As a subclass of FitLayout, CenterLayout expects to have a single child panel of the container that uses
  201. * the layout. The layout does not require any config options, although the child panel contained within the
  202. * layout must provide a fixed or percentage width. The child panel's height will fit to the container by
  203. * default, but you can specify <tt>autoHeight:true</tt> to allow it to autosize based on its content height.
  204. * Example usage:</p>
  205. * <pre><code>
  206. // The content panel is centered in the container
  207. var p = new Ext.Panel({
  208. title: 'Center Layout',
  209. layout: 'ux.center',
  210. items: [{
  211. title: 'Centered Content',
  212. width: '75%',
  213. html: 'Some content'
  214. }]
  215. });
  216. // If you leave the title blank and specify no border
  217. // you'll create a non-visual, structural panel just
  218. // for centering the contents in the main container.
  219. var p = new Ext.Panel({
  220. layout: 'ux.center',
  221. border: false,
  222. items: [{
  223. title: 'Centered Content',
  224. width: 300,
  225. autoHeight: true,
  226. html: 'Some content'
  227. }]
  228. });
  229. </code></pre>
  230. */
  231. Ext.ux.layout.CenterLayout = Ext.extend(Ext.layout.FitLayout, {
  232. // private
  233. setItemSize : function(item, size){
  234. this.container.addClass('ux-layout-center');
  235. item.addClass('ux-layout-center-item');
  236. if(item && size.height > 0){
  237. if(item.width){
  238. size.width = item.width;
  239. }
  240. item.setSize(size);
  241. }
  242. }
  243. });
  244. Ext.Container.LAYOUTS['ux.center'] = Ext.ux.layout.CenterLayout;
  245. Ext.ns('Ext.ux.grid');
  246. /**
  247. * @class Ext.ux.grid.CheckColumn
  248. * @extends Object
  249. * GridPanel plugin to add a column with check boxes to a grid.
  250. * <p>Example usage:</p>
  251. * <pre><code>
  252. // create the column
  253. var checkColumn = new Ext.grid.CheckColumn({
  254. header: 'Indoor?',
  255. dataIndex: 'indoor',
  256. id: 'check',
  257. width: 55
  258. });
  259. // add the column to the column model
  260. var cm = new Ext.grid.ColumnModel([{
  261. header: 'Foo',
  262. ...
  263. },
  264. checkColumn
  265. ]);
  266. // create the grid
  267. var grid = new Ext.grid.EditorGridPanel({
  268. ...
  269. cm: cm,
  270. plugins: [checkColumn], // include plugin
  271. ...
  272. });
  273. * </code></pre>
  274. * In addition to storing a Boolean value within the record data, this
  275. * class toggles a css class between <tt>'x-grid3-check-col'</tt> and
  276. * <tt>'x-grid3-check-col-on'</tt> to alter the background image used for
  277. * a column.
  278. */
  279. Ext.ux.grid.CheckColumn = function(config){
  280. Ext.apply(this, config);
  281. if(!this.id){
  282. this.id = Ext.id();
  283. }
  284. this.renderer = this.renderer.createDelegate(this);
  285. };
  286. Ext.ux.grid.CheckColumn.prototype ={
  287. init : function(grid){
  288. this.grid = grid;
  289. this.grid.on('render', function(){
  290. var view = this.grid.getView();
  291. view.mainBody.on('mousedown', this.onMouseDown, this);
  292. }, this);
  293. },
  294. onMouseDown : function(e, t){
  295. if(t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
  296. e.stopEvent();
  297. var index = this.grid.getView().findRowIndex(t);
  298. var record = this.grid.store.getAt(index);
  299. record.set(this.dataIndex, !record.data[this.dataIndex]);
  300. }
  301. },
  302. renderer : function(v, p, record){
  303. p.css += ' x-grid3-check-col-td';
  304. return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'">&#160;</div>';
  305. }
  306. };
  307. // register ptype
  308. Ext.preg('checkcolumn', Ext.ux.grid.CheckColumn);
  309. // backwards compat
  310. Ext.grid.CheckColumn = Ext.ux.grid.CheckColumn;Ext.ns('Ext.ux.tree');
  311. /**
  312. * @class Ext.ux.tree.ColumnTree
  313. * @extends Ext.tree.TreePanel
  314. *
  315. * @xtype columntree
  316. */
  317. Ext.ux.tree.ColumnTree = Ext.extend(Ext.tree.TreePanel, {
  318. lines : false,
  319. borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
  320. cls : 'x-column-tree',
  321. onRender : function(){
  322. Ext.tree.ColumnTree.superclass.onRender.apply(this, arguments);
  323. this.headers = this.header.createChild({cls:'x-tree-headers'});
  324. var cols = this.columns, c;
  325. var totalWidth = 0;
  326. var scrollOffset = 19; // similar to Ext.grid.GridView default
  327. for(var i = 0, len = cols.length; i < len; i++){
  328. c = cols[i];
  329. totalWidth += c.width;
  330. this.headers.createChild({
  331. cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
  332. cn: {
  333. cls:'x-tree-hd-text',
  334. html: c.header
  335. },
  336. style:'width:'+(c.width-this.borderWidth)+'px;'
  337. });
  338. }
  339. this.headers.createChild({cls:'x-clear'});
  340. // prevent floats from wrapping when clipped
  341. this.headers.setWidth(totalWidth+scrollOffset);
  342. this.innerCt.setWidth(totalWidth);
  343. }
  344. });
  345. Ext.reg('columntree', Ext.ux.tree.ColumnTree);
  346. //backwards compat
  347. Ext.tree.ColumnTree = Ext.ux.tree.ColumnTree;
  348. /**
  349. * @class Ext.ux.tree.ColumnNodeUI
  350. * @extends Ext.tree.TreeNodeUI
  351. */
  352. Ext.ux.tree.ColumnNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
  353. focus: Ext.emptyFn, // prevent odd scrolling behavior
  354. renderElements : function(n, a, targetNode, bulkRender){
  355. this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
  356. var t = n.getOwnerTree();
  357. var cols = t.columns;
  358. var bw = t.borderWidth;
  359. var c = cols[0];
  360. var buf = [
  361. '<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf ', a.cls,'">',
  362. '<div class="x-tree-col" style="width:',c.width-bw,'px;">',
  363. '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
  364. '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
  365. '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on">',
  366. '<a hidefocus="on" class="x-tree-node-anchor" href="',a.href ? a.href : "#",'" tabIndex="1" ',
  367. a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
  368. '<span unselectable="on">', n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</span></a>",
  369. "</div>"];
  370. for(var i = 1, len = cols.length; i < len; i++){
  371. c = cols[i];
  372. buf.push('<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
  373. '<div class="x-tree-col-text">',(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</div>",
  374. "</div>");
  375. }
  376. buf.push(
  377. '<div class="x-clear"></div></div>',
  378. '<ul class="x-tree-node-ct" style="display:none;"></ul>',
  379. "</li>");
  380. if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
  381. this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
  382. n.nextSibling.ui.getEl(), buf.join(""));
  383. }else{
  384. this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
  385. }
  386. this.elNode = this.wrap.childNodes[0];
  387. this.ctNode = this.wrap.childNodes[1];
  388. var cs = this.elNode.firstChild.childNodes;
  389. this.indentNode = cs[0];
  390. this.ecNode = cs[1];
  391. this.iconNode = cs[2];
  392. this.anchor = cs[3];
  393. this.textNode = cs[3].firstChild;
  394. }
  395. });
  396. //backwards compat
  397. Ext.tree.ColumnNodeUI = Ext.ux.tree.ColumnNodeUI;
  398. /**
  399. * @class Ext.DataView.LabelEditor
  400. * @extends Ext.Editor
  401. *
  402. */
  403. Ext.DataView.LabelEditor = Ext.extend(Ext.Editor, {
  404. alignment: "tl-tl",
  405. hideEl : false,
  406. cls: "x-small-editor",
  407. shim: false,
  408. completeOnEnter: true,
  409. cancelOnEsc: true,
  410. labelSelector: 'span.x-editable',
  411. constructor: function(cfg, field){
  412. Ext.DataView.LabelEditor.superclass.constructor.call(this,
  413. field || new Ext.form.TextField({
  414. allowBlank: false,
  415. growMin:90,
  416. growMax:240,
  417. grow:true,
  418. selectOnFocus:true
  419. }), cfg
  420. );
  421. },
  422. init : function(view){
  423. this.view = view;
  424. view.on('render', this.initEditor, this);
  425. this.on('complete', this.onSave, this);
  426. },
  427. initEditor : function(){
  428. this.view.on({
  429. scope: this,
  430. containerclick: this.doBlur,
  431. click: this.doBlur
  432. });
  433. this.view.getEl().on('mousedown', this.onMouseDown, this, {delegate: this.labelSelector});
  434. },
  435. doBlur: function(){
  436. if(this.editing){
  437. this.field.blur();
  438. }
  439. },
  440. onMouseDown : function(e, target){
  441. if(!e.ctrlKey && !e.shiftKey){
  442. var item = this.view.findItemFromChild(target);
  443. e.stopEvent();
  444. var record = this.view.store.getAt(this.view.indexOf(item));
  445. this.startEdit(target, record.data[this.dataIndex]);
  446. this.activeRecord = record;
  447. }else{
  448. e.preventDefault();
  449. }
  450. },
  451. onSave : function(ed, value){
  452. this.activeRecord.set(this.dataIndex, value);
  453. }
  454. });
  455. Ext.DataView.DragSelector = function(cfg){
  456. cfg = cfg || {};
  457. var view, proxy, tracker;
  458. var rs, bodyRegion, dragRegion = new Ext.lib.Region(0,0,0,0);
  459. var dragSafe = cfg.dragSafe === true;
  460. this.init = function(dataView){
  461. view = dataView;
  462. view.on('render', onRender);
  463. };
  464. function fillRegions(){
  465. rs = [];
  466. view.all.each(function(el){
  467. rs[rs.length] = el.getRegion();
  468. });
  469. bodyRegion = view.el.getRegion();
  470. }
  471. function cancelClick(){
  472. return false;
  473. }
  474. function onBeforeStart(e){
  475. return !dragSafe || e.target == view.el.dom;
  476. }
  477. function onStart(e){
  478. view.on('containerclick', cancelClick, view, {single:true});
  479. if(!proxy){
  480. proxy = view.el.createChild({cls:'x-view-selector'});
  481. }else{
  482. proxy.setDisplayed('block');
  483. }
  484. fillRegions();
  485. view.clearSelections();
  486. }
  487. function onDrag(e){
  488. var startXY = tracker.startXY;
  489. var xy = tracker.getXY();
  490. var x = Math.min(startXY[0], xy[0]);
  491. var y = Math.min(startXY[1], xy[1]);
  492. var w = Math.abs(startXY[0] - xy[0]);
  493. var h = Math.abs(startXY[1] - xy[1]);
  494. dragRegion.left = x;
  495. dragRegion.top = y;
  496. dragRegion.right = x+w;
  497. dragRegion.bottom = y+h;
  498. dragRegion.constrainTo(bodyRegion);
  499. proxy.setRegion(dragRegion);
  500. for(var i = 0, len = rs.length; i < len; i++){
  501. var r = rs[i], sel = dragRegion.intersect(r);
  502. if(sel && !r.selected){
  503. r.selected = true;
  504. view.select(i, true);
  505. }else if(!sel && r.selected){
  506. r.selected = false;
  507. view.deselect(i);
  508. }
  509. }
  510. }
  511. function onEnd(e){
  512. if (!Ext.isIE) {
  513. view.un('containerclick', cancelClick, view);
  514. }
  515. if(proxy){
  516. proxy.setDisplayed(false);
  517. }
  518. }
  519. function onRender(view){
  520. tracker = new Ext.dd.DragTracker({
  521. onBeforeStart: onBeforeStart,
  522. onStart: onStart,
  523. onDrag: onDrag,
  524. onEnd: onEnd
  525. });
  526. tracker.initEl(view.el);
  527. }
  528. };Ext.ns('Ext.ux.form');
  529. /**
  530. * @class Ext.ux.form.FileUploadField
  531. * @extends Ext.form.TextField
  532. * Creates a file upload field.
  533. * @xtype fileuploadfield
  534. */
  535. Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
  536. /**
  537. * @cfg {String} buttonText The button text to display on the upload button (defaults to
  538. * 'Browse...'). Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text
  539. * value will be used instead if available.
  540. */
  541. buttonText: 'Browse...',
  542. /**
  543. * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
  544. * text field (defaults to false). If true, all inherited TextField members will still be available.
  545. */
  546. buttonOnly: false,
  547. /**
  548. * @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field
  549. * (defaults to 3). Note that this only applies if {@link #buttonOnly} = false.
  550. */
  551. buttonOffset: 3,
  552. /**
  553. * @cfg {Object} buttonCfg A standard {@link Ext.Button} config object.
  554. */
  555. // private
  556. readOnly: true,
  557. /**
  558. * @hide
  559. * @method autoSize
  560. */
  561. autoSize: Ext.emptyFn,
  562. // private
  563. initComponent: function(){
  564. Ext.ux.form.FileUploadField.superclass.initComponent.call(this);
  565. this.addEvents(
  566. /**
  567. * @event fileselected
  568. * Fires when the underlying file input field's value has changed from the user
  569. * selecting a new file from the system file selection dialog.
  570. * @param {Ext.ux.form.FileUploadField} this
  571. * @param {String} value The file value returned by the underlying file input field
  572. */
  573. 'fileselected'
  574. );
  575. },
  576. // private
  577. onRender : function(ct, position){
  578. Ext.ux.form.FileUploadField.superclass.onRender.call(this, ct, position);
  579. this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'});
  580. this.el.addClass('x-form-file-text');
  581. this.el.dom.removeAttribute('name');
  582. this.fileInput = this.wrap.createChild({
  583. id: this.getFileInputId(),
  584. name: this.name||this.getId(),
  585. cls: 'x-form-file',
  586. tag: 'input',
  587. type: 'file',
  588. size: 1
  589. });
  590. var btnCfg = Ext.applyIf(this.buttonCfg || {}, {
  591. text: this.buttonText
  592. });
  593. this.button = new Ext.Button(Ext.apply(btnCfg, {
  594. renderTo: this.wrap,
  595. cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '')
  596. }));
  597. if(this.buttonOnly){
  598. this.el.hide();
  599. this.wrap.setWidth(this.button.getEl().getWidth());
  600. }
  601. this.fileInput.on('change', function(){
  602. var v = this.fileInput.dom.value;
  603. this.setValue(v);
  604. this.fireEvent('fileselected', this, v);
  605. }, this);
  606. },
  607. // private
  608. getFileInputId: function(){
  609. return this.id + '-file';
  610. },
  611. // private
  612. onResize : function(w, h){
  613. Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h);
  614. this.wrap.setWidth(w);
  615. if(!this.buttonOnly){
  616. var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset;
  617. this.el.setWidth(w);
  618. }
  619. },
  620. // private
  621. onDestroy: function(){
  622. Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
  623. Ext.destroy(this.fileInput, this.button, this.wrap);
  624. },
  625. // private
  626. preFocus : Ext.emptyFn,
  627. // private
  628. getResizeEl : function(){
  629. return this.wrap;
  630. },
  631. // private
  632. getPositionEl : function(){
  633. return this.wrap;
  634. },
  635. // private
  636. alignErrorIcon : function(){
  637. this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
  638. }
  639. });
  640. Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField);
  641. // backwards compat
  642. Ext.form.FileUploadField = Ext.ux.form.FileUploadField;
  643. (function(){
  644. Ext.ns('Ext.a11y');
  645. Ext.a11y.Frame = Ext.extend(Object, {
  646. initialized: false,
  647. constructor: function(size, color){
  648. this.setSize(size || 1);
  649. this.setColor(color || '15428B');
  650. },
  651. init: function(){
  652. if (!this.initialized) {
  653. this.sides = [];
  654. var s, i;
  655. this.ct = Ext.DomHelper.append(document.body, {
  656. cls: 'x-a11y-focusframe'
  657. }, true);
  658. for (i = 0; i < 4; i++) {
  659. s = Ext.DomHelper.append(this.ct, {
  660. cls: 'x-a11y-focusframe-side',
  661. style: 'background-color: #' + this.color
  662. }, true);
  663. s.visibilityMode = Ext.Element.DISPLAY;
  664. this.sides.push(s);
  665. }
  666. this.frameTask = new Ext.util.DelayedTask(function(el){
  667. var newEl = Ext.get(el);
  668. if (newEl != this.curEl) {
  669. var w = newEl.getWidth();
  670. var h = newEl.getHeight();
  671. this.sides[0].show().setSize(w, this.size).anchorTo(el, 'tl', [0, -1]);
  672. this.sides[2].show().setSize(w, this.size).anchorTo(el, 'bl', [0, -1]);
  673. this.sides[1].show().setSize(this.size, h).anchorTo(el, 'tr', [-1, 0]);
  674. this.sides[3].show().setSize(this.size, h).anchorTo(el, 'tl', [-1, 0]);
  675. this.curEl = newEl;
  676. }
  677. }, this);
  678. this.unframeTask = new Ext.util.DelayedTask(function(){
  679. if (this.initialized) {
  680. this.sides[0].hide();
  681. this.sides[1].hide();
  682. this.sides[2].hide();
  683. this.sides[3].hide();
  684. this.curEl = null;
  685. }
  686. }, this);
  687. this.initialized = true;
  688. }
  689. },
  690. frame: function(el){
  691. this.init();
  692. this.unframeTask.cancel();
  693. this.frameTask.delay(2, false, false, [el]);
  694. },
  695. unframe: function(){
  696. this.init();
  697. this.unframeTask.delay(2);
  698. },
  699. setSize: function(size){
  700. this.size = size;
  701. },
  702. setColor: function(color){
  703. this.color = color;
  704. }
  705. });
  706. Ext.a11y.FocusFrame = new Ext.a11y.Frame(2, '15428B');
  707. Ext.a11y.RelayFrame = new Ext.a11y.Frame(1, '6B8CBF');
  708. Ext.a11y.Focusable = Ext.extend(Ext.util.Observable, {
  709. constructor: function(el, relayTo, noFrame, frameEl){
  710. Ext.a11y.Focusable.superclass.constructor.call(this);
  711. this.addEvents('focus', 'blur', 'left', 'right', 'up', 'down', 'esc', 'enter', 'space');
  712. if (el instanceof Ext.Component) {
  713. this.el = el.el;
  714. this.setComponent(el);
  715. }
  716. else {
  717. this.el = Ext.get(el);
  718. this.setComponent(null);
  719. }
  720. this.setRelayTo(relayTo)
  721. this.setNoFrame(noFrame);
  722. this.setFrameEl(frameEl);
  723. this.init();
  724. Ext.a11y.FocusMgr.register(this);
  725. },
  726. init: function(){
  727. this.el.dom.tabIndex = '1';
  728. this.el.addClass('x-a11y-focusable');
  729. this.el.on({
  730. focus: this.onFocus,
  731. blur: this.onBlur,
  732. keydown: this.onKeyDown,
  733. scope: this
  734. });
  735. },
  736. setRelayTo: function(relayTo){
  737. this.relayTo = relayTo ? Ext.a11y.FocusMgr.get(relayTo) : null;
  738. },
  739. setNoFrame: function(noFrame){
  740. this.noFrame = (noFrame === true) ? true : false;
  741. },
  742. setFrameEl: function(frameEl){
  743. this.frameEl = frameEl && Ext.get(frameEl) || this.el;
  744. },
  745. setComponent: function(cmp){
  746. this.component = cmp || null;
  747. },
  748. onKeyDown: function(e, t){
  749. var k = e.getKey(), SK = Ext.a11y.Focusable.SpecialKeys, ret, tf;
  750. tf = (t !== this.el.dom) ? Ext.a11y.FocusMgr.get(t, true) : this;
  751. if (!tf) {
  752. // this can happen when you are on a focused item within a panel body
  753. // that is not a Ext.a11y.Focusable
  754. tf = Ext.a11y.FocusMgr.get(Ext.fly(t).parent('.x-a11y-focusable'));
  755. }
  756. if (SK[k] !== undefined) {
  757. ret = this.fireEvent(SK[k], e, t, tf, this);
  758. }
  759. if (ret === false || this.fireEvent('keydown', e, t, tf, this) === false) {
  760. e.stopEvent();
  761. }
  762. },
  763. focus: function(){
  764. this.el.dom.focus();
  765. },
  766. blur: function(){
  767. this.el.dom.blur();
  768. },
  769. onFocus: function(e, t){
  770. this.el.addClass('x-a11y-focused');
  771. if (this.relayTo) {
  772. this.relayTo.el.addClass('x-a11y-focused-relay');
  773. if (!this.relayTo.noFrame) {
  774. Ext.a11y.FocusFrame.frame(this.relayTo.frameEl);
  775. }
  776. if (!this.noFrame) {
  777. Ext.a11y.RelayFrame.frame(this.frameEl);
  778. }
  779. }
  780. else {
  781. if (!this.noFrame) {
  782. Ext.a11y.FocusFrame.frame(this.frameEl);
  783. }
  784. }
  785. this.fireEvent('focus', e, t, this);
  786. },
  787. onBlur: function(e, t){
  788. if (this.relayTo) {
  789. this.relayTo.el.removeClass('x-a11y-focused-relay');
  790. Ext.a11y.RelayFrame.unframe();
  791. }
  792. this.el.removeClass('x-a11y-focused');
  793. Ext.a11y.FocusFrame.unframe();
  794. this.fireEvent('blur', e, t, this);
  795. },
  796. destroy: function(){
  797. this.el.un('keydown', this.onKeyDown);
  798. this.el.un('focus', this.onFocus);
  799. this.el.un('blur', this.onBlur);
  800. this.el.removeClass('x-a11y-focusable');
  801. this.el.removeClass('x-a11y-focused');
  802. if (this.relayTo) {
  803. this.relayTo.el.removeClass('x-a11y-focused-relay');
  804. }
  805. }
  806. });
  807. Ext.a11y.FocusItem = Ext.extend(Object, {
  808. constructor: function(el, enableTabbing){
  809. Ext.a11y.FocusItem.superclass.constructor.call(this);
  810. this.el = Ext.get(el);
  811. this.fi = new Ext.a11y.Focusable(el);
  812. this.fi.setComponent(this);
  813. this.fi.on('tab', this.onTab, this);
  814. this.enableTabbing = enableTabbing === true ? true : false;
  815. },
  816. getEnterItem: function(){
  817. if (this.enableTabbing) {
  818. var items = this.getFocusItems();
  819. if (items && items.length) {
  820. return items[0];
  821. }
  822. }
  823. },
  824. getFocusItems: function(){
  825. if (this.enableTabbing) {
  826. return this.el.query('a, button, input, select');
  827. }
  828. return null;
  829. },
  830. onTab: function(e, t){
  831. var items = this.getFocusItems(), i;
  832. if (items && items.length && (i = items.indexOf(t)) !== -1) {
  833. if (e.shiftKey && i > 0) {
  834. e.stopEvent();
  835. items[i - 1].focus();
  836. Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
  837. return;
  838. }
  839. else
  840. if (!e.shiftKey && i < items.length - 1) {
  841. e.stopEvent();
  842. items[i + 1].focus();
  843. Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
  844. return;
  845. }
  846. }
  847. },
  848. focus: function(){
  849. if (this.enableTabbing) {
  850. var items = this.getFocusItems();
  851. if (items && items.length) {
  852. items[0].focus();
  853. Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
  854. return;
  855. }
  856. }
  857. this.fi.focus();
  858. },
  859. blur: function(){
  860. this.fi.blur();
  861. }
  862. });
  863. Ext.a11y.FocusMgr = function(){
  864. var all = new Ext.util.MixedCollection();
  865. return {
  866. register: function(f){
  867. all.add(f.el && Ext.id(f.el), f);
  868. },
  869. unregister: function(f){
  870. all.remove(f);
  871. },
  872. get: function(el, noCreate){
  873. return all.get(Ext.id(el)) || (noCreate ? false : new Ext.a11y.Focusable(el));
  874. },
  875. all: all
  876. }
  877. }();
  878. Ext.a11y.Focusable.SpecialKeys = {};
  879. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.LEFT] = 'left';
  880. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.RIGHT] = 'right';
  881. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.DOWN] = 'down';
  882. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.UP] = 'up';
  883. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.ESC] = 'esc';
  884. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.ENTER] = 'enter';
  885. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.SPACE] = 'space';
  886. Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.TAB] = 'tab';
  887. // we use the new observeClass method to fire our new initFocus method on components
  888. Ext.util.Observable.observeClass(Ext.Component);
  889. Ext.Component.on('render', function(cmp){
  890. cmp.initFocus();
  891. cmp.initARIA();
  892. });
  893. Ext.override(Ext.Component, {
  894. initFocus: Ext.emptyFn,
  895. initARIA: Ext.emptyFn
  896. });
  897. Ext.override(Ext.Container, {
  898. isFocusable: true,
  899. noFocus: false,
  900. // private
  901. initFocus: function(){
  902. if (!this.fi && !this.noFocus) {
  903. this.fi = new Ext.a11y.Focusable(this);
  904. }
  905. this.mon(this.fi, {
  906. focus: this.onFocus,
  907. blur: this.onBlur,
  908. tab: this.onTab,
  909. enter: this.onEnter,
  910. esc: this.onEsc,
  911. scope: this
  912. });
  913. if (this.hidden) {
  914. this.isFocusable = false;
  915. }
  916. this.on('show', function(){
  917. this.isFocusable = true;
  918. }, this);
  919. this.on('hide', function(){
  920. this.isFocusable = false;
  921. }, this);
  922. },
  923. focus: function(){
  924. this.fi.focus();
  925. },
  926. blur: function(){
  927. this.fi.blur();
  928. },
  929. enter: function(){
  930. var eitem = this.getEnterItem();
  931. if (eitem) {
  932. eitem.focus();
  933. }
  934. },
  935. onFocus: Ext.emptyFn,
  936. onBlur: Ext.emptyFn,
  937. onTab: function(e, t, tf){
  938. var rf = tf.relayTo || tf;
  939. if (rf.component && rf.component !== this) {
  940. e.stopEvent();
  941. var item = e.shiftKey ? this.getPreviousFocus(rf.component) : this.getNextFocus(rf.component);
  942. item.focus();
  943. }
  944. },
  945. onEnter: function(e, t, tf){
  946. // check to see if enter is pressed while "on" the panel
  947. if (tf.component && tf.component === this) {
  948. e.stopEvent();
  949. this.enter();
  950. }
  951. e.stopPropagation();
  952. },
  953. onEsc: function(e, t){
  954. e.preventDefault();
  955. // check to see if esc is pressed while "inside" the panel
  956. // or while "on" the panel
  957. if (t === this.el.dom) {
  958. // "on" the panel, check if this panel has an owner panel and focus that
  959. // we dont stop the event in this case so that this same check will be
  960. // done for this ownerCt
  961. if (this.ownerCt) {
  962. this.ownerCt.focus();
  963. }
  964. }
  965. else {
  966. // we were inside the panel when esc was pressed,
  967. // so go back "on" the panel
  968. if (this.ownerCt && this.ownerCt.isFocusable) {
  969. var si = this.ownerCt.getFocusItems();
  970. if (si && si.getCount() > 1) {
  971. e.stopEvent();
  972. }
  973. }
  974. this.focus();
  975. }
  976. },
  977. getFocusItems: function(){
  978. return this.items &&
  979. this.items.filterBy(function(o){
  980. return o.isFocusable;
  981. }) ||
  982. null;
  983. },
  984. getEnterItem: function(){
  985. var ci = this.getFocusItems(), length = ci ? ci.getCount() : 0;
  986. if (length === 1) {
  987. return ci.first().getEnterItem && ci.first().getEnterItem() || ci.first();
  988. }
  989. else
  990. if (length > 1) {
  991. return ci.first();
  992. }
  993. },
  994. getNextFocus: function(current){
  995. var items = this.getFocusItems(), next = current, i = items.indexOf(current), length = items.getCount();
  996. if (i === length - 1) {
  997. next = items.first();
  998. }
  999. else {
  1000. next = items.get(i + 1);
  1001. }
  1002. return next;
  1003. },
  1004. getPreviousFocus: function(current){
  1005. var items = this.getFocusItems(), prev = current, i = items.indexOf(current), length = items.getCount();
  1006. if (i === 0) {
  1007. prev = items.last();
  1008. }
  1009. else {
  1010. prev = items.get(i - 1);
  1011. }
  1012. return prev;
  1013. },
  1014. getFocusable : function() {
  1015. return this.fi;
  1016. }
  1017. });
  1018. Ext.override(Ext.Panel, {
  1019. /**
  1020. * @cfg {Boolean} enableTabbing <tt>true</tt> to enable tabbing. Default is <tt>false</tt>.
  1021. */
  1022. getFocusItems: function(){
  1023. // items gets all the items inside the body
  1024. var items = Ext.Panel.superclass.getFocusItems.call(this), bodyFocus = null;
  1025. if (!items) {
  1026. items = new Ext.util.MixedCollection();
  1027. this.bodyFocus = this.bodyFocus || new Ext.a11y.FocusItem(this.body, this.enableTabbing);
  1028. items.add('body', this.bodyFocus);
  1029. }
  1030. // but panels can also have tbar, bbar, fbar
  1031. if (this.tbar && this.topToolbar) {
  1032. items.insert(0, this.topToolbar);
  1033. }
  1034. if (this.bbar && this.bottomToolbar) {
  1035. items.add(this.bottomToolbar);
  1036. }
  1037. if (this.fbar) {
  1038. items.add(this.fbar);
  1039. }
  1040. return items;
  1041. }
  1042. });
  1043. Ext.override(Ext.TabPanel, {
  1044. // private
  1045. initFocus: function(){
  1046. Ext.TabPanel.superclass.initFocus.call(this);
  1047. this.mon(this.fi, {
  1048. left: this.onLeft,
  1049. right: this.onRight,
  1050. scope: this
  1051. });
  1052. },
  1053. onLeft: function(e){
  1054. if (!this.activeTab) {
  1055. return;
  1056. }
  1057. e.stopEvent();
  1058. var prev = this.items.itemAt(this.items.indexOf(this.activeTab) - 1);
  1059. if (prev) {
  1060. this.setActiveTab(prev);
  1061. }
  1062. return false;
  1063. },
  1064. onRight: function(e){
  1065. if (!this.activeTab) {
  1066. return;
  1067. }
  1068. e.stopEvent();
  1069. var next = this.items.itemAt(this.items.indexOf(this.activeTab) + 1);
  1070. if (next) {
  1071. this.setActiveTab(next);
  1072. }
  1073. return false;
  1074. }
  1075. });
  1076. Ext.override(Ext.tree.TreeNodeUI, {
  1077. // private
  1078. focus: function(){
  1079. this.node.getOwnerTree().bodyFocus.focus();
  1080. }
  1081. });
  1082. Ext.override(Ext.tree.TreePanel, {
  1083. // private
  1084. afterRender : function(){
  1085. Ext.tree.TreePanel.superclass.afterRender.call(this);
  1086. this.root.render();
  1087. if(!this.rootVisible){
  1088. this.root.renderChildren();
  1089. }
  1090. this.bodyFocus = new Ext.a11y.FocusItem(this.body.down('.x-tree-root-ct'));
  1091. this.bodyFocus.fi.setFrameEl(this.body);
  1092. }
  1093. });
  1094. Ext.override(Ext.grid.GridPanel, {
  1095. initFocus: function(){
  1096. Ext.grid.GridPanel.superclass.initFocus.call(this);
  1097. this.bodyFocus = new Ext.a11y.FocusItem(this.view.focusEl);
  1098. this.bodyFocus.fi.setFrameEl(this.body);
  1099. }
  1100. });
  1101. Ext.override(Ext.Button, {
  1102. isFocusable: true,
  1103. noFocus: false,
  1104. initFocus: function(){
  1105. Ext.Button.superclass.initFocus.call(this);
  1106. this.fi = this.fi || new Ext.a11y.Focusable(this.btnEl, null, null, this.el);
  1107. this.fi.setComponent(this);
  1108. this.mon(this.fi, {
  1109. focus: this.onFocus,
  1110. blur: this.onBlur,
  1111. scope: this
  1112. });
  1113. if (this.menu) {
  1114. this.mon(this.fi, 'down', this.showMenu, this);
  1115. this.on('menuhide', this.focus, this);
  1116. }
  1117. if (this.hidden) {
  1118. this.isFocusable = false;
  1119. }
  1120. this.on('show', function(){
  1121. this.isFocusable = true;
  1122. }, this);
  1123. this.on('hide', function(){
  1124. this.isFocusable = false;
  1125. }, this);
  1126. },
  1127. focus: function(){
  1128. this.fi.focus();
  1129. },
  1130. blur: function(){
  1131. this.fi.blur();
  1132. },
  1133. onFocus: function(){
  1134. if (!this.disabled) {
  1135. this.el.addClass("x-btn-focus");
  1136. }
  1137. },
  1138. onBlur: function(){
  1139. this.el.removeClass("x-btn-focus");
  1140. }
  1141. });
  1142. Ext.override(Ext.Toolbar, {
  1143. initFocus: function(){
  1144. Ext.Toolbar.superclass.initFocus.call(this);
  1145. this.mon(this.fi, {
  1146. left: this.onLeft,
  1147. right: this.onRight,
  1148. scope: this
  1149. });
  1150. this.on('focus', this.onButtonFocus, this, {
  1151. stopEvent: true
  1152. });
  1153. },
  1154. addItem: function(item){
  1155. Ext.Toolbar.superclass.add.apply(this, arguments);
  1156. if (item.rendered && item.fi !== undefined) {
  1157. item.fi.setRelayTo(this.el);
  1158. this.relayEvents(item.fi, ['focus']);
  1159. }
  1160. else {
  1161. item.on('render', function(){
  1162. if (item.fi !== undefined) {
  1163. item.fi.setRelayTo(this.el);
  1164. this.relayEvents(item.fi, ['focus']);
  1165. }
  1166. }, this, {
  1167. single: true
  1168. });
  1169. }
  1170. return item;
  1171. },
  1172. onFocus: function(){
  1173. var items = this.getFocusItems();
  1174. if (items && items.getCount() > 0) {
  1175. if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) {
  1176. this.lastFocus.focus();
  1177. }
  1178. else {
  1179. items.first().focus();
  1180. }
  1181. }
  1182. },
  1183. onButtonFocus: function(e, t, tf){
  1184. this.lastFocus = tf.component || null;
  1185. },
  1186. onLeft: function(e, t, tf){
  1187. e.stopEvent();
  1188. this.getPreviousFocus(tf.component).focus();
  1189. },
  1190. onRight: function(e, t, tf){
  1191. e.stopEvent();
  1192. this.getNextFocus(tf.component).focus();
  1193. },
  1194. getEnterItem: Ext.emptyFn,
  1195. onTab: Ext.emptyFn,
  1196. onEsc: Ext.emptyFn
  1197. });
  1198. Ext.override(Ext.menu.BaseItem, {
  1199. initFocus: function(){
  1200. this.fi = new Ext.a11y.Focusable(this, this.parentMenu && this.parentMenu.el || null, true);
  1201. }
  1202. });
  1203. Ext.override(Ext.menu.Menu, {
  1204. initFocus: function(){
  1205. this.fi = new Ext.a11y.Focusable(this);
  1206. this.focusEl = this.fi;
  1207. }
  1208. });
  1209. Ext.a11y.WindowMgr = new Ext.WindowGroup();
  1210. Ext.apply(Ext.WindowMgr, {
  1211. bringToFront: function(win){
  1212. Ext.a11y.WindowMgr.bringToFront.call(this, win);
  1213. if (win.modal) {
  1214. win.enter();
  1215. }
  1216. else {
  1217. win.focus();
  1218. }
  1219. }
  1220. });
  1221. Ext.override(Ext.Window, {
  1222. initFocus: function(){
  1223. Ext.Window.superclass.initFocus.call(this);
  1224. this.on('beforehide', function(){
  1225. Ext.a11y.RelayFrame.unframe();
  1226. Ext.a11y.FocusFrame.unframe();
  1227. });
  1228. }
  1229. });
  1230. Ext.override(Ext.form.Field, {
  1231. isFocusable: true,
  1232. noFocus: false,
  1233. initFocus: function(){
  1234. this.fi = this.fi || new Ext.a11y.Focusable(this, null, true);
  1235. Ext.form.Field.superclass.initFocus.call(this);
  1236. if (this.hidden) {
  1237. this.isFocusable = false;
  1238. }
  1239. this.on('show', function(){
  1240. this.isFocusable = true;
  1241. }, this);
  1242. this.on('hide', function(){
  1243. this.isFocusable = false;
  1244. }, this);
  1245. }
  1246. });
  1247. Ext.override(Ext.FormPanel, {
  1248. initFocus: function(){
  1249. Ext.FormPanel.superclass.initFocus.call(this);
  1250. this.on('focus', this.onFieldFocus, this, {
  1251. stopEvent: true
  1252. });
  1253. },
  1254. // private
  1255. createForm: function(){
  1256. delete this.initialConfig.listeners;
  1257. var form = new Ext.form.BasicForm(null, this.initialConfig);
  1258. form.afterMethod('add', this.formItemAdd, this);
  1259. return form;
  1260. },
  1261. formItemAdd: function(item){
  1262. item.on('render', function(field){
  1263. field.fi.setRelayTo(this.el);
  1264. this.relayEvents(field.fi, ['focus']);
  1265. }, this, {
  1266. single: true
  1267. });
  1268. },
  1269. onFocus: function(){
  1270. var items = this.getFocusItems();
  1271. if (items && items.getCount() > 0) {
  1272. if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) {
  1273. this.lastFocus.focus();
  1274. }
  1275. else {
  1276. items.first().focus();
  1277. }
  1278. }
  1279. },
  1280. onFieldFocus: function(e, t, tf){
  1281. this.lastFocus = tf.component || null;
  1282. },
  1283. onTab: function(e, t, tf){
  1284. if (tf.relayTo.component === this) {
  1285. var item = e.shiftKey ? this.getPreviousFocus(tf.component) : this.getNextFocus(tf.component);
  1286. if (item) {
  1287. ev.stopEvent();
  1288. item.focus();
  1289. return;
  1290. }
  1291. }
  1292. Ext.FormPanel.superclass.onTab.apply(this, arguments);
  1293. },
  1294. getNextFocus: function(current){
  1295. var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
  1296. return (i < length - 1) ? items.get(i + 1) : false;
  1297. },
  1298. getPreviousFocus: function(current){
  1299. var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
  1300. return (i > 0) ? items.get(i - 1) : false;
  1301. }
  1302. });
  1303. Ext.override(Ext.Viewport, {
  1304. initFocus: function(){
  1305. Ext.Viewport.superclass.initFocus.apply(this);
  1306. this.mon(Ext.get(document), 'focus', this.focus, this);
  1307. this.mon(Ext.get(document), 'blur', this.blur, this);
  1308. this.fi.setNoFrame(true);
  1309. },
  1310. onTab: function(e, t, tf, f){
  1311. e.stopEvent();
  1312. if (tf === f) {
  1313. items = this.getFocusItems();
  1314. if (items && items.getCount() > 0) {
  1315. items.first().focus();
  1316. }
  1317. }
  1318. else {
  1319. var rf = tf.relayTo || tf;
  1320. var item = e.shiftKey ? this.getPreviousFocus(rf.component) : this.getNextFocus(rf.component);
  1321. item.focus();
  1322. }
  1323. }
  1324. });
  1325. })();/**
  1326. * @class Ext.ux.GMapPanel
  1327. * @extends Ext.Panel
  1328. * @author Shea Frederick
  1329. */
  1330. Ext.ux.GMapPanel = Ext.extend(Ext.Panel, {
  1331. initComponent : function(){
  1332. var defConfig = {
  1333. plain: true,
  1334. zoomLevel: 3,
  1335. yaw: 180,
  1336. pitch: 0,
  1337. zoom: 0,
  1338. gmapType: 'map',
  1339. border: false
  1340. };
  1341. Ext.applyIf(this,defConfig);
  1342. Ext.ux.GMapPanel.superclass.initComponent.call(this);
  1343. },
  1344. afterRender : function(){
  1345. var wh = this.ownerCt.getSize();
  1346. Ext.applyIf(this, wh);
  1347. Ext.ux.GMapPanel.superclass.afterRender.call(this);
  1348. if (this.gmapType === 'map'){
  1349. this.gmap = new GMap2(this.body.dom);
  1350. }
  1351. if (this.gmapType === 'panorama'){
  1352. this.gmap = new GStreetviewPanorama(this.body.dom);
  1353. }
  1354. if (typeof this.addControl == 'object' && this.gmapType === 'map') {
  1355. this.gmap.addControl(this.addControl);
  1356. }
  1357. if (typeof this.setCenter === 'object') {
  1358. if (typeof this.setCenter.geoCodeAddr === 'string'){
  1359. this.geoCodeLookup(this.setCenter.geoCodeAddr);
  1360. }else{
  1361. if (this.gmapType === 'map'){
  1362. var point = new GLatLng(this.setCenter.lat,this.setCenter.lng);
  1363. this.gmap.setCenter(point, this.zoomLevel);
  1364. }
  1365. if (typeof this.setCenter.marker === 'object' && typeof point === 'object'){
  1366. this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear);
  1367. }
  1368. }
  1369. if (this.gmapType === 'panorama'){
  1370. this.gmap.setLocationAndPOV(new GLatLng(this.setCenter.lat,this.setCenter.lng), {yaw: this.yaw, pitch: this.pitch, zoom: this.zoom});
  1371. }
  1372. }
  1373. GEvent.bind(this.gmap, 'load', this, function(){
  1374. this.onMapReady();
  1375. });
  1376. },
  1377. onMapReady : function(){
  1378. this.addMarkers(this.markers);
  1379. this.addMapControls();
  1380. this.addOptions();
  1381. },
  1382. onResize : function(w, h){
  1383. if (typeof this.getMap() == 'object') {
  1384. this.gmap.checkResize();
  1385. }
  1386. Ext.ux.GMapPanel.superclass.onResize.call(this, w, h);
  1387. },
  1388. setSize : function(width, height, animate){
  1389. if (typeof this.getMap() == 'object') {
  1390. this.gmap.checkResize();
  1391. }
  1392. Ext.ux.GMapPanel.superclass.setSize.call(this, width, height, animate);
  1393. },
  1394. getMap : function(){
  1395. return this.gmap;
  1396. },
  1397. getCenter : function(){
  1398. return this.getMap().getCenter();
  1399. },
  1400. getCenterLatLng : function(){
  1401. var ll = this.getCenter();
  1402. return {lat: ll.lat(), lng: ll.lng()};
  1403. },
  1404. addMarkers : function(markers) {
  1405. if (Ext.isArray(markers)){
  1406. for (var i = 0; i < markers.length; i++) {
  1407. var mkr_point = new GLatLng(markers[i].lat,markers[i].lng);
  1408. this.addMarker(mkr_point,markers[i].marker,false,markers[i].setCenter, markers[i].listeners);
  1409. }
  1410. }
  1411. },
  1412. addMarker : function(point, marker, clear, center, listeners){
  1413. Ext.applyIf(marker,G_DEFAULT_ICON);
  1414. if (clear === true){
  1415. this.getMap().clearOverlays();
  1416. }
  1417. if (center === true) {
  1418. this.getMap().setCenter(point, this.zoomLevel);
  1419. }
  1420. var mark = new GMarker(point,marker);
  1421. if (typeof listeners === 'object'){
  1422. for (evt in listeners) {
  1423. GEvent.bind(mark, evt, this, listeners[evt]);
  1424. }
  1425. }
  1426. this.getMap().addOverlay(mark);
  1427. },
  1428. addMapControls : function(){
  1429. if (this.gmapType === 'map') {
  1430. if (Ext.isArray(this.mapControls)) {
  1431. for(i=0;i<this.mapControls.length;i++){
  1432. this.addMapControl(this.mapControls[i]);
  1433. }
  1434. }else if(typeof this.mapControls === 'string'){
  1435. this.addMapControl(this.mapControls);
  1436. }else if(typeof this.mapControls === 'object'){
  1437. this.getMap().addControl(this.mapControls);
  1438. }
  1439. }
  1440. },
  1441. addMapControl : function(mc){
  1442. var mcf = window[mc];
  1443. if (typeof mcf === 'function') {
  1444. this.getMap().addControl(new mcf());
  1445. }
  1446. },
  1447. addOptions : function(){
  1448. if (Ext.isArray(this.mapConfOpts)) {
  1449. var mc;
  1450. for(i=0;i<this.mapConfOpts.length;i++){
  1451. this.addOption(this.mapConfOpts[i]);
  1452. }
  1453. }else if(typeof this.mapConfOpts === 'string'){
  1454. this.addOption(this.mapConfOpts);
  1455. }
  1456. },
  1457. addOption : function(mc){
  1458. var mcf = this.getMap()[mc];
  1459. if (typeof mcf === 'function') {
  1460. this.getMap()[mc]();
  1461. }
  1462. },
  1463. geoCodeLookup : function(addr) {
  1464. this.geocoder = new GClientGeocoder();
  1465. this.geocoder.getLocations(addr, this.addAddressToMap.createDelegate(this));
  1466. },
  1467. addAddressToMap : function(response) {
  1468. if (!response || response.Status.code != 200) {
  1469. Ext.MessageBox.alert('Error', 'Code '+response.Status.code+' Error Returned');
  1470. }else{
  1471. place = response.Placemark[0];
  1472. addressinfo = place.AddressDetails;
  1473. accuracy = addressinfo.Accuracy;
  1474. if (accuracy === 0) {
  1475. Ext.MessageBox.alert('Unable to Locate Address', 'Unable to Locate the Address you provided');
  1476. }else{
  1477. if (accuracy < 7) {
  1478. Ext.MessageBox.alert('Address Accuracy', 'The address provided has a low accuracy.<br><br>Level '+accuracy+' Accuracy (8 = Exact Match, 1 = Vague Match)');
  1479. }else{
  1480. point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
  1481. if (typeof this.setCenter.marker === 'object' && typeof point === 'object'){
  1482. this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear,true, this.setCenter.listeners);
  1483. }
  1484. }
  1485. }
  1486. }
  1487. }
  1488. });
  1489. Ext.reg('gmappanel', Ext.ux.GMapPanel); Ext.ns('Ext.ux.grid');
  1490. /**
  1491. * @class Ext.ux.grid.GroupSummary
  1492. * @extends Ext.util.Observable
  1493. * A GridPanel plugin that enables dynamic column calculations and a dynamically
  1494. * updated grouped summary row.
  1495. */
  1496. Ext.ux.grid.GroupSummary = Ext.extend(Ext.util.Observable, {
  1497. /**
  1498. * @cfg {Function} summaryRenderer Renderer example:<pre><code>
  1499. summaryRenderer: function(v, params, data){
  1500. return ((v === 0 || v > 1) ? '(' + v +' Tasks)' : '(1 Task)');
  1501. },
  1502. * </code></pre>
  1503. */
  1504. /**
  1505. * @cfg {String} summaryType (Optional) The type of
  1506. * calculation to be used for the column. For options available see
  1507. * {@link #Calculations}.
  1508. */
  1509. constructor : function(config){
  1510. Ext.apply(this, config);
  1511. Ext.ux.grid.GroupSummary.superclass.constructor.call(this);
  1512. },
  1513. init : function(grid){
  1514. this.grid = grid;
  1515. this.cm = grid.getColumnModel();
  1516. this.view = grid.getView();
  1517. var v = this.view;
  1518. v.doGroupEnd = this.doGroupEnd.createDelegate(this);
  1519. v.afterMethod('onColumnWidthUpdated', this.doWidth, this);
  1520. v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);
  1521. v.afterMethod('onColumnHiddenUpdated', this.doHidden, this);
  1522. v.afterMethod('onUpdate', this.doUpdate, this);
  1523. v.afterMethod('onRemove', this.doRemove, this);
  1524. if(!this.rowTpl){
  1525. this.rowTpl = new Ext.Template(
  1526. '<div class="x-grid3-summary-row" style="{tstyle}">',
  1527. '<table class="x-grid3-summary-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
  1528. '<tbody><tr>{cells}</tr></tbody>',
  1529. '</table></div>'
  1530. );
  1531. this.rowTpl.disableFormats = true;
  1532. }
  1533. this.rowTpl.compile();
  1534. if(!this.cellTpl){
  1535. this.cellTpl = new Ext.Template(
  1536. '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}">',
  1537. '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on">{value}</div>',
  1538. "</td>"
  1539. );
  1540. this.cellTpl.disableFormats = true;
  1541. }
  1542. this.cellTpl.compile();
  1543. },
  1544. /**
  1545. * Toggle the display of the summary row on/off
  1546. * @param {Boolean} visible <tt>true</tt> to show the summary, <tt>false</tt> to hide the summary.
  1547. */
  1548. toggleSummaries : function(visible){
  1549. var el = this.grid.getGridEl();
  1550. if(el){
  1551. if(visible === undefined){
  1552. visible = el.hasClass('x-grid-hide-summary');
  1553. }
  1554. el[visible ? 'removeClass' : 'addClass']('x-grid-hide-summary');
  1555. }
  1556. },
  1557. renderSummary : function(o, cs){
  1558. cs = cs || this.view.getColumnData();
  1559. var cfg = this.cm.config;
  1560. var buf = [], c, p = {}, cf, last = cs.length-1;
  1561. for(var i = 0, len = cs.length; i < len; i++){
  1562. c = cs[i];
  1563. cf = cfg[i];
  1564. p.id = c.id;
  1565. p.style = c.style;
  1566. p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
  1567. if(cf.summaryType || cf.summaryRenderer){
  1568. p.value = (cf.summaryRenderer || c.renderer)(o.data[c.name], p, o);
  1569. }else{
  1570. p.value = '';
  1571. }
  1572. if(p.value == undefined || p.value === "") p.value = "&#160;";
  1573. buf[buf.length] = this.cellTpl.apply(p);
  1574. }
  1575. return this.rowTpl.apply({
  1576. tstyle: 'width:'+this.view.getTotalWidth()+';',
  1577. cells: buf.join('')
  1578. });
  1579. },
  1580. /**
  1581. * @private
  1582. * @param {Object} rs
  1583. * @param {Object} cs
  1584. */
  1585. calculate : function(rs, cs){
  1586. var data = {}, r, c, cfg = this.cm.config, cf;
  1587. for(var j = 0, jlen = rs.length; j < jlen; j++){
  1588. r = rs[j];
  1589. for(var i = 0, len = cs.length; i < len; i++){
  1590. c = cs[i];
  1591. cf = cfg[i];
  1592. if(cf.summaryType){
  1593. data[c.name] = Ext.ux.grid.GroupSummary.Calculations[cf.summaryType](data[c.name] || 0, r, c.name, data);
  1594. }
  1595. }
  1596. }
  1597. return data;
  1598. },
  1599. doGroupEnd : function(buf, g, cs, ds, colCount){
  1600. var data = this.calculate(g.rs, cs);
  1601. buf.push('</div>', this.renderSummary({data: data}, cs), '</div>');
  1602. },
  1603. doWidth : function(col, w, tw){
  1604. var gs = this.view.getGroups(), s;
  1605. for(var i = 0, len = gs.length; i < len; i++){
  1606. s = gs[i].childNodes[2];
  1607. s.style.width = tw;
  1608. s.firstChild.style.width = tw;
  1609. s.firstChild.rows[0].childNodes[col].style.width = w;
  1610. }
  1611. },
  1612. doAllWidths : function(ws, tw){
  1613. var gs = this.view.getGroups(), s, cells, wlen = ws.length;
  1614. for(var i = 0, len = gs.length; i < len; i++){
  1615. s = gs[i].childNodes[2];
  1616. s.style.width = tw;
  1617. s.firstChild.style.width = tw;
  1618. cells = s.firstChild.rows[0].childNodes;
  1619. for(var j = 0; j < wlen; j++){
  1620. cells[j].style.width = ws[j];
  1621. }
  1622. }
  1623. },
  1624. doHidden : function(col, hidden, tw){
  1625. var gs = this.view.getGroups(), s, display = hidden ? 'none' : '';
  1626. for(var i = 0, len = gs.length; i < len; i++){
  1627. s = gs[i].childNodes[2];
  1628. s.style.width = tw;
  1629. s.firstChild.style.width = tw;
  1630. s.firstChild.rows[0].childNodes[col].style.display = display;
  1631. }
  1632. },
  1633. // Note: requires that all (or the first) record in the
  1634. // group share the same group value. Returns false if the group
  1635. // could not be found.
  1636. refreshSummary : function(groupValue){
  1637. return this.refreshSummaryById(this.view.getGroupId(groupValue));
  1638. },
  1639. getSummaryNode : function(gid){
  1640. var g = Ext.fly(gid, '_gsummary');
  1641. if(g){
  1642. return g.down('.x-grid3-summary-row', true);
  1643. }
  1644. return null;
  1645. },
  1646. refreshSummaryById : function(gid){
  1647. var g = document.getElementById(gid);
  1648. if(!g){
  1649. return false;
  1650. }
  1651. var rs = [];
  1652. this.grid.store.each(function(r){
  1653. if(r._groupId == gid){
  1654. rs[rs.length] = r;
  1655. }
  1656. });
  1657. var cs = this.view.getColumnData();
  1658. var data = this.calculate(rs, cs);
  1659. var markup = this.renderSummary({data: data}, cs);
  1660. var existing = this.getSummaryNode(gid);
  1661. if(existing){
  1662. g.removeChild(existing);
  1663. }
  1664. Ext.DomHelper.append(g, markup);
  1665. return true;
  1666. },
  1667. doUpdate : function(ds, record){
  1668. this.refreshSummaryById(record._groupId);
  1669. },
  1670. doRemove : function(ds, record, index, isUpdate){
  1671. if(!isUpdate){
  1672. this.refreshSummaryById(record._groupId);
  1673. }
  1674. },
  1675. /**
  1676. * Show a message in the summary row.
  1677. * <pre><code>
  1678. grid.on('afteredit', function(){
  1679. var groupValue = 'Ext Forms: Field Anchoring';
  1680. summary.showSummaryMsg(groupValue, 'Updating Summary...');
  1681. });
  1682. * </code></pre>
  1683. * @param {String} groupValue
  1684. * @param {String} msg Text to use as innerHTML for the summary row.
  1685. */
  1686. showSummaryMsg : function(groupValue, msg){
  1687. var gid = this.view.getGroupId(groupValue);
  1688. var node = this.getSummaryNode(gid);
  1689. if(node){
  1690. node.innerHTML = '<div class="x-grid3-summary-msg">' + msg + '</div>';
  1691. }
  1692. }
  1693. });
  1694. //backwards compat
  1695. Ext.grid.GroupSummary = Ext.ux.grid.GroupSummary;
  1696. /**
  1697. * Calculation types for summary row:</p><div class="mdetail-params"><ul>
  1698. * <li><b><tt>sum</tt></b> : <div class="sub-desc"></div></li>
  1699. * <li><b><tt>count</tt></b> : <div class="sub-desc"></div></li>
  1700. * <li><b><tt>max</tt></b> : <div class="sub-desc"></div></li>
  1701. * <li><b><tt>min</tt></b> : <div class="sub-desc"></div></li>
  1702. * <li><b><tt>average</tt></b> : <div class="sub-desc"></div></li>
  1703. * </ul></div>
  1704. * <p>Custom calculations may be implemented. An example of
  1705. * custom <code>summaryType=totalCost</code>:</p><pre><code>
  1706. // define a custom summary function
  1707. Ext.ux.grid.GroupSummary.Calculations['totalCost'] = function(v, record, field){
  1708. return v + (record.data.estimate * record.data.rate);
  1709. };
  1710. * </code></pre>
  1711. * @property Calculations
  1712. */
  1713. Ext.ux.grid.GroupSummary.Calculations = {
  1714. 'sum' : function(v, record, field){
  1715. return v + (record.data[field]||0);
  1716. },
  1717. 'count' : function(v, record, field, data){
  1718. return data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);
  1719. },
  1720. 'max' : function(v, record, field, data){
  1721. var v = record.data[field];
  1722. var max = data[field+'max'] === undefined ? (data[field+'max'] = v) : data[field+'max'];
  1723. return v > max ? (data[field+'max'] = v) : max;
  1724. },
  1725. 'min' : function(v, record, field, data){
  1726. var v = record.data[field];
  1727. var min = data[field+'min'] === undefined ? (data[field+'min'] = v) : data[field+'min'];
  1728. return v < min ? (data[field+'min'] = v) : min;
  1729. },
  1730. 'average' : function(v, record, field, data){
  1731. var c = data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);
  1732. var t = (data[field+'total'] = ((data[field+'total']||0) + (record.data[field]||0)));
  1733. return t === 0 ? 0 : t / c;
  1734. }
  1735. };
  1736. Ext.grid.GroupSummary.Calculations = Ext.ux.grid.GroupSummary.Calculations;
  1737. /**
  1738. * @class Ext.ux.grid.HybridSummary
  1739. * @extends Ext.ux.grid.GroupSummary
  1740. * Adds capability to specify the summary data for the group via json as illustrated here:
  1741. * <pre><code>
  1742. {
  1743. data: [
  1744. {
  1745. projectId: 100, project: 'House',
  1746. taskId: 112, description: 'Paint',
  1747. estimate: 6, rate: 150,
  1748. due:'06/24/2007'
  1749. },
  1750. ...
  1751. ],
  1752. summaryData: {
  1753. 'House': {
  1754. description: 14, estimate: 9,
  1755. rate: 99, due: new Date(2009, 6, 29),
  1756. cost: 999
  1757. }
  1758. }
  1759. }
  1760. * </code></pre>
  1761. *
  1762. */
  1763. Ext.ux.grid.HybridSummary = Ext.extend(Ext.ux.grid.GroupSummary, {
  1764. /**
  1765. * @private
  1766. * @param {Object} rs
  1767. * @param {Object} cs
  1768. */
  1769. calculate : function(rs, cs){
  1770. var gcol = this.view.getGroupField();
  1771. var gvalue = rs[0].data[gcol];
  1772. var gdata = this.getSummaryData(gvalue);
  1773. return gdata || Ext.ux.grid.HybridSummary.superclass.calculate.call(this, rs, cs);
  1774. },
  1775. /**
  1776. * <pre><code>
  1777. grid.on('afteredit', function(){
  1778. var groupValue = 'Ext Forms: Field Anchoring';
  1779. summary.showSummaryMsg(groupValue, 'Updating Summary...');
  1780. setTimeout(function(){ // simulate server call
  1781. // HybridSummary class implements updateSummaryData
  1782. summary.updateSummaryData(groupValue,
  1783. // create data object based on configured dataIndex
  1784. {description: 22, estimate: 888, rate: 888, due: new Date(), cost: 8});
  1785. }, 2000);
  1786. });
  1787. * </code></pre>
  1788. * @param {String} groupValue
  1789. * @param {Object} data data object
  1790. * @param {Boolean} skipRefresh (Optional) Defaults to false
  1791. */
  1792. updateSummaryData : function(groupValue, data, skipRefresh){
  1793. var json = this.grid.store.reader.jsonData;
  1794. if(!json.summaryData){
  1795. json.summaryData = {};
  1796. }
  1797. json.summaryData[groupValue] = data;
  1798. if(!skipRefresh){
  1799. this.refreshSummary(groupValue);
  1800. }
  1801. },
  1802. /**
  1803. * Returns the summaryData for the specified groupValue or null.
  1804. * @param {String} groupValue
  1805. * @return {Object} summaryData
  1806. */
  1807. getSummaryData : function(groupValue){
  1808. var json = this.grid.store.reader.jsonData;
  1809. if(json && json.summaryData){
  1810. return json.summaryData[groupValue];
  1811. }
  1812. return null;
  1813. }
  1814. });
  1815. //backwards compat
  1816. Ext.grid.HybridSummary = Ext.ux.grid.HybridSummary;
  1817. Ext.ux.GroupTab = Ext.extend(Ext.Container, {
  1818. mainItem: 0,
  1819. expanded: true,
  1820. deferredRender: true,
  1821. activeTab: null,
  1822. idDelimiter: '__',
  1823. headerAsText: false,
  1824. frame: false,
  1825. hideBorders: true,
  1826. initComponent: function(config){
  1827. Ext.apply(this, config);
  1828. this.frame = false;
  1829. Ext.ux.GroupTab.superclass.initComponent.call(this);
  1830. this.addEvents('activate', 'deactivate', 'changemainitem', 'beforetabchange', 'tabchange');
  1831. this.setLayout(new Ext.layout.CardLayout({
  1832. deferredRender: this.deferredRender
  1833. }));
  1834. if (!this.stack) {
  1835. this.stack = Ext.TabPanel.AccessStack();
  1836. }
  1837. this.initItems();
  1838. this.on('beforerender', function(){
  1839. this.groupEl = this.ownerCt.getGroupEl(this);
  1840. }, this);
  1841. this.on('add', this.onAdd, this, {
  1842. target: this
  1843. });
  1844. this.on('remove', this.onRemove, this, {
  1845. target: this
  1846. });
  1847. if (this.mainItem !== undefined) {
  1848. var item = (typeof this.mainItem == 'object') ? this.mainItem : this.items.get(this.mainItem);
  1849. delete this.mainItem;
  1850. this.setMainItem(item);
  1851. }
  1852. },
  1853. /**
  1854. * Sets the specified tab as the active tab. This method fires the {@link #beforetabchange} event which
  1855. * can return false to cancel the tab change.
  1856. * @param {String/Panel} tab The id or tab Panel to activate
  1857. */
  1858. setActiveTab : function(item){
  1859. item = this.getComponent(item);
  1860. if(!item || this.fireEvent('beforetabchange', this, item, this.activeTab) === false){
  1861. return;
  1862. }
  1863. if(!this.rendered){
  1864. this.activeTab = item;
  1865. return;
  1866. }
  1867. if(this.activeTab != item){
  1868. if(this.activeTab && this.activeTab != this.mainItem){
  1869. var oldEl = this.getTabEl(this.activeTab);
  1870. if(oldEl){
  1871. Ext.fly(oldEl).removeClass('x-grouptabs-strip-active');
  1872. }
  1873. this.activeTab.fireEvent('deactivate', this.activeTab);
  1874. }
  1875. var el = this.getTabEl(item);
  1876. Ext.fly(el).addClass('x-grouptabs-strip-active');
  1877. this.activeTab = item;
  1878. this.stack.add(item);
  1879. this.layout.setActiveItem(item);
  1880. if(this.layoutOnTabChange && item.doLayout){
  1881. item.doLayout();
  1882. }
  1883. if(this.scrolling){
  1884. this.scrollToTab(item, this.animScroll);
  1885. }
  1886. item.fireEvent('activate', item);
  1887. this.fireEvent('tabchange', this, item);
  1888. }
  1889. },
  1890. getTabEl: function(item){
  1891. if (item == this.mainItem) {
  1892. return this.groupEl;
  1893. }
  1894. return Ext.TabPanel.prototype.getTabEl.call(this, item);
  1895. },
  1896. onRender: function(ct, position){
  1897. Ext.ux.GroupTab.superclass.onRender.call(this, ct, position);
  1898. this.strip = Ext.fly(this.groupEl).createChild({
  1899. tag: 'ul',
  1900. cls: 'x-grouptabs-sub'
  1901. });
  1902. this.tooltip = new Ext.ToolTip({
  1903. target: this.groupEl,
  1904. delegate: 'a.x-grouptabs-text',
  1905. trackMouse: true,
  1906. renderTo: document.body,
  1907. listeners: {
  1908. beforeshow: function(tip) {
  1909. var item = (tip.triggerElement.parentNode === this.mainItem.tabEl)
  1910. ? this.mainItem
  1911. : this.findById(tip.triggerElement.parentNode.id.split(this.idDelimiter)[1]);
  1912. if(!item.tabTip) {
  1913. return false;
  1914. }
  1915. tip.body.dom.innerHTML = item.tabTip;
  1916. },
  1917. scope: this
  1918. }
  1919. });
  1920. if (!this.itemTpl) {
  1921. var tt = new Ext.Template('<li class="{cls}" id="{id}">', '<a onclick="return false;" class="x-grouptabs-text {iconCls}">{text}</a>', '</li>');
  1922. tt.disableFormats = true;
  1923. tt.compile();
  1924. Ext.ux.GroupTab.prototype.itemTpl = tt;
  1925. }
  1926. this.items.each(this.initTab, this);
  1927. },
  1928. afterRender: function(){
  1929. Ext.ux.GroupTab.superclass.afterRender.call(this);
  1930. if (this.activeTab !== undefined) {
  1931. var item = (typeof this.activeTab == 'object') ? this.activeTab : this.items.get(this.activeTab);
  1932. delete this.activeTab;
  1933. this.setActiveTab(item);
  1934. }
  1935. },
  1936. // private
  1937. initTab: function(item, index){
  1938. var before = this.strip.dom.childNodes[index];
  1939. var p = Ext.TabPanel.prototype.getTemplateArgs.call(this, item);
  1940. if (item === this.mainItem) {
  1941. item.tabEl = this.groupEl;
  1942. p.cls += ' x-grouptabs-main-item';
  1943. }
  1944. var el = before ? this.itemTpl.insertBefore(before, p) : this.itemTpl.append(this.strip, p);
  1945. item.tabEl = item.tabEl || el;
  1946. item.on('disable', this.onItemDisabled, this);
  1947. item.on('enable', this.onItemEnabled, this);
  1948. item.on('titlechange', this.onItemTitleChanged, this);
  1949. item.on('iconchange', this.onItemIconChanged, this);
  1950. item.on('beforeshow', this.onBeforeShowItem, this);
  1951. },
  1952. setMainItem: function(item){
  1953. item = this.getComponent(item);
  1954. if (!item || this.fireEvent('changemainitem', this, item, this.mainItem) === false) {
  1955. return;
  1956. }
  1957. this.mainItem = item;
  1958. },
  1959. getMainItem: function(){
  1960. return this.mainItem || null;
  1961. },
  1962. // private
  1963. onBeforeShowItem: function(item){
  1964. if (item != this.activeTab) {
  1965. this.setActiveTab(item);
  1966. return false;
  1967. }
  1968. },
  1969. // private
  1970. onAdd: function(gt, item, index){
  1971. if (this.rendered) {
  1972. this.initTab.call(this, item, index);
  1973. }
  1974. },
  1975. // private
  1976. onRemove: function(tp, item){
  1977. Ext.destroy(Ext.get(this.getTabEl(item)));
  1978. this.stack.remove(item);
  1979. item.un('disable', this.onItemDisabled, this);
  1980. item.un('enable', this.onItemEnabled, this);
  1981. item.un('titlechange', this.onItemTitleChanged, this);
  1982. item.un('iconchange', this.onItemIconChanged, this);
  1983. item.un('beforeshow', this.onBeforeShowItem, this);
  1984. if (item == this.activeTab) {
  1985. var next = this.stack.next();
  1986. if (next) {
  1987. this.setActiveTab(next);
  1988. }
  1989. else if (this.items.getCount() > 0) {
  1990. this.setActiveTab(0);
  1991. }
  1992. else {
  1993. this.activeTab = null;
  1994. }
  1995. }
  1996. },
  1997. // private
  1998. onBeforeAdd: function(item){
  1999. var existing = item.events ? (this.items.containsKey(item.getItemId()) ? item : null) : this.items.get(item);
  2000. if (existing) {
  2001. this.setActiveTab(item);
  2002. return false;
  2003. }
  2004. Ext.TabPanel.superclass.onBeforeAdd.apply(this, arguments);
  2005. var es = item.elements;
  2006. item.elements = es ? es.replace(',header', '') : es;
  2007. item.border = (item.border === true);
  2008. },
  2009. // private
  2010. onItemDisabled: Ext.TabPanel.prototype.onItemDisabled,
  2011. onItemEnabled: Ext.TabPanel.prototype.onItemEnabled,
  2012. // private
  2013. onItemTitleChanged: function(item){
  2014. var el = this.getTabEl(item);
  2015. if (el) {
  2016. Ext.fly(el).child('a.x-grouptabs-text', true).innerHTML = item.title;
  2017. }
  2018. },
  2019. //private
  2020. onItemIconChanged: function(item, iconCls, oldCls){
  2021. var el = this.getTabEl(item);
  2022. if (el) {
  2023. Ext.fly(el).child('a.x-grouptabs-text').replaceClass(oldCls, iconCls);
  2024. }
  2025. },
  2026. beforeDestroy: function(){
  2027. Ext.TabPanel.prototype.beforeDestroy.call(this);
  2028. this.tooltip.destroy();
  2029. }
  2030. });
  2031. Ext.reg('grouptab', Ext.ux.GroupTab);
  2032. Ext.ns('Ext.ux');
  2033. Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
  2034. tabPosition: 'left',
  2035. alternateColor: false,
  2036. alternateCls: 'x-grouptabs-panel-alt',
  2037. defaultType: 'grouptab',
  2038. deferredRender: false,
  2039. activeGroup : null,
  2040. initComponent: function(){
  2041. Ext.ux.GroupTabPanel.superclass.initComponent.call(this);
  2042. this.addEvents(
  2043. 'beforegroupchange',
  2044. 'groupchange'
  2045. );
  2046. this.elements = 'body,header';
  2047. this.stripTarget = 'header';
  2048. this.tabPosition = this.tabPosition == 'right' ? 'right' : 'left';
  2049. this.addClass('x-grouptabs-panel');
  2050. if (this.tabStyle && this.tabStyle != '') {
  2051. this.addClass('x-grouptabs-panel-' + this.tabStyle);
  2052. }
  2053. if (this.alternateColor) {
  2054. this.addClass(this.alternateCls);
  2055. }
  2056. this.on('beforeadd', function(gtp, item, index){
  2057. this.initGroup(item, index);
  2058. });
  2059. },
  2060. initEvents : function() {
  2061. this.mon(this.strip, 'mousedown', this.onStripMouseDown, this);
  2062. },
  2063. onRender: function(ct, position){
  2064. Ext.TabPanel.superclass.onRender.call(this, ct, position);
  2065. if(this.plain){
  2066. var pos = this.tabPosition == 'top' ? 'header' : 'footer';
  2067. this[pos].addClass('x-tab-panel-'+pos+'-plain');
  2068. }
  2069. var st = this[this.stripTarget];
  2070. this.stripWrap = st.createChild({cls:'x-tab-strip-wrap ', cn:{
  2071. tag:'ul', cls:'x-grouptabs-strip x-grouptabs-tab-strip-'+this.tabPosition}});
  2072. var beforeEl = (this.tabPosition=='bottom' ? this.stripWrap : null);
  2073. this.strip = new Ext.Element(this.stripWrap.dom.firstChild);
  2074. this.header.addClass('x-grouptabs-panel-header');
  2075. this.bwrap.addClass('x-grouptabs-bwrap');
  2076. this.body.addClass('x-tab-panel-body-'+this.tabPosition + ' x-grouptabs-panel-body');
  2077. if (!this.itemTpl) {
  2078. var tt = new Ext.Template(
  2079. '<li class="{cls}" id="{id}">',
  2080. '<a class="x-grouptabs-expand" onclick="return false;"></a>',
  2081. '<a class="x-grouptabs-text {iconCls}" href="#" onclick="return false;">',
  2082. '<span>{text}</span></a>',
  2083. '</li>'
  2084. );
  2085. tt.disableFormats = true;
  2086. tt.compile();
  2087. Ext.ux.GroupTabPanel.prototype.itemTpl = tt;
  2088. }
  2089. this.items.each(this.initGroup, this);
  2090. },
  2091. afterRender: function(){
  2092. Ext.ux.GroupTabPanel.superclass.afterRender.call(this);
  2093. this.tabJoint = Ext.fly(this.body.dom.parentNode).createChild({
  2094. cls: 'x-tab-joint'
  2095. });
  2096. this.addClass('x-tab-panel-' + this.tabPosition);
  2097. this.header.setWidth(this.tabWidth);
  2098. if (this.activeGroup !== undefined) {
  2099. var group = (typeof this.activeGroup == 'object') ? this.activeGroup : this.items.get(this.activeGroup);
  2100. delete this.activeGroup;
  2101. this.setActiveGroup(group);
  2102. group.setActiveTab(group.getMainItem());
  2103. }
  2104. },
  2105. getGroupEl : Ext.TabPanel.prototype.getTabEl,
  2106. // private
  2107. findTargets: function(e){
  2108. var item = null;
  2109. var itemEl = e.getTarget('li', this.strip);
  2110. if (itemEl) {
  2111. item = this.findById(itemEl.id.split(this.idDelimiter)[1]);
  2112. if (item.disabled) {
  2113. return {
  2114. expand: null,
  2115. item: null,
  2116. el: null
  2117. };
  2118. }
  2119. }
  2120. return {
  2121. expand: e.getTarget('.x-grouptabs-expand', this.strip),
  2122. isGroup: !e.getTarget('ul.x-grouptabs-sub', this.strip),
  2123. item: item,
  2124. el: itemEl
  2125. };
  2126. },
  2127. // private
  2128. onStripMouseDown: function(e){
  2129. if (e.button != 0) {
  2130. return;
  2131. }
  2132. e.preventDefault();
  2133. var t = this.findTargets(e);
  2134. if (t.expand) {
  2135. this.toggleGroup(t.el);
  2136. }
  2137. else if (t.item) {
  2138. if(t.isGroup) {
  2139. t.item.setActiveTab(t.item.getMainItem());
  2140. }
  2141. else {
  2142. t.item.ownerCt.setActiveTab(t.item);
  2143. }
  2144. }
  2145. },
  2146. expandGroup: function(groupEl){
  2147. if(groupEl.isXType) {
  2148. groupEl = this.getGroupEl(groupEl);
  2149. }
  2150. Ext.fly(groupEl).addClass('x-grouptabs-expanded');
  2151. },
  2152. toggleGroup: function(groupEl){
  2153. if(groupEl.isXType) {
  2154. groupEl = this.getGroupEl(groupEl);
  2155. }
  2156. Ext.fly(groupEl).toggleClass('x-grouptabs-expanded');
  2157. this.syncTabJoint();
  2158. },
  2159. syncTabJoint: function(groupEl){
  2160. if (!this.tabJoint) {
  2161. return;
  2162. }
  2163. groupEl = groupEl || this.getGroupEl(this.activeGroup);
  2164. if(groupEl) {
  2165. this.tabJoint.setHeight(Ext.fly(groupEl).getHeight() - 2);
  2166. var y = Ext.isGecko2 ? 0 : 1;
  2167. if (this.tabPosition == 'left'){
  2168. this.tabJoint.alignTo(groupEl, 'tl-tr', [-2,y]);
  2169. }
  2170. else {
  2171. this.tabJoint.alignTo(groupEl, 'tr-tl', [1,y]);
  2172. }
  2173. }
  2174. else {
  2175. this.tabJoint.hide();
  2176. }
  2177. },
  2178. getActiveTab : function() {
  2179. if(!this.activeGroup) return null;
  2180. return this.activeGroup.getTabEl(this.activeGroup.activeTab) || null;
  2181. },
  2182. onResize: function(){
  2183. Ext.ux.GroupTabPanel.superclass.onResize.apply(this, arguments);
  2184. this.syncTabJoint();
  2185. },
  2186. createCorner: function(el, pos){
  2187. return Ext.fly(el).createChild({
  2188. cls: 'x-grouptabs-corner x-grouptabs-corner-' + pos
  2189. });
  2190. },
  2191. initGroup: function(group, index){
  2192. var before = this.strip.dom.childNodes[index];
  2193. var p = this.getTemplateArgs(group);
  2194. if (index === 0) {
  2195. p.cls += ' x-tab-first';
  2196. }
  2197. p.cls += ' x-grouptabs-main';
  2198. p.text = group.getMainItem().title;
  2199. var el = before ? this.itemTpl.insertBefore(before, p) : this.itemTpl.append(this.strip, p);
  2200. var tl = this.createCorner(el, 'top-' + this.tabPosition);
  2201. var bl = this.createCorner(el, 'bottom-' + this.tabPosition);
  2202. if (group.expanded) {
  2203. this.expandGroup(el);
  2204. }
  2205. if (Ext.isIE6 || (Ext.isIE && !Ext.isStrict)){
  2206. bl.setLeft('-10px');
  2207. bl.setBottom('-5px');
  2208. tl.setLeft('-10px');
  2209. tl.setTop('-5px');
  2210. }
  2211. this.mon(group, 'changemainitem', this.onGroupChangeMainItem, this);
  2212. this.mon(group, 'beforetabchange', this.onGroupBeforeTabChange, this);
  2213. },
  2214. setActiveGroup : function(group) {
  2215. group = this.getComponent(group);
  2216. if(!group || this.fireEvent('beforegroupchange', this, group, this.activeGroup) === false){
  2217. return;
  2218. }
  2219. if(!this.rendered){
  2220. this.activeGroup = group;
  2221. return;
  2222. }
  2223. if(this.activeGroup != group){
  2224. if(this.activeGroup){
  2225. var oldEl = this.getGroupEl(this.activeGroup);
  2226. if(oldEl){
  2227. Ext.fly(oldEl).removeClass('x-grouptabs-strip-active');
  2228. }
  2229. this.activeGroup.fireEvent('deactivate', this.activeTab);
  2230. }
  2231. var groupEl = this.getGroupEl(group);
  2232. Ext.fly(groupEl).addClass('x-grouptabs-strip-active');
  2233. this.activeGroup = group;
  2234. this.stack.add(group);
  2235. this.layout.setActiveItem(group);
  2236. this.syncTabJoint(groupEl);
  2237. group.fireEvent('activate', group);
  2238. this.fireEvent('groupchange', this, group);
  2239. }
  2240. },
  2241. onGroupBeforeTabChange: function(group, newTab, oldTab){
  2242. if(group !== this.activeGroup || newTab !== oldTab) {
  2243. this.strip.select('.x-grouptabs-sub > li.x-grouptabs-strip-active', true).removeClass('x-grouptabs-strip-active');
  2244. }
  2245. this.expandGroup(this.getGroupEl(group));
  2246. this.setActiveGroup(group);
  2247. },
  2248. getFrameHeight: function(){
  2249. var h = this.el.getFrameWidth('tb');
  2250. h += (this.tbar ? this.tbar.getHeight() : 0) +
  2251. (this.bbar ? this.bbar.getHeight() : 0);
  2252. return h;
  2253. },
  2254. adjustBodyWidth: function(w){
  2255. return w - this.tabWidth;
  2256. }
  2257. });
  2258. Ext.reg('grouptabpanel', Ext.ux.GroupTabPanel);/*
  2259. * Note that this control will most likely remain as an example, and not as a core Ext form
  2260. * control. However, the API will be changing in a future release and so should not yet be
  2261. * treated as a final, stable API at this time.
  2262. */
  2263. /**
  2264. * @class Ext.ux.form.ItemSelector
  2265. * @extends Ext.form.Field
  2266. * A control that allows selection of between two Ext.ux.form.MultiSelect controls.
  2267. *
  2268. * @history
  2269. * 2008-06-19 bpm Original code contributed by Toby Stuart (with contributions from Robert Williams)
  2270. *
  2271. * @constructor
  2272. * Create a new ItemSelector
  2273. * @param {Object} config Configuration options
  2274. * @xtype itemselector
  2275. */
  2276. Ext.ux.form.ItemSelector = Ext.extend(Ext.form.Field, {
  2277. hideNavIcons:false,
  2278. imagePath:"",
  2279. iconUp:"up2.gif",
  2280. iconDown:"down2.gif",
  2281. iconLeft:"left2.gif",
  2282. iconRight:"right2.gif",
  2283. iconTop:"top2.gif",
  2284. iconBottom:"bottom2.gif",
  2285. drawUpIcon:true,
  2286. drawDownIcon:true,
  2287. drawLeftIcon:true,
  2288. drawRightIcon:true,
  2289. drawTopIcon:true,
  2290. drawBotIcon:true,
  2291. delimiter:',',
  2292. bodyStyle:null,
  2293. border:false,
  2294. defaultAutoCreate:{tag: "div"},
  2295. /**
  2296. * @cfg {Array} multiselects An array of {@link Ext.ux.form.MultiSelect} config objects, with at least all required parameters (e.g., store)
  2297. */
  2298. multiselects:null,
  2299. initComponent: function(){
  2300. Ext.ux.form.ItemSelector.superclass.initComponent.call(this);
  2301. this.addEvents({
  2302. 'rowdblclick' : true,
  2303. 'change' : true
  2304. });
  2305. },
  2306. onRender: function(ct, position){
  2307. Ext.ux.form.ItemSelector.superclass.onRender.call(this, ct, position);
  2308. // Internal default configuration for both multiselects
  2309. var msConfig = [{
  2310. legend: 'Available',
  2311. draggable: true,
  2312. droppable: true,
  2313. width: 100,
  2314. height: 100
  2315. },{
  2316. legend: 'Selected',
  2317. droppable: true,
  2318. draggable: true,
  2319. width: 100,
  2320. height: 100
  2321. }];
  2322. this.fromMultiselect = new Ext.ux.form.MultiSelect(Ext.applyIf(this.multiselects[0], msConfig[0]));
  2323. this.fromMultiselect.on('dblclick', this.onRowDblClick, this);
  2324. this.toMultiselect = new Ext.ux.form.MultiSelect(Ext.applyIf(this.multiselects[1], msConfig[1]));
  2325. this.toMultiselect.on('dblclick', this.onRowDblClick, this);
  2326. var p = new Ext.Panel({
  2327. bodyStyle:this.bodyStyle,
  2328. border:this.border,
  2329. layout:"table",
  2330. layoutConfig:{columns:3}
  2331. });
  2332. p.add(this.fromMultiselect);
  2333. var icons = new Ext.Panel({header:false});
  2334. p.add(icons);
  2335. p.add(this.toMultiselect);
  2336. p.render(this.el);
  2337. icons.el.down('.'+icons.bwrapCls).remove();
  2338. // ICON HELL!!!
  2339. if (this.imagePath!="" && this.imagePath.charAt(this.imagePath.length-1)!="/")
  2340. this.imagePath+="/";
  2341. this.iconUp = this.imagePath + (this.iconUp || 'up2.gif');
  2342. this.iconDown = this.imagePath + (this.iconDown || 'down2.gif');
  2343. this.iconLeft = this.imagePath + (this.iconLeft || 'left2.gif');
  2344. this.iconRight = this.imagePath + (this.iconRight || 'right2.gif');
  2345. this.iconTop = this.imagePath + (this.iconTop || 'top2.gif');
  2346. this.iconBottom = this.imagePath + (this.iconBottom || 'bottom2.gif');
  2347. var el=icons.getEl();
  2348. this.toTopIcon = el.createChild({tag:'img', src:this.iconTop, style:{cursor:'pointer', margin:'2px'}});
  2349. el.createChild({tag: 'br'});
  2350. this.upIcon = el.createChild({tag:'img', src:this.iconUp, style:{cursor:'pointer', margin:'2px'}});
  2351. el.createChild({tag: 'br'});
  2352. this.addIcon = el.createChild({tag:'img', src:this.iconRight, style:{cursor:'pointer', margin:'2px'}});
  2353. el.createChild({tag: 'br'});
  2354. this.removeIcon = el.createChild({tag:'img', src:this.iconLeft, style:{cursor:'pointer', margin:'2px'}});
  2355. el.createChild({tag: 'br'});
  2356. this.downIcon = el.createChild({tag:'img', src:this.iconDown, style:{cursor:'pointer', margin:'2px'}});
  2357. el.createChild({tag: 'br'});
  2358. this.toBottomIcon = el.createChild({tag:'img', src:this.iconBottom, style:{cursor:'pointer', margin:'2px'}});
  2359. this.toTopIcon.on('click', this.toTop, this);
  2360. this.upIcon.on('click', this.up, this);
  2361. this.downIcon.on('click', this.down, this);
  2362. this.toBottomIcon.on('click', this.toBottom, this);
  2363. this.addIcon.on('click', this.fromTo, this);
  2364. this.removeIcon.on('click', this.toFrom, this);
  2365. if (!this.drawUpIcon || this.hideNavIcons) { this.upIcon.dom.style.display='none'; }
  2366. if (!this.drawDownIcon || this.hideNavIcons) { this.downIcon.dom.style.display='none'; }
  2367. if (!this.drawLeftIcon || this.hideNavIcons) { this.addIcon.dom.style.display='none'; }
  2368. if (!this.drawRightIcon || this.hideNavIcons) { this.removeIcon.dom.style.display='none'; }
  2369. if (!this.drawTopIcon || this.hideNavIcons) { this.toTopIcon.dom.style.display='none'; }
  2370. if (!this.drawBotIcon || this.hideNavIcons) { this.toBottomIcon.dom.style.display='none'; }
  2371. var tb = p.body.first();
  2372. this.el.setWidth(p.body.first().getWidth());
  2373. p.body.removeClass();
  2374. this.hiddenName = this.name;
  2375. var hiddenTag = {tag: "input", type: "hidden", value: "", name: this.name};
  2376. this.hiddenField = this.el.createChild(hiddenTag);
  2377. },
  2378. doLayout: function(){
  2379. if(this.rendered){
  2380. this.fromMultiselect.fs.doLayout();
  2381. this.toMultiselect.fs.doLayout();
  2382. }
  2383. },
  2384. afterRender: function(){
  2385. Ext.ux.form.ItemSelector.superclass.afterRender.call(this);
  2386. this.toStore = this.toMultiselect.store;
  2387. this.toStore.on('add', this.valueChanged, this);
  2388. this.toStore.on('remove', this.valueChanged, this);
  2389. this.toStore.on('load', this.valueChanged, this);
  2390. this.valueChanged(this.toStore);
  2391. },
  2392. toTop : function() {
  2393. var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  2394. var records = [];
  2395. if (selectionsArray.length > 0) {
  2396. selectionsArray.sort();
  2397. for (var i=0; i<selectionsArray.length; i++) {
  2398. record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  2399. records.push(record);
  2400. }
  2401. selectionsArray = [];
  2402. for (var i=records.length-1; i>-1; i--) {
  2403. record = records[i];
  2404. this.toMultiselect.view.store.remove(record);
  2405. this.toMultiselect.view.store.insert(0, record);
  2406. selectionsArray.push(((records.length - 1) - i));
  2407. }
  2408. }
  2409. this.toMultiselect.view.refresh();
  2410. this.toMultiselect.view.select(selectionsArray);
  2411. },
  2412. toBottom : function() {
  2413. var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  2414. var records = [];
  2415. if (selectionsArray.length > 0) {
  2416. selectionsArray.sort();
  2417. for (var i=0; i<selectionsArray.length; i++) {
  2418. record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  2419. records.push(record);
  2420. }
  2421. selectionsArray = [];
  2422. for (var i=0; i<records.length; i++) {
  2423. record = records[i];
  2424. this.toMultiselect.view.store.remove(record);
  2425. this.toMultiselect.view.store.add(record);
  2426. selectionsArray.push((this.toMultiselect.view.store.getCount()) - (records.length - i));
  2427. }
  2428. }
  2429. this.toMultiselect.view.refresh();
  2430. this.toMultiselect.view.select(selectionsArray);
  2431. },
  2432. up : function() {
  2433. var record = null;
  2434. var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  2435. selectionsArray.sort();
  2436. var newSelectionsArray = [];
  2437. if (selectionsArray.length > 0) {
  2438. for (var i=0; i<selectionsArray.length; i++) {
  2439. record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  2440. if ((selectionsArray[i] - 1) >= 0) {
  2441. this.toMultiselect.view.store.remove(record);
  2442. this.toMultiselect.view.store.insert(selectionsArray[i] - 1, record);
  2443. newSelectionsArray.push(selectionsArray[i] - 1);
  2444. }
  2445. }
  2446. this.toMultiselect.view.refresh();
  2447. this.toMultiselect.view.select(newSelectionsArray);
  2448. }
  2449. },
  2450. down : function() {
  2451. var record = null;
  2452. var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  2453. selectionsArray.sort();
  2454. selectionsArray.reverse();
  2455. var newSelectionsArray = [];
  2456. if (selectionsArray.length > 0) {
  2457. for (var i=0; i<selectionsArray.length; i++) {
  2458. record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  2459. if ((selectionsArray[i] + 1) < this.toMultiselect.view.store.getCount()) {
  2460. this.toMultiselect.view.store.remove(record);
  2461. this.toMultiselect.view.store.insert(selectionsArray[i] + 1, record);
  2462. newSelectionsArray.push(selectionsArray[i] + 1);
  2463. }
  2464. }
  2465. this.toMultiselect.view.refresh();
  2466. this.toMultiselect.view.select(newSelectionsArray);
  2467. }
  2468. },
  2469. fromTo : function() {
  2470. var selectionsArray = this.fromMultiselect.view.getSelectedIndexes();
  2471. var records = [];
  2472. if (selectionsArray.length > 0) {
  2473. for (var i=0; i<selectionsArray.length; i++) {
  2474. record = this.fromMultiselect.view.store.getAt(selectionsArray[i]);
  2475. records.push(record);
  2476. }
  2477. if(!this.allowDup)selectionsArray = [];
  2478. for (var i=0; i<records.length; i++) {
  2479. record = records[i];
  2480. if(this.allowDup){
  2481. var x=new Ext.data.Record();
  2482. record.id=x.id;
  2483. delete x;
  2484. this.toMultiselect.view.store.add(record);
  2485. }else{
  2486. this.fromMultiselect.view.store.remove(record);
  2487. this.toMultiselect.view.store.add(record);
  2488. selectionsArray.push((this.toMultiselect.view.store.getCount() - 1));
  2489. }
  2490. }
  2491. }
  2492. this.toMultiselect.view.refresh();
  2493. this.fromMultiselect.view.refresh();
  2494. var si = this.toMultiselect.store.sortInfo;
  2495. if(si){
  2496. this.toMultiselect.store.sort(si.field, si.direction);
  2497. }
  2498. this.toMultiselect.view.select(selectionsArray);
  2499. },
  2500. toFrom : function() {
  2501. var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  2502. var records = [];
  2503. if (selectionsArray.length > 0) {
  2504. for (var i=0; i<selectionsArray.length; i++) {
  2505. record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  2506. records.push(record);
  2507. }
  2508. selectionsArray = [];
  2509. for (var i=0; i<records.length; i++) {
  2510. record = records[i];
  2511. this.toMultiselect.view.store.remove(record);
  2512. if(!this.allowDup){
  2513. this.fromMultiselect.view.store.add(record);
  2514. selectionsArray.push((this.fromMultiselect.view.store.getCount() - 1));
  2515. }
  2516. }
  2517. }
  2518. this.fromMultiselect.view.refresh();
  2519. this.toMultiselect.view.refresh();
  2520. var si = this.fromMultiselect.store.sortInfo;
  2521. if (si){
  2522. this.fromMultiselect.store.sort(si.field, si.direction);
  2523. }
  2524. this.fromMultiselect.view.select(selectionsArray);
  2525. },
  2526. valueChanged: function(store) {
  2527. var record = null;
  2528. var values = [];
  2529. for (var i=0; i<store.getCount(); i++) {
  2530. record = store.getAt(i);
  2531. values.push(record.get(this.toMultiselect.valueField));
  2532. }
  2533. this.hiddenField.dom.value = values.join(this.delimiter);
  2534. this.fireEvent('change', this, this.getValue(), this.hiddenField.dom.value);
  2535. },
  2536. getValue : function() {
  2537. return this.hiddenField.dom.value;
  2538. },
  2539. onRowDblClick : function(vw, index, node, e) {
  2540. if (vw == this.toMultiselect.view){
  2541. this.toFrom();
  2542. } else if (vw == this.fromMultiselect.view) {
  2543. this.fromTo();
  2544. }
  2545. return this.fireEvent('rowdblclick', vw, index, node, e);
  2546. },
  2547. reset: function(){
  2548. range = this.toMultiselect.store.getRange();
  2549. this.toMultiselect.store.removeAll();
  2550. this.fromMultiselect.store.add(range);
  2551. var si = this.fromMultiselect.store.sortInfo;
  2552. if (si){
  2553. this.fromMultiselect.store.sort(si.field, si.direction);
  2554. }
  2555. this.valueChanged(this.toMultiselect.store);
  2556. }
  2557. });
  2558. Ext.reg('itemselector', Ext.ux.form.ItemSelector);
  2559. //backwards compat
  2560. Ext.ux.ItemSelector = Ext.ux.form.ItemSelector;
  2561. Ext.ns('Ext.ux.form');
  2562. /**
  2563. * @class Ext.ux.form.MultiSelect
  2564. * @extends Ext.form.Field
  2565. * A control that allows selection and form submission of multiple list items.
  2566. *
  2567. * @history
  2568. * 2008-06-19 bpm Original code contributed by Toby Stuart (with contributions from Robert Williams)
  2569. * 2008-06-19 bpm Docs and demo code clean up
  2570. *
  2571. * @constructor
  2572. * Create a new MultiSelect
  2573. * @param {Object} config Configuration options
  2574. * @xtype multiselect
  2575. */
  2576. Ext.ux.form.MultiSelect = Ext.extend(Ext.form.Field, {
  2577. /**
  2578. * @cfg {String} legend Wraps the object with a fieldset and specified legend.
  2579. */
  2580. /**
  2581. * @cfg {Ext.ListView} view The {@link Ext.ListView} used to render the multiselect list.
  2582. */
  2583. /**
  2584. * @cfg {String/Array} dragGroup The ddgroup name(s) for the MultiSelect DragZone (defaults to undefined).
  2585. */
  2586. /**
  2587. * @cfg {String/Array} dropGroup The ddgroup name(s) for the MultiSelect DropZone (defaults to undefined).
  2588. */
  2589. /**
  2590. * @cfg {Boolean} ddReorder Whether the items in the MultiSelect list are drag/drop reorderable (defaults to false).
  2591. */
  2592. ddReorder:false,
  2593. /**
  2594. * @cfg {Object/Array} tbar The top toolbar of the control. This can be a {@link Ext.Toolbar} object, a
  2595. * toolbar config, or an array of buttons/button configs to be added to the toolbar.
  2596. */
  2597. /**
  2598. * @cfg {String} appendOnly True if the list should only allow append drops when drag/drop is enabled
  2599. * (use for lists which are sorted, defaults to false).
  2600. */
  2601. appendOnly:false,
  2602. /**
  2603. * @cfg {Number} width Width in pixels of the control (defaults to 100).
  2604. */
  2605. width:100,
  2606. /**
  2607. * @cfg {Number} height Height in pixels of the control (defaults to 100).
  2608. */
  2609. height:100,
  2610. /**
  2611. * @cfg {String/Number} displayField Name/Index of the desired display field in the dataset (defaults to 0).
  2612. */
  2613. displayField:0,
  2614. /**
  2615. * @cfg {String/Number} valueField Name/Index of the desired value field in the dataset (defaults to 1).
  2616. */
  2617. valueField:1,
  2618. /**
  2619. * @cfg {Boolean} allowBlank False to require at least one item in the list to be selected, true to allow no
  2620. * selection (defaults to true).
  2621. */
  2622. allowBlank:true,
  2623. /**
  2624. * @cfg {Number} minSelections Minimum number of selections allowed (defaults to 0).
  2625. */
  2626. minSelections:0,
  2627. /**
  2628. * @cfg {Number} maxSelections Maximum number of selections allowed (defaults to Number.MAX_VALUE).
  2629. */
  2630. maxSelections:Number.MAX_VALUE,
  2631. /**
  2632. * @cfg {String} blankText Default text displayed when the control contains no items (defaults to the same value as
  2633. * {@link Ext.form.TextField#blankText}.
  2634. */
  2635. blankText:Ext.form.TextField.prototype.blankText,
  2636. /**
  2637. * @cfg {String} minSelectionsText Validation message displayed when {@link #minSelections} is not met (defaults to 'Minimum {0}
  2638. * item(s) required'). The {0} token will be replaced by the value of {@link #minSelections}.
  2639. */
  2640. minSelectionsText:'Minimum {0} item(s) required',
  2641. /**
  2642. * @cfg {String} maxSelectionsText Validation message displayed when {@link #maxSelections} is not met (defaults to 'Maximum {0}
  2643. * item(s) allowed'). The {0} token will be replaced by the value of {@link #maxSelections}.
  2644. */
  2645. maxSelectionsText:'Maximum {0} item(s) allowed',
  2646. /**
  2647. * @cfg {String} delimiter The string used to delimit between items when set or returned as a string of values
  2648. * (defaults to ',').
  2649. */
  2650. delimiter:',',
  2651. /**
  2652. * @cfg {Ext.data.Store/Array} store The data source to which this MultiSelect is bound (defaults to <tt>undefined</tt>).
  2653. * Acceptable values for this property are:
  2654. * <div class="mdetail-params"><ul>
  2655. * <li><b>any {@link Ext.data.Store Store} subclass</b></li>
  2656. * <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.ArrayStore} internally.
  2657. * <div class="mdetail-params"><ul>
  2658. * <li><b>1-dimensional array</b> : (e.g., <tt>['Foo','Bar']</tt>)<div class="sub-desc">
  2659. * A 1-dimensional array will automatically be expanded (each array item will be the combo
  2660. * {@link #valueField value} and {@link #displayField text})</div></li>
  2661. * <li><b>2-dimensional array</b> : (e.g., <tt>[['f','Foo'],['b','Bar']]</tt>)<div class="sub-desc">
  2662. * For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
  2663. * {@link #valueField value}, while the value at index 1 is assumed to be the combo {@link #displayField text}.
  2664. * </div></li></ul></div></li></ul></div>
  2665. */
  2666. // private
  2667. defaultAutoCreate : {tag: "div"},
  2668. // private
  2669. initComponent: function(){
  2670. Ext.ux.form.MultiSelect.superclass.initComponent.call(this);
  2671. if(Ext.isArray(this.store)){
  2672. if (Ext.isArray(this.store[0])){
  2673. this.store = new Ext.data.ArrayStore({
  2674. fields: ['value','text'],
  2675. data: this.store
  2676. });
  2677. this.valueField = 'value';
  2678. }else{
  2679. this.store = new Ext.data.ArrayStore({
  2680. fields: ['text'],
  2681. data: this.store,
  2682. expandData: true
  2683. });
  2684. this.valueField = 'text';
  2685. }
  2686. this.displayField = 'text';
  2687. } else {
  2688. this.store = Ext.StoreMgr.lookup(this.store);
  2689. }
  2690. this.addEvents({
  2691. 'dblclick' : true,
  2692. 'click' : true,
  2693. 'change' : true,
  2694. 'drop' : true
  2695. });
  2696. },
  2697. // private
  2698. onRender: function(ct, position){
  2699. Ext.ux.form.MultiSelect.superclass.onRender.call(this, ct, position);
  2700. var fs = this.fs = new Ext.form.FieldSet({
  2701. renderTo: this.el,
  2702. title: this.legend,
  2703. height: this.height,
  2704. width: this.width,
  2705. style: "padding:0;",
  2706. tbar: this.tbar,
  2707. bodyStyle: 'overflow: auto;'
  2708. });
  2709. this.view = new Ext.ListView({
  2710. multiSelect: true,
  2711. store: this.store,
  2712. columns: [{ header: 'Value', width: 1, dataIndex: this.displayField }],
  2713. hideHeaders: true
  2714. });
  2715. fs.add(this.view);
  2716. this.view.on('click', this.onViewClick, this);
  2717. this.view.on('beforeclick', this.onViewBeforeClick, this);
  2718. this.view.on('dblclick', this.onViewDblClick, this);
  2719. this.hiddenName = this.name || Ext.id();
  2720. var hiddenTag = { tag: "input", type: "hidden", value: "", name: this.hiddenName };
  2721. this.hiddenField = this.el.createChild(hiddenTag);
  2722. this.hiddenField.dom.disabled = this.hiddenName != this.name;
  2723. fs.doLayout();
  2724. },
  2725. // private
  2726. afterRender: function(){
  2727. Ext.ux.form.MultiSelect.superclass.afterRender.call(this);
  2728. if (this.ddReorder && !this.dragGroup && !this.dropGroup){
  2729. this.dragGroup = this.dropGroup = 'MultiselectDD-' + Ext.id();
  2730. }
  2731. if (this.draggable || this.dragGroup){
  2732. this.dragZone = new Ext.ux.form.MultiSelect.DragZone(this, {
  2733. ddGroup: this.dragGroup
  2734. });
  2735. }
  2736. if (this.droppable || this.dropGroup){
  2737. this.dropZone = new Ext.ux.form.MultiSelect.DropZone(this, {
  2738. ddGroup: this.dropGroup
  2739. });
  2740. }
  2741. },
  2742. // private
  2743. onViewClick: function(vw, index, node, e) {
  2744. this.fireEvent('change', this, this.getValue(), this.hiddenField.dom.value);
  2745. this.hiddenField.dom.value = this.getValue();
  2746. this.fireEvent('click', this, e);
  2747. this.validate();
  2748. },
  2749. // private
  2750. onViewBeforeClick: function(vw, index, node, e) {
  2751. if (this.disabled) {return false;}
  2752. },
  2753. // private
  2754. onViewDblClick : function(vw, index, node, e) {
  2755. return this.fireEvent('dblclick', vw, index, node, e);
  2756. },
  2757. /**
  2758. * Returns an array of data values for the selected items in the list. The values will be separated
  2759. * by {@link #delimiter}.
  2760. * @return {Array} value An array of string data values
  2761. */
  2762. getValue: function(valueField){
  2763. var returnArray = [];
  2764. var selectionsArray = this.view.getSelectedIndexes();
  2765. if (selectionsArray.length == 0) {return '';}
  2766. for (var i=0; i<selectionsArray.length; i++) {
  2767. returnArray.push(this.store.getAt(selectionsArray[i]).get((valueField != null) ? valueField : this.valueField));
  2768. }
  2769. return returnArray.join(this.delimiter);
  2770. },
  2771. /**
  2772. * Sets a delimited string (using {@link #delimiter}) or array of data values into the list.
  2773. * @param {String/Array} values The values to set
  2774. */
  2775. setValue: function(values) {
  2776. var index;
  2777. var selections = [];
  2778. this.view.clearSelections();
  2779. this.hiddenField.dom.value = '';
  2780. if (!values || (values == '')) { return; }
  2781. if (!Ext.isArray(values)) { values = values.split(this.delimiter); }
  2782. for (var i=0; i<values.length; i++) {
  2783. index = this.view.store.indexOf(this.view.store.query(this.valueField,
  2784. new RegExp('^' + values[i] + '$', "i")).itemAt(0));
  2785. selections.push(index);
  2786. }
  2787. this.view.select(selections);
  2788. this.hiddenField.dom.value = this.getValue();
  2789. this.validate();
  2790. },
  2791. // inherit docs
  2792. reset : function() {
  2793. this.setValue('');
  2794. },
  2795. // inherit docs
  2796. getRawValue: function(valueField) {
  2797. var tmp = this.getValue(valueField);
  2798. if (tmp.length) {
  2799. tmp = tmp.split(this.delimiter);
  2800. }
  2801. else {
  2802. tmp = [];
  2803. }
  2804. return tmp;
  2805. },
  2806. // inherit docs
  2807. setRawValue: function(values){
  2808. setValue(values);
  2809. },
  2810. // inherit docs
  2811. validateValue : function(value){
  2812. if (value.length < 1) { // if it has no value
  2813. if (this.allowBlank) {
  2814. this.clearInvalid();
  2815. return true;
  2816. } else {
  2817. this.markInvalid(this.blankText);
  2818. return false;
  2819. }
  2820. }
  2821. if (value.length < this.minSelections) {
  2822. this.markInvalid(String.format(this.minSelectionsText, this.minSelections));
  2823. return false;
  2824. }
  2825. if (value.length > this.maxSelections) {
  2826. this.markInvalid(String.format(this.maxSelectionsText, this.maxSelections));
  2827. return false;
  2828. }
  2829. return true;
  2830. },
  2831. // inherit docs
  2832. disable: function(){
  2833. this.disabled = true;
  2834. this.hiddenField.dom.disabled = true;
  2835. this.fs.disable();
  2836. },
  2837. // inherit docs
  2838. enable: function(){
  2839. this.disabled = false;
  2840. this.hiddenField.dom.disabled = false;
  2841. this.fs.enable();
  2842. },
  2843. // inherit docs
  2844. destroy: function(){
  2845. Ext.destroy(this.fs, this.dragZone, this.dropZone);
  2846. Ext.ux.form.MultiSelect.superclass.destroy.call(this);
  2847. }
  2848. });
  2849. Ext.reg('multiselect', Ext.ux.form.MultiSelect);
  2850. //backwards compat
  2851. Ext.ux.Multiselect = Ext.ux.form.MultiSelect;
  2852. Ext.ux.form.MultiSelect.DragZone = function(ms, config){
  2853. this.ms = ms;
  2854. this.view = ms.view;
  2855. var ddGroup = config.ddGroup || 'MultiselectDD';
  2856. var dd;
  2857. if (Ext.isArray(ddGroup)){
  2858. dd = ddGroup.shift();
  2859. } else {
  2860. dd = ddGroup;
  2861. ddGroup = null;
  2862. }
  2863. Ext.ux.form.MultiSelect.DragZone.superclass.constructor.call(this, this.ms.fs.body, { containerScroll: true, ddGroup: dd });
  2864. this.setDraggable(ddGroup);
  2865. };
  2866. Ext.extend(Ext.ux.form.MultiSelect.DragZone, Ext.dd.DragZone, {
  2867. onInitDrag : function(x, y){
  2868. var el = Ext.get(this.dragData.ddel.cloneNode(true));
  2869. this.proxy.update(el.dom);
  2870. el.setWidth(el.child('em').getWidth());
  2871. this.onStartDrag(x, y);
  2872. return true;
  2873. },
  2874. // private
  2875. collectSelection: function(data) {
  2876. data.repairXY = Ext.fly(this.view.getSelectedNodes()[0]).getXY();
  2877. var i = 0;
  2878. this.view.store.each(function(rec){
  2879. if (this.view.isSelected(i)) {
  2880. var n = this.view.getNode(i);
  2881. var dragNode = n.cloneNode(true);
  2882. dragNode.id = Ext.id();
  2883. data.ddel.appendChild(dragNode);
  2884. data.records.push(this.view.store.getAt(i));
  2885. data.viewNodes.push(n);
  2886. }
  2887. i++;
  2888. }, this);
  2889. },
  2890. // override
  2891. onEndDrag: function(data, e) {
  2892. var d = Ext.get(this.dragData.ddel);
  2893. if (d && d.hasClass("multi-proxy")) {
  2894. d.remove();
  2895. }
  2896. },
  2897. // override
  2898. getDragData: function(e){
  2899. var target = this.view.findItemFromChild(e.getTarget());
  2900. if(target) {
  2901. if (!this.view.isSelected(target) && !e.ctrlKey && !e.shiftKey) {
  2902. this.view.select(target);
  2903. this.ms.setValue(this.ms.getValue());
  2904. }
  2905. if (this.view.getSelectionCount() == 0 || e.ctrlKey || e.shiftKey) return false;
  2906. var dragData = {
  2907. sourceView: this.view,
  2908. viewNodes: [],
  2909. records: []
  2910. };
  2911. if (this.view.getSelectionCount() == 1) {
  2912. var i = this.view.getSelectedIndexes()[0];
  2913. var n = this.view.getNode(i);
  2914. dragData.viewNodes.push(dragData.ddel = n);
  2915. dragData.records.push(this.view.store.getAt(i));
  2916. dragData.repairXY = Ext.fly(n).getXY();
  2917. } else {
  2918. dragData.ddel = document.createElement('div');
  2919. dragData.ddel.className = 'multi-proxy';
  2920. this.collectSelection(dragData);
  2921. }
  2922. return dragData;
  2923. }
  2924. return false;
  2925. },
  2926. // override the default repairXY.
  2927. getRepairXY : function(e){
  2928. return this.dragData.repairXY;
  2929. },
  2930. // private
  2931. setDraggable: function(ddGroup){
  2932. if (!ddGroup) return;
  2933. if (Ext.isArray(ddGroup)) {
  2934. Ext.each(ddGroup, this.setDraggable, this);
  2935. return;
  2936. }
  2937. this.addToGroup(ddGroup);
  2938. }
  2939. });
  2940. Ext.ux.form.MultiSelect.DropZone = function(ms, config){
  2941. this.ms = ms;
  2942. this.view = ms.view;
  2943. var ddGroup = config.ddGroup || 'MultiselectDD';
  2944. var dd;
  2945. if (Ext.isArray(ddGroup)){
  2946. dd = ddGroup.shift();
  2947. } else {
  2948. dd = ddGroup;
  2949. ddGroup = null;
  2950. }
  2951. Ext.ux.form.MultiSelect.DropZone.superclass.constructor.call(this, this.ms.fs.body, { containerScroll: true, ddGroup: dd });
  2952. this.setDroppable(ddGroup);
  2953. };
  2954. Ext.extend(Ext.ux.form.MultiSelect.DropZone, Ext.dd.DropZone, {
  2955. /**
  2956. * Part of the Ext.dd.DropZone interface. If no target node is found, the
  2957. * whole Element becomes the target, and this causes the drop gesture to append.
  2958. */
  2959. getTargetFromEvent : function(e) {
  2960. var target = e.getTarget();
  2961. return target;
  2962. },
  2963. // private
  2964. getDropPoint : function(e, n, dd){
  2965. if (n == this.ms.fs.body.dom) { return "below"; }
  2966. var t = Ext.lib.Dom.getY(n), b = t + n.offsetHeight;
  2967. var c = t + (b - t) / 2;
  2968. var y = Ext.lib.Event.getPageY(e);
  2969. if(y <= c) {
  2970. return "above";
  2971. }else{
  2972. return "below";
  2973. }
  2974. },
  2975. // private
  2976. isValidDropPoint: function(pt, n, data) {
  2977. if (!data.viewNodes || (data.viewNodes.length != 1)) {
  2978. return true;
  2979. }
  2980. var d = data.viewNodes[0];
  2981. if (d == n) {
  2982. return false;
  2983. }
  2984. if ((pt == "below") && (n.nextSibling == d)) {
  2985. return false;
  2986. }
  2987. if ((pt == "above") && (n.previousSibling == d)) {
  2988. return false;
  2989. }
  2990. return true;
  2991. },
  2992. // override
  2993. onNodeEnter : function(n, dd, e, data){
  2994. return false;
  2995. },
  2996. // override
  2997. onNodeOver : function(n, dd, e, data){
  2998. var dragElClass = this.dropNotAllowed;
  2999. var pt = this.getDropPoint(e, n, dd);
  3000. if (this.isValidDropPoint(pt, n, data)) {
  3001. if (this.ms.appendOnly) {
  3002. return "x-tree-drop-ok-below";
  3003. }
  3004. // set the insert point style on the target node
  3005. if (pt) {
  3006. var targetElClass;
  3007. if (pt == "above"){
  3008. dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
  3009. targetElClass = "x-view-drag-insert-above";
  3010. } else {
  3011. dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
  3012. targetElClass = "x-view-drag-insert-below";
  3013. }
  3014. if (this.lastInsertClass != targetElClass){
  3015. Ext.fly(n).replaceClass(this.lastInsertClass, targetElClass);
  3016. this.lastInsertClass = targetElClass;
  3017. }
  3018. }
  3019. }
  3020. return dragElClass;
  3021. },
  3022. // private
  3023. onNodeOut : function(n, dd, e, data){
  3024. this.removeDropIndicators(n);
  3025. },
  3026. // private
  3027. onNodeDrop : function(n, dd, e, data){
  3028. if (this.ms.fireEvent("drop", this, n, dd, e, data) === false) {
  3029. return false;
  3030. }
  3031. var pt = this.getDropPoint(e, n, dd);
  3032. if (n != this.ms.fs.body.dom)
  3033. n = this.view.findItemFromChild(n);
  3034. var insertAt = (this.ms.appendOnly || (n == this.ms.fs.body.dom)) ? this.view.store.getCount() : this.view.indexOf(n);
  3035. if (pt == "below") {
  3036. insertAt++;
  3037. }
  3038. var dir = false;
  3039. // Validate if dragging within the same MultiSelect
  3040. if (data.sourceView == this.view) {
  3041. // If the first element to be inserted below is the target node, remove it
  3042. if (pt == "below") {
  3043. if (data.viewNodes[0] == n) {
  3044. data.viewNodes.shift();
  3045. }
  3046. } else { // If the last element to be inserted above is the target node, remove it
  3047. if (data.viewNodes[data.viewNodes.length - 1] == n) {
  3048. data.viewNodes.pop();
  3049. }
  3050. }
  3051. // Nothing to drop...
  3052. if (!data.viewNodes.length) {
  3053. return false;
  3054. }
  3055. // If we are moving DOWN, then because a store.remove() takes place first,
  3056. // the insertAt must be decremented.
  3057. if (insertAt > this.view.store.indexOf(data.records[0])) {
  3058. dir = 'down';
  3059. insertAt--;
  3060. }
  3061. }
  3062. for (var i = 0; i < data.records.length; i++) {
  3063. var r = data.records[i];
  3064. if (data.sourceView) {
  3065. data.sourceView.store.remove(r);
  3066. }
  3067. this.view.store.insert(dir == 'down' ? insertAt : insertAt++, r);
  3068. var si = this.view.store.sortInfo;
  3069. if(si){
  3070. this.view.store.sort(si.field, si.direction);
  3071. }
  3072. }
  3073. return true;
  3074. },
  3075. // private
  3076. removeDropIndicators : function(n){
  3077. if(n){
  3078. Ext.fly(n).removeClass([
  3079. "x-view-drag-insert-above",
  3080. "x-view-drag-insert-left",
  3081. "x-view-drag-insert-right",
  3082. "x-view-drag-insert-below"]);
  3083. this.lastInsertClass = "_noclass";
  3084. }
  3085. },
  3086. // private
  3087. setDroppable: function(ddGroup){
  3088. if (!ddGroup) return;
  3089. if (Ext.isArray(ddGroup)) {
  3090. Ext.each(ddGroup, this.setDroppable, this);
  3091. return;
  3092. }
  3093. this.addToGroup(ddGroup);
  3094. }
  3095. });
  3096. /* Fix for Opera, which does not seem to include the map function on Array's */
  3097. if (!Array.prototype.map) {
  3098. Array.prototype.map = function(fun){
  3099. var len = this.length;
  3100. if (typeof fun != 'function') {
  3101. throw new TypeError();
  3102. }
  3103. var res = new Array(len);
  3104. var thisp = arguments[1];
  3105. for (var i = 0; i < len; i++) {
  3106. if (i in this) {
  3107. res[i] = fun.call(thisp, this[i], i, this);
  3108. }
  3109. }
  3110. return res;
  3111. };
  3112. }
  3113. Ext.ns('Ext.ux.data');
  3114. /**
  3115. * @class Ext.ux.data.PagingMemoryProxy
  3116. * @extends Ext.data.MemoryProxy
  3117. * <p>Paging Memory Proxy, allows to use paging grid with in memory dataset</p>
  3118. */
  3119. Ext.ux.data.PagingMemoryProxy = Ext.extend(Ext.data.MemoryProxy, {
  3120. constructor : function(data){
  3121. Ext.ux.data.PagingMemoryProxy.superclass.constructor.call(this);
  3122. this.data = data;
  3123. },
  3124. doRequest : function(action, rs, params, reader, callback, scope, options){
  3125. params = params ||
  3126. {};
  3127. var result;
  3128. try {
  3129. result = reader.readRecords(this.data);
  3130. }
  3131. catch (e) {
  3132. this.fireEvent('loadexception', this, options, null, e);
  3133. callback.call(scope, null, options, false);
  3134. return;
  3135. }
  3136. // filtering
  3137. if (params.filter !== undefined) {
  3138. result.records = result.records.filter(function(el){
  3139. if (typeof(el) == 'object') {
  3140. var att = params.filterCol || 0;
  3141. return String(el.data[att]).match(params.filter) ? true : false;
  3142. }
  3143. else {
  3144. return String(el).match(params.filter) ? true : false;
  3145. }
  3146. });
  3147. result.totalRecords = result.records.length;
  3148. }
  3149. // sorting
  3150. if (params.sort !== undefined) {
  3151. // use integer as params.sort to specify column, since arrays are not named
  3152. // params.sort=0; would also match a array without columns
  3153. var dir = String(params.dir).toUpperCase() == 'DESC' ? -1 : 1;
  3154. var fn = function(r1, r2){
  3155. return r1 < r2;
  3156. };
  3157. result.records.sort(function(a, b){
  3158. var v = 0;
  3159. if (typeof(a) == 'object') {
  3160. v = fn(a.data[params.sort], b.data[params.sort]) * dir;
  3161. }
  3162. else {
  3163. v = fn(a, b) * dir;
  3164. }
  3165. if (v == 0) {
  3166. v = (a.index < b.index ? -1 : 1);
  3167. }
  3168. return v;
  3169. });
  3170. }
  3171. // paging (use undefined cause start can also be 0 (thus false))
  3172. if (params.start !== undefined && params.limit !== undefined) {
  3173. result.records = result.records.slice(params.start, params.start + params.limit);
  3174. }
  3175. callback.call(scope, result, options, true);
  3176. }
  3177. });
  3178. //backwards compat.
  3179. Ext.data.PagingMemoryProxy = Ext.ux.data.PagingMemoryProxy;
  3180. Ext.ux.PanelResizer = Ext.extend(Ext.util.Observable, {
  3181. minHeight: 0,
  3182. maxHeight:10000000,
  3183. constructor: function(config){
  3184. Ext.apply(this, config);
  3185. this.events = {};
  3186. Ext.ux.PanelResizer.superclass.constructor.call(this, config);
  3187. },
  3188. init : function(p){
  3189. this.panel = p;
  3190. if(this.panel.elements.indexOf('footer')==-1){
  3191. p.elements += ',footer';
  3192. }
  3193. p.on('render', this.onRender, this);
  3194. },
  3195. onRender : function(p){
  3196. this.handle = p.footer.createChild({cls:'x-panel-resize'});
  3197. this.tracker = new Ext.dd.DragTracker({
  3198. onStart: this.onDragStart.createDelegate(this),
  3199. onDrag: this.onDrag.createDelegate(this),
  3200. onEnd: this.onDragEnd.createDelegate(this),
  3201. tolerance: 3,
  3202. autoStart: 300
  3203. });
  3204. this.tracker.initEl(this.handle);
  3205. p.on('beforedestroy', this.tracker.destroy, this.tracker);
  3206. },
  3207. // private
  3208. onDragStart: function(e){
  3209. this.dragging = true;
  3210. this.startHeight = this.panel.el.getHeight();
  3211. this.fireEvent('dragstart', this, e);
  3212. },
  3213. // private
  3214. onDrag: function(e){
  3215. this.panel.setHeight((this.startHeight-this.tracker.getOffset()[1]).constrain(this.minHeight, this.maxHeight));
  3216. this.fireEvent('drag', this, e);
  3217. },
  3218. // private
  3219. onDragEnd: function(e){
  3220. this.dragging = false;
  3221. this.fireEvent('dragend', this, e);
  3222. }
  3223. });
  3224. Ext.preg('panelresizer', Ext.ux.PanelResizer);Ext.ux.Portal = Ext.extend(Ext.Panel, {
  3225. layout : 'column',
  3226. autoScroll : true,
  3227. cls : 'x-portal',
  3228. defaultType : 'portalcolumn',
  3229. initComponent : function(){
  3230. Ext.ux.Portal.superclass.initComponent.call(this);
  3231. this.addEvents({
  3232. validatedrop:true,
  3233. beforedragover:true,
  3234. dragover:true,
  3235. beforedrop:true,
  3236. drop:true
  3237. });
  3238. },
  3239. initEvents : function(){
  3240. Ext.ux.Portal.superclass.initEvents.call(this);
  3241. this.dd = new Ext.ux.Portal.DropZone(this, this.dropConfig);
  3242. },
  3243. beforeDestroy : function() {
  3244. if(this.dd){
  3245. this.dd.unreg();
  3246. }
  3247. Ext.ux.Portal.superclass.beforeDestroy.call(this);
  3248. }
  3249. });
  3250. Ext.reg('portal', Ext.ux.Portal);
  3251. Ext.ux.Portal.DropZone = function(portal, cfg){
  3252. this.portal = portal;
  3253. Ext.dd.ScrollManager.register(portal.body);
  3254. Ext.ux.Portal.DropZone.superclass.constructor.call(this, portal.bwrap.dom, cfg);
  3255. portal.body.ddScrollConfig = this.ddScrollConfig;
  3256. };
  3257. Ext.extend(Ext.ux.Portal.DropZone, Ext.dd.DropTarget, {
  3258. ddScrollConfig : {
  3259. vthresh: 50,
  3260. hthresh: -1,
  3261. animate: true,
  3262. increment: 200
  3263. },
  3264. createEvent : function(dd, e, data, col, c, pos){
  3265. return {
  3266. portal: this.portal,
  3267. panel: data.panel,
  3268. columnIndex: col,
  3269. column: c,
  3270. position: pos,
  3271. data: data,
  3272. source: dd,
  3273. rawEvent: e,
  3274. status: this.dropAllowed
  3275. };
  3276. },
  3277. notifyOver : function(dd, e, data){
  3278. var xy = e.getXY(), portal = this.portal, px = dd.proxy;
  3279. // case column widths
  3280. if(!this.grid){
  3281. this.grid = this.getGrid();
  3282. }
  3283. // handle case scroll where scrollbars appear during drag
  3284. var cw = portal.body.dom.clientWidth;
  3285. if(!this.lastCW){
  3286. this.lastCW = cw;
  3287. }else if(this.lastCW != cw){
  3288. this.lastCW = cw;
  3289. portal.doLayout();
  3290. this.grid = this.getGrid();
  3291. }
  3292. // determine column
  3293. var col = 0, xs = this.grid.columnX, cmatch = false;
  3294. for(var len = xs.length; col < len; col++){
  3295. if(xy[0] < (xs[col].x + xs[col].w)){
  3296. cmatch = true;
  3297. break;
  3298. }
  3299. }
  3300. // no match, fix last index
  3301. if(!cmatch){
  3302. col--;
  3303. }
  3304. // find insert position
  3305. var p, match = false, pos = 0,
  3306. c = portal.items.itemAt(col),
  3307. items = c.items.items, overSelf = false;
  3308. for(var len = items.length; pos < len; pos++){
  3309. p = items[pos];
  3310. var h = p.el.getHeight();
  3311. if(h === 0){
  3312. overSelf = true;
  3313. }
  3314. else if((p.el.getY()+(h/2)) > xy[1]){
  3315. match = true;
  3316. break;
  3317. }
  3318. }
  3319. pos = (match && p ? pos : c.items.getCount()) + (overSelf ? -1 : 0);
  3320. var overEvent = this.createEvent(dd, e, data, col, c, pos);
  3321. if(portal.fireEvent('validatedrop', overEvent) !== false &&
  3322. portal.fireEvent('beforedragover', overEvent) !== false){
  3323. // make sure proxy width is fluid
  3324. px.getProxy().setWidth('auto');
  3325. if(p){
  3326. px.moveProxy(p.el.dom.parentNode, match ? p.el.dom : null);
  3327. }else{
  3328. px.moveProxy(c.el.dom, null);
  3329. }
  3330. this.lastPos = {c: c, col: col, p: overSelf || (match && p) ? pos : false};
  3331. this.scrollPos = portal.body.getScroll();
  3332. portal.fireEvent('dragover', overEvent);
  3333. return overEvent.status;
  3334. }else{
  3335. return overEvent.status;
  3336. }
  3337. },
  3338. notifyOut : function(){
  3339. delete this.grid;
  3340. },
  3341. notifyDrop : function(dd, e, data){
  3342. delete this.grid;
  3343. if(!this.lastPos){
  3344. return;
  3345. }
  3346. var c = this.lastPos.c, col = this.lastPos.col, pos = this.lastPos.p;
  3347. var dropEvent = this.createEvent(dd, e, data, col, c,
  3348. pos !== false ? pos : c.items.getCount());
  3349. if(this.portal.fireEvent('validatedrop', dropEvent) !== false &&
  3350. this.portal.fireEvent('beforedrop', dropEvent) !== false){
  3351. dd.proxy.getProxy().remove();
  3352. dd.panel.el.dom.parentNode.removeChild(dd.panel.el.dom);
  3353. if(pos !== false){
  3354. if(c == dd.panel.ownerCt && (c.items.items.indexOf(dd.panel) <= pos)){
  3355. pos++;
  3356. }
  3357. c.insert(pos, dd.panel);
  3358. }else{
  3359. c.add(dd.panel);
  3360. }
  3361. c.doLayout();
  3362. this.portal.fireEvent('drop', dropEvent);
  3363. // scroll position is lost on drop, fix it
  3364. var st = this.scrollPos.top;
  3365. if(st){
  3366. var d = this.portal.body.dom;
  3367. setTimeout(function(){
  3368. d.scrollTop = st;
  3369. }, 10);
  3370. }
  3371. }
  3372. delete this.lastPos;
  3373. },
  3374. // internal cache of body and column coords
  3375. getGrid : function(){
  3376. var box = this.portal.bwrap.getBox();
  3377. box.columnX = [];
  3378. this.portal.items.each(function(c){
  3379. box.columnX.push({x: c.el.getX(), w: c.el.getWidth()});
  3380. });
  3381. return box;
  3382. },
  3383. // unregister the dropzone from ScrollManager
  3384. unreg: function() {
  3385. //Ext.dd.ScrollManager.unregister(this.portal.body);
  3386. Ext.ux.Portal.DropZone.superclass.unreg.call(this);
  3387. }
  3388. });
  3389. Ext.ux.PortalColumn = Ext.extend(Ext.Container, {
  3390. layout : 'anchor',
  3391. //autoEl : 'div',//already defined by Ext.Component
  3392. defaultType : 'portlet',
  3393. cls : 'x-portal-column'
  3394. });
  3395. Ext.reg('portalcolumn', Ext.ux.PortalColumn);
  3396. Ext.ux.Portlet = Ext.extend(Ext.Panel, {
  3397. anchor : '100%',
  3398. frame : true,
  3399. collapsible : true,
  3400. draggable : true,
  3401. cls : 'x-portlet'
  3402. });
  3403. Ext.reg('portlet', Ext.ux.Portlet);
  3404. /**
  3405. * @class Ext.ux.ProgressBarPager
  3406. * @extends Object
  3407. * Plugin (ptype = 'tabclosemenu') for displaying a progressbar inside of a paging toolbar instead of plain text
  3408. *
  3409. * @ptype progressbarpager
  3410. * @constructor
  3411. * Create a new ItemSelector
  3412. * @param {Object} config Configuration options
  3413. * @xtype itemselector
  3414. */
  3415. Ext.ux.ProgressBarPager = Ext.extend(Object, {
  3416. /**
  3417. * @cfg {Integer} progBarWidth
  3418. * <p>The default progress bar width. Default is 225.</p>
  3419. */
  3420. progBarWidth : 225,
  3421. /**
  3422. * @cfg {String} defaultText
  3423. * <p>The text to display while the store is loading. Default is 'Loading...'</p>
  3424. */
  3425. defaultText : 'Loading...',
  3426. /**
  3427. * @cfg {Object} defaultAnimCfg
  3428. * <p>A {@link Ext.Fx Ext.Fx} configuration object. Default is { duration : 1, easing : 'bounceOut' }.</p>
  3429. */
  3430. defaultAnimCfg : {
  3431. duration : 1,
  3432. easing : 'bounceOut'
  3433. },
  3434. constructor : function(config) {
  3435. if (config) {
  3436. Ext.apply(this, config);
  3437. }
  3438. },
  3439. //public
  3440. init : function (parent) {
  3441. if(parent.displayInfo){
  3442. this.parent = parent;
  3443. var ind = parent.items.indexOf(parent.displayItem);
  3444. parent.remove(parent.displayItem, true);
  3445. this.progressBar = new Ext.ProgressBar({
  3446. text : this.defaultText,
  3447. width : this.progBarWidth,
  3448. animate : this.defaultAnimCfg
  3449. });
  3450. parent.displayItem = this.progressBar;
  3451. parent.add(parent.displayItem);
  3452. parent.doLayout();
  3453. Ext.apply(parent, this.parentOverrides);
  3454. this.progressBar.on('render', function(pb) {
  3455. pb.el.applyStyles('cursor:pointer');
  3456. pb.el.on('click', this.handleProgressBarClick, this);
  3457. }, this);
  3458. // Remove the click handler from the
  3459. this.progressBar.on({
  3460. scope : this,
  3461. beforeDestroy : function() {
  3462. this.progressBar.el.un('click', this.handleProgressBarClick, this);
  3463. }
  3464. });
  3465. }
  3466. },
  3467. // private
  3468. // This method handles the click for the progress bar
  3469. handleProgressBarClick : function(e){
  3470. var parent = this.parent;
  3471. var displayItem = parent.displayItem;
  3472. var box = this.progressBar.getBox();
  3473. var xy = e.getXY();
  3474. var position = xy[0]-box.x;
  3475. var pages = Math.ceil(parent.store.getTotalCount()/parent.pageSize);
  3476. var newpage = Math.ceil(position/(displayItem.width/pages));
  3477. parent.changePage(newpage);
  3478. },
  3479. // private, overriddes
  3480. parentOverrides : {
  3481. // private
  3482. // This method updates the information via the progress bar.
  3483. updateInfo : function(){
  3484. if(this.displayItem){
  3485. var count = this.store.getCount();
  3486. var pgData = this.getPageData();
  3487. var pageNum = this.readPage(pgData);
  3488. var msg = count == 0 ?
  3489. this.emptyMsg :
  3490. String.format(
  3491. this.displayMsg,
  3492. this.cursor+1, this.cursor+count, this.store.getTotalCount()
  3493. );
  3494. pageNum = pgData.activePage; ;
  3495. var pct = pageNum / pgData.pages;
  3496. this.displayItem.updateProgress(pct, msg, this.animate || this.defaultAnimConfig);
  3497. }
  3498. }
  3499. }
  3500. });
  3501. Ext.preg('progressbarpager', Ext.ux.ProgressBarPager);
  3502. Ext.ns('Ext.ux.grid');
  3503. /**
  3504. * @class Ext.ux.grid.RowEditor
  3505. * @extends Ext.Panel
  3506. * Plugin (ptype = 'roweditor') that adds the ability to rapidly edit full rows in a grid.
  3507. * A validation mode may be enabled which uses AnchorTips to notify the user of all
  3508. * validation errors at once.
  3509. *
  3510. * @ptype roweditor
  3511. */
  3512. Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
  3513. floating: true,
  3514. shadow: false,
  3515. layout: 'hbox',
  3516. cls: 'x-small-editor',
  3517. buttonAlign: 'center',
  3518. baseCls: 'x-row-editor',
  3519. elements: 'header,footer,body',
  3520. frameWidth: 5,
  3521. buttonPad: 3,
  3522. clicksToEdit: 'auto',
  3523. monitorValid: true,
  3524. focusDelay: 250,
  3525. errorSummary: true,
  3526. defaults: {
  3527. normalWidth: true
  3528. },
  3529. initComponent: function(){
  3530. Ext.ux.grid.RowEditor.superclass.initComponent.call(this);
  3531. this.addEvents(
  3532. /**
  3533. * @event beforeedit
  3534. * Fired before the row editor is activated.
  3535. * If the listener returns <tt>false</tt> the editor will not be activated.
  3536. * @param {Ext.ux.grid.RowEditor} roweditor This object
  3537. * @param {Number} rowIndex The rowIndex of the row just edited
  3538. */
  3539. 'beforeedit',
  3540. /**
  3541. * @event validateedit
  3542. * Fired after a row is edited and passes validation.
  3543. * If the listener returns <tt>false</tt> changes to the record will not be set.
  3544. * @param {Ext.ux.grid.RowEditor} roweditor This object
  3545. * @param {Object} changes Object with changes made to the record.
  3546. * @param {Ext.data.Record} r The Record that was edited.
  3547. * @param {Number} rowIndex The rowIndex of the row just edited
  3548. */
  3549. 'validateedit',
  3550. /**
  3551. * @event afteredit
  3552. * Fired after a row is edited and passes validation. This event is fired
  3553. * after the store's update event is fired with this edit.
  3554. * @param {Ext.ux.grid.RowEditor} roweditor This object
  3555. * @param {Object} changes Object with changes made to the record.
  3556. * @param {Ext.data.Record} r The Record that was edited.
  3557. * @param {Number} rowIndex The rowIndex of the row just edited
  3558. */
  3559. 'afteredit'
  3560. );
  3561. },
  3562. init: function(grid){
  3563. this.grid = grid;
  3564. this.ownerCt = grid;
  3565. if(this.clicksToEdit === 2){
  3566. grid.on('rowdblclick', this.onRowDblClick, this);
  3567. }else{
  3568. grid.on('rowclick', this.onRowClick, this);
  3569. if(Ext.isIE){
  3570. grid.on('rowdblclick', this.onRowDblClick, this);
  3571. }
  3572. }
  3573. // stopEditing without saving when a record is removed from Store.
  3574. grid.getStore().on('remove', function() {
  3575. this.stopEditing(false);
  3576. },this);
  3577. grid.on({
  3578. scope: this,
  3579. keydown: this.onGridKey,
  3580. columnresize: this.verifyLayout,
  3581. columnmove: this.refreshFields,
  3582. reconfigure: this.refreshFields,
  3583. destroy : this.destroy,
  3584. bodyscroll: {
  3585. buffer: 250,
  3586. fn: this.positionButtons
  3587. }
  3588. });
  3589. grid.getColumnModel().on('hiddenchange', this.verifyLayout, this, {delay:1});
  3590. grid.getView().on('refresh', this.stopEditing.createDelegate(this, []));
  3591. },
  3592. refreshFields: function(){
  3593. this.initFields();
  3594. this.verifyLayout();
  3595. },
  3596. isDirty: function(){
  3597. var dirty;
  3598. this.items.each(function(f){
  3599. if(String(this.values[f.id]) !== String(f.getValue())){
  3600. dirty = true;
  3601. return false;
  3602. }
  3603. }, this);
  3604. return dirty;
  3605. },
  3606. startEditing: function(rowIndex, doFocus){
  3607. if(this.editing && this.isDirty()){
  3608. this.showTooltip('You need to commit or cancel your changes');
  3609. return;
  3610. }
  3611. this.editing = true;
  3612. if(typeof rowIndex == 'object'){
  3613. rowIndex = this.grid.getStore().indexOf(rowIndex);
  3614. }
  3615. if(this.fireEvent('beforeedit', this, rowIndex) !== false){
  3616. var g = this.grid, view = g.getView();
  3617. var row = view.getRow(rowIndex);
  3618. var record = g.store.getAt(rowIndex);
  3619. this.record = record;
  3620. this.rowIndex = rowIndex;
  3621. this.values = {};
  3622. if(!this.rendered){
  3623. this.render(view.getEditorParent());
  3624. }
  3625. var w = Ext.fly(row).getWidth();
  3626. this.setSize(w);
  3627. if(!this.initialized){
  3628. this.initFields();
  3629. }
  3630. var cm = g.getColumnModel(), fields = this.items.items, f, val;
  3631. for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  3632. val = this.preEditValue(record, cm.getDataIndex(i));
  3633. f = fields[i];
  3634. f.setValue(val);
  3635. this.values[f.id] = val || '';
  3636. }
  3637. this.verifyLayout(true);
  3638. if(!this.isVisible()){
  3639. this.setPagePosition(Ext.fly(row).getXY());
  3640. } else{
  3641. this.el.setXY(Ext.fly(row).getXY(), {duration:0.15});
  3642. }
  3643. if(!this.isVisible()){
  3644. this.show().doLayout();
  3645. }
  3646. if(doFocus !== false){
  3647. this.doFocus.defer(this.focusDelay, this);
  3648. }
  3649. }
  3650. },
  3651. stopEditing : function(saveChanges){
  3652. this.editing = false;
  3653. if(!this.isVisible()){
  3654. return;
  3655. }
  3656. if(saveChanges === false || !this.isValid()){
  3657. this.hide();
  3658. return;
  3659. }
  3660. var changes = {}, r = this.record, hasChange = false;
  3661. var cm = this.grid.colModel, fields = this.items.items;
  3662. for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  3663. if(!cm.isHidden(i)){
  3664. var dindex = cm.getDataIndex(i);
  3665. if(!Ext.isEmpty(dindex)){
  3666. var oldValue = r.data[dindex];
  3667. var value = this.postEditValue(fields[i].getValue(), oldValue, r, dindex);
  3668. if(String(oldValue) !== String(value)){
  3669. changes[dindex] = value;
  3670. hasChange = true;
  3671. }
  3672. }
  3673. }
  3674. }
  3675. if(hasChange && this.fireEvent('validateedit', this, changes, r, this.rowIndex) !== false){
  3676. r.beginEdit();
  3677. for(var k in changes){
  3678. if(changes.hasOwnProperty(k)){
  3679. r.set(k, changes[k]);
  3680. }
  3681. }
  3682. r.endEdit();
  3683. this.fireEvent('afteredit', this, changes, r, this.rowIndex);
  3684. }
  3685. this.hide();
  3686. },
  3687. verifyLayout: function(force){
  3688. if(this.el && (this.isVisible() || force === true)){
  3689. var row = this.grid.getView().getRow(this.rowIndex);
  3690. this.setSize(Ext.fly(row).getWidth(), Ext.isIE ? Ext.fly(row).getHeight() + (Ext.isBorderBox ? 9 : 0) : undefined);
  3691. var cm = this.grid.colModel, fields = this.items.items;
  3692. for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  3693. if(!cm.isHidden(i)){
  3694. var adjust = 0;
  3695. if(i === 0){
  3696. adjust += 0; // outer padding
  3697. }
  3698. if(i === (len - 1)){
  3699. adjust += 3; // outer padding
  3700. } else{
  3701. adjust += 1;
  3702. }
  3703. fields[i].show();
  3704. fields[i].setWidth(cm.getColumnWidth(i) - adjust);
  3705. } else{
  3706. fields[i].hide();
  3707. }
  3708. }
  3709. this.doLayout();
  3710. this.positionButtons();
  3711. }
  3712. },
  3713. slideHide : function(){
  3714. this.hide();
  3715. },
  3716. initFields: function(){
  3717. var cm = this.grid.getColumnModel(), pm = Ext.layout.ContainerLayout.prototype.parseMargins;
  3718. this.removeAll(false);
  3719. for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  3720. var c = cm.getColumnAt(i);
  3721. var ed = c.getEditor();
  3722. if(!ed){
  3723. ed = c.displayEditor || new Ext.form.DisplayField();
  3724. }
  3725. if(i == 0){
  3726. ed.margins = pm('0 1 2 1');
  3727. } else if(i == len - 1){
  3728. ed.margins = pm('0 0 2 1');
  3729. } else{
  3730. ed.margins = pm('0 1 2');
  3731. }
  3732. ed.setWidth(cm.getColumnWidth(i));
  3733. ed.column = c;
  3734. if(ed.ownerCt !== this){
  3735. ed.on('focus', this.ensureVisible, this);
  3736. ed.on('specialkey', this.onKey, this);
  3737. }
  3738. this.insert(i, ed);
  3739. }
  3740. this.initialized = true;
  3741. },
  3742. onKey: function(f, e){
  3743. if(e.getKey() === e.ENTER){
  3744. this.stopEditing(true);
  3745. e.stopPropagation();
  3746. }
  3747. },
  3748. onGridKey: function(e){
  3749. if(e.getKey() === e.ENTER && !this.isVisible()){
  3750. var r = this.grid.getSelectionModel().getSelected();
  3751. if(r){
  3752. var index = this.grid.store.indexOf(r);
  3753. this.startEditing(index);
  3754. e.stopPropagation();
  3755. }
  3756. }
  3757. },
  3758. ensureVisible: function(editor){
  3759. if(this.isVisible()){
  3760. this.grid.getView().ensureVisible(this.rowIndex, this.grid.colModel.getIndexById(editor.column.id), true);
  3761. }
  3762. },
  3763. onRowClick: function(g, rowIndex, e){
  3764. if(this.clicksToEdit == 'auto'){
  3765. var li = this.lastClickIndex;
  3766. this.lastClickIndex = rowIndex;
  3767. if(li != rowIndex && !this.isVisible()){
  3768. return;
  3769. }
  3770. }
  3771. this.startEditing(rowIndex, false);
  3772. this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
  3773. },
  3774. onRowDblClick: function(g, rowIndex, e){
  3775. this.startEditing(rowIndex, false);
  3776. this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
  3777. },
  3778. onRender: function(){
  3779. Ext.ux.grid.RowEditor.superclass.onRender.apply(this, arguments);
  3780. this.el.swallowEvent(['keydown', 'keyup', 'keypress']);
  3781. this.btns = new Ext.Panel({
  3782. baseCls: 'x-plain',
  3783. cls: 'x-btns',
  3784. elements:'body',
  3785. layout: 'table',
  3786. width: (this.minButtonWidth * 2) + (this.frameWidth * 2) + (this.buttonPad * 4), // width must be specified for IE
  3787. items: [{
  3788. ref: 'saveBtn',
  3789. itemId: 'saveBtn',
  3790. xtype: 'button',
  3791. text: this.saveText || 'Save',
  3792. width: this.minButtonWidth,
  3793. handler: this.stopEditing.createDelegate(this, [true])
  3794. }, {
  3795. xtype: 'button',
  3796. text: this.cancelText || 'Cancel',
  3797. width: this.minButtonWidth,
  3798. handler: this.stopEditing.createDelegate(this, [false])
  3799. }]
  3800. });
  3801. this.btns.render(this.bwrap);
  3802. },
  3803. afterRender: function(){
  3804. Ext.ux.grid.RowEditor.superclass.afterRender.apply(this, arguments);
  3805. this.positionButtons();
  3806. if(this.monitorValid){
  3807. this.startMonitoring();
  3808. }
  3809. },
  3810. onShow: function(){
  3811. if(this.monitorValid){
  3812. this.startMonitoring();
  3813. }
  3814. Ext.ux.grid.RowEditor.superclass.onShow.apply(this, arguments);
  3815. },
  3816. onHide: function(){
  3817. Ext.ux.grid.RowEditor.superclass.onHide.apply(this, arguments);
  3818. this.stopMonitoring();
  3819. this.grid.getView().focusRow(this.rowIndex);
  3820. },
  3821. positionButtons: function(){
  3822. if(this.btns){
  3823. var h = this.el.dom.clientHeight;
  3824. var view = this.grid.getView();
  3825. var scroll = view.scroller.dom.scrollLeft;
  3826. var width = view.mainBody.getWidth();
  3827. var bw = this.btns.getWidth();
  3828. this.btns.el.shift({left: (width/2)-(bw/2)+scroll, top: h - 2, stopFx: true, duration:0.2});
  3829. }
  3830. },
  3831. // private
  3832. preEditValue : function(r, field){
  3833. var value = r.data[field];
  3834. return this.autoEncode && typeof value === 'string' ? Ext.util.Format.htmlDecode(value) : value;
  3835. },
  3836. // private
  3837. postEditValue : function(value, originalValue, r, field){
  3838. return this.autoEncode && typeof value == 'string' ? Ext.util.Format.htmlEncode(value) : value;
  3839. },
  3840. doFocus: function(pt){
  3841. if(this.isVisible()){
  3842. var index = 0;
  3843. if(pt){
  3844. index = this.getTargetColumnIndex(pt);
  3845. }
  3846. var cm = this.grid.getColumnModel();
  3847. for(var i = index||0, len = cm.getColumnCount(); i < len; i++){
  3848. var c = cm.getColumnAt(i);
  3849. if(!c.hidden && c.getEditor()){
  3850. c.getEditor().focus();
  3851. break;
  3852. }
  3853. }
  3854. }
  3855. },
  3856. getTargetColumnIndex: function(pt){
  3857. var grid = this.grid, v = grid.view;
  3858. var x = pt.left;
  3859. var cms = grid.colModel.config;
  3860. var i = 0, match = false;
  3861. for(var len = cms.length, c; c = cms[i]; i++){
  3862. if(!c.hidden){
  3863. if(Ext.fly(v.getHeaderCell(i)).getRegion().right >= x){
  3864. match = i;
  3865. break;
  3866. }
  3867. }
  3868. }
  3869. return match;
  3870. },
  3871. startMonitoring : function(){
  3872. if(!this.bound && this.monitorValid){
  3873. this.bound = true;
  3874. Ext.TaskMgr.start({
  3875. run : this.bindHandler,
  3876. interval : this.monitorPoll || 200,
  3877. scope: this
  3878. });
  3879. }
  3880. },
  3881. stopMonitoring : function(){
  3882. this.bound = false;
  3883. if(this.tooltip){
  3884. this.tooltip.hide();
  3885. }
  3886. },
  3887. isValid: function(){
  3888. var valid = true;
  3889. this.items.each(function(f){
  3890. if(!f.isValid(true)){
  3891. valid = false;
  3892. return false;
  3893. }
  3894. });
  3895. return valid;
  3896. },
  3897. // private
  3898. bindHandler : function(){
  3899. if(!this.bound){
  3900. return false; // stops binding
  3901. }
  3902. var valid = this.isValid();
  3903. if(!valid && this.errorSummary){
  3904. this.showTooltip(this.getErrorText().join(''));
  3905. }
  3906. this.btns.saveBtn.setDisabled(!valid);
  3907. this.fireEvent('validation', this, valid);
  3908. },
  3909. showTooltip: function(msg){
  3910. var t = this.tooltip;
  3911. if(!t){
  3912. t = this.tooltip = new Ext.ToolTip({
  3913. maxWidth: 600,
  3914. cls: 'errorTip',
  3915. width: 300,
  3916. title: 'Errors',
  3917. autoHide: false,
  3918. anchor: 'left',
  3919. anchorToTarget: true,
  3920. mouseOffset: [40,0]
  3921. });
  3922. }
  3923. t.initTarget(this.items.last().getEl());
  3924. if(!t.rendered){
  3925. t.show();
  3926. t.hide();
  3927. }
  3928. t.body.update(msg);
  3929. t.doAutoWidth();
  3930. t.show();
  3931. },
  3932. getErrorText: function(){
  3933. var data = ['<ul>'];
  3934. this.items.each(function(f){
  3935. if(!f.isValid(true)){
  3936. data.push('<li>', f.activeError, '</li>');
  3937. }
  3938. });
  3939. data.push('</ul>');
  3940. return data;
  3941. }
  3942. });
  3943. Ext.preg('roweditor', Ext.ux.grid.RowEditor);
  3944. Ext.override(Ext.form.Field, {
  3945. markInvalid : function(msg){
  3946. if(!this.rendered || this.preventMark){ // not rendered
  3947. return;
  3948. }
  3949. msg = msg || this.invalidText;
  3950. var mt = this.getMessageHandler();
  3951. if(mt){
  3952. mt.mark(this, msg);
  3953. }else if(this.msgTarget){
  3954. this.el.addClass(this.invalidClass);
  3955. var t = Ext.getDom(this.msgTarget);
  3956. if(t){
  3957. t.innerHTML = msg;
  3958. t.style.display = this.msgDisplay;
  3959. }
  3960. }
  3961. this.activeError = msg;
  3962. this.fireEvent('invalid', this, msg);
  3963. }
  3964. });
  3965. Ext.override(Ext.ToolTip, {
  3966. doAutoWidth : function(){
  3967. var bw = this.body.getTextWidth();
  3968. if(this.title){
  3969. bw = Math.max(bw, this.header.child('span').getTextWidth(this.title));
  3970. }
  3971. bw += this.getFrameWidth() + (this.closable ? 20 : 0) + this.body.getPadding("lr") + 20;
  3972. this.setWidth(bw.constrain(this.minWidth, this.maxWidth));
  3973. // IE7 repaint bug on initial show
  3974. if(Ext.isIE7 && !this.repainted){
  3975. this.el.repaint();
  3976. this.repainted = true;
  3977. }
  3978. }
  3979. });
  3980. Ext.ns('Ext.ux.grid');
  3981. /**
  3982. * @class Ext.ux.grid.RowExpander
  3983. * @extends Ext.util.Observable
  3984. * Plugin (ptype = 'rowexpander') that adds the ability to have a Column in a grid which enables
  3985. * a second row body which expands/contracts. The expand/contract behavior is configurable to react
  3986. * on clicking of the column, double click of the row, and/or hitting enter while a row is selected.
  3987. *
  3988. * @ptype rowexpander
  3989. */
  3990. Ext.ux.grid.RowExpander = Ext.extend(Ext.util.Observable, {
  3991. /**
  3992. * @cfg {Boolean} expandOnEnter
  3993. * <tt>true</tt> to toggle selected row(s) between expanded/collapsed when the enter
  3994. * key is pressed (defaults to <tt>true</tt>).
  3995. */
  3996. expandOnEnter : true,
  3997. /**
  3998. * @cfg {Boolean} expandOnDblClick
  3999. * <tt>true</tt> to toggle a row between expanded/collapsed when double clicked
  4000. * (defaults to <tt>true</tt>).
  4001. */
  4002. expandOnDblClick : true,
  4003. header : '',
  4004. width : 20,
  4005. sortable : false,
  4006. fixed : true,
  4007. menuDisabled : true,
  4008. dataIndex : '',
  4009. id : 'expander',
  4010. lazyRender : true,
  4011. enableCaching : true,
  4012. constructor: function(config){
  4013. Ext.apply(this, config);
  4014. this.addEvents({
  4015. /**
  4016. * @event beforeexpand
  4017. * Fires before the row expands. Have the listener return false to prevent the row from expanding.
  4018. * @param {Object} this RowExpander object.
  4019. * @param {Object} Ext.data.Record Record for the selected row.
  4020. * @param {Object} body body element for the secondary row.
  4021. * @param {Number} rowIndex The current row index.
  4022. */
  4023. beforeexpand: true,
  4024. /**
  4025. * @event expand
  4026. * Fires after the row expands.
  4027. * @param {Object} this RowExpander object.
  4028. * @param {Object} Ext.data.Record Record for the selected row.
  4029. * @param {Object} body body element for the secondary row.
  4030. * @param {Number} rowIndex The current row index.
  4031. */
  4032. expand: true,
  4033. /**
  4034. * @event beforecollapse
  4035. * Fires before the row collapses. Have the listener return false to prevent the row from collapsing.
  4036. * @param {Object} this RowExpander object.
  4037. * @param {Object} Ext.data.Record Record for the selected row.
  4038. * @param {Object} body body element for the secondary row.
  4039. * @param {Number} rowIndex The current row index.
  4040. */
  4041. beforecollapse: true,
  4042. /**
  4043. * @event collapse
  4044. * Fires after the row collapses.
  4045. * @param {Object} this RowExpander object.
  4046. * @param {Object} Ext.data.Record Record for the selected row.
  4047. * @param {Object} body body element for the secondary row.
  4048. * @param {Number} rowIndex The current row index.
  4049. */
  4050. collapse: true
  4051. });
  4052. Ext.ux.grid.RowExpander.superclass.constructor.call(this);
  4053. if(this.tpl){
  4054. if(typeof this.tpl == 'string'){
  4055. this.tpl = new Ext.Template(this.tpl);
  4056. }
  4057. this.tpl.compile();
  4058. }
  4059. this.state = {};
  4060. this.bodyContent = {};
  4061. },
  4062. getRowClass : function(record, rowIndex, p, ds){
  4063. p.cols = p.cols-1;
  4064. var content = this.bodyContent[record.id];
  4065. if(!content && !this.lazyRender){
  4066. content = this.getBodyContent(record, rowIndex);
  4067. }
  4068. if(content){
  4069. p.body = content;
  4070. }
  4071. return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed';
  4072. },
  4073. init : function(grid){
  4074. this.grid = grid;
  4075. var view = grid.getView();
  4076. view.getRowClass = this.getRowClass.createDelegate(this);
  4077. view.enableRowBody = true;
  4078. grid.on('render', this.onRender, this);
  4079. grid.on('destroy', this.onDestroy, this);
  4080. },
  4081. // @private
  4082. onRender: function() {
  4083. var grid = this.grid;
  4084. var mainBody = grid.getView().mainBody;
  4085. mainBody.on('mousedown', this.onMouseDown, this, {delegate: '.x-grid3-row-expander'});
  4086. if (this.expandOnEnter) {
  4087. this.keyNav = new Ext.KeyNav(this.grid.getGridEl(), {
  4088. 'enter' : this.onEnter,
  4089. scope: this
  4090. });
  4091. }
  4092. if (this.expandOnDblClick) {
  4093. grid.on('rowdblclick', this.onRowDblClick, this);
  4094. }
  4095. },
  4096. // @private
  4097. onDestroy: function() {
  4098. this.keyNav.disable();
  4099. delete this.keyNav;
  4100. var mainBody = this.grid.getView().mainBody;
  4101. mainBody.un('mousedown', this.onMouseDown, this);
  4102. },
  4103. // @private
  4104. onRowDblClick: function(grid, rowIdx, e) {
  4105. this.toggleRow(rowIdx);
  4106. },
  4107. onEnter: function(e) {
  4108. var g = this.grid;
  4109. var sm = g.getSelectionModel();
  4110. var sels = sm.getSelections();
  4111. for (var i = 0, len = sels.length; i < len; i++) {
  4112. var rowIdx = g.getStore().indexOf(sels[i]);
  4113. this.toggleRow(rowIdx);
  4114. }
  4115. },
  4116. getBodyContent : function(record, index){
  4117. if(!this.enableCaching){
  4118. return this.tpl.apply(record.data);
  4119. }
  4120. var content = this.bodyContent[record.id];
  4121. if(!content){
  4122. content = this.tpl.apply(record.data);
  4123. this.bodyContent[record.id] = content;
  4124. }
  4125. return content;
  4126. },
  4127. onMouseDown : function(e, t){
  4128. e.stopEvent();
  4129. var row = e.getTarget('.x-grid3-row');
  4130. this.toggleRow(row);
  4131. },
  4132. renderer : function(v, p, record){
  4133. p.cellAttr = 'rowspan="2"';
  4134. return '<div class="x-grid3-row-expander">&#160;</div>';
  4135. },
  4136. beforeExpand : function(record, body, rowIndex){
  4137. if(this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false){
  4138. if(this.tpl && this.lazyRender){
  4139. body.innerHTML = this.getBodyContent(record, rowIndex);
  4140. }
  4141. return true;
  4142. }else{
  4143. return false;
  4144. }
  4145. },
  4146. toggleRow : function(row){
  4147. if(typeof row == 'number'){
  4148. row = this.grid.view.getRow(row);
  4149. }
  4150. this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'expandRow' : 'collapseRow'](row);
  4151. },
  4152. expandRow : function(row){
  4153. if(typeof row == 'number'){
  4154. row = this.grid.view.getRow(row);
  4155. }
  4156. var record = this.grid.store.getAt(row.rowIndex);
  4157. var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
  4158. if(this.beforeExpand(record, body, row.rowIndex)){
  4159. this.state[record.id] = true;
  4160. Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded');
  4161. this.fireEvent('expand', this, record, body, row.rowIndex);
  4162. }
  4163. },
  4164. collapseRow : function(row){
  4165. if(typeof row == 'number'){
  4166. row = this.grid.view.getRow(row);
  4167. }
  4168. var record = this.grid.store.getAt(row.rowIndex);
  4169. var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
  4170. if(this.fireEvent('beforecollapse', this, record, body, row.rowIndex) !== false){
  4171. this.state[record.id] = false;
  4172. Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed');
  4173. this.fireEvent('collapse', this, record, body, row.rowIndex);
  4174. }
  4175. }
  4176. });
  4177. Ext.preg('rowexpander', Ext.ux.grid.RowExpander);
  4178. //backwards compat
  4179. Ext.grid.RowExpander = Ext.ux.grid.RowExpander;// We are adding these custom layouts to a namespace that does not
  4180. // exist by default in Ext, so we have to add the namespace first:
  4181. Ext.ns('Ext.ux.layout');
  4182. /**
  4183. * @class Ext.ux.layout.RowLayout
  4184. * @extends Ext.layout.ContainerLayout
  4185. * <p>This is the layout style of choice for creating structural layouts in a multi-row format where the height of
  4186. * each row can be specified as a percentage or fixed height. Row widths can also be fixed, percentage or auto.
  4187. * This class is intended to be extended or created via the layout:'ux.row' {@link Ext.Container#layout} config,
  4188. * and should generally not need to be created directly via the new keyword.</p>
  4189. * <p>RowLayout does not have any direct config options (other than inherited ones), but it does support a
  4190. * specific config property of <b><tt>rowHeight</tt></b> that can be included in the config of any panel added to it. The
  4191. * layout will use the rowHeight (if present) or height of each panel during layout to determine how to size each panel.
  4192. * If height or rowHeight is not specified for a given panel, its height will default to the panel's height (or auto).</p>
  4193. * <p>The height property is always evaluated as pixels, and must be a number greater than or equal to 1.
  4194. * The rowHeight property is always evaluated as a percentage, and must be a decimal value greater than 0 and
  4195. * less than 1 (e.g., .25).</p>
  4196. * <p>The basic rules for specifying row heights are pretty simple. The logic makes two passes through the
  4197. * set of contained panels. During the first layout pass, all panels that either have a fixed height or none
  4198. * specified (auto) are skipped, but their heights are subtracted from the overall container height. During the second
  4199. * pass, all panels with rowHeights are assigned pixel heights in proportion to their percentages based on
  4200. * the total <b>remaining</b> container height. In other words, percentage height panels are designed to fill the space
  4201. * left over by all the fixed-height and/or auto-height panels. Because of this, while you can specify any number of rows
  4202. * with different percentages, the rowHeights must always add up to 1 (or 100%) when added together, otherwise your
  4203. * layout may not render as expected. Example usage:</p>
  4204. * <pre><code>
  4205. // All rows are percentages -- they must add up to 1
  4206. var p = new Ext.Panel({
  4207. title: 'Row Layout - Percentage Only',
  4208. layout:'ux.row',
  4209. items: [{
  4210. title: 'Row 1',
  4211. rowHeight: .25
  4212. },{
  4213. title: 'Row 2',
  4214. rowHeight: .6
  4215. },{
  4216. title: 'Row 3',
  4217. rowHeight: .15
  4218. }]
  4219. });
  4220. // Mix of height and rowHeight -- all rowHeight values must add
  4221. // up to 1. The first row will take up exactly 120px, and the last two
  4222. // rows will fill the remaining container height.
  4223. var p = new Ext.Panel({
  4224. title: 'Row Layout - Mixed',
  4225. layout:'ux.row',
  4226. items: [{
  4227. title: 'Row 1',
  4228. height: 120,
  4229. // standard panel widths are still supported too:
  4230. width: '50%' // or 200
  4231. },{
  4232. title: 'Row 2',
  4233. rowHeight: .8,
  4234. width: 300
  4235. },{
  4236. title: 'Row 3',
  4237. rowHeight: .2
  4238. }]
  4239. });
  4240. </code></pre>
  4241. */
  4242. Ext.ux.layout.RowLayout = Ext.extend(Ext.layout.ContainerLayout, {
  4243. // private
  4244. monitorResize:true,
  4245. // private
  4246. isValidParent : function(c, target){
  4247. return c.getEl().dom.parentNode == this.innerCt.dom;
  4248. },
  4249. // private
  4250. onLayout : function(ct, target){
  4251. var rs = ct.items.items, len = rs.length, r, i;
  4252. if(!this.innerCt){
  4253. target.addClass('ux-row-layout-ct');
  4254. this.innerCt = target.createChild({cls:'x-row-inner'});
  4255. }
  4256. this.renderAll(ct, this.innerCt);
  4257. var size = target.getViewSize();
  4258. if(size.width < 1 && size.height < 1){ // display none?
  4259. return;
  4260. }
  4261. var h = size.height - target.getPadding('tb'),
  4262. ph = h;
  4263. this.innerCt.setSize({height:h});
  4264. // some rows can be percentages while others are fixed
  4265. // so we need to make 2 passes
  4266. for(i = 0; i < len; i++){
  4267. r = rs[i];
  4268. if(!r.rowHeight){
  4269. ph -= (r.getSize().height + r.getEl().getMargins('tb'));
  4270. }
  4271. }
  4272. ph = ph < 0 ? 0 : ph;
  4273. for(i = 0; i < len; i++){
  4274. r = rs[i];
  4275. if(r.rowHeight){
  4276. r.setSize({height: Math.floor(r.rowHeight*ph) - r.getEl().getMargins('tb')});
  4277. }
  4278. }
  4279. }
  4280. /**
  4281. * @property activeItem
  4282. * @hide
  4283. */
  4284. });
  4285. Ext.Container.LAYOUTS['ux.row'] = Ext.ux.layout.RowLayout;
  4286. Ext.ns('Ext.ux.form');
  4287. Ext.ux.form.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
  4288. initComponent : function(){
  4289. Ext.ux.form.SearchField.superclass.initComponent.call(this);
  4290. this.on('specialkey', function(f, e){
  4291. if(e.getKey() == e.ENTER){
  4292. this.onTrigger2Click();
  4293. }
  4294. }, this);
  4295. },
  4296. validationEvent:false,
  4297. validateOnBlur:false,
  4298. trigger1Class:'x-form-clear-trigger',
  4299. trigger2Class:'x-form-search-trigger',
  4300. hideTrigger1:true,
  4301. width:180,
  4302. hasSearch : false,
  4303. paramName : 'query',
  4304. onTrigger1Click : function(){
  4305. if(this.hasSearch){
  4306. this.el.dom.value = '';
  4307. var o = {start: 0};
  4308. this.store.baseParams = this.store.baseParams || {};
  4309. this.store.baseParams[this.paramName] = '';
  4310. this.store.reload({params:o});
  4311. this.triggers[0].hide();
  4312. this.hasSearch = false;
  4313. }
  4314. },
  4315. onTrigger2Click : function(){
  4316. var v = this.getRawValue();
  4317. if(v.length < 1){
  4318. this.onTrigger1Click();
  4319. return;
  4320. }
  4321. var o = {start: 0};
  4322. this.store.baseParams = this.store.baseParams || {};
  4323. this.store.baseParams[this.paramName] = v;
  4324. this.store.reload({params:o});
  4325. this.hasSearch = true;
  4326. this.triggers[0].show();
  4327. }
  4328. });Ext.ns('Ext.ux.form');
  4329. /**
  4330. * @class Ext.ux.form.SelectBox
  4331. * @extends Ext.form.ComboBox
  4332. * <p>Makes a ComboBox more closely mimic an HTML SELECT. Supports clicking and dragging
  4333. * through the list, with item selection occurring when the mouse button is released.
  4334. * When used will automatically set {@link #editable} to false and call {@link Ext.Element#unselectable}
  4335. * on inner elements. Re-enabling editable after calling this will NOT work.</p>
  4336. * @author Corey Gilmore http://extjs.com/forum/showthread.php?t=6392
  4337. * @history 2007-07-08 jvs
  4338. * Slight mods for Ext 2.0
  4339. * @xtype selectbox
  4340. */
  4341. Ext.ux.form.SelectBox = Ext.extend(Ext.form.ComboBox, {
  4342. constructor: function(config){
  4343. this.searchResetDelay = 1000;
  4344. config = config || {};
  4345. config = Ext.apply(config || {}, {
  4346. editable: false,
  4347. forceSelection: true,
  4348. rowHeight: false,
  4349. lastSearchTerm: false,
  4350. triggerAction: 'all',
  4351. mode: 'local'
  4352. });
  4353. Ext.ux.form.SelectBox.superclass.constructor.apply(this, arguments);
  4354. this.lastSelectedIndex = this.selectedIndex || 0;
  4355. },
  4356. initEvents : function(){
  4357. Ext.ux.form.SelectBox.superclass.initEvents.apply(this, arguments);
  4358. // you need to use keypress to capture upper/lower case and shift+key, but it doesn't work in IE
  4359. this.el.on('keydown', this.keySearch, this, true);
  4360. this.cshTask = new Ext.util.DelayedTask(this.clearSearchHistory, this);
  4361. },
  4362. keySearch : function(e, target, options) {
  4363. var raw = e.getKey();
  4364. var key = String.fromCharCode(raw);
  4365. var startIndex = 0;
  4366. if( !this.store.getCount() ) {
  4367. return;
  4368. }
  4369. switch(raw) {
  4370. case Ext.EventObject.HOME:
  4371. e.stopEvent();
  4372. this.selectFirst();
  4373. return;
  4374. case Ext.EventObject.END:
  4375. e.stopEvent();
  4376. this.selectLast();
  4377. return;
  4378. case Ext.EventObject.PAGEDOWN:
  4379. this.selectNextPage();
  4380. e.stopEvent();
  4381. return;
  4382. case Ext.EventObject.PAGEUP:
  4383. this.selectPrevPage();
  4384. e.stopEvent();
  4385. return;
  4386. }
  4387. // skip special keys other than the shift key
  4388. if( (e.hasModifier() && !e.shiftKey) || e.isNavKeyPress() || e.isSpecialKey() ) {
  4389. return;
  4390. }
  4391. if( this.lastSearchTerm == key ) {
  4392. startIndex = this.lastSelectedIndex;
  4393. }
  4394. this.search(this.displayField, key, startIndex);
  4395. this.cshTask.delay(this.searchResetDelay);
  4396. },
  4397. onRender : function(ct, position) {
  4398. this.store.on('load', this.calcRowsPerPage, this);
  4399. Ext.ux.form.SelectBox.superclass.onRender.apply(this, arguments);
  4400. if( this.mode == 'local' ) {
  4401. this.calcRowsPerPage();
  4402. }
  4403. },
  4404. onSelect : function(record, index, skipCollapse){
  4405. if(this.fireEvent('beforeselect', this, record, index) !== false){
  4406. this.setValue(record.data[this.valueField || this.displayField]);
  4407. if( !skipCollapse ) {
  4408. this.collapse();
  4409. }
  4410. this.lastSelectedIndex = index + 1;
  4411. this.fireEvent('select', this, record, index);
  4412. }
  4413. },
  4414. render : function(ct) {
  4415. Ext.ux.form.SelectBox.superclass.render.apply(this, arguments);
  4416. if( Ext.isSafari ) {
  4417. this.el.swallowEvent('mousedown', true);
  4418. }
  4419. this.el.unselectable();
  4420. this.innerList.unselectable();
  4421. this.trigger.unselectable();
  4422. this.innerList.on('mouseup', function(e, target, options) {
  4423. if( target.id && target.id == this.innerList.id ) {
  4424. return;
  4425. }
  4426. this.onViewClick();
  4427. }, this);
  4428. this.innerList.on('mouseover', function(e, target, options) {
  4429. if( target.id && target.id == this.innerList.id ) {
  4430. return;
  4431. }
  4432. this.lastSelectedIndex = this.view.getSelectedIndexes()[0] + 1;
  4433. this.cshTask.delay(this.searchResetDelay);
  4434. }, this);
  4435. this.trigger.un('click', this.onTriggerClick, this);
  4436. this.trigger.on('mousedown', function(e, target, options) {
  4437. e.preventDefault();
  4438. this.onTriggerClick();
  4439. }, this);
  4440. this.on('collapse', function(e, target, options) {
  4441. Ext.getDoc().un('mouseup', this.collapseIf, this);
  4442. }, this, true);
  4443. this.on('expand', function(e, target, options) {
  4444. Ext.getDoc().on('mouseup', this.collapseIf, this);
  4445. }, this, true);
  4446. },
  4447. clearSearchHistory : function() {
  4448. this.lastSelectedIndex = 0;
  4449. this.lastSearchTerm = false;
  4450. },
  4451. selectFirst : function() {
  4452. this.focusAndSelect(this.store.data.first());
  4453. },
  4454. selectLast : function() {
  4455. this.focusAndSelect(this.store.data.last());
  4456. },
  4457. selectPrevPage : function() {
  4458. if( !this.rowHeight ) {
  4459. return;
  4460. }
  4461. var index = Math.max(this.selectedIndex-this.rowsPerPage, 0);
  4462. this.focusAndSelect(this.store.getAt(index));
  4463. },
  4464. selectNextPage : function() {
  4465. if( !this.rowHeight ) {
  4466. return;
  4467. }
  4468. var index = Math.min(this.selectedIndex+this.rowsPerPage, this.store.getCount() - 1);
  4469. this.focusAndSelect(this.store.getAt(index));
  4470. },
  4471. search : function(field, value, startIndex) {
  4472. field = field || this.displayField;
  4473. this.lastSearchTerm = value;
  4474. var index = this.store.find.apply(this.store, arguments);
  4475. if( index !== -1 ) {
  4476. this.focusAndSelect(index);
  4477. }
  4478. },
  4479. focusAndSelect : function(record) {
  4480. var index = typeof record === 'number' ? record : this.store.indexOf(record);
  4481. this.select(index, this.isExpanded());
  4482. this.onSelect(this.store.getAt(record), index, this.isExpanded());
  4483. },
  4484. calcRowsPerPage : function() {
  4485. if( this.store.getCount() ) {
  4486. this.rowHeight = Ext.fly(this.view.getNode(0)).getHeight();
  4487. this.rowsPerPage = this.maxHeight / this.rowHeight;
  4488. } else {
  4489. this.rowHeight = false;
  4490. }
  4491. }
  4492. });
  4493. Ext.reg('selectbox', Ext.ux.form.SelectBox);
  4494. //backwards compat
  4495. Ext.ux.SelectBox = Ext.ux.form.SelectBox;
  4496. /**
  4497. * @class Ext.ux.SliderTip
  4498. * @extends Ext.Tip
  4499. * Simple plugin for using an Ext.Tip with a slider to show the slider value
  4500. */
  4501. Ext.ux.SliderTip = Ext.extend(Ext.Tip, {
  4502. minWidth: 10,
  4503. offsets : [0, -10],
  4504. init : function(slider){
  4505. slider.on('dragstart', this.onSlide, this);
  4506. slider.on('drag', this.onSlide, this);
  4507. slider.on('dragend', this.hide, this);
  4508. slider.on('destroy', this.destroy, this);
  4509. },
  4510. onSlide : function(slider){
  4511. this.show();
  4512. this.body.update(this.getText(slider));
  4513. this.doAutoWidth();
  4514. this.el.alignTo(slider.thumb, 'b-t?', this.offsets);
  4515. },
  4516. getText : function(slider){
  4517. return String(slider.getValue());
  4518. }
  4519. });
  4520. Ext.ux.SlidingPager = Ext.extend(Object, {
  4521. init : function(pbar){
  4522. Ext.each(pbar.items.getRange(2,6), function(c){
  4523. c.hide();
  4524. });
  4525. var slider = new Ext.Slider({
  4526. width: 114,
  4527. minValue: 1,
  4528. maxValue: 1,
  4529. plugins: new Ext.ux.SliderTip({
  4530. getText : function(s){
  4531. return String.format('Page <b>{0}</b> of <b>{1}</b>', s.value, s.maxValue);
  4532. }
  4533. }),
  4534. listeners: {
  4535. changecomplete: function(s, v){
  4536. pbar.changePage(v);
  4537. }
  4538. }
  4539. });
  4540. pbar.insert(5, slider);
  4541. pbar.on({
  4542. change: function(pb, data){
  4543. slider.maxValue = data.pages;
  4544. slider.setValue(data.activePage);
  4545. },
  4546. beforedestroy: function(){
  4547. slider.destroy();
  4548. }
  4549. });
  4550. }
  4551. });Ext.ns('Ext.ux.form');
  4552. /**
  4553. * @class Ext.ux.form.SpinnerField
  4554. * @extends Ext.form.NumberField
  4555. * Creates a field utilizing Ext.ux.Spinner
  4556. * @xtype spinnerfield
  4557. */
  4558. Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
  4559. deferHeight: true,
  4560. autoSize: Ext.emptyFn,
  4561. onBlur: Ext.emptyFn,
  4562. adjustSize: Ext.BoxComponent.prototype.adjustSize,
  4563. constructor: function(config) {
  4564. var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass');
  4565. var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig);
  4566. var plugins = config.plugins
  4567. ? (Ext.isArray(config.plugins)
  4568. ? config.plugins.push(spl)
  4569. : [config.plugins, spl])
  4570. : spl;
  4571. Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins}));
  4572. },
  4573. onShow: function(){
  4574. if (this.wrap) {
  4575. this.wrap.dom.style.display = '';
  4576. this.wrap.dom.style.visibility = 'visible';
  4577. }
  4578. },
  4579. onHide: function(){
  4580. this.wrap.dom.style.display = 'none';
  4581. },
  4582. // private
  4583. getResizeEl: function(){
  4584. return this.wrap;
  4585. },
  4586. // private
  4587. getPositionEl: function(){
  4588. return this.wrap;
  4589. },
  4590. // private
  4591. alignErrorIcon: function(){
  4592. if (this.wrap) {
  4593. this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
  4594. }
  4595. },
  4596. validateBlur: function(){
  4597. return true;
  4598. }
  4599. });
  4600. Ext.reg('spinnerfield', Ext.ux.form.SpinnerField);
  4601. //backwards compat
  4602. Ext.form.SpinnerField = Ext.ux.form.SpinnerField;
  4603. /**
  4604. * @class Ext.ux.Spinner
  4605. * @extends Ext.util.Observable
  4606. * Creates a Spinner control utilized by Ext.ux.form.SpinnerField
  4607. */
  4608. Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
  4609. incrementValue: 1,
  4610. alternateIncrementValue: 5,
  4611. triggerClass: 'x-form-spinner-trigger',
  4612. splitterClass: 'x-form-spinner-splitter',
  4613. alternateKey: Ext.EventObject.shiftKey,
  4614. defaultValue: 0,
  4615. accelerate: false,
  4616. constructor: function(config){
  4617. Ext.ux.Spinner.superclass.constructor.call(this, config);
  4618. Ext.apply(this, config);
  4619. this.mimicing = false;
  4620. },
  4621. init: function(field){
  4622. this.field = field;
  4623. field.afterMethod('onRender', this.doRender, this);
  4624. field.afterMethod('onEnable', this.doEnable, this);
  4625. field.afterMethod('onDisable', this.doDisable, this);
  4626. field.afterMethod('afterRender', this.doAfterRender, this);
  4627. field.afterMethod('onResize', this.doResize, this);
  4628. field.afterMethod('onFocus', this.doFocus, this);
  4629. field.beforeMethod('onDestroy', this.doDestroy, this);
  4630. },
  4631. doRender: function(ct, position){
  4632. var el = this.el = this.field.getEl();
  4633. var f = this.field;
  4634. if (!f.wrap) {
  4635. f.wrap = this.wrap = el.wrap({
  4636. cls: "x-form-field-wrap"
  4637. });
  4638. }
  4639. else {
  4640. this.wrap = f.wrap.addClass('x-form-field-wrap');
  4641. }
  4642. this.trigger = this.wrap.createChild({
  4643. tag: "img",
  4644. src: Ext.BLANK_IMAGE_URL,
  4645. cls: "x-form-trigger " + this.triggerClass
  4646. });
  4647. if (!f.width) {
  4648. this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
  4649. }
  4650. this.splitter = this.wrap.createChild({
  4651. tag: 'div',
  4652. cls: this.splitterClass,
  4653. style: 'width:13px; height:2px;'
  4654. });
  4655. this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
  4656. this.proxy = this.trigger.createProxy('', this.splitter, true);
  4657. this.proxy.addClass("x-form-spinner-proxy");
  4658. this.proxy.setStyle('left', '0px');
  4659. this.proxy.setSize(14, 1);
  4660. this.proxy.hide();
  4661. this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
  4662. dragElId: this.proxy.id
  4663. });
  4664. this.initTrigger();
  4665. this.initSpinner();
  4666. },
  4667. doAfterRender: function(){
  4668. var y;
  4669. if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
  4670. this.el.position();
  4671. this.el.setY(y);
  4672. }
  4673. },
  4674. doEnable: function(){
  4675. if (this.wrap) {
  4676. this.wrap.removeClass(this.field.disabledClass);
  4677. }
  4678. },
  4679. doDisable: function(){
  4680. if (this.wrap) {
  4681. this.wrap.addClass(this.field.disabledClass);
  4682. this.el.removeClass(this.field.disabledClass);
  4683. }
  4684. },
  4685. doResize: function(w, h){
  4686. if (typeof w == 'number') {
  4687. this.el.setWidth(this.field.adjustWidth('input', w - this.trigger.getWidth()));
  4688. }
  4689. this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
  4690. },
  4691. doFocus: function(){
  4692. if (!this.mimicing) {
  4693. this.wrap.addClass('x-trigger-wrap-focus');
  4694. this.mimicing = true;
  4695. Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
  4696. delay: 10
  4697. });
  4698. this.el.on('keydown', this.checkTab, this);
  4699. }
  4700. },
  4701. // private
  4702. checkTab: function(e){
  4703. if (e.getKey() == e.TAB) {
  4704. this.triggerBlur();
  4705. }
  4706. },
  4707. // private
  4708. mimicBlur: function(e){
  4709. if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
  4710. this.triggerBlur();
  4711. }
  4712. },
  4713. // private
  4714. triggerBlur: function(){
  4715. this.mimicing = false;
  4716. Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
  4717. this.el.un("keydown", this.checkTab, this);
  4718. this.field.beforeBlur();
  4719. this.wrap.removeClass('x-trigger-wrap-focus');
  4720. this.field.onBlur.call(this.field);
  4721. },
  4722. initTrigger: function(){
  4723. this.trigger.addClassOnOver('x-form-trigger-over');
  4724. this.trigger.addClassOnClick('x-form-trigger-click');
  4725. },
  4726. initSpinner: function(){
  4727. this.field.addEvents({
  4728. 'spin': true,
  4729. 'spinup': true,
  4730. 'spindown': true
  4731. });
  4732. this.keyNav = new Ext.KeyNav(this.el, {
  4733. "up": function(e){
  4734. e.preventDefault();
  4735. this.onSpinUp();
  4736. },
  4737. "down": function(e){
  4738. e.preventDefault();
  4739. this.onSpinDown();
  4740. },
  4741. "pageUp": function(e){
  4742. e.preventDefault();
  4743. this.onSpinUpAlternate();
  4744. },
  4745. "pageDown": function(e){
  4746. e.preventDefault();
  4747. this.onSpinDownAlternate();
  4748. },
  4749. scope: this
  4750. });
  4751. this.repeater = new Ext.util.ClickRepeater(this.trigger, {
  4752. accelerate: this.accelerate
  4753. });
  4754. this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
  4755. preventDefault: true
  4756. });
  4757. this.field.mon(this.trigger, {
  4758. mouseover: this.onMouseOver,
  4759. mouseout: this.onMouseOut,
  4760. mousemove: this.onMouseMove,
  4761. mousedown: this.onMouseDown,
  4762. mouseup: this.onMouseUp,
  4763. scope: this,
  4764. preventDefault: true
  4765. });
  4766. this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
  4767. this.dd.setXConstraint(0, 0, 10)
  4768. this.dd.setYConstraint(1500, 1500, 10);
  4769. this.dd.endDrag = this.endDrag.createDelegate(this);
  4770. this.dd.startDrag = this.startDrag.createDelegate(this);
  4771. this.dd.onDrag = this.onDrag.createDelegate(this);
  4772. },
  4773. onMouseOver: function(){
  4774. if (this.disabled) {
  4775. return;
  4776. }
  4777. var middle = this.getMiddle();
  4778. this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
  4779. this.trigger.addClass(this.tmpHoverClass);
  4780. },
  4781. //private
  4782. onMouseOut: function(){
  4783. this.trigger.removeClass(this.tmpHoverClass);
  4784. },
  4785. //private
  4786. onMouseMove: function(){
  4787. if (this.disabled) {
  4788. return;
  4789. }
  4790. var middle = this.getMiddle();
  4791. if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
  4792. ((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
  4793. }
  4794. },
  4795. //private
  4796. onMouseDown: function(){
  4797. if (this.disabled) {
  4798. return;
  4799. }
  4800. var middle = this.getMiddle();
  4801. this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
  4802. this.trigger.addClass(this.tmpClickClass);
  4803. },
  4804. //private
  4805. onMouseUp: function(){
  4806. this.trigger.removeClass(this.tmpClickClass);
  4807. },
  4808. //private
  4809. onTriggerClick: function(){
  4810. if (this.disabled || this.el.dom.readOnly) {
  4811. return;
  4812. }
  4813. var middle = this.getMiddle();
  4814. var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
  4815. this['onSpin' + ud]();
  4816. },
  4817. //private
  4818. getMiddle: function(){
  4819. var t = this.trigger.getTop();
  4820. var h = this.trigger.getHeight();
  4821. var middle = t + (h / 2);
  4822. return middle;
  4823. },
  4824. //private
  4825. //checks if control is allowed to spin
  4826. isSpinnable: function(){
  4827. if (this.disabled || this.el.dom.readOnly) {
  4828. Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
  4829. return false;
  4830. }
  4831. return true;
  4832. },
  4833. handleMouseWheel: function(e){
  4834. //disable scrolling when not focused
  4835. if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
  4836. return;
  4837. }
  4838. var delta = e.getWheelDelta();
  4839. if (delta > 0) {
  4840. this.onSpinUp();
  4841. e.stopEvent();
  4842. }
  4843. else
  4844. if (delta < 0) {
  4845. this.onSpinDown();
  4846. e.stopEvent();
  4847. }
  4848. },
  4849. //private
  4850. startDrag: function(){
  4851. this.proxy.show();
  4852. this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
  4853. },
  4854. //private
  4855. endDrag: function(){
  4856. this.proxy.hide();
  4857. },
  4858. //private
  4859. onDrag: function(){
  4860. if (this.disabled) {
  4861. return;
  4862. }
  4863. var y = Ext.fly(this.dd.getDragEl()).getTop();
  4864. var ud = '';
  4865. if (this._previousY > y) {
  4866. ud = 'Up';
  4867. } //up
  4868. if (this._previousY < y) {
  4869. ud = 'Down';
  4870. } //down
  4871. if (ud != '') {
  4872. this['onSpin' + ud]();
  4873. }
  4874. this._previousY = y;
  4875. },
  4876. //private
  4877. onSpinUp: function(){
  4878. if (this.isSpinnable() == false) {
  4879. return;
  4880. }
  4881. if (Ext.EventObject.shiftKey == true) {
  4882. this.onSpinUpAlternate();
  4883. return;
  4884. }
  4885. else {
  4886. this.spin(false, false);
  4887. }
  4888. this.field.fireEvent("spin", this);
  4889. this.field.fireEvent("spinup", this);
  4890. },
  4891. //private
  4892. onSpinDown: function(){
  4893. if (this.isSpinnable() == false) {
  4894. return;
  4895. }
  4896. if (Ext.EventObject.shiftKey == true) {
  4897. this.onSpinDownAlternate();
  4898. return;
  4899. }
  4900. else {
  4901. this.spin(true, false);
  4902. }
  4903. this.field.fireEvent("spin", this);
  4904. this.field.fireEvent("spindown", this);
  4905. },
  4906. //private
  4907. onSpinUpAlternate: function(){
  4908. if (this.isSpinnable() == false) {
  4909. return;
  4910. }
  4911. this.spin(false, true);
  4912. this.field.fireEvent("spin", this);
  4913. this.field.fireEvent("spinup", this);
  4914. },
  4915. //private
  4916. onSpinDownAlternate: function(){
  4917. if (this.isSpinnable() == false) {
  4918. return;
  4919. }
  4920. this.spin(true, true);
  4921. this.field.fireEvent("spin", this);
  4922. this.field.fireEvent("spindown", this);
  4923. },
  4924. spin: function(down, alternate){
  4925. var v = parseFloat(this.field.getValue());
  4926. var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
  4927. (down == true) ? v -= incr : v += incr;
  4928. v = (isNaN(v)) ? this.defaultValue : v;
  4929. v = this.fixBoundries(v);
  4930. this.field.setRawValue(v);
  4931. },
  4932. fixBoundries: function(value){
  4933. var v = value;
  4934. if (this.field.minValue != undefined && v < this.field.minValue) {
  4935. v = this.field.minValue;
  4936. }
  4937. if (this.field.maxValue != undefined && v > this.field.maxValue) {
  4938. v = this.field.maxValue;
  4939. }
  4940. return this.fixPrecision(v);
  4941. },
  4942. // private
  4943. fixPrecision: function(value){
  4944. var nan = isNaN(value);
  4945. if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
  4946. return nan ? '' : value;
  4947. }
  4948. return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
  4949. },
  4950. doDestroy: function(){
  4951. if (this.trigger) {
  4952. this.trigger.remove();
  4953. }
  4954. if (this.wrap) {
  4955. this.wrap.remove();
  4956. delete this.field.wrap;
  4957. }
  4958. if (this.splitter) {
  4959. this.splitter.remove();
  4960. }
  4961. if (this.dd) {
  4962. this.dd.unreg();
  4963. this.dd = null;
  4964. }
  4965. if (this.proxy) {
  4966. this.proxy.remove();
  4967. }
  4968. if (this.repeater) {
  4969. this.repeater.purgeListeners();
  4970. }
  4971. }
  4972. });
  4973. //backwards compat
  4974. Ext.form.Spinner = Ext.ux.Spinner;Ext.ux.Spotlight = function(config){
  4975. Ext.apply(this, config);
  4976. }
  4977. Ext.ux.Spotlight.prototype = {
  4978. active : false,
  4979. animate : true,
  4980. duration: .25,
  4981. easing:'easeNone',
  4982. // private
  4983. animated : false,
  4984. createElements : function(){
  4985. var bd = Ext.getBody();
  4986. this.right = bd.createChild({cls:'x-spotlight'});
  4987. this.left = bd.createChild({cls:'x-spotlight'});
  4988. this.top = bd.createChild({cls:'x-spotlight'});
  4989. this.bottom = bd.createChild({cls:'x-spotlight'});
  4990. this.all = new Ext.CompositeElement([this.right, this.left, this.top, this.bottom]);
  4991. },
  4992. show : function(el, callback, scope){
  4993. if(this.animated){
  4994. this.show.defer(50, this, [el, callback, scope]);
  4995. return;
  4996. }
  4997. this.el = Ext.get(el);
  4998. if(!this.right){
  4999. this.createElements();
  5000. }
  5001. if(!this.active){
  5002. this.all.setDisplayed('');
  5003. this.applyBounds(true, false);
  5004. this.active = true;
  5005. Ext.EventManager.onWindowResize(this.syncSize, this);
  5006. this.applyBounds(false, this.animate, false, callback, scope);
  5007. }else{
  5008. this.applyBounds(false, false, false, callback, scope); // all these booleans look hideous
  5009. }
  5010. },
  5011. hide : function(callback, scope){
  5012. if(this.animated){
  5013. this.hide.defer(50, this, [callback, scope]);
  5014. return;
  5015. }
  5016. Ext.EventManager.removeResizeListener(this.syncSize, this);
  5017. this.applyBounds(true, this.animate, true, callback, scope);
  5018. },
  5019. doHide : function(){
  5020. this.active = false;
  5021. this.all.setDisplayed(false);
  5022. },
  5023. syncSize : function(){
  5024. this.applyBounds(false, false);
  5025. },
  5026. applyBounds : function(basePts, anim, doHide, callback, scope){
  5027. var rg = this.el.getRegion();
  5028. var dw = Ext.lib.Dom.getViewWidth(true);
  5029. var dh = Ext.lib.Dom.getViewHeight(true);
  5030. var c = 0, cb = false;
  5031. if(anim){
  5032. cb = {
  5033. callback: function(){
  5034. c++;
  5035. if(c == 4){
  5036. this.animated = false;
  5037. if(doHide){
  5038. this.doHide();
  5039. }
  5040. Ext.callback(callback, scope, [this]);
  5041. }
  5042. },
  5043. scope: this,
  5044. duration: this.duration,
  5045. easing: this.easing
  5046. };
  5047. this.animated = true;
  5048. }
  5049. this.right.setBounds(
  5050. rg.right,
  5051. basePts ? dh : rg.top,
  5052. dw - rg.right,
  5053. basePts ? 0 : (dh - rg.top),
  5054. cb);
  5055. this.left.setBounds(
  5056. 0,
  5057. 0,
  5058. rg.left,
  5059. basePts ? 0 : rg.bottom,
  5060. cb);
  5061. this.top.setBounds(
  5062. basePts ? dw : rg.left,
  5063. 0,
  5064. basePts ? 0 : dw - rg.left,
  5065. rg.top,
  5066. cb);
  5067. this.bottom.setBounds(
  5068. 0,
  5069. rg.bottom,
  5070. basePts ? 0 : rg.right,
  5071. dh - rg.bottom,
  5072. cb);
  5073. if(!anim){
  5074. if(doHide){
  5075. this.doHide();
  5076. }
  5077. if(callback){
  5078. Ext.callback(callback, scope, [this]);
  5079. }
  5080. }
  5081. },
  5082. destroy : function(){
  5083. this.doHide();
  5084. Ext.destroy(
  5085. this.right,
  5086. this.left,
  5087. this.top,
  5088. this.bottom);
  5089. delete this.el;
  5090. delete this.all;
  5091. }
  5092. };
  5093. //backwards compat
  5094. Ext.Spotlight = Ext.ux.Spotlight;/**
  5095. * @class Ext.ux.TabCloseMenu
  5096. * @extends Object
  5097. * Plugin (ptype = 'tabclosemenu') for adding a close context menu to tabs.
  5098. *
  5099. * @ptype tabclosemenu
  5100. */
  5101. Ext.ux.TabCloseMenu = function(){
  5102. var tabs, menu, ctxItem;
  5103. this.init = function(tp){
  5104. tabs = tp;
  5105. tabs.on('contextmenu', onContextMenu);
  5106. };
  5107. function onContextMenu(ts, item, e){
  5108. if(!menu){ // create context menu on first right click
  5109. menu = new Ext.menu.Menu({
  5110. items: [{
  5111. id: tabs.id + '-close',
  5112. text: 'Close Tab',
  5113. handler : function(){
  5114. tabs.remove(ctxItem);
  5115. }
  5116. },{
  5117. id: tabs.id + '-close-others',
  5118. text: 'Close Other Tabs',
  5119. handler : function(){
  5120. tabs.items.each(function(item){
  5121. if(item.closable && item != ctxItem){
  5122. tabs.remove(item);
  5123. }
  5124. });
  5125. }
  5126. }]});
  5127. }
  5128. ctxItem = item;
  5129. var items = menu.items;
  5130. items.get(tabs.id + '-close').setDisabled(!item.closable);
  5131. var disableOthers = true;
  5132. tabs.items.each(function(){
  5133. if(this != item && this.closable){
  5134. disableOthers = false;
  5135. return false;
  5136. }
  5137. });
  5138. items.get(tabs.id + '-close-others').setDisabled(disableOthers);
  5139. e.stopEvent();
  5140. menu.showAt(e.getPoint());
  5141. }
  5142. };
  5143. Ext.preg('tabclosemenu', Ext.ux.TabCloseMenu);
  5144. Ext.ns('Ext.ux.grid');
  5145. /**
  5146. * @class Ext.ux.grid.TableGrid
  5147. * @extends Ext.grid.GridPanel
  5148. * A Grid which creates itself from an existing HTML table element.
  5149. * @history
  5150. * 2007-03-01 Original version by Nige "Animal" White
  5151. * 2007-03-10 jvs Slightly refactored to reuse existing classes * @constructor
  5152. * @param {String/HTMLElement/Ext.Element} table The table element from which this grid will be created -
  5153. * The table MUST have some type of size defined for the grid to fill. The container will be
  5154. * automatically set to position relative if it isn't already.
  5155. * @param {Object} config A config object that sets properties on this grid and has two additional (optional)
  5156. * properties: fields and columns which allow for customizing data fields and columns for this grid.
  5157. */
  5158. Ext.ux.grid.TableGrid = function(table, config){
  5159. config = config ||
  5160. {};
  5161. Ext.apply(this, config);
  5162. var cf = config.fields || [], ch = config.columns || [];
  5163. table = Ext.get(table);
  5164. var ct = table.insertSibling();
  5165. var fields = [], cols = [];
  5166. var headers = table.query("thead th");
  5167. for (var i = 0, h; h = headers[i]; i++) {
  5168. var text = h.innerHTML;
  5169. var name = 'tcol-' + i;
  5170. fields.push(Ext.applyIf(cf[i] ||
  5171. {}, {
  5172. name: name,
  5173. mapping: 'td:nth(' + (i + 1) + ')/@innerHTML'
  5174. }));
  5175. cols.push(Ext.applyIf(ch[i] ||
  5176. {}, {
  5177. 'header': text,
  5178. 'dataIndex': name,
  5179. 'width': h.offsetWidth,
  5180. 'tooltip': h.title,
  5181. 'sortable': true
  5182. }));
  5183. }
  5184. var ds = new Ext.data.Store({
  5185. reader: new Ext.data.XmlReader({
  5186. record: 'tbody tr'
  5187. }, fields)
  5188. });
  5189. ds.loadData(table.dom);
  5190. var cm = new Ext.grid.ColumnModel(cols);
  5191. if (config.width || config.height) {
  5192. ct.setSize(config.width || 'auto', config.height || 'auto');
  5193. }
  5194. else {
  5195. ct.setWidth(table.getWidth());
  5196. }
  5197. if (config.remove !== false) {
  5198. table.remove();
  5199. }
  5200. Ext.applyIf(this, {
  5201. 'ds': ds,
  5202. 'cm': cm,
  5203. 'sm': new Ext.grid.RowSelectionModel(),
  5204. autoHeight: true,
  5205. autoWidth: false
  5206. });
  5207. Ext.ux.grid.TableGrid.superclass.constructor.call(this, ct, {});
  5208. };
  5209. Ext.extend(Ext.ux.grid.TableGrid, Ext.grid.GridPanel);
  5210. //backwards compat
  5211. Ext.grid.TableGrid = Ext.ux.grid.TableGrid;
  5212. Ext.ux.TabScrollerMenu = Ext.extend(Object, {
  5213. pageSize : 10,
  5214. maxText : 15,
  5215. menuPrefixText : 'Items',
  5216. constructor : function(config) {
  5217. config = config || {};
  5218. Ext.apply(this, config);
  5219. },
  5220. init : function(tabPanel) {
  5221. Ext.apply(tabPanel, this.tabPanelMethods);
  5222. tabPanel.tabScrollerMenu = this;
  5223. var thisRef = this;
  5224. tabPanel.on({
  5225. render : {
  5226. scope : tabPanel,
  5227. single : true,
  5228. fn : function() {
  5229. var newFn = tabPanel.createScrollers.createSequence(thisRef.createPanelsMenu, this);
  5230. tabPanel.createScrollers = newFn;
  5231. }
  5232. }
  5233. });
  5234. },
  5235. // private && sequeneced
  5236. createPanelsMenu : function() {
  5237. var h = this.stripWrap.dom.offsetHeight;
  5238. //move the right menu item to the left 18px
  5239. var rtScrBtn = this.header.dom.firstChild;
  5240. Ext.fly(rtScrBtn).applyStyles({
  5241. right : '18px'
  5242. });
  5243. var stripWrap = Ext.get(this.strip.dom.parentNode);
  5244. stripWrap.applyStyles({
  5245. 'margin-right' : '36px'
  5246. });
  5247. // Add the new righthand menu
  5248. var scrollMenu = this.header.insertFirst({
  5249. cls:'x-tab-tabmenu-right'
  5250. });
  5251. scrollMenu.setHeight(h);
  5252. scrollMenu.addClassOnOver('x-tab-tabmenu-over');
  5253. scrollMenu.on('click', this.showTabsMenu, this);
  5254. this.scrollLeft.show = this.scrollLeft.show.createSequence(function() {
  5255. scrollMenu.show();
  5256. });
  5257. this.scrollLeft.hide = this.scrollLeft.hide.createSequence(function() {
  5258. scrollMenu.hide();
  5259. });
  5260. },
  5261. // public
  5262. getPageSize : function() {
  5263. return this.pageSize;
  5264. },
  5265. // public
  5266. setPageSize : function(pageSize) {
  5267. this.pageSize = pageSize;
  5268. },
  5269. // public
  5270. getMaxText : function() {
  5271. return this.maxText;
  5272. },
  5273. // public
  5274. setMaxText : function(t) {
  5275. this.maxText = t;
  5276. },
  5277. getMenuPrefixText : function() {
  5278. return this.menuPrefixText;
  5279. },
  5280. setMenuPrefixText : function(t) {
  5281. this.menuPrefixText = t;
  5282. },
  5283. // private && applied to the tab panel itself.
  5284. tabPanelMethods : {
  5285. // all execute within the scope of the tab panel
  5286. // private
  5287. showTabsMenu : function(e) {
  5288. if (! this.tabsMenu) {
  5289. this.tabsMenu = new Ext.menu.Menu();
  5290. this.on('beforedestroy', this.tabsMenu.destroy, this.tabsMenu);
  5291. }
  5292. this.tabsMenu.removeAll();
  5293. this.generateTabMenuItems();
  5294. var target = Ext.get(e.getTarget());
  5295. var xy = target.getXY();
  5296. //Y param + 24 pixels
  5297. xy[1] += 24;
  5298. this.tabsMenu.showAt(xy);
  5299. },
  5300. // private
  5301. generateTabMenuItems : function() {
  5302. var curActive = this.getActiveTab();
  5303. var totalItems = this.items.getCount();
  5304. var pageSize = this.tabScrollerMenu.getPageSize();
  5305. if (totalItems > pageSize) {
  5306. var numSubMenus = Math.floor(totalItems / pageSize);
  5307. var remainder = totalItems % pageSize;
  5308. // Loop through all of the items and create submenus in chunks of 10
  5309. for (var i = 0 ; i < numSubMenus; i++) {
  5310. var curPage = (i + 1) * pageSize;
  5311. var menuItems = [];
  5312. for (var x = 0; x < pageSize; x++) {
  5313. index = x + curPage - pageSize;
  5314. var item = this.items.get(index);
  5315. menuItems.push(this.autoGenMenuItem(item));
  5316. }
  5317. this.tabsMenu.add({
  5318. text : this.tabScrollerMenu.getMenuPrefixText() + ' ' + (curPage - pageSize + 1) + ' - ' + curPage,
  5319. menu : menuItems
  5320. });
  5321. }
  5322. // remaining items
  5323. if (remainder > 0) {
  5324. var start = numSubMenus * pageSize;
  5325. menuItems = [];
  5326. for (var i = start ; i < totalItems; i ++ ) {
  5327. var item = this.items.get(i);
  5328. menuItems.push(this.autoGenMenuItem(item));
  5329. }
  5330. this.tabsMenu.add({
  5331. text : this.tabScrollerMenu.menuPrefixText + ' ' + (start + 1) + ' - ' + (start + menuItems.length),
  5332. menu : menuItems
  5333. });
  5334. }
  5335. }
  5336. else {
  5337. this.items.each(function(item) {
  5338. if (item.id != curActive.id && ! item.hidden) {
  5339. menuItems.push(this.autoGenMenuItem(item));
  5340. }
  5341. }, this);
  5342. }
  5343. },
  5344. // private
  5345. autoGenMenuItem : function(item) {
  5346. var maxText = this.tabScrollerMenu.getMaxText();
  5347. var text = Ext.util.Format.ellipsis(item.title, maxText);
  5348. return {
  5349. text : text,
  5350. handler : this.showTabFromMenu,
  5351. scope : this,
  5352. disabled : item.disabled,
  5353. tabToShow : item,
  5354. iconCls : item.iconCls
  5355. }
  5356. },
  5357. // private
  5358. showTabFromMenu : function(menuItem) {
  5359. this.setActiveTab(menuItem.tabToShow);
  5360. }
  5361. }
  5362. });
  5363. Ext.ns('Ext.ux.tree');
  5364. /**
  5365. * @class Ext.ux.tree.XmlTreeLoader
  5366. * @extends Ext.tree.TreeLoader
  5367. * <p>A TreeLoader that can convert an XML document into a hierarchy of {@link Ext.tree.TreeNode}s.
  5368. * Any text value included as a text node in the XML will be added to the parent node as an attribute
  5369. * called <tt>innerText</tt>. Also, the tag name of each XML node will be added to the tree node as
  5370. * an attribute called <tt>tagName</tt>.</p>
  5371. * <p>By default, this class expects that your source XML will provide the necessary attributes on each
  5372. * node as expected by the {@link Ext.tree.TreePanel} to display and load properly. However, you can
  5373. * provide your own custom processing of node attributes by overriding the {@link #processNode} method
  5374. * and modifying the attributes as needed before they are used to create the associated TreeNode.</p>
  5375. * @constructor
  5376. * Creates a new XmlTreeloader.
  5377. * @param {Object} config A config object containing config properties.
  5378. */
  5379. Ext.ux.tree.XmlTreeLoader = Ext.extend(Ext.tree.TreeLoader, {
  5380. /**
  5381. * @property XML_NODE_ELEMENT
  5382. * XML element node (value 1, read-only)
  5383. * @type Number
  5384. */
  5385. XML_NODE_ELEMENT : 1,
  5386. /**
  5387. * @property XML_NODE_TEXT
  5388. * XML text node (value 3, read-only)
  5389. * @type Number
  5390. */
  5391. XML_NODE_TEXT : 3,
  5392. // private override
  5393. processResponse : function(response, node, callback){
  5394. var xmlData = response.responseXML;
  5395. var root = xmlData.documentElement || xmlData;
  5396. try{
  5397. node.beginUpdate();
  5398. node.appendChild(this.parseXml(root));
  5399. node.endUpdate();
  5400. if(typeof callback == "function"){
  5401. callback(this, node);
  5402. }
  5403. }catch(e){
  5404. this.handleFailure(response);
  5405. }
  5406. },
  5407. // private
  5408. parseXml : function(node) {
  5409. var nodes = [];
  5410. Ext.each(node.childNodes, function(n){
  5411. if(n.nodeType == this.XML_NODE_ELEMENT){
  5412. var treeNode = this.createNode(n);
  5413. if(n.childNodes.length > 0){
  5414. var child = this.parseXml(n);
  5415. if(typeof child == 'string'){
  5416. treeNode.attributes.innerText = child;
  5417. }else{
  5418. treeNode.appendChild(child);
  5419. }
  5420. }
  5421. nodes.push(treeNode);
  5422. }
  5423. else if(n.nodeType == this.XML_NODE_TEXT){
  5424. var text = n.nodeValue.trim();
  5425. if(text.length > 0){
  5426. return nodes = text;
  5427. }
  5428. }
  5429. }, this);
  5430. return nodes;
  5431. },
  5432. // private override
  5433. createNode : function(node){
  5434. var attr = {
  5435. tagName: node.tagName
  5436. };
  5437. Ext.each(node.attributes, function(a){
  5438. attr[a.nodeName] = a.nodeValue;
  5439. });
  5440. this.processAttributes(attr);
  5441. return Ext.ux.tree.XmlTreeLoader.superclass.createNode.call(this, attr);
  5442. },
  5443. /*
  5444. * Template method intended to be overridden by subclasses that need to provide
  5445. * custom attribute processing prior to the creation of each TreeNode. This method
  5446. * will be passed a config object containing existing TreeNode attribute name/value
  5447. * pairs which can be modified as needed directly (no need to return the object).
  5448. */
  5449. processAttributes: Ext.emptyFn
  5450. });
  5451. //backwards compat
  5452. Ext.ux.XmlTreeLoader = Ext.ux.tree.XmlTreeLoader;