kityminder.edit.js 1.7 MB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464274652746627467274682746927470274712747227473274742747527476274772747827479274802748127482274832748427485274862748727488274892749027491274922749327494274952749627497274982749927500275012750227503275042750527506275072750827509275102751127512275132751427515275162751727518275192752027521275222752327524275252752627527275282752927530275312753227533275342753527536275372753827539275402754127542275432754427545275462754727548275492755027551275522755327554275552755627557275582755927560275612756227563275642756527566275672756827569275702757127572275732757427575275762757727578275792758027581275822758327584275852758627587275882758927590275912759227593275942759527596275972759827599276002760127602276032760427605276062760727608276092761027611276122761327614276152761627617276182761927620276212762227623276242762527626276272762827629276302763127632276332763427635276362763727638276392764027641276422764327644276452764627647276482764927650276512765227653276542765527656276572765827659276602766127662276632766427665276662766727668276692767027671276722767327674276752767627677276782767927680276812768227683276842768527686276872768827689276902769127692276932769427695276962769727698276992770027701277022770327704277052770627707277082770927710277112771227713277142771527716277172771827719277202772127722277232772427725277262772727728277292773027731277322773327734277352773627737277382773927740277412774227743277442774527746277472774827749277502775127752277532775427755277562775727758277592776027761277622776327764277652776627767277682776927770277712777227773277742777527776277772777827779277802778127782277832778427785277862778727788277892779027791277922779327794277952779627797277982779927800278012780227803278042780527806278072780827809278102781127812278132781427815278162781727818278192782027821278222782327824278252782627827278282782927830278312783227833278342783527836278372783827839278402784127842278432784427845278462784727848278492785027851278522785327854278552785627857278582785927860278612786227863278642786527866278672786827869278702787127872278732787427875278762787727878278792788027881278822788327884278852788627887278882788927890278912789227893278942789527896278972789827899279002790127902279032790427905279062790727908279092791027911279122791327914279152791627917279182791927920279212792227923279242792527926279272792827929279302793127932279332793427935279362793727938279392794027941279422794327944279452794627947279482794927950279512795227953279542795527956279572795827959279602796127962279632796427965279662796727968279692797027971279722797327974279752797627977279782797927980279812798227983279842798527986279872798827989279902799127992279932799427995279962799727998279992800028001280022800328004280052800628007280082800928010280112801228013280142801528016280172801828019280202802128022280232802428025280262802728028280292803028031280322803328034280352803628037280382803928040280412804228043280442804528046280472804828049280502805128052280532805428055280562805728058280592806028061280622806328064280652806628067280682806928070280712807228073280742807528076280772807828079280802808128082280832808428085280862808728088280892809028091280922809328094280952809628097280982809928100281012810228103281042810528106281072810828109281102811128112281132811428115281162811728118281192812028121281222812328124281252812628127281282812928130281312813228133281342813528136281372813828139281402814128142281432814428145281462814728148281492815028151281522815328154281552815628157281582815928160281612816228163281642816528166281672816828169281702817128172281732817428175281762817728178281792818028181281822818328184281852818628187281882818928190281912819228193281942819528196281972819828199282002820128202282032820428205282062820728208282092821028211282122821328214282152821628217282182821928220282212822228223282242822528226282272822828229282302823128232282332823428235282362823728238282392824028241282422824328244282452824628247282482824928250282512825228253282542825528256282572825828259282602826128262282632826428265282662826728268282692827028271282722827328274282752827628277282782827928280282812828228283282842828528286282872828828289282902829128292282932829428295282962829728298282992830028301283022830328304283052830628307283082830928310283112831228313283142831528316283172831828319283202832128322283232832428325283262832728328283292833028331283322833328334283352833628337283382833928340283412834228343283442834528346283472834828349283502835128352283532835428355283562835728358283592836028361283622836328364283652836628367283682836928370283712837228373283742837528376283772837828379283802838128382283832838428385283862838728388283892839028391283922839328394283952839628397283982839928400284012840228403284042840528406284072840828409284102841128412284132841428415284162841728418284192842028421284222842328424284252842628427284282842928430284312843228433284342843528436284372843828439284402844128442284432844428445284462844728448284492845028451284522845328454284552845628457284582845928460284612846228463284642846528466284672846828469284702847128472284732847428475284762847728478284792848028481284822848328484284852848628487284882848928490284912849228493284942849528496284972849828499285002850128502285032850428505285062850728508285092851028511285122851328514285152851628517285182851928520285212852228523285242852528526285272852828529285302853128532285332853428535285362853728538285392854028541285422854328544285452854628547285482854928550285512855228553285542855528556285572855828559285602856128562285632856428565285662856728568285692857028571285722857328574285752857628577285782857928580285812858228583285842858528586285872858828589285902859128592285932859428595285962859728598285992860028601286022860328604286052860628607286082860928610286112861228613286142861528616286172861828619286202862128622286232862428625286262862728628286292863028631286322863328634286352863628637286382863928640286412864228643286442864528646286472864828649286502865128652286532865428655286562865728658286592866028661286622866328664286652866628667286682866928670286712867228673286742867528676286772867828679286802868128682286832868428685286862868728688286892869028691286922869328694286952869628697286982869928700287012870228703287042870528706287072870828709287102871128712287132871428715287162871728718287192872028721287222872328724287252872628727287282872928730287312873228733287342873528736287372873828739287402874128742287432874428745287462874728748287492875028751287522875328754287552875628757287582875928760287612876228763287642876528766287672876828769287702877128772287732877428775287762877728778287792878028781287822878328784287852878628787287882878928790287912879228793287942879528796287972879828799288002880128802288032880428805288062880728808288092881028811288122881328814288152881628817288182881928820288212882228823288242882528826288272882828829288302883128832288332883428835288362883728838288392884028841288422884328844288452884628847288482884928850288512885228853288542885528856288572885828859288602886128862288632886428865288662886728868288692887028871288722887328874288752887628877288782887928880288812888228883288842888528886288872888828889288902889128892288932889428895288962889728898288992890028901289022890328904289052890628907289082890928910289112891228913289142891528916289172891828919289202892128922289232892428925289262892728928289292893028931289322893328934289352893628937289382893928940289412894228943289442894528946289472894828949289502895128952289532895428955289562895728958289592896028961289622896328964289652896628967289682896928970289712897228973289742897528976289772897828979289802898128982289832898428985289862898728988289892899028991289922899328994289952899628997289982899929000290012900229003290042900529006290072900829009290102901129012290132901429015290162901729018290192902029021290222902329024290252902629027290282902929030290312903229033290342903529036290372903829039290402904129042290432904429045290462904729048290492905029051290522905329054290552905629057290582905929060290612906229063290642906529066290672906829069290702907129072290732907429075290762907729078290792908029081290822908329084290852908629087290882908929090290912909229093290942909529096290972909829099291002910129102291032910429105291062910729108291092911029111291122911329114291152911629117291182911929120291212912229123291242912529126291272912829129291302913129132291332913429135291362913729138291392914029141291422914329144291452914629147291482914929150291512915229153291542915529156291572915829159291602916129162291632916429165291662916729168291692917029171291722917329174291752917629177291782917929180291812918229183291842918529186291872918829189291902919129192291932919429195291962919729198291992920029201292022920329204292052920629207292082920929210292112921229213292142921529216292172921829219292202922129222292232922429225292262922729228292292923029231292322923329234292352923629237292382923929240292412924229243292442924529246292472924829249292502925129252292532925429255292562925729258292592926029261292622926329264292652926629267292682926929270292712927229273292742927529276292772927829279292802928129282292832928429285292862928729288292892929029291292922929329294292952929629297292982929929300293012930229303293042930529306293072930829309293102931129312293132931429315293162931729318293192932029321293222932329324293252932629327293282932929330293312933229333293342933529336293372933829339293402934129342293432934429345293462934729348293492935029351293522935329354293552935629357293582935929360293612936229363293642936529366293672936829369293702937129372293732937429375293762937729378293792938029381293822938329384293852938629387293882938929390293912939229393293942939529396293972939829399294002940129402294032940429405294062940729408294092941029411294122941329414294152941629417294182941929420294212942229423294242942529426294272942829429294302943129432294332943429435294362943729438294392944029441294422944329444294452944629447294482944929450294512945229453294542945529456294572945829459294602946129462294632946429465294662946729468294692947029471294722947329474294752947629477294782947929480294812948229483294842948529486294872948829489294902949129492294932949429495294962949729498294992950029501295022950329504295052950629507295082950929510295112951229513295142951529516295172951829519295202952129522295232952429525295262952729528295292953029531295322953329534295352953629537295382953929540295412954229543295442954529546295472954829549295502955129552295532955429555295562955729558295592956029561295622956329564295652956629567295682956929570295712957229573295742957529576295772957829579295802958129582295832958429585295862958729588295892959029591295922959329594295952959629597295982959929600296012960229603296042960529606296072960829609296102961129612296132961429615296162961729618296192962029621296222962329624296252962629627296282962929630296312963229633296342963529636296372963829639296402964129642296432964429645296462964729648296492965029651296522965329654296552965629657296582965929660296612966229663296642966529666296672966829669296702967129672296732967429675296762967729678296792968029681296822968329684296852968629687296882968929690296912969229693296942969529696296972969829699297002970129702297032970429705297062970729708297092971029711297122971329714297152971629717297182971929720297212972229723297242972529726297272972829729297302973129732297332973429735297362973729738297392974029741297422974329744297452974629747297482974929750297512975229753297542975529756297572975829759297602976129762297632976429765297662976729768297692977029771297722977329774297752977629777297782977929780297812978229783297842978529786297872978829789297902979129792297932979429795297962979729798297992980029801298022980329804298052980629807298082980929810298112981229813298142981529816298172981829819298202982129822298232982429825298262982729828298292983029831298322983329834298352983629837298382983929840298412984229843298442984529846298472984829849298502985129852298532985429855298562985729858298592986029861298622986329864298652986629867298682986929870298712987229873298742987529876298772987829879298802988129882298832988429885298862988729888298892989029891298922989329894298952989629897298982989929900299012990229903299042990529906299072990829909299102991129912299132991429915299162991729918299192992029921299222992329924299252992629927299282992929930299312993229933299342993529936299372993829939299402994129942299432994429945299462994729948299492995029951299522995329954299552995629957299582995929960299612996229963299642996529966299672996829969299702997129972299732997429975299762997729978299792998029981299822998329984299852998629987299882998929990299912999229993299942999529996299972999829999300003000130002300033000430005300063000730008300093001030011300123001330014300153001630017300183001930020300213002230023300243002530026300273002830029300303003130032300333003430035300363003730038300393004030041300423004330044300453004630047300483004930050300513005230053300543005530056300573005830059300603006130062300633006430065300663006730068300693007030071300723007330074300753007630077300783007930080300813008230083300843008530086300873008830089300903009130092300933009430095300963009730098300993010030101301023010330104301053010630107301083010930110301113011230113301143011530116301173011830119301203012130122301233012430125301263012730128301293013030131301323013330134301353013630137301383013930140301413014230143301443014530146301473014830149301503015130152301533015430155301563015730158301593016030161301623016330164301653016630167301683016930170301713017230173301743017530176301773017830179301803018130182301833018430185301863018730188301893019030191301923019330194301953019630197301983019930200302013020230203302043020530206302073020830209302103021130212302133021430215302163021730218302193022030221302223022330224302253022630227302283022930230302313023230233302343023530236302373023830239302403024130242302433024430245302463024730248302493025030251302523025330254302553025630257302583025930260302613026230263302643026530266302673026830269302703027130272302733027430275302763027730278302793028030281302823028330284302853028630287302883028930290302913029230293302943029530296302973029830299303003030130302303033030430305303063030730308303093031030311303123031330314303153031630317303183031930320303213032230323303243032530326303273032830329303303033130332303333033430335303363033730338303393034030341303423034330344303453034630347303483034930350303513035230353303543035530356303573035830359303603036130362303633036430365303663036730368303693037030371303723037330374303753037630377303783037930380303813038230383303843038530386303873038830389303903039130392303933039430395303963039730398303993040030401304023040330404304053040630407304083040930410304113041230413304143041530416304173041830419304203042130422304233042430425304263042730428304293043030431304323043330434304353043630437304383043930440304413044230443304443044530446304473044830449304503045130452304533045430455304563045730458304593046030461304623046330464304653046630467304683046930470304713047230473304743047530476304773047830479304803048130482304833048430485304863048730488304893049030491304923049330494304953049630497304983049930500305013050230503305043050530506305073050830509305103051130512305133051430515305163051730518305193052030521305223052330524305253052630527305283052930530305313053230533305343053530536305373053830539305403054130542305433054430545305463054730548305493055030551305523055330554305553055630557305583055930560305613056230563305643056530566305673056830569305703057130572305733057430575305763057730578305793058030581305823058330584305853058630587305883058930590305913059230593305943059530596305973059830599306003060130602306033060430605306063060730608306093061030611306123061330614306153061630617306183061930620306213062230623306243062530626306273062830629306303063130632306333063430635306363063730638306393064030641306423064330644306453064630647306483064930650306513065230653306543065530656306573065830659306603066130662306633066430665306663066730668306693067030671306723067330674306753067630677306783067930680306813068230683306843068530686306873068830689306903069130692306933069430695306963069730698306993070030701307023070330704307053070630707307083070930710307113071230713307143071530716307173071830719307203072130722307233072430725307263072730728307293073030731307323073330734307353073630737307383073930740307413074230743307443074530746307473074830749307503075130752307533075430755307563075730758307593076030761307623076330764307653076630767307683076930770307713077230773307743077530776307773077830779307803078130782307833078430785307863078730788307893079030791307923079330794307953079630797307983079930800308013080230803308043080530806308073080830809308103081130812308133081430815308163081730818308193082030821308223082330824308253082630827308283082930830308313083230833308343083530836308373083830839308403084130842308433084430845308463084730848308493085030851308523085330854308553085630857308583085930860308613086230863308643086530866308673086830869308703087130872308733087430875308763087730878308793088030881308823088330884308853088630887308883088930890308913089230893308943089530896308973089830899309003090130902309033090430905309063090730908309093091030911309123091330914309153091630917309183091930920309213092230923309243092530926309273092830929309303093130932309333093430935309363093730938309393094030941309423094330944309453094630947309483094930950309513095230953309543095530956309573095830959309603096130962309633096430965309663096730968309693097030971309723097330974309753097630977309783097930980309813098230983309843098530986309873098830989309903099130992309933099430995309963099730998309993100031001310023100331004310053100631007310083100931010310113101231013310143101531016310173101831019310203102131022310233102431025310263102731028310293103031031310323103331034310353103631037310383103931040310413104231043310443104531046310473104831049310503105131052310533105431055310563105731058310593106031061310623106331064310653106631067310683106931070310713107231073310743107531076310773107831079310803108131082310833108431085310863108731088310893109031091310923109331094310953109631097310983109931100311013110231103311043110531106311073110831109311103111131112311133111431115311163111731118311193112031121311223112331124311253112631127311283112931130311313113231133311343113531136311373113831139311403114131142311433114431145311463114731148311493115031151311523115331154311553115631157311583115931160311613116231163311643116531166311673116831169311703117131172311733117431175311763117731178311793118031181311823118331184311853118631187311883118931190311913119231193311943119531196311973119831199312003120131202312033120431205312063120731208312093121031211312123121331214312153121631217312183121931220312213122231223312243122531226312273122831229312303123131232312333123431235312363123731238312393124031241312423124331244312453124631247312483124931250312513125231253312543125531256312573125831259312603126131262312633126431265312663126731268312693127031271312723127331274312753127631277312783127931280312813128231283312843128531286312873128831289312903129131292312933129431295312963129731298312993130031301313023130331304313053130631307313083130931310313113131231313313143131531316313173131831319313203132131322313233132431325313263132731328313293133031331313323133331334313353133631337313383133931340313413134231343313443134531346313473134831349313503135131352313533135431355313563135731358313593136031361313623136331364313653136631367313683136931370313713137231373313743137531376313773137831379313803138131382313833138431385313863138731388313893139031391313923139331394313953139631397313983139931400314013140231403314043140531406314073140831409314103141131412314133141431415314163141731418314193142031421314223142331424314253142631427314283142931430314313143231433314343143531436314373143831439314403144131442314433144431445314463144731448314493145031451314523145331454314553145631457314583145931460314613146231463314643146531466314673146831469314703147131472314733147431475314763147731478314793148031481314823148331484314853148631487314883148931490314913149231493314943149531496314973149831499315003150131502315033150431505315063150731508315093151031511315123151331514315153151631517315183151931520315213152231523315243152531526315273152831529315303153131532315333153431535315363153731538315393154031541315423154331544315453154631547315483154931550315513155231553315543155531556315573155831559315603156131562315633156431565315663156731568315693157031571315723157331574315753157631577315783157931580315813158231583315843158531586315873158831589315903159131592315933159431595315963159731598315993160031601316023160331604316053160631607316083160931610316113161231613316143161531616316173161831619316203162131622316233162431625316263162731628316293163031631316323163331634316353163631637316383163931640316413164231643316443164531646316473164831649316503165131652316533165431655316563165731658316593166031661316623166331664316653166631667316683166931670316713167231673316743167531676316773167831679316803168131682316833168431685316863168731688316893169031691316923169331694316953169631697316983169931700317013170231703317043170531706317073170831709317103171131712317133171431715317163171731718317193172031721317223172331724317253172631727317283172931730317313173231733317343173531736317373173831739317403174131742317433174431745317463174731748317493175031751317523175331754317553175631757317583175931760317613176231763317643176531766317673176831769317703177131772317733177431775317763177731778317793178031781317823178331784317853178631787317883178931790317913179231793317943179531796317973179831799318003180131802318033180431805318063180731808318093181031811318123181331814318153181631817318183181931820318213182231823318243182531826318273182831829318303183131832318333183431835318363183731838318393184031841318423184331844318453184631847318483184931850318513185231853318543185531856318573185831859318603186131862318633186431865318663186731868318693187031871318723187331874318753187631877318783187931880318813188231883318843188531886318873188831889318903189131892318933189431895318963189731898318993190031901319023190331904319053190631907319083190931910319113191231913319143191531916319173191831919319203192131922319233192431925319263192731928319293193031931319323193331934319353193631937319383193931940319413194231943319443194531946319473194831949319503195131952319533195431955319563195731958319593196031961319623196331964319653196631967319683196931970319713197231973319743197531976319773197831979319803198131982319833198431985319863198731988319893199031991319923199331994319953199631997319983199932000320013200232003320043200532006320073200832009320103201132012320133201432015320163201732018320193202032021320223202332024320253202632027320283202932030320313203232033320343203532036320373203832039320403204132042320433204432045320463204732048320493205032051320523205332054320553205632057320583205932060320613206232063320643206532066320673206832069320703207132072320733207432075320763207732078320793208032081320823208332084320853208632087320883208932090320913209232093320943209532096320973209832099321003210132102321033210432105321063210732108321093211032111321123211332114321153211632117321183211932120321213212232123321243212532126321273212832129321303213132132321333213432135321363213732138321393214032141321423214332144321453214632147321483214932150321513215232153321543215532156321573215832159321603216132162321633216432165321663216732168321693217032171321723217332174321753217632177321783217932180321813218232183321843218532186321873218832189321903219132192321933219432195321963219732198321993220032201322023220332204322053220632207322083220932210322113221232213322143221532216322173221832219322203222132222322233222432225322263222732228322293223032231322323223332234322353223632237322383223932240322413224232243322443224532246322473224832249322503225132252322533225432255322563225732258322593226032261322623226332264322653226632267322683226932270322713227232273322743227532276322773227832279322803228132282322833228432285322863228732288322893229032291322923229332294322953229632297322983229932300323013230232303323043230532306323073230832309323103231132312323133231432315323163231732318323193232032321323223232332324323253232632327323283232932330323313233232333323343233532336323373233832339323403234132342323433234432345323463234732348323493235032351323523235332354323553235632357323583235932360323613236232363323643236532366323673236832369323703237132372323733237432375323763237732378323793238032381323823238332384323853238632387323883238932390323913239232393323943239532396323973239832399324003240132402324033240432405324063240732408324093241032411324123241332414324153241632417324183241932420324213242232423324243242532426324273242832429324303243132432324333243432435324363243732438324393244032441324423244332444324453244632447324483244932450324513245232453324543245532456324573245832459324603246132462324633246432465324663246732468324693247032471324723247332474324753247632477324783247932480324813248232483324843248532486324873248832489324903249132492324933249432495324963249732498324993250032501325023250332504325053250632507325083250932510325113251232513325143251532516325173251832519325203252132522325233252432525325263252732528325293253032531325323253332534325353253632537325383253932540325413254232543325443254532546325473254832549325503255132552325533255432555325563255732558325593256032561325623256332564325653256632567325683256932570325713257232573325743257532576325773257832579325803258132582325833258432585325863258732588325893259032591325923259332594325953259632597325983259932600326013260232603326043260532606326073260832609326103261132612326133261432615326163261732618326193262032621326223262332624326253262632627326283262932630326313263232633326343263532636326373263832639326403264132642326433264432645326463264732648326493265032651326523265332654326553265632657326583265932660326613266232663326643266532666326673266832669326703267132672326733267432675326763267732678326793268032681326823268332684326853268632687326883268932690326913269232693326943269532696326973269832699327003270132702327033270432705327063270732708327093271032711327123271332714327153271632717327183271932720327213272232723327243272532726327273272832729327303273132732327333273432735327363273732738327393274032741327423274332744327453274632747327483274932750327513275232753327543275532756327573275832759327603276132762327633276432765327663276732768327693277032771327723277332774327753277632777327783277932780327813278232783327843278532786327873278832789327903279132792327933279432795327963279732798327993280032801328023280332804328053280632807328083280932810328113281232813328143281532816328173281832819328203282132822328233282432825328263282732828328293283032831328323283332834328353283632837328383283932840328413284232843328443284532846328473284832849328503285132852328533285432855328563285732858328593286032861328623286332864328653286632867328683286932870328713287232873328743287532876328773287832879328803288132882328833288432885328863288732888328893289032891328923289332894328953289632897328983289932900329013290232903329043290532906329073290832909329103291132912329133291432915329163291732918329193292032921329223292332924329253292632927329283292932930329313293232933329343293532936329373293832939329403294132942329433294432945329463294732948329493295032951329523295332954329553295632957329583295932960329613296232963329643296532966329673296832969329703297132972329733297432975329763297732978329793298032981329823298332984329853298632987329883298932990329913299232993329943299532996329973299832999330003300133002330033300433005330063300733008330093301033011330123301333014330153301633017330183301933020330213302233023330243302533026330273302833029330303303133032330333303433035330363303733038330393304033041330423304333044330453304633047330483304933050330513305233053330543305533056330573305833059330603306133062330633306433065330663306733068330693307033071330723307333074330753307633077330783307933080330813308233083330843308533086330873308833089330903309133092330933309433095330963309733098330993310033101331023310333104331053310633107331083310933110331113311233113331143311533116331173311833119331203312133122331233312433125331263312733128331293313033131331323313333134331353313633137331383313933140331413314233143331443314533146331473314833149331503315133152331533315433155331563315733158331593316033161331623316333164331653316633167331683316933170331713317233173331743317533176331773317833179331803318133182331833318433185331863318733188331893319033191331923319333194331953319633197331983319933200332013320233203332043320533206332073320833209332103321133212332133321433215332163321733218332193322033221332223322333224332253322633227332283322933230332313323233233332343323533236332373323833239332403324133242332433324433245332463324733248332493325033251332523325333254332553325633257332583325933260332613326233263332643326533266332673326833269332703327133272332733327433275332763327733278332793328033281332823328333284332853328633287332883328933290332913329233293332943329533296332973329833299333003330133302333033330433305333063330733308333093331033311333123331333314333153331633317333183331933320333213332233323333243332533326333273332833329333303333133332333333333433335333363333733338333393334033341333423334333344333453334633347333483334933350333513335233353333543335533356333573335833359333603336133362333633336433365333663336733368333693337033371333723337333374333753337633377333783337933380333813338233383333843338533386333873338833389333903339133392333933339433395333963339733398333993340033401334023340333404334053340633407334083340933410334113341233413334143341533416334173341833419334203342133422334233342433425334263342733428334293343033431334323343333434334353343633437334383343933440334413344233443334443344533446334473344833449334503345133452334533345433455334563345733458334593346033461334623346333464334653346633467334683346933470334713347233473334743347533476334773347833479334803348133482334833348433485334863348733488334893349033491334923349333494334953349633497334983349933500335013350233503335043350533506335073350833509335103351133512335133351433515335163351733518335193352033521335223352333524335253352633527335283352933530335313353233533335343353533536335373353833539335403354133542335433354433545335463354733548335493355033551335523355333554335553355633557335583355933560335613356233563335643356533566335673356833569335703357133572335733357433575335763357733578335793358033581335823358333584335853358633587335883358933590335913359233593335943359533596335973359833599336003360133602336033360433605336063360733608336093361033611336123361333614336153361633617336183361933620336213362233623336243362533626336273362833629336303363133632336333363433635336363363733638336393364033641336423364333644336453364633647336483364933650336513365233653336543365533656336573365833659336603366133662336633366433665336663366733668336693367033671336723367333674336753367633677336783367933680336813368233683336843368533686336873368833689336903369133692336933369433695336963369733698336993370033701337023370333704337053370633707337083370933710337113371233713337143371533716337173371833719337203372133722337233372433725337263372733728337293373033731337323373333734337353373633737337383373933740337413374233743337443374533746337473374833749337503375133752337533375433755337563375733758337593376033761337623376333764337653376633767337683376933770337713377233773337743377533776337773377833779337803378133782337833378433785337863378733788337893379033791337923379333794337953379633797337983379933800338013380233803338043380533806338073380833809338103381133812338133381433815338163381733818338193382033821338223382333824338253382633827338283382933830338313383233833338343383533836338373383833839338403384133842338433384433845338463384733848338493385033851338523385333854338553385633857338583385933860338613386233863338643386533866338673386833869338703387133872338733387433875338763387733878338793388033881338823388333884338853388633887338883388933890338913389233893338943389533896338973389833899339003390133902339033390433905339063390733908339093391033911339123391333914339153391633917339183391933920339213392233923339243392533926339273392833929339303393133932339333393433935339363393733938339393394033941339423394333944339453394633947339483394933950339513395233953339543395533956339573395833959339603396133962339633396433965339663396733968339693397033971339723397333974339753397633977339783397933980339813398233983339843398533986339873398833989339903399133992339933399433995339963399733998339993400034001340023400334004340053400634007340083400934010340113401234013340143401534016340173401834019340203402134022340233402434025340263402734028340293403034031340323403334034340353403634037340383403934040340413404234043340443404534046340473404834049340503405134052340533405434055340563405734058340593406034061340623406334064340653406634067340683406934070340713407234073340743407534076340773407834079340803408134082340833408434085340863408734088340893409034091340923409334094340953409634097340983409934100341013410234103341043410534106341073410834109341103411134112341133411434115341163411734118341193412034121341223412334124341253412634127341283412934130341313413234133341343413534136341373413834139341403414134142341433414434145341463414734148341493415034151341523415334154341553415634157341583415934160341613416234163341643416534166341673416834169341703417134172341733417434175341763417734178341793418034181341823418334184341853418634187341883418934190341913419234193341943419534196341973419834199342003420134202342033420434205342063420734208342093421034211342123421334214342153421634217342183421934220342213422234223342243422534226342273422834229342303423134232342333423434235342363423734238342393424034241342423424334244342453424634247342483424934250342513425234253342543425534256342573425834259342603426134262342633426434265342663426734268342693427034271342723427334274342753427634277342783427934280342813428234283342843428534286342873428834289342903429134292342933429434295342963429734298342993430034301343023430334304343053430634307343083430934310343113431234313343143431534316343173431834319343203432134322343233432434325343263432734328343293433034331343323433334334343353433634337343383433934340343413434234343343443434534346343473434834349343503435134352343533435434355343563435734358343593436034361343623436334364343653436634367343683436934370343713437234373343743437534376343773437834379343803438134382343833438434385343863438734388343893439034391343923439334394343953439634397343983439934400344013440234403344043440534406344073440834409344103441134412344133441434415344163441734418344193442034421344223442334424344253442634427344283442934430344313443234433344343443534436344373443834439344403444134442344433444434445344463444734448344493445034451344523445334454344553445634457344583445934460344613446234463344643446534466344673446834469344703447134472344733447434475344763447734478344793448034481344823448334484344853448634487344883448934490344913449234493344943449534496344973449834499345003450134502345033450434505345063450734508345093451034511345123451334514345153451634517345183451934520345213452234523345243452534526345273452834529345303453134532345333453434535345363453734538345393454034541345423454334544345453454634547345483454934550345513455234553345543455534556345573455834559345603456134562345633456434565345663456734568345693457034571345723457334574345753457634577345783457934580345813458234583345843458534586345873458834589345903459134592345933459434595345963459734598345993460034601346023460334604346053460634607346083460934610346113461234613346143461534616346173461834619346203462134622346233462434625346263462734628346293463034631346323463334634346353463634637346383463934640346413464234643346443464534646346473464834649346503465134652346533465434655346563465734658346593466034661346623466334664346653466634667346683466934670346713467234673346743467534676346773467834679346803468134682346833468434685346863468734688346893469034691346923469334694346953469634697346983469934700347013470234703347043470534706347073470834709347103471134712347133471434715347163471734718347193472034721347223472334724347253472634727347283472934730347313473234733347343473534736347373473834739347403474134742347433474434745347463474734748347493475034751347523475334754347553475634757347583475934760347613476234763347643476534766347673476834769347703477134772347733477434775347763477734778347793478034781347823478334784347853478634787347883478934790347913479234793347943479534796347973479834799348003480134802348033480434805348063480734808348093481034811348123481334814348153481634817348183481934820348213482234823348243482534826348273482834829348303483134832348333483434835348363483734838348393484034841348423484334844348453484634847348483484934850348513485234853348543485534856348573485834859348603486134862348633486434865348663486734868348693487034871348723487334874348753487634877348783487934880348813488234883348843488534886348873488834889348903489134892348933489434895348963489734898348993490034901349023490334904349053490634907349083490934910349113491234913349143491534916349173491834919349203492134922349233492434925349263492734928349293493034931349323493334934349353493634937349383493934940349413494234943349443494534946349473494834949349503495134952349533495434955349563495734958349593496034961349623496334964349653496634967349683496934970349713497234973349743497534976349773497834979349803498134982349833498434985349863498734988349893499034991349923499334994349953499634997349983499935000350013500235003350043500535006350073500835009350103501135012350133501435015350163501735018350193502035021350223502335024350253502635027350283502935030350313503235033350343503535036350373503835039350403504135042350433504435045350463504735048350493505035051350523505335054350553505635057350583505935060350613506235063350643506535066350673506835069350703507135072350733507435075350763507735078350793508035081350823508335084350853508635087350883508935090350913509235093350943509535096350973509835099351003510135102351033510435105351063510735108351093511035111351123511335114351153511635117351183511935120351213512235123351243512535126351273512835129351303513135132351333513435135351363513735138351393514035141351423514335144351453514635147351483514935150351513515235153351543515535156351573515835159351603516135162351633516435165351663516735168351693517035171351723517335174351753517635177351783517935180351813518235183351843518535186351873518835189351903519135192351933519435195351963519735198351993520035201352023520335204352053520635207352083520935210352113521235213352143521535216352173521835219352203522135222352233522435225352263522735228352293523035231352323523335234352353523635237352383523935240352413524235243352443524535246352473524835249352503525135252352533525435255352563525735258352593526035261352623526335264352653526635267352683526935270352713527235273352743527535276352773527835279352803528135282352833528435285352863528735288352893529035291352923529335294352953529635297352983529935300353013530235303353043530535306353073530835309353103531135312353133531435315353163531735318353193532035321353223532335324353253532635327353283532935330353313533235333353343533535336353373533835339353403534135342353433534435345353463534735348353493535035351353523535335354353553535635357353583535935360353613536235363353643536535366353673536835369353703537135372353733537435375353763537735378353793538035381353823538335384353853538635387353883538935390353913539235393353943539535396353973539835399354003540135402354033540435405354063540735408354093541035411354123541335414354153541635417354183541935420354213542235423354243542535426354273542835429354303543135432354333543435435354363543735438354393544035441354423544335444354453544635447354483544935450354513545235453354543545535456354573545835459354603546135462354633546435465354663546735468354693547035471354723547335474354753547635477354783547935480354813548235483354843548535486354873548835489354903549135492354933549435495354963549735498354993550035501355023550335504355053550635507355083550935510355113551235513355143551535516355173551835519355203552135522355233552435525355263552735528355293553035531355323553335534355353553635537355383553935540355413554235543355443554535546355473554835549355503555135552355533555435555355563555735558355593556035561355623556335564355653556635567355683556935570355713557235573355743557535576355773557835579355803558135582355833558435585355863558735588355893559035591355923559335594355953559635597355983559935600356013560235603356043560535606356073560835609356103561135612356133561435615356163561735618356193562035621356223562335624356253562635627356283562935630356313563235633356343563535636356373563835639356403564135642356433564435645356463564735648356493565035651356523565335654356553565635657356583565935660356613566235663356643566535666356673566835669356703567135672356733567435675356763567735678356793568035681356823568335684356853568635687356883568935690356913569235693356943569535696356973569835699357003570135702357033570435705357063570735708357093571035711357123571335714357153571635717357183571935720357213572235723357243572535726357273572835729357303573135732357333573435735357363573735738357393574035741357423574335744357453574635747357483574935750357513575235753357543575535756357573575835759357603576135762357633576435765357663576735768357693577035771357723577335774357753577635777357783577935780357813578235783357843578535786357873578835789357903579135792357933579435795357963579735798357993580035801358023580335804358053580635807358083580935810358113581235813358143581535816358173581835819358203582135822358233582435825358263582735828358293583035831358323583335834358353583635837358383583935840358413584235843358443584535846358473584835849358503585135852358533585435855358563585735858358593586035861358623586335864358653586635867358683586935870358713587235873358743587535876358773587835879358803588135882358833588435885358863588735888358893589035891358923589335894358953589635897358983589935900359013590235903359043590535906359073590835909359103591135912359133591435915359163591735918359193592035921359223592335924359253592635927359283592935930359313593235933359343593535936359373593835939359403594135942359433594435945359463594735948359493595035951359523595335954359553595635957359583595935960359613596235963359643596535966359673596835969359703597135972359733597435975359763597735978359793598035981359823598335984359853598635987359883598935990359913599235993359943599535996359973599835999360003600136002360033600436005360063600736008360093601036011360123601336014360153601636017360183601936020360213602236023360243602536026360273602836029360303603136032360333603436035360363603736038360393604036041360423604336044360453604636047360483604936050360513605236053360543605536056360573605836059360603606136062360633606436065360663606736068360693607036071360723607336074360753607636077360783607936080360813608236083360843608536086360873608836089360903609136092360933609436095360963609736098360993610036101361023610336104361053610636107361083610936110361113611236113361143611536116361173611836119361203612136122361233612436125361263612736128361293613036131361323613336134361353613636137361383613936140361413614236143361443614536146361473614836149361503615136152361533615436155361563615736158361593616036161361623616336164361653616636167361683616936170361713617236173361743617536176361773617836179361803618136182361833618436185361863618736188361893619036191361923619336194361953619636197361983619936200362013620236203362043620536206362073620836209362103621136212362133621436215362163621736218362193622036221362223622336224362253622636227362283622936230362313623236233362343623536236362373623836239362403624136242362433624436245362463624736248362493625036251362523625336254362553625636257362583625936260362613626236263362643626536266362673626836269362703627136272362733627436275362763627736278362793628036281362823628336284362853628636287362883628936290362913629236293362943629536296362973629836299363003630136302363033630436305363063630736308363093631036311363123631336314363153631636317363183631936320363213632236323363243632536326363273632836329363303633136332363333633436335363363633736338363393634036341363423634336344363453634636347363483634936350363513635236353363543635536356363573635836359363603636136362363633636436365363663636736368363693637036371363723637336374363753637636377363783637936380363813638236383363843638536386363873638836389363903639136392363933639436395363963639736398363993640036401364023640336404364053640636407364083640936410364113641236413364143641536416364173641836419364203642136422364233642436425364263642736428364293643036431364323643336434364353643636437364383643936440364413644236443364443644536446364473644836449364503645136452364533645436455364563645736458364593646036461364623646336464364653646636467364683646936470364713647236473364743647536476364773647836479364803648136482364833648436485364863648736488364893649036491364923649336494364953649636497364983649936500365013650236503365043650536506365073650836509365103651136512365133651436515365163651736518365193652036521365223652336524365253652636527365283652936530365313653236533365343653536536365373653836539365403654136542365433654436545365463654736548365493655036551365523655336554365553655636557365583655936560365613656236563365643656536566365673656836569365703657136572365733657436575365763657736578365793658036581365823658336584365853658636587365883658936590365913659236593365943659536596365973659836599366003660136602366033660436605366063660736608366093661036611366123661336614366153661636617366183661936620366213662236623366243662536626366273662836629366303663136632366333663436635366363663736638366393664036641366423664336644366453664636647366483664936650366513665236653366543665536656366573665836659366603666136662366633666436665366663666736668366693667036671366723667336674366753667636677366783667936680366813668236683366843668536686366873668836689366903669136692366933669436695366963669736698366993670036701367023670336704367053670636707367083670936710367113671236713367143671536716367173671836719367203672136722367233672436725367263672736728367293673036731367323673336734367353673636737367383673936740367413674236743367443674536746367473674836749367503675136752367533675436755367563675736758367593676036761367623676336764367653676636767367683676936770367713677236773367743677536776367773677836779367803678136782367833678436785367863678736788367893679036791367923679336794367953679636797367983679936800368013680236803368043680536806368073680836809368103681136812368133681436815368163681736818368193682036821368223682336824368253682636827368283682936830368313683236833368343683536836368373683836839368403684136842368433684436845368463684736848368493685036851368523685336854368553685636857368583685936860368613686236863368643686536866368673686836869368703687136872368733687436875368763687736878368793688036881368823688336884368853688636887368883688936890368913689236893368943689536896368973689836899369003690136902369033690436905369063690736908369093691036911369123691336914369153691636917369183691936920369213692236923369243692536926369273692836929369303693136932369333693436935369363693736938369393694036941369423694336944369453694636947369483694936950369513695236953369543695536956369573695836959369603696136962369633696436965369663696736968369693697036971369723697336974369753697636977369783697936980369813698236983369843698536986369873698836989369903699136992369933699436995369963699736998369993700037001370023700337004370053700637007370083700937010370113701237013370143701537016370173701837019370203702137022370233702437025370263702737028370293703037031370323703337034370353703637037370383703937040370413704237043370443704537046370473704837049370503705137052370533705437055370563705737058370593706037061370623706337064370653706637067370683706937070370713707237073370743707537076370773707837079370803708137082370833708437085370863708737088370893709037091370923709337094370953709637097370983709937100371013710237103371043710537106371073710837109371103711137112371133711437115371163711737118371193712037121371223712337124371253712637127371283712937130371313713237133371343713537136371373713837139371403714137142371433714437145371463714737148371493715037151371523715337154371553715637157371583715937160371613716237163371643716537166371673716837169371703717137172371733717437175371763717737178371793718037181371823718337184371853718637187371883718937190371913719237193371943719537196371973719837199372003720137202372033720437205372063720737208372093721037211372123721337214372153721637217372183721937220372213722237223372243722537226372273722837229372303723137232372333723437235372363723737238372393724037241372423724337244372453724637247372483724937250372513725237253372543725537256372573725837259372603726137262372633726437265372663726737268372693727037271372723727337274372753727637277372783727937280372813728237283372843728537286372873728837289372903729137292372933729437295372963729737298372993730037301373023730337304373053730637307373083730937310373113731237313373143731537316373173731837319373203732137322373233732437325373263732737328373293733037331373323733337334373353733637337373383733937340373413734237343373443734537346373473734837349373503735137352373533735437355373563735737358373593736037361373623736337364373653736637367373683736937370373713737237373373743737537376373773737837379373803738137382373833738437385373863738737388373893739037391373923739337394373953739637397373983739937400374013740237403374043740537406374073740837409374103741137412374133741437415374163741737418374193742037421374223742337424374253742637427374283742937430374313743237433374343743537436374373743837439374403744137442374433744437445374463744737448374493745037451374523745337454374553745637457374583745937460374613746237463374643746537466374673746837469374703747137472374733747437475374763747737478374793748037481374823748337484374853748637487374883748937490374913749237493374943749537496374973749837499375003750137502375033750437505375063750737508375093751037511375123751337514375153751637517375183751937520375213752237523375243752537526375273752837529375303753137532375333753437535375363753737538375393754037541375423754337544375453754637547375483754937550375513755237553375543755537556375573755837559375603756137562375633756437565375663756737568375693757037571375723757337574375753757637577375783757937580375813758237583375843758537586375873758837589375903759137592375933759437595375963759737598375993760037601376023760337604376053760637607376083760937610376113761237613376143761537616376173761837619376203762137622376233762437625376263762737628376293763037631376323763337634376353763637637376383763937640376413764237643376443764537646376473764837649376503765137652376533765437655376563765737658376593766037661376623766337664376653766637667376683766937670376713767237673376743767537676376773767837679376803768137682376833768437685376863768737688376893769037691376923769337694376953769637697376983769937700377013770237703377043770537706377073770837709377103771137712377133771437715377163771737718377193772037721377223772337724377253772637727377283772937730377313773237733377343773537736377373773837739377403774137742377433774437745377463774737748377493775037751377523775337754377553775637757377583775937760377613776237763377643776537766377673776837769377703777137772377733777437775377763777737778377793778037781377823778337784377853778637787377883778937790377913779237793377943779537796377973779837799378003780137802378033780437805378063780737808378093781037811378123781337814378153781637817378183781937820378213782237823378243782537826378273782837829378303783137832378333783437835378363783737838378393784037841378423784337844378453784637847378483784937850378513785237853378543785537856378573785837859378603786137862378633786437865378663786737868378693787037871378723787337874378753787637877378783787937880378813788237883378843788537886378873788837889378903789137892378933789437895378963789737898378993790037901379023790337904379053790637907379083790937910379113791237913379143791537916379173791837919379203792137922379233792437925379263792737928379293793037931379323793337934379353793637937379383793937940379413794237943379443794537946379473794837949379503795137952379533795437955379563795737958379593796037961379623796337964379653796637967379683796937970379713797237973379743797537976379773797837979379803798137982379833798437985379863798737988379893799037991379923799337994379953799637997379983799938000380013800238003380043800538006380073800838009380103801138012380133801438015380163801738018380193802038021380223802338024380253802638027380283802938030380313803238033380343803538036380373803838039380403804138042380433804438045380463804738048380493805038051380523805338054380553805638057380583805938060380613806238063380643806538066380673806838069380703807138072380733807438075380763807738078380793808038081380823808338084380853808638087380883808938090380913809238093380943809538096380973809838099381003810138102381033810438105381063810738108381093811038111381123811338114381153811638117381183811938120381213812238123381243812538126381273812838129381303813138132381333813438135381363813738138381393814038141381423814338144381453814638147381483814938150381513815238153381543815538156381573815838159381603816138162381633816438165381663816738168381693817038171381723817338174381753817638177381783817938180381813818238183381843818538186381873818838189381903819138192381933819438195381963819738198381993820038201382023820338204382053820638207382083820938210382113821238213382143821538216382173821838219382203822138222382233822438225382263822738228382293823038231382323823338234382353823638237382383823938240382413824238243382443824538246382473824838249382503825138252382533825438255382563825738258382593826038261382623826338264382653826638267382683826938270382713827238273382743827538276382773827838279382803828138282382833828438285382863828738288382893829038291382923829338294382953829638297382983829938300383013830238303383043830538306383073830838309383103831138312383133831438315383163831738318383193832038321383223832338324383253832638327383283832938330383313833238333383343833538336383373833838339383403834138342383433834438345383463834738348383493835038351383523835338354383553835638357383583835938360383613836238363383643836538366383673836838369383703837138372383733837438375383763837738378383793838038381383823838338384383853838638387383883838938390383913839238393383943839538396383973839838399384003840138402384033840438405384063840738408384093841038411384123841338414384153841638417384183841938420384213842238423384243842538426384273842838429384303843138432384333843438435384363843738438384393844038441384423844338444384453844638447384483844938450384513845238453384543845538456384573845838459384603846138462384633846438465384663846738468384693847038471384723847338474384753847638477384783847938480384813848238483384843848538486384873848838489384903849138492384933849438495384963849738498384993850038501385023850338504385053850638507385083850938510385113851238513385143851538516385173851838519385203852138522385233852438525385263852738528385293853038531385323853338534385353853638537385383853938540385413854238543385443854538546385473854838549385503855138552385533855438555385563855738558385593856038561385623856338564385653856638567385683856938570385713857238573385743857538576385773857838579385803858138582385833858438585385863858738588385893859038591385923859338594385953859638597385983859938600386013860238603386043860538606386073860838609386103861138612386133861438615386163861738618386193862038621386223862338624386253862638627386283862938630386313863238633386343863538636386373863838639386403864138642386433864438645386463864738648386493865038651386523865338654386553865638657386583865938660386613866238663386643866538666386673866838669386703867138672386733867438675386763867738678386793868038681386823868338684386853868638687386883868938690386913869238693386943869538696386973869838699387003870138702387033870438705387063870738708387093871038711387123871338714387153871638717387183871938720387213872238723387243872538726387273872838729387303873138732387333873438735387363873738738387393874038741387423874338744387453874638747387483874938750387513875238753387543875538756387573875838759387603876138762387633876438765387663876738768387693877038771387723877338774387753877638777387783877938780387813878238783387843878538786387873878838789387903879138792387933879438795387963879738798387993880038801388023880338804388053880638807388083880938810388113881238813388143881538816388173881838819388203882138822388233882438825388263882738828388293883038831388323883338834388353883638837388383883938840388413884238843388443884538846388473884838849388503885138852388533885438855388563885738858388593886038861388623886338864388653886638867388683886938870388713887238873388743887538876388773887838879388803888138882388833888438885388863888738888388893889038891388923889338894388953889638897388983889938900389013890238903389043890538906389073890838909389103891138912389133891438915389163891738918389193892038921389223892338924389253892638927389283892938930389313893238933389343893538936389373893838939389403894138942389433894438945389463894738948389493895038951389523895338954389553895638957389583895938960389613896238963389643896538966389673896838969389703897138972389733897438975389763897738978389793898038981389823898338984389853898638987389883898938990389913899238993389943899538996389973899838999390003900139002390033900439005390063900739008390093901039011390123901339014390153901639017390183901939020390213902239023390243902539026390273902839029390303903139032390333903439035390363903739038390393904039041390423904339044390453904639047390483904939050390513905239053390543905539056390573905839059390603906139062390633906439065390663906739068390693907039071390723907339074390753907639077390783907939080390813908239083390843908539086390873908839089390903909139092390933909439095390963909739098390993910039101391023910339104391053910639107391083910939110391113911239113391143911539116391173911839119391203912139122391233912439125391263912739128391293913039131391323913339134391353913639137391383913939140391413914239143391443914539146391473914839149391503915139152391533915439155391563915739158391593916039161391623916339164391653916639167391683916939170391713917239173391743917539176391773917839179391803918139182391833918439185391863918739188391893919039191391923919339194391953919639197391983919939200392013920239203392043920539206392073920839209392103921139212392133921439215392163921739218392193922039221392223922339224392253922639227392283922939230392313923239233392343923539236392373923839239392403924139242392433924439245392463924739248392493925039251392523925339254392553925639257392583925939260392613926239263392643926539266392673926839269392703927139272392733927439275392763927739278392793928039281392823928339284392853928639287392883928939290392913929239293392943929539296392973929839299393003930139302393033930439305393063930739308393093931039311393123931339314393153931639317393183931939320393213932239323393243932539326393273932839329393303933139332393333933439335393363933739338393393934039341393423934339344393453934639347393483934939350393513935239353393543935539356393573935839359393603936139362393633936439365393663936739368393693937039371393723937339374393753937639377393783937939380393813938239383393843938539386393873938839389393903939139392393933939439395393963939739398393993940039401394023940339404394053940639407394083940939410394113941239413394143941539416394173941839419394203942139422394233942439425394263942739428394293943039431394323943339434394353943639437394383943939440394413944239443394443944539446394473944839449394503945139452394533945439455394563945739458394593946039461394623946339464394653946639467394683946939470394713947239473394743947539476394773947839479394803948139482394833948439485394863948739488394893949039491394923949339494394953949639497394983949939500395013950239503395043950539506395073950839509395103951139512395133951439515395163951739518395193952039521395223952339524395253952639527395283952939530395313953239533395343953539536395373953839539395403954139542395433954439545395463954739548395493955039551395523955339554395553955639557395583955939560395613956239563395643956539566395673956839569395703957139572395733957439575395763957739578395793958039581395823958339584395853958639587395883958939590395913959239593395943959539596395973959839599396003960139602396033960439605396063960739608396093961039611396123961339614396153961639617396183961939620396213962239623396243962539626396273962839629396303963139632396333963439635396363963739638396393964039641396423964339644396453964639647396483964939650396513965239653396543965539656396573965839659396603966139662396633966439665396663966739668396693967039671396723967339674396753967639677396783967939680396813968239683396843968539686396873968839689396903969139692396933969439695396963969739698396993970039701397023970339704397053970639707397083970939710397113971239713397143971539716397173971839719397203972139722397233972439725397263972739728397293973039731397323973339734397353973639737397383973939740397413974239743397443974539746397473974839749397503975139752397533975439755397563975739758397593976039761397623976339764397653976639767397683976939770397713977239773397743977539776397773977839779397803978139782397833978439785397863978739788397893979039791397923979339794397953979639797397983979939800398013980239803398043980539806398073980839809398103981139812398133981439815398163981739818398193982039821398223982339824398253982639827398283982939830398313983239833398343983539836398373983839839398403984139842398433984439845398463984739848398493985039851398523985339854398553985639857398583985939860398613986239863398643986539866398673986839869398703987139872398733987439875398763987739878398793988039881398823988339884398853988639887398883988939890398913989239893398943989539896398973989839899399003990139902399033990439905399063990739908399093991039911399123991339914399153991639917399183991939920399213992239923399243992539926399273992839929399303993139932399333993439935399363993739938399393994039941399423994339944399453994639947399483994939950399513995239953399543995539956399573995839959399603996139962399633996439965399663996739968399693997039971399723997339974399753997639977399783997939980399813998239983399843998539986399873998839989399903999139992399933999439995399963999739998399994000040001400024000340004400054000640007400084000940010400114001240013400144001540016400174001840019400204002140022400234002440025400264002740028400294003040031400324003340034400354003640037400384003940040400414004240043400444004540046400474004840049400504005140052400534005440055400564005740058400594006040061400624006340064400654006640067400684006940070400714007240073400744007540076400774007840079400804008140082400834008440085400864008740088400894009040091400924009340094400954009640097400984009940100401014010240103401044010540106401074010840109401104011140112401134011440115401164011740118401194012040121401224012340124401254012640127401284012940130401314013240133401344013540136401374013840139401404014140142401434014440145401464014740148401494015040151401524015340154401554015640157401584015940160401614016240163401644016540166401674016840169401704017140172401734017440175401764017740178401794018040181401824018340184401854018640187401884018940190401914019240193401944019540196401974019840199402004020140202402034020440205402064020740208402094021040211402124021340214402154021640217402184021940220402214022240223402244022540226402274022840229402304023140232402334023440235402364023740238402394024040241402424024340244402454024640247402484024940250402514025240253402544025540256402574025840259402604026140262402634026440265402664026740268402694027040271402724027340274402754027640277402784027940280402814028240283402844028540286402874028840289402904029140292402934029440295402964029740298402994030040301403024030340304403054030640307403084030940310403114031240313403144031540316403174031840319403204032140322403234032440325403264032740328403294033040331403324033340334403354033640337403384033940340403414034240343403444034540346403474034840349403504035140352403534035440355403564035740358403594036040361403624036340364403654036640367403684036940370403714037240373403744037540376403774037840379403804038140382403834038440385403864038740388403894039040391403924039340394403954039640397403984039940400404014040240403404044040540406404074040840409404104041140412404134041440415404164041740418404194042040421404224042340424404254042640427404284042940430404314043240433404344043540436404374043840439404404044140442404434044440445404464044740448404494045040451404524045340454404554045640457404584045940460404614046240463404644046540466404674046840469404704047140472404734047440475404764047740478404794048040481404824048340484404854048640487404884048940490404914049240493404944049540496404974049840499405004050140502405034050440505405064050740508405094051040511405124051340514405154051640517405184051940520405214052240523405244052540526405274052840529405304053140532405334053440535405364053740538405394054040541405424054340544405454054640547405484054940550405514055240553405544055540556405574055840559405604056140562405634056440565405664056740568405694057040571405724057340574405754057640577405784057940580405814058240583405844058540586405874058840589405904059140592405934059440595405964059740598405994060040601406024060340604406054060640607406084060940610406114061240613406144061540616406174061840619406204062140622406234062440625406264062740628406294063040631406324063340634406354063640637406384063940640406414064240643406444064540646406474064840649406504065140652406534065440655406564065740658406594066040661406624066340664406654066640667406684066940670406714067240673406744067540676406774067840679406804068140682406834068440685406864068740688406894069040691406924069340694406954069640697406984069940700407014070240703407044070540706407074070840709407104071140712407134071440715407164071740718407194072040721407224072340724407254072640727407284072940730407314073240733407344073540736407374073840739407404074140742407434074440745407464074740748407494075040751407524075340754407554075640757407584075940760407614076240763407644076540766407674076840769407704077140772407734077440775407764077740778407794078040781407824078340784407854078640787407884078940790407914079240793407944079540796407974079840799408004080140802408034080440805408064080740808408094081040811408124081340814408154081640817408184081940820408214082240823408244082540826408274082840829408304083140832408334083440835408364083740838408394084040841408424084340844408454084640847408484084940850408514085240853408544085540856408574085840859408604086140862408634086440865408664086740868408694087040871408724087340874408754087640877408784087940880408814088240883408844088540886408874088840889408904089140892408934089440895408964089740898408994090040901409024090340904409054090640907409084090940910409114091240913409144091540916409174091840919409204092140922409234092440925409264092740928409294093040931409324093340934409354093640937409384093940940409414094240943409444094540946409474094840949409504095140952409534095440955409564095740958409594096040961409624096340964409654096640967409684096940970409714097240973409744097540976409774097840979409804098140982409834098440985409864098740988409894099040991409924099340994409954099640997409984099941000410014100241003410044100541006410074100841009410104101141012410134101441015410164101741018410194102041021410224102341024410254102641027410284102941030410314103241033410344103541036410374103841039410404104141042410434104441045410464104741048410494105041051410524105341054410554105641057410584105941060410614106241063410644106541066410674106841069410704107141072410734107441075410764107741078410794108041081410824108341084410854108641087410884108941090410914109241093410944109541096410974109841099411004110141102411034110441105411064110741108411094111041111411124111341114411154111641117411184111941120411214112241123411244112541126411274112841129411304113141132411334113441135411364113741138411394114041141411424114341144411454114641147411484114941150411514115241153411544115541156411574115841159411604116141162411634116441165411664116741168411694117041171411724117341174411754117641177411784117941180411814118241183411844118541186411874118841189411904119141192411934119441195411964119741198411994120041201412024120341204412054120641207412084120941210412114121241213412144121541216412174121841219412204122141222412234122441225412264122741228412294123041231412324123341234412354123641237412384123941240412414124241243412444124541246412474124841249412504125141252412534125441255412564125741258412594126041261412624126341264412654126641267412684126941270412714127241273412744127541276412774127841279412804128141282412834128441285412864128741288412894129041291412924129341294412954129641297412984129941300413014130241303413044130541306413074130841309413104131141312413134131441315413164131741318413194132041321413224132341324413254132641327413284132941330413314133241333413344133541336413374133841339413404134141342413434134441345413464134741348413494135041351413524135341354413554135641357413584135941360413614136241363413644136541366413674136841369413704137141372413734137441375413764137741378413794138041381413824138341384413854138641387413884138941390413914139241393413944139541396413974139841399414004140141402414034140441405414064140741408414094141041411414124141341414414154141641417414184141941420414214142241423414244142541426414274142841429414304143141432414334143441435414364143741438414394144041441414424144341444414454144641447414484144941450414514145241453414544145541456414574145841459414604146141462414634146441465414664146741468414694147041471414724147341474414754147641477414784147941480414814148241483414844148541486414874148841489414904149141492414934149441495414964149741498414994150041501415024150341504415054150641507415084150941510415114151241513415144151541516415174151841519415204152141522415234152441525415264152741528415294153041531415324153341534415354153641537415384153941540415414154241543415444154541546415474154841549415504155141552415534155441555415564155741558415594156041561415624156341564415654156641567415684156941570415714157241573415744157541576415774157841579415804158141582415834158441585415864158741588415894159041591415924159341594415954159641597415984159941600416014160241603416044160541606416074160841609416104161141612416134161441615416164161741618416194162041621416224162341624416254162641627416284162941630416314163241633416344163541636416374163841639416404164141642416434164441645416464164741648416494165041651416524165341654416554165641657416584165941660416614166241663416644166541666416674166841669416704167141672416734167441675416764167741678416794168041681416824168341684416854168641687416884168941690416914169241693416944169541696416974169841699417004170141702417034170441705417064170741708417094171041711417124171341714417154171641717417184171941720417214172241723417244172541726417274172841729417304173141732417334173441735417364173741738417394174041741417424174341744417454174641747417484174941750417514175241753417544175541756417574175841759417604176141762417634176441765417664176741768417694177041771417724177341774417754177641777417784177941780417814178241783417844178541786417874178841789417904179141792417934179441795417964179741798417994180041801418024180341804418054180641807418084180941810418114181241813418144181541816418174181841819418204182141822418234182441825418264182741828418294183041831418324183341834418354183641837418384183941840418414184241843418444184541846418474184841849418504185141852418534185441855418564185741858418594186041861418624186341864418654186641867418684186941870418714187241873418744187541876418774187841879418804188141882418834188441885418864188741888418894189041891418924189341894418954189641897418984189941900419014190241903419044190541906419074190841909419104191141912419134191441915419164191741918419194192041921419224192341924419254192641927419284192941930419314193241933419344193541936419374193841939419404194141942419434194441945419464194741948419494195041951419524195341954419554195641957419584195941960419614196241963419644196541966419674196841969419704197141972419734197441975419764197741978419794198041981419824198341984419854198641987419884198941990419914199241993419944199541996419974199841999420004200142002420034200442005420064200742008420094201042011420124201342014420154201642017420184201942020420214202242023420244202542026420274202842029420304203142032420334203442035420364203742038420394204042041420424204342044420454204642047420484204942050420514205242053420544205542056420574205842059420604206142062420634206442065420664206742068420694207042071420724207342074420754207642077420784207942080420814208242083420844208542086420874208842089420904209142092420934209442095420964209742098420994210042101421024210342104421054210642107421084210942110421114211242113421144211542116421174211842119421204212142122421234212442125421264212742128421294213042131421324213342134421354213642137421384213942140421414214242143421444214542146421474214842149421504215142152421534215442155421564215742158421594216042161421624216342164421654216642167421684216942170421714217242173421744217542176421774217842179421804218142182421834218442185421864218742188421894219042191421924219342194421954219642197421984219942200422014220242203422044220542206422074220842209422104221142212422134221442215422164221742218422194222042221422224222342224422254222642227422284222942230422314223242233422344223542236422374223842239422404224142242422434224442245422464224742248422494225042251422524225342254422554225642257422584225942260422614226242263422644226542266422674226842269422704227142272422734227442275422764227742278422794228042281422824228342284422854228642287422884228942290422914229242293422944229542296422974229842299423004230142302423034230442305423064230742308423094231042311423124231342314423154231642317423184231942320423214232242323423244232542326423274232842329423304233142332423334233442335423364233742338423394234042341423424234342344423454234642347423484234942350423514235242353423544235542356423574235842359423604236142362423634236442365423664236742368423694237042371423724237342374423754237642377423784237942380423814238242383423844238542386423874238842389423904239142392423934239442395423964239742398423994240042401424024240342404424054240642407424084240942410424114241242413424144241542416424174241842419424204242142422424234242442425424264242742428424294243042431424324243342434424354243642437424384243942440424414244242443424444244542446424474244842449424504245142452424534245442455424564245742458424594246042461424624246342464424654246642467424684246942470424714247242473424744247542476424774247842479424804248142482424834248442485424864248742488424894249042491424924249342494424954249642497424984249942500425014250242503425044250542506425074250842509425104251142512425134251442515425164251742518425194252042521425224252342524425254252642527425284252942530425314253242533425344253542536425374253842539425404254142542425434254442545425464254742548425494255042551425524255342554425554255642557425584255942560425614256242563425644256542566425674256842569425704257142572425734257442575425764257742578425794258042581425824258342584425854258642587425884258942590425914259242593425944259542596425974259842599426004260142602426034260442605426064260742608426094261042611426124261342614426154261642617426184261942620426214262242623426244262542626426274262842629426304263142632426334263442635426364263742638426394264042641426424264342644426454264642647426484264942650426514265242653426544265542656426574265842659426604266142662426634266442665426664266742668426694267042671426724267342674426754267642677426784267942680426814268242683426844268542686426874268842689426904269142692426934269442695426964269742698426994270042701427024270342704427054270642707427084270942710427114271242713427144271542716427174271842719427204272142722427234272442725427264272742728427294273042731427324273342734427354273642737427384273942740427414274242743427444274542746427474274842749427504275142752427534275442755427564275742758427594276042761427624276342764427654276642767427684276942770427714277242773427744277542776427774277842779427804278142782427834278442785427864278742788427894279042791427924279342794427954279642797427984279942800428014280242803428044280542806428074280842809428104281142812428134281442815428164281742818428194282042821428224282342824428254282642827428284282942830428314283242833428344283542836428374283842839428404284142842428434284442845428464284742848428494285042851428524285342854428554285642857428584285942860428614286242863428644286542866428674286842869428704287142872428734287442875428764287742878428794288042881428824288342884428854288642887428884288942890428914289242893428944289542896428974289842899429004290142902429034290442905429064290742908429094291042911429124291342914429154291642917429184291942920429214292242923429244292542926429274292842929429304293142932429334293442935429364293742938429394294042941429424294342944429454294642947429484294942950429514295242953429544295542956429574295842959429604296142962429634296442965429664296742968429694297042971429724297342974429754297642977429784297942980429814298242983429844298542986429874298842989429904299142992429934299442995429964299742998429994300043001430024300343004430054300643007430084300943010430114301243013430144301543016430174301843019430204302143022430234302443025430264302743028430294303043031430324303343034430354303643037430384303943040430414304243043430444304543046430474304843049430504305143052430534305443055430564305743058430594306043061430624306343064430654306643067430684306943070430714307243073430744307543076430774307843079430804308143082430834308443085430864308743088430894309043091430924309343094430954309643097430984309943100431014310243103431044310543106431074310843109431104311143112431134311443115431164311743118431194312043121431224312343124431254312643127431284312943130431314313243133431344313543136431374313843139431404314143142431434314443145431464314743148431494315043151431524315343154431554315643157431584315943160431614316243163431644316543166431674316843169431704317143172431734317443175431764317743178431794318043181431824318343184431854318643187431884318943190431914319243193431944319543196431974319843199432004320143202432034320443205432064320743208432094321043211432124321343214432154321643217432184321943220432214322243223432244322543226432274322843229432304323143232432334323443235432364323743238432394324043241432424324343244432454324643247432484324943250432514325243253432544325543256432574325843259432604326143262432634326443265432664326743268432694327043271432724327343274432754327643277432784327943280432814328243283432844328543286432874328843289432904329143292432934329443295432964329743298432994330043301433024330343304433054330643307433084330943310433114331243313433144331543316433174331843319433204332143322433234332443325433264332743328433294333043331433324333343334433354333643337433384333943340433414334243343433444334543346433474334843349433504335143352433534335443355433564335743358433594336043361433624336343364433654336643367433684336943370433714337243373433744337543376433774337843379433804338143382433834338443385433864338743388433894339043391433924339343394433954339643397433984339943400434014340243403434044340543406434074340843409434104341143412434134341443415434164341743418434194342043421434224342343424434254342643427434284342943430434314343243433434344343543436434374343843439434404344143442434434344443445434464344743448434494345043451434524345343454434554345643457434584345943460434614346243463434644346543466434674346843469434704347143472434734347443475434764347743478434794348043481434824348343484434854348643487434884348943490434914349243493434944349543496434974349843499435004350143502435034350443505435064350743508435094351043511435124351343514435154351643517435184351943520435214352243523435244352543526435274352843529435304353143532435334353443535435364353743538435394354043541435424354343544435454354643547435484354943550435514355243553435544355543556435574355843559435604356143562435634356443565435664356743568435694357043571435724357343574435754357643577435784357943580435814358243583435844358543586435874358843589435904359143592435934359443595435964359743598435994360043601436024360343604436054360643607436084360943610436114361243613436144361543616436174361843619436204362143622436234362443625436264362743628436294363043631436324363343634436354363643637436384363943640436414364243643436444364543646436474364843649436504365143652436534365443655436564365743658436594366043661436624366343664436654366643667436684366943670436714367243673436744367543676436774367843679436804368143682436834368443685436864368743688436894369043691436924369343694436954369643697436984369943700437014370243703437044370543706437074370843709437104371143712437134371443715437164371743718437194372043721437224372343724437254372643727437284372943730437314373243733437344373543736437374373843739437404374143742437434374443745437464374743748437494375043751437524375343754437554375643757437584375943760437614376243763437644376543766437674376843769437704377143772437734377443775437764377743778437794378043781437824378343784437854378643787437884378943790437914379243793437944379543796437974379843799438004380143802438034380443805438064380743808438094381043811438124381343814438154381643817438184381943820438214382243823438244382543826438274382843829438304383143832438334383443835438364383743838438394384043841438424384343844438454384643847438484384943850438514385243853438544385543856438574385843859438604386143862438634386443865438664386743868438694387043871438724387343874438754387643877438784387943880438814388243883438844388543886438874388843889438904389143892438934389443895438964389743898438994390043901439024390343904439054390643907439084390943910439114391243913439144391543916439174391843919439204392143922439234392443925439264392743928439294393043931439324393343934439354393643937439384393943940439414394243943439444394543946439474394843949439504395143952439534395443955439564395743958439594396043961439624396343964439654396643967439684396943970439714397243973439744397543976439774397843979439804398143982439834398443985439864398743988439894399043991439924399343994439954399643997439984399944000440014400244003440044400544006440074400844009440104401144012440134401444015440164401744018440194402044021440224402344024440254402644027440284402944030440314403244033440344403544036440374403844039440404404144042440434404444045440464404744048440494405044051440524405344054440554405644057440584405944060440614406244063440644406544066440674406844069440704407144072440734407444075440764407744078440794408044081440824408344084440854408644087440884408944090440914409244093440944409544096440974409844099441004410144102441034410444105441064410744108441094411044111441124411344114441154411644117441184411944120441214412244123441244412544126441274412844129441304413144132441334413444135441364413744138441394414044141441424414344144441454414644147441484414944150441514415244153441544415544156441574415844159441604416144162441634416444165441664416744168441694417044171441724417344174441754417644177441784417944180441814418244183441844418544186441874418844189441904419144192441934419444195441964419744198441994420044201442024420344204442054420644207442084420944210442114421244213442144421544216442174421844219442204422144222442234422444225442264422744228442294423044231442324423344234442354423644237442384423944240442414424244243442444424544246442474424844249442504425144252442534425444255442564425744258442594426044261442624426344264442654426644267442684426944270442714427244273442744427544276442774427844279442804428144282442834428444285442864428744288442894429044291442924429344294442954429644297442984429944300443014430244303443044430544306443074430844309443104431144312443134431444315443164431744318443194432044321443224432344324443254432644327443284432944330443314433244333443344433544336443374433844339443404434144342443434434444345443464434744348443494435044351443524435344354443554435644357443584435944360443614436244363443644436544366443674436844369443704437144372443734437444375443764437744378443794438044381443824438344384443854438644387443884438944390443914439244393443944439544396443974439844399444004440144402444034440444405444064440744408444094441044411444124441344414444154441644417444184441944420444214442244423444244442544426444274442844429444304443144432444334443444435444364443744438444394444044441444424444344444444454444644447444484444944450444514445244453444544445544456444574445844459444604446144462444634446444465444664446744468444694447044471444724447344474444754447644477444784447944480444814448244483444844448544486444874448844489444904449144492444934449444495444964449744498444994450044501445024450344504445054450644507445084450944510445114451244513445144451544516445174451844519445204452144522445234452444525445264452744528445294453044531445324453344534445354453644537445384453944540445414454244543445444454544546445474454844549445504455144552445534455444555445564455744558445594456044561445624456344564445654456644567445684456944570445714457244573445744457544576445774457844579445804458144582445834458444585445864458744588445894459044591445924459344594445954459644597445984459944600446014460244603446044460544606446074460844609446104461144612446134461444615446164461744618446194462044621446224462344624446254462644627446284462944630446314463244633446344463544636446374463844639446404464144642446434464444645446464464744648446494465044651446524465344654446554465644657446584465944660446614466244663446644466544666446674466844669446704467144672446734467444675446764467744678446794468044681446824468344684446854468644687446884468944690446914469244693446944469544696446974469844699447004470144702447034470444705447064470744708447094471044711447124471344714447154471644717447184471944720447214472244723447244472544726447274472844729447304473144732447334473444735447364473744738447394474044741447424474344744447454474644747447484474944750447514475244753447544475544756447574475844759447604476144762447634476444765447664476744768447694477044771447724477344774447754477644777447784477944780447814478244783447844478544786447874478844789447904479144792447934479444795447964479744798447994480044801448024480344804448054480644807448084480944810448114481244813448144481544816448174481844819448204482144822448234482444825448264482744828448294483044831448324483344834448354483644837448384483944840448414484244843448444484544846448474484844849448504485144852448534485444855448564485744858448594486044861448624486344864448654486644867448684486944870448714487244873448744487544876448774487844879448804488144882448834488444885448864488744888448894489044891448924489344894448954489644897448984489944900449014490244903449044490544906449074490844909449104491144912449134491444915449164491744918449194492044921449224492344924449254492644927449284492944930449314493244933449344493544936449374493844939449404494144942449434494444945449464494744948449494495044951449524495344954449554495644957449584495944960449614496244963449644496544966449674496844969449704497144972449734497444975449764497744978449794498044981449824498344984449854498644987449884498944990449914499244993449944499544996449974499844999450004500145002450034500445005450064500745008450094501045011450124501345014450154501645017450184501945020450214502245023450244502545026450274502845029450304503145032450334503445035450364503745038450394504045041450424504345044450454504645047450484504945050450514505245053450544505545056450574505845059450604506145062450634506445065450664506745068450694507045071450724507345074450754507645077450784507945080450814508245083450844508545086450874508845089450904509145092450934509445095450964509745098450994510045101451024510345104451054510645107451084510945110451114511245113451144511545116451174511845119451204512145122451234512445125451264512745128451294513045131451324513345134451354513645137451384513945140451414514245143451444514545146451474514845149451504515145152451534515445155451564515745158451594516045161451624516345164451654516645167451684516945170451714517245173451744517545176451774517845179451804518145182451834518445185451864518745188451894519045191451924519345194451954519645197451984519945200452014520245203452044520545206452074520845209452104521145212452134521445215452164521745218452194522045221452224522345224452254522645227452284522945230452314523245233452344523545236452374523845239452404524145242452434524445245452464524745248452494525045251452524525345254452554525645257452584525945260452614526245263452644526545266452674526845269452704527145272452734527445275452764527745278452794528045281452824528345284452854528645287452884528945290452914529245293452944529545296452974529845299453004530145302453034530445305453064530745308453094531045311453124531345314453154531645317453184531945320453214532245323453244532545326453274532845329453304533145332453334533445335453364533745338453394534045341453424534345344453454534645347453484534945350453514535245353453544535545356453574535845359453604536145362453634536445365453664536745368453694537045371453724537345374453754537645377453784537945380453814538245383453844538545386453874538845389453904539145392453934539445395453964539745398453994540045401454024540345404454054540645407454084540945410454114541245413454144541545416454174541845419454204542145422454234542445425454264542745428454294543045431454324543345434454354543645437454384543945440454414544245443454444544545446454474544845449454504545145452454534545445455454564545745458454594546045461454624546345464454654546645467454684546945470454714547245473454744547545476454774547845479454804548145482454834548445485454864548745488454894549045491454924549345494454954549645497454984549945500455014550245503455044550545506455074550845509455104551145512455134551445515455164551745518455194552045521455224552345524455254552645527455284552945530455314553245533455344553545536455374553845539455404554145542455434554445545455464554745548455494555045551455524555345554455554555645557455584555945560455614556245563455644556545566455674556845569455704557145572455734557445575455764557745578455794558045581455824558345584455854558645587455884558945590455914559245593455944559545596455974559845599456004560145602456034560445605456064560745608456094561045611456124561345614456154561645617456184561945620456214562245623456244562545626456274562845629456304563145632456334563445635456364563745638456394564045641456424564345644456454564645647456484564945650456514565245653456544565545656456574565845659456604566145662456634566445665456664566745668456694567045671456724567345674456754567645677456784567945680456814568245683456844568545686456874568845689456904569145692456934569445695456964569745698456994570045701457024570345704457054570645707457084570945710457114571245713457144571545716457174571845719457204572145722457234572445725457264572745728457294573045731457324573345734457354573645737457384573945740457414574245743457444574545746457474574845749457504575145752457534575445755457564575745758457594576045761457624576345764457654576645767457684576945770457714577245773457744577545776457774577845779457804578145782457834578445785457864578745788457894579045791457924579345794457954579645797457984579945800458014580245803458044580545806458074580845809458104581145812458134581445815458164581745818458194582045821458224582345824458254582645827458284582945830458314583245833458344583545836458374583845839458404584145842458434584445845458464584745848458494585045851458524585345854458554585645857458584585945860458614586245863458644586545866458674586845869458704587145872458734587445875458764587745878458794588045881458824588345884458854588645887458884588945890458914589245893458944589545896458974589845899459004590145902459034590445905459064590745908459094591045911459124591345914459154591645917459184591945920459214592245923459244592545926459274592845929459304593145932459334593445935459364593745938459394594045941459424594345944459454594645947459484594945950459514595245953459544595545956459574595845959459604596145962459634596445965459664596745968459694597045971459724597345974459754597645977459784597945980459814598245983459844598545986459874598845989459904599145992459934599445995459964599745998459994600046001460024600346004460054600646007460084600946010460114601246013460144601546016460174601846019460204602146022460234602446025460264602746028460294603046031460324603346034460354603646037460384603946040460414604246043460444604546046460474604846049460504605146052460534605446055460564605746058460594606046061460624606346064460654606646067460684606946070460714607246073460744607546076460774607846079460804608146082460834608446085460864608746088460894609046091460924609346094460954609646097460984609946100461014610246103461044610546106461074610846109461104611146112461134611446115461164611746118461194612046121461224612346124461254612646127461284612946130461314613246133461344613546136461374613846139461404614146142461434614446145461464614746148461494615046151461524615346154461554615646157461584615946160461614616246163461644616546166461674616846169461704617146172461734617446175461764617746178461794618046181461824618346184461854618646187461884618946190461914619246193461944619546196461974619846199462004620146202462034620446205462064620746208462094621046211462124621346214462154621646217462184621946220462214622246223462244622546226462274622846229462304623146232462334623446235462364623746238462394624046241462424624346244462454624646247462484624946250462514625246253462544625546256462574625846259462604626146262462634626446265462664626746268462694627046271462724627346274462754627646277462784627946280462814628246283462844628546286462874628846289462904629146292462934629446295462964629746298462994630046301463024630346304463054630646307463084630946310463114631246313463144631546316463174631846319463204632146322463234632446325463264632746328463294633046331463324633346334463354633646337463384633946340463414634246343463444634546346463474634846349463504635146352463534635446355463564635746358463594636046361463624636346364463654636646367463684636946370463714637246373463744637546376463774637846379463804638146382463834638446385463864638746388463894639046391463924639346394463954639646397463984639946400464014640246403464044640546406464074640846409464104641146412464134641446415464164641746418464194642046421464224642346424464254642646427464284642946430464314643246433464344643546436464374643846439464404644146442464434644446445464464644746448464494645046451464524645346454464554645646457464584645946460464614646246463464644646546466464674646846469464704647146472464734647446475464764647746478464794648046481464824648346484464854648646487464884648946490464914649246493464944649546496464974649846499465004650146502465034650446505465064650746508465094651046511465124651346514465154651646517465184651946520465214652246523465244652546526465274652846529465304653146532465334653446535465364653746538465394654046541465424654346544465454654646547465484654946550465514655246553465544655546556465574655846559465604656146562465634656446565465664656746568465694657046571465724657346574465754657646577465784657946580465814658246583465844658546586465874658846589465904659146592465934659446595465964659746598465994660046601466024660346604466054660646607466084660946610466114661246613466144661546616466174661846619466204662146622466234662446625466264662746628466294663046631466324663346634466354663646637466384663946640466414664246643466444664546646466474664846649466504665146652466534665446655466564665746658466594666046661466624666346664466654666646667466684666946670466714667246673466744667546676466774667846679466804668146682466834668446685466864668746688466894669046691466924669346694466954669646697466984669946700467014670246703467044670546706467074670846709467104671146712467134671446715467164671746718467194672046721467224672346724467254672646727467284672946730467314673246733467344673546736467374673846739467404674146742467434674446745467464674746748467494675046751467524675346754467554675646757467584675946760467614676246763467644676546766467674676846769467704677146772467734677446775467764677746778467794678046781467824678346784467854678646787467884678946790467914679246793467944679546796467974679846799468004680146802468034680446805468064680746808468094681046811468124681346814468154681646817468184681946820468214682246823468244682546826468274682846829468304683146832468334683446835468364683746838468394684046841468424684346844468454684646847468484684946850468514685246853468544685546856468574685846859468604686146862468634686446865468664686746868468694687046871468724687346874468754687646877468784687946880468814688246883468844688546886468874688846889468904689146892468934689446895468964689746898468994690046901469024690346904469054690646907469084690946910469114691246913469144691546916469174691846919469204692146922469234692446925469264692746928469294693046931469324693346934469354693646937469384693946940469414694246943469444694546946469474694846949469504695146952469534695446955469564695746958469594696046961469624696346964469654696646967469684696946970469714697246973469744697546976469774697846979469804698146982469834698446985469864698746988469894699046991469924699346994469954699646997469984699947000470014700247003470044700547006470074700847009470104701147012470134701447015470164701747018470194702047021470224702347024470254702647027470284702947030470314703247033470344703547036470374703847039470404704147042470434704447045470464704747048470494705047051470524705347054470554705647057470584705947060470614706247063470644706547066470674706847069470704707147072470734707447075470764707747078470794708047081470824708347084470854708647087470884708947090470914709247093470944709547096470974709847099471004710147102471034710447105471064710747108471094711047111471124711347114471154711647117471184711947120471214712247123471244712547126471274712847129471304713147132471334713447135471364713747138471394714047141471424714347144471454714647147471484714947150471514715247153471544715547156471574715847159471604716147162471634716447165471664716747168471694717047171471724717347174471754717647177471784717947180471814718247183471844718547186471874718847189471904719147192471934719447195471964719747198471994720047201472024720347204472054720647207472084720947210472114721247213472144721547216472174721847219472204722147222472234722447225472264722747228472294723047231472324723347234472354723647237472384723947240472414724247243472444724547246472474724847249472504725147252472534725447255472564725747258472594726047261472624726347264472654726647267472684726947270472714727247273472744727547276472774727847279472804728147282472834728447285472864728747288472894729047291472924729347294472954729647297472984729947300473014730247303473044730547306473074730847309473104731147312473134731447315473164731747318473194732047321473224732347324473254732647327473284732947330473314733247333473344733547336473374733847339473404734147342473434734447345473464734747348473494735047351473524735347354473554735647357473584735947360473614736247363473644736547366473674736847369473704737147372473734737447375473764737747378473794738047381473824738347384473854738647387473884738947390473914739247393473944739547396473974739847399474004740147402474034740447405474064740747408474094741047411474124741347414474154741647417474184741947420474214742247423474244742547426474274742847429474304743147432474334743447435474364743747438474394744047441474424744347444474454744647447474484744947450474514745247453474544745547456474574745847459474604746147462474634746447465474664746747468474694747047471474724747347474474754747647477474784747947480474814748247483474844748547486474874748847489474904749147492474934749447495474964749747498474994750047501475024750347504475054750647507475084750947510475114751247513475144751547516475174751847519475204752147522475234752447525475264752747528475294753047531475324753347534475354753647537475384753947540475414754247543475444754547546475474754847549475504755147552475534755447555475564755747558475594756047561475624756347564475654756647567475684756947570475714757247573475744757547576475774757847579475804758147582475834758447585475864758747588475894759047591475924759347594475954759647597475984759947600476014760247603476044760547606476074760847609476104761147612476134761447615476164761747618476194762047621476224762347624476254762647627476284762947630476314763247633476344763547636476374763847639476404764147642476434764447645476464764747648476494765047651476524765347654476554765647657476584765947660476614766247663476644766547666476674766847669476704767147672476734767447675476764767747678476794768047681476824768347684476854768647687476884768947690476914769247693476944769547696476974769847699477004770147702477034770447705477064770747708477094771047711477124771347714477154771647717477184771947720477214772247723477244772547726477274772847729477304773147732477334773447735477364773747738477394774047741477424774347744477454774647747477484774947750477514775247753477544775547756477574775847759477604776147762477634776447765477664776747768477694777047771477724777347774477754777647777477784777947780477814778247783477844778547786477874778847789477904779147792477934779447795477964779747798477994780047801478024780347804478054780647807478084780947810478114781247813478144781547816478174781847819478204782147822478234782447825478264782747828478294783047831478324783347834478354783647837478384783947840478414784247843478444784547846478474784847849478504785147852478534785447855478564785747858478594786047861478624786347864478654786647867478684786947870478714787247873478744787547876478774787847879478804788147882478834788447885478864788747888478894789047891478924789347894478954789647897478984789947900479014790247903479044790547906479074790847909479104791147912479134791447915479164791747918479194792047921479224792347924479254792647927479284792947930479314793247933479344793547936479374793847939479404794147942479434794447945479464794747948479494795047951479524795347954479554795647957479584795947960479614796247963479644796547966479674796847969479704797147972479734797447975479764797747978479794798047981479824798347984479854798647987479884798947990479914799247993479944799547996479974799847999480004800148002480034800448005480064800748008480094801048011480124801348014480154801648017480184801948020480214802248023480244802548026480274802848029480304803148032480334803448035480364803748038480394804048041480424804348044480454804648047480484804948050480514805248053480544805548056480574805848059480604806148062480634806448065480664806748068480694807048071480724807348074480754807648077480784807948080480814808248083480844808548086480874808848089480904809148092480934809448095480964809748098480994810048101481024810348104481054810648107481084810948110481114811248113481144811548116481174811848119481204812148122481234812448125481264812748128481294813048131481324813348134481354813648137481384813948140481414814248143481444814548146481474814848149481504815148152481534815448155481564815748158481594816048161481624816348164481654816648167481684816948170481714817248173481744817548176481774817848179481804818148182481834818448185481864818748188481894819048191481924819348194481954819648197481984819948200482014820248203482044820548206482074820848209482104821148212482134821448215482164821748218482194822048221482224822348224482254822648227482284822948230482314823248233482344823548236482374823848239482404824148242482434824448245482464824748248482494825048251482524825348254482554825648257482584825948260482614826248263482644826548266482674826848269482704827148272482734827448275482764827748278482794828048281482824828348284482854828648287482884828948290482914829248293482944829548296482974829848299483004830148302483034830448305483064830748308483094831048311483124831348314483154831648317483184831948320483214832248323483244832548326483274832848329483304833148332483334833448335483364833748338483394834048341483424834348344483454834648347483484834948350483514835248353483544835548356483574835848359483604836148362483634836448365483664836748368483694837048371483724837348374483754837648377483784837948380483814838248383483844838548386483874838848389483904839148392483934839448395483964839748398483994840048401484024840348404484054840648407484084840948410484114841248413484144841548416484174841848419484204842148422484234842448425484264842748428484294843048431484324843348434484354843648437484384843948440484414844248443484444844548446484474844848449484504845148452484534845448455484564845748458484594846048461484624846348464484654846648467484684846948470484714847248473484744847548476484774847848479484804848148482484834848448485484864848748488484894849048491484924849348494484954849648497484984849948500485014850248503485044850548506485074850848509485104851148512485134851448515485164851748518485194852048521485224852348524485254852648527485284852948530485314853248533485344853548536485374853848539485404854148542485434854448545485464854748548485494855048551485524855348554485554855648557485584855948560485614856248563485644856548566485674856848569485704857148572485734857448575485764857748578485794858048581485824858348584485854858648587485884858948590485914859248593485944859548596485974859848599486004860148602486034860448605486064860748608486094861048611486124861348614486154861648617486184861948620486214862248623486244862548626486274862848629486304863148632486334863448635486364863748638486394864048641486424864348644486454864648647486484864948650486514865248653486544865548656486574865848659486604866148662486634866448665486664866748668486694867048671486724867348674486754867648677486784867948680486814868248683486844868548686486874868848689486904869148692486934869448695486964869748698486994870048701487024870348704487054870648707487084870948710487114871248713487144871548716487174871848719487204872148722487234872448725487264872748728487294873048731487324873348734487354873648737487384873948740487414874248743487444874548746487474874848749487504875148752487534875448755487564875748758487594876048761487624876348764487654876648767487684876948770487714877248773487744877548776487774877848779487804878148782487834878448785487864878748788487894879048791487924879348794487954879648797487984879948800488014880248803488044880548806488074880848809488104881148812488134881448815488164881748818488194882048821488224882348824488254882648827488284882948830488314883248833488344883548836488374883848839488404884148842488434884448845488464884748848488494885048851488524885348854488554885648857488584885948860488614886248863488644886548866488674886848869488704887148872488734887448875488764887748878488794888048881488824888348884488854888648887488884888948890488914889248893488944889548896488974889848899489004890148902489034890448905489064890748908489094891048911489124891348914489154891648917489184891948920489214892248923489244892548926489274892848929489304893148932489334893448935489364893748938489394894048941489424894348944489454894648947489484894948950489514895248953489544895548956489574895848959489604896148962489634896448965489664896748968489694897048971489724897348974489754897648977489784897948980489814898248983489844898548986489874898848989489904899148992489934899448995489964899748998489994900049001490024900349004490054900649007490084900949010490114901249013490144901549016490174901849019490204902149022490234902449025490264902749028490294903049031490324903349034490354903649037490384903949040490414904249043490444904549046490474904849049490504905149052490534905449055490564905749058490594906049061490624906349064490654906649067490684906949070490714907249073490744907549076490774907849079490804908149082490834908449085490864908749088490894909049091490924909349094490954909649097490984909949100491014910249103491044910549106491074910849109491104911149112491134911449115491164911749118491194912049121491224912349124491254912649127491284912949130491314913249133491344913549136491374913849139491404914149142491434914449145491464914749148491494915049151491524915349154491554915649157491584915949160491614916249163491644916549166491674916849169491704917149172491734917449175491764917749178491794918049181491824918349184491854918649187491884918949190491914919249193491944919549196491974919849199492004920149202492034920449205492064920749208492094921049211492124921349214492154921649217492184921949220492214922249223492244922549226492274922849229492304923149232492334923449235492364923749238492394924049241492424924349244492454924649247492484924949250492514925249253492544925549256492574925849259492604926149262492634926449265492664926749268492694927049271492724927349274492754927649277492784927949280492814928249283492844928549286492874928849289492904929149292492934929449295492964929749298492994930049301493024930349304493054930649307493084930949310493114931249313493144931549316493174931849319493204932149322493234932449325493264932749328493294933049331493324933349334493354933649337493384933949340493414934249343493444934549346493474934849349493504935149352493534935449355493564935749358493594936049361493624936349364493654936649367493684936949370493714937249373493744937549376493774937849379493804938149382493834938449385493864938749388493894939049391493924939349394493954939649397493984939949400494014940249403494044940549406494074940849409494104941149412494134941449415494164941749418494194942049421494224942349424494254942649427494284942949430494314943249433494344943549436494374943849439494404944149442494434944449445494464944749448494494945049451494524945349454494554945649457494584945949460494614946249463494644946549466494674946849469494704947149472494734947449475494764947749478494794948049481494824948349484494854948649487494884948949490494914949249493494944949549496494974949849499495004950149502495034950449505495064950749508495094951049511495124951349514495154951649517495184951949520495214952249523495244952549526495274952849529495304953149532495334953449535495364953749538495394954049541495424954349544495454954649547495484954949550495514955249553495544955549556495574955849559495604956149562495634956449565495664956749568495694957049571495724957349574495754957649577495784957949580495814958249583495844958549586495874958849589495904959149592495934959449595495964959749598495994960049601496024960349604496054960649607496084960949610496114961249613496144961549616496174961849619496204962149622496234962449625496264962749628496294963049631496324963349634496354963649637496384963949640496414964249643496444964549646496474964849649496504965149652496534965449655496564965749658496594966049661496624966349664496654966649667496684966949670496714967249673496744967549676496774967849679496804968149682496834968449685496864968749688496894969049691496924969349694496954969649697496984969949700497014970249703497044970549706497074970849709497104971149712497134971449715497164971749718497194972049721497224972349724497254972649727497284972949730497314973249733497344973549736497374973849739497404974149742497434974449745497464974749748497494975049751497524975349754497554975649757497584975949760497614976249763497644976549766497674976849769497704977149772497734977449775497764977749778497794978049781497824978349784497854978649787497884978949790497914979249793497944979549796497974979849799498004980149802498034980449805498064980749808498094981049811498124981349814498154981649817498184981949820498214982249823498244982549826498274982849829498304983149832498334983449835498364983749838498394984049841498424984349844498454984649847498484984949850498514985249853498544985549856498574985849859498604986149862498634986449865498664986749868498694987049871498724987349874498754987649877498784987949880498814988249883498844988549886498874988849889498904989149892498934989449895498964989749898498994990049901499024990349904499054990649907499084990949910499114991249913499144991549916499174991849919499204992149922499234992449925499264992749928499294993049931499324993349934499354993649937499384993949940499414994249943499444994549946499474994849949499504995149952499534995449955499564995749958499594996049961499624996349964499654996649967499684996949970499714997249973499744997549976499774997849979499804998149982499834998449985499864998749988499894999049991499924999349994499954999649997499984999950000500015000250003500045000550006500075000850009500105001150012500135001450015500165001750018500195002050021500225002350024500255002650027500285002950030500315003250033500345003550036500375003850039500405004150042500435004450045500465004750048500495005050051500525005350054500555005650057500585005950060500615006250063500645006550066500675006850069500705007150072500735007450075500765007750078500795008050081500825008350084500855008650087500885008950090500915009250093500945009550096500975009850099501005010150102501035010450105501065010750108501095011050111501125011350114501155011650117501185011950120501215012250123501245012550126501275012850129501305013150132501335013450135501365013750138501395014050141501425014350144501455014650147501485014950150501515015250153501545015550156501575015850159501605016150162501635016450165501665016750168501695017050171501725017350174501755017650177501785017950180501815018250183501845018550186501875018850189501905019150192501935019450195501965019750198501995020050201502025020350204502055020650207502085020950210502115021250213502145021550216502175021850219502205022150222502235022450225502265022750228502295023050231502325023350234502355023650237502385023950240502415024250243502445024550246502475024850249502505025150252502535025450255502565025750258502595026050261502625026350264502655026650267502685026950270502715027250273502745027550276502775027850279502805028150282502835028450285502865028750288502895029050291502925029350294502955029650297502985029950300503015030250303503045030550306503075030850309503105031150312503135031450315503165031750318503195032050321503225032350324503255032650327503285032950330503315033250333503345033550336503375033850339503405034150342503435034450345503465034750348503495035050351503525035350354503555035650357503585035950360503615036250363503645036550366503675036850369503705037150372503735037450375503765037750378503795038050381503825038350384503855038650387503885038950390503915039250393503945039550396503975039850399504005040150402504035040450405504065040750408504095041050411504125041350414504155041650417504185041950420504215042250423504245042550426504275042850429504305043150432504335043450435504365043750438504395044050441504425044350444504455044650447504485044950450504515045250453504545045550456504575045850459504605046150462504635046450465504665046750468504695047050471504725047350474504755047650477504785047950480504815048250483504845048550486504875048850489504905049150492504935049450495504965049750498504995050050501505025050350504505055050650507505085050950510505115051250513505145051550516505175051850519505205052150522505235052450525505265052750528505295053050531505325053350534505355053650537505385053950540505415054250543505445054550546505475054850549505505055150552505535055450555505565055750558505595056050561505625056350564505655056650567505685056950570505715057250573505745057550576505775057850579505805058150582505835058450585505865058750588505895059050591505925059350594505955059650597505985059950600506015060250603506045060550606506075060850609506105061150612506135061450615506165061750618506195062050621506225062350624506255062650627506285062950630506315063250633506345063550636506375063850639506405064150642506435064450645506465064750648506495065050651506525065350654506555065650657506585065950660506615066250663506645066550666506675066850669506705067150672506735067450675506765067750678506795068050681506825068350684506855068650687506885068950690506915069250693506945069550696506975069850699507005070150702507035070450705507065070750708507095071050711507125071350714507155071650717507185071950720507215072250723507245072550726507275072850729507305073150732507335073450735507365073750738507395074050741507425074350744507455074650747507485074950750507515075250753507545075550756507575075850759507605076150762507635076450765507665076750768507695077050771507725077350774507755077650777507785077950780507815078250783507845078550786507875078850789507905079150792507935079450795507965079750798507995080050801508025080350804508055080650807508085080950810508115081250813508145081550816508175081850819508205082150822508235082450825508265082750828508295083050831508325083350834508355083650837508385083950840508415084250843508445084550846508475084850849508505085150852508535085450855508565085750858508595086050861508625086350864508655086650867508685086950870508715087250873508745087550876508775087850879508805088150882508835088450885508865088750888508895089050891508925089350894508955089650897508985089950900509015090250903509045090550906509075090850909509105091150912509135091450915509165091750918509195092050921509225092350924509255092650927509285092950930509315093250933509345093550936509375093850939509405094150942509435094450945509465094750948509495095050951509525095350954509555095650957509585095950960509615096250963509645096550966509675096850969509705097150972509735097450975509765097750978509795098050981509825098350984509855098650987509885098950990509915099250993509945099550996509975099850999510005100151002510035100451005510065100751008510095101051011510125101351014510155101651017510185101951020510215102251023510245102551026510275102851029510305103151032510335103451035510365103751038510395104051041510425104351044510455104651047510485104951050510515105251053510545105551056510575105851059510605106151062510635106451065510665106751068510695107051071510725107351074510755107651077510785107951080510815108251083510845108551086510875108851089510905109151092510935109451095510965109751098510995110051101511025110351104511055110651107511085110951110511115111251113511145111551116511175111851119511205112151122511235112451125511265112751128511295113051131511325113351134511355113651137511385113951140511415114251143511445114551146511475114851149511505115151152511535115451155511565115751158511595116051161511625116351164511655116651167511685116951170511715117251173511745117551176511775117851179511805118151182511835118451185511865118751188511895119051191511925119351194511955119651197511985119951200512015120251203512045120551206512075120851209512105121151212512135121451215512165121751218512195122051221512225122351224512255122651227512285122951230512315123251233512345123551236512375123851239512405124151242512435124451245512465124751248512495125051251512525125351254512555125651257512585125951260512615126251263512645126551266512675126851269512705127151272512735127451275512765127751278512795128051281512825128351284512855128651287512885128951290512915129251293512945129551296512975129851299513005130151302513035130451305513065130751308513095131051311513125131351314513155131651317513185131951320513215132251323513245132551326513275132851329513305133151332513335133451335513365133751338513395134051341513425134351344513455134651347513485134951350513515135251353513545135551356513575135851359513605136151362513635136451365513665136751368513695137051371513725137351374513755137651377513785137951380513815138251383513845138551386513875138851389513905139151392513935139451395513965139751398513995140051401514025140351404514055140651407514085140951410514115141251413514145141551416514175141851419514205142151422514235142451425514265142751428514295143051431514325143351434514355143651437514385143951440514415144251443514445144551446514475144851449514505145151452514535145451455514565145751458514595146051461514625146351464514655146651467514685146951470514715147251473514745147551476514775147851479514805148151482514835148451485514865148751488514895149051491514925149351494514955149651497514985149951500515015150251503515045150551506515075150851509515105151151512515135151451515515165151751518515195152051521515225152351524515255152651527515285152951530515315153251533515345153551536515375153851539515405154151542515435154451545515465154751548515495155051551515525155351554515555155651557515585155951560515615156251563515645156551566515675156851569515705157151572515735157451575515765157751578515795158051581515825158351584515855158651587515885158951590515915159251593515945159551596515975159851599516005160151602516035160451605516065160751608516095161051611516125161351614516155161651617516185161951620516215162251623516245162551626516275162851629516305163151632516335163451635516365163751638516395164051641516425164351644516455164651647516485164951650516515165251653516545165551656516575165851659516605166151662516635166451665516665166751668516695167051671516725167351674516755167651677516785167951680516815168251683516845168551686516875168851689516905169151692516935169451695516965169751698516995170051701517025170351704517055170651707517085170951710517115171251713517145171551716517175171851719517205172151722517235172451725517265172751728517295173051731517325173351734517355173651737517385173951740517415174251743517445174551746517475174851749517505175151752517535175451755517565175751758517595176051761517625176351764517655176651767517685176951770517715177251773517745177551776517775177851779517805178151782517835178451785517865178751788517895179051791517925179351794517955179651797517985179951800518015180251803518045180551806518075180851809518105181151812518135181451815518165181751818518195182051821518225182351824518255182651827518285182951830518315183251833518345183551836518375183851839518405184151842518435184451845518465184751848518495185051851518525185351854518555185651857518585185951860518615186251863518645186551866518675186851869518705187151872518735187451875518765187751878518795188051881518825188351884518855188651887518885188951890518915189251893518945189551896518975189851899519005190151902519035190451905519065190751908519095191051911519125191351914519155191651917519185191951920519215192251923519245192551926519275192851929519305193151932519335193451935519365193751938519395194051941519425194351944519455194651947519485194951950519515195251953519545195551956519575195851959519605196151962519635196451965519665196751968519695197051971519725197351974519755197651977519785197951980519815198251983519845198551986519875198851989519905199151992519935199451995519965199751998519995200052001520025200352004520055200652007520085200952010520115201252013520145201552016520175201852019520205202152022520235202452025520265202752028520295203052031520325203352034520355203652037520385203952040520415204252043520445204552046520475204852049520505205152052520535205452055520565205752058520595206052061520625206352064520655206652067520685206952070520715207252073520745207552076520775207852079520805208152082520835208452085520865208752088520895209052091520925209352094520955209652097520985209952100521015210252103521045210552106521075210852109521105211152112521135211452115521165211752118521195212052121521225212352124521255212652127521285212952130521315213252133521345213552136521375213852139521405214152142521435214452145521465214752148521495215052151521525215352154521555215652157521585215952160521615216252163521645216552166521675216852169521705217152172521735217452175521765217752178521795218052181521825218352184521855218652187521885218952190521915219252193521945219552196521975219852199522005220152202522035220452205522065220752208522095221052211522125221352214522155221652217522185221952220522215222252223522245222552226522275222852229522305223152232522335223452235522365223752238522395224052241522425224352244522455224652247522485224952250522515225252253522545225552256522575225852259522605226152262522635226452265522665226752268522695227052271522725227352274522755227652277522785227952280522815228252283522845228552286522875228852289522905229152292522935229452295522965229752298522995230052301523025230352304523055230652307523085230952310523115231252313523145231552316523175231852319523205232152322523235232452325523265232752328523295233052331523325233352334523355233652337523385233952340523415234252343523445234552346523475234852349523505235152352523535235452355523565235752358523595236052361523625236352364523655236652367523685236952370523715237252373523745237552376523775237852379523805238152382523835238452385523865238752388523895239052391523925239352394523955239652397523985239952400524015240252403524045240552406524075240852409524105241152412524135241452415524165241752418524195242052421524225242352424524255242652427524285242952430524315243252433524345243552436524375243852439524405244152442524435244452445524465244752448524495245052451524525245352454524555245652457524585245952460524615246252463524645246552466524675246852469524705247152472524735247452475524765247752478524795248052481524825248352484524855248652487524885248952490524915249252493524945249552496524975249852499525005250152502525035250452505525065250752508525095251052511525125251352514525155251652517525185251952520525215252252523525245252552526525275252852529525305253152532525335253452535525365253752538525395254052541525425254352544525455254652547525485254952550525515255252553525545255552556525575255852559525605256152562525635256452565525665256752568525695257052571525725257352574525755257652577525785257952580525815258252583525845258552586525875258852589525905259152592525935259452595525965259752598525995260052601526025260352604526055260652607526085260952610526115261252613526145261552616526175261852619526205262152622526235262452625526265262752628526295263052631526325263352634526355263652637526385263952640526415264252643526445264552646526475264852649526505265152652526535265452655526565265752658526595266052661526625266352664526655266652667526685266952670526715267252673526745267552676526775267852679526805268152682526835268452685526865268752688526895269052691526925269352694526955269652697526985269952700527015270252703527045270552706527075270852709527105271152712527135271452715527165271752718527195272052721527225272352724527255272652727527285272952730527315273252733527345273552736527375273852739527405274152742527435274452745527465274752748527495275052751527525275352754527555275652757527585275952760527615276252763527645276552766527675276852769527705277152772527735277452775527765277752778527795278052781527825278352784527855278652787527885278952790527915279252793527945279552796527975279852799528005280152802528035280452805528065280752808528095281052811528125281352814528155281652817528185281952820528215282252823528245282552826528275282852829528305283152832528335283452835528365283752838528395284052841528425284352844528455284652847528485284952850528515285252853528545285552856528575285852859528605286152862528635286452865528665286752868528695287052871528725287352874528755287652877528785287952880528815288252883528845288552886528875288852889528905289152892528935289452895528965289752898528995290052901529025290352904529055290652907529085290952910529115291252913529145291552916529175291852919529205292152922529235292452925529265292752928529295293052931529325293352934529355293652937529385293952940529415294252943529445294552946529475294852949529505295152952529535295452955529565295752958529595296052961529625296352964529655296652967529685296952970529715297252973529745297552976529775297852979529805298152982529835298452985529865298752988529895299052991529925299352994529955299652997529985299953000530015300253003530045300553006530075300853009530105301153012530135301453015530165301753018530195302053021530225302353024530255302653027530285302953030530315303253033530345303553036530375303853039530405304153042530435304453045530465304753048530495305053051530525305353054530555305653057530585305953060530615306253063530645306553066530675306853069530705307153072530735307453075530765307753078530795308053081530825308353084530855308653087530885308953090530915309253093530945309553096530975309853099531005310153102531035310453105531065310753108531095311053111531125311353114531155311653117531185311953120531215312253123531245312553126531275312853129531305313153132531335313453135531365313753138531395314053141531425314353144531455314653147531485314953150531515315253153531545315553156531575315853159531605316153162531635316453165531665316753168531695317053171531725317353174531755317653177531785317953180531815318253183531845318553186531875318853189531905319153192531935319453195531965319753198531995320053201532025320353204532055320653207532085320953210532115321253213532145321553216532175321853219532205322153222532235322453225532265322753228532295323053231532325323353234532355323653237532385323953240532415324253243532445324553246532475324853249532505325153252532535325453255532565325753258532595326053261532625326353264532655326653267532685326953270532715327253273532745327553276532775327853279532805328153282532835328453285532865328753288532895329053291532925329353294532955329653297532985329953300533015330253303533045330553306533075330853309533105331153312533135331453315533165331753318533195332053321533225332353324533255332653327533285332953330533315333253333533345333553336533375333853339533405334153342533435334453345533465334753348533495335053351533525335353354533555335653357533585335953360533615336253363533645336553366533675336853369533705337153372533735337453375533765337753378533795338053381533825338353384533855338653387533885338953390533915339253393533945339553396533975339853399534005340153402534035340453405534065340753408534095341053411534125341353414534155341653417534185341953420534215342253423534245342553426534275342853429534305343153432534335343453435534365343753438534395344053441534425344353444534455344653447534485344953450534515345253453534545345553456534575345853459534605346153462534635346453465534665346753468534695347053471534725347353474534755347653477534785347953480534815348253483534845348553486534875348853489534905349153492534935349453495534965349753498534995350053501535025350353504535055350653507535085350953510535115351253513535145351553516535175351853519535205352153522535235352453525535265352753528535295353053531535325353353534535355353653537535385353953540535415354253543535445354553546535475354853549535505355153552535535355453555535565355753558535595356053561535625356353564535655356653567535685356953570535715357253573535745357553576535775357853579535805358153582535835358453585535865358753588535895359053591535925359353594535955359653597535985359953600536015360253603536045360553606536075360853609536105361153612536135361453615536165361753618536195362053621536225362353624536255362653627536285362953630536315363253633536345363553636536375363853639536405364153642536435364453645536465364753648536495365053651536525365353654536555365653657536585365953660536615366253663536645366553666536675366853669536705367153672536735367453675536765367753678536795368053681536825368353684536855368653687536885368953690536915369253693536945369553696536975369853699537005370153702537035370453705537065370753708537095371053711537125371353714537155371653717537185371953720537215372253723537245372553726537275372853729537305373153732537335373453735537365373753738537395374053741537425374353744537455374653747537485374953750537515375253753537545375553756537575375853759537605376153762537635376453765537665376753768537695377053771537725377353774537755377653777537785377953780537815378253783537845378553786537875378853789537905379153792537935379453795537965379753798537995380053801538025380353804538055380653807538085380953810538115381253813538145381553816538175381853819538205382153822538235382453825538265382753828538295383053831538325383353834538355383653837538385383953840538415384253843538445384553846538475384853849538505385153852538535385453855538565385753858538595386053861538625386353864538655386653867538685386953870538715387253873538745387553876538775387853879538805388153882538835388453885538865388753888538895389053891538925389353894538955389653897538985389953900539015390253903539045390553906539075390853909539105391153912539135391453915539165391753918539195392053921539225392353924539255392653927539285392953930539315393253933539345393553936539375393853939539405394153942539435394453945539465394753948539495395053951539525395353954539555395653957539585395953960539615396253963539645396553966539675396853969539705397153972539735397453975539765397753978539795398053981539825398353984539855398653987539885398953990539915399253993539945399553996539975399853999540005400154002540035400454005540065400754008540095401054011540125401354014540155401654017540185401954020540215402254023540245402554026540275402854029540305403154032540335403454035540365403754038540395404054041540425404354044540455404654047540485404954050540515405254053540545405554056540575405854059540605406154062540635406454065540665406754068540695407054071540725407354074540755407654077540785407954080540815408254083540845408554086540875408854089540905409154092540935409454095540965409754098540995410054101541025410354104541055410654107541085410954110541115411254113541145411554116541175411854119541205412154122541235412454125541265412754128541295413054131541325413354134541355413654137541385413954140541415414254143541445414554146541475414854149541505415154152541535415454155541565415754158541595416054161541625416354164541655416654167541685416954170541715417254173541745417554176541775417854179541805418154182541835418454185541865418754188541895419054191541925419354194541955419654197541985419954200542015420254203542045420554206542075420854209542105421154212542135421454215542165421754218542195422054221542225422354224542255422654227542285422954230542315423254233542345423554236542375423854239542405424154242542435424454245542465424754248542495425054251542525425354254542555425654257542585425954260542615426254263542645426554266542675426854269542705427154272542735427454275542765427754278542795428054281542825428354284542855428654287542885428954290542915429254293542945429554296542975429854299543005430154302543035430454305543065430754308543095431054311543125431354314543155431654317543185431954320543215432254323543245432554326543275432854329543305433154332543335433454335543365433754338543395434054341543425434354344543455434654347543485434954350543515435254353543545435554356543575435854359543605436154362543635436454365543665436754368543695437054371543725437354374543755437654377543785437954380543815438254383543845438554386543875438854389543905439154392543935439454395543965439754398543995440054401544025440354404544055440654407544085440954410544115441254413544145441554416544175441854419544205442154422544235442454425544265442754428544295443054431544325443354434544355443654437544385443954440544415444254443544445444554446544475444854449544505445154452544535445454455544565445754458544595446054461544625446354464544655446654467544685446954470544715447254473544745447554476544775447854479544805448154482544835448454485544865448754488544895449054491544925449354494544955449654497544985449954500545015450254503545045450554506545075450854509545105451154512545135451454515545165451754518545195452054521545225452354524545255452654527545285452954530545315453254533545345453554536545375453854539545405454154542545435454454545545465454754548545495455054551545525455354554545555455654557545585455954560545615456254563545645456554566545675456854569545705457154572545735457454575545765457754578545795458054581545825458354584545855458654587545885458954590545915459254593545945459554596545975459854599546005460154602546035460454605546065460754608546095461054611546125461354614546155461654617546185461954620546215462254623546245462554626546275462854629546305463154632546335463454635546365463754638546395464054641546425464354644546455464654647546485464954650546515465254653546545465554656546575465854659546605466154662546635466454665546665466754668546695467054671546725467354674546755467654677546785467954680546815468254683546845468554686546875468854689546905469154692546935469454695546965469754698546995470054701547025470354704547055470654707547085470954710547115471254713547145471554716547175471854719547205472154722547235472454725547265472754728547295473054731547325473354734547355473654737547385473954740547415474254743547445474554746547475474854749547505475154752547535475454755547565475754758547595476054761547625476354764547655476654767547685476954770547715477254773547745477554776547775477854779547805478154782547835478454785547865478754788547895479054791547925479354794547955479654797547985479954800548015480254803548045480554806548075480854809548105481154812548135481454815548165481754818548195482054821548225482354824548255482654827548285482954830548315483254833548345483554836548375483854839548405484154842548435484454845548465484754848548495485054851548525485354854548555485654857548585485954860548615486254863548645486554866548675486854869548705487154872548735487454875548765487754878548795488054881548825488354884548855488654887548885488954890548915489254893548945489554896548975489854899549005490154902549035490454905549065490754908549095491054911549125491354914549155491654917549185491954920549215492254923549245492554926549275492854929549305493154932549335493454935549365493754938549395494054941549425494354944549455494654947549485494954950549515495254953549545495554956549575495854959549605496154962549635496454965549665496754968549695497054971549725497354974549755497654977
  1. /*!
  2. * ====================================================
  3. * kityminder - v1.3.5 - 2015-05-15
  4. * https://github.com/fex-team/kityminder
  5. * GitHub: https://github.com/fex-team/kityminder.git
  6. * Copyright (c) 2015 f-cube @ FEX; Licensed MIT
  7. * ====================================================
  8. */
  9. (function(window) {
  10. /*!
  11. * jQuery JavaScript Library v2.1.1
  12. * http://jquery.com/
  13. *
  14. * Includes Sizzle.js
  15. * http://sizzlejs.com/
  16. *
  17. * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
  18. * Released under the MIT license
  19. * http://jquery.org/license
  20. *
  21. * Date: 2014-05-01T17:11Z
  22. */
  23. (function( global, factory ) {
  24. if ( typeof module === "object" && typeof module.exports === "object" ) {
  25. // For CommonJS and CommonJS-like environments where a proper window is present,
  26. // execute the factory and get jQuery
  27. // For environments that do not inherently posses a window with a document
  28. // (such as Node.js), expose a jQuery-making factory as module.exports
  29. // This accentuates the need for the creation of a real window
  30. // e.g. var jQuery = require("jquery")(window);
  31. // See ticket #14549 for more info
  32. module.exports = global.document ?
  33. factory( global, true ) :
  34. function( w ) {
  35. if ( !w.document ) {
  36. throw new Error( "jQuery requires a window with a document" );
  37. }
  38. return factory( w );
  39. };
  40. } else {
  41. factory( global );
  42. }
  43. // Pass this if window is not defined yet
  44. }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
  45. // Can't do this because several apps including ASP.NET trace
  46. // the stack via arguments.caller.callee and Firefox dies if
  47. // you try to trace through "use strict" call chains. (#13335)
  48. // Support: Firefox 18+
  49. //
  50. var arr = [];
  51. var slice = arr.slice;
  52. var concat = arr.concat;
  53. var push = arr.push;
  54. var indexOf = arr.indexOf;
  55. var class2type = {};
  56. var toString = class2type.toString;
  57. var hasOwn = class2type.hasOwnProperty;
  58. var support = {};
  59. var
  60. // Use the correct document accordingly with window argument (sandbox)
  61. document = window.document,
  62. version = "2.1.1",
  63. // Define a local copy of jQuery
  64. jQuery = function( selector, context ) {
  65. // The jQuery object is actually just the init constructor 'enhanced'
  66. // Need init if jQuery is called (just allow error to be thrown if not included)
  67. return new jQuery.fn.init( selector, context );
  68. },
  69. // Support: Android<4.1
  70. // Make sure we trim BOM and NBSP
  71. rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
  72. // Matches dashed string for camelizing
  73. rmsPrefix = /^-ms-/,
  74. rdashAlpha = /-([\da-z])/gi,
  75. // Used by jQuery.camelCase as callback to replace()
  76. fcamelCase = function( all, letter ) {
  77. return letter.toUpperCase();
  78. };
  79. jQuery.fn = jQuery.prototype = {
  80. // The current version of jQuery being used
  81. jquery: version,
  82. constructor: jQuery,
  83. // Start with an empty selector
  84. selector: "",
  85. // The default length of a jQuery object is 0
  86. length: 0,
  87. toArray: function() {
  88. return slice.call( this );
  89. },
  90. // Get the Nth element in the matched element set OR
  91. // Get the whole matched element set as a clean array
  92. get: function( num ) {
  93. return num != null ?
  94. // Return just the one element from the set
  95. ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
  96. // Return all the elements in a clean array
  97. slice.call( this );
  98. },
  99. // Take an array of elements and push it onto the stack
  100. // (returning the new matched element set)
  101. pushStack: function( elems ) {
  102. // Build a new jQuery matched element set
  103. var ret = jQuery.merge( this.constructor(), elems );
  104. // Add the old object onto the stack (as a reference)
  105. ret.prevObject = this;
  106. ret.context = this.context;
  107. // Return the newly-formed element set
  108. return ret;
  109. },
  110. // Execute a callback for every element in the matched set.
  111. // (You can seed the arguments with an array of args, but this is
  112. // only used internally.)
  113. each: function( callback, args ) {
  114. return jQuery.each( this, callback, args );
  115. },
  116. map: function( callback ) {
  117. return this.pushStack( jQuery.map(this, function( elem, i ) {
  118. return callback.call( elem, i, elem );
  119. }));
  120. },
  121. slice: function() {
  122. return this.pushStack( slice.apply( this, arguments ) );
  123. },
  124. first: function() {
  125. return this.eq( 0 );
  126. },
  127. last: function() {
  128. return this.eq( -1 );
  129. },
  130. eq: function( i ) {
  131. var len = this.length,
  132. j = +i + ( i < 0 ? len : 0 );
  133. return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
  134. },
  135. end: function() {
  136. return this.prevObject || this.constructor(null);
  137. },
  138. // For internal use only.
  139. // Behaves like an Array's method, not like a jQuery method.
  140. push: push,
  141. sort: arr.sort,
  142. splice: arr.splice
  143. };
  144. jQuery.extend = jQuery.fn.extend = function() {
  145. var options, name, src, copy, copyIsArray, clone,
  146. target = arguments[0] || {},
  147. i = 1,
  148. length = arguments.length,
  149. deep = false;
  150. // Handle a deep copy situation
  151. if ( typeof target === "boolean" ) {
  152. deep = target;
  153. // skip the boolean and the target
  154. target = arguments[ i ] || {};
  155. i++;
  156. }
  157. // Handle case when target is a string or something (possible in deep copy)
  158. if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
  159. target = {};
  160. }
  161. // extend jQuery itself if only one argument is passed
  162. if ( i === length ) {
  163. target = this;
  164. i--;
  165. }
  166. for ( ; i < length; i++ ) {
  167. // Only deal with non-null/undefined values
  168. if ( (options = arguments[ i ]) != null ) {
  169. // Extend the base object
  170. for ( name in options ) {
  171. src = target[ name ];
  172. copy = options[ name ];
  173. // Prevent never-ending loop
  174. if ( target === copy ) {
  175. continue;
  176. }
  177. // Recurse if we're merging plain objects or arrays
  178. if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
  179. if ( copyIsArray ) {
  180. copyIsArray = false;
  181. clone = src && jQuery.isArray(src) ? src : [];
  182. } else {
  183. clone = src && jQuery.isPlainObject(src) ? src : {};
  184. }
  185. // Never move original objects, clone them
  186. target[ name ] = jQuery.extend( deep, clone, copy );
  187. // Don't bring in undefined values
  188. } else if ( copy !== undefined ) {
  189. target[ name ] = copy;
  190. }
  191. }
  192. }
  193. }
  194. // Return the modified object
  195. return target;
  196. };
  197. jQuery.extend({
  198. // Unique for each copy of jQuery on the page
  199. expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
  200. // Assume jQuery is ready without the ready module
  201. isReady: true,
  202. error: function( msg ) {
  203. throw new Error( msg );
  204. },
  205. noop: function() {},
  206. // See test/unit/core.js for details concerning isFunction.
  207. // Since version 1.3, DOM methods and functions like alert
  208. // aren't supported. They return false on IE (#2968).
  209. isFunction: function( obj ) {
  210. return jQuery.type(obj) === "function";
  211. },
  212. isArray: Array.isArray,
  213. isWindow: function( obj ) {
  214. return obj != null && obj === obj.window;
  215. },
  216. isNumeric: function( obj ) {
  217. // parseFloat NaNs numeric-cast false positives (null|true|false|"")
  218. // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
  219. // subtraction forces infinities to NaN
  220. return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
  221. },
  222. isPlainObject: function( obj ) {
  223. // Not plain objects:
  224. // - Any object or value whose internal [[Class]] property is not "[object Object]"
  225. // - DOM nodes
  226. // - window
  227. if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
  228. return false;
  229. }
  230. if ( obj.constructor &&
  231. !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
  232. return false;
  233. }
  234. // If the function hasn't returned already, we're confident that
  235. // |obj| is a plain object, created by {} or constructed with new Object
  236. return true;
  237. },
  238. isEmptyObject: function( obj ) {
  239. var name;
  240. for ( name in obj ) {
  241. return false;
  242. }
  243. return true;
  244. },
  245. type: function( obj ) {
  246. if ( obj == null ) {
  247. return obj + "";
  248. }
  249. // Support: Android < 4.0, iOS < 6 (functionish RegExp)
  250. return typeof obj === "object" || typeof obj === "function" ?
  251. class2type[ toString.call(obj) ] || "object" :
  252. typeof obj;
  253. },
  254. // Evaluates a script in a global context
  255. globalEval: function( code ) {
  256. var script,
  257. indirect = eval;
  258. code = jQuery.trim( code );
  259. if ( code ) {
  260. // If the code includes a valid, prologue position
  261. // strict mode pragma, execute code by injecting a
  262. // script tag into the document.
  263. if ( code.indexOf("use strict") === 1 ) {
  264. script = document.createElement("script");
  265. script.text = code;
  266. document.head.appendChild( script ).parentNode.removeChild( script );
  267. } else {
  268. // Otherwise, avoid the DOM node creation, insertion
  269. // and removal by using an indirect global eval
  270. indirect( code );
  271. }
  272. }
  273. },
  274. // Convert dashed to camelCase; used by the css and data modules
  275. // Microsoft forgot to hump their vendor prefix (#9572)
  276. camelCase: function( string ) {
  277. return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
  278. },
  279. nodeName: function( elem, name ) {
  280. return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
  281. },
  282. // args is for internal usage only
  283. each: function( obj, callback, args ) {
  284. var value,
  285. i = 0,
  286. length = obj.length,
  287. isArray = isArraylike( obj );
  288. if ( args ) {
  289. if ( isArray ) {
  290. for ( ; i < length; i++ ) {
  291. value = callback.apply( obj[ i ], args );
  292. if ( value === false ) {
  293. break;
  294. }
  295. }
  296. } else {
  297. for ( i in obj ) {
  298. value = callback.apply( obj[ i ], args );
  299. if ( value === false ) {
  300. break;
  301. }
  302. }
  303. }
  304. // A special, fast, case for the most common use of each
  305. } else {
  306. if ( isArray ) {
  307. for ( ; i < length; i++ ) {
  308. value = callback.call( obj[ i ], i, obj[ i ] );
  309. if ( value === false ) {
  310. break;
  311. }
  312. }
  313. } else {
  314. for ( i in obj ) {
  315. value = callback.call( obj[ i ], i, obj[ i ] );
  316. if ( value === false ) {
  317. break;
  318. }
  319. }
  320. }
  321. }
  322. return obj;
  323. },
  324. // Support: Android<4.1
  325. trim: function( text ) {
  326. return text == null ?
  327. "" :
  328. ( text + "" ).replace( rtrim, "" );
  329. },
  330. // results is for internal usage only
  331. makeArray: function( arr, results ) {
  332. var ret = results || [];
  333. if ( arr != null ) {
  334. if ( isArraylike( Object(arr) ) ) {
  335. jQuery.merge( ret,
  336. typeof arr === "string" ?
  337. [ arr ] : arr
  338. );
  339. } else {
  340. push.call( ret, arr );
  341. }
  342. }
  343. return ret;
  344. },
  345. inArray: function( elem, arr, i ) {
  346. return arr == null ? -1 : indexOf.call( arr, elem, i );
  347. },
  348. merge: function( first, second ) {
  349. var len = +second.length,
  350. j = 0,
  351. i = first.length;
  352. for ( ; j < len; j++ ) {
  353. first[ i++ ] = second[ j ];
  354. }
  355. first.length = i;
  356. return first;
  357. },
  358. grep: function( elems, callback, invert ) {
  359. var callbackInverse,
  360. matches = [],
  361. i = 0,
  362. length = elems.length,
  363. callbackExpect = !invert;
  364. // Go through the array, only saving the items
  365. // that pass the validator function
  366. for ( ; i < length; i++ ) {
  367. callbackInverse = !callback( elems[ i ], i );
  368. if ( callbackInverse !== callbackExpect ) {
  369. matches.push( elems[ i ] );
  370. }
  371. }
  372. return matches;
  373. },
  374. // arg is for internal usage only
  375. map: function( elems, callback, arg ) {
  376. var value,
  377. i = 0,
  378. length = elems.length,
  379. isArray = isArraylike( elems ),
  380. ret = [];
  381. // Go through the array, translating each of the items to their new values
  382. if ( isArray ) {
  383. for ( ; i < length; i++ ) {
  384. value = callback( elems[ i ], i, arg );
  385. if ( value != null ) {
  386. ret.push( value );
  387. }
  388. }
  389. // Go through every key on the object,
  390. } else {
  391. for ( i in elems ) {
  392. value = callback( elems[ i ], i, arg );
  393. if ( value != null ) {
  394. ret.push( value );
  395. }
  396. }
  397. }
  398. // Flatten any nested arrays
  399. return concat.apply( [], ret );
  400. },
  401. // A global GUID counter for objects
  402. guid: 1,
  403. // Bind a function to a context, optionally partially applying any
  404. // arguments.
  405. proxy: function( fn, context ) {
  406. var tmp, args, proxy;
  407. if ( typeof context === "string" ) {
  408. tmp = fn[ context ];
  409. context = fn;
  410. fn = tmp;
  411. }
  412. // Quick check to determine if target is callable, in the spec
  413. // this throws a TypeError, but we will just return undefined.
  414. if ( !jQuery.isFunction( fn ) ) {
  415. return undefined;
  416. }
  417. // Simulated bind
  418. args = slice.call( arguments, 2 );
  419. proxy = function() {
  420. return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
  421. };
  422. // Set the guid of unique handler to the same of original handler, so it can be removed
  423. proxy.guid = fn.guid = fn.guid || jQuery.guid++;
  424. return proxy;
  425. },
  426. now: Date.now,
  427. // jQuery.support is not used in Core but other projects attach their
  428. // properties to it so it needs to exist.
  429. support: support
  430. });
  431. // Populate the class2type map
  432. jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
  433. class2type[ "[object " + name + "]" ] = name.toLowerCase();
  434. });
  435. function isArraylike( obj ) {
  436. var length = obj.length,
  437. type = jQuery.type( obj );
  438. if ( type === "function" || jQuery.isWindow( obj ) ) {
  439. return false;
  440. }
  441. if ( obj.nodeType === 1 && length ) {
  442. return true;
  443. }
  444. return type === "array" || length === 0 ||
  445. typeof length === "number" && length > 0 && ( length - 1 ) in obj;
  446. }
  447. var Sizzle =
  448. /*!
  449. * Sizzle CSS Selector Engine v1.10.19
  450. * http://sizzlejs.com/
  451. *
  452. * Copyright 2013 jQuery Foundation, Inc. and other contributors
  453. * Released under the MIT license
  454. * http://jquery.org/license
  455. *
  456. * Date: 2014-04-18
  457. */
  458. (function( window ) {
  459. var i,
  460. support,
  461. Expr,
  462. getText,
  463. isXML,
  464. tokenize,
  465. compile,
  466. select,
  467. outermostContext,
  468. sortInput,
  469. hasDuplicate,
  470. // Local document vars
  471. setDocument,
  472. document,
  473. docElem,
  474. documentIsHTML,
  475. rbuggyQSA,
  476. rbuggyMatches,
  477. matches,
  478. contains,
  479. // Instance-specific data
  480. expando = "sizzle" + -(new Date()),
  481. preferredDoc = window.document,
  482. dirruns = 0,
  483. done = 0,
  484. classCache = createCache(),
  485. tokenCache = createCache(),
  486. compilerCache = createCache(),
  487. sortOrder = function( a, b ) {
  488. if ( a === b ) {
  489. hasDuplicate = true;
  490. }
  491. return 0;
  492. },
  493. // General-purpose constants
  494. strundefined = typeof undefined,
  495. MAX_NEGATIVE = 1 << 31,
  496. // Instance methods
  497. hasOwn = ({}).hasOwnProperty,
  498. arr = [],
  499. pop = arr.pop,
  500. push_native = arr.push,
  501. push = arr.push,
  502. slice = arr.slice,
  503. // Use a stripped-down indexOf if we can't use a native one
  504. indexOf = arr.indexOf || function( elem ) {
  505. var i = 0,
  506. len = this.length;
  507. for ( ; i < len; i++ ) {
  508. if ( this[i] === elem ) {
  509. return i;
  510. }
  511. }
  512. return -1;
  513. },
  514. booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
  515. // Regular expressions
  516. // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
  517. whitespace = "[\\x20\\t\\r\\n\\f]",
  518. // http://www.w3.org/TR/css3-syntax/#characters
  519. characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
  520. // Loosely modeled on CSS identifier characters
  521. // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
  522. // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
  523. identifier = characterEncoding.replace( "w", "w#" ),
  524. // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
  525. attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
  526. // Operator (capture 2)
  527. "*([*^$|!~]?=)" + whitespace +
  528. // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
  529. "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
  530. "*\\]",
  531. pseudos = ":(" + characterEncoding + ")(?:\\((" +
  532. // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
  533. // 1. quoted (capture 3; capture 4 or capture 5)
  534. "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
  535. // 2. simple (capture 6)
  536. "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
  537. // 3. anything else (capture 2)
  538. ".*" +
  539. ")\\)|)",
  540. // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
  541. rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
  542. rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
  543. rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
  544. rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
  545. rpseudo = new RegExp( pseudos ),
  546. ridentifier = new RegExp( "^" + identifier + "$" ),
  547. matchExpr = {
  548. "ID": new RegExp( "^#(" + characterEncoding + ")" ),
  549. "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
  550. "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
  551. "ATTR": new RegExp( "^" + attributes ),
  552. "PSEUDO": new RegExp( "^" + pseudos ),
  553. "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
  554. "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
  555. "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
  556. "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
  557. // For use in libraries implementing .is()
  558. // We use this for POS matching in `select`
  559. "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
  560. whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
  561. },
  562. rinputs = /^(?:input|select|textarea|button)$/i,
  563. rheader = /^h\d$/i,
  564. rnative = /^[^{]+\{\s*\[native \w/,
  565. // Easily-parseable/retrievable ID or TAG or CLASS selectors
  566. rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
  567. rsibling = /[+~]/,
  568. rescape = /'|\\/g,
  569. // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
  570. runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
  571. funescape = function( _, escaped, escapedWhitespace ) {
  572. var high = "0x" + escaped - 0x10000;
  573. // NaN means non-codepoint
  574. // Support: Firefox<24
  575. // Workaround erroneous numeric interpretation of +"0x"
  576. return high !== high || escapedWhitespace ?
  577. escaped :
  578. high < 0 ?
  579. // BMP codepoint
  580. String.fromCharCode( high + 0x10000 ) :
  581. // Supplemental Plane codepoint (surrogate pair)
  582. String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
  583. };
  584. // Optimize for push.apply( _, NodeList )
  585. try {
  586. push.apply(
  587. (arr = slice.call( preferredDoc.childNodes )),
  588. preferredDoc.childNodes
  589. );
  590. // Support: Android<4.0
  591. // Detect silently failing push.apply
  592. arr[ preferredDoc.childNodes.length ].nodeType;
  593. } catch ( e ) {
  594. push = { apply: arr.length ?
  595. // Leverage slice if possible
  596. function( target, els ) {
  597. push_native.apply( target, slice.call(els) );
  598. } :
  599. // Support: IE<9
  600. // Otherwise append directly
  601. function( target, els ) {
  602. var j = target.length,
  603. i = 0;
  604. // Can't trust NodeList.length
  605. while ( (target[j++] = els[i++]) ) {}
  606. target.length = j - 1;
  607. }
  608. };
  609. }
  610. function Sizzle( selector, context, results, seed ) {
  611. var match, elem, m, nodeType,
  612. // QSA vars
  613. i, groups, old, nid, newContext, newSelector;
  614. if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
  615. setDocument( context );
  616. }
  617. context = context || document;
  618. results = results || [];
  619. if ( !selector || typeof selector !== "string" ) {
  620. return results;
  621. }
  622. if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
  623. return [];
  624. }
  625. if ( documentIsHTML && !seed ) {
  626. // Shortcuts
  627. if ( (match = rquickExpr.exec( selector )) ) {
  628. // Speed-up: Sizzle("#ID")
  629. if ( (m = match[1]) ) {
  630. if ( nodeType === 9 ) {
  631. elem = context.getElementById( m );
  632. // Check parentNode to catch when Blackberry 4.6 returns
  633. // nodes that are no longer in the document (jQuery #6963)
  634. if ( elem && elem.parentNode ) {
  635. // Handle the case where IE, Opera, and Webkit return items
  636. // by name instead of ID
  637. if ( elem.id === m ) {
  638. results.push( elem );
  639. return results;
  640. }
  641. } else {
  642. return results;
  643. }
  644. } else {
  645. // Context is not a document
  646. if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
  647. contains( context, elem ) && elem.id === m ) {
  648. results.push( elem );
  649. return results;
  650. }
  651. }
  652. // Speed-up: Sizzle("TAG")
  653. } else if ( match[2] ) {
  654. push.apply( results, context.getElementsByTagName( selector ) );
  655. return results;
  656. // Speed-up: Sizzle(".CLASS")
  657. } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
  658. push.apply( results, context.getElementsByClassName( m ) );
  659. return results;
  660. }
  661. }
  662. // QSA path
  663. if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
  664. nid = old = expando;
  665. newContext = context;
  666. newSelector = nodeType === 9 && selector;
  667. // qSA works strangely on Element-rooted queries
  668. // We can work around this by specifying an extra ID on the root
  669. // and working up from there (Thanks to Andrew Dupont for the technique)
  670. // IE 8 doesn't work on object elements
  671. if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
  672. groups = tokenize( selector );
  673. if ( (old = context.getAttribute("id")) ) {
  674. nid = old.replace( rescape, "\\$&" );
  675. } else {
  676. context.setAttribute( "id", nid );
  677. }
  678. nid = "[id='" + nid + "'] ";
  679. i = groups.length;
  680. while ( i-- ) {
  681. groups[i] = nid + toSelector( groups[i] );
  682. }
  683. newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
  684. newSelector = groups.join(",");
  685. }
  686. if ( newSelector ) {
  687. try {
  688. push.apply( results,
  689. newContext.querySelectorAll( newSelector )
  690. );
  691. return results;
  692. } catch(qsaError) {
  693. } finally {
  694. if ( !old ) {
  695. context.removeAttribute("id");
  696. }
  697. }
  698. }
  699. }
  700. }
  701. // All others
  702. return select( selector.replace( rtrim, "$1" ), context, results, seed );
  703. }
  704. /**
  705. * Create key-value caches of limited size
  706. * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
  707. * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
  708. * deleting the oldest entry
  709. */
  710. function createCache() {
  711. var keys = [];
  712. function cache( key, value ) {
  713. // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
  714. if ( keys.push( key + " " ) > Expr.cacheLength ) {
  715. // Only keep the most recent entries
  716. delete cache[ keys.shift() ];
  717. }
  718. return (cache[ key + " " ] = value);
  719. }
  720. return cache;
  721. }
  722. /**
  723. * Mark a function for special use by Sizzle
  724. * @param {Function} fn The function to mark
  725. */
  726. function markFunction( fn ) {
  727. fn[ expando ] = true;
  728. return fn;
  729. }
  730. /**
  731. * Support testing using an element
  732. * @param {Function} fn Passed the created div and expects a boolean result
  733. */
  734. function assert( fn ) {
  735. var div = document.createElement("div");
  736. try {
  737. return !!fn( div );
  738. } catch (e) {
  739. return false;
  740. } finally {
  741. // Remove from its parent by default
  742. if ( div.parentNode ) {
  743. div.parentNode.removeChild( div );
  744. }
  745. // release memory in IE
  746. div = null;
  747. }
  748. }
  749. /**
  750. * Adds the same handler for all of the specified attrs
  751. * @param {String} attrs Pipe-separated list of attributes
  752. * @param {Function} handler The method that will be applied
  753. */
  754. function addHandle( attrs, handler ) {
  755. var arr = attrs.split("|"),
  756. i = attrs.length;
  757. while ( i-- ) {
  758. Expr.attrHandle[ arr[i] ] = handler;
  759. }
  760. }
  761. /**
  762. * Checks document order of two siblings
  763. * @param {Element} a
  764. * @param {Element} b
  765. * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
  766. */
  767. function siblingCheck( a, b ) {
  768. var cur = b && a,
  769. diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
  770. ( ~b.sourceIndex || MAX_NEGATIVE ) -
  771. ( ~a.sourceIndex || MAX_NEGATIVE );
  772. // Use IE sourceIndex if available on both nodes
  773. if ( diff ) {
  774. return diff;
  775. }
  776. // Check if b follows a
  777. if ( cur ) {
  778. while ( (cur = cur.nextSibling) ) {
  779. if ( cur === b ) {
  780. return -1;
  781. }
  782. }
  783. }
  784. return a ? 1 : -1;
  785. }
  786. /**
  787. * Returns a function to use in pseudos for input types
  788. * @param {String} type
  789. */
  790. function createInputPseudo( type ) {
  791. return function( elem ) {
  792. var name = elem.nodeName.toLowerCase();
  793. return name === "input" && elem.type === type;
  794. };
  795. }
  796. /**
  797. * Returns a function to use in pseudos for buttons
  798. * @param {String} type
  799. */
  800. function createButtonPseudo( type ) {
  801. return function( elem ) {
  802. var name = elem.nodeName.toLowerCase();
  803. return (name === "input" || name === "button") && elem.type === type;
  804. };
  805. }
  806. /**
  807. * Returns a function to use in pseudos for positionals
  808. * @param {Function} fn
  809. */
  810. function createPositionalPseudo( fn ) {
  811. return markFunction(function( argument ) {
  812. argument = +argument;
  813. return markFunction(function( seed, matches ) {
  814. var j,
  815. matchIndexes = fn( [], seed.length, argument ),
  816. i = matchIndexes.length;
  817. // Match elements found at the specified indexes
  818. while ( i-- ) {
  819. if ( seed[ (j = matchIndexes[i]) ] ) {
  820. seed[j] = !(matches[j] = seed[j]);
  821. }
  822. }
  823. });
  824. });
  825. }
  826. /**
  827. * Checks a node for validity as a Sizzle context
  828. * @param {Element|Object=} context
  829. * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
  830. */
  831. function testContext( context ) {
  832. return context && typeof context.getElementsByTagName !== strundefined && context;
  833. }
  834. // Expose support vars for convenience
  835. support = Sizzle.support = {};
  836. /**
  837. * Detects XML nodes
  838. * @param {Element|Object} elem An element or a document
  839. * @returns {Boolean} True iff elem is a non-HTML XML node
  840. */
  841. isXML = Sizzle.isXML = function( elem ) {
  842. // documentElement is verified for cases where it doesn't yet exist
  843. // (such as loading iframes in IE - #4833)
  844. var documentElement = elem && (elem.ownerDocument || elem).documentElement;
  845. return documentElement ? documentElement.nodeName !== "HTML" : false;
  846. };
  847. /**
  848. * Sets document-related variables once based on the current document
  849. * @param {Element|Object} [doc] An element or document object to use to set the document
  850. * @returns {Object} Returns the current document
  851. */
  852. setDocument = Sizzle.setDocument = function( node ) {
  853. var hasCompare,
  854. doc = node ? node.ownerDocument || node : preferredDoc,
  855. parent = doc.defaultView;
  856. // If no document and documentElement is available, return
  857. if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
  858. return document;
  859. }
  860. // Set our document
  861. document = doc;
  862. docElem = doc.documentElement;
  863. // Support tests
  864. documentIsHTML = !isXML( doc );
  865. // Support: IE>8
  866. // If iframe document is assigned to "document" variable and if iframe has been reloaded,
  867. // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
  868. // IE6-8 do not support the defaultView property so parent will be undefined
  869. if ( parent && parent !== parent.top ) {
  870. // IE11 does not have attachEvent, so all must suffer
  871. if ( parent.addEventListener ) {
  872. parent.addEventListener( "unload", function() {
  873. setDocument();
  874. }, false );
  875. } else if ( parent.attachEvent ) {
  876. parent.attachEvent( "onunload", function() {
  877. setDocument();
  878. });
  879. }
  880. }
  881. /* Attributes
  882. ---------------------------------------------------------------------- */
  883. // Support: IE<8
  884. // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
  885. support.attributes = assert(function( div ) {
  886. div.className = "i";
  887. return !div.getAttribute("className");
  888. });
  889. /* getElement(s)By*
  890. ---------------------------------------------------------------------- */
  891. // Check if getElementsByTagName("*") returns only elements
  892. support.getElementsByTagName = assert(function( div ) {
  893. div.appendChild( doc.createComment("") );
  894. return !div.getElementsByTagName("*").length;
  895. });
  896. // Check if getElementsByClassName can be trusted
  897. support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
  898. div.innerHTML = "<div class='a'></div><div class='a i'></div>";
  899. // Support: Safari<4
  900. // Catch class over-caching
  901. div.firstChild.className = "i";
  902. // Support: Opera<10
  903. // Catch gEBCN failure to find non-leading classes
  904. return div.getElementsByClassName("i").length === 2;
  905. });
  906. // Support: IE<10
  907. // Check if getElementById returns elements by name
  908. // The broken getElementById methods don't pick up programatically-set names,
  909. // so use a roundabout getElementsByName test
  910. support.getById = assert(function( div ) {
  911. docElem.appendChild( div ).id = expando;
  912. return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
  913. });
  914. // ID find and filter
  915. if ( support.getById ) {
  916. Expr.find["ID"] = function( id, context ) {
  917. if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
  918. var m = context.getElementById( id );
  919. // Check parentNode to catch when Blackberry 4.6 returns
  920. // nodes that are no longer in the document #6963
  921. return m && m.parentNode ? [ m ] : [];
  922. }
  923. };
  924. Expr.filter["ID"] = function( id ) {
  925. var attrId = id.replace( runescape, funescape );
  926. return function( elem ) {
  927. return elem.getAttribute("id") === attrId;
  928. };
  929. };
  930. } else {
  931. // Support: IE6/7
  932. // getElementById is not reliable as a find shortcut
  933. delete Expr.find["ID"];
  934. Expr.filter["ID"] = function( id ) {
  935. var attrId = id.replace( runescape, funescape );
  936. return function( elem ) {
  937. var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
  938. return node && node.value === attrId;
  939. };
  940. };
  941. }
  942. // Tag
  943. Expr.find["TAG"] = support.getElementsByTagName ?
  944. function( tag, context ) {
  945. if ( typeof context.getElementsByTagName !== strundefined ) {
  946. return context.getElementsByTagName( tag );
  947. }
  948. } :
  949. function( tag, context ) {
  950. var elem,
  951. tmp = [],
  952. i = 0,
  953. results = context.getElementsByTagName( tag );
  954. // Filter out possible comments
  955. if ( tag === "*" ) {
  956. while ( (elem = results[i++]) ) {
  957. if ( elem.nodeType === 1 ) {
  958. tmp.push( elem );
  959. }
  960. }
  961. return tmp;
  962. }
  963. return results;
  964. };
  965. // Class
  966. Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
  967. if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
  968. return context.getElementsByClassName( className );
  969. }
  970. };
  971. /* QSA/matchesSelector
  972. ---------------------------------------------------------------------- */
  973. // QSA and matchesSelector support
  974. // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
  975. rbuggyMatches = [];
  976. // qSa(:focus) reports false when true (Chrome 21)
  977. // We allow this because of a bug in IE8/9 that throws an error
  978. // whenever `document.activeElement` is accessed on an iframe
  979. // So, we allow :focus to pass through QSA all the time to avoid the IE error
  980. // See http://bugs.jquery.com/ticket/13378
  981. rbuggyQSA = [];
  982. if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
  983. // Build QSA regex
  984. // Regex strategy adopted from Diego Perini
  985. assert(function( div ) {
  986. // Select is set to empty string on purpose
  987. // This is to test IE's treatment of not explicitly
  988. // setting a boolean content attribute,
  989. // since its presence should be enough
  990. // http://bugs.jquery.com/ticket/12359
  991. div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
  992. // Support: IE8, Opera 11-12.16
  993. // Nothing should be selected when empty strings follow ^= or $= or *=
  994. // The test attribute must be unknown in Opera but "safe" for WinRT
  995. // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
  996. if ( div.querySelectorAll("[msallowclip^='']").length ) {
  997. rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
  998. }
  999. // Support: IE8
  1000. // Boolean attributes and "value" are not treated correctly
  1001. if ( !div.querySelectorAll("[selected]").length ) {
  1002. rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
  1003. }
  1004. // Webkit/Opera - :checked should return selected option elements
  1005. // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
  1006. // IE8 throws error here and will not see later tests
  1007. if ( !div.querySelectorAll(":checked").length ) {
  1008. rbuggyQSA.push(":checked");
  1009. }
  1010. });
  1011. assert(function( div ) {
  1012. // Support: Windows 8 Native Apps
  1013. // The type and name attributes are restricted during .innerHTML assignment
  1014. var input = doc.createElement("input");
  1015. input.setAttribute( "type", "hidden" );
  1016. div.appendChild( input ).setAttribute( "name", "D" );
  1017. // Support: IE8
  1018. // Enforce case-sensitivity of name attribute
  1019. if ( div.querySelectorAll("[name=d]").length ) {
  1020. rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
  1021. }
  1022. // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
  1023. // IE8 throws error here and will not see later tests
  1024. if ( !div.querySelectorAll(":enabled").length ) {
  1025. rbuggyQSA.push( ":enabled", ":disabled" );
  1026. }
  1027. // Opera 10-11 does not throw on post-comma invalid pseudos
  1028. div.querySelectorAll("*,:x");
  1029. rbuggyQSA.push(",.*:");
  1030. });
  1031. }
  1032. if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
  1033. docElem.webkitMatchesSelector ||
  1034. docElem.mozMatchesSelector ||
  1035. docElem.oMatchesSelector ||
  1036. docElem.msMatchesSelector) )) ) {
  1037. assert(function( div ) {
  1038. // Check to see if it's possible to do matchesSelector
  1039. // on a disconnected node (IE 9)
  1040. support.disconnectedMatch = matches.call( div, "div" );
  1041. // This should fail with an exception
  1042. // Gecko does not error, returns false instead
  1043. matches.call( div, "[s!='']:x" );
  1044. rbuggyMatches.push( "!=", pseudos );
  1045. });
  1046. }
  1047. rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
  1048. rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
  1049. /* Contains
  1050. ---------------------------------------------------------------------- */
  1051. hasCompare = rnative.test( docElem.compareDocumentPosition );
  1052. // Element contains another
  1053. // Purposefully does not implement inclusive descendent
  1054. // As in, an element does not contain itself
  1055. contains = hasCompare || rnative.test( docElem.contains ) ?
  1056. function( a, b ) {
  1057. var adown = a.nodeType === 9 ? a.documentElement : a,
  1058. bup = b && b.parentNode;
  1059. return a === bup || !!( bup && bup.nodeType === 1 && (
  1060. adown.contains ?
  1061. adown.contains( bup ) :
  1062. a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
  1063. ));
  1064. } :
  1065. function( a, b ) {
  1066. if ( b ) {
  1067. while ( (b = b.parentNode) ) {
  1068. if ( b === a ) {
  1069. return true;
  1070. }
  1071. }
  1072. }
  1073. return false;
  1074. };
  1075. /* Sorting
  1076. ---------------------------------------------------------------------- */
  1077. // Document order sorting
  1078. sortOrder = hasCompare ?
  1079. function( a, b ) {
  1080. // Flag for duplicate removal
  1081. if ( a === b ) {
  1082. hasDuplicate = true;
  1083. return 0;
  1084. }
  1085. // Sort on method existence if only one input has compareDocumentPosition
  1086. var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
  1087. if ( compare ) {
  1088. return compare;
  1089. }
  1090. // Calculate position if both inputs belong to the same document
  1091. compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
  1092. a.compareDocumentPosition( b ) :
  1093. // Otherwise we know they are disconnected
  1094. 1;
  1095. // Disconnected nodes
  1096. if ( compare & 1 ||
  1097. (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
  1098. // Choose the first element that is related to our preferred document
  1099. if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
  1100. return -1;
  1101. }
  1102. if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
  1103. return 1;
  1104. }
  1105. // Maintain original order
  1106. return sortInput ?
  1107. ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
  1108. 0;
  1109. }
  1110. return compare & 4 ? -1 : 1;
  1111. } :
  1112. function( a, b ) {
  1113. // Exit early if the nodes are identical
  1114. if ( a === b ) {
  1115. hasDuplicate = true;
  1116. return 0;
  1117. }
  1118. var cur,
  1119. i = 0,
  1120. aup = a.parentNode,
  1121. bup = b.parentNode,
  1122. ap = [ a ],
  1123. bp = [ b ];
  1124. // Parentless nodes are either documents or disconnected
  1125. if ( !aup || !bup ) {
  1126. return a === doc ? -1 :
  1127. b === doc ? 1 :
  1128. aup ? -1 :
  1129. bup ? 1 :
  1130. sortInput ?
  1131. ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
  1132. 0;
  1133. // If the nodes are siblings, we can do a quick check
  1134. } else if ( aup === bup ) {
  1135. return siblingCheck( a, b );
  1136. }
  1137. // Otherwise we need full lists of their ancestors for comparison
  1138. cur = a;
  1139. while ( (cur = cur.parentNode) ) {
  1140. ap.unshift( cur );
  1141. }
  1142. cur = b;
  1143. while ( (cur = cur.parentNode) ) {
  1144. bp.unshift( cur );
  1145. }
  1146. // Walk down the tree looking for a discrepancy
  1147. while ( ap[i] === bp[i] ) {
  1148. i++;
  1149. }
  1150. return i ?
  1151. // Do a sibling check if the nodes have a common ancestor
  1152. siblingCheck( ap[i], bp[i] ) :
  1153. // Otherwise nodes in our document sort first
  1154. ap[i] === preferredDoc ? -1 :
  1155. bp[i] === preferredDoc ? 1 :
  1156. 0;
  1157. };
  1158. return doc;
  1159. };
  1160. Sizzle.matches = function( expr, elements ) {
  1161. return Sizzle( expr, null, null, elements );
  1162. };
  1163. Sizzle.matchesSelector = function( elem, expr ) {
  1164. // Set document vars if needed
  1165. if ( ( elem.ownerDocument || elem ) !== document ) {
  1166. setDocument( elem );
  1167. }
  1168. // Make sure that attribute selectors are quoted
  1169. expr = expr.replace( rattributeQuotes, "='$1']" );
  1170. if ( support.matchesSelector && documentIsHTML &&
  1171. ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
  1172. ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
  1173. try {
  1174. var ret = matches.call( elem, expr );
  1175. // IE 9's matchesSelector returns false on disconnected nodes
  1176. if ( ret || support.disconnectedMatch ||
  1177. // As well, disconnected nodes are said to be in a document
  1178. // fragment in IE 9
  1179. elem.document && elem.document.nodeType !== 11 ) {
  1180. return ret;
  1181. }
  1182. } catch(e) {}
  1183. }
  1184. return Sizzle( expr, document, null, [ elem ] ).length > 0;
  1185. };
  1186. Sizzle.contains = function( context, elem ) {
  1187. // Set document vars if needed
  1188. if ( ( context.ownerDocument || context ) !== document ) {
  1189. setDocument( context );
  1190. }
  1191. return contains( context, elem );
  1192. };
  1193. Sizzle.attr = function( elem, name ) {
  1194. // Set document vars if needed
  1195. if ( ( elem.ownerDocument || elem ) !== document ) {
  1196. setDocument( elem );
  1197. }
  1198. var fn = Expr.attrHandle[ name.toLowerCase() ],
  1199. // Don't get fooled by Object.prototype properties (jQuery #13807)
  1200. val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
  1201. fn( elem, name, !documentIsHTML ) :
  1202. undefined;
  1203. return val !== undefined ?
  1204. val :
  1205. support.attributes || !documentIsHTML ?
  1206. elem.getAttribute( name ) :
  1207. (val = elem.getAttributeNode(name)) && val.specified ?
  1208. val.value :
  1209. null;
  1210. };
  1211. Sizzle.error = function( msg ) {
  1212. throw new Error( "Syntax error, unrecognized expression: " + msg );
  1213. };
  1214. /**
  1215. * Document sorting and removing duplicates
  1216. * @param {ArrayLike} results
  1217. */
  1218. Sizzle.uniqueSort = function( results ) {
  1219. var elem,
  1220. duplicates = [],
  1221. j = 0,
  1222. i = 0;
  1223. // Unless we *know* we can detect duplicates, assume their presence
  1224. hasDuplicate = !support.detectDuplicates;
  1225. sortInput = !support.sortStable && results.slice( 0 );
  1226. results.sort( sortOrder );
  1227. if ( hasDuplicate ) {
  1228. while ( (elem = results[i++]) ) {
  1229. if ( elem === results[ i ] ) {
  1230. j = duplicates.push( i );
  1231. }
  1232. }
  1233. while ( j-- ) {
  1234. results.splice( duplicates[ j ], 1 );
  1235. }
  1236. }
  1237. // Clear input after sorting to release objects
  1238. // See https://github.com/jquery/sizzle/pull/225
  1239. sortInput = null;
  1240. return results;
  1241. };
  1242. /**
  1243. * Utility function for retrieving the text value of an array of DOM nodes
  1244. * @param {Array|Element} elem
  1245. */
  1246. getText = Sizzle.getText = function( elem ) {
  1247. var node,
  1248. ret = "",
  1249. i = 0,
  1250. nodeType = elem.nodeType;
  1251. if ( !nodeType ) {
  1252. // If no nodeType, this is expected to be an array
  1253. while ( (node = elem[i++]) ) {
  1254. // Do not traverse comment nodes
  1255. ret += getText( node );
  1256. }
  1257. } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
  1258. // Use textContent for elements
  1259. // innerText usage removed for consistency of new lines (jQuery #11153)
  1260. if ( typeof elem.textContent === "string" ) {
  1261. return elem.textContent;
  1262. } else {
  1263. // Traverse its children
  1264. for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
  1265. ret += getText( elem );
  1266. }
  1267. }
  1268. } else if ( nodeType === 3 || nodeType === 4 ) {
  1269. return elem.nodeValue;
  1270. }
  1271. // Do not include comment or processing instruction nodes
  1272. return ret;
  1273. };
  1274. Expr = Sizzle.selectors = {
  1275. // Can be adjusted by the user
  1276. cacheLength: 50,
  1277. createPseudo: markFunction,
  1278. match: matchExpr,
  1279. attrHandle: {},
  1280. find: {},
  1281. relative: {
  1282. ">": { dir: "parentNode", first: true },
  1283. " ": { dir: "parentNode" },
  1284. "+": { dir: "previousSibling", first: true },
  1285. "~": { dir: "previousSibling" }
  1286. },
  1287. preFilter: {
  1288. "ATTR": function( match ) {
  1289. match[1] = match[1].replace( runescape, funescape );
  1290. // Move the given value to match[3] whether quoted or unquoted
  1291. match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
  1292. if ( match[2] === "~=" ) {
  1293. match[3] = " " + match[3] + " ";
  1294. }
  1295. return match.slice( 0, 4 );
  1296. },
  1297. "CHILD": function( match ) {
  1298. /* matches from matchExpr["CHILD"]
  1299. 1 type (only|nth|...)
  1300. 2 what (child|of-type)
  1301. 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
  1302. 4 xn-component of xn+y argument ([+-]?\d*n|)
  1303. 5 sign of xn-component
  1304. 6 x of xn-component
  1305. 7 sign of y-component
  1306. 8 y of y-component
  1307. */
  1308. match[1] = match[1].toLowerCase();
  1309. if ( match[1].slice( 0, 3 ) === "nth" ) {
  1310. // nth-* requires argument
  1311. if ( !match[3] ) {
  1312. Sizzle.error( match[0] );
  1313. }
  1314. // numeric x and y parameters for Expr.filter.CHILD
  1315. // remember that false/true cast respectively to 0/1
  1316. match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
  1317. match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
  1318. // other types prohibit arguments
  1319. } else if ( match[3] ) {
  1320. Sizzle.error( match[0] );
  1321. }
  1322. return match;
  1323. },
  1324. "PSEUDO": function( match ) {
  1325. var excess,
  1326. unquoted = !match[6] && match[2];
  1327. if ( matchExpr["CHILD"].test( match[0] ) ) {
  1328. return null;
  1329. }
  1330. // Accept quoted arguments as-is
  1331. if ( match[3] ) {
  1332. match[2] = match[4] || match[5] || "";
  1333. // Strip excess characters from unquoted arguments
  1334. } else if ( unquoted && rpseudo.test( unquoted ) &&
  1335. // Get excess from tokenize (recursively)
  1336. (excess = tokenize( unquoted, true )) &&
  1337. // advance to the next closing parenthesis
  1338. (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
  1339. // excess is a negative index
  1340. match[0] = match[0].slice( 0, excess );
  1341. match[2] = unquoted.slice( 0, excess );
  1342. }
  1343. // Return only captures needed by the pseudo filter method (type and argument)
  1344. return match.slice( 0, 3 );
  1345. }
  1346. },
  1347. filter: {
  1348. "TAG": function( nodeNameSelector ) {
  1349. var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
  1350. return nodeNameSelector === "*" ?
  1351. function() { return true; } :
  1352. function( elem ) {
  1353. return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
  1354. };
  1355. },
  1356. "CLASS": function( className ) {
  1357. var pattern = classCache[ className + " " ];
  1358. return pattern ||
  1359. (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
  1360. classCache( className, function( elem ) {
  1361. return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
  1362. });
  1363. },
  1364. "ATTR": function( name, operator, check ) {
  1365. return function( elem ) {
  1366. var result = Sizzle.attr( elem, name );
  1367. if ( result == null ) {
  1368. return operator === "!=";
  1369. }
  1370. if ( !operator ) {
  1371. return true;
  1372. }
  1373. result += "";
  1374. return operator === "=" ? result === check :
  1375. operator === "!=" ? result !== check :
  1376. operator === "^=" ? check && result.indexOf( check ) === 0 :
  1377. operator === "*=" ? check && result.indexOf( check ) > -1 :
  1378. operator === "$=" ? check && result.slice( -check.length ) === check :
  1379. operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
  1380. operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
  1381. false;
  1382. };
  1383. },
  1384. "CHILD": function( type, what, argument, first, last ) {
  1385. var simple = type.slice( 0, 3 ) !== "nth",
  1386. forward = type.slice( -4 ) !== "last",
  1387. ofType = what === "of-type";
  1388. return first === 1 && last === 0 ?
  1389. // Shortcut for :nth-*(n)
  1390. function( elem ) {
  1391. return !!elem.parentNode;
  1392. } :
  1393. function( elem, context, xml ) {
  1394. var cache, outerCache, node, diff, nodeIndex, start,
  1395. dir = simple !== forward ? "nextSibling" : "previousSibling",
  1396. parent = elem.parentNode,
  1397. name = ofType && elem.nodeName.toLowerCase(),
  1398. useCache = !xml && !ofType;
  1399. if ( parent ) {
  1400. // :(first|last|only)-(child|of-type)
  1401. if ( simple ) {
  1402. while ( dir ) {
  1403. node = elem;
  1404. while ( (node = node[ dir ]) ) {
  1405. if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
  1406. return false;
  1407. }
  1408. }
  1409. // Reverse direction for :only-* (if we haven't yet done so)
  1410. start = dir = type === "only" && !start && "nextSibling";
  1411. }
  1412. return true;
  1413. }
  1414. start = [ forward ? parent.firstChild : parent.lastChild ];
  1415. // non-xml :nth-child(...) stores cache data on `parent`
  1416. if ( forward && useCache ) {
  1417. // Seek `elem` from a previously-cached index
  1418. outerCache = parent[ expando ] || (parent[ expando ] = {});
  1419. cache = outerCache[ type ] || [];
  1420. nodeIndex = cache[0] === dirruns && cache[1];
  1421. diff = cache[0] === dirruns && cache[2];
  1422. node = nodeIndex && parent.childNodes[ nodeIndex ];
  1423. while ( (node = ++nodeIndex && node && node[ dir ] ||
  1424. // Fallback to seeking `elem` from the start
  1425. (diff = nodeIndex = 0) || start.pop()) ) {
  1426. // When found, cache indexes on `parent` and break
  1427. if ( node.nodeType === 1 && ++diff && node === elem ) {
  1428. outerCache[ type ] = [ dirruns, nodeIndex, diff ];
  1429. break;
  1430. }
  1431. }
  1432. // Use previously-cached element index if available
  1433. } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
  1434. diff = cache[1];
  1435. // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
  1436. } else {
  1437. // Use the same loop as above to seek `elem` from the start
  1438. while ( (node = ++nodeIndex && node && node[ dir ] ||
  1439. (diff = nodeIndex = 0) || start.pop()) ) {
  1440. if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
  1441. // Cache the index of each encountered element
  1442. if ( useCache ) {
  1443. (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
  1444. }
  1445. if ( node === elem ) {
  1446. break;
  1447. }
  1448. }
  1449. }
  1450. }
  1451. // Incorporate the offset, then check against cycle size
  1452. diff -= last;
  1453. return diff === first || ( diff % first === 0 && diff / first >= 0 );
  1454. }
  1455. };
  1456. },
  1457. "PSEUDO": function( pseudo, argument ) {
  1458. // pseudo-class names are case-insensitive
  1459. // http://www.w3.org/TR/selectors/#pseudo-classes
  1460. // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
  1461. // Remember that setFilters inherits from pseudos
  1462. var args,
  1463. fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
  1464. Sizzle.error( "unsupported pseudo: " + pseudo );
  1465. // The user may use createPseudo to indicate that
  1466. // arguments are needed to create the filter function
  1467. // just as Sizzle does
  1468. if ( fn[ expando ] ) {
  1469. return fn( argument );
  1470. }
  1471. // But maintain support for old signatures
  1472. if ( fn.length > 1 ) {
  1473. args = [ pseudo, pseudo, "", argument ];
  1474. return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
  1475. markFunction(function( seed, matches ) {
  1476. var idx,
  1477. matched = fn( seed, argument ),
  1478. i = matched.length;
  1479. while ( i-- ) {
  1480. idx = indexOf.call( seed, matched[i] );
  1481. seed[ idx ] = !( matches[ idx ] = matched[i] );
  1482. }
  1483. }) :
  1484. function( elem ) {
  1485. return fn( elem, 0, args );
  1486. };
  1487. }
  1488. return fn;
  1489. }
  1490. },
  1491. pseudos: {
  1492. // Potentially complex pseudos
  1493. "not": markFunction(function( selector ) {
  1494. // Trim the selector passed to compile
  1495. // to avoid treating leading and trailing
  1496. // spaces as combinators
  1497. var input = [],
  1498. results = [],
  1499. matcher = compile( selector.replace( rtrim, "$1" ) );
  1500. return matcher[ expando ] ?
  1501. markFunction(function( seed, matches, context, xml ) {
  1502. var elem,
  1503. unmatched = matcher( seed, null, xml, [] ),
  1504. i = seed.length;
  1505. // Match elements unmatched by `matcher`
  1506. while ( i-- ) {
  1507. if ( (elem = unmatched[i]) ) {
  1508. seed[i] = !(matches[i] = elem);
  1509. }
  1510. }
  1511. }) :
  1512. function( elem, context, xml ) {
  1513. input[0] = elem;
  1514. matcher( input, null, xml, results );
  1515. return !results.pop();
  1516. };
  1517. }),
  1518. "has": markFunction(function( selector ) {
  1519. return function( elem ) {
  1520. return Sizzle( selector, elem ).length > 0;
  1521. };
  1522. }),
  1523. "contains": markFunction(function( text ) {
  1524. return function( elem ) {
  1525. return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
  1526. };
  1527. }),
  1528. // "Whether an element is represented by a :lang() selector
  1529. // is based solely on the element's language value
  1530. // being equal to the identifier C,
  1531. // or beginning with the identifier C immediately followed by "-".
  1532. // The matching of C against the element's language value is performed case-insensitively.
  1533. // The identifier C does not have to be a valid language name."
  1534. // http://www.w3.org/TR/selectors/#lang-pseudo
  1535. "lang": markFunction( function( lang ) {
  1536. // lang value must be a valid identifier
  1537. if ( !ridentifier.test(lang || "") ) {
  1538. Sizzle.error( "unsupported lang: " + lang );
  1539. }
  1540. lang = lang.replace( runescape, funescape ).toLowerCase();
  1541. return function( elem ) {
  1542. var elemLang;
  1543. do {
  1544. if ( (elemLang = documentIsHTML ?
  1545. elem.lang :
  1546. elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
  1547. elemLang = elemLang.toLowerCase();
  1548. return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
  1549. }
  1550. } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
  1551. return false;
  1552. };
  1553. }),
  1554. // Miscellaneous
  1555. "target": function( elem ) {
  1556. var hash = window.location && window.location.hash;
  1557. return hash && hash.slice( 1 ) === elem.id;
  1558. },
  1559. "root": function( elem ) {
  1560. return elem === docElem;
  1561. },
  1562. "focus": function( elem ) {
  1563. return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
  1564. },
  1565. // Boolean properties
  1566. "enabled": function( elem ) {
  1567. return elem.disabled === false;
  1568. },
  1569. "disabled": function( elem ) {
  1570. return elem.disabled === true;
  1571. },
  1572. "checked": function( elem ) {
  1573. // In CSS3, :checked should return both checked and selected elements
  1574. // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
  1575. var nodeName = elem.nodeName.toLowerCase();
  1576. return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
  1577. },
  1578. "selected": function( elem ) {
  1579. // Accessing this property makes selected-by-default
  1580. // options in Safari work properly
  1581. if ( elem.parentNode ) {
  1582. elem.parentNode.selectedIndex;
  1583. }
  1584. return elem.selected === true;
  1585. },
  1586. // Contents
  1587. "empty": function( elem ) {
  1588. // http://www.w3.org/TR/selectors/#empty-pseudo
  1589. // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
  1590. // but not by others (comment: 8; processing instruction: 7; etc.)
  1591. // nodeType < 6 works because attributes (2) do not appear as children
  1592. for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
  1593. if ( elem.nodeType < 6 ) {
  1594. return false;
  1595. }
  1596. }
  1597. return true;
  1598. },
  1599. "parent": function( elem ) {
  1600. return !Expr.pseudos["empty"]( elem );
  1601. },
  1602. // Element/input types
  1603. "header": function( elem ) {
  1604. return rheader.test( elem.nodeName );
  1605. },
  1606. "input": function( elem ) {
  1607. return rinputs.test( elem.nodeName );
  1608. },
  1609. "button": function( elem ) {
  1610. var name = elem.nodeName.toLowerCase();
  1611. return name === "input" && elem.type === "button" || name === "button";
  1612. },
  1613. "text": function( elem ) {
  1614. var attr;
  1615. return elem.nodeName.toLowerCase() === "input" &&
  1616. elem.type === "text" &&
  1617. // Support: IE<8
  1618. // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
  1619. ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
  1620. },
  1621. // Position-in-collection
  1622. "first": createPositionalPseudo(function() {
  1623. return [ 0 ];
  1624. }),
  1625. "last": createPositionalPseudo(function( matchIndexes, length ) {
  1626. return [ length - 1 ];
  1627. }),
  1628. "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
  1629. return [ argument < 0 ? argument + length : argument ];
  1630. }),
  1631. "even": createPositionalPseudo(function( matchIndexes, length ) {
  1632. var i = 0;
  1633. for ( ; i < length; i += 2 ) {
  1634. matchIndexes.push( i );
  1635. }
  1636. return matchIndexes;
  1637. }),
  1638. "odd": createPositionalPseudo(function( matchIndexes, length ) {
  1639. var i = 1;
  1640. for ( ; i < length; i += 2 ) {
  1641. matchIndexes.push( i );
  1642. }
  1643. return matchIndexes;
  1644. }),
  1645. "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
  1646. var i = argument < 0 ? argument + length : argument;
  1647. for ( ; --i >= 0; ) {
  1648. matchIndexes.push( i );
  1649. }
  1650. return matchIndexes;
  1651. }),
  1652. "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
  1653. var i = argument < 0 ? argument + length : argument;
  1654. for ( ; ++i < length; ) {
  1655. matchIndexes.push( i );
  1656. }
  1657. return matchIndexes;
  1658. })
  1659. }
  1660. };
  1661. Expr.pseudos["nth"] = Expr.pseudos["eq"];
  1662. // Add button/input type pseudos
  1663. for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
  1664. Expr.pseudos[ i ] = createInputPseudo( i );
  1665. }
  1666. for ( i in { submit: true, reset: true } ) {
  1667. Expr.pseudos[ i ] = createButtonPseudo( i );
  1668. }
  1669. // Easy API for creating new setFilters
  1670. function setFilters() {}
  1671. setFilters.prototype = Expr.filters = Expr.pseudos;
  1672. Expr.setFilters = new setFilters();
  1673. tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
  1674. var matched, match, tokens, type,
  1675. soFar, groups, preFilters,
  1676. cached = tokenCache[ selector + " " ];
  1677. if ( cached ) {
  1678. return parseOnly ? 0 : cached.slice( 0 );
  1679. }
  1680. soFar = selector;
  1681. groups = [];
  1682. preFilters = Expr.preFilter;
  1683. while ( soFar ) {
  1684. // Comma and first run
  1685. if ( !matched || (match = rcomma.exec( soFar )) ) {
  1686. if ( match ) {
  1687. // Don't consume trailing commas as valid
  1688. soFar = soFar.slice( match[0].length ) || soFar;
  1689. }
  1690. groups.push( (tokens = []) );
  1691. }
  1692. matched = false;
  1693. // Combinators
  1694. if ( (match = rcombinators.exec( soFar )) ) {
  1695. matched = match.shift();
  1696. tokens.push({
  1697. value: matched,
  1698. // Cast descendant combinators to space
  1699. type: match[0].replace( rtrim, " " )
  1700. });
  1701. soFar = soFar.slice( matched.length );
  1702. }
  1703. // Filters
  1704. for ( type in Expr.filter ) {
  1705. if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
  1706. (match = preFilters[ type ]( match ))) ) {
  1707. matched = match.shift();
  1708. tokens.push({
  1709. value: matched,
  1710. type: type,
  1711. matches: match
  1712. });
  1713. soFar = soFar.slice( matched.length );
  1714. }
  1715. }
  1716. if ( !matched ) {
  1717. break;
  1718. }
  1719. }
  1720. // Return the length of the invalid excess
  1721. // if we're just parsing
  1722. // Otherwise, throw an error or return tokens
  1723. return parseOnly ?
  1724. soFar.length :
  1725. soFar ?
  1726. Sizzle.error( selector ) :
  1727. // Cache the tokens
  1728. tokenCache( selector, groups ).slice( 0 );
  1729. };
  1730. function toSelector( tokens ) {
  1731. var i = 0,
  1732. len = tokens.length,
  1733. selector = "";
  1734. for ( ; i < len; i++ ) {
  1735. selector += tokens[i].value;
  1736. }
  1737. return selector;
  1738. }
  1739. function addCombinator( matcher, combinator, base ) {
  1740. var dir = combinator.dir,
  1741. checkNonElements = base && dir === "parentNode",
  1742. doneName = done++;
  1743. return combinator.first ?
  1744. // Check against closest ancestor/preceding element
  1745. function( elem, context, xml ) {
  1746. while ( (elem = elem[ dir ]) ) {
  1747. if ( elem.nodeType === 1 || checkNonElements ) {
  1748. return matcher( elem, context, xml );
  1749. }
  1750. }
  1751. } :
  1752. // Check against all ancestor/preceding elements
  1753. function( elem, context, xml ) {
  1754. var oldCache, outerCache,
  1755. newCache = [ dirruns, doneName ];
  1756. // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
  1757. if ( xml ) {
  1758. while ( (elem = elem[ dir ]) ) {
  1759. if ( elem.nodeType === 1 || checkNonElements ) {
  1760. if ( matcher( elem, context, xml ) ) {
  1761. return true;
  1762. }
  1763. }
  1764. }
  1765. } else {
  1766. while ( (elem = elem[ dir ]) ) {
  1767. if ( elem.nodeType === 1 || checkNonElements ) {
  1768. outerCache = elem[ expando ] || (elem[ expando ] = {});
  1769. if ( (oldCache = outerCache[ dir ]) &&
  1770. oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
  1771. // Assign to newCache so results back-propagate to previous elements
  1772. return (newCache[ 2 ] = oldCache[ 2 ]);
  1773. } else {
  1774. // Reuse newcache so results back-propagate to previous elements
  1775. outerCache[ dir ] = newCache;
  1776. // A match means we're done; a fail means we have to keep checking
  1777. if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
  1778. return true;
  1779. }
  1780. }
  1781. }
  1782. }
  1783. }
  1784. };
  1785. }
  1786. function elementMatcher( matchers ) {
  1787. return matchers.length > 1 ?
  1788. function( elem, context, xml ) {
  1789. var i = matchers.length;
  1790. while ( i-- ) {
  1791. if ( !matchers[i]( elem, context, xml ) ) {
  1792. return false;
  1793. }
  1794. }
  1795. return true;
  1796. } :
  1797. matchers[0];
  1798. }
  1799. function multipleContexts( selector, contexts, results ) {
  1800. var i = 0,
  1801. len = contexts.length;
  1802. for ( ; i < len; i++ ) {
  1803. Sizzle( selector, contexts[i], results );
  1804. }
  1805. return results;
  1806. }
  1807. function condense( unmatched, map, filter, context, xml ) {
  1808. var elem,
  1809. newUnmatched = [],
  1810. i = 0,
  1811. len = unmatched.length,
  1812. mapped = map != null;
  1813. for ( ; i < len; i++ ) {
  1814. if ( (elem = unmatched[i]) ) {
  1815. if ( !filter || filter( elem, context, xml ) ) {
  1816. newUnmatched.push( elem );
  1817. if ( mapped ) {
  1818. map.push( i );
  1819. }
  1820. }
  1821. }
  1822. }
  1823. return newUnmatched;
  1824. }
  1825. function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
  1826. if ( postFilter && !postFilter[ expando ] ) {
  1827. postFilter = setMatcher( postFilter );
  1828. }
  1829. if ( postFinder && !postFinder[ expando ] ) {
  1830. postFinder = setMatcher( postFinder, postSelector );
  1831. }
  1832. return markFunction(function( seed, results, context, xml ) {
  1833. var temp, i, elem,
  1834. preMap = [],
  1835. postMap = [],
  1836. preexisting = results.length,
  1837. // Get initial elements from seed or context
  1838. elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
  1839. // Prefilter to get matcher input, preserving a map for seed-results synchronization
  1840. matcherIn = preFilter && ( seed || !selector ) ?
  1841. condense( elems, preMap, preFilter, context, xml ) :
  1842. elems,
  1843. matcherOut = matcher ?
  1844. // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
  1845. postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
  1846. // ...intermediate processing is necessary
  1847. [] :
  1848. // ...otherwise use results directly
  1849. results :
  1850. matcherIn;
  1851. // Find primary matches
  1852. if ( matcher ) {
  1853. matcher( matcherIn, matcherOut, context, xml );
  1854. }
  1855. // Apply postFilter
  1856. if ( postFilter ) {
  1857. temp = condense( matcherOut, postMap );
  1858. postFilter( temp, [], context, xml );
  1859. // Un-match failing elements by moving them back to matcherIn
  1860. i = temp.length;
  1861. while ( i-- ) {
  1862. if ( (elem = temp[i]) ) {
  1863. matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
  1864. }
  1865. }
  1866. }
  1867. if ( seed ) {
  1868. if ( postFinder || preFilter ) {
  1869. if ( postFinder ) {
  1870. // Get the final matcherOut by condensing this intermediate into postFinder contexts
  1871. temp = [];
  1872. i = matcherOut.length;
  1873. while ( i-- ) {
  1874. if ( (elem = matcherOut[i]) ) {
  1875. // Restore matcherIn since elem is not yet a final match
  1876. temp.push( (matcherIn[i] = elem) );
  1877. }
  1878. }
  1879. postFinder( null, (matcherOut = []), temp, xml );
  1880. }
  1881. // Move matched elements from seed to results to keep them synchronized
  1882. i = matcherOut.length;
  1883. while ( i-- ) {
  1884. if ( (elem = matcherOut[i]) &&
  1885. (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
  1886. seed[temp] = !(results[temp] = elem);
  1887. }
  1888. }
  1889. }
  1890. // Add elements to results, through postFinder if defined
  1891. } else {
  1892. matcherOut = condense(
  1893. matcherOut === results ?
  1894. matcherOut.splice( preexisting, matcherOut.length ) :
  1895. matcherOut
  1896. );
  1897. if ( postFinder ) {
  1898. postFinder( null, results, matcherOut, xml );
  1899. } else {
  1900. push.apply( results, matcherOut );
  1901. }
  1902. }
  1903. });
  1904. }
  1905. function matcherFromTokens( tokens ) {
  1906. var checkContext, matcher, j,
  1907. len = tokens.length,
  1908. leadingRelative = Expr.relative[ tokens[0].type ],
  1909. implicitRelative = leadingRelative || Expr.relative[" "],
  1910. i = leadingRelative ? 1 : 0,
  1911. // The foundational matcher ensures that elements are reachable from top-level context(s)
  1912. matchContext = addCombinator( function( elem ) {
  1913. return elem === checkContext;
  1914. }, implicitRelative, true ),
  1915. matchAnyContext = addCombinator( function( elem ) {
  1916. return indexOf.call( checkContext, elem ) > -1;
  1917. }, implicitRelative, true ),
  1918. matchers = [ function( elem, context, xml ) {
  1919. return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
  1920. (checkContext = context).nodeType ?
  1921. matchContext( elem, context, xml ) :
  1922. matchAnyContext( elem, context, xml ) );
  1923. } ];
  1924. for ( ; i < len; i++ ) {
  1925. if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
  1926. matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
  1927. } else {
  1928. matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
  1929. // Return special upon seeing a positional matcher
  1930. if ( matcher[ expando ] ) {
  1931. // Find the next relative operator (if any) for proper handling
  1932. j = ++i;
  1933. for ( ; j < len; j++ ) {
  1934. if ( Expr.relative[ tokens[j].type ] ) {
  1935. break;
  1936. }
  1937. }
  1938. return setMatcher(
  1939. i > 1 && elementMatcher( matchers ),
  1940. i > 1 && toSelector(
  1941. // If the preceding token was a descendant combinator, insert an implicit any-element `*`
  1942. tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
  1943. ).replace( rtrim, "$1" ),
  1944. matcher,
  1945. i < j && matcherFromTokens( tokens.slice( i, j ) ),
  1946. j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
  1947. j < len && toSelector( tokens )
  1948. );
  1949. }
  1950. matchers.push( matcher );
  1951. }
  1952. }
  1953. return elementMatcher( matchers );
  1954. }
  1955. function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  1956. var bySet = setMatchers.length > 0,
  1957. byElement = elementMatchers.length > 0,
  1958. superMatcher = function( seed, context, xml, results, outermost ) {
  1959. var elem, j, matcher,
  1960. matchedCount = 0,
  1961. i = "0",
  1962. unmatched = seed && [],
  1963. setMatched = [],
  1964. contextBackup = outermostContext,
  1965. // We must always have either seed elements or outermost context
  1966. elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
  1967. // Use integer dirruns iff this is the outermost matcher
  1968. dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
  1969. len = elems.length;
  1970. if ( outermost ) {
  1971. outermostContext = context !== document && context;
  1972. }
  1973. // Add elements passing elementMatchers directly to results
  1974. // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
  1975. // Support: IE<9, Safari
  1976. // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
  1977. for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
  1978. if ( byElement && elem ) {
  1979. j = 0;
  1980. while ( (matcher = elementMatchers[j++]) ) {
  1981. if ( matcher( elem, context, xml ) ) {
  1982. results.push( elem );
  1983. break;
  1984. }
  1985. }
  1986. if ( outermost ) {
  1987. dirruns = dirrunsUnique;
  1988. }
  1989. }
  1990. // Track unmatched elements for set filters
  1991. if ( bySet ) {
  1992. // They will have gone through all possible matchers
  1993. if ( (elem = !matcher && elem) ) {
  1994. matchedCount--;
  1995. }
  1996. // Lengthen the array for every element, matched or not
  1997. if ( seed ) {
  1998. unmatched.push( elem );
  1999. }
  2000. }
  2001. }
  2002. // Apply set filters to unmatched elements
  2003. matchedCount += i;
  2004. if ( bySet && i !== matchedCount ) {
  2005. j = 0;
  2006. while ( (matcher = setMatchers[j++]) ) {
  2007. matcher( unmatched, setMatched, context, xml );
  2008. }
  2009. if ( seed ) {
  2010. // Reintegrate element matches to eliminate the need for sorting
  2011. if ( matchedCount > 0 ) {
  2012. while ( i-- ) {
  2013. if ( !(unmatched[i] || setMatched[i]) ) {
  2014. setMatched[i] = pop.call( results );
  2015. }
  2016. }
  2017. }
  2018. // Discard index placeholder values to get only actual matches
  2019. setMatched = condense( setMatched );
  2020. }
  2021. // Add matches to results
  2022. push.apply( results, setMatched );
  2023. // Seedless set matches succeeding multiple successful matchers stipulate sorting
  2024. if ( outermost && !seed && setMatched.length > 0 &&
  2025. ( matchedCount + setMatchers.length ) > 1 ) {
  2026. Sizzle.uniqueSort( results );
  2027. }
  2028. }
  2029. // Override manipulation of globals by nested matchers
  2030. if ( outermost ) {
  2031. dirruns = dirrunsUnique;
  2032. outermostContext = contextBackup;
  2033. }
  2034. return unmatched;
  2035. };
  2036. return bySet ?
  2037. markFunction( superMatcher ) :
  2038. superMatcher;
  2039. }
  2040. compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
  2041. var i,
  2042. setMatchers = [],
  2043. elementMatchers = [],
  2044. cached = compilerCache[ selector + " " ];
  2045. if ( !cached ) {
  2046. // Generate a function of recursive functions that can be used to check each element
  2047. if ( !match ) {
  2048. match = tokenize( selector );
  2049. }
  2050. i = match.length;
  2051. while ( i-- ) {
  2052. cached = matcherFromTokens( match[i] );
  2053. if ( cached[ expando ] ) {
  2054. setMatchers.push( cached );
  2055. } else {
  2056. elementMatchers.push( cached );
  2057. }
  2058. }
  2059. // Cache the compiled function
  2060. cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
  2061. // Save selector and tokenization
  2062. cached.selector = selector;
  2063. }
  2064. return cached;
  2065. };
  2066. /**
  2067. * A low-level selection function that works with Sizzle's compiled
  2068. * selector functions
  2069. * @param {String|Function} selector A selector or a pre-compiled
  2070. * selector function built with Sizzle.compile
  2071. * @param {Element} context
  2072. * @param {Array} [results]
  2073. * @param {Array} [seed] A set of elements to match against
  2074. */
  2075. select = Sizzle.select = function( selector, context, results, seed ) {
  2076. var i, tokens, token, type, find,
  2077. compiled = typeof selector === "function" && selector,
  2078. match = !seed && tokenize( (selector = compiled.selector || selector) );
  2079. results = results || [];
  2080. // Try to minimize operations if there is no seed and only one group
  2081. if ( match.length === 1 ) {
  2082. // Take a shortcut and set the context if the root selector is an ID
  2083. tokens = match[0] = match[0].slice( 0 );
  2084. if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
  2085. support.getById && context.nodeType === 9 && documentIsHTML &&
  2086. Expr.relative[ tokens[1].type ] ) {
  2087. context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
  2088. if ( !context ) {
  2089. return results;
  2090. // Precompiled matchers will still verify ancestry, so step up a level
  2091. } else if ( compiled ) {
  2092. context = context.parentNode;
  2093. }
  2094. selector = selector.slice( tokens.shift().value.length );
  2095. }
  2096. // Fetch a seed set for right-to-left matching
  2097. i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
  2098. while ( i-- ) {
  2099. token = tokens[i];
  2100. // Abort if we hit a combinator
  2101. if ( Expr.relative[ (type = token.type) ] ) {
  2102. break;
  2103. }
  2104. if ( (find = Expr.find[ type ]) ) {
  2105. // Search, expanding context for leading sibling combinators
  2106. if ( (seed = find(
  2107. token.matches[0].replace( runescape, funescape ),
  2108. rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
  2109. )) ) {
  2110. // If seed is empty or no tokens remain, we can return early
  2111. tokens.splice( i, 1 );
  2112. selector = seed.length && toSelector( tokens );
  2113. if ( !selector ) {
  2114. push.apply( results, seed );
  2115. return results;
  2116. }
  2117. break;
  2118. }
  2119. }
  2120. }
  2121. }
  2122. // Compile and execute a filtering function if one is not provided
  2123. // Provide `match` to avoid retokenization if we modified the selector above
  2124. ( compiled || compile( selector, match ) )(
  2125. seed,
  2126. context,
  2127. !documentIsHTML,
  2128. results,
  2129. rsibling.test( selector ) && testContext( context.parentNode ) || context
  2130. );
  2131. return results;
  2132. };
  2133. // One-time assignments
  2134. // Sort stability
  2135. support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
  2136. // Support: Chrome<14
  2137. // Always assume duplicates if they aren't passed to the comparison function
  2138. support.detectDuplicates = !!hasDuplicate;
  2139. // Initialize against the default document
  2140. setDocument();
  2141. // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
  2142. // Detached nodes confoundingly follow *each other*
  2143. support.sortDetached = assert(function( div1 ) {
  2144. // Should return 1, but returns 4 (following)
  2145. return div1.compareDocumentPosition( document.createElement("div") ) & 1;
  2146. });
  2147. // Support: IE<8
  2148. // Prevent attribute/property "interpolation"
  2149. // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
  2150. if ( !assert(function( div ) {
  2151. div.innerHTML = "<a href='#'></a>";
  2152. return div.firstChild.getAttribute("href") === "#" ;
  2153. }) ) {
  2154. addHandle( "type|href|height|width", function( elem, name, isXML ) {
  2155. if ( !isXML ) {
  2156. return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
  2157. }
  2158. });
  2159. }
  2160. // Support: IE<9
  2161. // Use defaultValue in place of getAttribute("value")
  2162. if ( !support.attributes || !assert(function( div ) {
  2163. div.innerHTML = "<input/>";
  2164. div.firstChild.setAttribute( "value", "" );
  2165. return div.firstChild.getAttribute( "value" ) === "";
  2166. }) ) {
  2167. addHandle( "value", function( elem, name, isXML ) {
  2168. if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
  2169. return elem.defaultValue;
  2170. }
  2171. });
  2172. }
  2173. // Support: IE<9
  2174. // Use getAttributeNode to fetch booleans when getAttribute lies
  2175. if ( !assert(function( div ) {
  2176. return div.getAttribute("disabled") == null;
  2177. }) ) {
  2178. addHandle( booleans, function( elem, name, isXML ) {
  2179. var val;
  2180. if ( !isXML ) {
  2181. return elem[ name ] === true ? name.toLowerCase() :
  2182. (val = elem.getAttributeNode( name )) && val.specified ?
  2183. val.value :
  2184. null;
  2185. }
  2186. });
  2187. }
  2188. return Sizzle;
  2189. })( window );
  2190. jQuery.find = Sizzle;
  2191. jQuery.expr = Sizzle.selectors;
  2192. jQuery.expr[":"] = jQuery.expr.pseudos;
  2193. jQuery.unique = Sizzle.uniqueSort;
  2194. jQuery.text = Sizzle.getText;
  2195. jQuery.isXMLDoc = Sizzle.isXML;
  2196. jQuery.contains = Sizzle.contains;
  2197. var rneedsContext = jQuery.expr.match.needsContext;
  2198. var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
  2199. var risSimple = /^.[^:#\[\.,]*$/;
  2200. // Implement the identical functionality for filter and not
  2201. function winnow( elements, qualifier, not ) {
  2202. if ( jQuery.isFunction( qualifier ) ) {
  2203. return jQuery.grep( elements, function( elem, i ) {
  2204. /* jshint -W018 */
  2205. return !!qualifier.call( elem, i, elem ) !== not;
  2206. });
  2207. }
  2208. if ( qualifier.nodeType ) {
  2209. return jQuery.grep( elements, function( elem ) {
  2210. return ( elem === qualifier ) !== not;
  2211. });
  2212. }
  2213. if ( typeof qualifier === "string" ) {
  2214. if ( risSimple.test( qualifier ) ) {
  2215. return jQuery.filter( qualifier, elements, not );
  2216. }
  2217. qualifier = jQuery.filter( qualifier, elements );
  2218. }
  2219. return jQuery.grep( elements, function( elem ) {
  2220. return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
  2221. });
  2222. }
  2223. jQuery.filter = function( expr, elems, not ) {
  2224. var elem = elems[ 0 ];
  2225. if ( not ) {
  2226. expr = ":not(" + expr + ")";
  2227. }
  2228. return elems.length === 1 && elem.nodeType === 1 ?
  2229. jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
  2230. jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
  2231. return elem.nodeType === 1;
  2232. }));
  2233. };
  2234. jQuery.fn.extend({
  2235. find: function( selector ) {
  2236. var i,
  2237. len = this.length,
  2238. ret = [],
  2239. self = this;
  2240. if ( typeof selector !== "string" ) {
  2241. return this.pushStack( jQuery( selector ).filter(function() {
  2242. for ( i = 0; i < len; i++ ) {
  2243. if ( jQuery.contains( self[ i ], this ) ) {
  2244. return true;
  2245. }
  2246. }
  2247. }) );
  2248. }
  2249. for ( i = 0; i < len; i++ ) {
  2250. jQuery.find( selector, self[ i ], ret );
  2251. }
  2252. // Needed because $( selector, context ) becomes $( context ).find( selector )
  2253. ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
  2254. ret.selector = this.selector ? this.selector + " " + selector : selector;
  2255. return ret;
  2256. },
  2257. filter: function( selector ) {
  2258. return this.pushStack( winnow(this, selector || [], false) );
  2259. },
  2260. not: function( selector ) {
  2261. return this.pushStack( winnow(this, selector || [], true) );
  2262. },
  2263. is: function( selector ) {
  2264. return !!winnow(
  2265. this,
  2266. // If this is a positional/relative selector, check membership in the returned set
  2267. // so $("p:first").is("p:last") won't return true for a doc with two "p".
  2268. typeof selector === "string" && rneedsContext.test( selector ) ?
  2269. jQuery( selector ) :
  2270. selector || [],
  2271. false
  2272. ).length;
  2273. }
  2274. });
  2275. // Initialize a jQuery object
  2276. // A central reference to the root jQuery(document)
  2277. var rootjQuery,
  2278. // A simple way to check for HTML strings
  2279. // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
  2280. // Strict HTML recognition (#11290: must start with <)
  2281. rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
  2282. init = jQuery.fn.init = function( selector, context ) {
  2283. var match, elem;
  2284. // HANDLE: $(""), $(null), $(undefined), $(false)
  2285. if ( !selector ) {
  2286. return this;
  2287. }
  2288. // Handle HTML strings
  2289. if ( typeof selector === "string" ) {
  2290. if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
  2291. // Assume that strings that start and end with <> are HTML and skip the regex check
  2292. match = [ null, selector, null ];
  2293. } else {
  2294. match = rquickExpr.exec( selector );
  2295. }
  2296. // Match html or make sure no context is specified for #id
  2297. if ( match && (match[1] || !context) ) {
  2298. // HANDLE: $(html) -> $(array)
  2299. if ( match[1] ) {
  2300. context = context instanceof jQuery ? context[0] : context;
  2301. // scripts is true for back-compat
  2302. // Intentionally let the error be thrown if parseHTML is not present
  2303. jQuery.merge( this, jQuery.parseHTML(
  2304. match[1],
  2305. context && context.nodeType ? context.ownerDocument || context : document,
  2306. true
  2307. ) );
  2308. // HANDLE: $(html, props)
  2309. if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
  2310. for ( match in context ) {
  2311. // Properties of context are called as methods if possible
  2312. if ( jQuery.isFunction( this[ match ] ) ) {
  2313. this[ match ]( context[ match ] );
  2314. // ...and otherwise set as attributes
  2315. } else {
  2316. this.attr( match, context[ match ] );
  2317. }
  2318. }
  2319. }
  2320. return this;
  2321. // HANDLE: $(#id)
  2322. } else {
  2323. elem = document.getElementById( match[2] );
  2324. // Check parentNode to catch when Blackberry 4.6 returns
  2325. // nodes that are no longer in the document #6963
  2326. if ( elem && elem.parentNode ) {
  2327. // Inject the element directly into the jQuery object
  2328. this.length = 1;
  2329. this[0] = elem;
  2330. }
  2331. this.context = document;
  2332. this.selector = selector;
  2333. return this;
  2334. }
  2335. // HANDLE: $(expr, $(...))
  2336. } else if ( !context || context.jquery ) {
  2337. return ( context || rootjQuery ).find( selector );
  2338. // HANDLE: $(expr, context)
  2339. // (which is just equivalent to: $(context).find(expr)
  2340. } else {
  2341. return this.constructor( context ).find( selector );
  2342. }
  2343. // HANDLE: $(DOMElement)
  2344. } else if ( selector.nodeType ) {
  2345. this.context = this[0] = selector;
  2346. this.length = 1;
  2347. return this;
  2348. // HANDLE: $(function)
  2349. // Shortcut for document ready
  2350. } else if ( jQuery.isFunction( selector ) ) {
  2351. return typeof rootjQuery.ready !== "undefined" ?
  2352. rootjQuery.ready( selector ) :
  2353. // Execute immediately if ready is not present
  2354. selector( jQuery );
  2355. }
  2356. if ( selector.selector !== undefined ) {
  2357. this.selector = selector.selector;
  2358. this.context = selector.context;
  2359. }
  2360. return jQuery.makeArray( selector, this );
  2361. };
  2362. // Give the init function the jQuery prototype for later instantiation
  2363. init.prototype = jQuery.fn;
  2364. // Initialize central reference
  2365. rootjQuery = jQuery( document );
  2366. var rparentsprev = /^(?:parents|prev(?:Until|All))/,
  2367. // methods guaranteed to produce a unique set when starting from a unique set
  2368. guaranteedUnique = {
  2369. children: true,
  2370. contents: true,
  2371. next: true,
  2372. prev: true
  2373. };
  2374. jQuery.extend({
  2375. dir: function( elem, dir, until ) {
  2376. var matched = [],
  2377. truncate = until !== undefined;
  2378. while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
  2379. if ( elem.nodeType === 1 ) {
  2380. if ( truncate && jQuery( elem ).is( until ) ) {
  2381. break;
  2382. }
  2383. matched.push( elem );
  2384. }
  2385. }
  2386. return matched;
  2387. },
  2388. sibling: function( n, elem ) {
  2389. var matched = [];
  2390. for ( ; n; n = n.nextSibling ) {
  2391. if ( n.nodeType === 1 && n !== elem ) {
  2392. matched.push( n );
  2393. }
  2394. }
  2395. return matched;
  2396. }
  2397. });
  2398. jQuery.fn.extend({
  2399. has: function( target ) {
  2400. var targets = jQuery( target, this ),
  2401. l = targets.length;
  2402. return this.filter(function() {
  2403. var i = 0;
  2404. for ( ; i < l; i++ ) {
  2405. if ( jQuery.contains( this, targets[i] ) ) {
  2406. return true;
  2407. }
  2408. }
  2409. });
  2410. },
  2411. closest: function( selectors, context ) {
  2412. var cur,
  2413. i = 0,
  2414. l = this.length,
  2415. matched = [],
  2416. pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
  2417. jQuery( selectors, context || this.context ) :
  2418. 0;
  2419. for ( ; i < l; i++ ) {
  2420. for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
  2421. // Always skip document fragments
  2422. if ( cur.nodeType < 11 && (pos ?
  2423. pos.index(cur) > -1 :
  2424. // Don't pass non-elements to Sizzle
  2425. cur.nodeType === 1 &&
  2426. jQuery.find.matchesSelector(cur, selectors)) ) {
  2427. matched.push( cur );
  2428. break;
  2429. }
  2430. }
  2431. }
  2432. return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
  2433. },
  2434. // Determine the position of an element within
  2435. // the matched set of elements
  2436. index: function( elem ) {
  2437. // No argument, return index in parent
  2438. if ( !elem ) {
  2439. return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
  2440. }
  2441. // index in selector
  2442. if ( typeof elem === "string" ) {
  2443. return indexOf.call( jQuery( elem ), this[ 0 ] );
  2444. }
  2445. // Locate the position of the desired element
  2446. return indexOf.call( this,
  2447. // If it receives a jQuery object, the first element is used
  2448. elem.jquery ? elem[ 0 ] : elem
  2449. );
  2450. },
  2451. add: function( selector, context ) {
  2452. return this.pushStack(
  2453. jQuery.unique(
  2454. jQuery.merge( this.get(), jQuery( selector, context ) )
  2455. )
  2456. );
  2457. },
  2458. addBack: function( selector ) {
  2459. return this.add( selector == null ?
  2460. this.prevObject : this.prevObject.filter(selector)
  2461. );
  2462. }
  2463. });
  2464. function sibling( cur, dir ) {
  2465. while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
  2466. return cur;
  2467. }
  2468. jQuery.each({
  2469. parent: function( elem ) {
  2470. var parent = elem.parentNode;
  2471. return parent && parent.nodeType !== 11 ? parent : null;
  2472. },
  2473. parents: function( elem ) {
  2474. return jQuery.dir( elem, "parentNode" );
  2475. },
  2476. parentsUntil: function( elem, i, until ) {
  2477. return jQuery.dir( elem, "parentNode", until );
  2478. },
  2479. next: function( elem ) {
  2480. return sibling( elem, "nextSibling" );
  2481. },
  2482. prev: function( elem ) {
  2483. return sibling( elem, "previousSibling" );
  2484. },
  2485. nextAll: function( elem ) {
  2486. return jQuery.dir( elem, "nextSibling" );
  2487. },
  2488. prevAll: function( elem ) {
  2489. return jQuery.dir( elem, "previousSibling" );
  2490. },
  2491. nextUntil: function( elem, i, until ) {
  2492. return jQuery.dir( elem, "nextSibling", until );
  2493. },
  2494. prevUntil: function( elem, i, until ) {
  2495. return jQuery.dir( elem, "previousSibling", until );
  2496. },
  2497. siblings: function( elem ) {
  2498. return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
  2499. },
  2500. children: function( elem ) {
  2501. return jQuery.sibling( elem.firstChild );
  2502. },
  2503. contents: function( elem ) {
  2504. return elem.contentDocument || jQuery.merge( [], elem.childNodes );
  2505. }
  2506. }, function( name, fn ) {
  2507. jQuery.fn[ name ] = function( until, selector ) {
  2508. var matched = jQuery.map( this, fn, until );
  2509. if ( name.slice( -5 ) !== "Until" ) {
  2510. selector = until;
  2511. }
  2512. if ( selector && typeof selector === "string" ) {
  2513. matched = jQuery.filter( selector, matched );
  2514. }
  2515. if ( this.length > 1 ) {
  2516. // Remove duplicates
  2517. if ( !guaranteedUnique[ name ] ) {
  2518. jQuery.unique( matched );
  2519. }
  2520. // Reverse order for parents* and prev-derivatives
  2521. if ( rparentsprev.test( name ) ) {
  2522. matched.reverse();
  2523. }
  2524. }
  2525. return this.pushStack( matched );
  2526. };
  2527. });
  2528. var rnotwhite = (/\S+/g);
  2529. // String to Object options format cache
  2530. var optionsCache = {};
  2531. // Convert String-formatted options into Object-formatted ones and store in cache
  2532. function createOptions( options ) {
  2533. var object = optionsCache[ options ] = {};
  2534. jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
  2535. object[ flag ] = true;
  2536. });
  2537. return object;
  2538. }
  2539. /*
  2540. * Create a callback list using the following parameters:
  2541. *
  2542. * options: an optional list of space-separated options that will change how
  2543. * the callback list behaves or a more traditional option object
  2544. *
  2545. * By default a callback list will act like an event callback list and can be
  2546. * "fired" multiple times.
  2547. *
  2548. * Possible options:
  2549. *
  2550. * once: will ensure the callback list can only be fired once (like a Deferred)
  2551. *
  2552. * memory: will keep track of previous values and will call any callback added
  2553. * after the list has been fired right away with the latest "memorized"
  2554. * values (like a Deferred)
  2555. *
  2556. * unique: will ensure a callback can only be added once (no duplicate in the list)
  2557. *
  2558. * stopOnFalse: interrupt callings when a callback returns false
  2559. *
  2560. */
  2561. jQuery.Callbacks = function( options ) {
  2562. // Convert options from String-formatted to Object-formatted if needed
  2563. // (we check in cache first)
  2564. options = typeof options === "string" ?
  2565. ( optionsCache[ options ] || createOptions( options ) ) :
  2566. jQuery.extend( {}, options );
  2567. var // Last fire value (for non-forgettable lists)
  2568. memory,
  2569. // Flag to know if list was already fired
  2570. fired,
  2571. // Flag to know if list is currently firing
  2572. firing,
  2573. // First callback to fire (used internally by add and fireWith)
  2574. firingStart,
  2575. // End of the loop when firing
  2576. firingLength,
  2577. // Index of currently firing callback (modified by remove if needed)
  2578. firingIndex,
  2579. // Actual callback list
  2580. list = [],
  2581. // Stack of fire calls for repeatable lists
  2582. stack = !options.once && [],
  2583. // Fire callbacks
  2584. fire = function( data ) {
  2585. memory = options.memory && data;
  2586. fired = true;
  2587. firingIndex = firingStart || 0;
  2588. firingStart = 0;
  2589. firingLength = list.length;
  2590. firing = true;
  2591. for ( ; list && firingIndex < firingLength; firingIndex++ ) {
  2592. if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
  2593. memory = false; // To prevent further calls using add
  2594. break;
  2595. }
  2596. }
  2597. firing = false;
  2598. if ( list ) {
  2599. if ( stack ) {
  2600. if ( stack.length ) {
  2601. fire( stack.shift() );
  2602. }
  2603. } else if ( memory ) {
  2604. list = [];
  2605. } else {
  2606. self.disable();
  2607. }
  2608. }
  2609. },
  2610. // Actual Callbacks object
  2611. self = {
  2612. // Add a callback or a collection of callbacks to the list
  2613. add: function() {
  2614. if ( list ) {
  2615. // First, we save the current length
  2616. var start = list.length;
  2617. (function add( args ) {
  2618. jQuery.each( args, function( _, arg ) {
  2619. var type = jQuery.type( arg );
  2620. if ( type === "function" ) {
  2621. if ( !options.unique || !self.has( arg ) ) {
  2622. list.push( arg );
  2623. }
  2624. } else if ( arg && arg.length && type !== "string" ) {
  2625. // Inspect recursively
  2626. add( arg );
  2627. }
  2628. });
  2629. })( arguments );
  2630. // Do we need to add the callbacks to the
  2631. // current firing batch?
  2632. if ( firing ) {
  2633. firingLength = list.length;
  2634. // With memory, if we're not firing then
  2635. // we should call right away
  2636. } else if ( memory ) {
  2637. firingStart = start;
  2638. fire( memory );
  2639. }
  2640. }
  2641. return this;
  2642. },
  2643. // Remove a callback from the list
  2644. remove: function() {
  2645. if ( list ) {
  2646. jQuery.each( arguments, function( _, arg ) {
  2647. var index;
  2648. while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
  2649. list.splice( index, 1 );
  2650. // Handle firing indexes
  2651. if ( firing ) {
  2652. if ( index <= firingLength ) {
  2653. firingLength--;
  2654. }
  2655. if ( index <= firingIndex ) {
  2656. firingIndex--;
  2657. }
  2658. }
  2659. }
  2660. });
  2661. }
  2662. return this;
  2663. },
  2664. // Check if a given callback is in the list.
  2665. // If no argument is given, return whether or not list has callbacks attached.
  2666. has: function( fn ) {
  2667. return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
  2668. },
  2669. // Remove all callbacks from the list
  2670. empty: function() {
  2671. list = [];
  2672. firingLength = 0;
  2673. return this;
  2674. },
  2675. // Have the list do nothing anymore
  2676. disable: function() {
  2677. list = stack = memory = undefined;
  2678. return this;
  2679. },
  2680. // Is it disabled?
  2681. disabled: function() {
  2682. return !list;
  2683. },
  2684. // Lock the list in its current state
  2685. lock: function() {
  2686. stack = undefined;
  2687. if ( !memory ) {
  2688. self.disable();
  2689. }
  2690. return this;
  2691. },
  2692. // Is it locked?
  2693. locked: function() {
  2694. return !stack;
  2695. },
  2696. // Call all callbacks with the given context and arguments
  2697. fireWith: function( context, args ) {
  2698. if ( list && ( !fired || stack ) ) {
  2699. args = args || [];
  2700. args = [ context, args.slice ? args.slice() : args ];
  2701. if ( firing ) {
  2702. stack.push( args );
  2703. } else {
  2704. fire( args );
  2705. }
  2706. }
  2707. return this;
  2708. },
  2709. // Call all the callbacks with the given arguments
  2710. fire: function() {
  2711. self.fireWith( this, arguments );
  2712. return this;
  2713. },
  2714. // To know if the callbacks have already been called at least once
  2715. fired: function() {
  2716. return !!fired;
  2717. }
  2718. };
  2719. return self;
  2720. };
  2721. jQuery.extend({
  2722. Deferred: function( func ) {
  2723. var tuples = [
  2724. // action, add listener, listener list, final state
  2725. [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
  2726. [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
  2727. [ "notify", "progress", jQuery.Callbacks("memory") ]
  2728. ],
  2729. state = "pending",
  2730. promise = {
  2731. state: function() {
  2732. return state;
  2733. },
  2734. always: function() {
  2735. deferred.done( arguments ).fail( arguments );
  2736. return this;
  2737. },
  2738. then: function( /* fnDone, fnFail, fnProgress */ ) {
  2739. var fns = arguments;
  2740. return jQuery.Deferred(function( newDefer ) {
  2741. jQuery.each( tuples, function( i, tuple ) {
  2742. var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
  2743. // deferred[ done | fail | progress ] for forwarding actions to newDefer
  2744. deferred[ tuple[1] ](function() {
  2745. var returned = fn && fn.apply( this, arguments );
  2746. if ( returned && jQuery.isFunction( returned.promise ) ) {
  2747. returned.promise()
  2748. .done( newDefer.resolve )
  2749. .fail( newDefer.reject )
  2750. .progress( newDefer.notify );
  2751. } else {
  2752. newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
  2753. }
  2754. });
  2755. });
  2756. fns = null;
  2757. }).promise();
  2758. },
  2759. // Get a promise for this deferred
  2760. // If obj is provided, the promise aspect is added to the object
  2761. promise: function( obj ) {
  2762. return obj != null ? jQuery.extend( obj, promise ) : promise;
  2763. }
  2764. },
  2765. deferred = {};
  2766. // Keep pipe for back-compat
  2767. promise.pipe = promise.then;
  2768. // Add list-specific methods
  2769. jQuery.each( tuples, function( i, tuple ) {
  2770. var list = tuple[ 2 ],
  2771. stateString = tuple[ 3 ];
  2772. // promise[ done | fail | progress ] = list.add
  2773. promise[ tuple[1] ] = list.add;
  2774. // Handle state
  2775. if ( stateString ) {
  2776. list.add(function() {
  2777. // state = [ resolved | rejected ]
  2778. state = stateString;
  2779. // [ reject_list | resolve_list ].disable; progress_list.lock
  2780. }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
  2781. }
  2782. // deferred[ resolve | reject | notify ]
  2783. deferred[ tuple[0] ] = function() {
  2784. deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
  2785. return this;
  2786. };
  2787. deferred[ tuple[0] + "With" ] = list.fireWith;
  2788. });
  2789. // Make the deferred a promise
  2790. promise.promise( deferred );
  2791. // Call given func if any
  2792. if ( func ) {
  2793. func.call( deferred, deferred );
  2794. }
  2795. // All done!
  2796. return deferred;
  2797. },
  2798. // Deferred helper
  2799. when: function( subordinate /* , ..., subordinateN */ ) {
  2800. var i = 0,
  2801. resolveValues = slice.call( arguments ),
  2802. length = resolveValues.length,
  2803. // the count of uncompleted subordinates
  2804. remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
  2805. // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
  2806. deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
  2807. // Update function for both resolve and progress values
  2808. updateFunc = function( i, contexts, values ) {
  2809. return function( value ) {
  2810. contexts[ i ] = this;
  2811. values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
  2812. if ( values === progressValues ) {
  2813. deferred.notifyWith( contexts, values );
  2814. } else if ( !( --remaining ) ) {
  2815. deferred.resolveWith( contexts, values );
  2816. }
  2817. };
  2818. },
  2819. progressValues, progressContexts, resolveContexts;
  2820. // add listeners to Deferred subordinates; treat others as resolved
  2821. if ( length > 1 ) {
  2822. progressValues = new Array( length );
  2823. progressContexts = new Array( length );
  2824. resolveContexts = new Array( length );
  2825. for ( ; i < length; i++ ) {
  2826. if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
  2827. resolveValues[ i ].promise()
  2828. .done( updateFunc( i, resolveContexts, resolveValues ) )
  2829. .fail( deferred.reject )
  2830. .progress( updateFunc( i, progressContexts, progressValues ) );
  2831. } else {
  2832. --remaining;
  2833. }
  2834. }
  2835. }
  2836. // if we're not waiting on anything, resolve the master
  2837. if ( !remaining ) {
  2838. deferred.resolveWith( resolveContexts, resolveValues );
  2839. }
  2840. return deferred.promise();
  2841. }
  2842. });
  2843. // The deferred used on DOM ready
  2844. var readyList;
  2845. jQuery.fn.ready = function( fn ) {
  2846. // Add the callback
  2847. jQuery.ready.promise().done( fn );
  2848. return this;
  2849. };
  2850. jQuery.extend({
  2851. // Is the DOM ready to be used? Set to true once it occurs.
  2852. isReady: false,
  2853. // A counter to track how many items to wait for before
  2854. // the ready event fires. See #6781
  2855. readyWait: 1,
  2856. // Hold (or release) the ready event
  2857. holdReady: function( hold ) {
  2858. if ( hold ) {
  2859. jQuery.readyWait++;
  2860. } else {
  2861. jQuery.ready( true );
  2862. }
  2863. },
  2864. // Handle when the DOM is ready
  2865. ready: function( wait ) {
  2866. // Abort if there are pending holds or we're already ready
  2867. if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
  2868. return;
  2869. }
  2870. // Remember that the DOM is ready
  2871. jQuery.isReady = true;
  2872. // If a normal DOM Ready event fired, decrement, and wait if need be
  2873. if ( wait !== true && --jQuery.readyWait > 0 ) {
  2874. return;
  2875. }
  2876. // If there are functions bound, to execute
  2877. readyList.resolveWith( document, [ jQuery ] );
  2878. // Trigger any bound ready events
  2879. if ( jQuery.fn.triggerHandler ) {
  2880. jQuery( document ).triggerHandler( "ready" );
  2881. jQuery( document ).off( "ready" );
  2882. }
  2883. }
  2884. });
  2885. /**
  2886. * The ready event handler and self cleanup method
  2887. */
  2888. function completed() {
  2889. document.removeEventListener( "DOMContentLoaded", completed, false );
  2890. window.removeEventListener( "load", completed, false );
  2891. jQuery.ready();
  2892. }
  2893. jQuery.ready.promise = function( obj ) {
  2894. if ( !readyList ) {
  2895. readyList = jQuery.Deferred();
  2896. // Catch cases where $(document).ready() is called after the browser event has already occurred.
  2897. // we once tried to use readyState "interactive" here, but it caused issues like the one
  2898. // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
  2899. if ( document.readyState === "complete" ) {
  2900. // Handle it asynchronously to allow scripts the opportunity to delay ready
  2901. setTimeout( jQuery.ready );
  2902. } else {
  2903. // Use the handy event callback
  2904. document.addEventListener( "DOMContentLoaded", completed, false );
  2905. // A fallback to window.onload, that will always work
  2906. window.addEventListener( "load", completed, false );
  2907. }
  2908. }
  2909. return readyList.promise( obj );
  2910. };
  2911. // Kick off the DOM ready check even if the user does not
  2912. jQuery.ready.promise();
  2913. // Multifunctional method to get and set values of a collection
  2914. // The value/s can optionally be executed if it's a function
  2915. var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
  2916. var i = 0,
  2917. len = elems.length,
  2918. bulk = key == null;
  2919. // Sets many values
  2920. if ( jQuery.type( key ) === "object" ) {
  2921. chainable = true;
  2922. for ( i in key ) {
  2923. jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
  2924. }
  2925. // Sets one value
  2926. } else if ( value !== undefined ) {
  2927. chainable = true;
  2928. if ( !jQuery.isFunction( value ) ) {
  2929. raw = true;
  2930. }
  2931. if ( bulk ) {
  2932. // Bulk operations run against the entire set
  2933. if ( raw ) {
  2934. fn.call( elems, value );
  2935. fn = null;
  2936. // ...except when executing function values
  2937. } else {
  2938. bulk = fn;
  2939. fn = function( elem, key, value ) {
  2940. return bulk.call( jQuery( elem ), value );
  2941. };
  2942. }
  2943. }
  2944. if ( fn ) {
  2945. for ( ; i < len; i++ ) {
  2946. fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
  2947. }
  2948. }
  2949. }
  2950. return chainable ?
  2951. elems :
  2952. // Gets
  2953. bulk ?
  2954. fn.call( elems ) :
  2955. len ? fn( elems[0], key ) : emptyGet;
  2956. };
  2957. /**
  2958. * Determines whether an object can have data
  2959. */
  2960. jQuery.acceptData = function( owner ) {
  2961. // Accepts only:
  2962. // - Node
  2963. // - Node.ELEMENT_NODE
  2964. // - Node.DOCUMENT_NODE
  2965. // - Object
  2966. // - Any
  2967. /* jshint -W018 */
  2968. return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
  2969. };
  2970. function Data() {
  2971. // Support: Android < 4,
  2972. // Old WebKit does not have Object.preventExtensions/freeze method,
  2973. // return new empty object instead with no [[set]] accessor
  2974. Object.defineProperty( this.cache = {}, 0, {
  2975. get: function() {
  2976. return {};
  2977. }
  2978. });
  2979. this.expando = jQuery.expando + Math.random();
  2980. }
  2981. Data.uid = 1;
  2982. Data.accepts = jQuery.acceptData;
  2983. Data.prototype = {
  2984. key: function( owner ) {
  2985. // We can accept data for non-element nodes in modern browsers,
  2986. // but we should not, see #8335.
  2987. // Always return the key for a frozen object.
  2988. if ( !Data.accepts( owner ) ) {
  2989. return 0;
  2990. }
  2991. var descriptor = {},
  2992. // Check if the owner object already has a cache key
  2993. unlock = owner[ this.expando ];
  2994. // If not, create one
  2995. if ( !unlock ) {
  2996. unlock = Data.uid++;
  2997. // Secure it in a non-enumerable, non-writable property
  2998. try {
  2999. descriptor[ this.expando ] = { value: unlock };
  3000. Object.defineProperties( owner, descriptor );
  3001. // Support: Android < 4
  3002. // Fallback to a less secure definition
  3003. } catch ( e ) {
  3004. descriptor[ this.expando ] = unlock;
  3005. jQuery.extend( owner, descriptor );
  3006. }
  3007. }
  3008. // Ensure the cache object
  3009. if ( !this.cache[ unlock ] ) {
  3010. this.cache[ unlock ] = {};
  3011. }
  3012. return unlock;
  3013. },
  3014. set: function( owner, data, value ) {
  3015. var prop,
  3016. // There may be an unlock assigned to this node,
  3017. // if there is no entry for this "owner", create one inline
  3018. // and set the unlock as though an owner entry had always existed
  3019. unlock = this.key( owner ),
  3020. cache = this.cache[ unlock ];
  3021. // Handle: [ owner, key, value ] args
  3022. if ( typeof data === "string" ) {
  3023. cache[ data ] = value;
  3024. // Handle: [ owner, { properties } ] args
  3025. } else {
  3026. // Fresh assignments by object are shallow copied
  3027. if ( jQuery.isEmptyObject( cache ) ) {
  3028. jQuery.extend( this.cache[ unlock ], data );
  3029. // Otherwise, copy the properties one-by-one to the cache object
  3030. } else {
  3031. for ( prop in data ) {
  3032. cache[ prop ] = data[ prop ];
  3033. }
  3034. }
  3035. }
  3036. return cache;
  3037. },
  3038. get: function( owner, key ) {
  3039. // Either a valid cache is found, or will be created.
  3040. // New caches will be created and the unlock returned,
  3041. // allowing direct access to the newly created
  3042. // empty data object. A valid owner object must be provided.
  3043. var cache = this.cache[ this.key( owner ) ];
  3044. return key === undefined ?
  3045. cache : cache[ key ];
  3046. },
  3047. access: function( owner, key, value ) {
  3048. var stored;
  3049. // In cases where either:
  3050. //
  3051. // 1. No key was specified
  3052. // 2. A string key was specified, but no value provided
  3053. //
  3054. // Take the "read" path and allow the get method to determine
  3055. // which value to return, respectively either:
  3056. //
  3057. // 1. The entire cache object
  3058. // 2. The data stored at the key
  3059. //
  3060. if ( key === undefined ||
  3061. ((key && typeof key === "string") && value === undefined) ) {
  3062. stored = this.get( owner, key );
  3063. return stored !== undefined ?
  3064. stored : this.get( owner, jQuery.camelCase(key) );
  3065. }
  3066. // [*]When the key is not a string, or both a key and value
  3067. // are specified, set or extend (existing objects) with either:
  3068. //
  3069. // 1. An object of properties
  3070. // 2. A key and value
  3071. //
  3072. this.set( owner, key, value );
  3073. // Since the "set" path can have two possible entry points
  3074. // return the expected data based on which path was taken[*]
  3075. return value !== undefined ? value : key;
  3076. },
  3077. remove: function( owner, key ) {
  3078. var i, name, camel,
  3079. unlock = this.key( owner ),
  3080. cache = this.cache[ unlock ];
  3081. if ( key === undefined ) {
  3082. this.cache[ unlock ] = {};
  3083. } else {
  3084. // Support array or space separated string of keys
  3085. if ( jQuery.isArray( key ) ) {
  3086. // If "name" is an array of keys...
  3087. // When data is initially created, via ("key", "val") signature,
  3088. // keys will be converted to camelCase.
  3089. // Since there is no way to tell _how_ a key was added, remove
  3090. // both plain key and camelCase key. #12786
  3091. // This will only penalize the array argument path.
  3092. name = key.concat( key.map( jQuery.camelCase ) );
  3093. } else {
  3094. camel = jQuery.camelCase( key );
  3095. // Try the string as a key before any manipulation
  3096. if ( key in cache ) {
  3097. name = [ key, camel ];
  3098. } else {
  3099. // If a key with the spaces exists, use it.
  3100. // Otherwise, create an array by matching non-whitespace
  3101. name = camel;
  3102. name = name in cache ?
  3103. [ name ] : ( name.match( rnotwhite ) || [] );
  3104. }
  3105. }
  3106. i = name.length;
  3107. while ( i-- ) {
  3108. delete cache[ name[ i ] ];
  3109. }
  3110. }
  3111. },
  3112. hasData: function( owner ) {
  3113. return !jQuery.isEmptyObject(
  3114. this.cache[ owner[ this.expando ] ] || {}
  3115. );
  3116. },
  3117. discard: function( owner ) {
  3118. if ( owner[ this.expando ] ) {
  3119. delete this.cache[ owner[ this.expando ] ];
  3120. }
  3121. }
  3122. };
  3123. var data_priv = new Data();
  3124. var data_user = new Data();
  3125. /*
  3126. Implementation Summary
  3127. 1. Enforce API surface and semantic compatibility with 1.9.x branch
  3128. 2. Improve the module's maintainability by reducing the storage
  3129. paths to a single mechanism.
  3130. 3. Use the same single mechanism to support "private" and "user" data.
  3131. 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
  3132. 5. Avoid exposing implementation details on user objects (eg. expando properties)
  3133. 6. Provide a clear path for implementation upgrade to WeakMap in 2014
  3134. */
  3135. var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
  3136. rmultiDash = /([A-Z])/g;
  3137. function dataAttr( elem, key, data ) {
  3138. var name;
  3139. // If nothing was found internally, try to fetch any
  3140. // data from the HTML5 data-* attribute
  3141. if ( data === undefined && elem.nodeType === 1 ) {
  3142. name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
  3143. data = elem.getAttribute( name );
  3144. if ( typeof data === "string" ) {
  3145. try {
  3146. data = data === "true" ? true :
  3147. data === "false" ? false :
  3148. data === "null" ? null :
  3149. // Only convert to a number if it doesn't change the string
  3150. +data + "" === data ? +data :
  3151. rbrace.test( data ) ? jQuery.parseJSON( data ) :
  3152. data;
  3153. } catch( e ) {}
  3154. // Make sure we set the data so it isn't changed later
  3155. data_user.set( elem, key, data );
  3156. } else {
  3157. data = undefined;
  3158. }
  3159. }
  3160. return data;
  3161. }
  3162. jQuery.extend({
  3163. hasData: function( elem ) {
  3164. return data_user.hasData( elem ) || data_priv.hasData( elem );
  3165. },
  3166. data: function( elem, name, data ) {
  3167. return data_user.access( elem, name, data );
  3168. },
  3169. removeData: function( elem, name ) {
  3170. data_user.remove( elem, name );
  3171. },
  3172. // TODO: Now that all calls to _data and _removeData have been replaced
  3173. // with direct calls to data_priv methods, these can be deprecated.
  3174. _data: function( elem, name, data ) {
  3175. return data_priv.access( elem, name, data );
  3176. },
  3177. _removeData: function( elem, name ) {
  3178. data_priv.remove( elem, name );
  3179. }
  3180. });
  3181. jQuery.fn.extend({
  3182. data: function( key, value ) {
  3183. var i, name, data,
  3184. elem = this[ 0 ],
  3185. attrs = elem && elem.attributes;
  3186. // Gets all values
  3187. if ( key === undefined ) {
  3188. if ( this.length ) {
  3189. data = data_user.get( elem );
  3190. if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
  3191. i = attrs.length;
  3192. while ( i-- ) {
  3193. // Support: IE11+
  3194. // The attrs elements can be null (#14894)
  3195. if ( attrs[ i ] ) {
  3196. name = attrs[ i ].name;
  3197. if ( name.indexOf( "data-" ) === 0 ) {
  3198. name = jQuery.camelCase( name.slice(5) );
  3199. dataAttr( elem, name, data[ name ] );
  3200. }
  3201. }
  3202. }
  3203. data_priv.set( elem, "hasDataAttrs", true );
  3204. }
  3205. }
  3206. return data;
  3207. }
  3208. // Sets multiple values
  3209. if ( typeof key === "object" ) {
  3210. return this.each(function() {
  3211. data_user.set( this, key );
  3212. });
  3213. }
  3214. return access( this, function( value ) {
  3215. var data,
  3216. camelKey = jQuery.camelCase( key );
  3217. // The calling jQuery object (element matches) is not empty
  3218. // (and therefore has an element appears at this[ 0 ]) and the
  3219. // `value` parameter was not undefined. An empty jQuery object
  3220. // will result in `undefined` for elem = this[ 0 ] which will
  3221. // throw an exception if an attempt to read a data cache is made.
  3222. if ( elem && value === undefined ) {
  3223. // Attempt to get data from the cache
  3224. // with the key as-is
  3225. data = data_user.get( elem, key );
  3226. if ( data !== undefined ) {
  3227. return data;
  3228. }
  3229. // Attempt to get data from the cache
  3230. // with the key camelized
  3231. data = data_user.get( elem, camelKey );
  3232. if ( data !== undefined ) {
  3233. return data;
  3234. }
  3235. // Attempt to "discover" the data in
  3236. // HTML5 custom data-* attrs
  3237. data = dataAttr( elem, camelKey, undefined );
  3238. if ( data !== undefined ) {
  3239. return data;
  3240. }
  3241. // We tried really hard, but the data doesn't exist.
  3242. return;
  3243. }
  3244. // Set the data...
  3245. this.each(function() {
  3246. // First, attempt to store a copy or reference of any
  3247. // data that might've been store with a camelCased key.
  3248. var data = data_user.get( this, camelKey );
  3249. // For HTML5 data-* attribute interop, we have to
  3250. // store property names with dashes in a camelCase form.
  3251. // This might not apply to all properties...*
  3252. data_user.set( this, camelKey, value );
  3253. // *... In the case of properties that might _actually_
  3254. // have dashes, we need to also store a copy of that
  3255. // unchanged property.
  3256. if ( key.indexOf("-") !== -1 && data !== undefined ) {
  3257. data_user.set( this, key, value );
  3258. }
  3259. });
  3260. }, null, value, arguments.length > 1, null, true );
  3261. },
  3262. removeData: function( key ) {
  3263. return this.each(function() {
  3264. data_user.remove( this, key );
  3265. });
  3266. }
  3267. });
  3268. jQuery.extend({
  3269. queue: function( elem, type, data ) {
  3270. var queue;
  3271. if ( elem ) {
  3272. type = ( type || "fx" ) + "queue";
  3273. queue = data_priv.get( elem, type );
  3274. // Speed up dequeue by getting out quickly if this is just a lookup
  3275. if ( data ) {
  3276. if ( !queue || jQuery.isArray( data ) ) {
  3277. queue = data_priv.access( elem, type, jQuery.makeArray(data) );
  3278. } else {
  3279. queue.push( data );
  3280. }
  3281. }
  3282. return queue || [];
  3283. }
  3284. },
  3285. dequeue: function( elem, type ) {
  3286. type = type || "fx";
  3287. var queue = jQuery.queue( elem, type ),
  3288. startLength = queue.length,
  3289. fn = queue.shift(),
  3290. hooks = jQuery._queueHooks( elem, type ),
  3291. next = function() {
  3292. jQuery.dequeue( elem, type );
  3293. };
  3294. // If the fx queue is dequeued, always remove the progress sentinel
  3295. if ( fn === "inprogress" ) {
  3296. fn = queue.shift();
  3297. startLength--;
  3298. }
  3299. if ( fn ) {
  3300. // Add a progress sentinel to prevent the fx queue from being
  3301. // automatically dequeued
  3302. if ( type === "fx" ) {
  3303. queue.unshift( "inprogress" );
  3304. }
  3305. // clear up the last queue stop function
  3306. delete hooks.stop;
  3307. fn.call( elem, next, hooks );
  3308. }
  3309. if ( !startLength && hooks ) {
  3310. hooks.empty.fire();
  3311. }
  3312. },
  3313. // not intended for public consumption - generates a queueHooks object, or returns the current one
  3314. _queueHooks: function( elem, type ) {
  3315. var key = type + "queueHooks";
  3316. return data_priv.get( elem, key ) || data_priv.access( elem, key, {
  3317. empty: jQuery.Callbacks("once memory").add(function() {
  3318. data_priv.remove( elem, [ type + "queue", key ] );
  3319. })
  3320. });
  3321. }
  3322. });
  3323. jQuery.fn.extend({
  3324. queue: function( type, data ) {
  3325. var setter = 2;
  3326. if ( typeof type !== "string" ) {
  3327. data = type;
  3328. type = "fx";
  3329. setter--;
  3330. }
  3331. if ( arguments.length < setter ) {
  3332. return jQuery.queue( this[0], type );
  3333. }
  3334. return data === undefined ?
  3335. this :
  3336. this.each(function() {
  3337. var queue = jQuery.queue( this, type, data );
  3338. // ensure a hooks for this queue
  3339. jQuery._queueHooks( this, type );
  3340. if ( type === "fx" && queue[0] !== "inprogress" ) {
  3341. jQuery.dequeue( this, type );
  3342. }
  3343. });
  3344. },
  3345. dequeue: function( type ) {
  3346. return this.each(function() {
  3347. jQuery.dequeue( this, type );
  3348. });
  3349. },
  3350. clearQueue: function( type ) {
  3351. return this.queue( type || "fx", [] );
  3352. },
  3353. // Get a promise resolved when queues of a certain type
  3354. // are emptied (fx is the type by default)
  3355. promise: function( type, obj ) {
  3356. var tmp,
  3357. count = 1,
  3358. defer = jQuery.Deferred(),
  3359. elements = this,
  3360. i = this.length,
  3361. resolve = function() {
  3362. if ( !( --count ) ) {
  3363. defer.resolveWith( elements, [ elements ] );
  3364. }
  3365. };
  3366. if ( typeof type !== "string" ) {
  3367. obj = type;
  3368. type = undefined;
  3369. }
  3370. type = type || "fx";
  3371. while ( i-- ) {
  3372. tmp = data_priv.get( elements[ i ], type + "queueHooks" );
  3373. if ( tmp && tmp.empty ) {
  3374. count++;
  3375. tmp.empty.add( resolve );
  3376. }
  3377. }
  3378. resolve();
  3379. return defer.promise( obj );
  3380. }
  3381. });
  3382. var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
  3383. var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
  3384. var isHidden = function( elem, el ) {
  3385. // isHidden might be called from jQuery#filter function;
  3386. // in that case, element will be second argument
  3387. elem = el || elem;
  3388. return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
  3389. };
  3390. var rcheckableType = (/^(?:checkbox|radio)$/i);
  3391. (function() {
  3392. var fragment = document.createDocumentFragment(),
  3393. div = fragment.appendChild( document.createElement( "div" ) ),
  3394. input = document.createElement( "input" );
  3395. // #11217 - WebKit loses check when the name is after the checked attribute
  3396. // Support: Windows Web Apps (WWA)
  3397. // `name` and `type` need .setAttribute for WWA
  3398. input.setAttribute( "type", "radio" );
  3399. input.setAttribute( "checked", "checked" );
  3400. input.setAttribute( "name", "t" );
  3401. div.appendChild( input );
  3402. // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
  3403. // old WebKit doesn't clone checked state correctly in fragments
  3404. support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
  3405. // Make sure textarea (and checkbox) defaultValue is properly cloned
  3406. // Support: IE9-IE11+
  3407. div.innerHTML = "<textarea>x</textarea>";
  3408. support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
  3409. })();
  3410. var strundefined = typeof undefined;
  3411. support.focusinBubbles = "onfocusin" in window;
  3412. var
  3413. rkeyEvent = /^key/,
  3414. rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
  3415. rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
  3416. rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
  3417. function returnTrue() {
  3418. return true;
  3419. }
  3420. function returnFalse() {
  3421. return false;
  3422. }
  3423. function safeActiveElement() {
  3424. try {
  3425. return document.activeElement;
  3426. } catch ( err ) { }
  3427. }
  3428. /*
  3429. * Helper functions for managing events -- not part of the public interface.
  3430. * Props to Dean Edwards' addEvent library for many of the ideas.
  3431. */
  3432. jQuery.event = {
  3433. global: {},
  3434. add: function( elem, types, handler, data, selector ) {
  3435. var handleObjIn, eventHandle, tmp,
  3436. events, t, handleObj,
  3437. special, handlers, type, namespaces, origType,
  3438. elemData = data_priv.get( elem );
  3439. // Don't attach events to noData or text/comment nodes (but allow plain objects)
  3440. if ( !elemData ) {
  3441. return;
  3442. }
  3443. // Caller can pass in an object of custom data in lieu of the handler
  3444. if ( handler.handler ) {
  3445. handleObjIn = handler;
  3446. handler = handleObjIn.handler;
  3447. selector = handleObjIn.selector;
  3448. }
  3449. // Make sure that the handler has a unique ID, used to find/remove it later
  3450. if ( !handler.guid ) {
  3451. handler.guid = jQuery.guid++;
  3452. }
  3453. // Init the element's event structure and main handler, if this is the first
  3454. if ( !(events = elemData.events) ) {
  3455. events = elemData.events = {};
  3456. }
  3457. if ( !(eventHandle = elemData.handle) ) {
  3458. eventHandle = elemData.handle = function( e ) {
  3459. // Discard the second event of a jQuery.event.trigger() and
  3460. // when an event is called after a page has unloaded
  3461. return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
  3462. jQuery.event.dispatch.apply( elem, arguments ) : undefined;
  3463. };
  3464. }
  3465. // Handle multiple events separated by a space
  3466. types = ( types || "" ).match( rnotwhite ) || [ "" ];
  3467. t = types.length;
  3468. while ( t-- ) {
  3469. tmp = rtypenamespace.exec( types[t] ) || [];
  3470. type = origType = tmp[1];
  3471. namespaces = ( tmp[2] || "" ).split( "." ).sort();
  3472. // There *must* be a type, no attaching namespace-only handlers
  3473. if ( !type ) {
  3474. continue;
  3475. }
  3476. // If event changes its type, use the special event handlers for the changed type
  3477. special = jQuery.event.special[ type ] || {};
  3478. // If selector defined, determine special event api type, otherwise given type
  3479. type = ( selector ? special.delegateType : special.bindType ) || type;
  3480. // Update special based on newly reset type
  3481. special = jQuery.event.special[ type ] || {};
  3482. // handleObj is passed to all event handlers
  3483. handleObj = jQuery.extend({
  3484. type: type,
  3485. origType: origType,
  3486. data: data,
  3487. handler: handler,
  3488. guid: handler.guid,
  3489. selector: selector,
  3490. needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
  3491. namespace: namespaces.join(".")
  3492. }, handleObjIn );
  3493. // Init the event handler queue if we're the first
  3494. if ( !(handlers = events[ type ]) ) {
  3495. handlers = events[ type ] = [];
  3496. handlers.delegateCount = 0;
  3497. // Only use addEventListener if the special events handler returns false
  3498. if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
  3499. if ( elem.addEventListener ) {
  3500. elem.addEventListener( type, eventHandle, false );
  3501. }
  3502. }
  3503. }
  3504. if ( special.add ) {
  3505. special.add.call( elem, handleObj );
  3506. if ( !handleObj.handler.guid ) {
  3507. handleObj.handler.guid = handler.guid;
  3508. }
  3509. }
  3510. // Add to the element's handler list, delegates in front
  3511. if ( selector ) {
  3512. handlers.splice( handlers.delegateCount++, 0, handleObj );
  3513. } else {
  3514. handlers.push( handleObj );
  3515. }
  3516. // Keep track of which events have ever been used, for event optimization
  3517. jQuery.event.global[ type ] = true;
  3518. }
  3519. },
  3520. // Detach an event or set of events from an element
  3521. remove: function( elem, types, handler, selector, mappedTypes ) {
  3522. var j, origCount, tmp,
  3523. events, t, handleObj,
  3524. special, handlers, type, namespaces, origType,
  3525. elemData = data_priv.hasData( elem ) && data_priv.get( elem );
  3526. if ( !elemData || !(events = elemData.events) ) {
  3527. return;
  3528. }
  3529. // Once for each type.namespace in types; type may be omitted
  3530. types = ( types || "" ).match( rnotwhite ) || [ "" ];
  3531. t = types.length;
  3532. while ( t-- ) {
  3533. tmp = rtypenamespace.exec( types[t] ) || [];
  3534. type = origType = tmp[1];
  3535. namespaces = ( tmp[2] || "" ).split( "." ).sort();
  3536. // Unbind all events (on this namespace, if provided) for the element
  3537. if ( !type ) {
  3538. for ( type in events ) {
  3539. jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
  3540. }
  3541. continue;
  3542. }
  3543. special = jQuery.event.special[ type ] || {};
  3544. type = ( selector ? special.delegateType : special.bindType ) || type;
  3545. handlers = events[ type ] || [];
  3546. tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
  3547. // Remove matching events
  3548. origCount = j = handlers.length;
  3549. while ( j-- ) {
  3550. handleObj = handlers[ j ];
  3551. if ( ( mappedTypes || origType === handleObj.origType ) &&
  3552. ( !handler || handler.guid === handleObj.guid ) &&
  3553. ( !tmp || tmp.test( handleObj.namespace ) ) &&
  3554. ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
  3555. handlers.splice( j, 1 );
  3556. if ( handleObj.selector ) {
  3557. handlers.delegateCount--;
  3558. }
  3559. if ( special.remove ) {
  3560. special.remove.call( elem, handleObj );
  3561. }
  3562. }
  3563. }
  3564. // Remove generic event handler if we removed something and no more handlers exist
  3565. // (avoids potential for endless recursion during removal of special event handlers)
  3566. if ( origCount && !handlers.length ) {
  3567. if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
  3568. jQuery.removeEvent( elem, type, elemData.handle );
  3569. }
  3570. delete events[ type ];
  3571. }
  3572. }
  3573. // Remove the expando if it's no longer used
  3574. if ( jQuery.isEmptyObject( events ) ) {
  3575. delete elemData.handle;
  3576. data_priv.remove( elem, "events" );
  3577. }
  3578. },
  3579. trigger: function( event, data, elem, onlyHandlers ) {
  3580. var i, cur, tmp, bubbleType, ontype, handle, special,
  3581. eventPath = [ elem || document ],
  3582. type = hasOwn.call( event, "type" ) ? event.type : event,
  3583. namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
  3584. cur = tmp = elem = elem || document;
  3585. // Don't do events on text and comment nodes
  3586. if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
  3587. return;
  3588. }
  3589. // focus/blur morphs to focusin/out; ensure we're not firing them right now
  3590. if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
  3591. return;
  3592. }
  3593. if ( type.indexOf(".") >= 0 ) {
  3594. // Namespaced trigger; create a regexp to match event type in handle()
  3595. namespaces = type.split(".");
  3596. type = namespaces.shift();
  3597. namespaces.sort();
  3598. }
  3599. ontype = type.indexOf(":") < 0 && "on" + type;
  3600. // Caller can pass in a jQuery.Event object, Object, or just an event type string
  3601. event = event[ jQuery.expando ] ?
  3602. event :
  3603. new jQuery.Event( type, typeof event === "object" && event );
  3604. // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
  3605. event.isTrigger = onlyHandlers ? 2 : 3;
  3606. event.namespace = namespaces.join(".");
  3607. event.namespace_re = event.namespace ?
  3608. new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
  3609. null;
  3610. // Clean up the event in case it is being reused
  3611. event.result = undefined;
  3612. if ( !event.target ) {
  3613. event.target = elem;
  3614. }
  3615. // Clone any incoming data and prepend the event, creating the handler arg list
  3616. data = data == null ?
  3617. [ event ] :
  3618. jQuery.makeArray( data, [ event ] );
  3619. // Allow special events to draw outside the lines
  3620. special = jQuery.event.special[ type ] || {};
  3621. if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
  3622. return;
  3623. }
  3624. // Determine event propagation path in advance, per W3C events spec (#9951)
  3625. // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
  3626. if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
  3627. bubbleType = special.delegateType || type;
  3628. if ( !rfocusMorph.test( bubbleType + type ) ) {
  3629. cur = cur.parentNode;
  3630. }
  3631. for ( ; cur; cur = cur.parentNode ) {
  3632. eventPath.push( cur );
  3633. tmp = cur;
  3634. }
  3635. // Only add window if we got to document (e.g., not plain obj or detached DOM)
  3636. if ( tmp === (elem.ownerDocument || document) ) {
  3637. eventPath.push( tmp.defaultView || tmp.parentWindow || window );
  3638. }
  3639. }
  3640. // Fire handlers on the event path
  3641. i = 0;
  3642. while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
  3643. event.type = i > 1 ?
  3644. bubbleType :
  3645. special.bindType || type;
  3646. // jQuery handler
  3647. handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
  3648. if ( handle ) {
  3649. handle.apply( cur, data );
  3650. }
  3651. // Native handler
  3652. handle = ontype && cur[ ontype ];
  3653. if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
  3654. event.result = handle.apply( cur, data );
  3655. if ( event.result === false ) {
  3656. event.preventDefault();
  3657. }
  3658. }
  3659. }
  3660. event.type = type;
  3661. // If nobody prevented the default action, do it now
  3662. if ( !onlyHandlers && !event.isDefaultPrevented() ) {
  3663. if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
  3664. jQuery.acceptData( elem ) ) {
  3665. // Call a native DOM method on the target with the same name name as the event.
  3666. // Don't do default actions on window, that's where global variables be (#6170)
  3667. if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
  3668. // Don't re-trigger an onFOO event when we call its FOO() method
  3669. tmp = elem[ ontype ];
  3670. if ( tmp ) {
  3671. elem[ ontype ] = null;
  3672. }
  3673. // Prevent re-triggering of the same event, since we already bubbled it above
  3674. jQuery.event.triggered = type;
  3675. elem[ type ]();
  3676. jQuery.event.triggered = undefined;
  3677. if ( tmp ) {
  3678. elem[ ontype ] = tmp;
  3679. }
  3680. }
  3681. }
  3682. }
  3683. return event.result;
  3684. },
  3685. dispatch: function( event ) {
  3686. // Make a writable jQuery.Event from the native event object
  3687. event = jQuery.event.fix( event );
  3688. var i, j, ret, matched, handleObj,
  3689. handlerQueue = [],
  3690. args = slice.call( arguments ),
  3691. handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
  3692. special = jQuery.event.special[ event.type ] || {};
  3693. // Use the fix-ed jQuery.Event rather than the (read-only) native event
  3694. args[0] = event;
  3695. event.delegateTarget = this;
  3696. // Call the preDispatch hook for the mapped type, and let it bail if desired
  3697. if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
  3698. return;
  3699. }
  3700. // Determine handlers
  3701. handlerQueue = jQuery.event.handlers.call( this, event, handlers );
  3702. // Run delegates first; they may want to stop propagation beneath us
  3703. i = 0;
  3704. while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
  3705. event.currentTarget = matched.elem;
  3706. j = 0;
  3707. while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
  3708. // Triggered event must either 1) have no namespace, or
  3709. // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
  3710. if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
  3711. event.handleObj = handleObj;
  3712. event.data = handleObj.data;
  3713. ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
  3714. .apply( matched.elem, args );
  3715. if ( ret !== undefined ) {
  3716. if ( (event.result = ret) === false ) {
  3717. event.preventDefault();
  3718. event.stopPropagation();
  3719. }
  3720. }
  3721. }
  3722. }
  3723. }
  3724. // Call the postDispatch hook for the mapped type
  3725. if ( special.postDispatch ) {
  3726. special.postDispatch.call( this, event );
  3727. }
  3728. return event.result;
  3729. },
  3730. handlers: function( event, handlers ) {
  3731. var i, matches, sel, handleObj,
  3732. handlerQueue = [],
  3733. delegateCount = handlers.delegateCount,
  3734. cur = event.target;
  3735. // Find delegate handlers
  3736. // Black-hole SVG <use> instance trees (#13180)
  3737. // Avoid non-left-click bubbling in Firefox (#3861)
  3738. if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
  3739. for ( ; cur !== this; cur = cur.parentNode || this ) {
  3740. // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
  3741. if ( cur.disabled !== true || event.type !== "click" ) {
  3742. matches = [];
  3743. for ( i = 0; i < delegateCount; i++ ) {
  3744. handleObj = handlers[ i ];
  3745. // Don't conflict with Object.prototype properties (#13203)
  3746. sel = handleObj.selector + " ";
  3747. if ( matches[ sel ] === undefined ) {
  3748. matches[ sel ] = handleObj.needsContext ?
  3749. jQuery( sel, this ).index( cur ) >= 0 :
  3750. jQuery.find( sel, this, null, [ cur ] ).length;
  3751. }
  3752. if ( matches[ sel ] ) {
  3753. matches.push( handleObj );
  3754. }
  3755. }
  3756. if ( matches.length ) {
  3757. handlerQueue.push({ elem: cur, handlers: matches });
  3758. }
  3759. }
  3760. }
  3761. }
  3762. // Add the remaining (directly-bound) handlers
  3763. if ( delegateCount < handlers.length ) {
  3764. handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
  3765. }
  3766. return handlerQueue;
  3767. },
  3768. // Includes some event props shared by KeyEvent and MouseEvent
  3769. props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
  3770. fixHooks: {},
  3771. keyHooks: {
  3772. props: "char charCode key keyCode".split(" "),
  3773. filter: function( event, original ) {
  3774. // Add which for key events
  3775. if ( event.which == null ) {
  3776. event.which = original.charCode != null ? original.charCode : original.keyCode;
  3777. }
  3778. return event;
  3779. }
  3780. },
  3781. mouseHooks: {
  3782. props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
  3783. filter: function( event, original ) {
  3784. var eventDoc, doc, body,
  3785. button = original.button;
  3786. // Calculate pageX/Y if missing and clientX/Y available
  3787. if ( event.pageX == null && original.clientX != null ) {
  3788. eventDoc = event.target.ownerDocument || document;
  3789. doc = eventDoc.documentElement;
  3790. body = eventDoc.body;
  3791. event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
  3792. event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
  3793. }
  3794. // Add which for click: 1 === left; 2 === middle; 3 === right
  3795. // Note: button is not normalized, so don't use it
  3796. if ( !event.which && button !== undefined ) {
  3797. event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
  3798. }
  3799. return event;
  3800. }
  3801. },
  3802. fix: function( event ) {
  3803. if ( event[ jQuery.expando ] ) {
  3804. return event;
  3805. }
  3806. // Create a writable copy of the event object and normalize some properties
  3807. var i, prop, copy,
  3808. type = event.type,
  3809. originalEvent = event,
  3810. fixHook = this.fixHooks[ type ];
  3811. if ( !fixHook ) {
  3812. this.fixHooks[ type ] = fixHook =
  3813. rmouseEvent.test( type ) ? this.mouseHooks :
  3814. rkeyEvent.test( type ) ? this.keyHooks :
  3815. {};
  3816. }
  3817. copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
  3818. event = new jQuery.Event( originalEvent );
  3819. i = copy.length;
  3820. while ( i-- ) {
  3821. prop = copy[ i ];
  3822. event[ prop ] = originalEvent[ prop ];
  3823. }
  3824. // Support: Cordova 2.5 (WebKit) (#13255)
  3825. // All events should have a target; Cordova deviceready doesn't
  3826. if ( !event.target ) {
  3827. event.target = document;
  3828. }
  3829. // Support: Safari 6.0+, Chrome < 28
  3830. // Target should not be a text node (#504, #13143)
  3831. if ( event.target.nodeType === 3 ) {
  3832. event.target = event.target.parentNode;
  3833. }
  3834. return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
  3835. },
  3836. special: {
  3837. load: {
  3838. // Prevent triggered image.load events from bubbling to window.load
  3839. noBubble: true
  3840. },
  3841. focus: {
  3842. // Fire native event if possible so blur/focus sequence is correct
  3843. trigger: function() {
  3844. if ( this !== safeActiveElement() && this.focus ) {
  3845. this.focus();
  3846. return false;
  3847. }
  3848. },
  3849. delegateType: "focusin"
  3850. },
  3851. blur: {
  3852. trigger: function() {
  3853. if ( this === safeActiveElement() && this.blur ) {
  3854. this.blur();
  3855. return false;
  3856. }
  3857. },
  3858. delegateType: "focusout"
  3859. },
  3860. click: {
  3861. // For checkbox, fire native event so checked state will be right
  3862. trigger: function() {
  3863. if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
  3864. this.click();
  3865. return false;
  3866. }
  3867. },
  3868. // For cross-browser consistency, don't fire native .click() on links
  3869. _default: function( event ) {
  3870. return jQuery.nodeName( event.target, "a" );
  3871. }
  3872. },
  3873. beforeunload: {
  3874. postDispatch: function( event ) {
  3875. // Support: Firefox 20+
  3876. // Firefox doesn't alert if the returnValue field is not set.
  3877. if ( event.result !== undefined && event.originalEvent ) {
  3878. event.originalEvent.returnValue = event.result;
  3879. }
  3880. }
  3881. }
  3882. },
  3883. simulate: function( type, elem, event, bubble ) {
  3884. // Piggyback on a donor event to simulate a different one.
  3885. // Fake originalEvent to avoid donor's stopPropagation, but if the
  3886. // simulated event prevents default then we do the same on the donor.
  3887. var e = jQuery.extend(
  3888. new jQuery.Event(),
  3889. event,
  3890. {
  3891. type: type,
  3892. isSimulated: true,
  3893. originalEvent: {}
  3894. }
  3895. );
  3896. if ( bubble ) {
  3897. jQuery.event.trigger( e, null, elem );
  3898. } else {
  3899. jQuery.event.dispatch.call( elem, e );
  3900. }
  3901. if ( e.isDefaultPrevented() ) {
  3902. event.preventDefault();
  3903. }
  3904. }
  3905. };
  3906. jQuery.removeEvent = function( elem, type, handle ) {
  3907. if ( elem.removeEventListener ) {
  3908. elem.removeEventListener( type, handle, false );
  3909. }
  3910. };
  3911. jQuery.Event = function( src, props ) {
  3912. // Allow instantiation without the 'new' keyword
  3913. if ( !(this instanceof jQuery.Event) ) {
  3914. return new jQuery.Event( src, props );
  3915. }
  3916. // Event object
  3917. if ( src && src.type ) {
  3918. this.originalEvent = src;
  3919. this.type = src.type;
  3920. // Events bubbling up the document may have been marked as prevented
  3921. // by a handler lower down the tree; reflect the correct value.
  3922. this.isDefaultPrevented = src.defaultPrevented ||
  3923. src.defaultPrevented === undefined &&
  3924. // Support: Android < 4.0
  3925. src.returnValue === false ?
  3926. returnTrue :
  3927. returnFalse;
  3928. // Event type
  3929. } else {
  3930. this.type = src;
  3931. }
  3932. // Put explicitly provided properties onto the event object
  3933. if ( props ) {
  3934. jQuery.extend( this, props );
  3935. }
  3936. // Create a timestamp if incoming event doesn't have one
  3937. this.timeStamp = src && src.timeStamp || jQuery.now();
  3938. // Mark it as fixed
  3939. this[ jQuery.expando ] = true;
  3940. };
  3941. // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
  3942. // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  3943. jQuery.Event.prototype = {
  3944. isDefaultPrevented: returnFalse,
  3945. isPropagationStopped: returnFalse,
  3946. isImmediatePropagationStopped: returnFalse,
  3947. preventDefault: function() {
  3948. var e = this.originalEvent;
  3949. this.isDefaultPrevented = returnTrue;
  3950. if ( e && e.preventDefault ) {
  3951. e.preventDefault();
  3952. }
  3953. },
  3954. stopPropagation: function() {
  3955. var e = this.originalEvent;
  3956. this.isPropagationStopped = returnTrue;
  3957. if ( e && e.stopPropagation ) {
  3958. e.stopPropagation();
  3959. }
  3960. },
  3961. stopImmediatePropagation: function() {
  3962. var e = this.originalEvent;
  3963. this.isImmediatePropagationStopped = returnTrue;
  3964. if ( e && e.stopImmediatePropagation ) {
  3965. e.stopImmediatePropagation();
  3966. }
  3967. this.stopPropagation();
  3968. }
  3969. };
  3970. // Create mouseenter/leave events using mouseover/out and event-time checks
  3971. // Support: Chrome 15+
  3972. jQuery.each({
  3973. mouseenter: "mouseover",
  3974. mouseleave: "mouseout",
  3975. pointerenter: "pointerover",
  3976. pointerleave: "pointerout"
  3977. }, function( orig, fix ) {
  3978. jQuery.event.special[ orig ] = {
  3979. delegateType: fix,
  3980. bindType: fix,
  3981. handle: function( event ) {
  3982. var ret,
  3983. target = this,
  3984. related = event.relatedTarget,
  3985. handleObj = event.handleObj;
  3986. // For mousenter/leave call the handler if related is outside the target.
  3987. // NB: No relatedTarget if the mouse left/entered the browser window
  3988. if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
  3989. event.type = handleObj.origType;
  3990. ret = handleObj.handler.apply( this, arguments );
  3991. event.type = fix;
  3992. }
  3993. return ret;
  3994. }
  3995. };
  3996. });
  3997. // Create "bubbling" focus and blur events
  3998. // Support: Firefox, Chrome, Safari
  3999. if ( !support.focusinBubbles ) {
  4000. jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
  4001. // Attach a single capturing handler on the document while someone wants focusin/focusout
  4002. var handler = function( event ) {
  4003. jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
  4004. };
  4005. jQuery.event.special[ fix ] = {
  4006. setup: function() {
  4007. var doc = this.ownerDocument || this,
  4008. attaches = data_priv.access( doc, fix );
  4009. if ( !attaches ) {
  4010. doc.addEventListener( orig, handler, true );
  4011. }
  4012. data_priv.access( doc, fix, ( attaches || 0 ) + 1 );
  4013. },
  4014. teardown: function() {
  4015. var doc = this.ownerDocument || this,
  4016. attaches = data_priv.access( doc, fix ) - 1;
  4017. if ( !attaches ) {
  4018. doc.removeEventListener( orig, handler, true );
  4019. data_priv.remove( doc, fix );
  4020. } else {
  4021. data_priv.access( doc, fix, attaches );
  4022. }
  4023. }
  4024. };
  4025. });
  4026. }
  4027. jQuery.fn.extend({
  4028. on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
  4029. var origFn, type;
  4030. // Types can be a map of types/handlers
  4031. if ( typeof types === "object" ) {
  4032. // ( types-Object, selector, data )
  4033. if ( typeof selector !== "string" ) {
  4034. // ( types-Object, data )
  4035. data = data || selector;
  4036. selector = undefined;
  4037. }
  4038. for ( type in types ) {
  4039. this.on( type, selector, data, types[ type ], one );
  4040. }
  4041. return this;
  4042. }
  4043. if ( data == null && fn == null ) {
  4044. // ( types, fn )
  4045. fn = selector;
  4046. data = selector = undefined;
  4047. } else if ( fn == null ) {
  4048. if ( typeof selector === "string" ) {
  4049. // ( types, selector, fn )
  4050. fn = data;
  4051. data = undefined;
  4052. } else {
  4053. // ( types, data, fn )
  4054. fn = data;
  4055. data = selector;
  4056. selector = undefined;
  4057. }
  4058. }
  4059. if ( fn === false ) {
  4060. fn = returnFalse;
  4061. } else if ( !fn ) {
  4062. return this;
  4063. }
  4064. if ( one === 1 ) {
  4065. origFn = fn;
  4066. fn = function( event ) {
  4067. // Can use an empty set, since event contains the info
  4068. jQuery().off( event );
  4069. return origFn.apply( this, arguments );
  4070. };
  4071. // Use same guid so caller can remove using origFn
  4072. fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
  4073. }
  4074. return this.each( function() {
  4075. jQuery.event.add( this, types, fn, data, selector );
  4076. });
  4077. },
  4078. one: function( types, selector, data, fn ) {
  4079. return this.on( types, selector, data, fn, 1 );
  4080. },
  4081. off: function( types, selector, fn ) {
  4082. var handleObj, type;
  4083. if ( types && types.preventDefault && types.handleObj ) {
  4084. // ( event ) dispatched jQuery.Event
  4085. handleObj = types.handleObj;
  4086. jQuery( types.delegateTarget ).off(
  4087. handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
  4088. handleObj.selector,
  4089. handleObj.handler
  4090. );
  4091. return this;
  4092. }
  4093. if ( typeof types === "object" ) {
  4094. // ( types-object [, selector] )
  4095. for ( type in types ) {
  4096. this.off( type, selector, types[ type ] );
  4097. }
  4098. return this;
  4099. }
  4100. if ( selector === false || typeof selector === "function" ) {
  4101. // ( types [, fn] )
  4102. fn = selector;
  4103. selector = undefined;
  4104. }
  4105. if ( fn === false ) {
  4106. fn = returnFalse;
  4107. }
  4108. return this.each(function() {
  4109. jQuery.event.remove( this, types, fn, selector );
  4110. });
  4111. },
  4112. trigger: function( type, data ) {
  4113. return this.each(function() {
  4114. jQuery.event.trigger( type, data, this );
  4115. });
  4116. },
  4117. triggerHandler: function( type, data ) {
  4118. var elem = this[0];
  4119. if ( elem ) {
  4120. return jQuery.event.trigger( type, data, elem, true );
  4121. }
  4122. }
  4123. });
  4124. var
  4125. rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
  4126. rtagName = /<([\w:]+)/,
  4127. rhtml = /<|&#?\w+;/,
  4128. rnoInnerhtml = /<(?:script|style|link)/i,
  4129. // checked="checked" or checked
  4130. rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
  4131. rscriptType = /^$|\/(?:java|ecma)script/i,
  4132. rscriptTypeMasked = /^true\/(.*)/,
  4133. rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
  4134. // We have to close these tags to support XHTML (#13200)
  4135. wrapMap = {
  4136. // Support: IE 9
  4137. option: [ 1, "<select multiple='multiple'>", "</select>" ],
  4138. thead: [ 1, "<table>", "</table>" ],
  4139. col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
  4140. tr: [ 2, "<table><tbody>", "</tbody></table>" ],
  4141. td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
  4142. _default: [ 0, "", "" ]
  4143. };
  4144. // Support: IE 9
  4145. wrapMap.optgroup = wrapMap.option;
  4146. wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
  4147. wrapMap.th = wrapMap.td;
  4148. // Support: 1.x compatibility
  4149. // Manipulating tables requires a tbody
  4150. function manipulationTarget( elem, content ) {
  4151. return jQuery.nodeName( elem, "table" ) &&
  4152. jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
  4153. elem.getElementsByTagName("tbody")[0] ||
  4154. elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
  4155. elem;
  4156. }
  4157. // Replace/restore the type attribute of script elements for safe DOM manipulation
  4158. function disableScript( elem ) {
  4159. elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
  4160. return elem;
  4161. }
  4162. function restoreScript( elem ) {
  4163. var match = rscriptTypeMasked.exec( elem.type );
  4164. if ( match ) {
  4165. elem.type = match[ 1 ];
  4166. } else {
  4167. elem.removeAttribute("type");
  4168. }
  4169. return elem;
  4170. }
  4171. // Mark scripts as having already been evaluated
  4172. function setGlobalEval( elems, refElements ) {
  4173. var i = 0,
  4174. l = elems.length;
  4175. for ( ; i < l; i++ ) {
  4176. data_priv.set(
  4177. elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
  4178. );
  4179. }
  4180. }
  4181. function cloneCopyEvent( src, dest ) {
  4182. var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
  4183. if ( dest.nodeType !== 1 ) {
  4184. return;
  4185. }
  4186. // 1. Copy private data: events, handlers, etc.
  4187. if ( data_priv.hasData( src ) ) {
  4188. pdataOld = data_priv.access( src );
  4189. pdataCur = data_priv.set( dest, pdataOld );
  4190. events = pdataOld.events;
  4191. if ( events ) {
  4192. delete pdataCur.handle;
  4193. pdataCur.events = {};
  4194. for ( type in events ) {
  4195. for ( i = 0, l = events[ type ].length; i < l; i++ ) {
  4196. jQuery.event.add( dest, type, events[ type ][ i ] );
  4197. }
  4198. }
  4199. }
  4200. }
  4201. // 2. Copy user data
  4202. if ( data_user.hasData( src ) ) {
  4203. udataOld = data_user.access( src );
  4204. udataCur = jQuery.extend( {}, udataOld );
  4205. data_user.set( dest, udataCur );
  4206. }
  4207. }
  4208. function getAll( context, tag ) {
  4209. var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
  4210. context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
  4211. [];
  4212. return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
  4213. jQuery.merge( [ context ], ret ) :
  4214. ret;
  4215. }
  4216. // Support: IE >= 9
  4217. function fixInput( src, dest ) {
  4218. var nodeName = dest.nodeName.toLowerCase();
  4219. // Fails to persist the checked state of a cloned checkbox or radio button.
  4220. if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
  4221. dest.checked = src.checked;
  4222. // Fails to return the selected option to the default selected state when cloning options
  4223. } else if ( nodeName === "input" || nodeName === "textarea" ) {
  4224. dest.defaultValue = src.defaultValue;
  4225. }
  4226. }
  4227. jQuery.extend({
  4228. clone: function( elem, dataAndEvents, deepDataAndEvents ) {
  4229. var i, l, srcElements, destElements,
  4230. clone = elem.cloneNode( true ),
  4231. inPage = jQuery.contains( elem.ownerDocument, elem );
  4232. // Support: IE >= 9
  4233. // Fix Cloning issues
  4234. if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
  4235. !jQuery.isXMLDoc( elem ) ) {
  4236. // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
  4237. destElements = getAll( clone );
  4238. srcElements = getAll( elem );
  4239. for ( i = 0, l = srcElements.length; i < l; i++ ) {
  4240. fixInput( srcElements[ i ], destElements[ i ] );
  4241. }
  4242. }
  4243. // Copy the events from the original to the clone
  4244. if ( dataAndEvents ) {
  4245. if ( deepDataAndEvents ) {
  4246. srcElements = srcElements || getAll( elem );
  4247. destElements = destElements || getAll( clone );
  4248. for ( i = 0, l = srcElements.length; i < l; i++ ) {
  4249. cloneCopyEvent( srcElements[ i ], destElements[ i ] );
  4250. }
  4251. } else {
  4252. cloneCopyEvent( elem, clone );
  4253. }
  4254. }
  4255. // Preserve script evaluation history
  4256. destElements = getAll( clone, "script" );
  4257. if ( destElements.length > 0 ) {
  4258. setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
  4259. }
  4260. // Return the cloned set
  4261. return clone;
  4262. },
  4263. buildFragment: function( elems, context, scripts, selection ) {
  4264. var elem, tmp, tag, wrap, contains, j,
  4265. fragment = context.createDocumentFragment(),
  4266. nodes = [],
  4267. i = 0,
  4268. l = elems.length;
  4269. for ( ; i < l; i++ ) {
  4270. elem = elems[ i ];
  4271. if ( elem || elem === 0 ) {
  4272. // Add nodes directly
  4273. if ( jQuery.type( elem ) === "object" ) {
  4274. // Support: QtWebKit
  4275. // jQuery.merge because push.apply(_, arraylike) throws
  4276. jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
  4277. // Convert non-html into a text node
  4278. } else if ( !rhtml.test( elem ) ) {
  4279. nodes.push( context.createTextNode( elem ) );
  4280. // Convert html into DOM nodes
  4281. } else {
  4282. tmp = tmp || fragment.appendChild( context.createElement("div") );
  4283. // Deserialize a standard representation
  4284. tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
  4285. wrap = wrapMap[ tag ] || wrapMap._default;
  4286. tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
  4287. // Descend through wrappers to the right content
  4288. j = wrap[ 0 ];
  4289. while ( j-- ) {
  4290. tmp = tmp.lastChild;
  4291. }
  4292. // Support: QtWebKit
  4293. // jQuery.merge because push.apply(_, arraylike) throws
  4294. jQuery.merge( nodes, tmp.childNodes );
  4295. // Remember the top-level container
  4296. tmp = fragment.firstChild;
  4297. // Fixes #12346
  4298. // Support: Webkit, IE
  4299. tmp.textContent = "";
  4300. }
  4301. }
  4302. }
  4303. // Remove wrapper from fragment
  4304. fragment.textContent = "";
  4305. i = 0;
  4306. while ( (elem = nodes[ i++ ]) ) {
  4307. // #4087 - If origin and destination elements are the same, and this is
  4308. // that element, do not do anything
  4309. if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
  4310. continue;
  4311. }
  4312. contains = jQuery.contains( elem.ownerDocument, elem );
  4313. // Append to fragment
  4314. tmp = getAll( fragment.appendChild( elem ), "script" );
  4315. // Preserve script evaluation history
  4316. if ( contains ) {
  4317. setGlobalEval( tmp );
  4318. }
  4319. // Capture executables
  4320. if ( scripts ) {
  4321. j = 0;
  4322. while ( (elem = tmp[ j++ ]) ) {
  4323. if ( rscriptType.test( elem.type || "" ) ) {
  4324. scripts.push( elem );
  4325. }
  4326. }
  4327. }
  4328. }
  4329. return fragment;
  4330. },
  4331. cleanData: function( elems ) {
  4332. var data, elem, type, key,
  4333. special = jQuery.event.special,
  4334. i = 0;
  4335. for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
  4336. if ( jQuery.acceptData( elem ) ) {
  4337. key = elem[ data_priv.expando ];
  4338. if ( key && (data = data_priv.cache[ key ]) ) {
  4339. if ( data.events ) {
  4340. for ( type in data.events ) {
  4341. if ( special[ type ] ) {
  4342. jQuery.event.remove( elem, type );
  4343. // This is a shortcut to avoid jQuery.event.remove's overhead
  4344. } else {
  4345. jQuery.removeEvent( elem, type, data.handle );
  4346. }
  4347. }
  4348. }
  4349. if ( data_priv.cache[ key ] ) {
  4350. // Discard any remaining `private` data
  4351. delete data_priv.cache[ key ];
  4352. }
  4353. }
  4354. }
  4355. // Discard any remaining `user` data
  4356. delete data_user.cache[ elem[ data_user.expando ] ];
  4357. }
  4358. }
  4359. });
  4360. jQuery.fn.extend({
  4361. text: function( value ) {
  4362. return access( this, function( value ) {
  4363. return value === undefined ?
  4364. jQuery.text( this ) :
  4365. this.empty().each(function() {
  4366. if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
  4367. this.textContent = value;
  4368. }
  4369. });
  4370. }, null, value, arguments.length );
  4371. },
  4372. append: function() {
  4373. return this.domManip( arguments, function( elem ) {
  4374. if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
  4375. var target = manipulationTarget( this, elem );
  4376. target.appendChild( elem );
  4377. }
  4378. });
  4379. },
  4380. prepend: function() {
  4381. return this.domManip( arguments, function( elem ) {
  4382. if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
  4383. var target = manipulationTarget( this, elem );
  4384. target.insertBefore( elem, target.firstChild );
  4385. }
  4386. });
  4387. },
  4388. before: function() {
  4389. return this.domManip( arguments, function( elem ) {
  4390. if ( this.parentNode ) {
  4391. this.parentNode.insertBefore( elem, this );
  4392. }
  4393. });
  4394. },
  4395. after: function() {
  4396. return this.domManip( arguments, function( elem ) {
  4397. if ( this.parentNode ) {
  4398. this.parentNode.insertBefore( elem, this.nextSibling );
  4399. }
  4400. });
  4401. },
  4402. remove: function( selector, keepData /* Internal Use Only */ ) {
  4403. var elem,
  4404. elems = selector ? jQuery.filter( selector, this ) : this,
  4405. i = 0;
  4406. for ( ; (elem = elems[i]) != null; i++ ) {
  4407. if ( !keepData && elem.nodeType === 1 ) {
  4408. jQuery.cleanData( getAll( elem ) );
  4409. }
  4410. if ( elem.parentNode ) {
  4411. if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
  4412. setGlobalEval( getAll( elem, "script" ) );
  4413. }
  4414. elem.parentNode.removeChild( elem );
  4415. }
  4416. }
  4417. return this;
  4418. },
  4419. empty: function() {
  4420. var elem,
  4421. i = 0;
  4422. for ( ; (elem = this[i]) != null; i++ ) {
  4423. if ( elem.nodeType === 1 ) {
  4424. // Prevent memory leaks
  4425. jQuery.cleanData( getAll( elem, false ) );
  4426. // Remove any remaining nodes
  4427. elem.textContent = "";
  4428. }
  4429. }
  4430. return this;
  4431. },
  4432. clone: function( dataAndEvents, deepDataAndEvents ) {
  4433. dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
  4434. deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
  4435. return this.map(function() {
  4436. return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
  4437. });
  4438. },
  4439. html: function( value ) {
  4440. return access( this, function( value ) {
  4441. var elem = this[ 0 ] || {},
  4442. i = 0,
  4443. l = this.length;
  4444. if ( value === undefined && elem.nodeType === 1 ) {
  4445. return elem.innerHTML;
  4446. }
  4447. // See if we can take a shortcut and just use innerHTML
  4448. if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
  4449. !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
  4450. value = value.replace( rxhtmlTag, "<$1></$2>" );
  4451. try {
  4452. for ( ; i < l; i++ ) {
  4453. elem = this[ i ] || {};
  4454. // Remove element nodes and prevent memory leaks
  4455. if ( elem.nodeType === 1 ) {
  4456. jQuery.cleanData( getAll( elem, false ) );
  4457. elem.innerHTML = value;
  4458. }
  4459. }
  4460. elem = 0;
  4461. // If using innerHTML throws an exception, use the fallback method
  4462. } catch( e ) {}
  4463. }
  4464. if ( elem ) {
  4465. this.empty().append( value );
  4466. }
  4467. }, null, value, arguments.length );
  4468. },
  4469. replaceWith: function() {
  4470. var arg = arguments[ 0 ];
  4471. // Make the changes, replacing each context element with the new content
  4472. this.domManip( arguments, function( elem ) {
  4473. arg = this.parentNode;
  4474. jQuery.cleanData( getAll( this ) );
  4475. if ( arg ) {
  4476. arg.replaceChild( elem, this );
  4477. }
  4478. });
  4479. // Force removal if there was no new content (e.g., from empty arguments)
  4480. return arg && (arg.length || arg.nodeType) ? this : this.remove();
  4481. },
  4482. detach: function( selector ) {
  4483. return this.remove( selector, true );
  4484. },
  4485. domManip: function( args, callback ) {
  4486. // Flatten any nested arrays
  4487. args = concat.apply( [], args );
  4488. var fragment, first, scripts, hasScripts, node, doc,
  4489. i = 0,
  4490. l = this.length,
  4491. set = this,
  4492. iNoClone = l - 1,
  4493. value = args[ 0 ],
  4494. isFunction = jQuery.isFunction( value );
  4495. // We can't cloneNode fragments that contain checked, in WebKit
  4496. if ( isFunction ||
  4497. ( l > 1 && typeof value === "string" &&
  4498. !support.checkClone && rchecked.test( value ) ) ) {
  4499. return this.each(function( index ) {
  4500. var self = set.eq( index );
  4501. if ( isFunction ) {
  4502. args[ 0 ] = value.call( this, index, self.html() );
  4503. }
  4504. self.domManip( args, callback );
  4505. });
  4506. }
  4507. if ( l ) {
  4508. fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
  4509. first = fragment.firstChild;
  4510. if ( fragment.childNodes.length === 1 ) {
  4511. fragment = first;
  4512. }
  4513. if ( first ) {
  4514. scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
  4515. hasScripts = scripts.length;
  4516. // Use the original fragment for the last item instead of the first because it can end up
  4517. // being emptied incorrectly in certain situations (#8070).
  4518. for ( ; i < l; i++ ) {
  4519. node = fragment;
  4520. if ( i !== iNoClone ) {
  4521. node = jQuery.clone( node, true, true );
  4522. // Keep references to cloned scripts for later restoration
  4523. if ( hasScripts ) {
  4524. // Support: QtWebKit
  4525. // jQuery.merge because push.apply(_, arraylike) throws
  4526. jQuery.merge( scripts, getAll( node, "script" ) );
  4527. }
  4528. }
  4529. callback.call( this[ i ], node, i );
  4530. }
  4531. if ( hasScripts ) {
  4532. doc = scripts[ scripts.length - 1 ].ownerDocument;
  4533. // Reenable scripts
  4534. jQuery.map( scripts, restoreScript );
  4535. // Evaluate executable scripts on first document insertion
  4536. for ( i = 0; i < hasScripts; i++ ) {
  4537. node = scripts[ i ];
  4538. if ( rscriptType.test( node.type || "" ) &&
  4539. !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
  4540. if ( node.src ) {
  4541. // Optional AJAX dependency, but won't run scripts if not present
  4542. if ( jQuery._evalUrl ) {
  4543. jQuery._evalUrl( node.src );
  4544. }
  4545. } else {
  4546. jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
  4547. }
  4548. }
  4549. }
  4550. }
  4551. }
  4552. }
  4553. return this;
  4554. }
  4555. });
  4556. jQuery.each({
  4557. appendTo: "append",
  4558. prependTo: "prepend",
  4559. insertBefore: "before",
  4560. insertAfter: "after",
  4561. replaceAll: "replaceWith"
  4562. }, function( name, original ) {
  4563. jQuery.fn[ name ] = function( selector ) {
  4564. var elems,
  4565. ret = [],
  4566. insert = jQuery( selector ),
  4567. last = insert.length - 1,
  4568. i = 0;
  4569. for ( ; i <= last; i++ ) {
  4570. elems = i === last ? this : this.clone( true );
  4571. jQuery( insert[ i ] )[ original ]( elems );
  4572. // Support: QtWebKit
  4573. // .get() because push.apply(_, arraylike) throws
  4574. push.apply( ret, elems.get() );
  4575. }
  4576. return this.pushStack( ret );
  4577. };
  4578. });
  4579. var iframe,
  4580. elemdisplay = {};
  4581. /**
  4582. * Retrieve the actual display of a element
  4583. * @param {String} name nodeName of the element
  4584. * @param {Object} doc Document object
  4585. */
  4586. // Called only from within defaultDisplay
  4587. function actualDisplay( name, doc ) {
  4588. var style,
  4589. elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
  4590. // getDefaultComputedStyle might be reliably used only on attached element
  4591. display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
  4592. // Use of this method is a temporary fix (more like optmization) until something better comes along,
  4593. // since it was removed from specification and supported only in FF
  4594. style.display : jQuery.css( elem[ 0 ], "display" );
  4595. // We don't have any data stored on the element,
  4596. // so use "detach" method as fast way to get rid of the element
  4597. elem.detach();
  4598. return display;
  4599. }
  4600. /**
  4601. * Try to determine the default display value of an element
  4602. * @param {String} nodeName
  4603. */
  4604. function defaultDisplay( nodeName ) {
  4605. var doc = document,
  4606. display = elemdisplay[ nodeName ];
  4607. if ( !display ) {
  4608. display = actualDisplay( nodeName, doc );
  4609. // If the simple way fails, read from inside an iframe
  4610. if ( display === "none" || !display ) {
  4611. // Use the already-created iframe if possible
  4612. iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
  4613. // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
  4614. doc = iframe[ 0 ].contentDocument;
  4615. // Support: IE
  4616. doc.write();
  4617. doc.close();
  4618. display = actualDisplay( nodeName, doc );
  4619. iframe.detach();
  4620. }
  4621. // Store the correct default display
  4622. elemdisplay[ nodeName ] = display;
  4623. }
  4624. return display;
  4625. }
  4626. var rmargin = (/^margin/);
  4627. var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
  4628. var getStyles = function( elem ) {
  4629. return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
  4630. };
  4631. function curCSS( elem, name, computed ) {
  4632. var width, minWidth, maxWidth, ret,
  4633. style = elem.style;
  4634. computed = computed || getStyles( elem );
  4635. // Support: IE9
  4636. // getPropertyValue is only needed for .css('filter') in IE9, see #12537
  4637. if ( computed ) {
  4638. ret = computed.getPropertyValue( name ) || computed[ name ];
  4639. }
  4640. if ( computed ) {
  4641. if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
  4642. ret = jQuery.style( elem, name );
  4643. }
  4644. // Support: iOS < 6
  4645. // A tribute to the "awesome hack by Dean Edwards"
  4646. // iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
  4647. // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
  4648. if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
  4649. // Remember the original values
  4650. width = style.width;
  4651. minWidth = style.minWidth;
  4652. maxWidth = style.maxWidth;
  4653. // Put in the new values to get a computed value out
  4654. style.minWidth = style.maxWidth = style.width = ret;
  4655. ret = computed.width;
  4656. // Revert the changed values
  4657. style.width = width;
  4658. style.minWidth = minWidth;
  4659. style.maxWidth = maxWidth;
  4660. }
  4661. }
  4662. return ret !== undefined ?
  4663. // Support: IE
  4664. // IE returns zIndex value as an integer.
  4665. ret + "" :
  4666. ret;
  4667. }
  4668. function addGetHookIf( conditionFn, hookFn ) {
  4669. // Define the hook, we'll check on the first run if it's really needed.
  4670. return {
  4671. get: function() {
  4672. if ( conditionFn() ) {
  4673. // Hook not needed (or it's not possible to use it due to missing dependency),
  4674. // remove it.
  4675. // Since there are no other hooks for marginRight, remove the whole object.
  4676. delete this.get;
  4677. return;
  4678. }
  4679. // Hook needed; redefine it so that the support test is not executed again.
  4680. return (this.get = hookFn).apply( this, arguments );
  4681. }
  4682. };
  4683. }
  4684. (function() {
  4685. var pixelPositionVal, boxSizingReliableVal,
  4686. docElem = document.documentElement,
  4687. container = document.createElement( "div" ),
  4688. div = document.createElement( "div" );
  4689. if ( !div.style ) {
  4690. return;
  4691. }
  4692. div.style.backgroundClip = "content-box";
  4693. div.cloneNode( true ).style.backgroundClip = "";
  4694. support.clearCloneStyle = div.style.backgroundClip === "content-box";
  4695. container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
  4696. "position:absolute";
  4697. container.appendChild( div );
  4698. // Executing both pixelPosition & boxSizingReliable tests require only one layout
  4699. // so they're executed at the same time to save the second computation.
  4700. function computePixelPositionAndBoxSizingReliable() {
  4701. div.style.cssText =
  4702. // Support: Firefox<29, Android 2.3
  4703. // Vendor-prefix box-sizing
  4704. "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
  4705. "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
  4706. "border:1px;padding:1px;width:4px;position:absolute";
  4707. div.innerHTML = "";
  4708. docElem.appendChild( container );
  4709. var divStyle = window.getComputedStyle( div, null );
  4710. pixelPositionVal = divStyle.top !== "1%";
  4711. boxSizingReliableVal = divStyle.width === "4px";
  4712. docElem.removeChild( container );
  4713. }
  4714. // Support: node.js jsdom
  4715. // Don't assume that getComputedStyle is a property of the global object
  4716. if ( window.getComputedStyle ) {
  4717. jQuery.extend( support, {
  4718. pixelPosition: function() {
  4719. // This test is executed only once but we still do memoizing
  4720. // since we can use the boxSizingReliable pre-computing.
  4721. // No need to check if the test was already performed, though.
  4722. computePixelPositionAndBoxSizingReliable();
  4723. return pixelPositionVal;
  4724. },
  4725. boxSizingReliable: function() {
  4726. if ( boxSizingReliableVal == null ) {
  4727. computePixelPositionAndBoxSizingReliable();
  4728. }
  4729. return boxSizingReliableVal;
  4730. },
  4731. reliableMarginRight: function() {
  4732. // Support: Android 2.3
  4733. // Check if div with explicit width and no margin-right incorrectly
  4734. // gets computed margin-right based on width of container. (#3333)
  4735. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  4736. // This support function is only executed once so no memoizing is needed.
  4737. var ret,
  4738. marginDiv = div.appendChild( document.createElement( "div" ) );
  4739. // Reset CSS: box-sizing; display; margin; border; padding
  4740. marginDiv.style.cssText = div.style.cssText =
  4741. // Support: Firefox<29, Android 2.3
  4742. // Vendor-prefix box-sizing
  4743. "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
  4744. "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
  4745. marginDiv.style.marginRight = marginDiv.style.width = "0";
  4746. div.style.width = "1px";
  4747. docElem.appendChild( container );
  4748. ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
  4749. docElem.removeChild( container );
  4750. return ret;
  4751. }
  4752. });
  4753. }
  4754. })();
  4755. // A method for quickly swapping in/out CSS properties to get correct calculations.
  4756. jQuery.swap = function( elem, options, callback, args ) {
  4757. var ret, name,
  4758. old = {};
  4759. // Remember the old values, and insert the new ones
  4760. for ( name in options ) {
  4761. old[ name ] = elem.style[ name ];
  4762. elem.style[ name ] = options[ name ];
  4763. }
  4764. ret = callback.apply( elem, args || [] );
  4765. // Revert the old values
  4766. for ( name in options ) {
  4767. elem.style[ name ] = old[ name ];
  4768. }
  4769. return ret;
  4770. };
  4771. var
  4772. // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
  4773. // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
  4774. rdisplayswap = /^(none|table(?!-c[ea]).+)/,
  4775. rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
  4776. rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
  4777. cssShow = { position: "absolute", visibility: "hidden", display: "block" },
  4778. cssNormalTransform = {
  4779. letterSpacing: "0",
  4780. fontWeight: "400"
  4781. },
  4782. cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
  4783. // return a css property mapped to a potentially vendor prefixed property
  4784. function vendorPropName( style, name ) {
  4785. // shortcut for names that are not vendor prefixed
  4786. if ( name in style ) {
  4787. return name;
  4788. }
  4789. // check for vendor prefixed names
  4790. var capName = name[0].toUpperCase() + name.slice(1),
  4791. origName = name,
  4792. i = cssPrefixes.length;
  4793. while ( i-- ) {
  4794. name = cssPrefixes[ i ] + capName;
  4795. if ( name in style ) {
  4796. return name;
  4797. }
  4798. }
  4799. return origName;
  4800. }
  4801. function setPositiveNumber( elem, value, subtract ) {
  4802. var matches = rnumsplit.exec( value );
  4803. return matches ?
  4804. // Guard against undefined "subtract", e.g., when used as in cssHooks
  4805. Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
  4806. value;
  4807. }
  4808. function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  4809. var i = extra === ( isBorderBox ? "border" : "content" ) ?
  4810. // If we already have the right measurement, avoid augmentation
  4811. 4 :
  4812. // Otherwise initialize for horizontal or vertical properties
  4813. name === "width" ? 1 : 0,
  4814. val = 0;
  4815. for ( ; i < 4; i += 2 ) {
  4816. // both box models exclude margin, so add it if we want it
  4817. if ( extra === "margin" ) {
  4818. val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
  4819. }
  4820. if ( isBorderBox ) {
  4821. // border-box includes padding, so remove it if we want content
  4822. if ( extra === "content" ) {
  4823. val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  4824. }
  4825. // at this point, extra isn't border nor margin, so remove border
  4826. if ( extra !== "margin" ) {
  4827. val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  4828. }
  4829. } else {
  4830. // at this point, extra isn't content, so add padding
  4831. val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  4832. // at this point, extra isn't content nor padding, so add border
  4833. if ( extra !== "padding" ) {
  4834. val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  4835. }
  4836. }
  4837. }
  4838. return val;
  4839. }
  4840. function getWidthOrHeight( elem, name, extra ) {
  4841. // Start with offset property, which is equivalent to the border-box value
  4842. var valueIsBorderBox = true,
  4843. val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
  4844. styles = getStyles( elem ),
  4845. isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
  4846. // some non-html elements return undefined for offsetWidth, so check for null/undefined
  4847. // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
  4848. // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
  4849. if ( val <= 0 || val == null ) {
  4850. // Fall back to computed then uncomputed css if necessary
  4851. val = curCSS( elem, name, styles );
  4852. if ( val < 0 || val == null ) {
  4853. val = elem.style[ name ];
  4854. }
  4855. // Computed unit is not pixels. Stop here and return.
  4856. if ( rnumnonpx.test(val) ) {
  4857. return val;
  4858. }
  4859. // we need the check for style in case a browser which returns unreliable values
  4860. // for getComputedStyle silently falls back to the reliable elem.style
  4861. valueIsBorderBox = isBorderBox &&
  4862. ( support.boxSizingReliable() || val === elem.style[ name ] );
  4863. // Normalize "", auto, and prepare for extra
  4864. val = parseFloat( val ) || 0;
  4865. }
  4866. // use the active box-sizing model to add/subtract irrelevant styles
  4867. return ( val +
  4868. augmentWidthOrHeight(
  4869. elem,
  4870. name,
  4871. extra || ( isBorderBox ? "border" : "content" ),
  4872. valueIsBorderBox,
  4873. styles
  4874. )
  4875. ) + "px";
  4876. }
  4877. function showHide( elements, show ) {
  4878. var display, elem, hidden,
  4879. values = [],
  4880. index = 0,
  4881. length = elements.length;
  4882. for ( ; index < length; index++ ) {
  4883. elem = elements[ index ];
  4884. if ( !elem.style ) {
  4885. continue;
  4886. }
  4887. values[ index ] = data_priv.get( elem, "olddisplay" );
  4888. display = elem.style.display;
  4889. if ( show ) {
  4890. // Reset the inline display of this element to learn if it is
  4891. // being hidden by cascaded rules or not
  4892. if ( !values[ index ] && display === "none" ) {
  4893. elem.style.display = "";
  4894. }
  4895. // Set elements which have been overridden with display: none
  4896. // in a stylesheet to whatever the default browser style is
  4897. // for such an element
  4898. if ( elem.style.display === "" && isHidden( elem ) ) {
  4899. values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
  4900. }
  4901. } else {
  4902. hidden = isHidden( elem );
  4903. if ( display !== "none" || !hidden ) {
  4904. data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
  4905. }
  4906. }
  4907. }
  4908. // Set the display of most of the elements in a second loop
  4909. // to avoid the constant reflow
  4910. for ( index = 0; index < length; index++ ) {
  4911. elem = elements[ index ];
  4912. if ( !elem.style ) {
  4913. continue;
  4914. }
  4915. if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
  4916. elem.style.display = show ? values[ index ] || "" : "none";
  4917. }
  4918. }
  4919. return elements;
  4920. }
  4921. jQuery.extend({
  4922. // Add in style property hooks for overriding the default
  4923. // behavior of getting and setting a style property
  4924. cssHooks: {
  4925. opacity: {
  4926. get: function( elem, computed ) {
  4927. if ( computed ) {
  4928. // We should always get a number back from opacity
  4929. var ret = curCSS( elem, "opacity" );
  4930. return ret === "" ? "1" : ret;
  4931. }
  4932. }
  4933. }
  4934. },
  4935. // Don't automatically add "px" to these possibly-unitless properties
  4936. cssNumber: {
  4937. "columnCount": true,
  4938. "fillOpacity": true,
  4939. "flexGrow": true,
  4940. "flexShrink": true,
  4941. "fontWeight": true,
  4942. "lineHeight": true,
  4943. "opacity": true,
  4944. "order": true,
  4945. "orphans": true,
  4946. "widows": true,
  4947. "zIndex": true,
  4948. "zoom": true
  4949. },
  4950. // Add in properties whose names you wish to fix before
  4951. // setting or getting the value
  4952. cssProps: {
  4953. // normalize float css property
  4954. "float": "cssFloat"
  4955. },
  4956. // Get and set the style property on a DOM Node
  4957. style: function( elem, name, value, extra ) {
  4958. // Don't set styles on text and comment nodes
  4959. if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
  4960. return;
  4961. }
  4962. // Make sure that we're working with the right name
  4963. var ret, type, hooks,
  4964. origName = jQuery.camelCase( name ),
  4965. style = elem.style;
  4966. name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
  4967. // gets hook for the prefixed version
  4968. // followed by the unprefixed version
  4969. hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  4970. // Check if we're setting a value
  4971. if ( value !== undefined ) {
  4972. type = typeof value;
  4973. // convert relative number strings (+= or -=) to relative numbers. #7345
  4974. if ( type === "string" && (ret = rrelNum.exec( value )) ) {
  4975. value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
  4976. // Fixes bug #9237
  4977. type = "number";
  4978. }
  4979. // Make sure that null and NaN values aren't set. See: #7116
  4980. if ( value == null || value !== value ) {
  4981. return;
  4982. }
  4983. // If a number was passed in, add 'px' to the (except for certain CSS properties)
  4984. if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
  4985. value += "px";
  4986. }
  4987. // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
  4988. // but it would mean to define eight (for every problematic property) identical functions
  4989. if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
  4990. style[ name ] = "inherit";
  4991. }
  4992. // If a hook was provided, use that value, otherwise just set the specified value
  4993. if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
  4994. style[ name ] = value;
  4995. }
  4996. } else {
  4997. // If a hook was provided get the non-computed value from there
  4998. if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
  4999. return ret;
  5000. }
  5001. // Otherwise just get the value from the style object
  5002. return style[ name ];
  5003. }
  5004. },
  5005. css: function( elem, name, extra, styles ) {
  5006. var val, num, hooks,
  5007. origName = jQuery.camelCase( name );
  5008. // Make sure that we're working with the right name
  5009. name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
  5010. // gets hook for the prefixed version
  5011. // followed by the unprefixed version
  5012. hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  5013. // If a hook was provided get the computed value from there
  5014. if ( hooks && "get" in hooks ) {
  5015. val = hooks.get( elem, true, extra );
  5016. }
  5017. // Otherwise, if a way to get the computed value exists, use that
  5018. if ( val === undefined ) {
  5019. val = curCSS( elem, name, styles );
  5020. }
  5021. //convert "normal" to computed value
  5022. if ( val === "normal" && name in cssNormalTransform ) {
  5023. val = cssNormalTransform[ name ];
  5024. }
  5025. // Return, converting to number if forced or a qualifier was provided and val looks numeric
  5026. if ( extra === "" || extra ) {
  5027. num = parseFloat( val );
  5028. return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
  5029. }
  5030. return val;
  5031. }
  5032. });
  5033. jQuery.each([ "height", "width" ], function( i, name ) {
  5034. jQuery.cssHooks[ name ] = {
  5035. get: function( elem, computed, extra ) {
  5036. if ( computed ) {
  5037. // certain elements can have dimension info if we invisibly show them
  5038. // however, it must have a current display style that would benefit from this
  5039. return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
  5040. jQuery.swap( elem, cssShow, function() {
  5041. return getWidthOrHeight( elem, name, extra );
  5042. }) :
  5043. getWidthOrHeight( elem, name, extra );
  5044. }
  5045. },
  5046. set: function( elem, value, extra ) {
  5047. var styles = extra && getStyles( elem );
  5048. return setPositiveNumber( elem, value, extra ?
  5049. augmentWidthOrHeight(
  5050. elem,
  5051. name,
  5052. extra,
  5053. jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
  5054. styles
  5055. ) : 0
  5056. );
  5057. }
  5058. };
  5059. });
  5060. // Support: Android 2.3
  5061. jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
  5062. function( elem, computed ) {
  5063. if ( computed ) {
  5064. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  5065. // Work around by temporarily setting element display to inline-block
  5066. return jQuery.swap( elem, { "display": "inline-block" },
  5067. curCSS, [ elem, "marginRight" ] );
  5068. }
  5069. }
  5070. );
  5071. // These hooks are used by animate to expand properties
  5072. jQuery.each({
  5073. margin: "",
  5074. padding: "",
  5075. border: "Width"
  5076. }, function( prefix, suffix ) {
  5077. jQuery.cssHooks[ prefix + suffix ] = {
  5078. expand: function( value ) {
  5079. var i = 0,
  5080. expanded = {},
  5081. // assumes a single number if not a string
  5082. parts = typeof value === "string" ? value.split(" ") : [ value ];
  5083. for ( ; i < 4; i++ ) {
  5084. expanded[ prefix + cssExpand[ i ] + suffix ] =
  5085. parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
  5086. }
  5087. return expanded;
  5088. }
  5089. };
  5090. if ( !rmargin.test( prefix ) ) {
  5091. jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
  5092. }
  5093. });
  5094. jQuery.fn.extend({
  5095. css: function( name, value ) {
  5096. return access( this, function( elem, name, value ) {
  5097. var styles, len,
  5098. map = {},
  5099. i = 0;
  5100. if ( jQuery.isArray( name ) ) {
  5101. styles = getStyles( elem );
  5102. len = name.length;
  5103. for ( ; i < len; i++ ) {
  5104. map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
  5105. }
  5106. return map;
  5107. }
  5108. return value !== undefined ?
  5109. jQuery.style( elem, name, value ) :
  5110. jQuery.css( elem, name );
  5111. }, name, value, arguments.length > 1 );
  5112. },
  5113. show: function() {
  5114. return showHide( this, true );
  5115. },
  5116. hide: function() {
  5117. return showHide( this );
  5118. },
  5119. toggle: function( state ) {
  5120. if ( typeof state === "boolean" ) {
  5121. return state ? this.show() : this.hide();
  5122. }
  5123. return this.each(function() {
  5124. if ( isHidden( this ) ) {
  5125. jQuery( this ).show();
  5126. } else {
  5127. jQuery( this ).hide();
  5128. }
  5129. });
  5130. }
  5131. });
  5132. function Tween( elem, options, prop, end, easing ) {
  5133. return new Tween.prototype.init( elem, options, prop, end, easing );
  5134. }
  5135. jQuery.Tween = Tween;
  5136. Tween.prototype = {
  5137. constructor: Tween,
  5138. init: function( elem, options, prop, end, easing, unit ) {
  5139. this.elem = elem;
  5140. this.prop = prop;
  5141. this.easing = easing || "swing";
  5142. this.options = options;
  5143. this.start = this.now = this.cur();
  5144. this.end = end;
  5145. this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
  5146. },
  5147. cur: function() {
  5148. var hooks = Tween.propHooks[ this.prop ];
  5149. return hooks && hooks.get ?
  5150. hooks.get( this ) :
  5151. Tween.propHooks._default.get( this );
  5152. },
  5153. run: function( percent ) {
  5154. var eased,
  5155. hooks = Tween.propHooks[ this.prop ];
  5156. if ( this.options.duration ) {
  5157. this.pos = eased = jQuery.easing[ this.easing ](
  5158. percent, this.options.duration * percent, 0, 1, this.options.duration
  5159. );
  5160. } else {
  5161. this.pos = eased = percent;
  5162. }
  5163. this.now = ( this.end - this.start ) * eased + this.start;
  5164. if ( this.options.step ) {
  5165. this.options.step.call( this.elem, this.now, this );
  5166. }
  5167. if ( hooks && hooks.set ) {
  5168. hooks.set( this );
  5169. } else {
  5170. Tween.propHooks._default.set( this );
  5171. }
  5172. return this;
  5173. }
  5174. };
  5175. Tween.prototype.init.prototype = Tween.prototype;
  5176. Tween.propHooks = {
  5177. _default: {
  5178. get: function( tween ) {
  5179. var result;
  5180. if ( tween.elem[ tween.prop ] != null &&
  5181. (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
  5182. return tween.elem[ tween.prop ];
  5183. }
  5184. // passing an empty string as a 3rd parameter to .css will automatically
  5185. // attempt a parseFloat and fallback to a string if the parse fails
  5186. // so, simple values such as "10px" are parsed to Float.
  5187. // complex values such as "rotate(1rad)" are returned as is.
  5188. result = jQuery.css( tween.elem, tween.prop, "" );
  5189. // Empty strings, null, undefined and "auto" are converted to 0.
  5190. return !result || result === "auto" ? 0 : result;
  5191. },
  5192. set: function( tween ) {
  5193. // use step hook for back compat - use cssHook if its there - use .style if its
  5194. // available and use plain properties where available
  5195. if ( jQuery.fx.step[ tween.prop ] ) {
  5196. jQuery.fx.step[ tween.prop ]( tween );
  5197. } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
  5198. jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
  5199. } else {
  5200. tween.elem[ tween.prop ] = tween.now;
  5201. }
  5202. }
  5203. }
  5204. };
  5205. // Support: IE9
  5206. // Panic based approach to setting things on disconnected nodes
  5207. Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
  5208. set: function( tween ) {
  5209. if ( tween.elem.nodeType && tween.elem.parentNode ) {
  5210. tween.elem[ tween.prop ] = tween.now;
  5211. }
  5212. }
  5213. };
  5214. jQuery.easing = {
  5215. linear: function( p ) {
  5216. return p;
  5217. },
  5218. swing: function( p ) {
  5219. return 0.5 - Math.cos( p * Math.PI ) / 2;
  5220. }
  5221. };
  5222. jQuery.fx = Tween.prototype.init;
  5223. // Back Compat <1.8 extension point
  5224. jQuery.fx.step = {};
  5225. var
  5226. fxNow, timerId,
  5227. rfxtypes = /^(?:toggle|show|hide)$/,
  5228. rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
  5229. rrun = /queueHooks$/,
  5230. animationPrefilters = [ defaultPrefilter ],
  5231. tweeners = {
  5232. "*": [ function( prop, value ) {
  5233. var tween = this.createTween( prop, value ),
  5234. target = tween.cur(),
  5235. parts = rfxnum.exec( value ),
  5236. unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
  5237. // Starting value computation is required for potential unit mismatches
  5238. start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
  5239. rfxnum.exec( jQuery.css( tween.elem, prop ) ),
  5240. scale = 1,
  5241. maxIterations = 20;
  5242. if ( start && start[ 3 ] !== unit ) {
  5243. // Trust units reported by jQuery.css
  5244. unit = unit || start[ 3 ];
  5245. // Make sure we update the tween properties later on
  5246. parts = parts || [];
  5247. // Iteratively approximate from a nonzero starting point
  5248. start = +target || 1;
  5249. do {
  5250. // If previous iteration zeroed out, double until we get *something*
  5251. // Use a string for doubling factor so we don't accidentally see scale as unchanged below
  5252. scale = scale || ".5";
  5253. // Adjust and apply
  5254. start = start / scale;
  5255. jQuery.style( tween.elem, prop, start + unit );
  5256. // Update scale, tolerating zero or NaN from tween.cur()
  5257. // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
  5258. } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
  5259. }
  5260. // Update tween properties
  5261. if ( parts ) {
  5262. start = tween.start = +start || +target || 0;
  5263. tween.unit = unit;
  5264. // If a +=/-= token was provided, we're doing a relative animation
  5265. tween.end = parts[ 1 ] ?
  5266. start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
  5267. +parts[ 2 ];
  5268. }
  5269. return tween;
  5270. } ]
  5271. };
  5272. // Animations created synchronously will run synchronously
  5273. function createFxNow() {
  5274. setTimeout(function() {
  5275. fxNow = undefined;
  5276. });
  5277. return ( fxNow = jQuery.now() );
  5278. }
  5279. // Generate parameters to create a standard animation
  5280. function genFx( type, includeWidth ) {
  5281. var which,
  5282. i = 0,
  5283. attrs = { height: type };
  5284. // if we include width, step value is 1 to do all cssExpand values,
  5285. // if we don't include width, step value is 2 to skip over Left and Right
  5286. includeWidth = includeWidth ? 1 : 0;
  5287. for ( ; i < 4 ; i += 2 - includeWidth ) {
  5288. which = cssExpand[ i ];
  5289. attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
  5290. }
  5291. if ( includeWidth ) {
  5292. attrs.opacity = attrs.width = type;
  5293. }
  5294. return attrs;
  5295. }
  5296. function createTween( value, prop, animation ) {
  5297. var tween,
  5298. collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
  5299. index = 0,
  5300. length = collection.length;
  5301. for ( ; index < length; index++ ) {
  5302. if ( (tween = collection[ index ].call( animation, prop, value )) ) {
  5303. // we're done with this property
  5304. return tween;
  5305. }
  5306. }
  5307. }
  5308. function defaultPrefilter( elem, props, opts ) {
  5309. /* jshint validthis: true */
  5310. var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
  5311. anim = this,
  5312. orig = {},
  5313. style = elem.style,
  5314. hidden = elem.nodeType && isHidden( elem ),
  5315. dataShow = data_priv.get( elem, "fxshow" );
  5316. // handle queue: false promises
  5317. if ( !opts.queue ) {
  5318. hooks = jQuery._queueHooks( elem, "fx" );
  5319. if ( hooks.unqueued == null ) {
  5320. hooks.unqueued = 0;
  5321. oldfire = hooks.empty.fire;
  5322. hooks.empty.fire = function() {
  5323. if ( !hooks.unqueued ) {
  5324. oldfire();
  5325. }
  5326. };
  5327. }
  5328. hooks.unqueued++;
  5329. anim.always(function() {
  5330. // doing this makes sure that the complete handler will be called
  5331. // before this completes
  5332. anim.always(function() {
  5333. hooks.unqueued--;
  5334. if ( !jQuery.queue( elem, "fx" ).length ) {
  5335. hooks.empty.fire();
  5336. }
  5337. });
  5338. });
  5339. }
  5340. // height/width overflow pass
  5341. if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
  5342. // Make sure that nothing sneaks out
  5343. // Record all 3 overflow attributes because IE9-10 do not
  5344. // change the overflow attribute when overflowX and
  5345. // overflowY are set to the same value
  5346. opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
  5347. // Set display property to inline-block for height/width
  5348. // animations on inline elements that are having width/height animated
  5349. display = jQuery.css( elem, "display" );
  5350. // Test default display if display is currently "none"
  5351. checkDisplay = display === "none" ?
  5352. data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
  5353. if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
  5354. style.display = "inline-block";
  5355. }
  5356. }
  5357. if ( opts.overflow ) {
  5358. style.overflow = "hidden";
  5359. anim.always(function() {
  5360. style.overflow = opts.overflow[ 0 ];
  5361. style.overflowX = opts.overflow[ 1 ];
  5362. style.overflowY = opts.overflow[ 2 ];
  5363. });
  5364. }
  5365. // show/hide pass
  5366. for ( prop in props ) {
  5367. value = props[ prop ];
  5368. if ( rfxtypes.exec( value ) ) {
  5369. delete props[ prop ];
  5370. toggle = toggle || value === "toggle";
  5371. if ( value === ( hidden ? "hide" : "show" ) ) {
  5372. // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
  5373. if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
  5374. hidden = true;
  5375. } else {
  5376. continue;
  5377. }
  5378. }
  5379. orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
  5380. // Any non-fx value stops us from restoring the original display value
  5381. } else {
  5382. display = undefined;
  5383. }
  5384. }
  5385. if ( !jQuery.isEmptyObject( orig ) ) {
  5386. if ( dataShow ) {
  5387. if ( "hidden" in dataShow ) {
  5388. hidden = dataShow.hidden;
  5389. }
  5390. } else {
  5391. dataShow = data_priv.access( elem, "fxshow", {} );
  5392. }
  5393. // store state if its toggle - enables .stop().toggle() to "reverse"
  5394. if ( toggle ) {
  5395. dataShow.hidden = !hidden;
  5396. }
  5397. if ( hidden ) {
  5398. jQuery( elem ).show();
  5399. } else {
  5400. anim.done(function() {
  5401. jQuery( elem ).hide();
  5402. });
  5403. }
  5404. anim.done(function() {
  5405. var prop;
  5406. data_priv.remove( elem, "fxshow" );
  5407. for ( prop in orig ) {
  5408. jQuery.style( elem, prop, orig[ prop ] );
  5409. }
  5410. });
  5411. for ( prop in orig ) {
  5412. tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
  5413. if ( !( prop in dataShow ) ) {
  5414. dataShow[ prop ] = tween.start;
  5415. if ( hidden ) {
  5416. tween.end = tween.start;
  5417. tween.start = prop === "width" || prop === "height" ? 1 : 0;
  5418. }
  5419. }
  5420. }
  5421. // If this is a noop like .hide().hide(), restore an overwritten display value
  5422. } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
  5423. style.display = display;
  5424. }
  5425. }
  5426. function propFilter( props, specialEasing ) {
  5427. var index, name, easing, value, hooks;
  5428. // camelCase, specialEasing and expand cssHook pass
  5429. for ( index in props ) {
  5430. name = jQuery.camelCase( index );
  5431. easing = specialEasing[ name ];
  5432. value = props[ index ];
  5433. if ( jQuery.isArray( value ) ) {
  5434. easing = value[ 1 ];
  5435. value = props[ index ] = value[ 0 ];
  5436. }
  5437. if ( index !== name ) {
  5438. props[ name ] = value;
  5439. delete props[ index ];
  5440. }
  5441. hooks = jQuery.cssHooks[ name ];
  5442. if ( hooks && "expand" in hooks ) {
  5443. value = hooks.expand( value );
  5444. delete props[ name ];
  5445. // not quite $.extend, this wont overwrite keys already present.
  5446. // also - reusing 'index' from above because we have the correct "name"
  5447. for ( index in value ) {
  5448. if ( !( index in props ) ) {
  5449. props[ index ] = value[ index ];
  5450. specialEasing[ index ] = easing;
  5451. }
  5452. }
  5453. } else {
  5454. specialEasing[ name ] = easing;
  5455. }
  5456. }
  5457. }
  5458. function Animation( elem, properties, options ) {
  5459. var result,
  5460. stopped,
  5461. index = 0,
  5462. length = animationPrefilters.length,
  5463. deferred = jQuery.Deferred().always( function() {
  5464. // don't match elem in the :animated selector
  5465. delete tick.elem;
  5466. }),
  5467. tick = function() {
  5468. if ( stopped ) {
  5469. return false;
  5470. }
  5471. var currentTime = fxNow || createFxNow(),
  5472. remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
  5473. // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
  5474. temp = remaining / animation.duration || 0,
  5475. percent = 1 - temp,
  5476. index = 0,
  5477. length = animation.tweens.length;
  5478. for ( ; index < length ; index++ ) {
  5479. animation.tweens[ index ].run( percent );
  5480. }
  5481. deferred.notifyWith( elem, [ animation, percent, remaining ]);
  5482. if ( percent < 1 && length ) {
  5483. return remaining;
  5484. } else {
  5485. deferred.resolveWith( elem, [ animation ] );
  5486. return false;
  5487. }
  5488. },
  5489. animation = deferred.promise({
  5490. elem: elem,
  5491. props: jQuery.extend( {}, properties ),
  5492. opts: jQuery.extend( true, { specialEasing: {} }, options ),
  5493. originalProperties: properties,
  5494. originalOptions: options,
  5495. startTime: fxNow || createFxNow(),
  5496. duration: options.duration,
  5497. tweens: [],
  5498. createTween: function( prop, end ) {
  5499. var tween = jQuery.Tween( elem, animation.opts, prop, end,
  5500. animation.opts.specialEasing[ prop ] || animation.opts.easing );
  5501. animation.tweens.push( tween );
  5502. return tween;
  5503. },
  5504. stop: function( gotoEnd ) {
  5505. var index = 0,
  5506. // if we are going to the end, we want to run all the tweens
  5507. // otherwise we skip this part
  5508. length = gotoEnd ? animation.tweens.length : 0;
  5509. if ( stopped ) {
  5510. return this;
  5511. }
  5512. stopped = true;
  5513. for ( ; index < length ; index++ ) {
  5514. animation.tweens[ index ].run( 1 );
  5515. }
  5516. // resolve when we played the last frame
  5517. // otherwise, reject
  5518. if ( gotoEnd ) {
  5519. deferred.resolveWith( elem, [ animation, gotoEnd ] );
  5520. } else {
  5521. deferred.rejectWith( elem, [ animation, gotoEnd ] );
  5522. }
  5523. return this;
  5524. }
  5525. }),
  5526. props = animation.props;
  5527. propFilter( props, animation.opts.specialEasing );
  5528. for ( ; index < length ; index++ ) {
  5529. result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
  5530. if ( result ) {
  5531. return result;
  5532. }
  5533. }
  5534. jQuery.map( props, createTween, animation );
  5535. if ( jQuery.isFunction( animation.opts.start ) ) {
  5536. animation.opts.start.call( elem, animation );
  5537. }
  5538. jQuery.fx.timer(
  5539. jQuery.extend( tick, {
  5540. elem: elem,
  5541. anim: animation,
  5542. queue: animation.opts.queue
  5543. })
  5544. );
  5545. // attach callbacks from options
  5546. return animation.progress( animation.opts.progress )
  5547. .done( animation.opts.done, animation.opts.complete )
  5548. .fail( animation.opts.fail )
  5549. .always( animation.opts.always );
  5550. }
  5551. jQuery.Animation = jQuery.extend( Animation, {
  5552. tweener: function( props, callback ) {
  5553. if ( jQuery.isFunction( props ) ) {
  5554. callback = props;
  5555. props = [ "*" ];
  5556. } else {
  5557. props = props.split(" ");
  5558. }
  5559. var prop,
  5560. index = 0,
  5561. length = props.length;
  5562. for ( ; index < length ; index++ ) {
  5563. prop = props[ index ];
  5564. tweeners[ prop ] = tweeners[ prop ] || [];
  5565. tweeners[ prop ].unshift( callback );
  5566. }
  5567. },
  5568. prefilter: function( callback, prepend ) {
  5569. if ( prepend ) {
  5570. animationPrefilters.unshift( callback );
  5571. } else {
  5572. animationPrefilters.push( callback );
  5573. }
  5574. }
  5575. });
  5576. jQuery.speed = function( speed, easing, fn ) {
  5577. var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
  5578. complete: fn || !fn && easing ||
  5579. jQuery.isFunction( speed ) && speed,
  5580. duration: speed,
  5581. easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
  5582. };
  5583. opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
  5584. opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
  5585. // normalize opt.queue - true/undefined/null -> "fx"
  5586. if ( opt.queue == null || opt.queue === true ) {
  5587. opt.queue = "fx";
  5588. }
  5589. // Queueing
  5590. opt.old = opt.complete;
  5591. opt.complete = function() {
  5592. if ( jQuery.isFunction( opt.old ) ) {
  5593. opt.old.call( this );
  5594. }
  5595. if ( opt.queue ) {
  5596. jQuery.dequeue( this, opt.queue );
  5597. }
  5598. };
  5599. return opt;
  5600. };
  5601. jQuery.fn.extend({
  5602. fadeTo: function( speed, to, easing, callback ) {
  5603. // show any hidden elements after setting opacity to 0
  5604. return this.filter( isHidden ).css( "opacity", 0 ).show()
  5605. // animate to the value specified
  5606. .end().animate({ opacity: to }, speed, easing, callback );
  5607. },
  5608. animate: function( prop, speed, easing, callback ) {
  5609. var empty = jQuery.isEmptyObject( prop ),
  5610. optall = jQuery.speed( speed, easing, callback ),
  5611. doAnimation = function() {
  5612. // Operate on a copy of prop so per-property easing won't be lost
  5613. var anim = Animation( this, jQuery.extend( {}, prop ), optall );
  5614. // Empty animations, or finishing resolves immediately
  5615. if ( empty || data_priv.get( this, "finish" ) ) {
  5616. anim.stop( true );
  5617. }
  5618. };
  5619. doAnimation.finish = doAnimation;
  5620. return empty || optall.queue === false ?
  5621. this.each( doAnimation ) :
  5622. this.queue( optall.queue, doAnimation );
  5623. },
  5624. stop: function( type, clearQueue, gotoEnd ) {
  5625. var stopQueue = function( hooks ) {
  5626. var stop = hooks.stop;
  5627. delete hooks.stop;
  5628. stop( gotoEnd );
  5629. };
  5630. if ( typeof type !== "string" ) {
  5631. gotoEnd = clearQueue;
  5632. clearQueue = type;
  5633. type = undefined;
  5634. }
  5635. if ( clearQueue && type !== false ) {
  5636. this.queue( type || "fx", [] );
  5637. }
  5638. return this.each(function() {
  5639. var dequeue = true,
  5640. index = type != null && type + "queueHooks",
  5641. timers = jQuery.timers,
  5642. data = data_priv.get( this );
  5643. if ( index ) {
  5644. if ( data[ index ] && data[ index ].stop ) {
  5645. stopQueue( data[ index ] );
  5646. }
  5647. } else {
  5648. for ( index in data ) {
  5649. if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
  5650. stopQueue( data[ index ] );
  5651. }
  5652. }
  5653. }
  5654. for ( index = timers.length; index--; ) {
  5655. if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
  5656. timers[ index ].anim.stop( gotoEnd );
  5657. dequeue = false;
  5658. timers.splice( index, 1 );
  5659. }
  5660. }
  5661. // start the next in the queue if the last step wasn't forced
  5662. // timers currently will call their complete callbacks, which will dequeue
  5663. // but only if they were gotoEnd
  5664. if ( dequeue || !gotoEnd ) {
  5665. jQuery.dequeue( this, type );
  5666. }
  5667. });
  5668. },
  5669. finish: function( type ) {
  5670. if ( type !== false ) {
  5671. type = type || "fx";
  5672. }
  5673. return this.each(function() {
  5674. var index,
  5675. data = data_priv.get( this ),
  5676. queue = data[ type + "queue" ],
  5677. hooks = data[ type + "queueHooks" ],
  5678. timers = jQuery.timers,
  5679. length = queue ? queue.length : 0;
  5680. // enable finishing flag on private data
  5681. data.finish = true;
  5682. // empty the queue first
  5683. jQuery.queue( this, type, [] );
  5684. if ( hooks && hooks.stop ) {
  5685. hooks.stop.call( this, true );
  5686. }
  5687. // look for any active animations, and finish them
  5688. for ( index = timers.length; index--; ) {
  5689. if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
  5690. timers[ index ].anim.stop( true );
  5691. timers.splice( index, 1 );
  5692. }
  5693. }
  5694. // look for any animations in the old queue and finish them
  5695. for ( index = 0; index < length; index++ ) {
  5696. if ( queue[ index ] && queue[ index ].finish ) {
  5697. queue[ index ].finish.call( this );
  5698. }
  5699. }
  5700. // turn off finishing flag
  5701. delete data.finish;
  5702. });
  5703. }
  5704. });
  5705. jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
  5706. var cssFn = jQuery.fn[ name ];
  5707. jQuery.fn[ name ] = function( speed, easing, callback ) {
  5708. return speed == null || typeof speed === "boolean" ?
  5709. cssFn.apply( this, arguments ) :
  5710. this.animate( genFx( name, true ), speed, easing, callback );
  5711. };
  5712. });
  5713. // Generate shortcuts for custom animations
  5714. jQuery.each({
  5715. slideDown: genFx("show"),
  5716. slideUp: genFx("hide"),
  5717. slideToggle: genFx("toggle"),
  5718. fadeIn: { opacity: "show" },
  5719. fadeOut: { opacity: "hide" },
  5720. fadeToggle: { opacity: "toggle" }
  5721. }, function( name, props ) {
  5722. jQuery.fn[ name ] = function( speed, easing, callback ) {
  5723. return this.animate( props, speed, easing, callback );
  5724. };
  5725. });
  5726. jQuery.timers = [];
  5727. jQuery.fx.tick = function() {
  5728. var timer,
  5729. i = 0,
  5730. timers = jQuery.timers;
  5731. fxNow = jQuery.now();
  5732. for ( ; i < timers.length; i++ ) {
  5733. timer = timers[ i ];
  5734. // Checks the timer has not already been removed
  5735. if ( !timer() && timers[ i ] === timer ) {
  5736. timers.splice( i--, 1 );
  5737. }
  5738. }
  5739. if ( !timers.length ) {
  5740. jQuery.fx.stop();
  5741. }
  5742. fxNow = undefined;
  5743. };
  5744. jQuery.fx.timer = function( timer ) {
  5745. jQuery.timers.push( timer );
  5746. if ( timer() ) {
  5747. jQuery.fx.start();
  5748. } else {
  5749. jQuery.timers.pop();
  5750. }
  5751. };
  5752. jQuery.fx.interval = 13;
  5753. jQuery.fx.start = function() {
  5754. if ( !timerId ) {
  5755. timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
  5756. }
  5757. };
  5758. jQuery.fx.stop = function() {
  5759. clearInterval( timerId );
  5760. timerId = null;
  5761. };
  5762. jQuery.fx.speeds = {
  5763. slow: 600,
  5764. fast: 200,
  5765. // Default speed
  5766. _default: 400
  5767. };
  5768. // Based off of the plugin by Clint Helfers, with permission.
  5769. // http://blindsignals.com/index.php/2009/07/jquery-delay/
  5770. jQuery.fn.delay = function( time, type ) {
  5771. time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
  5772. type = type || "fx";
  5773. return this.queue( type, function( next, hooks ) {
  5774. var timeout = setTimeout( next, time );
  5775. hooks.stop = function() {
  5776. clearTimeout( timeout );
  5777. };
  5778. });
  5779. };
  5780. (function() {
  5781. var input = document.createElement( "input" ),
  5782. select = document.createElement( "select" ),
  5783. opt = select.appendChild( document.createElement( "option" ) );
  5784. input.type = "checkbox";
  5785. // Support: iOS 5.1, Android 4.x, Android 2.3
  5786. // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
  5787. support.checkOn = input.value !== "";
  5788. // Must access the parent to make an option select properly
  5789. // Support: IE9, IE10
  5790. support.optSelected = opt.selected;
  5791. // Make sure that the options inside disabled selects aren't marked as disabled
  5792. // (WebKit marks them as disabled)
  5793. select.disabled = true;
  5794. support.optDisabled = !opt.disabled;
  5795. // Check if an input maintains its value after becoming a radio
  5796. // Support: IE9, IE10
  5797. input = document.createElement( "input" );
  5798. input.value = "t";
  5799. input.type = "radio";
  5800. support.radioValue = input.value === "t";
  5801. })();
  5802. var nodeHook, boolHook,
  5803. attrHandle = jQuery.expr.attrHandle;
  5804. jQuery.fn.extend({
  5805. attr: function( name, value ) {
  5806. return access( this, jQuery.attr, name, value, arguments.length > 1 );
  5807. },
  5808. removeAttr: function( name ) {
  5809. return this.each(function() {
  5810. jQuery.removeAttr( this, name );
  5811. });
  5812. }
  5813. });
  5814. jQuery.extend({
  5815. attr: function( elem, name, value ) {
  5816. var hooks, ret,
  5817. nType = elem.nodeType;
  5818. // don't get/set attributes on text, comment and attribute nodes
  5819. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  5820. return;
  5821. }
  5822. // Fallback to prop when attributes are not supported
  5823. if ( typeof elem.getAttribute === strundefined ) {
  5824. return jQuery.prop( elem, name, value );
  5825. }
  5826. // All attributes are lowercase
  5827. // Grab necessary hook if one is defined
  5828. if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
  5829. name = name.toLowerCase();
  5830. hooks = jQuery.attrHooks[ name ] ||
  5831. ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
  5832. }
  5833. if ( value !== undefined ) {
  5834. if ( value === null ) {
  5835. jQuery.removeAttr( elem, name );
  5836. } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
  5837. return ret;
  5838. } else {
  5839. elem.setAttribute( name, value + "" );
  5840. return value;
  5841. }
  5842. } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
  5843. return ret;
  5844. } else {
  5845. ret = jQuery.find.attr( elem, name );
  5846. // Non-existent attributes return null, we normalize to undefined
  5847. return ret == null ?
  5848. undefined :
  5849. ret;
  5850. }
  5851. },
  5852. removeAttr: function( elem, value ) {
  5853. var name, propName,
  5854. i = 0,
  5855. attrNames = value && value.match( rnotwhite );
  5856. if ( attrNames && elem.nodeType === 1 ) {
  5857. while ( (name = attrNames[i++]) ) {
  5858. propName = jQuery.propFix[ name ] || name;
  5859. // Boolean attributes get special treatment (#10870)
  5860. if ( jQuery.expr.match.bool.test( name ) ) {
  5861. // Set corresponding property to false
  5862. elem[ propName ] = false;
  5863. }
  5864. elem.removeAttribute( name );
  5865. }
  5866. }
  5867. },
  5868. attrHooks: {
  5869. type: {
  5870. set: function( elem, value ) {
  5871. if ( !support.radioValue && value === "radio" &&
  5872. jQuery.nodeName( elem, "input" ) ) {
  5873. // Setting the type on a radio button after the value resets the value in IE6-9
  5874. // Reset value to default in case type is set after value during creation
  5875. var val = elem.value;
  5876. elem.setAttribute( "type", value );
  5877. if ( val ) {
  5878. elem.value = val;
  5879. }
  5880. return value;
  5881. }
  5882. }
  5883. }
  5884. }
  5885. });
  5886. // Hooks for boolean attributes
  5887. boolHook = {
  5888. set: function( elem, value, name ) {
  5889. if ( value === false ) {
  5890. // Remove boolean attributes when set to false
  5891. jQuery.removeAttr( elem, name );
  5892. } else {
  5893. elem.setAttribute( name, name );
  5894. }
  5895. return name;
  5896. }
  5897. };
  5898. jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
  5899. var getter = attrHandle[ name ] || jQuery.find.attr;
  5900. attrHandle[ name ] = function( elem, name, isXML ) {
  5901. var ret, handle;
  5902. if ( !isXML ) {
  5903. // Avoid an infinite loop by temporarily removing this function from the getter
  5904. handle = attrHandle[ name ];
  5905. attrHandle[ name ] = ret;
  5906. ret = getter( elem, name, isXML ) != null ?
  5907. name.toLowerCase() :
  5908. null;
  5909. attrHandle[ name ] = handle;
  5910. }
  5911. return ret;
  5912. };
  5913. });
  5914. var rfocusable = /^(?:input|select|textarea|button)$/i;
  5915. jQuery.fn.extend({
  5916. prop: function( name, value ) {
  5917. return access( this, jQuery.prop, name, value, arguments.length > 1 );
  5918. },
  5919. removeProp: function( name ) {
  5920. return this.each(function() {
  5921. delete this[ jQuery.propFix[ name ] || name ];
  5922. });
  5923. }
  5924. });
  5925. jQuery.extend({
  5926. propFix: {
  5927. "for": "htmlFor",
  5928. "class": "className"
  5929. },
  5930. prop: function( elem, name, value ) {
  5931. var ret, hooks, notxml,
  5932. nType = elem.nodeType;
  5933. // don't get/set properties on text, comment and attribute nodes
  5934. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  5935. return;
  5936. }
  5937. notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
  5938. if ( notxml ) {
  5939. // Fix name and attach hooks
  5940. name = jQuery.propFix[ name ] || name;
  5941. hooks = jQuery.propHooks[ name ];
  5942. }
  5943. if ( value !== undefined ) {
  5944. return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
  5945. ret :
  5946. ( elem[ name ] = value );
  5947. } else {
  5948. return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
  5949. ret :
  5950. elem[ name ];
  5951. }
  5952. },
  5953. propHooks: {
  5954. tabIndex: {
  5955. get: function( elem ) {
  5956. return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
  5957. elem.tabIndex :
  5958. -1;
  5959. }
  5960. }
  5961. }
  5962. });
  5963. // Support: IE9+
  5964. // Selectedness for an option in an optgroup can be inaccurate
  5965. if ( !support.optSelected ) {
  5966. jQuery.propHooks.selected = {
  5967. get: function( elem ) {
  5968. var parent = elem.parentNode;
  5969. if ( parent && parent.parentNode ) {
  5970. parent.parentNode.selectedIndex;
  5971. }
  5972. return null;
  5973. }
  5974. };
  5975. }
  5976. jQuery.each([
  5977. "tabIndex",
  5978. "readOnly",
  5979. "maxLength",
  5980. "cellSpacing",
  5981. "cellPadding",
  5982. "rowSpan",
  5983. "colSpan",
  5984. "useMap",
  5985. "frameBorder",
  5986. "contentEditable"
  5987. ], function() {
  5988. jQuery.propFix[ this.toLowerCase() ] = this;
  5989. });
  5990. var rclass = /[\t\r\n\f]/g;
  5991. jQuery.fn.extend({
  5992. addClass: function( value ) {
  5993. var classes, elem, cur, clazz, j, finalValue,
  5994. proceed = typeof value === "string" && value,
  5995. i = 0,
  5996. len = this.length;
  5997. if ( jQuery.isFunction( value ) ) {
  5998. return this.each(function( j ) {
  5999. jQuery( this ).addClass( value.call( this, j, this.className ) );
  6000. });
  6001. }
  6002. if ( proceed ) {
  6003. // The disjunction here is for better compressibility (see removeClass)
  6004. classes = ( value || "" ).match( rnotwhite ) || [];
  6005. for ( ; i < len; i++ ) {
  6006. elem = this[ i ];
  6007. cur = elem.nodeType === 1 && ( elem.className ?
  6008. ( " " + elem.className + " " ).replace( rclass, " " ) :
  6009. " "
  6010. );
  6011. if ( cur ) {
  6012. j = 0;
  6013. while ( (clazz = classes[j++]) ) {
  6014. if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
  6015. cur += clazz + " ";
  6016. }
  6017. }
  6018. // only assign if different to avoid unneeded rendering.
  6019. finalValue = jQuery.trim( cur );
  6020. if ( elem.className !== finalValue ) {
  6021. elem.className = finalValue;
  6022. }
  6023. }
  6024. }
  6025. }
  6026. return this;
  6027. },
  6028. removeClass: function( value ) {
  6029. var classes, elem, cur, clazz, j, finalValue,
  6030. proceed = arguments.length === 0 || typeof value === "string" && value,
  6031. i = 0,
  6032. len = this.length;
  6033. if ( jQuery.isFunction( value ) ) {
  6034. return this.each(function( j ) {
  6035. jQuery( this ).removeClass( value.call( this, j, this.className ) );
  6036. });
  6037. }
  6038. if ( proceed ) {
  6039. classes = ( value || "" ).match( rnotwhite ) || [];
  6040. for ( ; i < len; i++ ) {
  6041. elem = this[ i ];
  6042. // This expression is here for better compressibility (see addClass)
  6043. cur = elem.nodeType === 1 && ( elem.className ?
  6044. ( " " + elem.className + " " ).replace( rclass, " " ) :
  6045. ""
  6046. );
  6047. if ( cur ) {
  6048. j = 0;
  6049. while ( (clazz = classes[j++]) ) {
  6050. // Remove *all* instances
  6051. while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
  6052. cur = cur.replace( " " + clazz + " ", " " );
  6053. }
  6054. }
  6055. // only assign if different to avoid unneeded rendering.
  6056. finalValue = value ? jQuery.trim( cur ) : "";
  6057. if ( elem.className !== finalValue ) {
  6058. elem.className = finalValue;
  6059. }
  6060. }
  6061. }
  6062. }
  6063. return this;
  6064. },
  6065. toggleClass: function( value, stateVal ) {
  6066. var type = typeof value;
  6067. if ( typeof stateVal === "boolean" && type === "string" ) {
  6068. return stateVal ? this.addClass( value ) : this.removeClass( value );
  6069. }
  6070. if ( jQuery.isFunction( value ) ) {
  6071. return this.each(function( i ) {
  6072. jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
  6073. });
  6074. }
  6075. return this.each(function() {
  6076. if ( type === "string" ) {
  6077. // toggle individual class names
  6078. var className,
  6079. i = 0,
  6080. self = jQuery( this ),
  6081. classNames = value.match( rnotwhite ) || [];
  6082. while ( (className = classNames[ i++ ]) ) {
  6083. // check each className given, space separated list
  6084. if ( self.hasClass( className ) ) {
  6085. self.removeClass( className );
  6086. } else {
  6087. self.addClass( className );
  6088. }
  6089. }
  6090. // Toggle whole class name
  6091. } else if ( type === strundefined || type === "boolean" ) {
  6092. if ( this.className ) {
  6093. // store className if set
  6094. data_priv.set( this, "__className__", this.className );
  6095. }
  6096. // If the element has a class name or if we're passed "false",
  6097. // then remove the whole classname (if there was one, the above saved it).
  6098. // Otherwise bring back whatever was previously saved (if anything),
  6099. // falling back to the empty string if nothing was stored.
  6100. this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
  6101. }
  6102. });
  6103. },
  6104. hasClass: function( selector ) {
  6105. var className = " " + selector + " ",
  6106. i = 0,
  6107. l = this.length;
  6108. for ( ; i < l; i++ ) {
  6109. if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
  6110. return true;
  6111. }
  6112. }
  6113. return false;
  6114. }
  6115. });
  6116. var rreturn = /\r/g;
  6117. jQuery.fn.extend({
  6118. val: function( value ) {
  6119. var hooks, ret, isFunction,
  6120. elem = this[0];
  6121. if ( !arguments.length ) {
  6122. if ( elem ) {
  6123. hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
  6124. if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
  6125. return ret;
  6126. }
  6127. ret = elem.value;
  6128. return typeof ret === "string" ?
  6129. // handle most common string cases
  6130. ret.replace(rreturn, "") :
  6131. // handle cases where value is null/undef or number
  6132. ret == null ? "" : ret;
  6133. }
  6134. return;
  6135. }
  6136. isFunction = jQuery.isFunction( value );
  6137. return this.each(function( i ) {
  6138. var val;
  6139. if ( this.nodeType !== 1 ) {
  6140. return;
  6141. }
  6142. if ( isFunction ) {
  6143. val = value.call( this, i, jQuery( this ).val() );
  6144. } else {
  6145. val = value;
  6146. }
  6147. // Treat null/undefined as ""; convert numbers to string
  6148. if ( val == null ) {
  6149. val = "";
  6150. } else if ( typeof val === "number" ) {
  6151. val += "";
  6152. } else if ( jQuery.isArray( val ) ) {
  6153. val = jQuery.map( val, function( value ) {
  6154. return value == null ? "" : value + "";
  6155. });
  6156. }
  6157. hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
  6158. // If set returns undefined, fall back to normal setting
  6159. if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
  6160. this.value = val;
  6161. }
  6162. });
  6163. }
  6164. });
  6165. jQuery.extend({
  6166. valHooks: {
  6167. option: {
  6168. get: function( elem ) {
  6169. var val = jQuery.find.attr( elem, "value" );
  6170. return val != null ?
  6171. val :
  6172. // Support: IE10-11+
  6173. // option.text throws exceptions (#14686, #14858)
  6174. jQuery.trim( jQuery.text( elem ) );
  6175. }
  6176. },
  6177. select: {
  6178. get: function( elem ) {
  6179. var value, option,
  6180. options = elem.options,
  6181. index = elem.selectedIndex,
  6182. one = elem.type === "select-one" || index < 0,
  6183. values = one ? null : [],
  6184. max = one ? index + 1 : options.length,
  6185. i = index < 0 ?
  6186. max :
  6187. one ? index : 0;
  6188. // Loop through all the selected options
  6189. for ( ; i < max; i++ ) {
  6190. option = options[ i ];
  6191. // IE6-9 doesn't update selected after form reset (#2551)
  6192. if ( ( option.selected || i === index ) &&
  6193. // Don't return options that are disabled or in a disabled optgroup
  6194. ( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) &&
  6195. ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
  6196. // Get the specific value for the option
  6197. value = jQuery( option ).val();
  6198. // We don't need an array for one selects
  6199. if ( one ) {
  6200. return value;
  6201. }
  6202. // Multi-Selects return an array
  6203. values.push( value );
  6204. }
  6205. }
  6206. return values;
  6207. },
  6208. set: function( elem, value ) {
  6209. var optionSet, option,
  6210. options = elem.options,
  6211. values = jQuery.makeArray( value ),
  6212. i = options.length;
  6213. while ( i-- ) {
  6214. option = options[ i ];
  6215. if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
  6216. optionSet = true;
  6217. }
  6218. }
  6219. // force browsers to behave consistently when non-matching value is set
  6220. if ( !optionSet ) {
  6221. elem.selectedIndex = -1;
  6222. }
  6223. return values;
  6224. }
  6225. }
  6226. }
  6227. });
  6228. // Radios and checkboxes getter/setter
  6229. jQuery.each([ "radio", "checkbox" ], function() {
  6230. jQuery.valHooks[ this ] = {
  6231. set: function( elem, value ) {
  6232. if ( jQuery.isArray( value ) ) {
  6233. return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
  6234. }
  6235. }
  6236. };
  6237. if ( !support.checkOn ) {
  6238. jQuery.valHooks[ this ].get = function( elem ) {
  6239. // Support: Webkit
  6240. // "" is returned instead of "on" if a value isn't specified
  6241. return elem.getAttribute("value") === null ? "on" : elem.value;
  6242. };
  6243. }
  6244. });
  6245. // Return jQuery for attributes-only inclusion
  6246. jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
  6247. "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
  6248. "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
  6249. // Handle event binding
  6250. jQuery.fn[ name ] = function( data, fn ) {
  6251. return arguments.length > 0 ?
  6252. this.on( name, null, data, fn ) :
  6253. this.trigger( name );
  6254. };
  6255. });
  6256. jQuery.fn.extend({
  6257. hover: function( fnOver, fnOut ) {
  6258. return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
  6259. },
  6260. bind: function( types, data, fn ) {
  6261. return this.on( types, null, data, fn );
  6262. },
  6263. unbind: function( types, fn ) {
  6264. return this.off( types, null, fn );
  6265. },
  6266. delegate: function( selector, types, data, fn ) {
  6267. return this.on( types, selector, data, fn );
  6268. },
  6269. undelegate: function( selector, types, fn ) {
  6270. // ( namespace ) or ( selector, types [, fn] )
  6271. return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
  6272. }
  6273. });
  6274. var nonce = jQuery.now();
  6275. var rquery = (/\?/);
  6276. // Support: Android 2.3
  6277. // Workaround failure to string-cast null input
  6278. jQuery.parseJSON = function( data ) {
  6279. return JSON.parse( data + "" );
  6280. };
  6281. // Cross-browser xml parsing
  6282. jQuery.parseXML = function( data ) {
  6283. var xml, tmp;
  6284. if ( !data || typeof data !== "string" ) {
  6285. return null;
  6286. }
  6287. // Support: IE9
  6288. try {
  6289. tmp = new DOMParser();
  6290. xml = tmp.parseFromString( data, "text/xml" );
  6291. } catch ( e ) {
  6292. xml = undefined;
  6293. }
  6294. if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
  6295. jQuery.error( "Invalid XML: " + data );
  6296. }
  6297. return xml;
  6298. };
  6299. var
  6300. // Document location
  6301. ajaxLocParts,
  6302. ajaxLocation,
  6303. rhash = /#.*$/,
  6304. rts = /([?&])_=[^&]*/,
  6305. rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
  6306. // #7653, #8125, #8152: local protocol detection
  6307. rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
  6308. rnoContent = /^(?:GET|HEAD)$/,
  6309. rprotocol = /^\/\//,
  6310. rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
  6311. /* Prefilters
  6312. * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
  6313. * 2) These are called:
  6314. * - BEFORE asking for a transport
  6315. * - AFTER param serialization (s.data is a string if s.processData is true)
  6316. * 3) key is the dataType
  6317. * 4) the catchall symbol "*" can be used
  6318. * 5) execution will start with transport dataType and THEN continue down to "*" if needed
  6319. */
  6320. prefilters = {},
  6321. /* Transports bindings
  6322. * 1) key is the dataType
  6323. * 2) the catchall symbol "*" can be used
  6324. * 3) selection will start with transport dataType and THEN go to "*" if needed
  6325. */
  6326. transports = {},
  6327. // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
  6328. allTypes = "*/".concat("*");
  6329. // #8138, IE may throw an exception when accessing
  6330. // a field from window.location if document.domain has been set
  6331. try {
  6332. ajaxLocation = location.href;
  6333. } catch( e ) {
  6334. // Use the href attribute of an A element
  6335. // since IE will modify it given document.location
  6336. ajaxLocation = document.createElement( "a" );
  6337. ajaxLocation.href = "";
  6338. ajaxLocation = ajaxLocation.href;
  6339. }
  6340. // Segment location into parts
  6341. ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
  6342. // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
  6343. function addToPrefiltersOrTransports( structure ) {
  6344. // dataTypeExpression is optional and defaults to "*"
  6345. return function( dataTypeExpression, func ) {
  6346. if ( typeof dataTypeExpression !== "string" ) {
  6347. func = dataTypeExpression;
  6348. dataTypeExpression = "*";
  6349. }
  6350. var dataType,
  6351. i = 0,
  6352. dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
  6353. if ( jQuery.isFunction( func ) ) {
  6354. // For each dataType in the dataTypeExpression
  6355. while ( (dataType = dataTypes[i++]) ) {
  6356. // Prepend if requested
  6357. if ( dataType[0] === "+" ) {
  6358. dataType = dataType.slice( 1 ) || "*";
  6359. (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
  6360. // Otherwise append
  6361. } else {
  6362. (structure[ dataType ] = structure[ dataType ] || []).push( func );
  6363. }
  6364. }
  6365. }
  6366. };
  6367. }
  6368. // Base inspection function for prefilters and transports
  6369. function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
  6370. var inspected = {},
  6371. seekingTransport = ( structure === transports );
  6372. function inspect( dataType ) {
  6373. var selected;
  6374. inspected[ dataType ] = true;
  6375. jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
  6376. var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
  6377. if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
  6378. options.dataTypes.unshift( dataTypeOrTransport );
  6379. inspect( dataTypeOrTransport );
  6380. return false;
  6381. } else if ( seekingTransport ) {
  6382. return !( selected = dataTypeOrTransport );
  6383. }
  6384. });
  6385. return selected;
  6386. }
  6387. return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
  6388. }
  6389. // A special extend for ajax options
  6390. // that takes "flat" options (not to be deep extended)
  6391. // Fixes #9887
  6392. function ajaxExtend( target, src ) {
  6393. var key, deep,
  6394. flatOptions = jQuery.ajaxSettings.flatOptions || {};
  6395. for ( key in src ) {
  6396. if ( src[ key ] !== undefined ) {
  6397. ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
  6398. }
  6399. }
  6400. if ( deep ) {
  6401. jQuery.extend( true, target, deep );
  6402. }
  6403. return target;
  6404. }
  6405. /* Handles responses to an ajax request:
  6406. * - finds the right dataType (mediates between content-type and expected dataType)
  6407. * - returns the corresponding response
  6408. */
  6409. function ajaxHandleResponses( s, jqXHR, responses ) {
  6410. var ct, type, finalDataType, firstDataType,
  6411. contents = s.contents,
  6412. dataTypes = s.dataTypes;
  6413. // Remove auto dataType and get content-type in the process
  6414. while ( dataTypes[ 0 ] === "*" ) {
  6415. dataTypes.shift();
  6416. if ( ct === undefined ) {
  6417. ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
  6418. }
  6419. }
  6420. // Check if we're dealing with a known content-type
  6421. if ( ct ) {
  6422. for ( type in contents ) {
  6423. if ( contents[ type ] && contents[ type ].test( ct ) ) {
  6424. dataTypes.unshift( type );
  6425. break;
  6426. }
  6427. }
  6428. }
  6429. // Check to see if we have a response for the expected dataType
  6430. if ( dataTypes[ 0 ] in responses ) {
  6431. finalDataType = dataTypes[ 0 ];
  6432. } else {
  6433. // Try convertible dataTypes
  6434. for ( type in responses ) {
  6435. if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
  6436. finalDataType = type;
  6437. break;
  6438. }
  6439. if ( !firstDataType ) {
  6440. firstDataType = type;
  6441. }
  6442. }
  6443. // Or just use first one
  6444. finalDataType = finalDataType || firstDataType;
  6445. }
  6446. // If we found a dataType
  6447. // We add the dataType to the list if needed
  6448. // and return the corresponding response
  6449. if ( finalDataType ) {
  6450. if ( finalDataType !== dataTypes[ 0 ] ) {
  6451. dataTypes.unshift( finalDataType );
  6452. }
  6453. return responses[ finalDataType ];
  6454. }
  6455. }
  6456. /* Chain conversions given the request and the original response
  6457. * Also sets the responseXXX fields on the jqXHR instance
  6458. */
  6459. function ajaxConvert( s, response, jqXHR, isSuccess ) {
  6460. var conv2, current, conv, tmp, prev,
  6461. converters = {},
  6462. // Work with a copy of dataTypes in case we need to modify it for conversion
  6463. dataTypes = s.dataTypes.slice();
  6464. // Create converters map with lowercased keys
  6465. if ( dataTypes[ 1 ] ) {
  6466. for ( conv in s.converters ) {
  6467. converters[ conv.toLowerCase() ] = s.converters[ conv ];
  6468. }
  6469. }
  6470. current = dataTypes.shift();
  6471. // Convert to each sequential dataType
  6472. while ( current ) {
  6473. if ( s.responseFields[ current ] ) {
  6474. jqXHR[ s.responseFields[ current ] ] = response;
  6475. }
  6476. // Apply the dataFilter if provided
  6477. if ( !prev && isSuccess && s.dataFilter ) {
  6478. response = s.dataFilter( response, s.dataType );
  6479. }
  6480. prev = current;
  6481. current = dataTypes.shift();
  6482. if ( current ) {
  6483. // There's only work to do if current dataType is non-auto
  6484. if ( current === "*" ) {
  6485. current = prev;
  6486. // Convert response if prev dataType is non-auto and differs from current
  6487. } else if ( prev !== "*" && prev !== current ) {
  6488. // Seek a direct converter
  6489. conv = converters[ prev + " " + current ] || converters[ "* " + current ];
  6490. // If none found, seek a pair
  6491. if ( !conv ) {
  6492. for ( conv2 in converters ) {
  6493. // If conv2 outputs current
  6494. tmp = conv2.split( " " );
  6495. if ( tmp[ 1 ] === current ) {
  6496. // If prev can be converted to accepted input
  6497. conv = converters[ prev + " " + tmp[ 0 ] ] ||
  6498. converters[ "* " + tmp[ 0 ] ];
  6499. if ( conv ) {
  6500. // Condense equivalence converters
  6501. if ( conv === true ) {
  6502. conv = converters[ conv2 ];
  6503. // Otherwise, insert the intermediate dataType
  6504. } else if ( converters[ conv2 ] !== true ) {
  6505. current = tmp[ 0 ];
  6506. dataTypes.unshift( tmp[ 1 ] );
  6507. }
  6508. break;
  6509. }
  6510. }
  6511. }
  6512. }
  6513. // Apply converter (if not an equivalence)
  6514. if ( conv !== true ) {
  6515. // Unless errors are allowed to bubble, catch and return them
  6516. if ( conv && s[ "throws" ] ) {
  6517. response = conv( response );
  6518. } else {
  6519. try {
  6520. response = conv( response );
  6521. } catch ( e ) {
  6522. return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
  6523. }
  6524. }
  6525. }
  6526. }
  6527. }
  6528. }
  6529. return { state: "success", data: response };
  6530. }
  6531. jQuery.extend({
  6532. // Counter for holding the number of active queries
  6533. active: 0,
  6534. // Last-Modified header cache for next request
  6535. lastModified: {},
  6536. etag: {},
  6537. ajaxSettings: {
  6538. url: ajaxLocation,
  6539. type: "GET",
  6540. isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
  6541. global: true,
  6542. processData: true,
  6543. async: true,
  6544. contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  6545. /*
  6546. timeout: 0,
  6547. data: null,
  6548. dataType: null,
  6549. username: null,
  6550. password: null,
  6551. cache: null,
  6552. throws: false,
  6553. traditional: false,
  6554. headers: {},
  6555. */
  6556. accepts: {
  6557. "*": allTypes,
  6558. text: "text/plain",
  6559. html: "text/html",
  6560. xml: "application/xml, text/xml",
  6561. json: "application/json, text/javascript"
  6562. },
  6563. contents: {
  6564. xml: /xml/,
  6565. html: /html/,
  6566. json: /json/
  6567. },
  6568. responseFields: {
  6569. xml: "responseXML",
  6570. text: "responseText",
  6571. json: "responseJSON"
  6572. },
  6573. // Data converters
  6574. // Keys separate source (or catchall "*") and destination types with a single space
  6575. converters: {
  6576. // Convert anything to text
  6577. "* text": String,
  6578. // Text to html (true = no transformation)
  6579. "text html": true,
  6580. // Evaluate text as a json expression
  6581. "text json": jQuery.parseJSON,
  6582. // Parse text as xml
  6583. "text xml": jQuery.parseXML
  6584. },
  6585. // For options that shouldn't be deep extended:
  6586. // you can add your own custom options here if
  6587. // and when you create one that shouldn't be
  6588. // deep extended (see ajaxExtend)
  6589. flatOptions: {
  6590. url: true,
  6591. context: true
  6592. }
  6593. },
  6594. // Creates a full fledged settings object into target
  6595. // with both ajaxSettings and settings fields.
  6596. // If target is omitted, writes into ajaxSettings.
  6597. ajaxSetup: function( target, settings ) {
  6598. return settings ?
  6599. // Building a settings object
  6600. ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
  6601. // Extending ajaxSettings
  6602. ajaxExtend( jQuery.ajaxSettings, target );
  6603. },
  6604. ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
  6605. ajaxTransport: addToPrefiltersOrTransports( transports ),
  6606. // Main method
  6607. ajax: function( url, options ) {
  6608. // If url is an object, simulate pre-1.5 signature
  6609. if ( typeof url === "object" ) {
  6610. options = url;
  6611. url = undefined;
  6612. }
  6613. // Force options to be an object
  6614. options = options || {};
  6615. var transport,
  6616. // URL without anti-cache param
  6617. cacheURL,
  6618. // Response headers
  6619. responseHeadersString,
  6620. responseHeaders,
  6621. // timeout handle
  6622. timeoutTimer,
  6623. // Cross-domain detection vars
  6624. parts,
  6625. // To know if global events are to be dispatched
  6626. fireGlobals,
  6627. // Loop variable
  6628. i,
  6629. // Create the final options object
  6630. s = jQuery.ajaxSetup( {}, options ),
  6631. // Callbacks context
  6632. callbackContext = s.context || s,
  6633. // Context for global events is callbackContext if it is a DOM node or jQuery collection
  6634. globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
  6635. jQuery( callbackContext ) :
  6636. jQuery.event,
  6637. // Deferreds
  6638. deferred = jQuery.Deferred(),
  6639. completeDeferred = jQuery.Callbacks("once memory"),
  6640. // Status-dependent callbacks
  6641. statusCode = s.statusCode || {},
  6642. // Headers (they are sent all at once)
  6643. requestHeaders = {},
  6644. requestHeadersNames = {},
  6645. // The jqXHR state
  6646. state = 0,
  6647. // Default abort message
  6648. strAbort = "canceled",
  6649. // Fake xhr
  6650. jqXHR = {
  6651. readyState: 0,
  6652. // Builds headers hashtable if needed
  6653. getResponseHeader: function( key ) {
  6654. var match;
  6655. if ( state === 2 ) {
  6656. if ( !responseHeaders ) {
  6657. responseHeaders = {};
  6658. while ( (match = rheaders.exec( responseHeadersString )) ) {
  6659. responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
  6660. }
  6661. }
  6662. match = responseHeaders[ key.toLowerCase() ];
  6663. }
  6664. return match == null ? null : match;
  6665. },
  6666. // Raw string
  6667. getAllResponseHeaders: function() {
  6668. return state === 2 ? responseHeadersString : null;
  6669. },
  6670. // Caches the header
  6671. setRequestHeader: function( name, value ) {
  6672. var lname = name.toLowerCase();
  6673. if ( !state ) {
  6674. name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
  6675. requestHeaders[ name ] = value;
  6676. }
  6677. return this;
  6678. },
  6679. // Overrides response content-type header
  6680. overrideMimeType: function( type ) {
  6681. if ( !state ) {
  6682. s.mimeType = type;
  6683. }
  6684. return this;
  6685. },
  6686. // Status-dependent callbacks
  6687. statusCode: function( map ) {
  6688. var code;
  6689. if ( map ) {
  6690. if ( state < 2 ) {
  6691. for ( code in map ) {
  6692. // Lazy-add the new callback in a way that preserves old ones
  6693. statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
  6694. }
  6695. } else {
  6696. // Execute the appropriate callbacks
  6697. jqXHR.always( map[ jqXHR.status ] );
  6698. }
  6699. }
  6700. return this;
  6701. },
  6702. // Cancel the request
  6703. abort: function( statusText ) {
  6704. var finalText = statusText || strAbort;
  6705. if ( transport ) {
  6706. transport.abort( finalText );
  6707. }
  6708. done( 0, finalText );
  6709. return this;
  6710. }
  6711. };
  6712. // Attach deferreds
  6713. deferred.promise( jqXHR ).complete = completeDeferred.add;
  6714. jqXHR.success = jqXHR.done;
  6715. jqXHR.error = jqXHR.fail;
  6716. // Remove hash character (#7531: and string promotion)
  6717. // Add protocol if not provided (prefilters might expect it)
  6718. // Handle falsy url in the settings object (#10093: consistency with old signature)
  6719. // We also use the url parameter if available
  6720. s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
  6721. .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
  6722. // Alias method option to type as per ticket #12004
  6723. s.type = options.method || options.type || s.method || s.type;
  6724. // Extract dataTypes list
  6725. s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
  6726. // A cross-domain request is in order when we have a protocol:host:port mismatch
  6727. if ( s.crossDomain == null ) {
  6728. parts = rurl.exec( s.url.toLowerCase() );
  6729. s.crossDomain = !!( parts &&
  6730. ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
  6731. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
  6732. ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
  6733. );
  6734. }
  6735. // Convert data if not already a string
  6736. if ( s.data && s.processData && typeof s.data !== "string" ) {
  6737. s.data = jQuery.param( s.data, s.traditional );
  6738. }
  6739. // Apply prefilters
  6740. inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
  6741. // If request was aborted inside a prefilter, stop there
  6742. if ( state === 2 ) {
  6743. return jqXHR;
  6744. }
  6745. // We can fire global events as of now if asked to
  6746. fireGlobals = s.global;
  6747. // Watch for a new set of requests
  6748. if ( fireGlobals && jQuery.active++ === 0 ) {
  6749. jQuery.event.trigger("ajaxStart");
  6750. }
  6751. // Uppercase the type
  6752. s.type = s.type.toUpperCase();
  6753. // Determine if request has content
  6754. s.hasContent = !rnoContent.test( s.type );
  6755. // Save the URL in case we're toying with the If-Modified-Since
  6756. // and/or If-None-Match header later on
  6757. cacheURL = s.url;
  6758. // More options handling for requests with no content
  6759. if ( !s.hasContent ) {
  6760. // If data is available, append data to url
  6761. if ( s.data ) {
  6762. cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
  6763. // #9682: remove data so that it's not used in an eventual retry
  6764. delete s.data;
  6765. }
  6766. // Add anti-cache in url if needed
  6767. if ( s.cache === false ) {
  6768. s.url = rts.test( cacheURL ) ?
  6769. // If there is already a '_' parameter, set its value
  6770. cacheURL.replace( rts, "$1_=" + nonce++ ) :
  6771. // Otherwise add one to the end
  6772. cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
  6773. }
  6774. }
  6775. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  6776. if ( s.ifModified ) {
  6777. if ( jQuery.lastModified[ cacheURL ] ) {
  6778. jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
  6779. }
  6780. if ( jQuery.etag[ cacheURL ] ) {
  6781. jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
  6782. }
  6783. }
  6784. // Set the correct header, if data is being sent
  6785. if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
  6786. jqXHR.setRequestHeader( "Content-Type", s.contentType );
  6787. }
  6788. // Set the Accepts header for the server, depending on the dataType
  6789. jqXHR.setRequestHeader(
  6790. "Accept",
  6791. s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
  6792. s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
  6793. s.accepts[ "*" ]
  6794. );
  6795. // Check for headers option
  6796. for ( i in s.headers ) {
  6797. jqXHR.setRequestHeader( i, s.headers[ i ] );
  6798. }
  6799. // Allow custom headers/mimetypes and early abort
  6800. if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
  6801. // Abort if not done already and return
  6802. return jqXHR.abort();
  6803. }
  6804. // aborting is no longer a cancellation
  6805. strAbort = "abort";
  6806. // Install callbacks on deferreds
  6807. for ( i in { success: 1, error: 1, complete: 1 } ) {
  6808. jqXHR[ i ]( s[ i ] );
  6809. }
  6810. // Get transport
  6811. transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
  6812. // If no transport, we auto-abort
  6813. if ( !transport ) {
  6814. done( -1, "No Transport" );
  6815. } else {
  6816. jqXHR.readyState = 1;
  6817. // Send global event
  6818. if ( fireGlobals ) {
  6819. globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
  6820. }
  6821. // Timeout
  6822. if ( s.async && s.timeout > 0 ) {
  6823. timeoutTimer = setTimeout(function() {
  6824. jqXHR.abort("timeout");
  6825. }, s.timeout );
  6826. }
  6827. try {
  6828. state = 1;
  6829. transport.send( requestHeaders, done );
  6830. } catch ( e ) {
  6831. // Propagate exception as error if not done
  6832. if ( state < 2 ) {
  6833. done( -1, e );
  6834. // Simply rethrow otherwise
  6835. } else {
  6836. throw e;
  6837. }
  6838. }
  6839. }
  6840. // Callback for when everything is done
  6841. function done( status, nativeStatusText, responses, headers ) {
  6842. var isSuccess, success, error, response, modified,
  6843. statusText = nativeStatusText;
  6844. // Called once
  6845. if ( state === 2 ) {
  6846. return;
  6847. }
  6848. // State is "done" now
  6849. state = 2;
  6850. // Clear timeout if it exists
  6851. if ( timeoutTimer ) {
  6852. clearTimeout( timeoutTimer );
  6853. }
  6854. // Dereference transport for early garbage collection
  6855. // (no matter how long the jqXHR object will be used)
  6856. transport = undefined;
  6857. // Cache response headers
  6858. responseHeadersString = headers || "";
  6859. // Set readyState
  6860. jqXHR.readyState = status > 0 ? 4 : 0;
  6861. // Determine if successful
  6862. isSuccess = status >= 200 && status < 300 || status === 304;
  6863. // Get response data
  6864. if ( responses ) {
  6865. response = ajaxHandleResponses( s, jqXHR, responses );
  6866. }
  6867. // Convert no matter what (that way responseXXX fields are always set)
  6868. response = ajaxConvert( s, response, jqXHR, isSuccess );
  6869. // If successful, handle type chaining
  6870. if ( isSuccess ) {
  6871. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  6872. if ( s.ifModified ) {
  6873. modified = jqXHR.getResponseHeader("Last-Modified");
  6874. if ( modified ) {
  6875. jQuery.lastModified[ cacheURL ] = modified;
  6876. }
  6877. modified = jqXHR.getResponseHeader("etag");
  6878. if ( modified ) {
  6879. jQuery.etag[ cacheURL ] = modified;
  6880. }
  6881. }
  6882. // if no content
  6883. if ( status === 204 || s.type === "HEAD" ) {
  6884. statusText = "nocontent";
  6885. // if not modified
  6886. } else if ( status === 304 ) {
  6887. statusText = "notmodified";
  6888. // If we have data, let's convert it
  6889. } else {
  6890. statusText = response.state;
  6891. success = response.data;
  6892. error = response.error;
  6893. isSuccess = !error;
  6894. }
  6895. } else {
  6896. // We extract error from statusText
  6897. // then normalize statusText and status for non-aborts
  6898. error = statusText;
  6899. if ( status || !statusText ) {
  6900. statusText = "error";
  6901. if ( status < 0 ) {
  6902. status = 0;
  6903. }
  6904. }
  6905. }
  6906. // Set data for the fake xhr object
  6907. jqXHR.status = status;
  6908. jqXHR.statusText = ( nativeStatusText || statusText ) + "";
  6909. // Success/Error
  6910. if ( isSuccess ) {
  6911. deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
  6912. } else {
  6913. deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
  6914. }
  6915. // Status-dependent callbacks
  6916. jqXHR.statusCode( statusCode );
  6917. statusCode = undefined;
  6918. if ( fireGlobals ) {
  6919. globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
  6920. [ jqXHR, s, isSuccess ? success : error ] );
  6921. }
  6922. // Complete
  6923. completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
  6924. if ( fireGlobals ) {
  6925. globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
  6926. // Handle the global AJAX counter
  6927. if ( !( --jQuery.active ) ) {
  6928. jQuery.event.trigger("ajaxStop");
  6929. }
  6930. }
  6931. }
  6932. return jqXHR;
  6933. },
  6934. getJSON: function( url, data, callback ) {
  6935. return jQuery.get( url, data, callback, "json" );
  6936. },
  6937. getScript: function( url, callback ) {
  6938. return jQuery.get( url, undefined, callback, "script" );
  6939. }
  6940. });
  6941. jQuery.each( [ "get", "post" ], function( i, method ) {
  6942. jQuery[ method ] = function( url, data, callback, type ) {
  6943. // shift arguments if data argument was omitted
  6944. if ( jQuery.isFunction( data ) ) {
  6945. type = type || callback;
  6946. callback = data;
  6947. data = undefined;
  6948. }
  6949. return jQuery.ajax({
  6950. url: url,
  6951. type: method,
  6952. dataType: type,
  6953. data: data,
  6954. success: callback
  6955. });
  6956. };
  6957. });
  6958. // Attach a bunch of functions for handling common AJAX events
  6959. jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
  6960. jQuery.fn[ type ] = function( fn ) {
  6961. return this.on( type, fn );
  6962. };
  6963. });
  6964. jQuery._evalUrl = function( url ) {
  6965. return jQuery.ajax({
  6966. url: url,
  6967. type: "GET",
  6968. dataType: "script",
  6969. async: false,
  6970. global: false,
  6971. "throws": true
  6972. });
  6973. };
  6974. jQuery.fn.extend({
  6975. wrapAll: function( html ) {
  6976. var wrap;
  6977. if ( jQuery.isFunction( html ) ) {
  6978. return this.each(function( i ) {
  6979. jQuery( this ).wrapAll( html.call(this, i) );
  6980. });
  6981. }
  6982. if ( this[ 0 ] ) {
  6983. // The elements to wrap the target around
  6984. wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
  6985. if ( this[ 0 ].parentNode ) {
  6986. wrap.insertBefore( this[ 0 ] );
  6987. }
  6988. wrap.map(function() {
  6989. var elem = this;
  6990. while ( elem.firstElementChild ) {
  6991. elem = elem.firstElementChild;
  6992. }
  6993. return elem;
  6994. }).append( this );
  6995. }
  6996. return this;
  6997. },
  6998. wrapInner: function( html ) {
  6999. if ( jQuery.isFunction( html ) ) {
  7000. return this.each(function( i ) {
  7001. jQuery( this ).wrapInner( html.call(this, i) );
  7002. });
  7003. }
  7004. return this.each(function() {
  7005. var self = jQuery( this ),
  7006. contents = self.contents();
  7007. if ( contents.length ) {
  7008. contents.wrapAll( html );
  7009. } else {
  7010. self.append( html );
  7011. }
  7012. });
  7013. },
  7014. wrap: function( html ) {
  7015. var isFunction = jQuery.isFunction( html );
  7016. return this.each(function( i ) {
  7017. jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
  7018. });
  7019. },
  7020. unwrap: function() {
  7021. return this.parent().each(function() {
  7022. if ( !jQuery.nodeName( this, "body" ) ) {
  7023. jQuery( this ).replaceWith( this.childNodes );
  7024. }
  7025. }).end();
  7026. }
  7027. });
  7028. jQuery.expr.filters.hidden = function( elem ) {
  7029. // Support: Opera <= 12.12
  7030. // Opera reports offsetWidths and offsetHeights less than zero on some elements
  7031. return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
  7032. };
  7033. jQuery.expr.filters.visible = function( elem ) {
  7034. return !jQuery.expr.filters.hidden( elem );
  7035. };
  7036. var r20 = /%20/g,
  7037. rbracket = /\[\]$/,
  7038. rCRLF = /\r?\n/g,
  7039. rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
  7040. rsubmittable = /^(?:input|select|textarea|keygen)/i;
  7041. function buildParams( prefix, obj, traditional, add ) {
  7042. var name;
  7043. if ( jQuery.isArray( obj ) ) {
  7044. // Serialize array item.
  7045. jQuery.each( obj, function( i, v ) {
  7046. if ( traditional || rbracket.test( prefix ) ) {
  7047. // Treat each array item as a scalar.
  7048. add( prefix, v );
  7049. } else {
  7050. // Item is non-scalar (array or object), encode its numeric index.
  7051. buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
  7052. }
  7053. });
  7054. } else if ( !traditional && jQuery.type( obj ) === "object" ) {
  7055. // Serialize object item.
  7056. for ( name in obj ) {
  7057. buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
  7058. }
  7059. } else {
  7060. // Serialize scalar item.
  7061. add( prefix, obj );
  7062. }
  7063. }
  7064. // Serialize an array of form elements or a set of
  7065. // key/values into a query string
  7066. jQuery.param = function( a, traditional ) {
  7067. var prefix,
  7068. s = [],
  7069. add = function( key, value ) {
  7070. // If value is a function, invoke it and return its value
  7071. value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
  7072. s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
  7073. };
  7074. // Set traditional to true for jQuery <= 1.3.2 behavior.
  7075. if ( traditional === undefined ) {
  7076. traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
  7077. }
  7078. // If an array was passed in, assume that it is an array of form elements.
  7079. if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
  7080. // Serialize the form elements
  7081. jQuery.each( a, function() {
  7082. add( this.name, this.value );
  7083. });
  7084. } else {
  7085. // If traditional, encode the "old" way (the way 1.3.2 or older
  7086. // did it), otherwise encode params recursively.
  7087. for ( prefix in a ) {
  7088. buildParams( prefix, a[ prefix ], traditional, add );
  7089. }
  7090. }
  7091. // Return the resulting serialization
  7092. return s.join( "&" ).replace( r20, "+" );
  7093. };
  7094. jQuery.fn.extend({
  7095. serialize: function() {
  7096. return jQuery.param( this.serializeArray() );
  7097. },
  7098. serializeArray: function() {
  7099. return this.map(function() {
  7100. // Can add propHook for "elements" to filter or add form elements
  7101. var elements = jQuery.prop( this, "elements" );
  7102. return elements ? jQuery.makeArray( elements ) : this;
  7103. })
  7104. .filter(function() {
  7105. var type = this.type;
  7106. // Use .is( ":disabled" ) so that fieldset[disabled] works
  7107. return this.name && !jQuery( this ).is( ":disabled" ) &&
  7108. rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
  7109. ( this.checked || !rcheckableType.test( type ) );
  7110. })
  7111. .map(function( i, elem ) {
  7112. var val = jQuery( this ).val();
  7113. return val == null ?
  7114. null :
  7115. jQuery.isArray( val ) ?
  7116. jQuery.map( val, function( val ) {
  7117. return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  7118. }) :
  7119. { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  7120. }).get();
  7121. }
  7122. });
  7123. jQuery.ajaxSettings.xhr = function() {
  7124. try {
  7125. return new XMLHttpRequest();
  7126. } catch( e ) {}
  7127. };
  7128. var xhrId = 0,
  7129. xhrCallbacks = {},
  7130. xhrSuccessStatus = {
  7131. // file protocol always yields status code 0, assume 200
  7132. 0: 200,
  7133. // Support: IE9
  7134. // #1450: sometimes IE returns 1223 when it should be 204
  7135. 1223: 204
  7136. },
  7137. xhrSupported = jQuery.ajaxSettings.xhr();
  7138. // Support: IE9
  7139. // Open requests must be manually aborted on unload (#5280)
  7140. if ( window.ActiveXObject ) {
  7141. jQuery( window ).on( "unload", function() {
  7142. for ( var key in xhrCallbacks ) {
  7143. xhrCallbacks[ key ]();
  7144. }
  7145. });
  7146. }
  7147. support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
  7148. support.ajax = xhrSupported = !!xhrSupported;
  7149. jQuery.ajaxTransport(function( options ) {
  7150. var callback;
  7151. // Cross domain only allowed if supported through XMLHttpRequest
  7152. if ( support.cors || xhrSupported && !options.crossDomain ) {
  7153. return {
  7154. send: function( headers, complete ) {
  7155. var i,
  7156. xhr = options.xhr(),
  7157. id = ++xhrId;
  7158. xhr.open( options.type, options.url, options.async, options.username, options.password );
  7159. // Apply custom fields if provided
  7160. if ( options.xhrFields ) {
  7161. for ( i in options.xhrFields ) {
  7162. xhr[ i ] = options.xhrFields[ i ];
  7163. }
  7164. }
  7165. // Override mime type if needed
  7166. if ( options.mimeType && xhr.overrideMimeType ) {
  7167. xhr.overrideMimeType( options.mimeType );
  7168. }
  7169. // X-Requested-With header
  7170. // For cross-domain requests, seeing as conditions for a preflight are
  7171. // akin to a jigsaw puzzle, we simply never set it to be sure.
  7172. // (it can always be set on a per-request basis or even using ajaxSetup)
  7173. // For same-domain requests, won't change header if already provided.
  7174. if ( !options.crossDomain && !headers["X-Requested-With"] ) {
  7175. headers["X-Requested-With"] = "XMLHttpRequest";
  7176. }
  7177. // Set headers
  7178. for ( i in headers ) {
  7179. xhr.setRequestHeader( i, headers[ i ] );
  7180. }
  7181. // Callback
  7182. callback = function( type ) {
  7183. return function() {
  7184. if ( callback ) {
  7185. delete xhrCallbacks[ id ];
  7186. callback = xhr.onload = xhr.onerror = null;
  7187. if ( type === "abort" ) {
  7188. xhr.abort();
  7189. } else if ( type === "error" ) {
  7190. complete(
  7191. // file: protocol always yields status 0; see #8605, #14207
  7192. xhr.status,
  7193. xhr.statusText
  7194. );
  7195. } else {
  7196. complete(
  7197. xhrSuccessStatus[ xhr.status ] || xhr.status,
  7198. xhr.statusText,
  7199. // Support: IE9
  7200. // Accessing binary-data responseText throws an exception
  7201. // (#11426)
  7202. typeof xhr.responseText === "string" ? {
  7203. text: xhr.responseText
  7204. } : undefined,
  7205. xhr.getAllResponseHeaders()
  7206. );
  7207. }
  7208. }
  7209. };
  7210. };
  7211. // Listen to events
  7212. xhr.onload = callback();
  7213. xhr.onerror = callback("error");
  7214. // Create the abort callback
  7215. callback = xhrCallbacks[ id ] = callback("abort");
  7216. try {
  7217. // Do send the request (this may raise an exception)
  7218. xhr.send( options.hasContent && options.data || null );
  7219. } catch ( e ) {
  7220. // #14683: Only rethrow if this hasn't been notified as an error yet
  7221. if ( callback ) {
  7222. throw e;
  7223. }
  7224. }
  7225. },
  7226. abort: function() {
  7227. if ( callback ) {
  7228. callback();
  7229. }
  7230. }
  7231. };
  7232. }
  7233. });
  7234. // Install script dataType
  7235. jQuery.ajaxSetup({
  7236. accepts: {
  7237. script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
  7238. },
  7239. contents: {
  7240. script: /(?:java|ecma)script/
  7241. },
  7242. converters: {
  7243. "text script": function( text ) {
  7244. jQuery.globalEval( text );
  7245. return text;
  7246. }
  7247. }
  7248. });
  7249. // Handle cache's special case and crossDomain
  7250. jQuery.ajaxPrefilter( "script", function( s ) {
  7251. if ( s.cache === undefined ) {
  7252. s.cache = false;
  7253. }
  7254. if ( s.crossDomain ) {
  7255. s.type = "GET";
  7256. }
  7257. });
  7258. // Bind script tag hack transport
  7259. jQuery.ajaxTransport( "script", function( s ) {
  7260. // This transport only deals with cross domain requests
  7261. if ( s.crossDomain ) {
  7262. var script, callback;
  7263. return {
  7264. send: function( _, complete ) {
  7265. script = jQuery("<script>").prop({
  7266. async: true,
  7267. charset: s.scriptCharset,
  7268. src: s.url
  7269. }).on(
  7270. "load error",
  7271. callback = function( evt ) {
  7272. script.remove();
  7273. callback = null;
  7274. if ( evt ) {
  7275. complete( evt.type === "error" ? 404 : 200, evt.type );
  7276. }
  7277. }
  7278. );
  7279. document.head.appendChild( script[ 0 ] );
  7280. },
  7281. abort: function() {
  7282. if ( callback ) {
  7283. callback();
  7284. }
  7285. }
  7286. };
  7287. }
  7288. });
  7289. var oldCallbacks = [],
  7290. rjsonp = /(=)\?(?=&|$)|\?\?/;
  7291. // Default jsonp settings
  7292. jQuery.ajaxSetup({
  7293. jsonp: "callback",
  7294. jsonpCallback: function() {
  7295. var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
  7296. this[ callback ] = true;
  7297. return callback;
  7298. }
  7299. });
  7300. // Detect, normalize options and install callbacks for jsonp requests
  7301. jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
  7302. var callbackName, overwritten, responseContainer,
  7303. jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
  7304. "url" :
  7305. typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
  7306. );
  7307. // Handle iff the expected data type is "jsonp" or we have a parameter to set
  7308. if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
  7309. // Get callback name, remembering preexisting value associated with it
  7310. callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
  7311. s.jsonpCallback() :
  7312. s.jsonpCallback;
  7313. // Insert callback into url or form data
  7314. if ( jsonProp ) {
  7315. s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
  7316. } else if ( s.jsonp !== false ) {
  7317. s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
  7318. }
  7319. // Use data converter to retrieve json after script execution
  7320. s.converters["script json"] = function() {
  7321. if ( !responseContainer ) {
  7322. jQuery.error( callbackName + " was not called" );
  7323. }
  7324. return responseContainer[ 0 ];
  7325. };
  7326. // force json dataType
  7327. s.dataTypes[ 0 ] = "json";
  7328. // Install callback
  7329. overwritten = window[ callbackName ];
  7330. window[ callbackName ] = function() {
  7331. responseContainer = arguments;
  7332. };
  7333. // Clean-up function (fires after converters)
  7334. jqXHR.always(function() {
  7335. // Restore preexisting value
  7336. window[ callbackName ] = overwritten;
  7337. // Save back as free
  7338. if ( s[ callbackName ] ) {
  7339. // make sure that re-using the options doesn't screw things around
  7340. s.jsonpCallback = originalSettings.jsonpCallback;
  7341. // save the callback name for future use
  7342. oldCallbacks.push( callbackName );
  7343. }
  7344. // Call if it was a function and we have a response
  7345. if ( responseContainer && jQuery.isFunction( overwritten ) ) {
  7346. overwritten( responseContainer[ 0 ] );
  7347. }
  7348. responseContainer = overwritten = undefined;
  7349. });
  7350. // Delegate to script
  7351. return "script";
  7352. }
  7353. });
  7354. // data: string of html
  7355. // context (optional): If specified, the fragment will be created in this context, defaults to document
  7356. // keepScripts (optional): If true, will include scripts passed in the html string
  7357. jQuery.parseHTML = function( data, context, keepScripts ) {
  7358. if ( !data || typeof data !== "string" ) {
  7359. return null;
  7360. }
  7361. if ( typeof context === "boolean" ) {
  7362. keepScripts = context;
  7363. context = false;
  7364. }
  7365. context = context || document;
  7366. var parsed = rsingleTag.exec( data ),
  7367. scripts = !keepScripts && [];
  7368. // Single tag
  7369. if ( parsed ) {
  7370. return [ context.createElement( parsed[1] ) ];
  7371. }
  7372. parsed = jQuery.buildFragment( [ data ], context, scripts );
  7373. if ( scripts && scripts.length ) {
  7374. jQuery( scripts ).remove();
  7375. }
  7376. return jQuery.merge( [], parsed.childNodes );
  7377. };
  7378. // Keep a copy of the old load method
  7379. var _load = jQuery.fn.load;
  7380. /**
  7381. * Load a url into a page
  7382. */
  7383. jQuery.fn.load = function( url, params, callback ) {
  7384. if ( typeof url !== "string" && _load ) {
  7385. return _load.apply( this, arguments );
  7386. }
  7387. var selector, type, response,
  7388. self = this,
  7389. off = url.indexOf(" ");
  7390. if ( off >= 0 ) {
  7391. selector = jQuery.trim( url.slice( off ) );
  7392. url = url.slice( 0, off );
  7393. }
  7394. // If it's a function
  7395. if ( jQuery.isFunction( params ) ) {
  7396. // We assume that it's the callback
  7397. callback = params;
  7398. params = undefined;
  7399. // Otherwise, build a param string
  7400. } else if ( params && typeof params === "object" ) {
  7401. type = "POST";
  7402. }
  7403. // If we have elements to modify, make the request
  7404. if ( self.length > 0 ) {
  7405. jQuery.ajax({
  7406. url: url,
  7407. // if "type" variable is undefined, then "GET" method will be used
  7408. type: type,
  7409. dataType: "html",
  7410. data: params
  7411. }).done(function( responseText ) {
  7412. // Save response for use in complete callback
  7413. response = arguments;
  7414. self.html( selector ?
  7415. // If a selector was specified, locate the right elements in a dummy div
  7416. // Exclude scripts to avoid IE 'Permission Denied' errors
  7417. jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
  7418. // Otherwise use the full result
  7419. responseText );
  7420. }).complete( callback && function( jqXHR, status ) {
  7421. self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
  7422. });
  7423. }
  7424. return this;
  7425. };
  7426. jQuery.expr.filters.animated = function( elem ) {
  7427. return jQuery.grep(jQuery.timers, function( fn ) {
  7428. return elem === fn.elem;
  7429. }).length;
  7430. };
  7431. var docElem = window.document.documentElement;
  7432. /**
  7433. * Gets a window from an element
  7434. */
  7435. function getWindow( elem ) {
  7436. return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
  7437. }
  7438. jQuery.offset = {
  7439. setOffset: function( elem, options, i ) {
  7440. var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
  7441. position = jQuery.css( elem, "position" ),
  7442. curElem = jQuery( elem ),
  7443. props = {};
  7444. // Set position first, in-case top/left are set even on static elem
  7445. if ( position === "static" ) {
  7446. elem.style.position = "relative";
  7447. }
  7448. curOffset = curElem.offset();
  7449. curCSSTop = jQuery.css( elem, "top" );
  7450. curCSSLeft = jQuery.css( elem, "left" );
  7451. calculatePosition = ( position === "absolute" || position === "fixed" ) &&
  7452. ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
  7453. // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
  7454. if ( calculatePosition ) {
  7455. curPosition = curElem.position();
  7456. curTop = curPosition.top;
  7457. curLeft = curPosition.left;
  7458. } else {
  7459. curTop = parseFloat( curCSSTop ) || 0;
  7460. curLeft = parseFloat( curCSSLeft ) || 0;
  7461. }
  7462. if ( jQuery.isFunction( options ) ) {
  7463. options = options.call( elem, i, curOffset );
  7464. }
  7465. if ( options.top != null ) {
  7466. props.top = ( options.top - curOffset.top ) + curTop;
  7467. }
  7468. if ( options.left != null ) {
  7469. props.left = ( options.left - curOffset.left ) + curLeft;
  7470. }
  7471. if ( "using" in options ) {
  7472. options.using.call( elem, props );
  7473. } else {
  7474. curElem.css( props );
  7475. }
  7476. }
  7477. };
  7478. jQuery.fn.extend({
  7479. offset: function( options ) {
  7480. if ( arguments.length ) {
  7481. return options === undefined ?
  7482. this :
  7483. this.each(function( i ) {
  7484. jQuery.offset.setOffset( this, options, i );
  7485. });
  7486. }
  7487. var docElem, win,
  7488. elem = this[ 0 ],
  7489. box = { top: 0, left: 0 },
  7490. doc = elem && elem.ownerDocument;
  7491. if ( !doc ) {
  7492. return;
  7493. }
  7494. docElem = doc.documentElement;
  7495. // Make sure it's not a disconnected DOM node
  7496. if ( !jQuery.contains( docElem, elem ) ) {
  7497. return box;
  7498. }
  7499. // If we don't have gBCR, just use 0,0 rather than error
  7500. // BlackBerry 5, iOS 3 (original iPhone)
  7501. if ( typeof elem.getBoundingClientRect !== strundefined ) {
  7502. box = elem.getBoundingClientRect();
  7503. }
  7504. win = getWindow( doc );
  7505. return {
  7506. top: box.top + win.pageYOffset - docElem.clientTop,
  7507. left: box.left + win.pageXOffset - docElem.clientLeft
  7508. };
  7509. },
  7510. position: function() {
  7511. if ( !this[ 0 ] ) {
  7512. return;
  7513. }
  7514. var offsetParent, offset,
  7515. elem = this[ 0 ],
  7516. parentOffset = { top: 0, left: 0 };
  7517. // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
  7518. if ( jQuery.css( elem, "position" ) === "fixed" ) {
  7519. // We assume that getBoundingClientRect is available when computed position is fixed
  7520. offset = elem.getBoundingClientRect();
  7521. } else {
  7522. // Get *real* offsetParent
  7523. offsetParent = this.offsetParent();
  7524. // Get correct offsets
  7525. offset = this.offset();
  7526. if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
  7527. parentOffset = offsetParent.offset();
  7528. }
  7529. // Add offsetParent borders
  7530. parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
  7531. parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
  7532. }
  7533. // Subtract parent offsets and element margins
  7534. return {
  7535. top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
  7536. left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
  7537. };
  7538. },
  7539. offsetParent: function() {
  7540. return this.map(function() {
  7541. var offsetParent = this.offsetParent || docElem;
  7542. while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
  7543. offsetParent = offsetParent.offsetParent;
  7544. }
  7545. return offsetParent || docElem;
  7546. });
  7547. }
  7548. });
  7549. // Create scrollLeft and scrollTop methods
  7550. jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
  7551. var top = "pageYOffset" === prop;
  7552. jQuery.fn[ method ] = function( val ) {
  7553. return access( this, function( elem, method, val ) {
  7554. var win = getWindow( elem );
  7555. if ( val === undefined ) {
  7556. return win ? win[ prop ] : elem[ method ];
  7557. }
  7558. if ( win ) {
  7559. win.scrollTo(
  7560. !top ? val : window.pageXOffset,
  7561. top ? val : window.pageYOffset
  7562. );
  7563. } else {
  7564. elem[ method ] = val;
  7565. }
  7566. }, method, val, arguments.length, null );
  7567. };
  7568. });
  7569. // Add the top/left cssHooks using jQuery.fn.position
  7570. // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
  7571. // getComputedStyle returns percent when specified for top/left/bottom/right
  7572. // rather than make the css module depend on the offset module, we just check for it here
  7573. jQuery.each( [ "top", "left" ], function( i, prop ) {
  7574. jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
  7575. function( elem, computed ) {
  7576. if ( computed ) {
  7577. computed = curCSS( elem, prop );
  7578. // if curCSS returns percentage, fallback to offset
  7579. return rnumnonpx.test( computed ) ?
  7580. jQuery( elem ).position()[ prop ] + "px" :
  7581. computed;
  7582. }
  7583. }
  7584. );
  7585. });
  7586. // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
  7587. jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
  7588. jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
  7589. // margin is only for outerHeight, outerWidth
  7590. jQuery.fn[ funcName ] = function( margin, value ) {
  7591. var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
  7592. extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
  7593. return access( this, function( elem, type, value ) {
  7594. var doc;
  7595. if ( jQuery.isWindow( elem ) ) {
  7596. // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
  7597. // isn't a whole lot we can do. See pull request at this URL for discussion:
  7598. // https://github.com/jquery/jquery/pull/764
  7599. return elem.document.documentElement[ "client" + name ];
  7600. }
  7601. // Get document width or height
  7602. if ( elem.nodeType === 9 ) {
  7603. doc = elem.documentElement;
  7604. // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
  7605. // whichever is greatest
  7606. return Math.max(
  7607. elem.body[ "scroll" + name ], doc[ "scroll" + name ],
  7608. elem.body[ "offset" + name ], doc[ "offset" + name ],
  7609. doc[ "client" + name ]
  7610. );
  7611. }
  7612. return value === undefined ?
  7613. // Get width or height on the element, requesting but not forcing parseFloat
  7614. jQuery.css( elem, type, extra ) :
  7615. // Set width or height on the element
  7616. jQuery.style( elem, type, value, extra );
  7617. }, type, chainable ? margin : undefined, chainable, null );
  7618. };
  7619. });
  7620. });
  7621. // The number of elements contained in the matched element set
  7622. jQuery.fn.size = function() {
  7623. return this.length;
  7624. };
  7625. jQuery.fn.andSelf = jQuery.fn.addBack;
  7626. // Register as a named AMD module, since jQuery can be concatenated with other
  7627. // files that may use define, but not via a proper concatenation script that
  7628. // understands anonymous AMD modules. A named AMD is safest and most robust
  7629. // way to register. Lowercase jquery is used because AMD module names are
  7630. // derived from file names, and jQuery is normally delivered in a lowercase
  7631. // file name. Do this after creating the global so that if an AMD module wants
  7632. // to call noConflict to hide this version of jQuery, it will work.
  7633. // Note that for maximum portability, libraries that are not jQuery should
  7634. // declare themselves as anonymous modules, and avoid setting a global if an
  7635. // AMD loader is present. jQuery is a special case. For more information, see
  7636. // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
  7637. if ( typeof define === "function" && define.amd ) {
  7638. define( "jquery", [], function() {
  7639. return jQuery;
  7640. });
  7641. }
  7642. var
  7643. // Map over jQuery in case of overwrite
  7644. _jQuery = window.jQuery,
  7645. // Map over the $ in case of overwrite
  7646. _$ = window.$;
  7647. jQuery.noConflict = function( deep ) {
  7648. if ( window.$ === jQuery ) {
  7649. window.$ = _$;
  7650. }
  7651. if ( deep && window.jQuery === jQuery ) {
  7652. window.jQuery = _jQuery;
  7653. }
  7654. return jQuery;
  7655. };
  7656. // Expose jQuery and $ identifiers, even in
  7657. // AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
  7658. // and CommonJS for browser emulators (#13566)
  7659. if ( typeof noGlobal === strundefined ) {
  7660. window.jQuery = window.$ = jQuery;
  7661. }
  7662. return jQuery;
  7663. }));
  7664. (function() {
  7665. var define, requireModule, require, requirejs;
  7666. (function() {
  7667. var registry = {}, seen = {};
  7668. define = function(name, deps, callback) {
  7669. registry[name] = { deps: deps, callback: callback };
  7670. };
  7671. requirejs = require = requireModule = function(name) {
  7672. requirejs._eak_seen = registry;
  7673. if (seen[name]) { return seen[name]; }
  7674. seen[name] = {};
  7675. if (!registry[name]) {
  7676. throw new Error("Could not find module " + name);
  7677. }
  7678. var mod = registry[name],
  7679. deps = mod.deps,
  7680. callback = mod.callback,
  7681. reified = [],
  7682. exports;
  7683. for (var i=0, l=deps.length; i<l; i++) {
  7684. if (deps[i] === 'exports') {
  7685. reified.push(exports = {});
  7686. } else {
  7687. reified.push(requireModule(resolve(deps[i])));
  7688. }
  7689. }
  7690. var value = callback.apply(this, reified);
  7691. return seen[name] = exports || value;
  7692. function resolve(child) {
  7693. if (child.charAt(0) !== '.') { return child; }
  7694. var parts = child.split("/");
  7695. var parentBase = name.split("/").slice(0, -1);
  7696. for (var i=0, l=parts.length; i<l; i++) {
  7697. var part = parts[i];
  7698. if (part === '..') { parentBase.pop(); }
  7699. else if (part === '.') { continue; }
  7700. else { parentBase.push(part); }
  7701. }
  7702. return parentBase.join("/");
  7703. }
  7704. };
  7705. })();
  7706. define("promise/all",
  7707. ["./utils","exports"],
  7708. function(__dependency1__, __exports__) {
  7709. "use strict";
  7710. /* global toString */
  7711. var isArray = __dependency1__.isArray;
  7712. var isFunction = __dependency1__.isFunction;
  7713. /**
  7714. Returns a promise that is fulfilled when all the given promises have been
  7715. fulfilled, or rejected if any of them become rejected. The return promise
  7716. is fulfilled with an array that gives all the values in the order they were
  7717. passed in the `promises` array argument.
  7718. Example:
  7719. ```javascript
  7720. var promise1 = RSVP.resolve(1);
  7721. var promise2 = RSVP.resolve(2);
  7722. var promise3 = RSVP.resolve(3);
  7723. var promises = [ promise1, promise2, promise3 ];
  7724. RSVP.all(promises).then(function(array){
  7725. // The array here would be [ 1, 2, 3 ];
  7726. });
  7727. ```
  7728. If any of the `promises` given to `RSVP.all` are rejected, the first promise
  7729. that is rejected will be given as an argument to the returned promises's
  7730. rejection handler. For example:
  7731. Example:
  7732. ```javascript
  7733. var promise1 = RSVP.resolve(1);
  7734. var promise2 = RSVP.reject(new Error("2"));
  7735. var promise3 = RSVP.reject(new Error("3"));
  7736. var promises = [ promise1, promise2, promise3 ];
  7737. RSVP.all(promises).then(function(array){
  7738. // Code here never runs because there are rejected promises!
  7739. }, function(error) {
  7740. // error.message === "2"
  7741. });
  7742. ```
  7743. @method all
  7744. @for RSVP
  7745. @param {Array} promises
  7746. @param {String} label
  7747. @return {Promise} promise that is fulfilled when all `promises` have been
  7748. fulfilled, or rejected if any of them become rejected.
  7749. */
  7750. function all(promises) {
  7751. /*jshint validthis:true */
  7752. var Promise = this;
  7753. if (!isArray(promises)) {
  7754. throw new TypeError('You must pass an array to all.');
  7755. }
  7756. return new Promise(function(resolve, reject) {
  7757. var results = [], remaining = promises.length,
  7758. promise;
  7759. if (remaining === 0) {
  7760. resolve([]);
  7761. }
  7762. function resolver(index) {
  7763. return function(value) {
  7764. resolveAll(index, value);
  7765. };
  7766. }
  7767. function resolveAll(index, value) {
  7768. results[index] = value;
  7769. if (--remaining === 0) {
  7770. resolve(results);
  7771. }
  7772. }
  7773. for (var i = 0; i < promises.length; i++) {
  7774. promise = promises[i];
  7775. if (promise && isFunction(promise.then)) {
  7776. promise.then(resolver(i), reject);
  7777. } else {
  7778. resolveAll(i, promise);
  7779. }
  7780. }
  7781. });
  7782. }
  7783. __exports__.all = all;
  7784. });
  7785. define("promise/asap",
  7786. ["exports"],
  7787. function(__exports__) {
  7788. "use strict";
  7789. var browserGlobal = (typeof window !== 'undefined') ? window : {};
  7790. var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
  7791. var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this);
  7792. // node
  7793. function useNextTick() {
  7794. return function() {
  7795. process.nextTick(flush);
  7796. };
  7797. }
  7798. function useMutationObserver() {
  7799. var iterations = 0;
  7800. var observer = new BrowserMutationObserver(flush);
  7801. var node = document.createTextNode('');
  7802. observer.observe(node, { characterData: true });
  7803. return function() {
  7804. node.data = (iterations = ++iterations % 2);
  7805. };
  7806. }
  7807. function useSetTimeout() {
  7808. return function() {
  7809. local.setTimeout(flush, 1);
  7810. };
  7811. }
  7812. var queue = [];
  7813. function flush() {
  7814. for (var i = 0; i < queue.length; i++) {
  7815. var tuple = queue[i];
  7816. var callback = tuple[0], arg = tuple[1];
  7817. callback(arg);
  7818. }
  7819. queue = [];
  7820. }
  7821. var scheduleFlush;
  7822. // Decide what async method to use to triggering processing of queued callbacks:
  7823. if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
  7824. scheduleFlush = useNextTick();
  7825. } else if (BrowserMutationObserver) {
  7826. scheduleFlush = useMutationObserver();
  7827. } else {
  7828. scheduleFlush = useSetTimeout();
  7829. }
  7830. function asap(callback, arg) {
  7831. var length = queue.push([callback, arg]);
  7832. if (length === 1) {
  7833. // If length is 1, that means that we need to schedule an async flush.
  7834. // If additional callbacks are queued before the queue is flushed, they
  7835. // will be processed by this flush that we are scheduling.
  7836. scheduleFlush();
  7837. }
  7838. }
  7839. __exports__.asap = asap;
  7840. });
  7841. define("promise/config",
  7842. ["exports"],
  7843. function(__exports__) {
  7844. "use strict";
  7845. var config = {
  7846. instrument: false
  7847. };
  7848. function configure(name, value) {
  7849. if (arguments.length === 2) {
  7850. config[name] = value;
  7851. } else {
  7852. return config[name];
  7853. }
  7854. }
  7855. __exports__.config = config;
  7856. __exports__.configure = configure;
  7857. });
  7858. define("promise/polyfill",
  7859. ["./promise","./utils","exports"],
  7860. function(__dependency1__, __dependency2__, __exports__) {
  7861. "use strict";
  7862. /*global self*/
  7863. var RSVPPromise = __dependency1__.Promise;
  7864. var isFunction = __dependency2__.isFunction;
  7865. function polyfill() {
  7866. var local;
  7867. if (typeof global !== 'undefined') {
  7868. local = global;
  7869. } else if (typeof window !== 'undefined' && window.document) {
  7870. local = window;
  7871. } else {
  7872. local = self;
  7873. }
  7874. var es6PromiseSupport =
  7875. "Promise" in local &&
  7876. // Some of these methods are missing from
  7877. // Firefox/Chrome experimental implementations
  7878. "resolve" in local.Promise &&
  7879. "reject" in local.Promise &&
  7880. "all" in local.Promise &&
  7881. "race" in local.Promise &&
  7882. // Older version of the spec had a resolver object
  7883. // as the arg rather than a function
  7884. (function() {
  7885. var resolve;
  7886. new local.Promise(function(r) { resolve = r; });
  7887. return isFunction(resolve);
  7888. }());
  7889. // !es6PromiseSupport || ~window.location.href.indexOf('rsvpromise')
  7890. if (true) {
  7891. local.Promise = RSVPPromise;
  7892. }
  7893. }
  7894. __exports__.polyfill = polyfill;
  7895. });
  7896. define("promise/promise",
  7897. ["./config","./utils","./all","./race","./resolve","./reject","./asap","exports"],
  7898. function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {
  7899. "use strict";
  7900. var config = __dependency1__.config;
  7901. var configure = __dependency1__.configure;
  7902. var objectOrFunction = __dependency2__.objectOrFunction;
  7903. var isFunction = __dependency2__.isFunction;
  7904. var now = __dependency2__.now;
  7905. var all = __dependency3__.all;
  7906. var race = __dependency4__.race;
  7907. var staticResolve = __dependency5__.resolve;
  7908. var staticReject = __dependency6__.reject;
  7909. var asap = __dependency7__.asap;
  7910. var counter = 0;
  7911. config.async = asap; // default async is asap;
  7912. function Promise(resolver) {
  7913. if (!isFunction(resolver)) {
  7914. throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
  7915. }
  7916. if (!(this instanceof Promise)) {
  7917. throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
  7918. }
  7919. this._subscribers = [];
  7920. invokeResolver(resolver, this);
  7921. }
  7922. function invokeResolver(resolver, promise) {
  7923. function resolvePromise(value) {
  7924. resolve(promise, value);
  7925. }
  7926. function rejectPromise(reason) {
  7927. reject(promise, reason);
  7928. }
  7929. try {
  7930. resolver(resolvePromise, rejectPromise);
  7931. } catch(e) {
  7932. rejectPromise(e);
  7933. }
  7934. }
  7935. function invokeCallback(settled, promise, callback, detail) {
  7936. var hasCallback = isFunction(callback),
  7937. value, error, succeeded, failed;
  7938. if (hasCallback) {
  7939. try {
  7940. value = callback(detail);
  7941. succeeded = true;
  7942. } catch(e) {
  7943. failed = true;
  7944. error = e;
  7945. }
  7946. } else {
  7947. value = detail;
  7948. succeeded = true;
  7949. }
  7950. if (handleThenable(promise, value)) {
  7951. return;
  7952. } else if (hasCallback && succeeded) {
  7953. resolve(promise, value);
  7954. } else if (failed) {
  7955. reject(promise, error);
  7956. } else if (settled === FULFILLED) {
  7957. resolve(promise, value);
  7958. } else if (settled === REJECTED) {
  7959. reject(promise, value);
  7960. }
  7961. }
  7962. var PENDING = void 0;
  7963. var SEALED = 0;
  7964. var FULFILLED = 1;
  7965. var REJECTED = 2;
  7966. function subscribe(parent, child, onFulfillment, onRejection) {
  7967. var subscribers = parent._subscribers;
  7968. var length = subscribers.length;
  7969. subscribers[length] = child;
  7970. subscribers[length + FULFILLED] = onFulfillment;
  7971. subscribers[length + REJECTED] = onRejection;
  7972. }
  7973. function publish(promise, settled) {
  7974. var child, callback, subscribers = promise._subscribers, detail = promise._detail;
  7975. for (var i = 0; i < subscribers.length; i += 3) {
  7976. child = subscribers[i];
  7977. callback = subscribers[i + settled];
  7978. invokeCallback(settled, child, callback, detail);
  7979. }
  7980. promise._subscribers = null;
  7981. }
  7982. Promise.prototype = {
  7983. constructor: Promise,
  7984. _state: undefined,
  7985. _detail: undefined,
  7986. _subscribers: undefined,
  7987. then: function(onFulfillment, onRejection) {
  7988. var promise = this;
  7989. var thenPromise = new this.constructor(function() {});
  7990. if (this._state) {
  7991. var callbacks = arguments;
  7992. config.async(function invokePromiseCallback() {
  7993. invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);
  7994. });
  7995. } else {
  7996. subscribe(this, thenPromise, onFulfillment, onRejection);
  7997. }
  7998. return thenPromise;
  7999. },
  8000. 'catch': function(onRejection) {
  8001. return this.then(null, onRejection);
  8002. }
  8003. };
  8004. Promise.all = all;
  8005. Promise.race = race;
  8006. Promise.resolve = staticResolve;
  8007. Promise.reject = staticReject;
  8008. function handleThenable(promise, value) {
  8009. var then = null,
  8010. resolved;
  8011. try {
  8012. if (promise === value) {
  8013. throw new TypeError("A promises callback cannot return that same promise.");
  8014. }
  8015. if (objectOrFunction(value)) {
  8016. then = value.then;
  8017. if (isFunction(then)) {
  8018. then.call(value, function(val) {
  8019. if (resolved) { return true; }
  8020. resolved = true;
  8021. if (value !== val) {
  8022. resolve(promise, val);
  8023. } else {
  8024. fulfill(promise, val);
  8025. }
  8026. }, function(val) {
  8027. if (resolved) { return true; }
  8028. resolved = true;
  8029. reject(promise, val);
  8030. });
  8031. return true;
  8032. }
  8033. }
  8034. } catch (error) {
  8035. if (resolved) { return true; }
  8036. reject(promise, error);
  8037. return true;
  8038. }
  8039. return false;
  8040. }
  8041. function resolve(promise, value) {
  8042. if (promise === value) {
  8043. fulfill(promise, value);
  8044. } else if (!handleThenable(promise, value)) {
  8045. fulfill(promise, value);
  8046. }
  8047. }
  8048. function fulfill(promise, value) {
  8049. if (promise._state !== PENDING) { return; }
  8050. promise._state = SEALED;
  8051. promise._detail = value;
  8052. config.async(publishFulfillment, promise);
  8053. }
  8054. function reject(promise, reason) {
  8055. if (promise._state !== PENDING) { return; }
  8056. promise._state = SEALED;
  8057. promise._detail = reason;
  8058. config.async(publishRejection, promise);
  8059. }
  8060. function publishFulfillment(promise) {
  8061. publish(promise, promise._state = FULFILLED);
  8062. }
  8063. function publishRejection(promise) {
  8064. publish(promise, promise._state = REJECTED);
  8065. }
  8066. __exports__.Promise = Promise;
  8067. });
  8068. define("promise/race",
  8069. ["./utils","exports"],
  8070. function(__dependency1__, __exports__) {
  8071. "use strict";
  8072. /* global toString */
  8073. var isArray = __dependency1__.isArray;
  8074. /**
  8075. `RSVP.race` allows you to watch a series of promises and act as soon as the
  8076. first promise given to the `promises` argument fulfills or rejects.
  8077. Example:
  8078. ```javascript
  8079. var promise1 = new RSVP.Promise(function(resolve, reject){
  8080. setTimeout(function(){
  8081. resolve("promise 1");
  8082. }, 200);
  8083. });
  8084. var promise2 = new RSVP.Promise(function(resolve, reject){
  8085. setTimeout(function(){
  8086. resolve("promise 2");
  8087. }, 100);
  8088. });
  8089. RSVP.race([promise1, promise2]).then(function(result){
  8090. // result === "promise 2" because it was resolved before promise1
  8091. // was resolved.
  8092. });
  8093. ```
  8094. `RSVP.race` is deterministic in that only the state of the first completed
  8095. promise matters. For example, even if other promises given to the `promises`
  8096. array argument are resolved, but the first completed promise has become
  8097. rejected before the other promises became fulfilled, the returned promise
  8098. will become rejected:
  8099. ```javascript
  8100. var promise1 = new RSVP.Promise(function(resolve, reject){
  8101. setTimeout(function(){
  8102. resolve("promise 1");
  8103. }, 200);
  8104. });
  8105. var promise2 = new RSVP.Promise(function(resolve, reject){
  8106. setTimeout(function(){
  8107. reject(new Error("promise 2"));
  8108. }, 100);
  8109. });
  8110. RSVP.race([promise1, promise2]).then(function(result){
  8111. // Code here never runs because there are rejected promises!
  8112. }, function(reason){
  8113. // reason.message === "promise2" because promise 2 became rejected before
  8114. // promise 1 became fulfilled
  8115. });
  8116. ```
  8117. @method race
  8118. @for RSVP
  8119. @param {Array} promises array of promises to observe
  8120. @param {String} label optional string for describing the promise returned.
  8121. Useful for tooling.
  8122. @return {Promise} a promise that becomes fulfilled with the value the first
  8123. completed promises is resolved with if the first completed promise was
  8124. fulfilled, or rejected with the reason that the first completed promise
  8125. was rejected with.
  8126. */
  8127. function race(promises) {
  8128. /*jshint validthis:true */
  8129. var Promise = this;
  8130. if (!isArray(promises)) {
  8131. throw new TypeError('You must pass an array to race.');
  8132. }
  8133. return new Promise(function(resolve, reject) {
  8134. var results = [], promise;
  8135. for (var i = 0; i < promises.length; i++) {
  8136. promise = promises[i];
  8137. if (promise && typeof promise.then === 'function') {
  8138. promise.then(resolve, reject);
  8139. } else {
  8140. resolve(promise);
  8141. }
  8142. }
  8143. });
  8144. }
  8145. __exports__.race = race;
  8146. });
  8147. define("promise/reject",
  8148. ["exports"],
  8149. function(__exports__) {
  8150. "use strict";
  8151. /**
  8152. `RSVP.reject` returns a promise that will become rejected with the passed
  8153. `reason`. `RSVP.reject` is essentially shorthand for the following:
  8154. ```javascript
  8155. var promise = new RSVP.Promise(function(resolve, reject){
  8156. reject(new Error('WHOOPS'));
  8157. });
  8158. promise.then(function(value){
  8159. // Code here doesn't run because the promise is rejected!
  8160. }, function(reason){
  8161. // reason.message === 'WHOOPS'
  8162. });
  8163. ```
  8164. Instead of writing the above, your code now simply becomes the following:
  8165. ```javascript
  8166. var promise = RSVP.reject(new Error('WHOOPS'));
  8167. promise.then(function(value){
  8168. // Code here doesn't run because the promise is rejected!
  8169. }, function(reason){
  8170. // reason.message === 'WHOOPS'
  8171. });
  8172. ```
  8173. @method reject
  8174. @for RSVP
  8175. @param {Any} reason value that the returned promise will be rejected with.
  8176. @param {String} label optional string for identifying the returned promise.
  8177. Useful for tooling.
  8178. @return {Promise} a promise that will become rejected with the given
  8179. `reason`.
  8180. */
  8181. function reject(reason) {
  8182. /*jshint validthis:true */
  8183. var Promise = this;
  8184. return new Promise(function (resolve, reject) {
  8185. reject(reason);
  8186. });
  8187. }
  8188. __exports__.reject = reject;
  8189. });
  8190. define("promise/resolve",
  8191. ["exports"],
  8192. function(__exports__) {
  8193. "use strict";
  8194. function resolve(value) {
  8195. /*jshint validthis:true */
  8196. if (value && typeof value === 'object' && value.constructor === this) {
  8197. return value;
  8198. }
  8199. var Promise = this;
  8200. return new Promise(function(resolve) {
  8201. resolve(value);
  8202. });
  8203. }
  8204. __exports__.resolve = resolve;
  8205. });
  8206. define("promise/utils",
  8207. ["exports"],
  8208. function(__exports__) {
  8209. "use strict";
  8210. function objectOrFunction(x) {
  8211. return isFunction(x) || (typeof x === "object" && x !== null);
  8212. }
  8213. function isFunction(x) {
  8214. return typeof x === "function";
  8215. }
  8216. function isArray(x) {
  8217. return Object.prototype.toString.call(x) === "[object Array]";
  8218. }
  8219. // Date.now is not available in browsers < IE9
  8220. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility
  8221. var now = Date.now || function() { return new Date().getTime(); };
  8222. __exports__.objectOrFunction = objectOrFunction;
  8223. __exports__.isFunction = isFunction;
  8224. __exports__.isArray = isArray;
  8225. __exports__.now = now;
  8226. });
  8227. requireModule('promise/polyfill').polyfill();
  8228. }());
  8229. /*
  8230. ### jQuery XML to JSON Plugin v1.3 - 2013-02-18 ###
  8231. * http://www.fyneworks.com/ - diego@fyneworks.com
  8232. * Licensed under http://en.wikipedia.org/wiki/MIT_License
  8233. ###
  8234. Website: http://www.fyneworks.com/jquery/xml-to-json/
  8235. *//*
  8236. # INSPIRED BY: http://www.terracoder.com/
  8237. AND: http://www.thomasfrank.se/xml_to_json.html
  8238. AND: http://www.kawa.net/works/js/xml/objtree-e.html
  8239. *//*
  8240. This simple script converts XML (document of code) into a JSON object. It is the combination of 2
  8241. 'xml to json' great parsers (see below) which allows for both 'simple' and 'extended' parsing modes.
  8242. */
  8243. // Avoid collisions
  8244. ;if(window.jQuery) (function($){
  8245. // Add function to jQuery namespace
  8246. $.extend({
  8247. // converts xml documents and xml text to json object
  8248. xml2json: function(xml, extended) {
  8249. if(!xml) return {}; // quick fail
  8250. //### PARSER LIBRARY
  8251. // Core function
  8252. function parseXML(node, simple){
  8253. if(!node) return null;
  8254. var txt = '', obj = null, att = null;
  8255. var nt = node.nodeType, nn = jsVar(node.localName || node.nodeName);
  8256. var nv = node.text || node.nodeValue || '';
  8257. /*DBG*/ //if(window.console) console.log(['x2j',nn,nt,nv.length+' bytes']);
  8258. if(node.childNodes){
  8259. if(node.childNodes.length>0){
  8260. /*DBG*/ //if(window.console) console.log(['x2j',nn,'CHILDREN',node.childNodes]);
  8261. $.each(node.childNodes, function(n,cn){
  8262. var cnt = cn.nodeType, cnn = jsVar(cn.localName || cn.nodeName);
  8263. var cnv = cn.text || cn.nodeValue || '';
  8264. /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>a',cnn,cnt,cnv]);
  8265. if(cnt == 8){
  8266. /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>b',cnn,'COMMENT (ignore)']);
  8267. return; // ignore comment node
  8268. }
  8269. else if(cnt == 3 || cnt == 4 || !cnn){
  8270. // ignore white-space in between tags
  8271. if(cnv.match(/^\s+$/)){
  8272. /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>c',cnn,'WHITE-SPACE (ignore)']);
  8273. return;
  8274. };
  8275. /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>d',cnn,'TEXT']);
  8276. txt += cnv.replace(/^\s+/,'').replace(/\s+$/,'');
  8277. // make sure we ditch trailing spaces from markup
  8278. }
  8279. else{
  8280. /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>e',cnn,'OBJECT']);
  8281. obj = obj || {};
  8282. if(obj[cnn]){
  8283. /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>f',cnn,'ARRAY']);
  8284. // http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
  8285. if(!obj[cnn].length) obj[cnn] = myArr(obj[cnn]);
  8286. obj[cnn] = myArr(obj[cnn]);
  8287. obj[cnn][ obj[cnn].length ] = parseXML(cn, true/* simple */);
  8288. obj[cnn].length = obj[cnn].length;
  8289. }
  8290. else{
  8291. /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>g',cnn,'dig deeper...']);
  8292. obj[cnn] = parseXML(cn);
  8293. };
  8294. };
  8295. });
  8296. };//node.childNodes.length>0
  8297. };//node.childNodes
  8298. if(node.attributes){
  8299. if(node.attributes.length>0){
  8300. /*DBG*/ //if(window.console) console.log(['x2j',nn,'ATTRIBUTES',node.attributes])
  8301. att = {}; obj = obj || {};
  8302. $.each(node.attributes, function(a,at){
  8303. var atn = jsVar(at.name), atv = at.value;
  8304. att[atn] = atv;
  8305. if(obj[atn]){
  8306. /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'ARRAY']);
  8307. // http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
  8308. //if(!obj[atn].length) obj[atn] = myArr(obj[atn]);//[ obj[ atn ] ];
  8309. obj[cnn] = myArr(obj[cnn]);
  8310. obj[atn][ obj[atn].length ] = atv;
  8311. obj[atn].length = obj[atn].length;
  8312. }
  8313. else{
  8314. /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'TEXT']);
  8315. obj[atn] = atv;
  8316. };
  8317. });
  8318. //obj['attributes'] = att;
  8319. };//node.attributes.length>0
  8320. };//node.attributes
  8321. if(obj){
  8322. obj = $.extend( (txt!='' ? new String(txt) : {}),/* {text:txt},*/ obj || {}/*, att || {}*/);
  8323. //txt = (obj.text) ? (typeof(obj.text)=='object' ? obj.text : [obj.text || '']).concat([txt]) : txt;
  8324. txt = (obj.text) ? ([obj.text || '']).concat([txt]) : txt;
  8325. if(txt) obj.text = txt;
  8326. txt = '';
  8327. };
  8328. var out = obj || txt;
  8329. //console.log([extended, simple, out]);
  8330. if(extended){
  8331. if(txt) out = {};//new String(out);
  8332. txt = out.text || txt || '';
  8333. if(txt) out.text = txt;
  8334. if(!simple) out = myArr(out);
  8335. };
  8336. return out;
  8337. };// parseXML
  8338. // Core Function End
  8339. // Utility functions
  8340. var jsVar = function(s){ return String(s || '').replace(/-/g,"_"); };
  8341. // NEW isNum function: 01/09/2010
  8342. // Thanks to Emile Grau, GigaTecnologies S.L., www.gigatransfer.com, www.mygigamail.com
  8343. function isNum(s){
  8344. // based on utility function isNum from xml2json plugin (http://www.fyneworks.com/ - diego@fyneworks.com)
  8345. // few bugs corrected from original function :
  8346. // - syntax error : regexp.test(string) instead of string.test(reg)
  8347. // - regexp modified to accept comma as decimal mark (latin syntax : 25,24 )
  8348. // - regexp modified to reject if no number before decimal mark : ".7" is not accepted
  8349. // - string is "trimmed", allowing to accept space at the beginning and end of string
  8350. var regexp=/^((-)?([0-9]+)(([\.\,]{0,1})([0-9]+))?$)/
  8351. return (typeof s == "number") || regexp.test(String((s && typeof s == "string") ? jQuery.trim(s) : ''));
  8352. };
  8353. // OLD isNum function: (for reference only)
  8354. //var isNum = function(s){ return (typeof s == "number") || String((s && typeof s == "string") ? s : '').test(/^((-)?([0-9]*)((\.{0,1})([0-9]+))?$)/); };
  8355. var myArr = function(o){
  8356. // http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
  8357. //if(!o.length) o = [ o ]; o.length=o.length;
  8358. if(!$.isArray(o)) o = [ o ]; o.length=o.length;
  8359. // here is where you can attach additional functionality, such as searching and sorting...
  8360. return o;
  8361. };
  8362. // Utility functions End
  8363. //### PARSER LIBRARY END
  8364. // Convert plain text to xml
  8365. if(typeof xml=='string') xml = $.text2xml(xml);
  8366. // Quick fail if not xml (or if this is a node)
  8367. if(!xml.nodeType) return;
  8368. if(xml.nodeType == 3 || xml.nodeType == 4) return xml.nodeValue;
  8369. // Find xml root node
  8370. var root = (xml.nodeType == 9) ? xml.documentElement : xml;
  8371. // Convert xml to json
  8372. var out = parseXML(root, true /* simple */);
  8373. // Clean-up memory
  8374. xml = null; root = null;
  8375. // Send output
  8376. return out;
  8377. },
  8378. // Convert text to XML DOM
  8379. text2xml: function(str) {
  8380. // NOTE: I'd like to use jQuery for this, but jQuery makes all tags uppercase
  8381. //return $(xml)[0];
  8382. /* prior to jquery 1.9 */
  8383. /*
  8384. var out;
  8385. try{
  8386. var xml = ((!$.support.opacity && !$.support.style))?new ActiveXObject("Microsoft.XMLDOM"):new DOMParser();
  8387. xml.async = false;
  8388. }catch(e){ throw new Error("XML Parser could not be instantiated") };
  8389. try{
  8390. if((!$.support.opacity && !$.support.style)) out = (xml.loadXML(str))?xml:false;
  8391. else out = xml.parseFromString(str, "text/xml");
  8392. }catch(e){ throw new Error("Error parsing XML string") };
  8393. return out;
  8394. */
  8395. /* jquery 1.9+ */
  8396. return $.parseXML(str);
  8397. }
  8398. }); // extend $
  8399. })(jQuery);
  8400. (function(t,e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else if(typeof exports==="object"){module.exports=e(require("jquery"))}else{e(t.jQuery)}})(this,function(t){t.transit={version:"0.9.12",propertyMap:{marginLeft:"margin",marginRight:"margin",marginBottom:"margin",marginTop:"margin",paddingLeft:"padding",paddingRight:"padding",paddingBottom:"padding",paddingTop:"padding"},enabled:true,useTransitionEnd:false};var e=document.createElement("div");var n={};function i(t){if(t in e.style)return t;var n=["Moz","Webkit","O","ms"];var i=t.charAt(0).toUpperCase()+t.substr(1);for(var r=0;r<n.length;++r){var s=n[r]+i;if(s in e.style){return s}}}function r(){e.style[n.transform]="";e.style[n.transform]="rotateY(90deg)";return e.style[n.transform]!==""}var s=navigator.userAgent.toLowerCase().indexOf("chrome")>-1;n.transition=i("transition");n.transitionDelay=i("transitionDelay");n.transform=i("transform");n.transformOrigin=i("transformOrigin");n.filter=i("Filter");n.transform3d=r();var a={transition:"transitionend",MozTransition:"transitionend",OTransition:"oTransitionEnd",WebkitTransition:"webkitTransitionEnd",msTransition:"MSTransitionEnd"};var o=n.transitionEnd=a[n.transition]||null;for(var u in n){if(n.hasOwnProperty(u)&&typeof t.support[u]==="undefined"){t.support[u]=n[u]}}e=null;t.cssEase={_default:"ease","in":"ease-in",out:"ease-out","in-out":"ease-in-out",snap:"cubic-bezier(0,1,.5,1)",easeInCubic:"cubic-bezier(.550,.055,.675,.190)",easeOutCubic:"cubic-bezier(.215,.61,.355,1)",easeInOutCubic:"cubic-bezier(.645,.045,.355,1)",easeInCirc:"cubic-bezier(.6,.04,.98,.335)",easeOutCirc:"cubic-bezier(.075,.82,.165,1)",easeInOutCirc:"cubic-bezier(.785,.135,.15,.86)",easeInExpo:"cubic-bezier(.95,.05,.795,.035)",easeOutExpo:"cubic-bezier(.19,1,.22,1)",easeInOutExpo:"cubic-bezier(1,0,0,1)",easeInQuad:"cubic-bezier(.55,.085,.68,.53)",easeOutQuad:"cubic-bezier(.25,.46,.45,.94)",easeInOutQuad:"cubic-bezier(.455,.03,.515,.955)",easeInQuart:"cubic-bezier(.895,.03,.685,.22)",easeOutQuart:"cubic-bezier(.165,.84,.44,1)",easeInOutQuart:"cubic-bezier(.77,0,.175,1)",easeInQuint:"cubic-bezier(.755,.05,.855,.06)",easeOutQuint:"cubic-bezier(.23,1,.32,1)",easeInOutQuint:"cubic-bezier(.86,0,.07,1)",easeInSine:"cubic-bezier(.47,0,.745,.715)",easeOutSine:"cubic-bezier(.39,.575,.565,1)",easeInOutSine:"cubic-bezier(.445,.05,.55,.95)",easeInBack:"cubic-bezier(.6,-.28,.735,.045)",easeOutBack:"cubic-bezier(.175, .885,.32,1.275)",easeInOutBack:"cubic-bezier(.68,-.55,.265,1.55)"};t.cssHooks["transit:transform"]={get:function(e){return t(e).data("transform")||new f},set:function(e,i){var r=i;if(!(r instanceof f)){r=new f(r)}if(n.transform==="WebkitTransform"&&!s){e.style[n.transform]=r.toString(true)}else{e.style[n.transform]=r.toString()}t(e).data("transform",r)}};t.cssHooks.transform={set:t.cssHooks["transit:transform"].set};t.cssHooks.filter={get:function(t){return t.style[n.filter]},set:function(t,e){t.style[n.filter]=e}};if(t.fn.jquery<"1.8"){t.cssHooks.transformOrigin={get:function(t){return t.style[n.transformOrigin]},set:function(t,e){t.style[n.transformOrigin]=e}};t.cssHooks.transition={get:function(t){return t.style[n.transition]},set:function(t,e){t.style[n.transition]=e}}}p("scale");p("scaleX");p("scaleY");p("translate");p("rotate");p("rotateX");p("rotateY");p("rotate3d");p("perspective");p("skewX");p("skewY");p("x",true);p("y",true);function f(t){if(typeof t==="string"){this.parse(t)}return this}f.prototype={setFromString:function(t,e){var n=typeof e==="string"?e.split(","):e.constructor===Array?e:[e];n.unshift(t);f.prototype.set.apply(this,n)},set:function(t){var e=Array.prototype.slice.apply(arguments,[1]);if(this.setter[t]){this.setter[t].apply(this,e)}else{this[t]=e.join(",")}},get:function(t){if(this.getter[t]){return this.getter[t].apply(this)}else{return this[t]||0}},setter:{rotate:function(t){this.rotate=b(t,"deg")},rotateX:function(t){this.rotateX=b(t,"deg")},rotateY:function(t){this.rotateY=b(t,"deg")},scale:function(t,e){if(e===undefined){e=t}this.scale=t+","+e},skewX:function(t){this.skewX=b(t,"deg")},skewY:function(t){this.skewY=b(t,"deg")},perspective:function(t){this.perspective=b(t,"px")},x:function(t){this.set("translate",t,null)},y:function(t){this.set("translate",null,t)},translate:function(t,e){if(this._translateX===undefined){this._translateX=0}if(this._translateY===undefined){this._translateY=0}if(t!==null&&t!==undefined){this._translateX=b(t,"px")}if(e!==null&&e!==undefined){this._translateY=b(e,"px")}this.translate=this._translateX+","+this._translateY}},getter:{x:function(){return this._translateX||0},y:function(){return this._translateY||0},scale:function(){var t=(this.scale||"1,1").split(",");if(t[0]){t[0]=parseFloat(t[0])}if(t[1]){t[1]=parseFloat(t[1])}return t[0]===t[1]?t[0]:t},rotate3d:function(){var t=(this.rotate3d||"0,0,0,0deg").split(",");for(var e=0;e<=3;++e){if(t[e]){t[e]=parseFloat(t[e])}}if(t[3]){t[3]=b(t[3],"deg")}return t}},parse:function(t){var e=this;t.replace(/([a-zA-Z0-9]+)\((.*?)\)/g,function(t,n,i){e.setFromString(n,i)})},toString:function(t){var e=[];for(var i in this){if(this.hasOwnProperty(i)){if(!n.transform3d&&(i==="rotateX"||i==="rotateY"||i==="perspective"||i==="transformOrigin")){continue}if(i[0]!=="_"){if(t&&i==="scale"){e.push(i+"3d("+this[i]+",1)")}else if(t&&i==="translate"){e.push(i+"3d("+this[i]+",0)")}else{e.push(i+"("+this[i]+")")}}}}return e.join(" ")}};function c(t,e,n){if(e===true){t.queue(n)}else if(e){t.queue(e,n)}else{t.each(function(){n.call(this)})}}function l(e){var i=[];t.each(e,function(e){e=t.camelCase(e);e=t.transit.propertyMap[e]||t.cssProps[e]||e;e=h(e);if(n[e])e=h(n[e]);if(t.inArray(e,i)===-1){i.push(e)}});return i}function d(e,n,i,r){var s=l(e);if(t.cssEase[i]){i=t.cssEase[i]}var a=""+y(n)+" "+i;if(parseInt(r,10)>0){a+=" "+y(r)}var o=[];t.each(s,function(t,e){o.push(e+" "+a)});return o.join(", ")}t.fn.transition=t.fn.transit=function(e,i,r,s){var a=this;var u=0;var f=true;var l=t.extend(true,{},e);if(typeof i==="function"){s=i;i=undefined}if(typeof i==="object"){r=i.easing;u=i.delay||0;f=typeof i.queue==="undefined"?true:i.queue;s=i.complete;i=i.duration}if(typeof r==="function"){s=r;r=undefined}if(typeof l.easing!=="undefined"){r=l.easing;delete l.easing}if(typeof l.duration!=="undefined"){i=l.duration;delete l.duration}if(typeof l.complete!=="undefined"){s=l.complete;delete l.complete}if(typeof l.queue!=="undefined"){f=l.queue;delete l.queue}if(typeof l.delay!=="undefined"){u=l.delay;delete l.delay}if(typeof i==="undefined"){i=t.fx.speeds._default}if(typeof r==="undefined"){r=t.cssEase._default}i=y(i);var p=d(l,i,r,u);var h=t.transit.enabled&&n.transition;var b=h?parseInt(i,10)+parseInt(u,10):0;if(b===0){var g=function(t){a.css(l);if(s){s.apply(a)}if(t){t()}};c(a,f,g);return a}var m={};var v=function(e){var i=false;var r=function(){if(i){a.unbind(o,r)}if(b>0){a.each(function(){this.style[n.transition]=m[this]||null})}if(typeof s==="function"){s.apply(a)}if(typeof e==="function"){e()}};if(b>0&&o&&t.transit.useTransitionEnd){i=true;a.bind(o,r)}else{window.setTimeout(r,b)}a.each(function(){if(b>0){this.style[n.transition]=p}t(this).css(l)})};var z=function(t){this.offsetWidth;v(t)};c(a,f,z);return this};function p(e,i){if(!i){t.cssNumber[e]=true}t.transit.propertyMap[e]=n.transform;t.cssHooks[e]={get:function(n){var i=t(n).css("transit:transform");return i.get(e)},set:function(n,i){var r=t(n).css("transit:transform");r.setFromString(e,i);t(n).css({"transit:transform":r})}}}function h(t){return t.replace(/([A-Z])/g,function(t){return"-"+t.toLowerCase()})}function b(t,e){if(typeof t==="string"&&!t.match(/^[\-0-9\.]+$/)){return t}else{return""+t+e}}function y(e){var n=e;if(typeof n==="string"&&!n.match(/^[\-0-9\.]+/)){n=t.fx.speeds[n]||t.fx.speeds._default}return b(n,"ms")}t.transit.getTransitionValue=d;return t});
  8401. (function($) {
  8402. /**
  8403. * 让 jQuery 支持 Blob 类型
  8404. */
  8405. $.ajaxTransport('+*', function(options, originalOptions, jqXHR) {
  8406. if (window.FormData && ((options.dataType &&
  8407. (options.dataType === 'blob' || options.dataType === 'arraybuffer')) ||
  8408. (options.data && ((window.Blob && options.data instanceof Blob) ||
  8409. (window.ArrayBuffer && options.data instanceof ArrayBuffer)))
  8410. )) {
  8411. return {
  8412. /**
  8413. * Return a transport capable of sending and/or receiving blobs - in this case, we instantiate
  8414. * a new XMLHttpRequest and use it to actually perform the request, and funnel the result back
  8415. * into the jquery complete callback (such as the success function, done blocks, etc.)
  8416. *
  8417. * @param headers
  8418. * @param completeCallback
  8419. */
  8420. send: function(headers, completeCallback) {
  8421. var xhr = new XMLHttpRequest(),
  8422. url = options.url || window.location.href,
  8423. type = options.type || 'GET',
  8424. dataType = options.dataType || 'text',
  8425. data = options.data || null,
  8426. async = options.async || true,
  8427. key;
  8428. xhr.addEventListener('load', function() {
  8429. var response = {},
  8430. status, isSuccess;
  8431. isSuccess = xhr.status >= 200 && xhr.status < 300 || xhr.status === 304;
  8432. if (isSuccess) {
  8433. response[dataType] = xhr.response;
  8434. } else {
  8435. // In case an error occured we assume that the response body contains
  8436. // text data - so let's convert the binary data to a string which we can
  8437. // pass to the complete callback.
  8438. response.text = String.fromCharCode.apply(null, new Uint8Array(xhr.response));
  8439. }
  8440. completeCallback(xhr.status, xhr.statusText, response, xhr.getAllResponseHeaders());
  8441. });
  8442. xhr.open(type, url, async);
  8443. xhr.responseType = dataType;
  8444. for (key in headers) {
  8445. if (headers.hasOwnProperty(key)) xhr.setRequestHeader(key, headers[key]);
  8446. }
  8447. xhr.send(data);
  8448. },
  8449. abort: function() {
  8450. jqXHR.abort();
  8451. }
  8452. };
  8453. }
  8454. });
  8455. })(window.jQuery);
  8456. /*
  8457. Copyright (c) 2012 Gildas Lormeau. All rights reserved.
  8458. Redistribution and use in source and binary forms, with or without
  8459. modification, are permitted provided that the following conditions are met:
  8460. 1. Redistributions of source code must retain the above copyright notice,
  8461. this list of conditions and the following disclaimer.
  8462. 2. Redistributions in binary form must reproduce the above copyright
  8463. notice, this list of conditions and the following disclaimer in
  8464. the documentation and/or other materials provided with the distribution.
  8465. 3. The names of the authors may not be used to endorse or promote products
  8466. derived from this software without specific prior written permission.
  8467. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  8468. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  8469. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
  8470. INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
  8471. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  8472. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  8473. OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  8474. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  8475. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  8476. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  8477. */
  8478. (function(obj) {
  8479. var ERR_BAD_FORMAT = "File format is not recognized.";
  8480. var ERR_ENCRYPTED = "File contains encrypted entry.";
  8481. var ERR_ZIP64 = "File is using Zip64 (4gb+ file size).";
  8482. var ERR_READ = "Error while reading zip file.";
  8483. var ERR_WRITE = "Error while writing zip file.";
  8484. var ERR_WRITE_DATA = "Error while writing file data.";
  8485. var ERR_READ_DATA = "Error while reading file data.";
  8486. var ERR_DUPLICATED_NAME = "File already exists.";
  8487. var ERR_HTTP_RANGE = "HTTP Range not supported.";
  8488. var CHUNK_SIZE = 512 * 1024;
  8489. var INFLATE_JS = "inflate.js";
  8490. var DEFLATE_JS = "deflate.js";
  8491. var appendABViewSupported;
  8492. try {
  8493. appendABViewSupported = new Blob([ getDataHelper(0).view ]).size == 0;
  8494. } catch (e) {
  8495. }
  8496. function Crc32() {
  8497. var crc = -1, that = this;
  8498. that.append = function(data) {
  8499. var offset, table = that.table;
  8500. for (offset = 0; offset < data.length; offset++)
  8501. crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
  8502. };
  8503. that.get = function() {
  8504. return ~crc;
  8505. };
  8506. }
  8507. Crc32.prototype.table = (function() {
  8508. var i, j, t, table = [];
  8509. for (i = 0; i < 256; i++) {
  8510. t = i;
  8511. for (j = 0; j < 8; j++)
  8512. if (t & 1)
  8513. t = (t >>> 1) ^ 0xEDB88320;
  8514. else
  8515. t = t >>> 1;
  8516. table[i] = t;
  8517. }
  8518. return table;
  8519. })();
  8520. function blobSlice(blob, index, length) {
  8521. if (blob.slice)
  8522. return blob.slice(index, index + length);
  8523. else if (blob.webkitSlice)
  8524. return blob.webkitSlice(index, index + length);
  8525. else if (blob.mozSlice)
  8526. return blob.mozSlice(index, index + length);
  8527. else if (blob.msSlice)
  8528. return blob.msSlice(index, index + length);
  8529. }
  8530. function getDataHelper(byteLength, bytes) {
  8531. var dataBuffer, dataArray;
  8532. dataBuffer = new ArrayBuffer(byteLength);
  8533. dataArray = new Uint8Array(dataBuffer);
  8534. if (bytes)
  8535. dataArray.set(bytes, 0);
  8536. return {
  8537. buffer : dataBuffer,
  8538. array : dataArray,
  8539. view : new DataView(dataBuffer)
  8540. };
  8541. }
  8542. // Readers
  8543. function Reader() {
  8544. }
  8545. function TextReader(text) {
  8546. var that = this, blobReader;
  8547. function init(callback, onerror) {
  8548. var blob = new Blob([ text ], {
  8549. type : "text/plain"
  8550. });
  8551. blobReader = new BlobReader(blob);
  8552. blobReader.init(function() {
  8553. that.size = blobReader.size;
  8554. callback();
  8555. }, onerror);
  8556. }
  8557. function readUint8Array(index, length, callback, onerror) {
  8558. blobReader.readUint8Array(index, length, callback, onerror);
  8559. }
  8560. that.size = 0;
  8561. that.init = init;
  8562. that.readUint8Array = readUint8Array;
  8563. }
  8564. TextReader.prototype = new Reader();
  8565. TextReader.prototype.constructor = TextReader;
  8566. function Data64URIReader(dataURI) {
  8567. var that = this, dataStart;
  8568. function init(callback) {
  8569. var dataEnd = dataURI.length;
  8570. while (dataURI.charAt(dataEnd - 1) == "=")
  8571. dataEnd--;
  8572. dataStart = dataURI.indexOf(",") + 1;
  8573. that.size = Math.floor((dataEnd - dataStart) * 0.75);
  8574. callback();
  8575. }
  8576. function readUint8Array(index, length, callback) {
  8577. var i, data = getDataHelper(length);
  8578. var start = Math.floor(index / 3) * 4;
  8579. var end = Math.ceil((index + length) / 3) * 4;
  8580. var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart));
  8581. var delta = index - Math.floor(start / 4) * 3;
  8582. for (i = delta; i < delta + length; i++)
  8583. data.array[i - delta] = bytes.charCodeAt(i);
  8584. callback(data.array);
  8585. }
  8586. that.size = 0;
  8587. that.init = init;
  8588. that.readUint8Array = readUint8Array;
  8589. }
  8590. Data64URIReader.prototype = new Reader();
  8591. Data64URIReader.prototype.constructor = Data64URIReader;
  8592. function BlobReader(blob) {
  8593. var that = this;
  8594. function init(callback) {
  8595. this.size = blob.size;
  8596. callback();
  8597. }
  8598. function readUint8Array(index, length, callback, onerror) {
  8599. var reader = new FileReader();
  8600. reader.onload = function(e) {
  8601. callback(new Uint8Array(e.target.result));
  8602. };
  8603. reader.onerror = onerror;
  8604. reader.readAsArrayBuffer(blobSlice(blob, index, length));
  8605. }
  8606. that.size = 0;
  8607. that.init = init;
  8608. that.readUint8Array = readUint8Array;
  8609. }
  8610. BlobReader.prototype = new Reader();
  8611. BlobReader.prototype.constructor = BlobReader;
  8612. function HttpReader(url) {
  8613. var that = this;
  8614. function getData(callback, onerror) {
  8615. var request;
  8616. if (!that.data) {
  8617. request = new XMLHttpRequest();
  8618. request.addEventListener("load", function() {
  8619. if (!that.size)
  8620. that.size = Number(request.getResponseHeader("Content-Length"));
  8621. that.data = new Uint8Array(request.response);
  8622. callback();
  8623. }, false);
  8624. request.addEventListener("error", onerror, false);
  8625. request.open("GET", url);
  8626. request.responseType = "arraybuffer";
  8627. request.send();
  8628. } else
  8629. callback();
  8630. }
  8631. function init(callback, onerror) {
  8632. var request = new XMLHttpRequest();
  8633. request.addEventListener("load", function() {
  8634. that.size = Number(request.getResponseHeader("Content-Length"));
  8635. callback();
  8636. }, false);
  8637. request.addEventListener("error", onerror, false);
  8638. request.open("HEAD", url);
  8639. request.send();
  8640. }
  8641. function readUint8Array(index, length, callback, onerror) {
  8642. getData(function() {
  8643. callback(new Uint8Array(that.data.subarray(index, index + length)));
  8644. }, onerror);
  8645. }
  8646. that.size = 0;
  8647. that.init = init;
  8648. that.readUint8Array = readUint8Array;
  8649. }
  8650. HttpReader.prototype = new Reader();
  8651. HttpReader.prototype.constructor = HttpReader;
  8652. function HttpRangeReader(url) {
  8653. var that = this;
  8654. function init(callback, onerror) {
  8655. var request = new XMLHttpRequest();
  8656. request.addEventListener("load", function() {
  8657. that.size = Number(request.getResponseHeader("Content-Length"));
  8658. if (request.getResponseHeader("Accept-Ranges") == "bytes")
  8659. callback();
  8660. else
  8661. onerror(ERR_HTTP_RANGE);
  8662. }, false);
  8663. request.addEventListener("error", onerror, false);
  8664. request.open("HEAD", url);
  8665. request.send();
  8666. }
  8667. function readArrayBuffer(index, length, callback, onerror) {
  8668. var request = new XMLHttpRequest();
  8669. request.open("GET", url);
  8670. request.responseType = "arraybuffer";
  8671. request.setRequestHeader("Range", "bytes=" + index + "-" + (index + length - 1));
  8672. request.addEventListener("load", function() {
  8673. callback(request.response);
  8674. }, false);
  8675. request.addEventListener("error", onerror, false);
  8676. request.send();
  8677. }
  8678. function readUint8Array(index, length, callback, onerror) {
  8679. readArrayBuffer(index, length, function(arraybuffer) {
  8680. callback(new Uint8Array(arraybuffer));
  8681. }, onerror);
  8682. }
  8683. that.size = 0;
  8684. that.init = init;
  8685. that.readUint8Array = readUint8Array;
  8686. }
  8687. HttpRangeReader.prototype = new Reader();
  8688. HttpRangeReader.prototype.constructor = HttpRangeReader;
  8689. // Writers
  8690. function Writer() {
  8691. }
  8692. Writer.prototype.getData = function(callback) {
  8693. callback(this.data);
  8694. };
  8695. function TextWriter() {
  8696. var that = this, blob;
  8697. function init(callback) {
  8698. blob = new Blob([], {
  8699. type : "text/plain"
  8700. });
  8701. callback();
  8702. }
  8703. function writeUint8Array(array, callback) {
  8704. blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
  8705. type : "text/plain"
  8706. });
  8707. callback();
  8708. }
  8709. function getData(callback, onerror) {
  8710. var reader = new FileReader();
  8711. reader.onload = function(e) {
  8712. callback(e.target.result);
  8713. };
  8714. reader.onerror = onerror;
  8715. reader.readAsText(blob);
  8716. }
  8717. that.init = init;
  8718. that.writeUint8Array = writeUint8Array;
  8719. that.getData = getData;
  8720. }
  8721. TextWriter.prototype = new Writer();
  8722. TextWriter.prototype.constructor = TextWriter;
  8723. function Data64URIWriter(contentType) {
  8724. var that = this, data = "", pending = "";
  8725. function init(callback) {
  8726. data += "data:" + (contentType || "") + ";base64,";
  8727. callback();
  8728. }
  8729. function writeUint8Array(array, callback) {
  8730. var i, delta = pending.length, dataString = pending;
  8731. pending = "";
  8732. for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++)
  8733. dataString += String.fromCharCode(array[i]);
  8734. for (; i < array.length; i++)
  8735. pending += String.fromCharCode(array[i]);
  8736. if (dataString.length > 2)
  8737. data += obj.btoa(dataString);
  8738. else
  8739. pending = dataString;
  8740. callback();
  8741. }
  8742. function getData(callback) {
  8743. callback(data + obj.btoa(pending));
  8744. }
  8745. that.init = init;
  8746. that.writeUint8Array = writeUint8Array;
  8747. that.getData = getData;
  8748. }
  8749. Data64URIWriter.prototype = new Writer();
  8750. Data64URIWriter.prototype.constructor = Data64URIWriter;
  8751. function FileWriter(fileEntry, contentType) {
  8752. var writer, that = this;
  8753. function init(callback, onerror) {
  8754. fileEntry.createWriter(function(fileWriter) {
  8755. writer = fileWriter;
  8756. callback();
  8757. }, onerror);
  8758. }
  8759. function writeUint8Array(array, callback, onerror) {
  8760. var blob = new Blob([ appendABViewSupported ? array : array.buffer ], {
  8761. type : contentType
  8762. });
  8763. writer.onwrite = function() {
  8764. writer.onwrite = null;
  8765. callback();
  8766. };
  8767. writer.onerror = onerror;
  8768. writer.write(blob);
  8769. }
  8770. function getData(callback) {
  8771. fileEntry.file(callback);
  8772. }
  8773. that.init = init;
  8774. that.writeUint8Array = writeUint8Array;
  8775. that.getData = getData;
  8776. }
  8777. FileWriter.prototype = new Writer();
  8778. FileWriter.prototype.constructor = FileWriter;
  8779. function BlobWriter(contentType) {
  8780. var blob, that = this;
  8781. function init(callback) {
  8782. blob = new Blob([], {
  8783. type : contentType
  8784. });
  8785. callback();
  8786. }
  8787. function writeUint8Array(array, callback) {
  8788. blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
  8789. type : contentType
  8790. });
  8791. callback();
  8792. }
  8793. function getData(callback) {
  8794. callback(blob);
  8795. }
  8796. that.init = init;
  8797. that.writeUint8Array = writeUint8Array;
  8798. that.getData = getData;
  8799. }
  8800. BlobWriter.prototype = new Writer();
  8801. BlobWriter.prototype.constructor = BlobWriter;
  8802. // inflate/deflate core functions
  8803. function launchWorkerProcess(worker, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
  8804. var chunkIndex = 0, index, outputSize;
  8805. function onflush() {
  8806. worker.removeEventListener("message", onmessage, false);
  8807. onend(outputSize);
  8808. }
  8809. function onmessage(event) {
  8810. var message = event.data, data = message.data;
  8811. if (message.onappend) {
  8812. outputSize += data.length;
  8813. writer.writeUint8Array(data, function() {
  8814. onappend(false, data);
  8815. step();
  8816. }, onwriteerror);
  8817. }
  8818. if (message.onflush)
  8819. if (data) {
  8820. outputSize += data.length;
  8821. writer.writeUint8Array(data, function() {
  8822. onappend(false, data);
  8823. onflush();
  8824. }, onwriteerror);
  8825. } else
  8826. onflush();
  8827. if (message.progress && onprogress)
  8828. onprogress(index + message.current, size);
  8829. }
  8830. function step() {
  8831. index = chunkIndex * CHUNK_SIZE;
  8832. if (index < size)
  8833. reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
  8834. worker.postMessage({
  8835. append : true,
  8836. data : array
  8837. });
  8838. chunkIndex++;
  8839. if (onprogress)
  8840. onprogress(index, size);
  8841. onappend(true, array);
  8842. }, onreaderror);
  8843. else
  8844. worker.postMessage({
  8845. flush : true
  8846. });
  8847. }
  8848. outputSize = 0;
  8849. worker.addEventListener("message", onmessage, false);
  8850. step();
  8851. }
  8852. function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
  8853. var chunkIndex = 0, index, outputSize = 0;
  8854. function step() {
  8855. var outputData;
  8856. index = chunkIndex * CHUNK_SIZE;
  8857. if (index < size)
  8858. reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) {
  8859. var outputData = process.append(inputData, function() {
  8860. if (onprogress)
  8861. onprogress(offset + index, size);
  8862. });
  8863. outputSize += outputData.length;
  8864. onappend(true, inputData);
  8865. writer.writeUint8Array(outputData, function() {
  8866. onappend(false, outputData);
  8867. chunkIndex++;
  8868. setTimeout(step, 1);
  8869. }, onwriteerror);
  8870. if (onprogress)
  8871. onprogress(index, size);
  8872. }, onreaderror);
  8873. else {
  8874. outputData = process.flush();
  8875. if (outputData) {
  8876. outputSize += outputData.length;
  8877. writer.writeUint8Array(outputData, function() {
  8878. onappend(false, outputData);
  8879. onend(outputSize);
  8880. }, onwriteerror);
  8881. } else
  8882. onend(outputSize);
  8883. }
  8884. }
  8885. step();
  8886. }
  8887. function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
  8888. var worker, crc32 = new Crc32();
  8889. function oninflateappend(sending, array) {
  8890. if (computeCrc32 && !sending)
  8891. crc32.append(array);
  8892. }
  8893. function oninflateend(outputSize) {
  8894. onend(outputSize, crc32.get());
  8895. }
  8896. if (obj.zip.useWebWorkers) {
  8897. worker = new Worker(obj.zip.inflateJSPath || INFLATE_JS);//INFLATE_JS
  8898. launchWorkerProcess(worker, reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
  8899. } else
  8900. launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
  8901. return worker;
  8902. }
  8903. function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
  8904. var worker, crc32 = new Crc32();
  8905. function ondeflateappend(sending, array) {
  8906. if (sending)
  8907. crc32.append(array);
  8908. }
  8909. function ondeflateend(outputSize) {
  8910. onend(outputSize, crc32.get());
  8911. }
  8912. function onmessage() {
  8913. worker.removeEventListener("message", onmessage, false);
  8914. launchWorkerProcess(worker, reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
  8915. }
  8916. if (obj.zip.useWebWorkers) {
  8917. worker = new Worker(obj.zip.workerScriptsPath + DEFLATE_JS);
  8918. worker.addEventListener("message", onmessage, false);
  8919. worker.postMessage({
  8920. init : true,
  8921. level : level
  8922. });
  8923. } else
  8924. launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
  8925. return worker;
  8926. }
  8927. function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
  8928. var chunkIndex = 0, crc32 = new Crc32();
  8929. function step() {
  8930. var index = chunkIndex * CHUNK_SIZE;
  8931. if (index < size)
  8932. reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
  8933. if (computeCrc32)
  8934. crc32.append(array);
  8935. if (onprogress)
  8936. onprogress(index, size, array);
  8937. writer.writeUint8Array(array, function() {
  8938. chunkIndex++;
  8939. step();
  8940. }, onwriteerror);
  8941. }, onreaderror);
  8942. else
  8943. onend(size, crc32.get());
  8944. }
  8945. step();
  8946. }
  8947. // ZipReader
  8948. function decodeASCII(str) {
  8949. var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB',
  8950. '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9',
  8951. '\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1',
  8952. '\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6',
  8953. '\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3',
  8954. '\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE',
  8955. '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE',
  8956. '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
  8957. '\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ];
  8958. for (i = 0; i < str.length; i++) {
  8959. charCode = str.charCodeAt(i) & 0xFF;
  8960. if (charCode > 127)
  8961. out += extendedASCII[charCode - 128];
  8962. else
  8963. out += String.fromCharCode(charCode);
  8964. }
  8965. return out;
  8966. }
  8967. function decodeUTF8(str_data) {
  8968. var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0;
  8969. str_data += '';
  8970. while (i < str_data.length) {
  8971. c1 = str_data.charCodeAt(i);
  8972. if (c1 < 128) {
  8973. tmp_arr[ac++] = String.fromCharCode(c1);
  8974. i++;
  8975. } else if (c1 > 191 && c1 < 224) {
  8976. c2 = str_data.charCodeAt(i + 1);
  8977. tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
  8978. i += 2;
  8979. } else {
  8980. c2 = str_data.charCodeAt(i + 1);
  8981. c3 = str_data.charCodeAt(i + 2);
  8982. tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  8983. i += 3;
  8984. }
  8985. }
  8986. return tmp_arr.join('');
  8987. }
  8988. function getString(bytes) {
  8989. var i, str = "";
  8990. for (i = 0; i < bytes.length; i++)
  8991. str += String.fromCharCode(bytes[i]);
  8992. return str;
  8993. }
  8994. function getDate(timeRaw) {
  8995. var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
  8996. try {
  8997. return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5,
  8998. (time & 0x001F) * 2, 0);
  8999. } catch (e) {
  9000. }
  9001. }
  9002. function readCommonHeader(entry, data, index, centralDirectory, onerror) {
  9003. entry.version = data.view.getUint16(index, true);
  9004. entry.bitFlag = data.view.getUint16(index + 2, true);
  9005. entry.compressionMethod = data.view.getUint16(index + 4, true);
  9006. entry.lastModDateRaw = data.view.getUint32(index + 6, true);
  9007. entry.lastModDate = getDate(entry.lastModDateRaw);
  9008. if ((entry.bitFlag & 0x01) === 0x01) {
  9009. onerror(ERR_ENCRYPTED);
  9010. return;
  9011. }
  9012. if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) {
  9013. entry.crc32 = data.view.getUint32(index + 10, true);
  9014. entry.compressedSize = data.view.getUint32(index + 14, true);
  9015. entry.uncompressedSize = data.view.getUint32(index + 18, true);
  9016. }
  9017. if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) {
  9018. onerror(ERR_ZIP64);
  9019. return;
  9020. }
  9021. entry.filenameLength = data.view.getUint16(index + 22, true);
  9022. entry.extraFieldLength = data.view.getUint16(index + 24, true);
  9023. }
  9024. function createZipReader(reader, onerror) {
  9025. function Entry() {
  9026. }
  9027. Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) {
  9028. var that = this, worker;
  9029. function terminate(callback, param) {
  9030. if (worker)
  9031. worker.terminate();
  9032. worker = null;
  9033. if (callback)
  9034. callback(param);
  9035. }
  9036. function testCrc32(crc32) {
  9037. var dataCrc32 = getDataHelper(4);
  9038. dataCrc32.view.setUint32(0, crc32);
  9039. return that.crc32 == dataCrc32.view.getUint32(0);
  9040. }
  9041. function getWriterData(uncompressedSize, crc32) {
  9042. if (checkCrc32 && !testCrc32(crc32))
  9043. onreaderror();
  9044. else
  9045. writer.getData(function(data) {
  9046. terminate(onend, data);
  9047. });
  9048. }
  9049. function onreaderror() {
  9050. terminate(onerror, ERR_READ_DATA);
  9051. }
  9052. function onwriteerror() {
  9053. terminate(onerror, ERR_WRITE_DATA);
  9054. }
  9055. reader.readUint8Array(that.offset, 30, function(bytes) {
  9056. var data = getDataHelper(bytes.length, bytes), dataOffset;
  9057. if (data.view.getUint32(0) != 0x504b0304) {
  9058. onerror(ERR_BAD_FORMAT);
  9059. return;
  9060. }
  9061. readCommonHeader(that, data, 4, false, function(error) {
  9062. onerror(error);
  9063. return;
  9064. });
  9065. dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
  9066. writer.init(function() {
  9067. if (that.compressionMethod === 0)
  9068. copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
  9069. else
  9070. worker = inflate(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
  9071. }, onwriteerror);
  9072. }, onreaderror);
  9073. };
  9074. function seekEOCDR(offset, entriesCallback) {
  9075. reader.readUint8Array(reader.size - offset, offset, function(bytes) {
  9076. var dataView = getDataHelper(bytes.length, bytes).view;
  9077. try{
  9078. if (dataView.getUint32(0) != 0x504b0506) {
  9079. seekEOCDR(offset + 1, entriesCallback);
  9080. } else {
  9081. entriesCallback(dataView);
  9082. }
  9083. }catch(e){
  9084. onerror(ERR_READ);
  9085. }
  9086. }, function() {
  9087. onerror(ERR_READ);
  9088. });
  9089. }
  9090. return {
  9091. getEntries : function(callback) {
  9092. if (reader.size < 22) {
  9093. onerror(ERR_BAD_FORMAT);
  9094. return;
  9095. }
  9096. // look for End of central directory record
  9097. seekEOCDR(22, function(dataView) {
  9098. var datalength, fileslength;
  9099. datalength = dataView.getUint32(16, true);
  9100. fileslength = dataView.getUint16(8, true);
  9101. reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
  9102. var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes);
  9103. for (i = 0; i < fileslength; i++) {
  9104. entry = new Entry();
  9105. if (data.view.getUint32(index) != 0x504b0102) {
  9106. onerror(ERR_BAD_FORMAT);
  9107. return;
  9108. }
  9109. readCommonHeader(entry, data, index + 6, true, function(error) {
  9110. onerror(error);
  9111. return;
  9112. });
  9113. entry.commentLength = data.view.getUint16(index + 32, true);
  9114. entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10);
  9115. entry.offset = data.view.getUint32(index + 42, true);
  9116. filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
  9117. entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
  9118. if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
  9119. entry.directory = true;
  9120. comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46
  9121. + entry.filenameLength + entry.extraFieldLength + entry.commentLength));
  9122. entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
  9123. entries.push(entry);
  9124. index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength;
  9125. }
  9126. callback(entries);
  9127. }, function() {
  9128. onerror(ERR_READ);
  9129. });
  9130. });
  9131. },
  9132. close : function(callback) {
  9133. if (callback)
  9134. callback();
  9135. }
  9136. };
  9137. }
  9138. // ZipWriter
  9139. function encodeUTF8(string) {
  9140. var n, c1, enc, utftext = [], start = 0, end = 0, stringl = string.length;
  9141. for (n = 0; n < stringl; n++) {
  9142. c1 = string.charCodeAt(n);
  9143. enc = null;
  9144. if (c1 < 128)
  9145. end++;
  9146. else if (c1 > 127 && c1 < 2048)
  9147. enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);
  9148. else
  9149. enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128);
  9150. if (enc != null) {
  9151. if (end > start)
  9152. utftext += string.slice(start, end);
  9153. utftext += enc;
  9154. start = end = n + 1;
  9155. }
  9156. }
  9157. if (end > start)
  9158. utftext += string.slice(start, stringl);
  9159. return utftext;
  9160. }
  9161. function getBytes(str) {
  9162. var i, array = [];
  9163. for (i = 0; i < str.length; i++)
  9164. array.push(str.charCodeAt(i));
  9165. return array;
  9166. }
  9167. function createZipWriter(writer, onerror, dontDeflate) {
  9168. var worker, files = [], filenames = [], datalength = 0;
  9169. function terminate(callback, message) {
  9170. if (worker)
  9171. worker.terminate();
  9172. worker = null;
  9173. if (callback)
  9174. callback(message);
  9175. }
  9176. function onwriteerror() {
  9177. terminate(onerror, ERR_WRITE);
  9178. }
  9179. function onreaderror() {
  9180. terminate(onerror, ERR_READ_DATA);
  9181. }
  9182. return {
  9183. add : function(name, reader, onend, onprogress, options) {
  9184. var header, filename, date;
  9185. function writeHeader(callback) {
  9186. var data;
  9187. date = options.lastModDate || new Date();
  9188. header = getDataHelper(26);
  9189. files[name] = {
  9190. headerArray : header.array,
  9191. directory : options.directory,
  9192. filename : filename,
  9193. offset : datalength,
  9194. comment : getBytes(encodeUTF8(options.comment || ""))
  9195. };
  9196. header.view.setUint32(0, 0x14000808);
  9197. if (options.version)
  9198. header.view.setUint8(0, options.version);
  9199. if (!dontDeflate && options.level != 0 && !options.directory)
  9200. header.view.setUint16(4, 0x0800);
  9201. header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true);
  9202. header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true);
  9203. header.view.setUint16(22, filename.length, true);
  9204. data = getDataHelper(30 + filename.length);
  9205. data.view.setUint32(0, 0x504b0304);
  9206. data.array.set(header.array, 4);
  9207. data.array.set(filename, 30);
  9208. datalength += data.array.length;
  9209. writer.writeUint8Array(data.array, callback, onwriteerror);
  9210. }
  9211. function writeFooter(compressedLength, crc32) {
  9212. var footer = getDataHelper(16);
  9213. datalength += compressedLength || 0;
  9214. footer.view.setUint32(0, 0x504b0708);
  9215. if (typeof crc32 != "undefined") {
  9216. header.view.setUint32(10, crc32, true);
  9217. footer.view.setUint32(4, crc32, true);
  9218. }
  9219. if (reader) {
  9220. footer.view.setUint32(8, compressedLength, true);
  9221. header.view.setUint32(14, compressedLength, true);
  9222. footer.view.setUint32(12, reader.size, true);
  9223. header.view.setUint32(18, reader.size, true);
  9224. }
  9225. writer.writeUint8Array(footer.array, function() {
  9226. datalength += 16;
  9227. terminate(onend);
  9228. }, onwriteerror);
  9229. }
  9230. function writeFile() {
  9231. options = options || {};
  9232. name = name.trim();
  9233. if (options.directory && name.charAt(name.length - 1) != "/")
  9234. name += "/";
  9235. if (files[name])
  9236. throw ERR_DUPLICATED_NAME;
  9237. filename = getBytes(encodeUTF8(name));
  9238. filenames.push(name);
  9239. writeHeader(function() {
  9240. if (reader)
  9241. if (dontDeflate || options.level == 0)
  9242. copy(reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror);
  9243. else
  9244. worker = deflate(reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror);
  9245. else
  9246. writeFooter();
  9247. }, onwriteerror);
  9248. }
  9249. if (reader)
  9250. reader.init(writeFile, onreaderror);
  9251. else
  9252. writeFile();
  9253. },
  9254. close : function(callback) {
  9255. var data, length = 0, index = 0;
  9256. filenames.forEach(function(name) {
  9257. var file = files[name];
  9258. length += 46 + file.filename.length + file.comment.length;
  9259. });
  9260. data = getDataHelper(length + 22);
  9261. filenames.forEach(function(name) {
  9262. var file = files[name];
  9263. data.view.setUint32(index, 0x504b0102);
  9264. data.view.setUint16(index + 4, 0x1400);
  9265. data.array.set(file.headerArray, index + 6);
  9266. data.view.setUint16(index + 32, file.comment.length, true);
  9267. if (file.directory)
  9268. data.view.setUint8(index + 38, 0x10);
  9269. data.view.setUint32(index + 42, file.offset, true);
  9270. data.array.set(file.filename, index + 46);
  9271. data.array.set(file.comment, index + 46 + file.filename.length);
  9272. index += 46 + file.filename.length + file.comment.length;
  9273. });
  9274. data.view.setUint32(index, 0x504b0506);
  9275. data.view.setUint16(index + 8, filenames.length, true);
  9276. data.view.setUint16(index + 10, filenames.length, true);
  9277. data.view.setUint32(index + 12, length, true);
  9278. data.view.setUint32(index + 16, datalength, true);
  9279. writer.writeUint8Array(data.array, function() {
  9280. terminate(function() {
  9281. writer.getData(callback);
  9282. });
  9283. }, onwriteerror);
  9284. }
  9285. };
  9286. }
  9287. obj.zip = {
  9288. Reader : Reader,
  9289. Writer : Writer,
  9290. BlobReader : BlobReader,
  9291. HttpReader : HttpReader,
  9292. HttpRangeReader : HttpRangeReader,
  9293. Data64URIReader : Data64URIReader,
  9294. TextReader : TextReader,
  9295. BlobWriter : BlobWriter,
  9296. FileWriter : FileWriter,
  9297. Data64URIWriter : Data64URIWriter,
  9298. TextWriter : TextWriter,
  9299. createReader : function(reader, callback, onerror) {
  9300. reader.init(function() {
  9301. callback(createZipReader(reader, onerror));
  9302. }, onerror);
  9303. },
  9304. createWriter : function(writer, callback, onerror, dontDeflate) {
  9305. writer.init(function() {
  9306. callback(createZipWriter(writer, onerror, dontDeflate));
  9307. }, onerror);
  9308. },
  9309. workerScriptsPath : "",
  9310. inflateJSPath:"",
  9311. useWebWorkers : true
  9312. };
  9313. })(this);
  9314. /*!
  9315. * ZeroClipboard
  9316. * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.
  9317. * Copyright (c) 2014 Jon Rohan, James M. Greene
  9318. * Licensed MIT
  9319. * http://zeroclipboard.org/
  9320. * v2.1.6
  9321. */
  9322. !function(a,b){"use strict";var c,d,e=a,f=e.document,g=e.navigator,h=e.setTimeout,i=e.encodeURIComponent,j=e.ActiveXObject,k=e.Error,l=e.Number.parseInt||e.parseInt,m=e.Number.parseFloat||e.parseFloat,n=e.Number.isNaN||e.isNaN,o=e.Math.round,p=e.Date.now,q=e.Object.keys,r=e.Object.defineProperty,s=e.Object.prototype.hasOwnProperty,t=e.Array.prototype.slice,u=function(){var a=function(a){return a};if("function"==typeof e.wrap&&"function"==typeof e.unwrap)try{var b=f.createElement("div"),c=e.unwrap(b);1===b.nodeType&&c&&1===c.nodeType&&(a=e.unwrap)}catch(d){}return a}(),v=function(a){return t.call(a,0)},w=function(){var a,c,d,e,f,g,h=v(arguments),i=h[0]||{};for(a=1,c=h.length;c>a;a++)if(null!=(d=h[a]))for(e in d)s.call(d,e)&&(f=i[e],g=d[e],i!==g&&g!==b&&(i[e]=g));return i},x=function(a){var b,c,d,e;if("object"!=typeof a||null==a)b=a;else if("number"==typeof a.length)for(b=[],c=0,d=a.length;d>c;c++)s.call(a,c)&&(b[c]=x(a[c]));else{b={};for(e in a)s.call(a,e)&&(b[e]=x(a[e]))}return b},y=function(a,b){for(var c={},d=0,e=b.length;e>d;d++)b[d]in a&&(c[b[d]]=a[b[d]]);return c},z=function(a,b){var c={};for(var d in a)-1===b.indexOf(d)&&(c[d]=a[d]);return c},A=function(a){if(a)for(var b in a)s.call(a,b)&&delete a[b];return a},B=function(a,b){if(a&&1===a.nodeType&&a.ownerDocument&&b&&(1===b.nodeType&&b.ownerDocument&&b.ownerDocument===a.ownerDocument||9===b.nodeType&&!b.ownerDocument&&b===a.ownerDocument))do{if(a===b)return!0;a=a.parentNode}while(a);return!1},C=function(a){var b;return"string"==typeof a&&a&&(b=a.split("#")[0].split("?")[0],b=a.slice(0,a.lastIndexOf("/")+1)),b},D=function(a){var b,c;return"string"==typeof a&&a&&(c=a.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]?b=c[1]:(c=a.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]&&(b=c[1]))),b},E=function(){var a,b;try{throw new k}catch(c){b=c}return b&&(a=b.sourceURL||b.fileName||D(b.stack)),a},F=function(){var a,c,d;if(f.currentScript&&(a=f.currentScript.src))return a;if(c=f.getElementsByTagName("script"),1===c.length)return c[0].src||b;if("readyState"in c[0])for(d=c.length;d--;)if("interactive"===c[d].readyState&&(a=c[d].src))return a;return"loading"===f.readyState&&(a=c[c.length-1].src)?a:(a=E())?a:b},G=function(){var a,c,d,e=f.getElementsByTagName("script");for(a=e.length;a--;){if(!(d=e[a].src)){c=null;break}if(d=C(d),null==c)c=d;else if(c!==d){c=null;break}}return c||b},H=function(){var a=C(F())||G()||"";return a+"ZeroClipboard.swf"},I={bridge:null,version:"0.0.0",pluginType:"unknown",disabled:null,outdated:null,unavailable:null,deactivated:null,overdue:null,ready:null},J="11.0.0",K={},L={},M=null,N={ready:"Flash communication is established",error:{"flash-disabled":"Flash is disabled or not installed","flash-outdated":"Flash is too outdated to support ZeroClipboard","flash-unavailable":"Flash is unable to communicate bidirectionally with JavaScript","flash-deactivated":"Flash is too outdated for your browser and/or is configured as click-to-activate","flash-overdue":"Flash communication was established but NOT within the acceptable time limit"}},O={swfPath:H(),trustedDomains:a.location.host?[a.location.host]:[],cacheBust:!0,forceEnhancedClipboard:!1,flashLoadTimeout:3e4,autoActivate:!0,bubbleEvents:!0,containerId:"global-zeroclipboard-html-bridge",containerClass:"global-zeroclipboard-container",swfObjectId:"global-zeroclipboard-flash-bridge",hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",forceHandCursor:!1,title:null,zIndex:999999999},P=function(a){if("object"==typeof a&&null!==a)for(var b in a)if(s.call(a,b))if(/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(b))O[b]=a[b];else if(null==I.bridge)if("containerId"===b||"swfObjectId"===b){if(!cb(a[b]))throw new Error("The specified `"+b+"` value is not valid as an HTML4 Element ID");O[b]=a[b]}else O[b]=a[b];{if("string"!=typeof a||!a)return x(O);if(s.call(O,a))return O[a]}},Q=function(){return{browser:y(g,["userAgent","platform","appName"]),flash:z(I,["bridge"]),zeroclipboard:{version:Fb.version,config:Fb.config()}}},R=function(){return!!(I.disabled||I.outdated||I.unavailable||I.deactivated)},S=function(a,b){var c,d,e,f={};if("string"==typeof a&&a)e=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)s.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&Fb.on(c,a[c]);if(e&&e.length){for(c=0,d=e.length;d>c;c++)a=e[c].replace(/^on/,""),f[a]=!0,K[a]||(K[a]=[]),K[a].push(b);if(f.ready&&I.ready&&Fb.emit({type:"ready"}),f.error){var g=["disabled","outdated","unavailable","deactivated","overdue"];for(c=0,d=g.length;d>c;c++)if(I[g[c]]===!0){Fb.emit({type:"error",name:"flash-"+g[c]});break}}}return Fb},T=function(a,b){var c,d,e,f,g;if(0===arguments.length)f=q(K);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)s.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&Fb.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=K[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return Fb},U=function(a){var b;return b="string"==typeof a&&a?x(K[a])||null:x(K)},V=function(a){var b,c,d;return a=db(a),a&&!jb(a)?"ready"===a.type&&I.overdue===!0?Fb.emit({type:"error",name:"flash-overdue"}):(b=w({},a),ib.call(this,b),"copy"===a.type&&(d=pb(L),c=d.data,M=d.formatMap),c):void 0},W=function(){if("boolean"!=typeof I.ready&&(I.ready=!1),!Fb.isFlashUnusable()&&null===I.bridge){var a=O.flashLoadTimeout;"number"==typeof a&&a>=0&&h(function(){"boolean"!=typeof I.deactivated&&(I.deactivated=!0),I.deactivated===!0&&Fb.emit({type:"error",name:"flash-deactivated"})},a),I.overdue=!1,nb()}},X=function(){Fb.clearData(),Fb.blur(),Fb.emit("destroy"),ob(),Fb.off()},Y=function(a,b){var c;if("object"==typeof a&&a&&"undefined"==typeof b)c=a,Fb.clearData();else{if("string"!=typeof a||!a)return;c={},c[a]=b}for(var d in c)"string"==typeof d&&d&&s.call(c,d)&&"string"==typeof c[d]&&c[d]&&(L[d]=c[d])},Z=function(a){"undefined"==typeof a?(A(L),M=null):"string"==typeof a&&s.call(L,a)&&delete L[a]},$=function(a){return"undefined"==typeof a?x(L):"string"==typeof a&&s.call(L,a)?L[a]:void 0},_=function(a){if(a&&1===a.nodeType){c&&(xb(c,O.activeClass),c!==a&&xb(c,O.hoverClass)),c=a,wb(a,O.hoverClass);var b=a.getAttribute("title")||O.title;if("string"==typeof b&&b){var d=mb(I.bridge);d&&d.setAttribute("title",b)}var e=O.forceHandCursor===!0||"pointer"===yb(a,"cursor");Cb(e),Bb()}},ab=function(){var a=mb(I.bridge);a&&(a.removeAttribute("title"),a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.top="1px"),c&&(xb(c,O.hoverClass),xb(c,O.activeClass),c=null)},bb=function(){return c||null},cb=function(a){return"string"==typeof a&&a&&/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(a)},db=function(a){var b;if("string"==typeof a&&a?(b=a,a={}):"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(b=a.type),b){!a.target&&/^(copy|aftercopy|_click)$/.test(b.toLowerCase())&&(a.target=d),w(a,{type:b.toLowerCase(),target:a.target||c||null,relatedTarget:a.relatedTarget||null,currentTarget:I&&I.bridge||null,timeStamp:a.timeStamp||p()||null});var e=N[a.type];return"error"===a.type&&a.name&&e&&(e=e[a.name]),e&&(a.message=e),"ready"===a.type&&w(a,{target:null,version:I.version}),"error"===a.type&&(/^flash-(disabled|outdated|unavailable|deactivated|overdue)$/.test(a.name)&&w(a,{target:null,minimumVersion:J}),/^flash-(outdated|unavailable|deactivated|overdue)$/.test(a.name)&&w(a,{version:I.version})),"copy"===a.type&&(a.clipboardData={setData:Fb.setData,clearData:Fb.clearData}),"aftercopy"===a.type&&(a=qb(a,M)),a.target&&!a.relatedTarget&&(a.relatedTarget=eb(a.target)),a=fb(a)}},eb=function(a){var b=a&&a.getAttribute&&a.getAttribute("data-clipboard-target");return b?f.getElementById(b):null},fb=function(a){if(a&&/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)){var c=a.target,d="_mouseover"===a.type&&a.relatedTarget?a.relatedTarget:b,g="_mouseout"===a.type&&a.relatedTarget?a.relatedTarget:b,h=Ab(c),i=e.screenLeft||e.screenX||0,j=e.screenTop||e.screenY||0,k=f.body.scrollLeft+f.documentElement.scrollLeft,l=f.body.scrollTop+f.documentElement.scrollTop,m=h.left+("number"==typeof a._stageX?a._stageX:0),n=h.top+("number"==typeof a._stageY?a._stageY:0),o=m-k,p=n-l,q=i+o,r=j+p,s="number"==typeof a.movementX?a.movementX:0,t="number"==typeof a.movementY?a.movementY:0;delete a._stageX,delete a._stageY,w(a,{srcElement:c,fromElement:d,toElement:g,screenX:q,screenY:r,pageX:m,pageY:n,clientX:o,clientY:p,x:o,y:p,movementX:s,movementY:t,offsetX:0,offsetY:0,layerX:0,layerY:0})}return a},gb=function(a){var b=a&&"string"==typeof a.type&&a.type||"";return!/^(?:(?:before)?copy|destroy)$/.test(b)},hb=function(a,b,c,d){d?h(function(){a.apply(b,c)},0):a.apply(b,c)},ib=function(a){if("object"==typeof a&&a&&a.type){var b=gb(a),c=K["*"]||[],d=K[a.type]||[],f=c.concat(d);if(f&&f.length){var g,h,i,j,k,l=this;for(g=0,h=f.length;h>g;g++)i=f[g],j=l,"string"==typeof i&&"function"==typeof e[i]&&(i=e[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(j=i,i=i.handleEvent),"function"==typeof i&&(k=w({},a),hb(i,j,[k],b))}return this}},jb=function(a){var b=a.target||c||null,e="swf"===a._source;delete a._source;var f=["flash-disabled","flash-outdated","flash-unavailable","flash-deactivated","flash-overdue"];switch(a.type){case"error":-1!==f.indexOf(a.name)&&w(I,{disabled:"flash-disabled"===a.name,outdated:"flash-outdated"===a.name,unavailable:"flash-unavailable"===a.name,deactivated:"flash-deactivated"===a.name,overdue:"flash-overdue"===a.name,ready:!1});break;case"ready":var g=I.deactivated===!0;w(I,{disabled:!1,outdated:!1,unavailable:!1,deactivated:!1,overdue:g,ready:!g});break;case"beforecopy":d=b;break;case"copy":var h,i,j=a.relatedTarget;!L["text/html"]&&!L["text/plain"]&&j&&(i=j.value||j.outerHTML||j.innerHTML)&&(h=j.value||j.textContent||j.innerText)?(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",h),i!==h&&a.clipboardData.setData("text/html",i)):!L["text/plain"]&&a.target&&(h=a.target.getAttribute("data-clipboard-text"))&&(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",h));break;case"aftercopy":Fb.clearData(),b&&b!==vb()&&b.focus&&b.focus();break;case"_mouseover":Fb.focus(b),O.bubbleEvents===!0&&e&&(b&&b!==a.relatedTarget&&!B(a.relatedTarget,b)&&kb(w({},a,{type:"mouseenter",bubbles:!1,cancelable:!1})),kb(w({},a,{type:"mouseover"})));break;case"_mouseout":Fb.blur(),O.bubbleEvents===!0&&e&&(b&&b!==a.relatedTarget&&!B(a.relatedTarget,b)&&kb(w({},a,{type:"mouseleave",bubbles:!1,cancelable:!1})),kb(w({},a,{type:"mouseout"})));break;case"_mousedown":wb(b,O.activeClass),O.bubbleEvents===!0&&e&&kb(w({},a,{type:a.type.slice(1)}));break;case"_mouseup":xb(b,O.activeClass),O.bubbleEvents===!0&&e&&kb(w({},a,{type:a.type.slice(1)}));break;case"_click":d=null,O.bubbleEvents===!0&&e&&kb(w({},a,{type:a.type.slice(1)}));break;case"_mousemove":O.bubbleEvents===!0&&e&&kb(w({},a,{type:a.type.slice(1)}))}return/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)?!0:void 0},kb=function(a){if(a&&"string"==typeof a.type&&a){var b,c=a.target||null,d=c&&c.ownerDocument||f,g={view:d.defaultView||e,canBubble:!0,cancelable:!0,detail:"click"===a.type?1:0,button:"number"==typeof a.which?a.which-1:"number"==typeof a.button?a.button:d.createEvent?0:1},h=w(g,a);c&&d.createEvent&&c.dispatchEvent&&(h=[h.type,h.canBubble,h.cancelable,h.view,h.detail,h.screenX,h.screenY,h.clientX,h.clientY,h.ctrlKey,h.altKey,h.shiftKey,h.metaKey,h.button,h.relatedTarget],b=d.createEvent("MouseEvents"),b.initMouseEvent&&(b.initMouseEvent.apply(b,h),b._source="js",c.dispatchEvent(b)))}},lb=function(){var a=f.createElement("div");return a.id=O.containerId,a.className=O.containerClass,a.style.position="absolute",a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px",a.style.zIndex=""+Db(O.zIndex),a},mb=function(a){for(var b=a&&a.parentNode;b&&"OBJECT"===b.nodeName&&b.parentNode;)b=b.parentNode;return b||null},nb=function(){var a,b=I.bridge,c=mb(b);if(!b){var d=ub(e.location.host,O),g="never"===d?"none":"all",h=sb(O),i=O.swfPath+rb(O.swfPath,O);c=lb();var j=f.createElement("div");c.appendChild(j),f.body.appendChild(c);var k=f.createElement("div"),l="activex"===I.pluginType;k.innerHTML='<object id="'+O.swfObjectId+'" name="'+O.swfObjectId+'" width="100%" height="100%" '+(l?'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"':'type="application/x-shockwave-flash" data="'+i+'"')+">"+(l?'<param name="movie" value="'+i+'"/>':"")+'<param name="allowScriptAccess" value="'+d+'"/><param name="allowNetworking" value="'+g+'"/><param name="menu" value="false"/><param name="wmode" value="transparent"/><param name="flashvars" value="'+h+'"/></object>',b=k.firstChild,k=null,u(b).ZeroClipboard=Fb,c.replaceChild(b,j)}return b||(b=f[O.swfObjectId],b&&(a=b.length)&&(b=b[a-1]),!b&&c&&(b=c.firstChild)),I.bridge=b||null,b},ob=function(){var a=I.bridge;if(a){var b=mb(a);b&&("activex"===I.pluginType&&"readyState"in a?(a.style.display="none",function c(){if(4===a.readyState){for(var d in a)"function"==typeof a[d]&&(a[d]=null);a.parentNode&&a.parentNode.removeChild(a),b.parentNode&&b.parentNode.removeChild(b)}else h(c,10)}()):(a.parentNode&&a.parentNode.removeChild(a),b.parentNode&&b.parentNode.removeChild(b))),I.ready=null,I.bridge=null,I.deactivated=null}},pb=function(a){var b={},c={};if("object"==typeof a&&a){for(var d in a)if(d&&s.call(a,d)&&"string"==typeof a[d]&&a[d])switch(d.toLowerCase()){case"text/plain":case"text":case"air:text":case"flash:text":b.text=a[d],c.text=d;break;case"text/html":case"html":case"air:html":case"flash:html":b.html=a[d],c.html=d;break;case"application/rtf":case"text/rtf":case"rtf":case"richtext":case"air:rtf":case"flash:rtf":b.rtf=a[d],c.rtf=d}return{data:b,formatMap:c}}},qb=function(a,b){if("object"!=typeof a||!a||"object"!=typeof b||!b)return a;var c={};for(var d in a)if(s.call(a,d)){if("success"!==d&&"data"!==d){c[d]=a[d];continue}c[d]={};var e=a[d];for(var f in e)f&&s.call(e,f)&&s.call(b,f)&&(c[d][b[f]]=e[f])}return c},rb=function(a,b){var c=null==b||b&&b.cacheBust===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+p():""},sb=function(a){var b,c,d,f,g="",h=[];if(a.trustedDomains&&("string"==typeof a.trustedDomains?f=[a.trustedDomains]:"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(f=a.trustedDomains)),f&&f.length)for(b=0,c=f.length;c>b;b++)if(s.call(f,b)&&f[b]&&"string"==typeof f[b]){if(d=tb(f[b]),!d)continue;if("*"===d){h.length=0,h.push(d);break}h.push.apply(h,[d,"//"+d,e.location.protocol+"//"+d])}return h.length&&(g+="trustedOrigins="+i(h.join(","))),a.forceEnhancedClipboard===!0&&(g+=(g?"&":"")+"forceEnhancedClipboard=true"),"string"==typeof a.swfObjectId&&a.swfObjectId&&(g+=(g?"&":"")+"swfObjectId="+i(a.swfObjectId)),g},tb=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},ub=function(){var a=function(a){var b,c,d,e=[];if("string"==typeof a&&(a=[a]),"object"!=typeof a||!a||"number"!=typeof a.length)return e;for(b=0,c=a.length;c>b;b++)if(s.call(a,b)&&(d=tb(a[b]))){if("*"===d){e.length=0,e.push("*");break}-1===e.indexOf(d)&&e.push(d)}return e};return function(b,c){var d=tb(c.swfPath);null===d&&(d=b);var e=a(c.trustedDomains),f=e.length;if(f>0){if(1===f&&"*"===e[0])return"always";if(-1!==e.indexOf(b))return 1===f&&b===d?"sameDomain":"always"}return"never"}}(),vb=function(){try{return f.activeElement}catch(a){return null}},wb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)||a.classList.add(b),a;if(b&&"string"==typeof b){var c=(b||"").split(/\s+/);if(1===a.nodeType)if(a.className){for(var d=" "+a.className+" ",e=a.className,f=0,g=c.length;g>f;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.className=e.replace(/^\s+|\s+$/g,"")}else a.className=b}return a},xb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)&&a.classList.remove(b),a;if("string"==typeof b&&b){var c=b.split(/\s+/);if(1===a.nodeType&&a.className){for(var d=(" "+a.className+" ").replace(/[\n\t]/g," "),e=0,f=c.length;f>e;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}}return a},yb=function(a,b){var c=e.getComputedStyle(a,null).getPropertyValue(b);return"cursor"!==b||c&&"auto"!==c||"A"!==a.nodeName?c:"pointer"},zb=function(){var a,b,c,d=1;return"function"==typeof f.body.getBoundingClientRect&&(a=f.body.getBoundingClientRect(),b=a.right-a.left,c=f.body.offsetWidth,d=o(b/c*100)/100),d},Ab=function(a){var b={left:0,top:0,width:0,height:0};if(a.getBoundingClientRect){var c,d,g,h=a.getBoundingClientRect();"pageXOffset"in e&&"pageYOffset"in e?(c=e.pageXOffset,d=e.pageYOffset):(g=zb(),c=o(f.documentElement.scrollLeft/g),d=o(f.documentElement.scrollTop/g));var i=f.documentElement.clientLeft||0,j=f.documentElement.clientTop||0;b.left=h.left+c-i,b.top=h.top+d-j,b.width="width"in h?h.width:h.right-h.left,b.height="height"in h?h.height:h.bottom-h.top}return b},Bb=function(){var a;if(c&&(a=mb(I.bridge))){var b=Ab(c);w(a.style,{width:b.width+"px",height:b.height+"px",top:b.top+"px",left:b.left+"px",zIndex:""+Db(O.zIndex)})}},Cb=function(a){I.ready===!0&&(I.bridge&&"function"==typeof I.bridge.setHandCursor?I.bridge.setHandCursor(a):I.ready=!1)},Db=function(a){if(/^(?:auto|inherit)$/.test(a))return a;var b;return"number"!=typeof a||n(a)?"string"==typeof a&&(b=Db(l(a,10))):b=a,"number"==typeof b?b:"auto"},Eb=function(a){function b(a){var b=a.match(/[\d]+/g);return b.length=3,b.join(".")}function c(a){return!!a&&(a=a.toLowerCase())&&(/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(a)||"chrome.plugin"===a.slice(-13))}function d(a){a&&(i=!0,a.version&&(l=b(a.version)),!l&&a.description&&(l=b(a.description)),a.filename&&(k=c(a.filename)))}var e,f,h,i=!1,j=!1,k=!1,l="";if(g.plugins&&g.plugins.length)e=g.plugins["Shockwave Flash"],d(e),g.plugins["Shockwave Flash 2.0"]&&(i=!0,l="2.0.0.11");else if(g.mimeTypes&&g.mimeTypes.length)h=g.mimeTypes["application/x-shockwave-flash"],e=h&&h.enabledPlugin,d(e);else if("undefined"!=typeof a){j=!0;try{f=new a("ShockwaveFlash.ShockwaveFlash.7"),i=!0,l=b(f.GetVariable("$version"))}catch(n){try{f=new a("ShockwaveFlash.ShockwaveFlash.6"),i=!0,l="6.0.21"}catch(o){try{f=new a("ShockwaveFlash.ShockwaveFlash"),i=!0,l=b(f.GetVariable("$version"))}catch(p){j=!1}}}}I.disabled=i!==!0,I.outdated=l&&m(l)<m(J),I.version=l||"0.0.0",I.pluginType=k?"pepper":j?"activex":i?"netscape":"unknown"};Eb(j);var Fb=function(){return this instanceof Fb?void("function"==typeof Fb._createClient&&Fb._createClient.apply(this,v(arguments))):new Fb};r(Fb,"version",{value:"2.1.6",writable:!1,configurable:!0,enumerable:!0}),Fb.config=function(){return P.apply(this,v(arguments))},Fb.state=function(){return Q.apply(this,v(arguments))},Fb.isFlashUnusable=function(){return R.apply(this,v(arguments))},Fb.on=function(){return S.apply(this,v(arguments))},Fb.off=function(){return T.apply(this,v(arguments))},Fb.handlers=function(){return U.apply(this,v(arguments))},Fb.emit=function(){return V.apply(this,v(arguments))},Fb.create=function(){return W.apply(this,v(arguments))},Fb.destroy=function(){return X.apply(this,v(arguments))},Fb.setData=function(){return Y.apply(this,v(arguments))},Fb.clearData=function(){return Z.apply(this,v(arguments))},Fb.getData=function(){return $.apply(this,v(arguments))},Fb.focus=Fb.activate=function(){return _.apply(this,v(arguments))},Fb.blur=Fb.deactivate=function(){return ab.apply(this,v(arguments))},Fb.activeElement=function(){return bb.apply(this,v(arguments))};var Gb=0,Hb={},Ib=0,Jb={},Kb={};w(O,{autoActivate:!0});var Lb=function(a){var b=this;b.id=""+Gb++,Hb[b.id]={instance:b,elements:[],handlers:{}},a&&b.clip(a),Fb.on("*",function(a){return b.emit(a)}),Fb.on("destroy",function(){b.destroy()}),Fb.create()},Mb=function(a,b){var c,d,e,f={},g=Hb[this.id]&&Hb[this.id].handlers;if("string"==typeof a&&a)e=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)s.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.on(c,a[c]);if(e&&e.length){for(c=0,d=e.length;d>c;c++)a=e[c].replace(/^on/,""),f[a]=!0,g[a]||(g[a]=[]),g[a].push(b);if(f.ready&&I.ready&&this.emit({type:"ready",client:this}),f.error){var h=["disabled","outdated","unavailable","deactivated","overdue"];for(c=0,d=h.length;d>c;c++)if(I[h[c]]){this.emit({type:"error",name:"flash-"+h[c],client:this});break}}}return this},Nb=function(a,b){var c,d,e,f,g,h=Hb[this.id]&&Hb[this.id].handlers;if(0===arguments.length)f=q(h);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)s.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=h[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return this},Ob=function(a){var b=null,c=Hb[this.id]&&Hb[this.id].handlers;return c&&(b="string"==typeof a&&a?c[a]?c[a].slice(0):[]:x(c)),b},Pb=function(a){if(Ub.call(this,a)){"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(a=w({},a));var b=w({},db(a),{client:this});Vb.call(this,b)}return this},Qb=function(a){a=Wb(a);for(var b=0;b<a.length;b++)if(s.call(a,b)&&a[b]&&1===a[b].nodeType){a[b].zcClippingId?-1===Jb[a[b].zcClippingId].indexOf(this.id)&&Jb[a[b].zcClippingId].push(this.id):(a[b].zcClippingId="zcClippingId_"+Ib++,Jb[a[b].zcClippingId]=[this.id],O.autoActivate===!0&&Xb(a[b]));var c=Hb[this.id]&&Hb[this.id].elements;-1===c.indexOf(a[b])&&c.push(a[b])}return this},Rb=function(a){var b=Hb[this.id];if(!b)return this;var c,d=b.elements;a="undefined"==typeof a?d.slice(0):Wb(a);for(var e=a.length;e--;)if(s.call(a,e)&&a[e]&&1===a[e].nodeType){for(c=0;-1!==(c=d.indexOf(a[e],c));)d.splice(c,1);var f=Jb[a[e].zcClippingId];if(f){for(c=0;-1!==(c=f.indexOf(this.id,c));)f.splice(c,1);0===f.length&&(O.autoActivate===!0&&Yb(a[e]),delete a[e].zcClippingId)}}return this},Sb=function(){var a=Hb[this.id];return a&&a.elements?a.elements.slice(0):[]},Tb=function(){this.unclip(),this.off(),delete Hb[this.id]},Ub=function(a){if(!a||!a.type)return!1;if(a.client&&a.client!==this)return!1;var b=Hb[this.id]&&Hb[this.id].elements,c=!!b&&b.length>0,d=!a.target||c&&-1!==b.indexOf(a.target),e=a.relatedTarget&&c&&-1!==b.indexOf(a.relatedTarget),f=a.client&&a.client===this;return d||e||f?!0:!1},Vb=function(a){if("object"==typeof a&&a&&a.type){var b=gb(a),c=Hb[this.id]&&Hb[this.id].handlers["*"]||[],d=Hb[this.id]&&Hb[this.id].handlers[a.type]||[],f=c.concat(d);if(f&&f.length){var g,h,i,j,k,l=this;for(g=0,h=f.length;h>g;g++)i=f[g],j=l,"string"==typeof i&&"function"==typeof e[i]&&(i=e[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(j=i,i=i.handleEvent),"function"==typeof i&&(k=w({},a),hb(i,j,[k],b))}return this}},Wb=function(a){return"string"==typeof a&&(a=[]),"number"!=typeof a.length?[a]:a},Xb=function(a){if(a&&1===a.nodeType){var b=function(a){(a||(a=e.event))&&("js"!==a._source&&(a.stopImmediatePropagation(),a.preventDefault()),delete a._source)},c=function(c){(c||(c=e.event))&&(b(c),Fb.focus(a))};a.addEventListener("mouseover",c,!1),a.addEventListener("mouseout",b,!1),a.addEventListener("mouseenter",b,!1),a.addEventListener("mouseleave",b,!1),a.addEventListener("mousemove",b,!1),Kb[a.zcClippingId]={mouseover:c,mouseout:b,mouseenter:b,mouseleave:b,mousemove:b}}},Yb=function(a){if(a&&1===a.nodeType){var b=Kb[a.zcClippingId];if("object"==typeof b&&b){for(var c,d,e=["move","leave","enter","out","over"],f=0,g=e.length;g>f;f++)c="mouse"+e[f],d=b[c],"function"==typeof d&&a.removeEventListener(c,d,!1);delete Kb[a.zcClippingId]}}};Fb._createClient=function(){Lb.apply(this,v(arguments))},Fb.prototype.on=function(){return Mb.apply(this,v(arguments))},Fb.prototype.off=function(){return Nb.apply(this,v(arguments))},Fb.prototype.handlers=function(){return Ob.apply(this,v(arguments))},Fb.prototype.emit=function(){return Pb.apply(this,v(arguments))},Fb.prototype.clip=function(){return Qb.apply(this,v(arguments))},Fb.prototype.unclip=function(){return Rb.apply(this,v(arguments))},Fb.prototype.elements=function(){return Sb.apply(this,v(arguments))},Fb.prototype.destroy=function(){return Tb.apply(this,v(arguments))},Fb.prototype.setText=function(a){return Fb.setData("text/plain",a),this},Fb.prototype.setHtml=function(a){return Fb.setData("text/html",a),this},Fb.prototype.setRichText=function(a){return Fb.setData("application/rtf",a),this},Fb.prototype.setData=function(){return Fb.setData.apply(this,v(arguments)),this},Fb.prototype.clearData=function(){return Fb.clearData.apply(this,v(arguments)),this},Fb.prototype.getData=function(){return Fb.getData.apply(this,v(arguments))},"function"==typeof define&&define.amd?define(function(){return Fb}):"object"==typeof module&&module&&"object"==typeof module.exports&&module.exports?module.exports=Fb:a.ZeroClipboard=Fb}(function(){return this||window}());
  9323. /**
  9324. * @fileoverview
  9325. * - Using the 'QRCode for Javascript library'
  9326. * - Fixed dataset of 'QRCode for Javascript library' for support full-spec.
  9327. * - this library has no dependencies.
  9328. *
  9329. * @author davidshimjs
  9330. * @see <a href="http://www.d-project.com/" target="_blank">http://www.d-project.com/</a>
  9331. * @see <a href="http://jeromeetienne.github.com/jquery-qrcode/" target="_blank">http://jeromeetienne.github.com/jquery-qrcode/</a>
  9332. */
  9333. (function () {
  9334. //---------------------------------------------------------------------
  9335. // QRCode for JavaScript
  9336. //
  9337. // Copyright (c) 2009 Kazuhiko Arase
  9338. //
  9339. // URL: http://www.d-project.com/
  9340. //
  9341. // Licensed under the MIT license:
  9342. // http://www.opensource.org/licenses/mit-license.php
  9343. //
  9344. // The word "QR Code" is registered trademark of
  9345. // DENSO WAVE INCORPORATED
  9346. // http://www.denso-wave.com/qrcode/faqpatent-e.html
  9347. //
  9348. //---------------------------------------------------------------------
  9349. function QR8bitByte(data) {
  9350. this.mode = QRMode.MODE_8BIT_BYTE;
  9351. this.data = data;
  9352. this.parsedData = [];
  9353. // Added to support UTF-8 Characters
  9354. for (var i = 0, l = this.data.length; i < l; i++) {
  9355. var byteArray = [];
  9356. var code = this.data.charCodeAt(i);
  9357. if (code > 0x10000) {
  9358. byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
  9359. byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
  9360. byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
  9361. byteArray[3] = 0x80 | (code & 0x3F);
  9362. } else if (code > 0x800) {
  9363. byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
  9364. byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
  9365. byteArray[2] = 0x80 | (code & 0x3F);
  9366. } else if (code > 0x80) {
  9367. byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
  9368. byteArray[1] = 0x80 | (code & 0x3F);
  9369. } else {
  9370. byteArray[0] = code;
  9371. }
  9372. this.parsedData.push(byteArray);
  9373. }
  9374. this.parsedData = Array.prototype.concat.apply([], this.parsedData);
  9375. if (this.parsedData.length != this.data.length) {
  9376. this.parsedData.unshift(191);
  9377. this.parsedData.unshift(187);
  9378. this.parsedData.unshift(239);
  9379. }
  9380. }
  9381. QR8bitByte.prototype = {
  9382. getLength: function (buffer) {
  9383. return this.parsedData.length;
  9384. },
  9385. write: function (buffer) {
  9386. for (var i = 0, l = this.parsedData.length; i < l; i++) {
  9387. buffer.put(this.parsedData[i], 8);
  9388. }
  9389. }
  9390. };
  9391. function QRCodeModel(typeNumber, errorCorrectLevel) {
  9392. this.typeNumber = typeNumber;
  9393. this.errorCorrectLevel = errorCorrectLevel;
  9394. this.modules = null;
  9395. this.moduleCount = 0;
  9396. this.dataCache = null;
  9397. this.dataList = [];
  9398. }
  9399. QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);}
  9400. return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row<this.moduleCount;row++){this.modules[row]=new Array(this.moduleCount);for(var col=0;col<this.moduleCount;col++){this.modules[row][col]=null;}}
  9401. this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(test,maskPattern);if(this.typeNumber>=7){this.setupTypeNumber(test);}
  9402. if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);}
  9403. this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}}
  9404. return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row<this.modules.length;row++){var y=row*cs;for(var col=0;col<this.modules[row].length;col++){var x=col*cs;var dark=this.modules[row][col];if(dark){qr_mc.beginFill(0,100);qr_mc.moveTo(x,y);qr_mc.lineTo(x+cs,y);qr_mc.lineTo(x+cs,y+cs);qr_mc.lineTo(x,y+cs);qr_mc.endFill();}}}
  9405. return qr_mc;},setupTimingPattern:function(){for(var r=8;r<this.moduleCount-8;r++){if(this.modules[r][6]!=null){continue;}
  9406. this.modules[r][6]=(r%2==0);}
  9407. for(var c=8;c<this.moduleCount-8;c++){if(this.modules[6][c]!=null){continue;}
  9408. this.modules[6][c]=(c%2==0);}},setupPositionAdjustPattern:function(){var pos=QRUtil.getPatternPosition(this.typeNumber);for(var i=0;i<pos.length;i++){for(var j=0;j<pos.length;j++){var row=pos[i];var col=pos[j];if(this.modules[row][col]!=null){continue;}
  9409. for(var r=-2;r<=2;r++){for(var c=-2;c<=2;c++){if(r==-2||r==2||c==-2||c==2||(r==0&&c==0)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}}}},setupTypeNumber:function(test){var bits=QRUtil.getBCHTypeNumber(this.typeNumber);for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;}
  9410. for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}}
  9411. for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}}
  9412. this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex<data.length){dark=(((data[byteIndex]>>>bitIndex)&1)==1);}
  9413. var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;}
  9414. this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}}
  9415. row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;i<dataList.length;i++){var data=dataList[i];buffer.put(data.mode,4);buffer.put(data.getLength(),QRUtil.getLengthInBits(data.mode,typeNumber));data.write(buffer);}
  9416. var totalDataCount=0;for(var i=0;i<rsBlocks.length;i++){totalDataCount+=rsBlocks[i].dataCount;}
  9417. if(buffer.getLengthInBits()>totalDataCount*8){throw new Error("code length overflow. ("
  9418. +buffer.getLengthInBits()
  9419. +">"
  9420. +totalDataCount*8
  9421. +")");}
  9422. if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);}
  9423. while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);}
  9424. while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;}
  9425. buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;}
  9426. buffer.put(QRCodeModel.PAD1,8);}
  9427. return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r<rsBlocks.length;r++){var dcCount=rsBlocks[r].dataCount;var ecCount=rsBlocks[r].totalCount-dcCount;maxDcCount=Math.max(maxDcCount,dcCount);maxEcCount=Math.max(maxEcCount,ecCount);dcdata[r]=new Array(dcCount);for(var i=0;i<dcdata[r].length;i++){dcdata[r][i]=0xff&buffer.buffer[i+offset];}
  9428. offset+=dcCount;var rsPoly=QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly=new QRPolynomial(dcdata[r],rsPoly.getLength()-1);var modPoly=rawPoly.mod(rsPoly);ecdata[r]=new Array(rsPoly.getLength()-1);for(var i=0;i<ecdata[r].length;i++){var modIndex=i+modPoly.getLength()-ecdata[r].length;ecdata[r][i]=(modIndex>=0)?modPoly.get(modIndex):0;}}
  9429. var totalCodeCount=0;for(var i=0;i<rsBlocks.length;i++){totalCodeCount+=rsBlocks[i].totalCount;}
  9430. var data=new Array(totalCodeCount);var index=0;for(var i=0;i<maxDcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<dcdata[r].length){data[index++]=dcdata[r][i];}}}
  9431. for(var i=0;i<maxEcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<ecdata[r].length){data[index++]=ecdata[r][i];}}}
  9432. return data;};var QRMode={MODE_NUMBER:1<<0,MODE_ALPHA_NUM:1<<1,MODE_8BIT_BYTE:1<<2,MODE_KANJI:1<<3};var QRErrorCorrectLevel={L:1,M:0,Q:3,H:2};var QRMaskPattern={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var QRUtil={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:(1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0),G18:(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0),G15_MASK:(1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1),getBCHTypeInfo:function(data){var d=data<<10;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)>=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));}
  9433. return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));}
  9434. return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;}
  9435. return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i<errorCorrectLength;i++){a=a.multiply(new QRPolynomial([1,QRMath.gexp(i)],0));}
  9436. return a;},getLengthInBits:function(mode,type){if(1<=type&&type<10){switch(mode){case QRMode.MODE_NUMBER:return 10;case QRMode.MODE_ALPHA_NUM:return 9;case QRMode.MODE_8BIT_BYTE:return 8;case QRMode.MODE_KANJI:return 8;default:throw new Error("mode:"+mode);}}else if(type<27){switch(mode){case QRMode.MODE_NUMBER:return 12;case QRMode.MODE_ALPHA_NUM:return 11;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 10;default:throw new Error("mode:"+mode);}}else if(type<41){switch(mode){case QRMode.MODE_NUMBER:return 14;case QRMode.MODE_ALPHA_NUM:return 13;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 12;default:throw new Error("mode:"+mode);}}else{throw new Error("type:"+type);}},getLostPoint:function(qrCode){var moduleCount=qrCode.getModuleCount();var lostPoint=0;for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount;col++){var sameCount=0;var dark=qrCode.isDark(row,col);for(var r=-1;r<=1;r++){if(row+r<0||moduleCount<=row+r){continue;}
  9437. for(var c=-1;c<=1;c++){if(col+c<0||moduleCount<=col+c){continue;}
  9438. if(r==0&&c==0){continue;}
  9439. if(dark==qrCode.isDark(row+r,col+c)){sameCount++;}}}
  9440. if(sameCount>5){lostPoint+=(3+sameCount-5);}}}
  9441. for(var row=0;row<moduleCount-1;row++){for(var col=0;col<moduleCount-1;col++){var count=0;if(qrCode.isDark(row,col))count++;if(qrCode.isDark(row+1,col))count++;if(qrCode.isDark(row,col+1))count++;if(qrCode.isDark(row+1,col+1))count++;if(count==0||count==4){lostPoint+=3;}}}
  9442. for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount-6;col++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row,col+1)&&qrCode.isDark(row,col+2)&&qrCode.isDark(row,col+3)&&qrCode.isDark(row,col+4)&&!qrCode.isDark(row,col+5)&&qrCode.isDark(row,col+6)){lostPoint+=40;}}}
  9443. for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount-6;row++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row+1,col)&&qrCode.isDark(row+2,col)&&qrCode.isDark(row+3,col)&&qrCode.isDark(row+4,col)&&!qrCode.isDark(row+5,col)&&qrCode.isDark(row+6,col)){lostPoint+=40;}}}
  9444. var darkCount=0;for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount;row++){if(qrCode.isDark(row,col)){darkCount++;}}}
  9445. var ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;lostPoint+=ratio*10;return lostPoint;}};var QRMath={glog:function(n){if(n<1){throw new Error("glog("+n+")");}
  9446. return QRMath.LOG_TABLE[n];},gexp:function(n){while(n<0){n+=255;}
  9447. while(n>=256){n-=255;}
  9448. return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<<i;}
  9449. for(var i=8;i<256;i++){QRMath.EXP_TABLE[i]=QRMath.EXP_TABLE[i-4]^QRMath.EXP_TABLE[i-5]^QRMath.EXP_TABLE[i-6]^QRMath.EXP_TABLE[i-8];}
  9450. for(var i=0;i<255;i++){QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]]=i;}
  9451. function QRPolynomial(num,shift){if(num.length==undefined){throw new Error(num.length+"/"+shift);}
  9452. var offset=0;while(offset<num.length&&num[offset]==0){offset++;}
  9453. this.num=new Array(num.length-offset+shift);for(var i=0;i<num.length-offset;i++){this.num[i]=num[i+offset];}}
  9454. QRPolynomial.prototype={get:function(index){return this.num[index];},getLength:function(){return this.num.length;},multiply:function(e){var num=new Array(this.getLength()+e.getLength()-1);for(var i=0;i<this.getLength();i++){for(var j=0;j<e.getLength();j++){num[i+j]^=QRMath.gexp(QRMath.glog(this.get(i))+QRMath.glog(e.get(j)));}}
  9455. return new QRPolynomial(num,0);},mod:function(e){if(this.getLength()-e.getLength()<0){return this;}
  9456. var ratio=QRMath.glog(this.get(0))-QRMath.glog(e.get(0));var num=new Array(this.getLength());for(var i=0;i<this.getLength();i++){num[i]=this.get(i);}
  9457. for(var i=0;i<e.getLength();i++){num[i]^=QRMath.gexp(QRMath.glog(e.get(i))+ratio);}
  9458. return new QRPolynomial(num,0).mod(e);}};function QRRSBlock(totalCount,dataCount){this.totalCount=totalCount;this.dataCount=dataCount;}
  9459. QRRSBlock.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];QRRSBlock.getRSBlocks=function(typeNumber,errorCorrectLevel){var rsBlock=QRRSBlock.getRsBlockTable(typeNumber,errorCorrectLevel);if(rsBlock==undefined){throw new Error("bad rs block @ typeNumber:"+typeNumber+"/errorCorrectLevel:"+errorCorrectLevel);}
  9460. var length=rsBlock.length/3;var list=[];for(var i=0;i<length;i++){var count=rsBlock[i*3+0];var totalCount=rsBlock[i*3+1];var dataCount=rsBlock[i*3+2];for(var j=0;j<count;j++){list.push(new QRRSBlock(totalCount,dataCount));}}
  9461. return list;};QRRSBlock.getRsBlockTable=function(typeNumber,errorCorrectLevel){switch(errorCorrectLevel){case QRErrorCorrectLevel.L:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+0];case QRErrorCorrectLevel.M:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+1];case QRErrorCorrectLevel.Q:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+2];case QRErrorCorrectLevel.H:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+3];default:return undefined;}};function QRBitBuffer(){this.buffer=[];this.length=0;}
  9462. QRBitBuffer.prototype={get:function(index){var bufIndex=Math.floor(index/8);return((this.buffer[bufIndex]>>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i<length;i++){this.putBit(((num>>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);}
  9463. if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));}
  9464. this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]];
  9465. function _isSupportCanvas() {
  9466. return typeof CanvasRenderingContext2D != "undefined";
  9467. }
  9468. // android 2.x doesn't support Data-URI spec
  9469. function _getAndroid() {
  9470. var android = false;
  9471. var sAgent = navigator.userAgent;
  9472. if (/android/i.test(sAgent)) { // android
  9473. android = true;
  9474. aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i);
  9475. if (aMat && aMat[1]) {
  9476. android = parseFloat(aMat[1]);
  9477. }
  9478. }
  9479. return android;
  9480. }
  9481. var svgDrawer = (function() {
  9482. var Drawing = function (el, htOption) {
  9483. this._el = el;
  9484. this._htOption = htOption;
  9485. };
  9486. Drawing.prototype.draw = function (oQRCode) {
  9487. var _htOption = this._htOption;
  9488. var _el = this._el;
  9489. var nCount = oQRCode.getModuleCount();
  9490. var nWidth = Math.floor(_htOption.width / nCount);
  9491. var nHeight = Math.floor(_htOption.height / nCount);
  9492. this.clear();
  9493. function makeSVG(tag, attrs) {
  9494. var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
  9495. for (var k in attrs)
  9496. if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]);
  9497. return el;
  9498. }
  9499. var svg = makeSVG("svg" , {'viewBox': '0 0 ' + String(nCount) + " " + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight});
  9500. svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
  9501. _el.appendChild(svg);
  9502. svg.appendChild(makeSVG("rect", {"fill": _htOption.colorDark, "width": "1", "height": "1", "id": "template"}));
  9503. for (var row = 0; row < nCount; row++) {
  9504. for (var col = 0; col < nCount; col++) {
  9505. if (oQRCode.isDark(row, col)) {
  9506. var child = makeSVG("use", {"x": String(row), "y": String(col)});
  9507. child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template")
  9508. svg.appendChild(child);
  9509. }
  9510. }
  9511. }
  9512. };
  9513. Drawing.prototype.clear = function () {
  9514. while (this._el.hasChildNodes())
  9515. this._el.removeChild(this._el.lastChild);
  9516. };
  9517. return Drawing;
  9518. })();
  9519. var useSVG = document.documentElement.tagName.toLowerCase() === "svg";
  9520. // Drawing in DOM by using Table tag
  9521. var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () {
  9522. var Drawing = function (el, htOption) {
  9523. this._el = el;
  9524. this._htOption = htOption;
  9525. };
  9526. /**
  9527. * Draw the QRCode
  9528. *
  9529. * @param {QRCode} oQRCode
  9530. */
  9531. Drawing.prototype.draw = function (oQRCode) {
  9532. var _htOption = this._htOption;
  9533. var _el = this._el;
  9534. var nCount = oQRCode.getModuleCount();
  9535. var nWidth = Math.floor(_htOption.width / nCount);
  9536. var nHeight = Math.floor(_htOption.height / nCount);
  9537. var aHTML = ['<table style="border:0;border-collapse:collapse;">'];
  9538. for (var row = 0; row < nCount; row++) {
  9539. aHTML.push('<tr>');
  9540. for (var col = 0; col < nCount; col++) {
  9541. aHTML.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' + nWidth + 'px;height:' + nHeight + 'px;background-color:' + (oQRCode.isDark(row, col) ? _htOption.colorDark : _htOption.colorLight) + ';"></td>');
  9542. }
  9543. aHTML.push('</tr>');
  9544. }
  9545. aHTML.push('</table>');
  9546. _el.innerHTML = aHTML.join('');
  9547. // Fix the margin values as real size.
  9548. var elTable = _el.childNodes[0];
  9549. var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;
  9550. var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;
  9551. if (nLeftMarginTable > 0 && nTopMarginTable > 0) {
  9552. elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px";
  9553. }
  9554. };
  9555. /**
  9556. * Clear the QRCode
  9557. */
  9558. Drawing.prototype.clear = function () {
  9559. this._el.innerHTML = '';
  9560. };
  9561. return Drawing;
  9562. })() : (function () { // Drawing in Canvas
  9563. function _onMakeImage() {
  9564. this._elImage.src = this._elCanvas.toDataURL("image/png");
  9565. this._elImage.style.display = "block";
  9566. this._elCanvas.style.display = "none";
  9567. }
  9568. // Android 2.1 bug workaround
  9569. // http://code.google.com/p/android/issues/detail?id=5141
  9570. if (this._android && this._android <= 2.1) {
  9571. var factor = 1 / window.devicePixelRatio;
  9572. var drawImage = CanvasRenderingContext2D.prototype.drawImage;
  9573. CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) {
  9574. if (("nodeName" in image) && /img/i.test(image.nodeName)) {
  9575. for (var i = arguments.length - 1; i >= 1; i--) {
  9576. arguments[i] = arguments[i] * factor;
  9577. }
  9578. } else if (typeof dw == "undefined") {
  9579. arguments[1] *= factor;
  9580. arguments[2] *= factor;
  9581. arguments[3] *= factor;
  9582. arguments[4] *= factor;
  9583. }
  9584. drawImage.apply(this, arguments);
  9585. };
  9586. }
  9587. /**
  9588. * Check whether the user's browser supports Data URI or not
  9589. *
  9590. * @private
  9591. * @param {Function} fSuccess Occurs if it supports Data URI
  9592. * @param {Function} fFail Occurs if it doesn't support Data URI
  9593. */
  9594. function _safeSetDataURI(fSuccess, fFail) {
  9595. var self = this;
  9596. self._fFail = fFail;
  9597. self._fSuccess = fSuccess;
  9598. // Check it just once
  9599. if (self._bSupportDataURI === null) {
  9600. var el = document.createElement("img");
  9601. var fOnError = function() {
  9602. self._bSupportDataURI = false;
  9603. if (self._fFail) {
  9604. _fFail.call(self);
  9605. }
  9606. };
  9607. var fOnSuccess = function() {
  9608. self._bSupportDataURI = true;
  9609. if (self._fSuccess) {
  9610. self._fSuccess.call(self);
  9611. }
  9612. };
  9613. el.onabort = fOnError;
  9614. el.onerror = fOnError;
  9615. el.onload = fOnSuccess;
  9616. el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data.
  9617. return;
  9618. } else if (self._bSupportDataURI === true && self._fSuccess) {
  9619. self._fSuccess.call(self);
  9620. } else if (self._bSupportDataURI === false && self._fFail) {
  9621. self._fFail.call(self);
  9622. }
  9623. };
  9624. /**
  9625. * Drawing QRCode by using canvas
  9626. *
  9627. * @constructor
  9628. * @param {HTMLElement} el
  9629. * @param {Object} htOption QRCode Options
  9630. */
  9631. var Drawing = function (el, htOption) {
  9632. this._bIsPainted = false;
  9633. this._android = _getAndroid();
  9634. this._htOption = htOption;
  9635. this._elCanvas = document.createElement("canvas");
  9636. this._elCanvas.width = htOption.width;
  9637. this._elCanvas.height = htOption.height;
  9638. el.appendChild(this._elCanvas);
  9639. this._el = el;
  9640. this._oContext = this._elCanvas.getContext("2d");
  9641. this._bIsPainted = false;
  9642. this._elImage = document.createElement("img");
  9643. this._elImage.alt = "Scan me!";
  9644. this._elImage.style.display = "none";
  9645. this._el.appendChild(this._elImage);
  9646. this._bSupportDataURI = null;
  9647. };
  9648. /**
  9649. * Draw the QRCode
  9650. *
  9651. * @param {QRCode} oQRCode
  9652. */
  9653. Drawing.prototype.draw = function (oQRCode) {
  9654. var _elImage = this._elImage;
  9655. var _oContext = this._oContext;
  9656. var _htOption = this._htOption;
  9657. var nCount = oQRCode.getModuleCount();
  9658. var nWidth = _htOption.width / nCount;
  9659. var nHeight = _htOption.height / nCount;
  9660. var nRoundedWidth = Math.round(nWidth);
  9661. var nRoundedHeight = Math.round(nHeight);
  9662. _elImage.style.display = "none";
  9663. this.clear();
  9664. for (var row = 0; row < nCount; row++) {
  9665. for (var col = 0; col < nCount; col++) {
  9666. var bIsDark = oQRCode.isDark(row, col);
  9667. var nLeft = col * nWidth;
  9668. var nTop = row * nHeight;
  9669. _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
  9670. _oContext.lineWidth = 1;
  9671. _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
  9672. _oContext.fillRect(nLeft, nTop, nWidth, nHeight);
  9673. // 안티 앨리어싱 방지 처리
  9674. _oContext.strokeRect(
  9675. Math.floor(nLeft) + 0.5,
  9676. Math.floor(nTop) + 0.5,
  9677. nRoundedWidth,
  9678. nRoundedHeight
  9679. );
  9680. _oContext.strokeRect(
  9681. Math.ceil(nLeft) - 0.5,
  9682. Math.ceil(nTop) - 0.5,
  9683. nRoundedWidth,
  9684. nRoundedHeight
  9685. );
  9686. }
  9687. }
  9688. this._bIsPainted = true;
  9689. };
  9690. /**
  9691. * Make the image from Canvas if the browser supports Data URI.
  9692. */
  9693. Drawing.prototype.makeImage = function () {
  9694. if (this._bIsPainted) {
  9695. _safeSetDataURI.call(this, _onMakeImage);
  9696. }
  9697. };
  9698. /**
  9699. * Return whether the QRCode is painted or not
  9700. *
  9701. * @return {Boolean}
  9702. */
  9703. Drawing.prototype.isPainted = function () {
  9704. return this._bIsPainted;
  9705. };
  9706. /**
  9707. * Clear the QRCode
  9708. */
  9709. Drawing.prototype.clear = function () {
  9710. this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);
  9711. this._bIsPainted = false;
  9712. };
  9713. /**
  9714. * @private
  9715. * @param {Number} nNumber
  9716. */
  9717. Drawing.prototype.round = function (nNumber) {
  9718. if (!nNumber) {
  9719. return nNumber;
  9720. }
  9721. return Math.floor(nNumber * 1000) / 1000;
  9722. };
  9723. return Drawing;
  9724. })();
  9725. /**
  9726. * Get the type by string length
  9727. *
  9728. * @private
  9729. * @param {String} sText
  9730. * @param {Number} nCorrectLevel
  9731. * @return {Number} type
  9732. */
  9733. function _getTypeNumber(sText, nCorrectLevel) {
  9734. var nType = 1;
  9735. var length = _getUTF8Length(sText);
  9736. for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {
  9737. var nLimit = 0;
  9738. switch (nCorrectLevel) {
  9739. case QRErrorCorrectLevel.L :
  9740. nLimit = QRCodeLimitLength[i][0];
  9741. break;
  9742. case QRErrorCorrectLevel.M :
  9743. nLimit = QRCodeLimitLength[i][1];
  9744. break;
  9745. case QRErrorCorrectLevel.Q :
  9746. nLimit = QRCodeLimitLength[i][2];
  9747. break;
  9748. case QRErrorCorrectLevel.H :
  9749. nLimit = QRCodeLimitLength[i][3];
  9750. break;
  9751. }
  9752. if (length <= nLimit) {
  9753. break;
  9754. } else {
  9755. nType++;
  9756. }
  9757. }
  9758. if (nType > QRCodeLimitLength.length) {
  9759. throw new Error("Too long data");
  9760. }
  9761. return nType;
  9762. }
  9763. function _getUTF8Length(sText) {
  9764. var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a');
  9765. return replacedText.length + (replacedText.length != sText ? 3 : 0);
  9766. }
  9767. /**
  9768. * @class QRCode
  9769. * @constructor
  9770. * @example
  9771. * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie");
  9772. *
  9773. * @example
  9774. * var oQRCode = new QRCode("test", {
  9775. * text : "http://naver.com",
  9776. * width : 128,
  9777. * height : 128
  9778. * });
  9779. *
  9780. * oQRCode.clear(); // Clear the QRCode.
  9781. * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode.
  9782. *
  9783. * @param {HTMLElement|String} el target element or 'id' attribute of element.
  9784. * @param {Object|String} vOption
  9785. * @param {String} vOption.text QRCode link data
  9786. * @param {Number} [vOption.width=256]
  9787. * @param {Number} [vOption.height=256]
  9788. * @param {String} [vOption.colorDark="#000000"]
  9789. * @param {String} [vOption.colorLight="#ffffff"]
  9790. * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H]
  9791. */
  9792. window.QRCode = function (el, vOption) {
  9793. this._htOption = {
  9794. width : 256,
  9795. height : 256,
  9796. typeNumber : 4,
  9797. colorDark : "#000000",
  9798. colorLight : "#ffffff",
  9799. correctLevel : QRErrorCorrectLevel.H
  9800. };
  9801. if (typeof vOption === 'string') {
  9802. vOption = {
  9803. text : vOption
  9804. };
  9805. }
  9806. // Overwrites options
  9807. if (vOption) {
  9808. for (var i in vOption) {
  9809. this._htOption[i] = vOption[i];
  9810. }
  9811. }
  9812. if (typeof el == "string") {
  9813. el = document.getElementById(el);
  9814. }
  9815. this._android = _getAndroid();
  9816. this._el = el;
  9817. this._oQRCode = null;
  9818. this._oDrawing = new Drawing(this._el, this._htOption);
  9819. if (this._htOption.text) {
  9820. this.makeCode(this._htOption.text);
  9821. }
  9822. };
  9823. /**
  9824. * Make the QRCode
  9825. *
  9826. * @param {String} sText link data
  9827. */
  9828. QRCode.prototype.makeCode = function (sText) {
  9829. this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);
  9830. this._oQRCode.addData(sText);
  9831. this._oQRCode.make();
  9832. this._el.title = sText;
  9833. this._oDrawing.draw(this._oQRCode);
  9834. this.makeImage();
  9835. };
  9836. /**
  9837. * Make the Image from Canvas element
  9838. * - It occurs automatically
  9839. * - Android below 3 doesn't support Data-URI spec.
  9840. *
  9841. * @private
  9842. */
  9843. QRCode.prototype.makeImage = function () {
  9844. if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) {
  9845. this._oDrawing.makeImage();
  9846. }
  9847. };
  9848. /**
  9849. * Clear the QRCode
  9850. */
  9851. QRCode.prototype.clear = function () {
  9852. this._oDrawing.clear();
  9853. };
  9854. /**
  9855. * @name QRCode.CorrectLevel
  9856. */
  9857. QRCode.CorrectLevel = QRErrorCorrectLevel;
  9858. })();
  9859. var jhtmls="undefined"==typeof exports?jhtmls||{}:exports;void function(e){"use strict";function n(e){return String(e).replace(/["<>& ]/g,function(e){return"&"+u[e]+";"})}function t(e){var n=[];return n.push("with(this){"),n.push(e.replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/g,function(e){return['!#{unescape("',escape(e),'")}'].join("")}).replace(/[\r\n]+/g,"\n").replace(/^\n+|\s+$/gm,"").replace(/^([ \w\t_$]*([^&\^?|\n\w\/'"{}\[\]+\-():; \t=\.$_]|:\/\/).*$|^(?!\s*(else|do|try|finally|void|typeof\s[\w$_]*)\s*$)[^'":;{}()\n|=&\/^?]+$)\s?/gm,function(e){return e=e.replace(/&none;/g,"").replace(/["'\\]/g,"\\$&").replace(/\n/g,"\\n").replace(/(!?#)\{(.*?)\}|(!?\$)([a-z_]+\w*(?:\.[a-z_]+\w*)*)/g,function(e,n,t,r,u){if(r&&(n=r,t=u),!t)return"";t=t.replace(/\\n/g,"\n").replace(/\\([\\'"])/g,"$1");var o=/^[a-z$][\w+$]+$/i.test(t)&&!/^(true|false|NaN|null|this)$/.test(t);return["',",o?["typeof ",t,"==='undefined'?'':"].join(""):"","#"===n||"$"===n?"_encode_":"","(",t,"),'"].join("")}),e=["'",e,"'"].join("").replace(/^'',|,''$/g,""),e?["_output_.push(",e,");"].join(""):""})),n.push("}"),new Function("_output_","_encode_","helper","jhtmls",n.join(""))}function r(r,u,o){"function"==typeof r&&(r=String(r).replace(/^[^\{]*\{\s*\/\*!?[ \f\t\v]*\n?|[ \f\t\v]*\*\/[;|\s]*\}$/g,""));var i=t(r),s=function(t,r){r=r||e;var u=[];return i.call(t,u,n,r,e),u.join("")};return arguments.length<=1?s:s(u,o)}var u={'"':"quot","<":"lt",">":"gt","&":"amp"," ":"nbsp"};e.render=r}(jhtmls);
  9860. /*!
  9861. * ====================================================
  9862. * Flex UI - v1.0.0 - 2015-01-12
  9863. * https://github.com/fex-team/fui
  9864. * GitHub: https://github.com/fex-team/fui.git
  9865. * Copyright (c) 2015 Baidu Kity Group; Licensed MIT
  9866. * ====================================================
  9867. */
  9868. (function () {
  9869. var _p = {
  9870. r: function(index) {
  9871. if (_p[index].inited) {
  9872. return _p[index].value;
  9873. }
  9874. if (typeof _p[index].value === "function") {
  9875. var module = {
  9876. exports: {}
  9877. }, returnValue = _p[index].value(null, module.exports, module);
  9878. _p[index].inited = true;
  9879. _p[index].value = returnValue;
  9880. if (returnValue !== undefined) {
  9881. return returnValue;
  9882. } else {
  9883. for (var key in module.exports) {
  9884. if (module.exports.hasOwnProperty(key)) {
  9885. _p[index].inited = true;
  9886. _p[index].value = module.exports;
  9887. return module.exports;
  9888. }
  9889. }
  9890. }
  9891. } else {
  9892. _p[index].inited = true;
  9893. return _p[index].value;
  9894. }
  9895. }
  9896. };
  9897. //src/base/creator.js
  9898. /**
  9899. * UI构造工厂, 提供可通过参数配置项创建多个构件的机制.
  9900. */
  9901. _p[0] = {
  9902. value: function(require) {
  9903. var Creator = {}, $ = _p.r(4), FUI_NS = _p.r(11);
  9904. $.extend(Creator, {
  9905. parse: function(options) {
  9906. var pool = [];
  9907. if ($.isArray(options)) {
  9908. $.each(options, function(i, opt) {
  9909. pool.push(getInstance(opt));
  9910. });
  9911. return pool;
  9912. } else {
  9913. return getInstance(options);
  9914. }
  9915. }
  9916. });
  9917. function getInstance(option) {
  9918. var Constructor = FUI_NS[option.clazz];
  9919. if (!Constructor) {
  9920. return null;
  9921. }
  9922. return new Constructor(option);
  9923. }
  9924. return Creator;
  9925. }
  9926. };
  9927. //src/base/exports.js
  9928. /**
  9929. * 模块暴露
  9930. */
  9931. _p[1] = {
  9932. value: function(require) {
  9933. var FUI_NS = _p.r(11);
  9934. // 配置参数必须最先注册
  9935. FUI_NS.___register({
  9936. ALLOW_FOCUS: true
  9937. });
  9938. FUI_NS.___register({
  9939. Widget: _p.r(60),
  9940. Icon: _p.r(42),
  9941. Label: _p.r(48),
  9942. Button: _p.r(37),
  9943. ToggleButton: _p.r(59),
  9944. Buttonset: _p.r(36),
  9945. Separator: _p.r(56),
  9946. Item: _p.r(46),
  9947. Input: _p.r(45),
  9948. InputButton: _p.r(43),
  9949. Mask: _p.r(49),
  9950. ColorPicker: _p.r(38),
  9951. Tabs: _p.r(58),
  9952. SpinButton: _p.r(57),
  9953. Container: _p.r(39),
  9954. Panel: _p.r(51),
  9955. PPanel: _p.r(54),
  9956. LabelPanel: _p.r(47),
  9957. Menu: _p.r(50),
  9958. InputMenu: _p.r(44),
  9959. ButtonMenu: _p.r(34),
  9960. DropPanel: _p.r(41),
  9961. Popup: _p.r(53),
  9962. PopupMenu: _p.r(52),
  9963. SelectMenu: _p.r(55),
  9964. Dialog: _p.r(40),
  9965. Utils: _p.r(13),
  9966. Creator: _p.r(0)
  9967. });
  9968. FUI_NS.__export();
  9969. }
  9970. };
  9971. //src/base/extensions.js
  9972. /**
  9973. * 扩展模块暴露
  9974. */
  9975. _p[2] = {
  9976. value: function(require) {
  9977. var FUI_NS = _p.r(11);
  9978. FUI_NS.___register({
  9979. TablePicker: _p.r(17)
  9980. });
  9981. }
  9982. };
  9983. //src/base/jhtmls.js
  9984. /**
  9985. * jhtmls模板引擎
  9986. */
  9987. _p[3] = {
  9988. value: function() {
  9989. /* global jhtmls: true */
  9990. return jhtmls;
  9991. }
  9992. };
  9993. //src/base/jquery.js
  9994. /**
  9995. * jquery模块封装
  9996. */
  9997. _p[4] = {
  9998. value: function(require) {
  9999. return window.jQuery;
  10000. }
  10001. };
  10002. //src/base/kit/class.js
  10003. /**
  10004. * @description 创建一个类
  10005. * @param {String} fullClassName 类全名,包括命名空间。
  10006. * @param {Plain} defines 要创建的类的特性
  10007. * defines.constructor {Function} 类的构造函数,实例化的时候会被调用。
  10008. * defines.base {String} 基类的名称。名称要使用全名。(因为base是javascript未来保留字,所以不用base)
  10009. * defines.mixin {Array<String>} 要混合到新类的类集合
  10010. * defines.<method> {Function} 其他类方法
  10011. *
  10012. * TODO:
  10013. * Mixin 构造函数调用支持
  10014. */
  10015. _p[5] = {
  10016. value: function(require, exports) {
  10017. // just to bind context
  10018. Function.prototype.bind = Function.prototype.bind || function(thisObj) {
  10019. var args = Array.prototype.slice.call(arguments, 1);
  10020. return this.apply(thisObj, args);
  10021. };
  10022. // 所有类的基类
  10023. function Class() {}
  10024. Class.__KityClassName = "Class";
  10025. // 提供 base 调用支持
  10026. Class.prototype.base = function(name) {
  10027. var caller = arguments.callee.caller;
  10028. var method = caller.__KityMethodClass.__KityBaseClass.prototype[name];
  10029. return method.apply(this, Array.prototype.slice.call(arguments, 1));
  10030. };
  10031. // 直接调用 base 类的同名方法
  10032. Class.prototype.callBase = function() {
  10033. var caller = arguments.callee.caller;
  10034. var method = caller.__KityMethodClass.__KityBaseClass.prototype[caller.__KityMethodName];
  10035. return method.apply(this, arguments);
  10036. };
  10037. Class.prototype.mixin = function(name) {
  10038. var caller = arguments.callee.caller;
  10039. var mixins = caller.__KityMethodClass.__KityMixins;
  10040. if (!mixins) {
  10041. return this;
  10042. }
  10043. var method = mixins[name];
  10044. return method.apply(this, Array.prototype.slice.call(arguments, 1));
  10045. };
  10046. Class.prototype.callMixin = function() {
  10047. var caller = arguments.callee.caller;
  10048. var methodName = caller.__KityMethodName;
  10049. var mixins = caller.__KityMethodClass.__KityMixins;
  10050. if (!mixins) {
  10051. return this;
  10052. }
  10053. var method = mixins[methodName];
  10054. if (methodName == "constructor") {
  10055. for (var i = 0, l = method.length; i < l; i++) {
  10056. method[i].call(this);
  10057. }
  10058. return this;
  10059. } else {
  10060. return method.apply(this, arguments);
  10061. }
  10062. };
  10063. Class.prototype.pipe = function(fn) {
  10064. if (typeof fn == "function") {
  10065. fn.call(this, this);
  10066. }
  10067. return this;
  10068. };
  10069. Class.prototype.getType = function() {
  10070. return this.__KityClassName;
  10071. };
  10072. Class.prototype.getClass = function() {
  10073. return this.constructor;
  10074. };
  10075. // 检查基类是否调用了父类的构造函数
  10076. // 该检查是弱检查,假如调用的代码被注释了,同样能检查成功(这个特性可用于知道建议调用,但是出于某些原因不想调用的情况)
  10077. function checkBaseConstructorCall(targetClass, classname) {
  10078. var code = targetClass.toString();
  10079. if (!/this\.callBase/.test(code)) {
  10080. throw new Error(classname + " : 类构造函数没有调用父类的构造函数!为了安全,请调用父类的构造函数");
  10081. }
  10082. }
  10083. var KITY_INHERIT_FLAG = "__KITY_INHERIT_FLAG_" + +new Date();
  10084. function inherit(constructor, BaseClass, classname) {
  10085. var KityClass = eval("(function " + classname + "( __inherit__flag ) {" + "if( __inherit__flag != KITY_INHERIT_FLAG ) {" + "KityClass.__KityConstructor.apply(this, arguments);" + "}" + "this.__KityClassName = KityClass.__KityClassName;" + "})||0");
  10086. KityClass.__KityConstructor = constructor;
  10087. KityClass.prototype = new BaseClass(KITY_INHERIT_FLAG);
  10088. for (var methodName in BaseClass.prototype) {
  10089. if (BaseClass.prototype.hasOwnProperty(methodName) && methodName.indexOf("__Kity") !== 0) {
  10090. KityClass.prototype[methodName] = BaseClass.prototype[methodName];
  10091. }
  10092. }
  10093. KityClass.prototype.constructor = KityClass;
  10094. return KityClass;
  10095. }
  10096. function mixin(NewClass, mixins) {
  10097. if (false === mixins instanceof Array) {
  10098. return NewClass;
  10099. }
  10100. var i, length = mixins.length, proto, method;
  10101. NewClass.__KityMixins = {
  10102. constructor: []
  10103. };
  10104. for (i = 0; i < length; i++) {
  10105. proto = mixins[i].prototype;
  10106. for (method in proto) {
  10107. if (false === proto.hasOwnProperty(method) || method.indexOf("__Kity") === 0) {
  10108. continue;
  10109. }
  10110. if (method === "constructor") {
  10111. // constructor 特殊处理
  10112. NewClass.__KityMixins.constructor.push(proto[method]);
  10113. } else {
  10114. NewClass.prototype[method] = NewClass.__KityMixins[method] = proto[method];
  10115. }
  10116. }
  10117. }
  10118. return NewClass;
  10119. }
  10120. function extend(BaseClass, extension) {
  10121. if (extension.__KityClassName) {
  10122. extension = extension.prototype;
  10123. }
  10124. for (var methodName in extension) {
  10125. if (extension.hasOwnProperty(methodName) && methodName.indexOf("__Kity") && methodName != "constructor") {
  10126. var method = BaseClass.prototype[methodName] = extension[methodName];
  10127. method.__KityMethodClass = BaseClass;
  10128. method.__KityMethodName = methodName;
  10129. }
  10130. }
  10131. return BaseClass;
  10132. }
  10133. Class.prototype._accessProperty = function() {
  10134. return this._propertyRawData || (this._propertyRawData = {});
  10135. };
  10136. exports.createClass = function(classname, defines) {
  10137. var constructor, NewClass, BaseClass;
  10138. if (arguments.length === 1) {
  10139. defines = arguments[0];
  10140. classname = "AnonymousClass";
  10141. }
  10142. BaseClass = defines.base || Class;
  10143. if (defines.hasOwnProperty("constructor")) {
  10144. constructor = defines.constructor;
  10145. if (BaseClass != Class) {
  10146. checkBaseConstructorCall(constructor, classname);
  10147. }
  10148. } else {
  10149. constructor = function() {
  10150. this.callBase.apply(this, arguments);
  10151. this.callMixin.apply(this, arguments);
  10152. };
  10153. }
  10154. NewClass = inherit(constructor, BaseClass, classname);
  10155. NewClass = mixin(NewClass, defines.mixins);
  10156. NewClass.__KityClassName = constructor.__KityClassName = classname;
  10157. NewClass.__KityBaseClass = constructor.__KityBaseClass = BaseClass;
  10158. NewClass.__KityMethodName = constructor.__KityMethodName = "constructor";
  10159. NewClass.__KityMethodClass = constructor.__KityMethodClass = NewClass;
  10160. // 下面这些不需要拷贝到原型链上
  10161. delete defines.mixins;
  10162. delete defines.constructor;
  10163. delete defines.base;
  10164. NewClass = extend(NewClass, defines);
  10165. return NewClass;
  10166. };
  10167. exports.extendClass = extend;
  10168. }
  10169. };
  10170. //src/base/kit/common.js
  10171. /**
  10172. * 通用工具包
  10173. */
  10174. _p[6] = {
  10175. value: function(require) {
  10176. var $ = _p.r(4), __marker = "__fui__marker__" + +new Date();
  10177. return {
  10178. isElement: function(target) {
  10179. return target.nodeType === 1;
  10180. },
  10181. getMarker: function() {
  10182. return __marker;
  10183. },
  10184. getRect: function(node) {
  10185. var rect = node.getBoundingClientRect();
  10186. return {
  10187. width: rect.width,
  10188. height: rect.height,
  10189. top: rect.top,
  10190. bottom: rect.bottom,
  10191. left: rect.left,
  10192. right: rect.right
  10193. };
  10194. },
  10195. getBound: function(node) {
  10196. var w = 0, h = 0;
  10197. if (node.tagName.toLowerCase() === "body") {
  10198. h = $(this.getView(node));
  10199. w = h.width();
  10200. h = h.height();
  10201. return {
  10202. top: 0,
  10203. left: 0,
  10204. bottom: h,
  10205. right: w,
  10206. width: w,
  10207. height: h
  10208. };
  10209. } else {
  10210. return this.getRect(node);
  10211. }
  10212. },
  10213. getView: function(node) {
  10214. return node.ownerDocument.defaultView || node.ownerDocument.parentWindow;
  10215. }
  10216. };
  10217. }
  10218. };
  10219. //src/base/kit/compile.js
  10220. /**
  10221. * 模板编译器
  10222. */
  10223. _p[7] = {
  10224. value: function(require) {
  10225. var jhtmls = _p.r(3), $ = _p.r(4);
  10226. var Helper = {
  10227. forEach: function(arras, cb) {
  10228. $.each(arras, function(i, item) {
  10229. cb.call(null, i, item);
  10230. });
  10231. }
  10232. };
  10233. return {
  10234. compile: function(tpl, data) {
  10235. tpl = $.trim(tpl);
  10236. if (tpl.length === 0) {
  10237. return "";
  10238. }
  10239. return jhtmls.render(tpl, data, Helper);
  10240. }
  10241. };
  10242. }
  10243. };
  10244. //src/base/kit/draggable.js
  10245. /**
  10246. * Draggable Lib
  10247. */
  10248. _p[8] = {
  10249. value: function(require, exports) {
  10250. var $ = _p.r(4), common = _p.r(6), DEFAULT_OPTIONS = {
  10251. handler: null,
  10252. target: null,
  10253. axis: "all",
  10254. range: null
  10255. };
  10256. function Draggable(options) {
  10257. this.__options = $.extend({}, DEFAULT_OPTIONS, options);
  10258. this.__started = false;
  10259. this.__point = {
  10260. x: 0,
  10261. y: 0
  10262. };
  10263. this.__location = {
  10264. x: 0,
  10265. y: 0
  10266. };
  10267. this.__range = {
  10268. top: 0,
  10269. left: 0,
  10270. bottom: 0,
  10271. right: 0
  10272. };
  10273. }
  10274. $.extend(Draggable.prototype, {
  10275. bind: function(target) {
  10276. if (target) {
  10277. this.__options.target = target;
  10278. }
  10279. if (!this.__options.target) {
  10280. throw new Error("target unset");
  10281. }
  10282. this.__target = this.__options.target;
  10283. this.__handler = this.__options.handler;
  10284. this.__rangeNode = this.__options.range;
  10285. this.__initOptions();
  10286. this.__initEnv();
  10287. this.__initEvent();
  10288. },
  10289. __initEvent: function() {
  10290. var handler = this.__handler, _self = this;
  10291. $(handler).on("mousedown", function(e) {
  10292. if (e.which !== 1) {
  10293. return;
  10294. }
  10295. var location = common.getRect(handler);
  10296. e.preventDefault();
  10297. _self.__started = true;
  10298. _self.__point = {
  10299. x: e.clientX,
  10300. y: e.clientY
  10301. };
  10302. _self.__location = {
  10303. x: location.left,
  10304. y: location.top
  10305. };
  10306. _self.__range = _self.__getRange();
  10307. });
  10308. $(handler.ownerDocument).on("mousemove", function(e) {
  10309. if (!_self.__started) {
  10310. return;
  10311. }
  10312. var x = e.clientX, y = e.clientY;
  10313. if (_self.__allowAxisX) {
  10314. _self.__xMove(x);
  10315. }
  10316. if (_self.__allowAxisY) {
  10317. _self.__yMove(y);
  10318. }
  10319. }).on("mouseup", function(e) {
  10320. _self.__started = false;
  10321. });
  10322. },
  10323. __xMove: function(x) {
  10324. var diff = x - this.__point.x;
  10325. diff = this.__location.x + diff;
  10326. if (diff < this.__range.left) {
  10327. diff = this.__range.left;
  10328. } else if (diff > this.__range.right) {
  10329. diff = this.__range.right;
  10330. }
  10331. this.__target.style.left = diff + "px";
  10332. },
  10333. __yMove: function(y) {
  10334. var diff = y - this.__point.y;
  10335. diff = this.__location.y + diff;
  10336. if (diff < this.__range.top) {
  10337. diff = this.__range.top;
  10338. } else if (diff > this.__range.bottom) {
  10339. diff = this.__range.bottom;
  10340. }
  10341. this.__target.style.top = diff + "px";
  10342. },
  10343. __initEnv: function() {
  10344. var $handler = $(this.__handler);
  10345. $handler.css("cursor", "move");
  10346. },
  10347. __initOptions: function() {
  10348. if (!this.__handler) {
  10349. this.__handler = this.__target;
  10350. }
  10351. if (!this.__rangeNode) {
  10352. this.__rangeNode = this.__options.target.ownerDocument.body;
  10353. }
  10354. this.__allowAxisX = this.__options.axis !== "y";
  10355. this.__allowAxisY = this.__options.axis !== "x";
  10356. },
  10357. __getRange: function() {
  10358. var range = this.__rangeNode, targetRect = common.getRect(this.__target);
  10359. if (range.tagName.toLowerCase() === "body") {
  10360. range = $(this.__rangeNode.ownerDocument);
  10361. range = {
  10362. top: 0,
  10363. left: 0,
  10364. bottom: range.height(),
  10365. right: range.width()
  10366. };
  10367. } else {
  10368. range = common.getRect(range);
  10369. }
  10370. return {
  10371. top: range.top,
  10372. left: range.left,
  10373. bottom: range.bottom - targetRect.height,
  10374. right: range.right - targetRect.width
  10375. };
  10376. }
  10377. });
  10378. return function(options) {
  10379. return new Draggable(options);
  10380. };
  10381. }
  10382. };
  10383. //src/base/kit/extend.js
  10384. /**
  10385. * 弥补jQuery的extend在克隆对象和数组时存在的问题
  10386. */
  10387. _p[9] = {
  10388. value: function(require) {
  10389. var $ = _p.r(4);
  10390. function extend(target) {
  10391. var isPlainObject = false, isArray = false, sourceObj = null;
  10392. if (arguments.length === 1) {
  10393. return copy(target);
  10394. }
  10395. $.each([].slice.call(arguments, 1), function(i, source) {
  10396. for (var key in source) {
  10397. sourceObj = source[key];
  10398. if (!source.hasOwnProperty(key)) {
  10399. continue;
  10400. }
  10401. isPlainObject = $.isPlainObject(sourceObj);
  10402. isArray = $.isArray(sourceObj);
  10403. if (!isPlainObject && !isArray) {
  10404. target[key] = source[key];
  10405. } else if (isPlainObject) {
  10406. if (!$.isPlainObject(target[key])) {
  10407. target[key] = {};
  10408. }
  10409. target[key] = extend(target[key], sourceObj);
  10410. } else if (isArray) {
  10411. target[key] = extend(sourceObj);
  10412. }
  10413. }
  10414. });
  10415. return target;
  10416. }
  10417. function copy(target) {
  10418. var tmp = null;
  10419. if ($.isPlainObject(target)) {
  10420. return extend({}, target);
  10421. } else if ($.isArray(target)) {
  10422. tmp = [];
  10423. $.each(target, function(index, item) {
  10424. if ($.isPlainObject(item) || $.isArray(item)) {
  10425. tmp.push(copy(item));
  10426. } else {
  10427. tmp.push(item);
  10428. }
  10429. });
  10430. return tmp;
  10431. } else {
  10432. return target;
  10433. }
  10434. }
  10435. return extend;
  10436. }
  10437. };
  10438. //src/base/kit/widget.js
  10439. /**
  10440. * 构件相关工具方法
  10441. */
  10442. _p[10] = {
  10443. value: function(require) {
  10444. return {
  10445. isContainer: function(widget) {
  10446. return widget.__widgetType === "container";
  10447. }
  10448. };
  10449. }
  10450. };
  10451. //src/base/ns.js
  10452. /**
  10453. * FUI名称空间
  10454. */
  10455. _p[11] = {
  10456. value: function() {
  10457. // 容纳所有构件的实例池
  10458. var WIDGET_POOL = {};
  10459. return {
  10460. widgets: WIDGET_POOL,
  10461. /**
  10462. * 暴露命名空间本身
  10463. * @private
  10464. */
  10465. __export: function() {
  10466. window.FUI = this;
  10467. },
  10468. ___register: function(widgetName, widget) {
  10469. if (typeof widgetName === "string") {
  10470. this[widgetName] = widget;
  10471. } else {
  10472. widget = widgetName;
  10473. for (var key in widget) {
  10474. if (widget.hasOwnProperty(key)) {
  10475. this[key] = widget[key];
  10476. }
  10477. }
  10478. }
  10479. },
  10480. __registerInstance: function(widget) {
  10481. WIDGET_POOL[widget.getId()] = widget;
  10482. }
  10483. };
  10484. }
  10485. };
  10486. //src/base/sysconf.js
  10487. /**
  10488. * UI系统配置
  10489. */
  10490. _p[12] = {
  10491. value: function(require) {
  10492. var NS = _p.r(11);
  10493. return {
  10494. classPrefix: "fui-",
  10495. layout: {
  10496. TOP: "top",
  10497. LEFT: "left",
  10498. BOTTOM: "bottom",
  10499. RIGHT: "right",
  10500. CENTER: "center",
  10501. MIDDLE: "middle",
  10502. // 内部定位
  10503. LEFT_TOP: "left-top",
  10504. RIGHT_TOP: "right-top",
  10505. LEFT_BOTTOM: "left-bottom",
  10506. RIGHT_BOTTOM: "right-bottom"
  10507. },
  10508. allowFocus: !!NS.ALLOW_FOCUS,
  10509. control: {
  10510. input: 1,
  10511. textarea: 1,
  10512. button: 1,
  10513. select: 1,
  10514. option: 1,
  10515. object: 1,
  10516. embed: 1
  10517. }
  10518. };
  10519. }
  10520. };
  10521. //src/base/utils.js
  10522. /**
  10523. * utils类包, 提供常用操作的封装,补充jQuery的不足
  10524. */
  10525. _p[13] = {
  10526. value: function(require) {
  10527. var $ = _p.r(4), Utils = {
  10528. Tpl: _p.r(7),
  10529. Widget: _p.r(10),
  10530. createDraggable: _p.r(8)
  10531. };
  10532. return $.extend(Utils, _p.r(6), _p.r(5));
  10533. }
  10534. };
  10535. //src/ext/word/tpl/t-picker.js
  10536. _p[14] = {
  10537. value: function() {
  10538. return '<div unselectable="on" class="fui-t-picker"></div>\n';
  10539. }
  10540. };
  10541. //src/ext/word/tpl/table-picker.js
  10542. _p[15] = {
  10543. value: function() {
  10544. return '<div unselectable="on" class="fui-table-picker"></div>\n';
  10545. }
  10546. };
  10547. //src/ext/word/widget/t-picker.js
  10548. /**
  10549. * TPicker -- table 选择器
  10550. */
  10551. _p[16] = {
  10552. value: function(require) {
  10553. var $ = _p.r(4), CONF = _p.r(12), tpl = _p.r(14);
  10554. return _p.r(13).createClass("TPicker", {
  10555. base: _p.r(60),
  10556. constructor: function(options) {
  10557. var defaultOptions = {
  10558. // 10行 10列
  10559. row: 10,
  10560. col: 10
  10561. };
  10562. options = $.extend({}, defaultOptions, options);
  10563. this.callBase(options);
  10564. },
  10565. __initOptions: function() {
  10566. this.callBase();
  10567. this.widgetName = "TPicker";
  10568. this.__tpl = tpl;
  10569. // 背板
  10570. this.__backplane = null;
  10571. },
  10572. __render: function() {
  10573. this.callBase();
  10574. this.__backplane = this.__createBackplane();
  10575. this.__element.appendChild(this.__backplane);
  10576. },
  10577. __initEvent: function() {
  10578. var _self = this;
  10579. var info = {};
  10580. this.callBase();
  10581. $(this.__backplane).delegate("td", "mousemove", function(e) {
  10582. info = e.target.getAttribute("data-index").split(",");
  10583. info = {
  10584. row: parseInt(info[0], 10),
  10585. col: parseInt(info[1], 10)
  10586. };
  10587. _self.__update(info.row, info.col);
  10588. });
  10589. $(this.__backplane).on("click", function(e) {
  10590. _self.__select(info.row, info.col);
  10591. });
  10592. },
  10593. __select: function(row, col) {
  10594. this.trigger("pickerselect", {
  10595. row: row,
  10596. col: col
  10597. });
  10598. },
  10599. __update: function(row, col) {
  10600. var tr = null, rowCount = this.__options.row, colCount = this.__options.col, className = CONF.classPrefix + "table-picker-hoverin";
  10601. for (var i = 0; i < rowCount; i++) {
  10602. tr = this.__backplane.rows[i];
  10603. for (var j = 0; j < colCount; j++) {
  10604. if (i <= row && j <= col) {
  10605. tr.cells[j].className = className;
  10606. } else {
  10607. tr.cells[j].className = "";
  10608. }
  10609. }
  10610. }
  10611. this.trigger("pickerhover", {
  10612. row: row,
  10613. col: col
  10614. });
  10615. },
  10616. __createBackplane: function() {
  10617. var tpl = [], tmp = null;
  10618. for (var i = 0, len = this.__options.row; i < len; i++) {
  10619. tmp = [];
  10620. for (var j = 0, jlen = this.__options.col; j < jlen; j++) {
  10621. tmp.push('<td data-index="' + i + "," + j + '"></td>');
  10622. }
  10623. tpl.push("<tr>" + tmp.join("") + "</tr>");
  10624. }
  10625. tpl = $("<table><tbody>" + tpl.join("") + "</tbody></table>");
  10626. tpl.addClass(CONF.classPrefix + "t-picker-table");
  10627. return tpl[0];
  10628. }
  10629. });
  10630. }
  10631. };
  10632. //src/ext/word/widget/table-picker.js
  10633. /**
  10634. * Table选择器构件
  10635. */
  10636. _p[17] = {
  10637. value: function(require) {
  10638. var $ = _p.r(4), CONF = _p.r(12), tpl = _p.r(15), Label = _p.r(48), TPicker = _p.r(16), Button = _p.r(37), PPanel = _p.r(54), Mask = _p.r(49);
  10639. return _p.r(13).createClass("TablePicker", {
  10640. base: _p.r(60),
  10641. constructor: function(options) {
  10642. var defaultOptions = {
  10643. button: null,
  10644. row: 10,
  10645. col: 10
  10646. };
  10647. options = $.extend({}, defaultOptions, options);
  10648. this.callBase(options);
  10649. },
  10650. open: function() {
  10651. this.__panelWidget.show();
  10652. this.__maskWidget.show();
  10653. },
  10654. close: function() {
  10655. this.__panelWidget.hide();
  10656. this.__maskWidget.hide();
  10657. },
  10658. // Overload
  10659. appendTo: function(container) {
  10660. container.appendChild(this.__buttonWidget.getElement());
  10661. },
  10662. getButton: function() {
  10663. return this.__buttonWidget;
  10664. },
  10665. __initOptions: function() {
  10666. this.callBase();
  10667. this.widgetName = "TablePicker";
  10668. this.__tpl = tpl;
  10669. this.__pickerWidget = null;
  10670. this.__labelWidget = null;
  10671. this.__buttonWidget = null;
  10672. this.__panelWidget = null;
  10673. this.__maskWidget = null;
  10674. },
  10675. __render: function() {
  10676. this.callBase();
  10677. this.__pickerWidget = new TPicker(this.__options);
  10678. this.__labelWidget = new Label({
  10679. text: "插入表格"
  10680. });
  10681. this.__buttonWidget = new Button(this.__options.button);
  10682. this.__panelWidget = new PPanel({
  10683. className: CONF.classPrefix + "table-picker-panel",
  10684. column: true,
  10685. resize: "none"
  10686. });
  10687. this.__maskWidget = new Mask();
  10688. this.__panelWidget.appendWidget(this.__labelWidget);
  10689. this.__panelWidget.appendWidget(this.__pickerWidget);
  10690. this.__panelWidget.positionTo(this.__buttonWidget);
  10691. },
  10692. __initEvent: function() {
  10693. var _self = this;
  10694. this.callBase();
  10695. this.__buttonWidget.on("btnclick", function(e) {
  10696. _self.open();
  10697. });
  10698. this.__maskWidget.on("maskclick", function(e) {
  10699. _self.close();
  10700. });
  10701. this.__pickerWidget.on("pickerhover", function(e, info) {
  10702. var row = info.row + 1, col = info.col + 1;
  10703. _self.__labelWidget.setText(row + "x" + col + " 表格");
  10704. }).on("pickerselect", function(e, info) {
  10705. var row = info.row + 1, col = info.col + 1;
  10706. _self.close();
  10707. _self.trigger("pickerselect", {
  10708. row: row,
  10709. col: col
  10710. });
  10711. });
  10712. },
  10713. __createBackplane: function() {
  10714. var tpl = [], tmp = null;
  10715. for (var i = 0, len = this.__options.row; i < len; i++) {
  10716. tmp = [];
  10717. for (var j = 0, jlen = this.__options.col; j < jlen; j++) {
  10718. tmp.push('<td data-index="' + i + "," + j + '"></td>');
  10719. }
  10720. tpl.push("<tr>" + tmp.join("") + "</tr>");
  10721. }
  10722. tpl = $("<table><tbody>" + tpl.join("") + "</tbody></table>");
  10723. tpl.addClass(CONF.classPrefix + "t-picker-table");
  10724. return tpl[0];
  10725. }
  10726. });
  10727. }
  10728. };
  10729. //src/tpl/button-menu.js
  10730. _p[18] = {
  10731. value: function() {
  10732. return '<div unselectable="on" class="fui-button-menu"></div>\n';
  10733. }
  10734. };
  10735. //src/tpl/button.js
  10736. _p[19] = {
  10737. value: function() {
  10738. return '<div unselectable="on" class="fui-button"></div>\n';
  10739. }
  10740. };
  10741. //src/tpl/colorpicker.js
  10742. _p[20] = {
  10743. value: function() {
  10744. return '<div unselectable="on" class="fui-colorpicker-container">\n' + '<div unselectable="on" class="fui-colorpicker-toolbar">\n' + '<div unselectable="on" class="fui-colorpicker-preview"></div>\n' + '<div unselectable="on" class="fui-colorpicker-clear">$clearText</div>\n' + "</div>\n" + '<div unselectable="on" class="fui-colorpicker-title">$commonText</div>\n' + '<div unselectable="on" class="fui-colorpicker-commoncolor">\n' + "helper.forEach( commonColor, function ( index, colors ) {\n" + '<div unselectable="on" class="fui-colorpicker-colors fui-colorpicker-colors-line$index">\n' + "helper.forEach( colors, function( i, color ) {\n" + '<span unselectable="on" class="fui-colorpicker-item" style="background-color: $color; border-color: #{color.toLowerCase() == \'#ffffff\' ? \'#eeeeee\': color};" data-color="$color"></span>\n' + "});\n" + "</div>\n" + "} );\n" + "</div>\n" + '<div unselectable="on" class="fui-colorpicker-title">$standardText</div>\n' + '<div unselectable="on" class="fui-colorpicker-standardcolor fui-colorpicker-colors">\n' + "helper.forEach( standardColor, function ( i, color ) {\n" + '<span unselectable="on" class="fui-colorpicker-item" style="background-color: $color; border-color: $color;" data-color="$color"></span>\n' + "} );\n" + "</div>\n" + "</div>\n";
  10745. }
  10746. };
  10747. //src/tpl/dialog.js
  10748. _p[21] = {
  10749. value: function() {
  10750. return '<div unselectable="on" class="fui-dialog-wrap">\n' + '<div unselectable="on" class="fui-dialog-head">\n' + '<h1 unselectable="on" class="fui-dialog-caption">$caption</h1>\n' + "</div>\n" + '<div unselectable="on" class="fui-dialog-body"></div>\n' + '<div unselectable="on" class="fui-dialog-foot"></div>\n' + "</div>\n";
  10751. }
  10752. };
  10753. //src/tpl/drop-panel.js
  10754. _p[22] = {
  10755. value: function() {
  10756. return "<div unselectable=\"on\" class=\"fui-drop-panel\" #{ text ? 'title=\"' + m.text + '\"' : '' }></div>\n";
  10757. }
  10758. };
  10759. //src/tpl/icon.js
  10760. _p[23] = {
  10761. value: function() {
  10762. return '<div unselectable="on" class="fui-icon" >\n' + "if ( this.img ) {\n" + '<img unselectable="on" src="#{this.img}" >\n' + "}\n" + "</div>\n";
  10763. }
  10764. };
  10765. //src/tpl/input-button.js
  10766. _p[24] = {
  10767. value: function() {
  10768. return '<div unselectable="on" class="fui-input-button"></div>\n';
  10769. }
  10770. };
  10771. //src/tpl/input-menu.js
  10772. _p[25] = {
  10773. value: function() {
  10774. return '<div unselectable="on" class="fui-input-menu"></div>\n';
  10775. }
  10776. };
  10777. //src/tpl/input.js
  10778. _p[26] = {
  10779. value: function() {
  10780. return '<input unselectable="on" class="fui-input" autocomplete="off" !#{ value ? \'value="\' + value + \'"\' : \'\'}>\n';
  10781. }
  10782. };
  10783. //src/tpl/item.js
  10784. _p[27] = {
  10785. value: function() {
  10786. return "<div unselectable=\"on\" class=\"fui-item!#{ selected ? ' fui-item-selected': '' }\" ></div>\n";
  10787. }
  10788. };
  10789. //src/tpl/label.js
  10790. _p[28] = {
  10791. value: function() {
  10792. return '<div unselectable="on" class="fui-label">$text</div>\n';
  10793. }
  10794. };
  10795. //src/tpl/mask.js
  10796. _p[29] = {
  10797. value: function() {
  10798. return '<div unselectable="on" class="fui-mask" style="background-color: $bgcolor; opacity: $opacity;"></div>\n';
  10799. }
  10800. };
  10801. //src/tpl/panel.js
  10802. _p[30] = {
  10803. value: function() {
  10804. return '<div unselectable="on" class="fui-panel"></div>\n';
  10805. }
  10806. };
  10807. //src/tpl/separator.js
  10808. _p[31] = {
  10809. value: function() {
  10810. return '<div unselectable="on" class="fui-separator"></div>\n';
  10811. }
  10812. };
  10813. //src/tpl/spin-button.js
  10814. _p[32] = {
  10815. value: function() {
  10816. return '<div unselectable="on" class="fui-spin-button"></div>\n';
  10817. }
  10818. };
  10819. //src/tpl/tabs.js
  10820. _p[33] = {
  10821. value: function() {
  10822. return '<div unselectable="on" class="fui-tabs">\n' + '<div unselectable="on" class="fui-tabs-button-wrap"></div>\n' + '<div unselectable="on" class="fui-tabs-panel-wrap"></div>\n' + "</div>\n";
  10823. }
  10824. };
  10825. //src/widget/button-menu.js
  10826. /**
  10827. * Button对象
  10828. * 通用按钮构件
  10829. */
  10830. _p[34] = {
  10831. value: function(require) {
  10832. var $ = _p.r(4), CONF = _p.r(12), tpl = _p.r(18), Button = _p.r(37), Menu = _p.r(50), Mask = _p.r(49), LAYOUT = CONF.layout;
  10833. return _p.r(13).createClass("ButtonMenu", {
  10834. base: _p.r(60),
  10835. constructor: function(options) {
  10836. var defaultOptions = {
  10837. // item选项
  10838. menu: null,
  10839. mask: null,
  10840. buttons: [],
  10841. selected: -1,
  10842. layout: LAYOUT.RIGHT
  10843. };
  10844. options = $.extend({}, defaultOptions, options);
  10845. this.callBase(options);
  10846. },
  10847. open: function() {
  10848. this.__openState = true;
  10849. this.__maskWidget.show();
  10850. this.__menuWidget.show();
  10851. this.addClass(CONF.classPrefix + "button-active");
  10852. },
  10853. close: function() {
  10854. this.__openState = false;
  10855. this.__maskWidget.hide();
  10856. this.__menuWidget.hide();
  10857. this.removeClass(CONF.classPrefix + "button-active");
  10858. },
  10859. isOpen: function() {
  10860. return !!this.__openState;
  10861. },
  10862. getSelected: function() {
  10863. return this.__menuWidget.getSelected();
  10864. },
  10865. getSelectedItem: function() {
  10866. return this.__menuWidget.getSelectedItem();
  10867. },
  10868. getValue: function() {
  10869. return this.getSelectedItem().getValue();
  10870. },
  10871. __render: function() {
  10872. this.callBase();
  10873. this.__initButtons();
  10874. this.__menuWidget = new Menu(this.__options.menu);
  10875. this.__maskWidget = new Mask(this.__options.mask);
  10876. this.__menuWidget.positionTo(this.__element);
  10877. this.__menuWidget.appendTo(this.__element.ownerDocument.body);
  10878. },
  10879. __initOptions: function() {
  10880. this.callBase();
  10881. this.widgetName = "ButtonMenu";
  10882. this.__tpl = tpl;
  10883. this.__buttonWidgets = null;
  10884. this.__menuWidget = null;
  10885. this.__maskWidget = null;
  10886. this.__openState = false;
  10887. if (this.__options.selected !== -1) {
  10888. this.__options.menu.selected = this.__options.selected;
  10889. }
  10890. },
  10891. __initButtons: function() {
  10892. var buttons = [], ele = this.__element, btn = null, lastIndex = this.__options.buttons.length - 1;
  10893. if (this.__options.layout === LAYOUT.TOP || this.__options.layout === LAYOUT.LEFT) {
  10894. btn = new Button(this.__options.buttons[lastIndex]);
  10895. btn.appendTo(ele);
  10896. } else {
  10897. lastIndex = -1;
  10898. }
  10899. $.each(this.__options.buttons, function(index, options) {
  10900. if (lastIndex !== index) {
  10901. var button = new Button(options);
  10902. button.appendTo(ele);
  10903. buttons.push(button);
  10904. } else {
  10905. buttons.push(btn);
  10906. }
  10907. });
  10908. this.addClass(CONF.classPrefix + "layout-" + this.__options.layout);
  10909. buttons[buttons.length - 1].addClass(CONF.classPrefix + "open-btn");
  10910. this.__buttonWidgets = buttons;
  10911. },
  10912. __initEvent: function() {
  10913. var lastBtn = this.__buttonWidgets[this.__buttonWidgets.length - 1], _self = this;
  10914. this.callBase();
  10915. lastBtn.on("click", function(e) {
  10916. _self.open();
  10917. });
  10918. this.__maskWidget.on("maskclick", function() {
  10919. _self.close();
  10920. });
  10921. this.__menuWidget.on("select", function(e, info) {
  10922. e.stopPropagation();
  10923. _self.close();
  10924. _self.trigger("select", info);
  10925. }).on("change", function(e, info) {
  10926. _self.trigger("change", info);
  10927. });
  10928. this.on("btnclick", function(e) {
  10929. e.stopPropagation();
  10930. var btnIndex = $.inArray(e.widget, this.__buttonWidgets);
  10931. if (btnIndex > -1 && btnIndex < this.__buttonWidgets.length - 1) {
  10932. this.trigger("buttonclick", {
  10933. button: this.__buttonWidgets[btnIndex]
  10934. });
  10935. }
  10936. });
  10937. }
  10938. });
  10939. }
  10940. };
  10941. //src/widget/button-set-menu.js
  10942. /**
  10943. * InputMenu构件
  10944. * 可接受输入的下拉菜单构件
  10945. */
  10946. _p[35] = {
  10947. value: function(require) {
  10948. var $ = _p.r(4), tpl = _p.r(25), InputButton = _p.r(43), Menu = _p.r(50), Mask = _p.r(49), Utils = _p.r(13);
  10949. return _p.r(13).createClass("InputMenu", {
  10950. base: _p.r(60),
  10951. constructor: function(options) {
  10952. var marker = Utils.getMarker();
  10953. this.callBase(marker);
  10954. var defaultOptions = {
  10955. input: null,
  10956. menu: null,
  10957. mask: null
  10958. };
  10959. this.__extendOptions(defaultOptions, options);
  10960. this.widgetName = "InputMenu";
  10961. this.__tpl = tpl;
  10962. // 最后输入时间
  10963. this.__lastTime = 0;
  10964. // 最后选中的记录
  10965. this.__lastSelect = null;
  10966. this.__inputWidget = null;
  10967. this.__menuWidget = null;
  10968. this.__maskWidget = null;
  10969. // menu状态, 记录是否已经append到dom树上
  10970. this.__menuState = false;
  10971. if (options !== marker) {
  10972. this.__render();
  10973. }
  10974. },
  10975. select: function(index) {
  10976. this.__menuWidget.select(index);
  10977. },
  10978. setValue: function(value) {
  10979. this.__inputWidget.setValue(value);
  10980. return this;
  10981. },
  10982. getValue: function() {
  10983. return this.__inputWidget.getValue();
  10984. },
  10985. __render: function() {
  10986. if (this.__rendered) {
  10987. return this;
  10988. }
  10989. this.__inputWidget = new InputButton(this.__options.input);
  10990. this.__menuWidget = new Menu(this.__options.menu);
  10991. this.__maskWidget = new Mask(this.__options.mask);
  10992. this.callBase();
  10993. this.__inputWidget.appendTo(this.__element);
  10994. this.__menuWidget.positionTo(this.__inputWidget);
  10995. this.__initInputMenuEvent();
  10996. },
  10997. open: function() {
  10998. this.__maskWidget.show();
  10999. this.__menuWidget.show();
  11000. },
  11001. close: function() {
  11002. this.__maskWidget.hide();
  11003. this.__menuWidget.hide();
  11004. },
  11005. __initInputMenuEvent: function() {
  11006. var _self = this;
  11007. this.on("buttonclick", function() {
  11008. if (!this.__menuState) {
  11009. this.__appendMenu();
  11010. this.__menuState = true;
  11011. }
  11012. this.__inputWidget.unfocus();
  11013. this.open();
  11014. });
  11015. this.on("keypress", function(e) {
  11016. this.__lastTime = new Date();
  11017. });
  11018. this.on("keyup", function(e) {
  11019. if (e.keyCode !== 8 && e.keyCode !== 13 && new Date() - this.__lastTime < 500) {
  11020. this.__update();
  11021. }
  11022. });
  11023. this.on("inputcomplete", function() {
  11024. this.__inputWidget.selectRange(99999999);
  11025. this.__inputComplete();
  11026. });
  11027. this.__menuWidget.on("select", function(e, info) {
  11028. e.stopPropagation();
  11029. _self.setValue(info.value);
  11030. _self.trigger("select", info);
  11031. _self.close();
  11032. });
  11033. this.__menuWidget.on("change", function(e, info) {
  11034. e.stopPropagation();
  11035. _self.trigger("change", info);
  11036. });
  11037. // 阻止input自身的select和change事件
  11038. this.__inputWidget.on("select change", function(e) {
  11039. e.stopPropagation();
  11040. });
  11041. // mask 点击关闭
  11042. this.__maskWidget.on("maskclick", function() {
  11043. _self.close();
  11044. });
  11045. // 记录最后选中的数据
  11046. this.on("select", function(e, info) {
  11047. this.__lastSelect = info;
  11048. });
  11049. },
  11050. // 更新输入框内容
  11051. __update: function() {
  11052. var inputValue = this.getValue(), lowerCaseValue = inputValue.toLowerCase(), values = this.__getItemValues(), targetValue = null;
  11053. if (!inputValue) {
  11054. return;
  11055. }
  11056. $.each(values, function(i, val) {
  11057. if (val.toLowerCase().indexOf(lowerCaseValue) === 0) {
  11058. targetValue = val;
  11059. return false;
  11060. }
  11061. });
  11062. if (targetValue) {
  11063. this.__inputWidget.setValue(targetValue);
  11064. this.__inputWidget.selectRange(inputValue.length);
  11065. }
  11066. },
  11067. // 获取所有item的值列表
  11068. __getItemValues: function() {
  11069. var vals = [];
  11070. $.each(this.__menuWidget.getWidgets(), function(index, item) {
  11071. vals.push(item.getValue());
  11072. });
  11073. return vals;
  11074. },
  11075. // 用户输入完成
  11076. __inputComplete: function() {
  11077. var values = this.__getItemValues(), targetIndex = -1, inputValue = this.getValue(), lastSelect = this.__lastSelect;
  11078. $.each(values, function(i, val) {
  11079. if (val === inputValue) {
  11080. targetIndex = i;
  11081. return false;
  11082. }
  11083. });
  11084. this.trigger("select", {
  11085. index: targetIndex,
  11086. value: inputValue
  11087. });
  11088. if (!lastSelect || lastSelect.value !== inputValue) {
  11089. this.trigger("change", {
  11090. from: lastSelect || {
  11091. index: -1,
  11092. value: null
  11093. },
  11094. to: {
  11095. index: targetIndex,
  11096. value: inputValue
  11097. }
  11098. });
  11099. }
  11100. },
  11101. __appendMenu: function() {
  11102. this.__menuWidget.appendTo(this.__inputWidget.getElement().ownerDocument.body);
  11103. }
  11104. });
  11105. }
  11106. };
  11107. //src/widget/button-set.js
  11108. /**
  11109. * Buttonset对象
  11110. * 通用按钮构件
  11111. */
  11112. _p[36] = {
  11113. value: function(require) {
  11114. var $ = _p.r(4), CONF = _p.r(12), ToggleButton = _p.r(59);
  11115. return _p.r(13).createClass("Buttonset", {
  11116. base: _p.r(51),
  11117. constructor: function(options) {
  11118. var defaultOptions = {
  11119. // 初始选中项, -1表示不选中任何项
  11120. selected: -1
  11121. };
  11122. options = $.extend({}, defaultOptions, options);
  11123. this.callBase(options);
  11124. },
  11125. getButtons: function() {
  11126. return this.getWidgets();
  11127. },
  11128. getButton: function(index) {
  11129. return this.getWidgets()[index] || null;
  11130. },
  11131. getValue: function() {
  11132. if (this.__currentIndex > -1) {
  11133. return this.__widgets[this.__currentIndex].getValue();
  11134. }
  11135. return null;
  11136. },
  11137. getSelectedIndex: function() {
  11138. return this.__currentIndex;
  11139. },
  11140. appendButton: function() {
  11141. return this.appendWidget.apply(this, arguments);
  11142. },
  11143. insertButton: function() {
  11144. return this.insertWidget.apply(this, arguments);
  11145. },
  11146. select: function(indexOrWidget) {
  11147. if (this.__options.disabled) {
  11148. return this;
  11149. }
  11150. if (indexOrWidget instanceof ToggleButton) {
  11151. indexOrWidget = $.inArray(indexOrWidget, this.__widgets);
  11152. }
  11153. if (indexOrWidget < 0) {
  11154. return this.clearSelect();
  11155. }
  11156. indexOrWidget = this.__widgets[indexOrWidget];
  11157. this.__pressButton(indexOrWidget);
  11158. return this;
  11159. },
  11160. selectByValue: function(value) {
  11161. var values = this.__widgets.map(function(button) {
  11162. return button.getValue();
  11163. });
  11164. return this.select(values.indexOf(value));
  11165. },
  11166. clearSelect: function() {
  11167. this.__pressButton(null);
  11168. return this;
  11169. },
  11170. removeButton: function() {
  11171. return this.removeWidget.apply(this, arguments);
  11172. },
  11173. insertWidget: function(index, widget) {
  11174. var returnValue = this.callBase(index, widget);
  11175. if (returnValue === null) {
  11176. return returnValue;
  11177. }
  11178. if (index <= this.__currentIndex) {
  11179. this.__currentIndex++;
  11180. }
  11181. if (index <= this.__prevIndex) {
  11182. this.__prevIndex++;
  11183. }
  11184. return returnValue;
  11185. },
  11186. removeWidget: function(widget) {
  11187. var index = widget;
  11188. if (typeof index !== "number") {
  11189. index = this.indexOf(widget);
  11190. }
  11191. widget = this.callBase(widget);
  11192. if (index === this.__currentIndex) {
  11193. this.__currentIndex = -1;
  11194. } else if (index < this.__currentIndex) {
  11195. this.__currentIndex--;
  11196. }
  11197. if (index === this.__prevIndex) {
  11198. this.__prevIndex = -1;
  11199. } else if (index < this.__prevIndex) {
  11200. this.__prevIndex--;
  11201. }
  11202. return widget;
  11203. },
  11204. __initOptions: function() {
  11205. this.callBase();
  11206. this.widgetName = "Buttonset";
  11207. // 当前选中项
  11208. this.__currentIndex = this.__options.selected;
  11209. // 前一次选中项
  11210. this.__prevIndex = -1;
  11211. },
  11212. __render: function() {
  11213. this.callBase();
  11214. $(this.__element).addClass(CONF.classPrefix + "buttonset");
  11215. this.__initButtons();
  11216. return this;
  11217. },
  11218. __initButtons: function() {
  11219. var _self = this, buttonWidget = null;
  11220. $.each(this.__options.buttons, function(index, buttonOption) {
  11221. buttonWidget = new ToggleButton($.extend({}, buttonOption, {
  11222. pressed: index === _self.__options.selected,
  11223. preventDefault: true
  11224. }));
  11225. // 切换
  11226. buttonWidget.__on("click", function(e) {
  11227. if (!_self.isDisabled()) {
  11228. _self.__pressButton(this);
  11229. }
  11230. });
  11231. buttonWidget.__on("change", function(e) {
  11232. // 阻止buton本身的事件向上冒泡
  11233. e.stopPropagation();
  11234. });
  11235. _self.appendButton(buttonWidget);
  11236. });
  11237. },
  11238. /**
  11239. * 按下指定按钮, 该方法会更新其他按钮的状态和整个button-set的状态
  11240. * @param button
  11241. * @private
  11242. */
  11243. __pressButton: function(button) {
  11244. this.__prevIndex = this.__currentIndex;
  11245. this.__currentIndex = this.indexOf(button);
  11246. if (this.__currentIndex === this.__prevIndex) {
  11247. return;
  11248. }
  11249. if (button) {
  11250. button.press();
  11251. }
  11252. // 弹起其他按钮
  11253. $.each(this.__widgets, function(i, otherButton) {
  11254. if (otherButton !== button) {
  11255. otherButton.bounce();
  11256. }
  11257. });
  11258. this.trigger("change", {
  11259. currentIndex: this.__currentIndex,
  11260. prevIndex: this.__prevIndex
  11261. });
  11262. },
  11263. __valid: function(ele) {
  11264. return ele instanceof ToggleButton;
  11265. }
  11266. });
  11267. }
  11268. };
  11269. //src/widget/button.js
  11270. /**
  11271. * Button对象
  11272. * 通用按钮构件
  11273. */
  11274. _p[37] = {
  11275. value: function(require) {
  11276. var $ = _p.r(4), CONF = _p.r(12), buttonTpl = _p.r(19), Icon = _p.r(42), Label = _p.r(48);
  11277. return _p.r(13).createClass("Button", {
  11278. base: _p.r(60),
  11279. constructor: function(options) {
  11280. var defaultOptions = {
  11281. label: null,
  11282. text: null,
  11283. icon: null,
  11284. // label相对icon的位置
  11285. layout: "right"
  11286. };
  11287. options = $.extend({}, defaultOptions, options);
  11288. this.callBase(options);
  11289. },
  11290. getLabel: function() {
  11291. return this.__labelWidget.getText();
  11292. },
  11293. setLabel: function(text) {
  11294. return this.__labelWidget.setText(text);
  11295. },
  11296. getLabelWidget: function() {
  11297. return this.__labelWidget;
  11298. },
  11299. getIconWidget: function() {
  11300. return this.__iconWidget;
  11301. },
  11302. __render: function() {
  11303. this.callBase();
  11304. this.__iconWidget = new Icon(this.__options.icon);
  11305. this.__labelWidget = new Label(this.__options.label);
  11306. // layout
  11307. switch (this.__options.layout) {
  11308. case "left":
  11309. /* falls through */
  11310. case "top":
  11311. this.__element.appendChild(this.__labelWidget.getElement());
  11312. this.__element.appendChild(this.__iconWidget.getElement());
  11313. break;
  11314. case "right":
  11315. /* falls through */
  11316. case "bottom":
  11317. /* falls through */
  11318. default:
  11319. this.__element.appendChild(this.__iconWidget.getElement());
  11320. this.__element.appendChild(this.__labelWidget.getElement());
  11321. break;
  11322. }
  11323. $(this.__element).addClass(CONF.classPrefix + "button-layout-" + this.__options.layout);
  11324. },
  11325. __initOptions: function() {
  11326. this.callBase();
  11327. this.widgetName = "Button";
  11328. this.__tpl = buttonTpl;
  11329. this.__iconWidget = null;
  11330. this.__labelWidget = null;
  11331. if (typeof this.__options.label !== "object") {
  11332. this.__options.label = {
  11333. text: this.__options.label
  11334. };
  11335. }
  11336. if (typeof this.__options.icon !== "object") {
  11337. this.__options.icon = {
  11338. img: this.__options.icon
  11339. };
  11340. }
  11341. },
  11342. __initEvent: function() {
  11343. this.callBase();
  11344. this.on("click", function() {
  11345. this.__trigger("btnclick");
  11346. });
  11347. }
  11348. });
  11349. }
  11350. };
  11351. //src/widget/colorpicker.js
  11352. /**
  11353. * 容器类: PPanel = Positioning Panel
  11354. */
  11355. _p[38] = {
  11356. value: function(require) {
  11357. var Utils = _p.r(13), CONF = _p.r(12), Mask = _p.r(49), tpl = _p.r(20), $ = _p.r(4);
  11358. return Utils.createClass("ColorPicker", {
  11359. base: _p.r(54),
  11360. constructor: function(options) {
  11361. var defaultOptions = {
  11362. clearText: "",
  11363. commonText: "",
  11364. commonColor: [ [ "#ffffff", "#000000", "#eeece1", "#1f497d", "#4f81bd", "#c0504d", "#9bbb59", "#8064a2", "#4bacc6", "#f79646" ], [ "#f2f2f2", "#808080", "#ddd8c2", "#c6d9f1", "#dbe5f1", "#f2dbdb", "#eaf1dd", "#e5dfec", "#daeef3", "#fde9d9" ], [ "#d9d9d9", "#595959", "#c4bc96", "#8db3e2", "#b8cce4", "#e5b8b7", "#d6e3bc", "#ccc0d9", "#b6dde8", "#fbd4b4" ], [ "#bfbfbf", "#404040", "#938953", "#548dd4", "#95b3d7", "#d99594", "#c2d69b", "#b2a1c7", "#92cddc", "#fabf8f" ], [ "#a6a6a6", "#262626", "#4a442a", "#17365d", "#365f91", "#943634", "#76923c", "#5f497a", "#31849b", "#e36c0a" ], [ "#7f7f7f", "#0d0d0d", "#1c1a10", "#0f243e", "#243f60", "#622423", "#4e6128", "#3f3151", "#205867", "#974706" ] ],
  11365. standardText: "",
  11366. standardColor: [ "#c00000", "#ff0000", "#ffc000", "#ffff00", "#92d050", "#00b050", "#00b0f0", "#0070c0", "#002060", "#7030a0" ]
  11367. };
  11368. options = $.extend({}, defaultOptions, options);
  11369. this.callBase(options);
  11370. },
  11371. show: function() {
  11372. if (!this.__inDoc) {
  11373. this.__inDoc = true;
  11374. this.appendTo(this.__element.ownerDocument.body);
  11375. }
  11376. this.__maskWidget.show();
  11377. this.callBase();
  11378. return this;
  11379. },
  11380. hide: function() {
  11381. this.callBase();
  11382. this.__maskWidget.hide();
  11383. return this;
  11384. },
  11385. attachTo: function($obj) {
  11386. var _self = this;
  11387. $obj.on("click", function() {
  11388. _self.appendTo($obj.getElement().ownerDocument.body);
  11389. _self.positionTo($obj);
  11390. _self.show();
  11391. });
  11392. },
  11393. __initOptions: function() {
  11394. this.callBase();
  11395. this.widgetName = "ColorPicker";
  11396. this.__contentElement = null;
  11397. this.__maskWidget = null;
  11398. this.__inDoc = false;
  11399. },
  11400. __render: function() {
  11401. this.callBase();
  11402. $(this.__element).addClass(CONF.classPrefix + "colorpicker");
  11403. var contentHtml = Utils.Tpl.compile(tpl, this.__options);
  11404. this.__contentElement.appendChild($(contentHtml)[0]);
  11405. this.__previewElement = $(this.__contentElement).find("." + CONF.classPrefix + "colorpicker-preview");
  11406. this.__clearElement = $(this.__contentElement).find("." + CONF.classPrefix + "colorpicker-clear");
  11407. this.__maskWidget = new Mask(this.__options.mask);
  11408. },
  11409. // 初始化点击事件
  11410. __initEvent: function() {
  11411. var _self = this;
  11412. this.callBase();
  11413. this.on("click", function(e) {
  11414. var color, $target = $(e.target);
  11415. if ($target.hasClass(CONF.classPrefix + "colorpicker-item")) {
  11416. color = $target.attr("data-color");
  11417. _self.trigger("selectcolor", color);
  11418. _self.hide();
  11419. } else if ($target.hasClass(CONF.classPrefix + "colorpicker-clear")) {
  11420. _self.trigger("selectcolor", "");
  11421. _self.hide();
  11422. }
  11423. });
  11424. this.on("mouseover", function(e) {
  11425. var color, $target = $(e.target);
  11426. if ($target.hasClass(CONF.classPrefix + "colorpicker-item")) {
  11427. color = $target.attr("data-color");
  11428. $(_self.__element).find("." + CONF.classPrefix + "colorpicker-preview").css({
  11429. "background-color": color,
  11430. "border-color": color
  11431. });
  11432. }
  11433. });
  11434. this.__maskWidget.on("click", function() {
  11435. _self.hide();
  11436. });
  11437. }
  11438. });
  11439. }
  11440. };
  11441. //src/widget/container.js
  11442. /**
  11443. * Container类, 所有容器类的父类`
  11444. * @abstract
  11445. */
  11446. _p[39] = {
  11447. value: function(require) {
  11448. var Utils = _p.r(13), CONF = _p.r(12), Widget = _p.r(60), Creator = _p.r(0), $ = _p.r(4);
  11449. return Utils.createClass("Container", {
  11450. base: Widget,
  11451. constructor: function(options) {
  11452. var defaultOptions = {
  11453. column: false,
  11454. widgets: null
  11455. };
  11456. options = $.extend({}, defaultOptions, options);
  11457. this.callBase(options);
  11458. },
  11459. indexOf: function(widget) {
  11460. return $.inArray(widget, this.__widgets);
  11461. },
  11462. disable: function() {
  11463. this.callBase();
  11464. $.each(this.__widgets, function(index, widget) {
  11465. widget.disable();
  11466. });
  11467. },
  11468. enable: function() {
  11469. this.callBase();
  11470. $.each(this.__widgets, function(index, widget) {
  11471. widget.enable();
  11472. });
  11473. },
  11474. getWidgets: function() {
  11475. return this.__widgets;
  11476. },
  11477. getWidget: function(index) {
  11478. return this.__widgets[index] || null;
  11479. },
  11480. getWidgetByValue: function(value) {
  11481. var widget = null;
  11482. $.each(this.__widgets, function(i, wgt) {
  11483. if (wgt.getValue() === value) {
  11484. widget = wgt;
  11485. return false;
  11486. }
  11487. });
  11488. return widget;
  11489. },
  11490. appendWidget: function(widget) {
  11491. if (!this.__valid(widget)) {
  11492. return null;
  11493. }
  11494. if (this.__options.disabled) {
  11495. widget.disable();
  11496. }
  11497. this.__widgets.push(widget);
  11498. widget.appendTo(this.__contentElement);
  11499. if (!this.__options.column) {
  11500. return widget;
  11501. }
  11502. if (this.__widgets.length > 0 && this.__widgets.length % this.__options.column === 0) {
  11503. this.__contentElement.appendChild($('<span class="fui-column"></span>')[0]);
  11504. }
  11505. $(widget.getElement()).addClass(CONF.classPrefix + "panel-column-widget");
  11506. return widget;
  11507. },
  11508. appendWidgets: function(widgetArray) {
  11509. var _self = this, widgets = widgetArray;
  11510. if (!$.isArray(widgetArray)) {
  11511. widgets = arguments;
  11512. }
  11513. $.each(widgets, function(i, widget) {
  11514. _self.appendWidget(widget);
  11515. });
  11516. return this;
  11517. },
  11518. // TODO insertWidget时, 如果columnu为指定的数字,那么该插入需要调整换行符,现在还未对这个逻辑做处理。
  11519. insertWidget: function(index, widget) {
  11520. var oldElement = null;
  11521. if (this.__widgets.length === 0) {
  11522. return this.appendWidget(widget);
  11523. }
  11524. if (!this.__valid(widget)) {
  11525. return null;
  11526. }
  11527. if (this.__options.disabled) {
  11528. widget.disable();
  11529. }
  11530. oldElement = this.__widgets[index];
  11531. this.__widgets.splice(index, 0, widget);
  11532. this.__contentElement.insertBefore(widget.getElement(), oldElement.getElement());
  11533. if (this.__options.column === false) {
  11534. return widget;
  11535. }
  11536. this.__contentElement.insertBefore($('<span class="fui-column"></span>')[0], oldElement.getElement());
  11537. $(widget.getElement()).addClass(CONF.classPrefix + "panel-column-widget");
  11538. return widget;
  11539. },
  11540. insertWidgets: function(index, widgetArray) {
  11541. var _self = this, widgets = widgetArray;
  11542. if (!$.isArray(widgetArray)) {
  11543. widgets = [].slice.call(arguments, 1);
  11544. }
  11545. $.each(widgets, function(i, widget) {
  11546. _self.insertWidget(index, widget);
  11547. index++;
  11548. });
  11549. return this;
  11550. },
  11551. getContentElement: function() {
  11552. return this.__contentElement;
  11553. },
  11554. removeWidget: function(widget) {
  11555. if (typeof widget === "number") {
  11556. widget = this.__widgets.splice(widget, 1)[0];
  11557. } else {
  11558. this.__widgets.splice(this.indexOf(widget), 1);
  11559. }
  11560. this.__contentElement.removeChild(widget.getElement());
  11561. $(widget.getElement()).removeClass(CONF.classPrefix + "panel-column-widget");
  11562. return widget;
  11563. },
  11564. __initOptions: function() {
  11565. this.widgetName = "Container";
  11566. this.__widgets = [];
  11567. this.__contentElement = null;
  11568. this.__options.column -= 0;
  11569. },
  11570. __render: function() {
  11571. this.callBase();
  11572. this.__contentElement = this.__element;
  11573. $(this.__element).addClass(CONF.classPrefix + "container");
  11574. if (this.__options.column) {
  11575. $(this.__element).addClass(CONF.classPrefix + "container-column");
  11576. }
  11577. return this;
  11578. },
  11579. // Override
  11580. __appendChild: function(childWidget) {
  11581. return this.appendWidget(childWidget);
  11582. },
  11583. __initWidgets: function() {
  11584. if (!this.__options.widgets) {
  11585. return;
  11586. }
  11587. var widgets = Creator.parse(this.__options.widgets), _self = this;
  11588. if (!$.isArray(widgets)) {
  11589. widgets = [ widgets ];
  11590. }
  11591. $.each(widgets, function(i, widget) {
  11592. _self.appendWidget(widget);
  11593. });
  11594. },
  11595. /**
  11596. * 验证元素给定元素是否可以插入当前容器中
  11597. * @param ele 需要验证的元素
  11598. * @returns {boolean} 允许插入返回true, 否则返回false
  11599. * @private
  11600. */
  11601. __valid: function(ele) {
  11602. return ele instanceof Widget;
  11603. }
  11604. });
  11605. }
  11606. };
  11607. //src/widget/dialog.js
  11608. /**
  11609. * 容器类: PPanel = Positioning Panel
  11610. */
  11611. _p[40] = {
  11612. value: function(require) {
  11613. var Utils = _p.r(13), CONF = _p.r(12), Widget = _p.r(60), Mask = _p.r(49), tpl = _p.r(21), Button = _p.r(37), LAYOUT = CONF.layout, $ = _p.r(4), ACTION = {
  11614. CANCEL: "cancel",
  11615. OK: "ok"
  11616. };
  11617. return Utils.createClass("Dialog", {
  11618. base: _p.r(54),
  11619. constructor: function(options) {
  11620. var defaultOptions = {
  11621. layout: LAYOUT.CENTER,
  11622. caption: null,
  11623. resize: "height",
  11624. draggable: true,
  11625. // 是否包含close button
  11626. closeButton: true,
  11627. mask: {
  11628. color: "#000",
  11629. opacity: .2
  11630. },
  11631. prompt: false,
  11632. // 底部按钮
  11633. buttons: [ {
  11634. className: CONF.classPrefix + "xdialog-ok-btn",
  11635. action: "ok",
  11636. label: "确定"
  11637. }, {
  11638. className: CONF.classPrefix + "xdialog-cancel-btn",
  11639. action: "cancel",
  11640. label: "取消"
  11641. } ]
  11642. };
  11643. options = $.extend({}, defaultOptions, options);
  11644. this.callBase(options);
  11645. },
  11646. open: function() {
  11647. this.__fire("open", function() {
  11648. this.show();
  11649. });
  11650. return this;
  11651. },
  11652. close: function() {
  11653. this.__fire("close", function() {
  11654. this.hide();
  11655. });
  11656. return this;
  11657. },
  11658. getButtons: function() {
  11659. return this.__buttons;
  11660. },
  11661. getButton: function(index) {
  11662. return this.__buttons[index];
  11663. },
  11664. appendTo: function(container) {
  11665. this.callBase(container);
  11666. this.__maskWidget.appendTo(container);
  11667. this.__inDoc = true;
  11668. return this;
  11669. },
  11670. show: function() {
  11671. if (!this.__target) {
  11672. this.__target = this.__element.ownerDocument.body;
  11673. }
  11674. if (!this.__inDoc) {
  11675. this.appendTo(this.__element.ownerDocument.body);
  11676. }
  11677. this.__maskWidget.show();
  11678. this.callBase();
  11679. this.__openState = true;
  11680. return this;
  11681. },
  11682. hide: function() {
  11683. this.callBase();
  11684. this.__maskWidget.hide();
  11685. this.__openState = false;
  11686. return this;
  11687. },
  11688. toggle: function() {
  11689. this.isOpen() ? this.close() : this.open();
  11690. return this;
  11691. },
  11692. isOpen: function() {
  11693. return this.__openState;
  11694. },
  11695. getHeadElement: function() {
  11696. return this.__headElement;
  11697. },
  11698. getBodyElement: function() {
  11699. return this.getContentElement();
  11700. },
  11701. getFootElement: function() {
  11702. return this.__footElement;
  11703. },
  11704. __initOptions: function() {
  11705. this.callBase();
  11706. this.widgetName = "Dialog";
  11707. this.__target = this.__options.target;
  11708. this.__layout = this.__options.layout;
  11709. this.__inDoc = false;
  11710. this.__hinting = false;
  11711. this.__openState = false;
  11712. this.__headElement = null;
  11713. this.__bodyElement = null;
  11714. this.__footElement = null;
  11715. this.__maskWidget = null;
  11716. this.__buttons = [];
  11717. if (this.__target instanceof Widget) {
  11718. this.__target = this.__target.getElement();
  11719. }
  11720. },
  11721. __render: function() {
  11722. this.callBase();
  11723. this.__innerTpl = Utils.Tpl.compile(tpl, this.__options);
  11724. this.__contentElement.appendChild($(this.__innerTpl)[0]);
  11725. $(this.__element).addClass(CONF.classPrefix + "dialog");
  11726. this.__headElement = $(".fui-dialog-head", this.__contentElement)[0];
  11727. this.__bodyElement = $(".fui-dialog-body", this.__contentElement)[0];
  11728. this.__footElement = $(".fui-dialog-foot", this.__contentElement)[0];
  11729. this.__maskWidget = new Mask(this.__options.mask);
  11730. this.__contentElement = this.__bodyElement;
  11731. if (this.__options.draggable) {
  11732. this.__initDraggable();
  11733. }
  11734. if (this.__options.closeButton) {
  11735. this.__initCloseButton();
  11736. }
  11737. this.__initButtons();
  11738. this.__initMaskLint();
  11739. },
  11740. __action: function(type, btn) {
  11741. switch (type) {
  11742. case ACTION.OK:
  11743. if (this.__triggerHandler(type) !== false) {
  11744. this.close();
  11745. }
  11746. break;
  11747. case ACTION.CANCEL:
  11748. this.__triggerHandler(type);
  11749. this.close();
  11750. break;
  11751. }
  11752. },
  11753. __initButtons: function() {
  11754. var _self = this, button = null, foot = this.__footElement;
  11755. $.each(this.__options.buttons, function(index, buttonOption) {
  11756. button = new Button(buttonOption);
  11757. button.appendTo(foot);
  11758. _self.__buttons.push(button);
  11759. });
  11760. },
  11761. __initEvent: function() {
  11762. var _self = this;
  11763. this.callBase();
  11764. $([ this.__footElement, this.__headElement ]).on("btnclick", function(e, btn) {
  11765. _self.__action(btn.getOptions().action, btn);
  11766. });
  11767. if (this.__options.prompt) {
  11768. $(this.__element).on("keydown", function(e) {
  11769. switch (e.keyCode) {
  11770. case 13:
  11771. _self.__action(ACTION.OK);
  11772. break;
  11773. case 27:
  11774. _self.__action(ACTION.CANCEL);
  11775. break;
  11776. }
  11777. });
  11778. }
  11779. },
  11780. __initDraggable: function() {
  11781. Utils.createDraggable({
  11782. handler: this.__headElement,
  11783. target: this.__element
  11784. }).bind();
  11785. },
  11786. __initCloseButton: function() {
  11787. var closeButton = new Button({
  11788. className: "fui-close-button",
  11789. action: "cancel",
  11790. icon: {
  11791. className: "fui-close-button-icon"
  11792. }
  11793. });
  11794. closeButton.appendTo(this.__headElement);
  11795. },
  11796. __initMaskLint: function() {
  11797. var _self = this;
  11798. this.__maskWidget.on("click", function() {
  11799. _self.__hint();
  11800. });
  11801. },
  11802. __hint: function() {
  11803. if (this.__hinting) {
  11804. return;
  11805. }
  11806. this.__hinting = true;
  11807. var $ele = $(this.__element), _self = this, classNmae = [ CONF.classPrefix + "mask-hint", CONF.classPrefix + "mask-animate" ];
  11808. $ele.addClass(classNmae.join(" "));
  11809. window.setTimeout(function() {
  11810. $ele.removeClass(classNmae[0]);
  11811. window.setTimeout(function() {
  11812. $ele.removeClass(classNmae[1]);
  11813. _self.__hinting = false;
  11814. }, 200);
  11815. }, 200);
  11816. }
  11817. });
  11818. }
  11819. };
  11820. //src/widget/drop-panel.js
  11821. /**
  11822. * DropPanel对象
  11823. * 可接受输入的按钮构件
  11824. */
  11825. _p[41] = {
  11826. value: function(require) {
  11827. var $ = _p.r(4), CONF = _p.r(12), tpl = _p.r(22), Button = _p.r(37), Panel = _p.r(51), PPanel = _p.r(54), Mask = _p.r(49);
  11828. return _p.r(13).createClass("DropPanel", {
  11829. base: _p.r(60),
  11830. constructor: function(options) {
  11831. var defaultOptions = {
  11832. button: null,
  11833. panel: null,
  11834. width: null,
  11835. height: null
  11836. };
  11837. options = $.extend({}, defaultOptions, options);
  11838. this.callBase(options);
  11839. },
  11840. disable: function() {
  11841. this.callBase();
  11842. },
  11843. enable: function() {
  11844. this.callBase();
  11845. },
  11846. open: function() {
  11847. this.__popupWidget.appendWidget(this.__panelWidget);
  11848. this.__maskWidget.show();
  11849. this.__popupWidget.show();
  11850. var $popup = $(this.__popupWidget.getElement());
  11851. $popup.css("top", parseInt($popup.css("top")) - $(this.__element).outerHeight());
  11852. $popup.css("min-width", $(this.__element).outerWidth());
  11853. $popup.css("min-height", $(this.__element).height());
  11854. },
  11855. close: function() {
  11856. this.__maskWidget.hide();
  11857. this.__popupWidget.hide();
  11858. this.__panelWidget.appendTo(this.__contentElement);
  11859. },
  11860. getPanelElement: function() {
  11861. return this.__panelWidget.getElement();
  11862. },
  11863. appendWidget: function(widget) {
  11864. this.__panelWidget.appendWidget(widget);
  11865. },
  11866. getWidgets: function() {
  11867. return this.__panelWidget.getWidgets();
  11868. },
  11869. getWidget: function(index) {
  11870. return this.__panelWidget.getWidget(index);
  11871. },
  11872. appendWidgets: function(widgets) {
  11873. this.__panelWidget.appendWidgets.apply(this, arguments);
  11874. return this;
  11875. },
  11876. insertWidget: function(index, widget) {
  11877. this.__panelWidget.insertWidget(index, widget);
  11878. },
  11879. insertWidgets: function(index, widgets) {
  11880. this.__panelWidget.insertWidgets.apply(this, arguments);
  11881. return this;
  11882. },
  11883. removeWidget: function(widget) {
  11884. return this.__panelWidget.removeWidget(widget);
  11885. },
  11886. __render: function() {
  11887. this.__initOptions();
  11888. this.__buttonWidget = new Button(this.__options.button);
  11889. this.__panelWidget = new Panel(this.__options.content);
  11890. this.__popupWidget = new PPanel();
  11891. this.__maskWidget = new Mask(this.__options.mask);
  11892. this.callBase();
  11893. this.__popupWidget.positionTo(this.__element);
  11894. $(this.__popupWidget.getElement()).addClass(CONF.classPrefix + "drop-panel-popup");
  11895. // 初始化content
  11896. var $content = $('<div class="' + CONF.classPrefix + 'drop-panel-content"></div>').append(this.__panelWidget.getElement());
  11897. this.__contentElement = $content[0];
  11898. // 插入按钮到element
  11899. $(this.__element).append($content).append(this.__buttonWidget.getElement());
  11900. this.__initDropPanelEvent();
  11901. },
  11902. __initOptions: function() {
  11903. this.widgetName = "DropPanel";
  11904. this.__tpl = tpl;
  11905. this.__buttonWidget = null;
  11906. this.__popupWidget = null;
  11907. this.__panelWidget = null;
  11908. this.__contentElement = null;
  11909. this.__maskWidget = null;
  11910. this.__popupState = false;
  11911. if (typeof this.__options.button !== "object") {
  11912. this.__options.input = {
  11913. icon: this.__options.button
  11914. };
  11915. }
  11916. },
  11917. __initDropPanelEvent: function() {
  11918. var _self = this;
  11919. this.__buttonWidget.on("click", function() {
  11920. if (!_self.__popupState) {
  11921. _self.__appendPopup();
  11922. _self.__popupState = true;
  11923. }
  11924. _self.trigger("buttonclick");
  11925. _self.open();
  11926. });
  11927. this.__panelWidget.on("click", function() {
  11928. _self.trigger("panelclick");
  11929. });
  11930. // mask 点击关闭
  11931. this.__maskWidget.on("maskclick", function() {
  11932. _self.close();
  11933. });
  11934. },
  11935. __appendPopup: function() {
  11936. this.__popupWidget.appendTo(this.__element.ownerDocument.body);
  11937. }
  11938. });
  11939. }
  11940. };
  11941. //src/widget/icon.js
  11942. /**
  11943. * icon widget
  11944. * 封装多种icon方式
  11945. */
  11946. _p[42] = {
  11947. value: function(require) {
  11948. var $ = _p.r(4), iconTpl = _p.r(23);
  11949. return _p.r(13).createClass("Icon", {
  11950. base: _p.r(60),
  11951. constructor: function(options) {
  11952. var defaultOptions = {
  11953. img: null
  11954. };
  11955. options = $.extend({}, defaultOptions, options);
  11956. this.callBase(options);
  11957. },
  11958. getValue: function() {
  11959. return this.__options.value || this.__options.img;
  11960. },
  11961. setImage: function(imageSrc) {
  11962. if (this.__options.img === imageSrc) {
  11963. return this;
  11964. }
  11965. if (this.__image) {
  11966. this.__image.src = imageSrc;
  11967. }
  11968. this.trigger("iconchange", {
  11969. prevImage: this.__prevIcon,
  11970. currentImage: this.__currentIcon
  11971. });
  11972. },
  11973. getImage: function() {
  11974. return this.__currentIcon;
  11975. },
  11976. __initOptions: function() {
  11977. this.callBase();
  11978. this.widgetName = "Icon";
  11979. this.__tpl = iconTpl;
  11980. this.__prevIcon = null;
  11981. this.__currentIcon = this.__options.img;
  11982. this.__image = null;
  11983. },
  11984. __render: function() {
  11985. this.__options.__width = this.__options.width;
  11986. this.__options.__height = this.__options.height;
  11987. this.__options.width = null;
  11988. this.__options.height = null;
  11989. this.callBase();
  11990. if (!this.__options.img) {
  11991. return;
  11992. }
  11993. this.__image = $("img", this.__element)[0];
  11994. if (this.__options.__width !== null) {
  11995. this.__image.width = this.__options.__width;
  11996. }
  11997. if (this.__options.__height !== null) {
  11998. this.__image.height = this.__options.__height;
  11999. }
  12000. }
  12001. });
  12002. }
  12003. };
  12004. //src/widget/input-button.js
  12005. /**
  12006. * InputButton对象
  12007. * 可接受输入的按钮构件
  12008. */
  12009. _p[43] = {
  12010. value: function(require) {
  12011. var $ = _p.r(4), CONF = _p.r(12), tpl = _p.r(24), Button = _p.r(37), Input = _p.r(45);
  12012. return _p.r(13).createClass("InputButton", {
  12013. base: _p.r(60),
  12014. constructor: function(options) {
  12015. var defaultOptions = {
  12016. button: null,
  12017. input: null,
  12018. placeholder: null,
  12019. // label相对icon的位置
  12020. layout: "right"
  12021. };
  12022. options = $.extend({}, defaultOptions, options);
  12023. this.callBase(options);
  12024. },
  12025. getValue: function() {
  12026. return this.__inputWidget.getValue();
  12027. },
  12028. setValue: function(value) {
  12029. this.__inputWidget.setValue(value);
  12030. return this;
  12031. },
  12032. reset: function() {
  12033. this.__inputWidget.reset();
  12034. },
  12035. selectAll: function() {
  12036. this.__inputWidget.selectAll();
  12037. return this;
  12038. },
  12039. selectRange: function(start, end) {
  12040. this.__inputWidget.selectRange(start, end);
  12041. return this;
  12042. },
  12043. focus: function() {
  12044. this.__inputWidget.focus();
  12045. return this;
  12046. },
  12047. unfocus: function() {
  12048. this.__inputWidget.unfocus();
  12049. return this;
  12050. },
  12051. __initOptions: function() {
  12052. this.callBase();
  12053. this.widgetName = "InputButton";
  12054. this.__tpl = tpl;
  12055. this.__inputWidget = null;
  12056. this.__buttonWidget = null;
  12057. if (typeof this.__options.input !== "object") {
  12058. this.__options.input = {
  12059. placeholder: this.__options.input
  12060. };
  12061. }
  12062. this.__options.input = $.extend({}, this.__options.input, {
  12063. placeholder: this.__options.placeholder
  12064. });
  12065. if (typeof this.__options.button !== "object") {
  12066. this.__options.button = {
  12067. icon: this.__options.button
  12068. };
  12069. }
  12070. },
  12071. __render: function() {
  12072. var _self = this;
  12073. this.callBase();
  12074. this.__buttonWidget = new Button(this.__options.button);
  12075. this.__inputWidget = new Input(this.__options.input);
  12076. // layout
  12077. switch (this.__options.layout) {
  12078. case "left":
  12079. /* falls through */
  12080. case "top":
  12081. this.__buttonWidget.appendTo(this.__element);
  12082. this.__inputWidget.appendTo(this.__element);
  12083. break;
  12084. case "right":
  12085. /* falls through */
  12086. case "bottom":
  12087. /* falls through */
  12088. default:
  12089. this.__inputWidget.appendTo(this.__element);
  12090. this.__buttonWidget.appendTo(this.__element);
  12091. break;
  12092. }
  12093. $(this.__element).addClass(CONF.classPrefix + "layout-" + this.__options.layout);
  12094. this.__buttonWidget.on("click", function() {
  12095. _self.trigger("buttonclick");
  12096. });
  12097. }
  12098. });
  12099. }
  12100. };
  12101. //src/widget/input-menu.js
  12102. /**
  12103. * InputMenu构件
  12104. * 可接受输入的下拉菜单构件
  12105. */
  12106. _p[44] = {
  12107. value: function(require) {
  12108. var $ = _p.r(4), tpl = _p.r(25), InputButton = _p.r(43), Menu = _p.r(50), Mask = _p.r(49);
  12109. return _p.r(13).createClass("InputMenu", {
  12110. base: _p.r(60),
  12111. constructor: function(options) {
  12112. var defaultOptions = {
  12113. input: null,
  12114. menu: null,
  12115. mask: null,
  12116. selected: -1
  12117. };
  12118. options = $.extend({}, defaultOptions, options);
  12119. this.callBase(options);
  12120. },
  12121. select: function(index) {
  12122. this.__menuWidget.select(index);
  12123. },
  12124. selectByValue: function(value) {
  12125. return this.__selectBy("values", value);
  12126. },
  12127. selectByLabel: function(value) {
  12128. return this.__selectBy("labels", value);
  12129. },
  12130. clearSelect: function() {
  12131. this.__lastSelect = -1;
  12132. this.__menuWidget.clearSelect();
  12133. this.__inputWidget.reset();
  12134. return this;
  12135. },
  12136. setValue: function(value) {
  12137. return this;
  12138. },
  12139. getValue: function() {
  12140. return this.__menuWidget.getSelectedItem().getValue();
  12141. },
  12142. open: function() {
  12143. this.__maskWidget.show();
  12144. this.__menuWidget.show();
  12145. },
  12146. close: function() {
  12147. this.__maskWidget.hide();
  12148. this.__menuWidget.hide();
  12149. },
  12150. __render: function() {
  12151. this.__inputWidget = new InputButton(this.__options.input);
  12152. this.__menuWidget = new Menu(this.__options.menu);
  12153. this.__maskWidget = new Mask(this.__options.mask);
  12154. this.callBase();
  12155. this.__inputWidget.appendTo(this.__element);
  12156. this.__menuWidget.positionTo(this.__inputWidget);
  12157. this.__initInputValue();
  12158. },
  12159. __selectBy: function(type, value) {
  12160. var values = this.__getItemValues()[type], index = -1;
  12161. $.each(values, function(i, val) {
  12162. if (value === val) {
  12163. index = i;
  12164. return false;
  12165. }
  12166. });
  12167. if (index !== -1) {
  12168. this.select(index);
  12169. return this.__menuWidget.getSelectedItem();
  12170. }
  12171. return null;
  12172. },
  12173. __initInputValue: function() {
  12174. var selectedItem = this.__menuWidget.getItem(this.__options.selected);
  12175. if (selectedItem) {
  12176. this.__inputWidget.setValue(selectedItem.getLabel());
  12177. }
  12178. },
  12179. __initEvent: function() {
  12180. var _self = this;
  12181. this.callBase();
  12182. this.on("buttonclick", function() {
  12183. if (!this.__menuState) {
  12184. this.__appendMenu();
  12185. this.__menuState = true;
  12186. }
  12187. this.__inputWidget.unfocus();
  12188. this.open();
  12189. });
  12190. this.on("keypress", function(e) {
  12191. this.__lastTime = new Date();
  12192. });
  12193. this.on("keyup", function(e) {
  12194. if (e.keyCode !== 8 && e.keyCode !== 13 && new Date() - this.__lastTime < 500) {
  12195. this.__update();
  12196. }
  12197. });
  12198. this.on("inputcomplete", function() {
  12199. this.__inputWidget.selectRange(99999999);
  12200. this.__inputComplete();
  12201. });
  12202. this.__menuWidget.on("select", function(e, info) {
  12203. e.stopPropagation();
  12204. _self.__inputWidget.setValue(info.label);
  12205. _self.trigger("select", info);
  12206. _self.close();
  12207. });
  12208. this.__menuWidget.on("menuitemclick", function(e, info) {
  12209. _self.trigger("itemclick", info);
  12210. });
  12211. this.__menuWidget.on("change", function(e, info) {
  12212. e.stopPropagation();
  12213. _self.trigger("change", info);
  12214. });
  12215. // 阻止input自身的select和change事件
  12216. this.__inputWidget.on("select change", function(e) {
  12217. e.stopPropagation();
  12218. });
  12219. // mask 点击关闭
  12220. this.__maskWidget.on("maskclick", function() {
  12221. _self.close();
  12222. });
  12223. // 记录最后选中的数据
  12224. this.on("select", function(e, info) {
  12225. this.__lastSelect = info;
  12226. });
  12227. },
  12228. // 更新输入框内容
  12229. __update: function() {
  12230. var inputValue = this.__inputWidget.getValue(), lowerCaseValue = inputValue.toLowerCase(), values = this.__getItemValues().labels, targetValue = null;
  12231. if (!inputValue) {
  12232. return;
  12233. }
  12234. $.each(values, function(i, val) {
  12235. if (val.toLowerCase().indexOf(lowerCaseValue) === 0) {
  12236. targetValue = val;
  12237. return false;
  12238. }
  12239. });
  12240. if (targetValue) {
  12241. this.__inputWidget.setValue(targetValue);
  12242. this.__inputWidget.selectRange(inputValue.length);
  12243. }
  12244. },
  12245. // 获取所有item的值列表
  12246. __getItemValues: function() {
  12247. var vals = [], labels = [];
  12248. $.each(this.__menuWidget.getWidgets(), function(index, item) {
  12249. labels.push(item.getLabel());
  12250. vals.push(item.getValue());
  12251. });
  12252. return {
  12253. labels: labels,
  12254. values: vals
  12255. };
  12256. },
  12257. // 用户输入完成
  12258. __inputComplete: function() {
  12259. var itemsInfo = this.__getItemValues(), labels = itemsInfo.labels, targetIndex = -1, inputValue = this.__inputWidget.getValue(), lastSelect = this.__lastSelect;
  12260. $.each(labels, function(i, label) {
  12261. if (label === inputValue) {
  12262. targetIndex = i;
  12263. return false;
  12264. }
  12265. });
  12266. this.trigger("select", {
  12267. index: targetIndex,
  12268. label: inputValue,
  12269. value: itemsInfo.values[targetIndex]
  12270. });
  12271. if (!lastSelect || lastSelect.value !== inputValue) {
  12272. this.trigger("change", {
  12273. from: lastSelect || {
  12274. index: -1,
  12275. label: null,
  12276. value: null
  12277. },
  12278. to: {
  12279. index: targetIndex,
  12280. label: inputValue,
  12281. value: itemsInfo.values[targetIndex]
  12282. }
  12283. });
  12284. }
  12285. },
  12286. __appendMenu: function() {
  12287. this.__menuWidget.appendTo(this.__inputWidget.getElement().ownerDocument.body);
  12288. },
  12289. __initOptions: function() {
  12290. this.callBase();
  12291. this.widgetName = "InputMenu";
  12292. this.__tpl = tpl;
  12293. // 最后输入时间
  12294. this.__lastTime = 0;
  12295. // 最后选中的记录
  12296. this.__lastSelect = null;
  12297. this.__inputWidget = null;
  12298. this.__menuWidget = null;
  12299. this.__maskWidget = null;
  12300. // menu状态, 记录是否已经append到dom树上
  12301. this.__menuState = false;
  12302. if (this.__options.selected !== -1) {
  12303. this.__options.menu.selected = this.__options.selected;
  12304. }
  12305. }
  12306. });
  12307. }
  12308. };
  12309. //src/widget/input.js
  12310. /*jshint camelcase:false*/
  12311. /**
  12312. * Input widget
  12313. */
  12314. _p[45] = {
  12315. value: function(require) {
  12316. var CONF = _p.r(12), $ = _p.r(4), tpl = _p.r(26);
  12317. return _p.r(13).createClass("Input", {
  12318. base: _p.r(60),
  12319. constructor: function(options) {
  12320. var defaultOptions = {
  12321. placeholder: null
  12322. };
  12323. options = $.extend({}, defaultOptions, options);
  12324. this.callBase(options);
  12325. },
  12326. getValue: function() {
  12327. return this.__element.value;
  12328. },
  12329. setValue: function(value) {
  12330. this.__element.value = value;
  12331. return this;
  12332. },
  12333. disable: function() {
  12334. this.callBase();
  12335. this.__element.disabled = true;
  12336. },
  12337. enable: function() {
  12338. this.__element.disabled = false;
  12339. this.callBase();
  12340. },
  12341. reset: function() {
  12342. this.__element.value = this.__options.value || "";
  12343. return this;
  12344. },
  12345. selectAll: function() {
  12346. this.__element.select();
  12347. },
  12348. selectRange: function(startIndex, endIndex) {
  12349. if (!startIndex) {
  12350. startIndex = 0;
  12351. }
  12352. if (!endIndex) {
  12353. endIndex = 1e9;
  12354. }
  12355. this.__element.setSelectionRange(startIndex, endIndex);
  12356. },
  12357. focus: function() {
  12358. this.__element.focus();
  12359. return this;
  12360. },
  12361. unfocus: function() {
  12362. this.__element.blur();
  12363. return this;
  12364. },
  12365. __initOptions: function() {
  12366. this.callBase();
  12367. this.widgetName = "Input";
  12368. this.__tpl = tpl;
  12369. // input构件允许获得焦点
  12370. this.__allow_focus = true;
  12371. },
  12372. __render: function() {
  12373. this.callBase();
  12374. this.__element.removeAttribute("unselectable");
  12375. if (this.__options.placeholder) {
  12376. this.__element.setAttribute("placeholder", this.__options.placeholder);
  12377. }
  12378. this.addClass(CONF.classPrefix + "selectable");
  12379. },
  12380. __initEvent: function() {
  12381. this.callBase();
  12382. this.on("keydown", function(e) {
  12383. if (e.keyCode === 13) {
  12384. this.trigger("inputcomplete", {
  12385. value: this.getValue()
  12386. });
  12387. }
  12388. });
  12389. }
  12390. });
  12391. }
  12392. };
  12393. //src/widget/item.js
  12394. /**
  12395. * Label Widget
  12396. */
  12397. _p[46] = {
  12398. value: function(require) {
  12399. var Utils = _p.r(13), itemTpl = _p.r(27), Icon = _p.r(42), Label = _p.r(48), CONF = _p.r(12), $ = _p.r(4);
  12400. return Utils.createClass("Item", {
  12401. base: _p.r(60),
  12402. constructor: function(options) {
  12403. var defaultOptions = {
  12404. label: "",
  12405. icon: null,
  12406. selected: false,
  12407. textAlign: "left"
  12408. };
  12409. options = $.extend({}, defaultOptions, options);
  12410. this.callBase(options);
  12411. },
  12412. getValue: function() {
  12413. return this.__options.value || this.__labelWidget.getValue() || this.__iconWidget.getValue() || null;
  12414. },
  12415. select: function() {
  12416. this.__update(true);
  12417. return this;
  12418. },
  12419. unselect: function() {
  12420. this.__update(false);
  12421. return this;
  12422. },
  12423. isSelected: function() {
  12424. return this.__selectState;
  12425. },
  12426. setLabel: function(text) {
  12427. this.__labelWidget.setText(text);
  12428. return this;
  12429. },
  12430. getLabel: function() {
  12431. return this.__labelWidget.getText();
  12432. },
  12433. setIcon: function(imageSrc) {
  12434. this.__iconWidget.setImage(imageSrc);
  12435. return this;
  12436. },
  12437. getIcon: function() {
  12438. return this.__iconWidget.getImage();
  12439. },
  12440. __render: function() {
  12441. this.callBase();
  12442. this.__iconWidget = new Icon(this.__options.icon);
  12443. this.__labelWidget = new Label(this.__options.label);
  12444. this.__iconWidget.appendTo(this.__element);
  12445. this.__labelWidget.appendTo(this.__element);
  12446. },
  12447. __update: function(state) {
  12448. var fn = state ? "addClass" : "removeClass";
  12449. state = !!state;
  12450. $(this.__element)[fn](CONF.classPrefix + "item-selected");
  12451. this.__selectState = state;
  12452. this.trigger(state ? "itemselect" : "itemunselect");
  12453. return this;
  12454. },
  12455. __initEvent: function() {
  12456. this.callBase();
  12457. this.on("click", function() {
  12458. this.trigger("itemclick");
  12459. });
  12460. },
  12461. /**
  12462. * 初始化模板所用的css值
  12463. * @private
  12464. */
  12465. __initOptions: function() {
  12466. this.callBase();
  12467. this.widgetName = "Item";
  12468. this.__tpl = itemTpl;
  12469. this.__iconWidget = null;
  12470. this.__labelWidget = null;
  12471. this.__selectState = this.__options.selected;
  12472. if (typeof this.__options.label !== "object") {
  12473. this.__options.label = {
  12474. text: this.__options.label
  12475. };
  12476. }
  12477. if (!this.__options.label.textAlign) {
  12478. this.__options.label.textAlign = this.__options.textAlign;
  12479. }
  12480. if (typeof this.__options.icon !== "object") {
  12481. this.__options.icon = {
  12482. img: this.__options.icon
  12483. };
  12484. }
  12485. }
  12486. });
  12487. }
  12488. };
  12489. //src/widget/label-panel.js
  12490. /**
  12491. * LabelPanel Widget
  12492. * 带标签的面板
  12493. */
  12494. _p[47] = {
  12495. value: function(require) {
  12496. var Utils = _p.r(13), CONF = _p.r(12), Label = _p.r(48), $ = _p.r(4);
  12497. return Utils.createClass("LabelPanel", {
  12498. base: _p.r(51),
  12499. constructor: function(options) {
  12500. var defaultOptions = {
  12501. layout: "bottom"
  12502. };
  12503. options = $.extend({}, defaultOptions, options);
  12504. this.callBase(options);
  12505. },
  12506. disable: function() {
  12507. this.callBase();
  12508. this.__labelWidget.disable();
  12509. },
  12510. enable: function() {
  12511. this.callBase();
  12512. this.__labelWidget.enable();
  12513. },
  12514. __render: function() {
  12515. var $contentElement = null, opts = this.__options, ele = this.__element, classPrefix = CONF.classPrefix, labelClass = "fui-label-panel-content", originEle = null;
  12516. this.__labelWidget = new Label(opts.label);
  12517. this.callBase();
  12518. originEle = this.__contentElement;
  12519. $(ele).addClass(classPrefix + "label-panel");
  12520. $(ele).addClass(classPrefix + "layout-" + opts.layout);
  12521. $contentElement = $('<div class="' + labelClass + '"></div>');
  12522. originEle.appendChild(this.__labelWidget.getElement());
  12523. originEle.appendChild($contentElement[0]);
  12524. // 更新contentElement
  12525. this.__contentElement = $contentElement[0];
  12526. return this;
  12527. },
  12528. __initOptions: function() {
  12529. var label = this.__options.label;
  12530. this.callBase();
  12531. this.widgetName = "LabelPanel";
  12532. this.__labelWidget = null;
  12533. if (typeof label !== "object") {
  12534. this.__options.label = {
  12535. text: label
  12536. };
  12537. }
  12538. if (!this.__options.label.className) {
  12539. this.__options.label.className = "";
  12540. }
  12541. this.__options.label.className += " fui-label-panel-label";
  12542. }
  12543. });
  12544. }
  12545. };
  12546. //src/widget/label.js
  12547. /**
  12548. * Label Widget
  12549. */
  12550. _p[48] = {
  12551. value: function(require) {
  12552. var Utils = _p.r(13), labelTpl = _p.r(28), $ = _p.r(4);
  12553. return Utils.createClass("Label", {
  12554. base: _p.r(60),
  12555. constructor: function(options) {
  12556. var defaultOptions = {
  12557. text: "",
  12558. textAlign: "center"
  12559. };
  12560. options = $.extend({}, defaultOptions, options);
  12561. this.callBase(options);
  12562. },
  12563. getValue: function() {
  12564. return this.__options.text;
  12565. },
  12566. setText: function(text) {
  12567. var oldtext = this.__options.text;
  12568. this.__options.text = text;
  12569. $(this.__element).text(text);
  12570. this.trigger("labelchange", {
  12571. currentText: text,
  12572. prevText: oldtext
  12573. });
  12574. return this;
  12575. },
  12576. getText: function() {
  12577. return this.__options.text;
  12578. },
  12579. // label 禁用title显示
  12580. __allowShowTitle: function() {
  12581. return false;
  12582. },
  12583. /**
  12584. * 初始化模板所用的css值
  12585. * @private
  12586. */
  12587. __initOptions: function() {
  12588. this.callBase();
  12589. this.widgetName = "Label";
  12590. this.__tpl = labelTpl;
  12591. this.__options.text = this.__options.text.toString();
  12592. }
  12593. });
  12594. }
  12595. };
  12596. //src/widget/mask.js
  12597. /*jshint camelcase:false*/
  12598. /**
  12599. * Mask Widget
  12600. */
  12601. _p[49] = {
  12602. value: function(require) {
  12603. var Utils = _p.r(13), tpl = _p.r(29), Widget = _p.r(60), $ = _p.r(4), __cache_inited = false, __MASK_CACHE = [];
  12604. return Utils.createClass("Mask", {
  12605. base: _p.r(60),
  12606. constructor: function(options) {
  12607. var defaultOptions = {
  12608. bgcolor: "#000",
  12609. opacity: 0,
  12610. inner: true,
  12611. target: null,
  12612. // 禁止mouse scroll事件
  12613. scroll: false,
  12614. hide: true
  12615. };
  12616. options = $.extend({}, defaultOptions, options);
  12617. this.callBase(options);
  12618. },
  12619. maskTo: function(target) {
  12620. if (target) {
  12621. this.__target = target;
  12622. }
  12623. return this;
  12624. },
  12625. show: function() {
  12626. var docNode = null;
  12627. if (!this.__target) {
  12628. this.__target = this.__element.ownerDocument.body;
  12629. }
  12630. docNode = this.__target.ownerDocument.documentElement;
  12631. // 如果节点未添加到dom树, 则自动添加到文档的body节点上
  12632. if (!$.contains(docNode, this.__element)) {
  12633. this.appendTo(this.__target.ownerDocument.body);
  12634. }
  12635. this.callBase();
  12636. this.__position();
  12637. this.__resize();
  12638. this.__hideState = false;
  12639. },
  12640. hide: function() {
  12641. this.callBase();
  12642. this.__hideState = true;
  12643. },
  12644. isHide: function() {
  12645. return this.__hideState;
  12646. },
  12647. __initOptions: function() {
  12648. this.callBase();
  12649. this.widgetName = "Mask";
  12650. this.__tpl = tpl;
  12651. this.__cacheId = __MASK_CACHE.length;
  12652. this.__hideState = true;
  12653. __MASK_CACHE.push(this);
  12654. this.__target = this.__options.target;
  12655. if (this.__target instanceof Widget) {
  12656. this.__target = this.__target.getElement();
  12657. }
  12658. },
  12659. __render: function() {
  12660. this.callBase();
  12661. this.__initMaskEvent();
  12662. if (!__cache_inited) {
  12663. __cache_inited = true;
  12664. __initCacheEvent();
  12665. }
  12666. },
  12667. __initMaskEvent: function() {
  12668. this.on("mousewheel", function(e) {
  12669. var evt = e.originalEvent;
  12670. e.preventDefault();
  12671. e.stopPropagation();
  12672. this.trigger("scroll", {
  12673. delta: evt.wheelDelta || evt.deltaY || evt.detail
  12674. });
  12675. });
  12676. this.on("click", function(e) {
  12677. e.stopPropagation();
  12678. if (e.target === this.__element) {
  12679. this.trigger("maskclick");
  12680. }
  12681. });
  12682. },
  12683. // 定位
  12684. __resize: function() {
  12685. var targetRect = null;
  12686. // body特殊处理
  12687. if (this.__targetIsBody()) {
  12688. targetRect = $(Utils.getView(this.__target));
  12689. targetRect = {
  12690. width: targetRect.width(),
  12691. height: targetRect.height()
  12692. };
  12693. } else {
  12694. targetRect = Utils.getRect(this.__target);
  12695. }
  12696. this.__element.style.width = targetRect.width + "px";
  12697. this.__element.style.height = targetRect.height + "px";
  12698. },
  12699. __position: function() {
  12700. var location = null, targetRect = null;
  12701. if (this.__targetIsBody()) {
  12702. location = {
  12703. top: 0,
  12704. left: 0
  12705. };
  12706. } else {
  12707. targetRect = Utils.getRect(this.__target);
  12708. location = {
  12709. top: targetRect.top,
  12710. left: targetRect.left
  12711. };
  12712. }
  12713. $(this.__element).css("top", location.top + "px").css("left", location.left + "px");
  12714. },
  12715. __targetIsBody: function() {
  12716. return this.__target.tagName.toLowerCase() === "body";
  12717. }
  12718. });
  12719. // 全局监听
  12720. function __initCacheEvent() {
  12721. $(window).on("resize", function() {
  12722. $.each(__MASK_CACHE, function(i, mask) {
  12723. if (mask && !mask.isHide()) {
  12724. mask.__resize();
  12725. }
  12726. });
  12727. });
  12728. }
  12729. }
  12730. };
  12731. //src/widget/menu.js
  12732. /**
  12733. * Menu Widget
  12734. */
  12735. _p[50] = {
  12736. value: function(require) {
  12737. var Utils = _p.r(13), Item = _p.r(46), CONF = _p.r(12), $ = _p.r(4);
  12738. return Utils.createClass("Menu", {
  12739. base: _p.r(54),
  12740. constructor: function(options) {
  12741. var defaultOptions = {
  12742. column: true,
  12743. selected: -1,
  12744. textAlign: "left",
  12745. items: []
  12746. };
  12747. options = $.extend({}, defaultOptions, options);
  12748. this.callBase(options);
  12749. },
  12750. select: function(index) {
  12751. var item = this.__widgets[index];
  12752. if (!item) {
  12753. return this;
  12754. }
  12755. this.__selectItem(item);
  12756. return this;
  12757. },
  12758. clearSelect: function() {
  12759. var selectedItem = this.getSelectedItem();
  12760. if (selectedItem) {
  12761. selectedItem.unselect();
  12762. }
  12763. this.__currentSelect = -1;
  12764. this.__prevSelect = -1;
  12765. },
  12766. getItems: function() {
  12767. return this.getWidgets.apply(this, arguments);
  12768. },
  12769. getItem: function() {
  12770. return this.getWidget.apply(this, arguments);
  12771. },
  12772. appendItem: function(item) {
  12773. return this.appendWidget.apply(this, arguments);
  12774. },
  12775. insertItem: function(item) {
  12776. return this.insertWidget.apply(this, arguments);
  12777. },
  12778. removeItem: function(item) {
  12779. return this.removeWidget.apply(this, arguments);
  12780. },
  12781. clearItems: function() {
  12782. while (this.getItems().length) {
  12783. this.removeItem(0);
  12784. }
  12785. return this;
  12786. },
  12787. getSelected: function() {
  12788. return this.__currentSelect;
  12789. },
  12790. getSelectedItem: function() {
  12791. return this.getItem(this.__currentSelect);
  12792. },
  12793. insertWidget: function(index, widget) {
  12794. var returnValue = this.callBase(index, widget);
  12795. if (returnValue === null) {
  12796. return returnValue;
  12797. }
  12798. if (index <= this.__currentSelect) {
  12799. this.__currentSelect++;
  12800. }
  12801. if (index <= this.__prevSelect) {
  12802. this.__prevSelect++;
  12803. }
  12804. return returnValue;
  12805. },
  12806. removeWidget: function(widget) {
  12807. var index = widget;
  12808. if (typeof index !== "number") {
  12809. index = this.indexOf(widget);
  12810. }
  12811. widget = this.callBase(widget);
  12812. if (index === this.__currentSelect) {
  12813. this.__currentSelect = -1;
  12814. } else if (index < this.__currentSelect) {
  12815. this.__currentSelect--;
  12816. }
  12817. if (index === this.__prevSelect) {
  12818. this.__prevSelect = -1;
  12819. } else if (index < this.__prevSelect) {
  12820. this.__prevSelect--;
  12821. }
  12822. return widget;
  12823. },
  12824. __initOptions: function() {
  12825. this.callBase();
  12826. this.__prevSelect = -1;
  12827. this.__currentSelect = this.__options.selected;
  12828. this.widgetName = "Menu";
  12829. },
  12830. __render: function() {
  12831. var _self = this, textAlign = this.__options.textAlign, selected = this.__options.selected;
  12832. this.callBase();
  12833. $(this.__element).addClass(CONF.classPrefix + "menu");
  12834. $.each(this.__options.items, function(index, itemOption) {
  12835. if (typeof itemOption !== "object") {
  12836. itemOption = {
  12837. label: itemOption
  12838. };
  12839. }
  12840. itemOption.selected = index === selected;
  12841. itemOption.textAlign = textAlign;
  12842. _self.appendItem(new Item(itemOption));
  12843. });
  12844. },
  12845. // 初始化点击事件
  12846. __initEvent: function() {
  12847. this.callBase();
  12848. this.on("itemclick", function(e) {
  12849. this.__selectItem(e.widget, true);
  12850. });
  12851. },
  12852. __selectItem: function(item, isUserTrigger) {
  12853. var info = null;
  12854. if (this.__currentSelect > -1) {
  12855. this.__widgets[this.__currentSelect].unselect();
  12856. }
  12857. this.__prevSelect = this.__currentSelect;
  12858. this.__currentSelect = this.indexOf(item);
  12859. item.select();
  12860. info = {
  12861. index: this.__currentSelect,
  12862. label: item.getLabel(),
  12863. value: item.getValue()
  12864. };
  12865. if (isUserTrigger) {
  12866. this.trigger("menuitemclick", info);
  12867. }
  12868. this.trigger("select", info);
  12869. if (this.__prevSelect !== this.__currentSelect) {
  12870. var fromItem = this.__widgets[this.__prevSelect] || null;
  12871. this.trigger("change", {
  12872. from: {
  12873. index: this.__prevSelect,
  12874. label: fromItem && fromItem.getLabel(),
  12875. value: fromItem && fromItem.getValue()
  12876. },
  12877. to: {
  12878. index: this.__currentSelect,
  12879. label: item.getLabel(),
  12880. value: item.getValue()
  12881. }
  12882. });
  12883. }
  12884. },
  12885. __valid: function(target) {
  12886. return target instanceof Item;
  12887. }
  12888. });
  12889. }
  12890. };
  12891. //src/widget/panel.js
  12892. /**
  12893. * 容器类: Panel
  12894. */
  12895. _p[51] = {
  12896. value: function(require) {
  12897. var Utils = _p.r(13), panelTpl = _p.r(30), $ = _p.r(4);
  12898. return Utils.createClass("Panel", {
  12899. base: _p.r(39),
  12900. constructor: function(options) {
  12901. var defaultOptions = {};
  12902. options = $.extend({}, defaultOptions, options);
  12903. this.callBase(options);
  12904. },
  12905. __render: function() {
  12906. var $content = null;
  12907. this.callBase();
  12908. $content = $('<div class="fui-panel-content"></div>');
  12909. this.__contentElement.appendChild($content[0]);
  12910. this.__contentElement = $content[0];
  12911. },
  12912. __initOptions: function() {
  12913. this.callBase();
  12914. this.widgetName = "Panel";
  12915. this.__tpl = panelTpl;
  12916. }
  12917. });
  12918. }
  12919. };
  12920. //src/widget/popup-menu.js
  12921. _p[52] = {
  12922. value: function(require) {
  12923. var Utils = _p.r(13), CONF = _p.r(12), $ = _p.r(4), Menu = _p.r(50);
  12924. return Utils.createClass("PopupMenu", {
  12925. base: _p.r(53),
  12926. constructor: function(options) {
  12927. this.callBase($.extend({
  12928. menu: {}
  12929. }, options));
  12930. },
  12931. getMenuWidget: function() {
  12932. return this.__menuWidget;
  12933. },
  12934. __initOptions: function() {
  12935. this.callBase();
  12936. this.widgetName = "PopupMenu";
  12937. },
  12938. __render: function() {
  12939. this.callBase();
  12940. this.__menuWidget = new Menu();
  12941. this.appendWidget(this.__menuWidget);
  12942. $(this.__element).addClass(CONF.classPrefix + "popup-menu");
  12943. }
  12944. });
  12945. }
  12946. };
  12947. //src/widget/popup.js
  12948. /**
  12949. * 容器类: PPanel = Positioning Panel
  12950. */
  12951. _p[53] = {
  12952. value: function(require) {
  12953. var Utils = _p.r(13), CONF = _p.r(12), Widget = _p.r(60), Mask = _p.r(49), $ = _p.r(4);
  12954. return Utils.createClass("Popup", {
  12955. base: _p.r(54),
  12956. constructor: function(options) {
  12957. var defaultOptions = {
  12958. mask: {}
  12959. };
  12960. options = $.extend({}, defaultOptions, options);
  12961. this.callBase(options);
  12962. },
  12963. open: function() {
  12964. this.__fire("open", function() {
  12965. this.show();
  12966. });
  12967. return this;
  12968. },
  12969. close: function() {
  12970. this.__fire("close", function() {
  12971. this.hide();
  12972. });
  12973. return this;
  12974. },
  12975. show: function() {
  12976. if (!this.__target) {
  12977. this.__target = this.__element.ownerDocument.body;
  12978. }
  12979. if (!this.__inDoc) {
  12980. this.__inDoc = true;
  12981. this.appendTo(this.__element.ownerDocument.body);
  12982. }
  12983. this.__maskWidget.show();
  12984. this.callBase();
  12985. this.__openState = true;
  12986. return this;
  12987. },
  12988. hide: function() {
  12989. this.callBase();
  12990. this.__maskWidget.hide();
  12991. this.__openState = false;
  12992. return this;
  12993. },
  12994. toggle: function() {
  12995. this.isOpen() ? this.close() : this.open();
  12996. return this;
  12997. },
  12998. isOpen: function() {
  12999. return this.__openState;
  13000. },
  13001. __initOptions: function() {
  13002. this.callBase();
  13003. this.widgetName = "Popup";
  13004. this.__target = this.__options.target;
  13005. this.__layout = this.__options.layout;
  13006. this.__inDoc = false;
  13007. this.__openState = false;
  13008. this.__maskWidget = null;
  13009. if (this.__target instanceof Widget) {
  13010. this.__target = this.__target.getElement();
  13011. }
  13012. },
  13013. __render: function() {
  13014. this.callBase();
  13015. $(this.__element).addClass(CONF.classPrefix + "popup");
  13016. this.__maskWidget = new Mask(this.__options.mask);
  13017. if (this.__options.draggable) {
  13018. this.__initDraggable();
  13019. }
  13020. this.__initMaskEvent();
  13021. },
  13022. __initMaskEvent: function() {
  13023. var _self = this;
  13024. this.__maskWidget.on("click", function() {
  13025. _self.close();
  13026. });
  13027. }
  13028. });
  13029. }
  13030. };
  13031. //src/widget/ppanel.js
  13032. /*jshint camelcase:false*/
  13033. /**
  13034. * 容器类: PPanel = Positioning Panel
  13035. */
  13036. _p[54] = {
  13037. value: function(require) {
  13038. var Utils = _p.r(13), CONF = _p.r(12), Widget = _p.r(60), LAYOUT = CONF.layout, $ = _p.r(4);
  13039. return Utils.createClass("PPanel", {
  13040. base: _p.r(51),
  13041. constructor: function(options) {
  13042. var defaultOptions = {
  13043. layout: LAYOUT.BOTTOM,
  13044. target: null,
  13045. // 边界容器
  13046. bound: null,
  13047. // 和边界之间的最小距离
  13048. diff: 10,
  13049. hide: true,
  13050. resize: "all",
  13051. iframe: false
  13052. };
  13053. options = $.extend({}, defaultOptions, options);
  13054. this.callBase(options);
  13055. },
  13056. positionTo: function(target, layout) {
  13057. if (target instanceof Widget) {
  13058. target = target.getElement();
  13059. }
  13060. this.__target = target;
  13061. if (layout) {
  13062. this.__layout = layout;
  13063. }
  13064. return this;
  13065. },
  13066. show: function() {
  13067. var docNode = null;
  13068. if (!this.__target) {
  13069. return this.callBase();
  13070. }
  13071. if (!this.__options.bound) {
  13072. this.__options.bound = this.__target.ownerDocument.body;
  13073. }
  13074. docNode = this.__target.ownerDocument.documentElement;
  13075. if (!$.contains(docNode, this.__element)) {
  13076. this.__target.ownerDocument.body.appendChild(this.__element);
  13077. }
  13078. if ($.contains(docNode, this.__target)) {
  13079. this.callBase(Utils.getMarker());
  13080. this.__position();
  13081. this.__resize();
  13082. }
  13083. return this;
  13084. },
  13085. __initOptions: function() {
  13086. this.callBase();
  13087. this.widgetName = "PPanel";
  13088. this.__target = this.__options.target;
  13089. this.__layout = this.__options.layout;
  13090. // 记录是否已调整过高度
  13091. this.__height_resized = false;
  13092. },
  13093. __render: function() {
  13094. this.callBase();
  13095. if (this.__options.iframe) {
  13096. $('<iframe class="fui-ppanel-cover" frameborder="0"></iframe>').appendTo(this.__element);
  13097. }
  13098. $(this.__element).addClass(CONF.classPrefix + "ppanel");
  13099. },
  13100. // 执行定位
  13101. __position: function() {
  13102. var location = null, className = CONF.classPrefix + "ppanel-position";
  13103. $(this.__element).addClass(className);
  13104. location = this.__getLocation();
  13105. $(this.__element).css("top", location.top + "px").css("left", location.left + "px");
  13106. },
  13107. __resize: function() {
  13108. var targetRect = Utils.getBound(this.__target);
  13109. switch (this.__options.resize) {
  13110. case "all":
  13111. this.__resizeWidth(targetRect);
  13112. this.__resizeHeight();
  13113. break;
  13114. case "width":
  13115. this.__resizeWidth(targetRect);
  13116. break;
  13117. case "height":
  13118. this.__resizeHeight();
  13119. break;
  13120. }
  13121. },
  13122. /**
  13123. * 在未指定宽度的情况下,执行自动宽度适配。
  13124. * 如果构件未被指定宽度, 则添加一个最小宽度, 该最小宽度等于给定目标的宽度
  13125. * @param targetRect 传递该参数,是出于整体性能上的考虑。
  13126. * @private
  13127. */
  13128. __resizeWidth: function(targetRect) {
  13129. if (!this.__target) {
  13130. return;
  13131. }
  13132. var $ele = $(this.__element), w = $ele.outerWidth(), h = $ele.outerHeight(), minWidth = targetRect.width - w - h;
  13133. this.__element.style.minWidth = minWidth + "px";
  13134. },
  13135. /**
  13136. * 调整panel高度,使其不超过边界范围,如果已设置高度, 则不进行调整
  13137. * @private
  13138. */
  13139. __resizeHeight: function() {
  13140. var boundRect = null, panelRect = null, diff = 0;
  13141. panelRect = Utils.getRect(this.__element);
  13142. panelRect.height = this.__element.scrollHeight;
  13143. panelRect.bottom = panelRect.top + panelRect.height;
  13144. boundRect = this.__getBoundRect();
  13145. diff = panelRect.bottom - boundRect.bottom;
  13146. if (diff > 0) {
  13147. this.__height_resized = true;
  13148. diff = panelRect.height - diff - this.__options.diff;
  13149. $(this.__element).css("height", diff + "px");
  13150. } else if (this.__height_resized) {
  13151. this.__element.style.height = null;
  13152. }
  13153. },
  13154. __getLocation: function() {
  13155. var targetRect = Utils.getBound(this.__target);
  13156. switch (this.__layout) {
  13157. case LAYOUT.CENTER:
  13158. case LAYOUT.MIDDLE:
  13159. return this.__getCenterLayout(targetRect);
  13160. case LAYOUT.LEFT:
  13161. case LAYOUT.RIGHT:
  13162. case LAYOUT.BOTTOM:
  13163. case LAYOUT.TOP:
  13164. return this.__getOuterLayout(targetRect);
  13165. default:
  13166. return this.__getInnerLayout(targetRect);
  13167. }
  13168. return location;
  13169. },
  13170. /**
  13171. * 居中定位的位置属性
  13172. * @private
  13173. */
  13174. __getCenterLayout: function(targetRect) {
  13175. var location = {
  13176. top: 0,
  13177. left: 0
  13178. }, panelRect = Utils.getRect(this.__element), diff = 0;
  13179. diff = targetRect.height - panelRect.height;
  13180. if (diff > 0) {
  13181. location.top = targetRect.top + diff / 2;
  13182. }
  13183. diff = targetRect.width - panelRect.width;
  13184. if (diff > 0) {
  13185. location.left = targetRect.left + diff / 2;
  13186. }
  13187. return location;
  13188. },
  13189. /**
  13190. * 获取外部布局定位属性
  13191. * @returns {{top: number, left: number}}
  13192. * @private
  13193. */
  13194. __getOuterLayout: function(targetRect) {
  13195. var location = {
  13196. top: 0,
  13197. left: 0
  13198. }, panelRect = Utils.getRect(this.__element);
  13199. switch (this.__layout) {
  13200. case LAYOUT.TOP:
  13201. location.left = targetRect.left;
  13202. location.top = targetRect.top - panelRect.height;
  13203. break;
  13204. case LAYOUT.LEFT:
  13205. location.top = targetRect.top;
  13206. location.left = targetRect.left - panelRect.width;
  13207. break;
  13208. case LAYOUT.RIGHT:
  13209. location.top = targetRect.top;
  13210. location.left = targetRect.right;
  13211. break;
  13212. case LAYOUT.BOTTOM:
  13213. /* falls through */
  13214. default:
  13215. location.left = targetRect.left;
  13216. location.top = targetRect.bottom;
  13217. break;
  13218. }
  13219. return location;
  13220. },
  13221. /**
  13222. * 获取内部布局定位属性,并且,内部布局还拥有根据水平空间的大小,自动进行更新定位的功能
  13223. * @private
  13224. */
  13225. __getInnerLayout: function(targetRect) {
  13226. var location = {
  13227. top: 0,
  13228. left: 0
  13229. }, rect = targetRect, panelRect = Utils.getRect(this.__element);
  13230. switch (this.__layout) {
  13231. case LAYOUT.LEFT_TOP:
  13232. location.top = rect.top;
  13233. location.left = rect.left;
  13234. break;
  13235. case LAYOUT.RIGHT_TOP:
  13236. location.top = rect.top;
  13237. location.left = rect.left + rect.width - panelRect.width;
  13238. break;
  13239. case LAYOUT.LEFT_BOTTOM:
  13240. location.top = rect.top + rect.height - panelRect.height;
  13241. location.left = rect.left;
  13242. break;
  13243. case LAYOUT.RIGHT_BOTTOM:
  13244. location.top = rect.top + rect.height - panelRect.height;
  13245. location.left = rect.left + rect.width - panelRect.width;
  13246. break;
  13247. }
  13248. return this.__correctionLocation(location);
  13249. },
  13250. __getBoundRect: function() {
  13251. var width = -1, height = -1, view = null;
  13252. if (this.__options.bound.tagName.toLowerCase() === "body") {
  13253. view = Utils.getView(this.__options.bound);
  13254. width = $(view).width();
  13255. height = $(view).height();
  13256. return {
  13257. top: 0,
  13258. left: 0,
  13259. right: width,
  13260. bottom: height,
  13261. width: width,
  13262. height: height
  13263. };
  13264. } else {
  13265. return Utils.getRect(this.__options.bound);
  13266. }
  13267. },
  13268. // 如果发生“溢出”,则修正定位
  13269. __correctionLocation: function(location) {
  13270. var panelRect = Utils.getRect(this.__element), targetRect = Utils.getRect(this.__target), boundRect = this.__getBoundRect();
  13271. switch (this.__layout) {
  13272. case LAYOUT.LEFT_TOP:
  13273. case LAYOUT.LEFT_BOTTOM:
  13274. if (location.left + panelRect.width > boundRect.right) {
  13275. location.left += targetRect.width - panelRect.width;
  13276. }
  13277. break;
  13278. case LAYOUT.RIGHT_TOP:
  13279. case LAYOUT.RIGHT_BOTTOM:
  13280. if (location.left < boundRect.left) {
  13281. location.left = targetRect.left;
  13282. }
  13283. break;
  13284. }
  13285. return location;
  13286. }
  13287. });
  13288. }
  13289. };
  13290. //src/widget/select-menu.js
  13291. /**
  13292. * SelectMenu构件
  13293. * 提供从下拉菜单中选中某一项的功能构件
  13294. */
  13295. _p[55] = {
  13296. value: function(require) {
  13297. var $ = _p.r(4), CONF = _p.r(12), Panel = _p.r(51), PPanel = _p.r(54), Button = _p.r(37), Creator = _p.r(0), Mask = _p.r(49);
  13298. return _p.r(13).createClass("SelectMenu", {
  13299. base: Panel,
  13300. constructor: function(options) {
  13301. var defaultOptions = {
  13302. // bed 是Panel的实例
  13303. bed: {
  13304. className: "fui-select-menu-bed"
  13305. },
  13306. button: {
  13307. className: "fui-select-menu-btn"
  13308. },
  13309. events: [ "btnclick" ],
  13310. selected: -1
  13311. };
  13312. options = $.extend({}, defaultOptions, options);
  13313. this.callBase(options);
  13314. },
  13315. show: function() {
  13316. this.__widgetMenu.show();
  13317. this.__mask.show();
  13318. },
  13319. hide: function() {
  13320. this.__widgetMenu.hide();
  13321. this.__mask.hide();
  13322. },
  13323. getValue: function() {
  13324. var selectedWidet = this.__widgets[this.__selected];
  13325. return selectedWidet ? selectedWidet.getValue() : null;
  13326. },
  13327. getSelected: function() {
  13328. return this.__widgets[this.__selected];
  13329. },
  13330. select: function(index) {
  13331. var widget = this.__widgets[index], className = "fui-select-menu-selected", oldIndex = this.__selected, oldSelected = this.__widgets[this.__selected], bedElement = this.__bed.getElement();
  13332. if (!widget) {
  13333. return this;
  13334. }
  13335. if (oldSelected) {
  13336. oldSelected.removeClass(className);
  13337. }
  13338. bedElement.innerHTML = "";
  13339. bedElement.appendChild(widget.cloneElement());
  13340. widget.addClass(className);
  13341. this.__selected = index;
  13342. this.trigger("select", {
  13343. index: index,
  13344. widget: widget
  13345. });
  13346. if (this.__selected !== oldIndex) {
  13347. this.trigger("change", {
  13348. from: {
  13349. index: oldIndex,
  13350. widget: oldSelected
  13351. },
  13352. to: {
  13353. index: index,
  13354. widget: widget
  13355. }
  13356. });
  13357. }
  13358. return this;
  13359. },
  13360. selectByWidget: function(widget) {
  13361. return this.select(this.indexOf(widget));
  13362. },
  13363. selectByValue: function(value) {
  13364. var index = -1;
  13365. $.each(this.__widgets, function(i, widget) {
  13366. if (widget.getValue() === value) {
  13367. index = i;
  13368. return false;
  13369. }
  13370. });
  13371. return this.select(index);
  13372. },
  13373. __render: function() {
  13374. this.__bed = new Panel(this.__options.bed);
  13375. this.__dropBtn = new Button(this.__options.button);
  13376. this.__widgetMenu = new PPanel({
  13377. className: "fui-select-menu-container",
  13378. layout: CONF.layout.LEFT_TOP,
  13379. column: this.__column
  13380. });
  13381. this.__mask = new Mask();
  13382. var widgets = this.__initWidgets();
  13383. this.callBase();
  13384. $(this.__element).addClass(CONF.classPrefix + "select-menu");
  13385. this.appendWidgets([ this.__bed, this.__dropBtn, this.__mask, this.__widgetMenu ]);
  13386. this.__widgets = [];
  13387. this.__oldContentElement = this.__contentElement;
  13388. this.__contentElement = this.__widgetMenu;
  13389. this.appendWidgets(widgets);
  13390. this.__widgetMenu.positionTo(this.getElement());
  13391. if (!$.isNumeric(this.__options.selected)) {
  13392. this.__bed.appendWidget(Creator.parse(this.__options.selected));
  13393. } else if (this.__options.selected != -1) {
  13394. this.select(this.__options.selected);
  13395. }
  13396. },
  13397. __initWidgets: function() {
  13398. var widgets = [];
  13399. if (!this.__options.widgets) {
  13400. return;
  13401. }
  13402. $.each(this.__options.widgets, function(index, widget) {
  13403. widgets.push(Creator.parse(widget));
  13404. });
  13405. return widgets;
  13406. },
  13407. __initEvent: function() {
  13408. this.callBase();
  13409. var _self = this;
  13410. this.__dropBtn.on("btnclick", function() {
  13411. _self.show();
  13412. });
  13413. this.__mask.on("click", function() {
  13414. _self.hide();
  13415. });
  13416. this.__widgetMenu.on(this.__options.events.join(" "), function(e) {
  13417. var target = e.target;
  13418. if (target === _self.__oldContentElement || target === _self.getElement) {
  13419. return;
  13420. }
  13421. e.stopPropagation();
  13422. _self.selectByWidget(e.widget);
  13423. _self.hide();
  13424. return false;
  13425. });
  13426. },
  13427. __initOptions: function() {
  13428. this.callBase();
  13429. this.widgetName = "SelectMenu";
  13430. // 被选中的元素
  13431. this.__bed = null;
  13432. // 下拉按钮
  13433. this.__dropBtn = null;
  13434. this.__widgetMenu = null;
  13435. this.__mask = null;
  13436. this.__widgets = [];
  13437. this.__selected = -1;
  13438. this.__oldContentElement = null;
  13439. this.__column = this.__options.column;
  13440. delete this.__options.column;
  13441. }
  13442. });
  13443. }
  13444. };
  13445. //src/widget/separator.js
  13446. /**
  13447. * Separator(分隔符) Widget
  13448. */
  13449. _p[56] = {
  13450. value: function(require) {
  13451. var Utils = _p.r(13), separatorTpl = _p.r(31), $ = _p.r(4);
  13452. return Utils.createClass("Separator", {
  13453. base: _p.r(60),
  13454. constructor: function(options) {
  13455. var defaultOptions = {
  13456. width: 1,
  13457. height: "100%",
  13458. bgcolor: "#e1e1e1"
  13459. };
  13460. options = $.extend({}, defaultOptions, options);
  13461. this.callBase(options);
  13462. },
  13463. __initOptions: function() {
  13464. this.callBase();
  13465. this.widgetName = "Separator";
  13466. this.__tpl = separatorTpl;
  13467. }
  13468. });
  13469. }
  13470. };
  13471. //src/widget/spin-button.js
  13472. /**
  13473. * SpinButton对象
  13474. * 数值按钮构件
  13475. */
  13476. _p[57] = {
  13477. value: function(require) {
  13478. var $ = _p.r(4), CONF = _p.r(12), tpl = _p.r(32), Button = _p.r(37), Input = _p.r(45), Panel = _p.r(51);
  13479. return _p.r(13).createClass("SpinButton", {
  13480. base: _p.r(60),
  13481. constructor: function(options) {
  13482. var defaultOptions = {
  13483. suffix: null,
  13484. selected: -1,
  13485. items: []
  13486. };
  13487. options = $.extend({}, defaultOptions, options);
  13488. this.callBase(options);
  13489. },
  13490. getValue: function() {
  13491. return this.__options.items[this.__currentSelected] || null;
  13492. },
  13493. // Overload
  13494. setValue: function(value) {},
  13495. select: function(index) {
  13496. this.__update(index);
  13497. },
  13498. // 根据值进行选择
  13499. selectByValue: function(value) {
  13500. value = value + "";
  13501. this.__update($.inArray(value, this.__options.items));
  13502. },
  13503. __render: function() {
  13504. this.callBase();
  13505. this.__buttons = [ new Button({
  13506. className: CONF.classPrefix + "spin-up-btn"
  13507. }), new Button({
  13508. className: CONF.classPrefix + "spin-down-btn"
  13509. }) ];
  13510. this.__inputWidget = new Input();
  13511. this.__panelWidget = new Panel({
  13512. column: true
  13513. });
  13514. this.__inputWidget.appendTo(this.__element);
  13515. this.__panelWidget.appendWidget(this.__buttons[0]);
  13516. this.__panelWidget.appendWidget(this.__buttons[1]);
  13517. this.__panelWidget.appendTo(this.__element);
  13518. this.__initSelected(this.__options.selected);
  13519. },
  13520. __initEvent: function() {
  13521. var _self = this;
  13522. this.callBase();
  13523. this.__buttons[0].on("btnclick", function() {
  13524. _self.__update(_self.__currentSelected - 1);
  13525. });
  13526. this.__buttons[1].on("btnclick", function() {
  13527. _self.__update(_self.__currentSelected + 1);
  13528. });
  13529. },
  13530. __initSelected: function(index) {
  13531. this.__update(index, false);
  13532. },
  13533. __update: function(index, isTrigger) {
  13534. var oldIndex = -1, value = null, toValue = null;
  13535. if (index < 0 || index >= this.__options.items.length) {
  13536. return;
  13537. }
  13538. oldIndex = this.__currentSelected;
  13539. this.__currentSelected = index;
  13540. toValue = this.__options.items[this.__currentSelected];
  13541. value = toValue + " " + (this.__options.suffix || "");
  13542. this.__inputWidget.setValue(value);
  13543. if (isTrigger !== false) {
  13544. this.trigger("change", {
  13545. from: this.__options.items[oldIndex] || null,
  13546. to: toValue
  13547. });
  13548. }
  13549. },
  13550. __initOptions: function() {
  13551. var items = this.__options.items;
  13552. this.callBase();
  13553. this.widgetName = "SpinButton";
  13554. this.__tpl = tpl;
  13555. this.__buttons = [];
  13556. this.__panelWidget = null;
  13557. this.__inputWidget = null;
  13558. this.__currentSelected = -1;
  13559. $.each(items, function(index, val) {
  13560. items[index] = val + "";
  13561. });
  13562. }
  13563. });
  13564. }
  13565. };
  13566. //src/widget/tabs.js
  13567. /**
  13568. * Tabs Widget
  13569. */
  13570. _p[58] = {
  13571. value: function(require) {
  13572. var $ = _p.r(4), CONF = _p.r(12), tpl = _p.r(33), Button = _p.r(37), Panel = _p.r(51);
  13573. return _p.r(13).createClass("Tabs", {
  13574. base: _p.r(60),
  13575. constructor: function(options) {
  13576. var defaultOptions = {
  13577. selected: 0,
  13578. buttons: [],
  13579. panels: []
  13580. };
  13581. options = $.extend({}, defaultOptions, options);
  13582. this.callBase(options);
  13583. },
  13584. getButtons: function() {
  13585. return this.__btns;
  13586. },
  13587. getButton: function(index) {
  13588. return this.getButtons()[index] || null;
  13589. },
  13590. getButtonByValue: function(value) {
  13591. var button = null;
  13592. $.each(this.__btns, function(i, btn) {
  13593. if (btn.getValue() === value) {
  13594. button = btn;
  13595. return false;
  13596. }
  13597. });
  13598. return button;
  13599. },
  13600. getPanels: function() {
  13601. return this.__panels;
  13602. },
  13603. getPanel: function(index) {
  13604. return this.getPanels()[index] || null;
  13605. },
  13606. getPanelByValue: function(value) {
  13607. var panel = null;
  13608. $.each(this.__panels, function(i, pan) {
  13609. if (pan.getValue() === value) {
  13610. panel = pan;
  13611. return false;
  13612. }
  13613. });
  13614. return panel;
  13615. },
  13616. getSelectedIndex: function() {
  13617. return this.__selected;
  13618. },
  13619. getSelected: function() {
  13620. var index = this.getSelectedIndex();
  13621. return {
  13622. button: this.getButton(index),
  13623. panel: this.getPanel(index)
  13624. };
  13625. },
  13626. appendTab: function(tabOpt) {
  13627. tabOpt.panels = tabOpt.panels || [];
  13628. return this.__renderByOptions(tabOpt);
  13629. },
  13630. removeTab: function(index) {
  13631. if (index < 0) {
  13632. return null;
  13633. }
  13634. var btn = this.__btns.splice(index, 1), panel = this.__panels.splice(index, 1);
  13635. if (!btn.length) {
  13636. return null;
  13637. }
  13638. btn = btn[0];
  13639. panel = panel[0];
  13640. btn.remove();
  13641. panel.remove();
  13642. return {
  13643. button: btn,
  13644. panel: panel
  13645. };
  13646. },
  13647. /**
  13648. * 选择接口
  13649. * @param index 需要选中的tab页索引
  13650. */
  13651. select: function(index) {
  13652. var toInfo = null;
  13653. if (!this.__selectItem(index)) {
  13654. return this;
  13655. }
  13656. toInfo = this.__getInfo(index);
  13657. this.trigger("tabsselect", toInfo);
  13658. if (this.__prevSelected !== this.__selected) {
  13659. this.trigger("tabschange", {
  13660. from: this.__getInfo(this.__prevSelected),
  13661. to: toInfo
  13662. });
  13663. }
  13664. return this;
  13665. },
  13666. getIndexByButton: function(btn) {
  13667. return $.inArray(btn, this.__btns);
  13668. },
  13669. /**
  13670. * 把所有button追加到其他容器中
  13671. */
  13672. appendButtonTo: function(container) {
  13673. $.each(this.__btns, function(index, btn) {
  13674. btn.appendTo(container);
  13675. });
  13676. },
  13677. appendPanelTo: function(container) {
  13678. $.each(this.__panels, function(index, panel) {
  13679. panel.appendTo(container);
  13680. });
  13681. },
  13682. __render: function() {
  13683. this.callBase();
  13684. this.__btnWrap = $(".fui-tabs-button-wrap", this.__element)[0];
  13685. this.__panelWrap = $(".fui-tabs-panel-wrap", this.__element)[0];
  13686. this.__renderByOptions(this.__options);
  13687. this.__selectItem(this.__options.selected);
  13688. },
  13689. __renderByOptions: function(options) {
  13690. var _self = this, mapping = [], btns = this.__btns, panels = this.__panels, btnWrap = this.__btnWrap, panelWrap = this.__panelWrap;
  13691. $.each(options.buttons, function(index, opt) {
  13692. var btn = null, panel = null;
  13693. if (typeof opt !== "object") {
  13694. opt = {
  13695. label: opt
  13696. };
  13697. }
  13698. btn = new Button(opt);
  13699. btn.on("click", function() {
  13700. _self.select(_self.getIndexByButton(this));
  13701. });
  13702. opt = options.panels[index] || {};
  13703. opt.hide = true;
  13704. panel = new Panel(opt);
  13705. btns.push(btn);
  13706. panels.push(panel);
  13707. mapping.push({
  13708. button: btn,
  13709. panel: panel
  13710. });
  13711. btn.appendTo(btnWrap);
  13712. panel.appendTo(panelWrap);
  13713. });
  13714. return mapping;
  13715. },
  13716. __initOptions: function() {
  13717. this.callBase();
  13718. this.widgetName = "Tabs";
  13719. this.__tpl = tpl;
  13720. this.__btns = [];
  13721. this.__panels = [];
  13722. this.__prevSelected = -1;
  13723. this.__selected = -1;
  13724. this.__btnWrap = null;
  13725. this.__panelWrap = null;
  13726. // panels不设置的情况下, 将根据button创建
  13727. if (this.__options.panels === null) {
  13728. this.__options.panels = [];
  13729. this.__options.panels.length = this.__options.buttons.length;
  13730. }
  13731. },
  13732. __selectItem: function(index) {
  13733. var btn = this.getButton(index), prevBtn = this.getButton(this.__selected), className = CONF.classPrefix + "selected";
  13734. if (!btn) {
  13735. return false;
  13736. }
  13737. if (prevBtn) {
  13738. prevBtn.removeClass(className);
  13739. this.getPanel(this.__selected).hide();
  13740. }
  13741. btn.addClass(className);
  13742. this.getPanel(index).show();
  13743. this.__prevSelected = this.__selected;
  13744. this.__selected = index;
  13745. return true;
  13746. },
  13747. // 根据给定的tab索引获取先关的信息, 这些信息将用于事件携带的参数
  13748. __getInfo: function(index) {
  13749. return {
  13750. index: index,
  13751. button: this.getButton(index),
  13752. panel: this.getPanel(index)
  13753. };
  13754. }
  13755. });
  13756. }
  13757. };
  13758. //src/widget/toggle-button.js
  13759. /**
  13760. * ToggleButton对象
  13761. * 可切换按钮构件
  13762. */
  13763. _p[59] = {
  13764. value: function(require) {
  13765. var $ = _p.r(4), CONF = _p.r(12);
  13766. return _p.r(13).createClass("ToggleButton", {
  13767. base: _p.r(37),
  13768. constructor: function(options) {
  13769. var defaultOptions = {
  13770. // 按钮初始时是否按下
  13771. pressed: false
  13772. };
  13773. options = $.extend({}, defaultOptions, options);
  13774. this.callBase(options);
  13775. },
  13776. /**
  13777. * 当前按钮是否已按下
  13778. */
  13779. isPressed: function() {
  13780. return this.__state;
  13781. },
  13782. /**
  13783. * 按下按钮
  13784. */
  13785. press: function() {
  13786. var className = CONF.classPrefix + "button-pressed";
  13787. $(this.__element).addClass(className);
  13788. this.__updateState(true);
  13789. },
  13790. /**
  13791. * 弹起按钮
  13792. */
  13793. bounce: function() {
  13794. var className = CONF.classPrefix + "button-pressed";
  13795. $(this.__element).removeClass(className);
  13796. this.__updateState(false);
  13797. },
  13798. toggle: function() {
  13799. if (this.__state) {
  13800. this.bounce();
  13801. } else {
  13802. this.press();
  13803. }
  13804. },
  13805. __initOptions: function() {
  13806. this.callBase();
  13807. this.widgetName = "ToggleButton";
  13808. // 按钮当前状态
  13809. this.__state = false;
  13810. },
  13811. __render: function() {
  13812. this.callBase();
  13813. $(this.__element).addClass(CONF.classPrefix + "toggle-button");
  13814. this.__initButtonState();
  13815. return this;
  13816. },
  13817. __initButtonState: function() {
  13818. if (!this.__options.pressed) {
  13819. return;
  13820. }
  13821. // 不直接调用press方法, 防止初始化时事件的触发
  13822. $(this.__element).addClass(CONF.classPrefix + "button-pressed");
  13823. this.__state = true;
  13824. },
  13825. /**
  13826. * 初始化事件监听, 控制状态的切换
  13827. * @private
  13828. */
  13829. __initEvent: function() {
  13830. this.callBase();
  13831. this.on("click", function() {
  13832. this.toggle();
  13833. });
  13834. },
  13835. __updateState: function(state) {
  13836. state = !!state;
  13837. this.__state = state;
  13838. this.trigger("change", state, !state);
  13839. }
  13840. });
  13841. }
  13842. };
  13843. //src/widget/widget.js
  13844. /*jshint camelcase:false*/
  13845. /**
  13846. * widget对象
  13847. * 所有的UI组件都是widget对象
  13848. */
  13849. _p[60] = {
  13850. value: function(require) {
  13851. var prefix = "_fui_", uid = 0, CONF = _p.r(12), FUI_NS = _p.r(11), $ = _p.r(4), Utils = _p.r(13);
  13852. var Widget = Utils.createClass("Widget", {
  13853. constructor: function(options) {
  13854. var defaultOptions = {
  13855. id: null,
  13856. className: "",
  13857. disabled: false,
  13858. preventDefault: false,
  13859. text: "",
  13860. value: null,
  13861. hide: false,
  13862. width: null,
  13863. height: null
  13864. };
  13865. this.__widgetType = "widget";
  13866. this.__tpl = "";
  13867. this.__compiledTpl = "";
  13868. this.__options = {};
  13869. this.__element = null;
  13870. // 禁止获取焦点
  13871. this.__allow_focus = !!CONF.allowFocus;
  13872. this.widgetName = "Widget";
  13873. this.__extendOptions(defaultOptions, options);
  13874. this.__initOptions();
  13875. this.__render();
  13876. this.__initEvent();
  13877. this.__initWidgets && this.__initWidgets();
  13878. },
  13879. getId: function() {
  13880. return this.id;
  13881. },
  13882. getValue: function() {
  13883. return this.__options.value;
  13884. },
  13885. getOptions: function() {
  13886. return this.__options;
  13887. },
  13888. setValue: function(value) {
  13889. this.__options.value = value;
  13890. return this;
  13891. },
  13892. show: function() {
  13893. this.__show();
  13894. return this;
  13895. },
  13896. hide: function() {
  13897. this.__hide();
  13898. return this;
  13899. },
  13900. addClass: function(className) {
  13901. $(this.__element).addClass(className);
  13902. return this;
  13903. },
  13904. removeClass: function(className) {
  13905. $(this.__element).removeClass(className);
  13906. return this;
  13907. },
  13908. setStyle: function() {
  13909. $.fn.css.apply($(this.__element), arguments);
  13910. return this;
  13911. },
  13912. getStyle: function() {
  13913. return $.fn.css.apply($(this.__element), arguments);
  13914. },
  13915. /**
  13916. * 当前构件是否是处于禁用状态
  13917. * @returns {boolean|disabled|jsl.$.disabled|id.disabled}
  13918. */
  13919. isDisabled: function() {
  13920. return this.__options.disabled;
  13921. },
  13922. /**
  13923. * 启用当前构件
  13924. * @returns {Widget}
  13925. */
  13926. enable: function() {
  13927. this.__options.disabled = false;
  13928. $(this.__element).removeClass(CONF.classPrefix + "disabled");
  13929. return this;
  13930. },
  13931. /**
  13932. * 禁用当前构件
  13933. * @returns {Widget}
  13934. */
  13935. disable: function() {
  13936. this.__options.disabled = true;
  13937. $(this.__element).addClass(CONF.classPrefix + "disabled");
  13938. return this;
  13939. },
  13940. cloneElement: function() {
  13941. return this.__element.cloneNode(true);
  13942. },
  13943. /**
  13944. * 获取
  13945. * @returns {null}
  13946. */
  13947. getElement: function() {
  13948. return this.__element;
  13949. },
  13950. appendTo: function(container) {
  13951. if (Utils.isElement(container)) {
  13952. container.appendChild(this.__element);
  13953. } else if (container instanceof Widget) {
  13954. container.__appendChild(this);
  13955. } else {
  13956. throw new Error("TypeError: Widget.appendTo()");
  13957. }
  13958. return this;
  13959. },
  13960. remove: function() {
  13961. var parent = this.__element.parentNode;
  13962. if (parent) {
  13963. parent.removeChild(this.__element);
  13964. }
  13965. return this;
  13966. },
  13967. off: function(type, cb) {
  13968. $(this.__element).off(cb && cb.__fui_listener);
  13969. return this;
  13970. },
  13971. on: function(type, cb) {
  13972. if (!this.__options.preventDefault) {
  13973. this.__on(type, cb);
  13974. }
  13975. return this;
  13976. },
  13977. __initOptions: function() {},
  13978. /**
  13979. * 根据模板渲染构件, 如果该构件已经渲染过, 则不会进行二次渲染
  13980. * @returns {Widget}
  13981. */
  13982. __render: function() {
  13983. var $ele = null, tpl = this.__tpl, opts = this.__options, className = null;
  13984. this.id = this.__id();
  13985. // 向NS注册自己
  13986. FUI_NS.__registerInstance(this);
  13987. this.__compiledTpl = Utils.Tpl.compile(tpl, opts);
  13988. this.__element = $(this.__compiledTpl)[0];
  13989. this.__element.setAttribute("id", this.id);
  13990. $ele = $(this.__element);
  13991. if (opts.disabled) {
  13992. $ele.addClass(CONF.classPrefix + "disabled");
  13993. }
  13994. $ele.addClass(CONF.classPrefix + "widget");
  13995. // add custom class-name
  13996. className = opts.className;
  13997. if (className.length > 0) {
  13998. if ($.isArray(className)) {
  13999. $ele.addClass(className.join(" "));
  14000. } else {
  14001. $ele.addClass(className);
  14002. }
  14003. }
  14004. this.__initBasicEnv();
  14005. if (opts.hide) {
  14006. this.__hide();
  14007. }
  14008. if (opts.style) {
  14009. this.setStyle(opts.style);
  14010. }
  14011. return this;
  14012. },
  14013. /**
  14014. * 该方法将被appendTo调用, 用于根据各组件自身的规则插入节点, 子类可根据需要覆盖该方法
  14015. * @param childWidget 将被追加的子构件对象
  14016. */
  14017. __appendChild: function(childWidget) {
  14018. return this.__element.appendChild(childWidget.getElement());
  14019. },
  14020. __initEvent: function() {
  14021. this.on("mousedown", function(e) {
  14022. var tagName = e.target.tagName.toLowerCase();
  14023. if (!CONF.control[tagName] && !this.__allowFocus()) {
  14024. e.preventDefault();
  14025. } else {
  14026. e.stopPropagation();
  14027. }
  14028. });
  14029. },
  14030. __on: function(type, cb) {
  14031. var _self = this;
  14032. cb.__fui_listener = function(e, widget) {
  14033. var params = [];
  14034. for (var i = 0, len = arguments.length; i < len; i++) {
  14035. if (i !== 1) {
  14036. params.push(arguments[i]);
  14037. }
  14038. }
  14039. e.widget = widget;
  14040. if (!_self.isDisabled()) {
  14041. return cb.apply(_self, params);
  14042. }
  14043. };
  14044. $(this.__element).on(type, cb.__fui_listener);
  14045. return this;
  14046. },
  14047. trigger: function(type, params) {
  14048. if (!this.__options.preventDefault) {
  14049. this.__trigger.apply(this, arguments);
  14050. }
  14051. return this;
  14052. },
  14053. __allowShowTitle: function() {
  14054. return true;
  14055. },
  14056. __allowFocus: function() {
  14057. return !!this.__allow_focus;
  14058. },
  14059. __trigger: function(type, params) {
  14060. var args = [].slice.call(arguments, 1);
  14061. $(this.__element).trigger(type, [ this ].concat(args));
  14062. return this;
  14063. },
  14064. __triggerHandler: function(type, params) {
  14065. var args = [ this ].concat([].slice.call(arguments, 1));
  14066. return $(this.__element).triggerHandler(type, args);
  14067. },
  14068. /**
  14069. * 同__trigger,都触发某事件,但是该方法触发的事件会主动触发before和after,
  14070. * 同时如果before事件返回false,则后续handler都不会执行,且后续事件也不会再触发。
  14071. * @param type 事件类型
  14072. * @param handler 该事件所需要执行的函数句柄, 且该函数的返回值将作为该事件的参数发送给事件监听器
  14073. * */
  14074. __fire: function(type, handler) {
  14075. var result = {
  14076. cancel: false
  14077. };
  14078. if (/^(before|after)/.test(type)) {
  14079. return this;
  14080. }
  14081. this.__trigger("before" + type, result);
  14082. if (result.cancel === true) {
  14083. return this;
  14084. }
  14085. result = handler.call(this, type);
  14086. this.__trigger(type);
  14087. this.__trigger("after" + type, result);
  14088. return this;
  14089. },
  14090. __extendOptions: function() {
  14091. var args = [ {}, this.__options ], params = [ true ];
  14092. args = args.concat([].slice.call(arguments, 0));
  14093. for (var i = 0, len = args.length; i < len; i++) {
  14094. if (typeof args[i] !== "string") {
  14095. params.push(args[i]);
  14096. }
  14097. }
  14098. this.__options = $.extend.apply($, params);
  14099. },
  14100. __hide: function() {
  14101. $(this.__element).addClass(CONF.classPrefix + "hide");
  14102. },
  14103. __show: function() {
  14104. $(this.__element).removeClass(CONF.classPrefix + "hide");
  14105. },
  14106. __initBasicEnv: function() {
  14107. if (this.__options.text && this.__allowShowTitle()) {
  14108. this.__element.setAttribute("title", this.__options.text);
  14109. }
  14110. if (this.__options.width) {
  14111. this.__element.style.width = this.__options.width + "px";
  14112. }
  14113. if (this.__options.height) {
  14114. this.__element.style.height = this.__options.height + "px";
  14115. }
  14116. if (this.widgetName) {
  14117. this.__element.setAttribute("rule", this.widgetName);
  14118. }
  14119. },
  14120. __id: function() {
  14121. return this.__options.id || generatorId();
  14122. }
  14123. });
  14124. // 为widget生成唯一id
  14125. function generatorId() {
  14126. return prefix + ++uid;
  14127. }
  14128. return Widget;
  14129. }
  14130. };
  14131. //dev-lib/exports.js
  14132. /**
  14133. * 模块暴露
  14134. */
  14135. _p[61] = {
  14136. value: function(require) {
  14137. _p.r(1);
  14138. _p.r(2);
  14139. }
  14140. };
  14141. var moduleMapping = {
  14142. "fui.export": 61
  14143. };
  14144. function use(name) {
  14145. _p.r([ moduleMapping[name] ]);
  14146. }
  14147. // 编译打包后的启动脚本
  14148. use( 'fui.export' );})();
  14149. /**
  14150. * @fileOverview
  14151. *
  14152. * FIO 核心代码
  14153. *
  14154. * @author techird, Baidu FEX.
  14155. *
  14156. */
  14157. (function(Promise) {
  14158. var fio = {
  14159. version: '1.0'
  14160. };
  14161. /* 三个主要的命名空间 */
  14162. fio.provider = {};
  14163. fio.file = {};
  14164. fio.user = {};
  14165. /* IO 提供方列表 */
  14166. var providerMap = {};
  14167. /* FIO 当前使用的 IO 提供方 */
  14168. var currentProvider = null;
  14169. /* 返回值为空的 Promise */
  14170. var noop = function() {
  14171. return new Promise.resolve(null);
  14172. };
  14173. /* FIO 当前的用户系统实现 */
  14174. var userImpl = {
  14175. check: noop,
  14176. login: noop,
  14177. logout: noop,
  14178. init: noop,
  14179. current: noop
  14180. };
  14181. function inherit(sub, parent) {
  14182. sub.prototype = Object.create(parent.prototype);
  14183. sub.prototype.constructor = sub;
  14184. }
  14185. function AuthError() { Error.apply(this, arguments); }
  14186. function FileRequestError(detail) {
  14187. Error.call(this, detail);
  14188. if (typeof(detail) == 'object') {
  14189. for (var p in detail) {
  14190. if (detail.hasOwnProperty(p)) this[p] = detail[p];
  14191. }
  14192. } else {
  14193. this.detail = detail;
  14194. }
  14195. }
  14196. inherit(AuthError, Error);
  14197. inherit(FileRequestError, Error);
  14198. fio.AuthError = AuthError;
  14199. fio.FileRequestError = FileRequestError;
  14200. /* 数据结构:表示一个用户 */
  14201. function User(id, username) {
  14202. this.id = id;
  14203. this.username = username;
  14204. }
  14205. /* 数据结构:表示一份数据 */
  14206. function Data(content) {
  14207. this.content = content;
  14208. if (content instanceof Blob) {
  14209. this.type = fio.file.TYPE_BLOB;
  14210. } else if (typeof(content) == 'string') {
  14211. this.type = fio.file.TYPE_TEXT;
  14212. } else if (typeof(content) == 'object') {
  14213. this.type = fio.file.TYPE_JSON;
  14214. } else {
  14215. this.type = fio.file.TYPE_UNKNOWN;
  14216. }
  14217. }
  14218. /* 数据结构:表示一个文件或目录 */
  14219. function File(path) {
  14220. this.setPath(path);
  14221. this.isDir = false;
  14222. this.data = null;
  14223. this.size = 0;
  14224. this.createTime = new Date();
  14225. this.modifyTime = new Date();
  14226. }
  14227. File.prototype.setPath = function(path) {
  14228. fio.file.anlysisPath(path, this);
  14229. };
  14230. fio.file.anlysisPath = function(path, fill) {
  14231. fill = fill || {};
  14232. var pathParts = path.split('/');
  14233. // trim start
  14234. while (pathParts[0] == '/' || pathParts[0] === '') {
  14235. pathParts.shift();
  14236. }
  14237. // trim end
  14238. while (pathParts[pathParts.length - 1] == '/' || pathParts[pathParts.length - 1] === '') {
  14239. pathParts.pop();
  14240. }
  14241. fill.filename = pathParts.pop() || null;
  14242. if (pathParts.length) {
  14243. fill.parentPath = '/' + pathParts.join('/') + '/';
  14244. } else {
  14245. fill.parentPath = fill.filename ? '/' : null;
  14246. }
  14247. if (fill.filename) {
  14248. var filenameParts = fill.filename.split('.');
  14249. if (filenameParts.length > 1) {
  14250. fill.extension = '.' + filenameParts.pop();
  14251. } else {
  14252. fill.extension = null;
  14253. }
  14254. fill.name = filenameParts.join('.');
  14255. fill.path = fill.parentPath + fill.filename;
  14256. } else {
  14257. fill.path = '/';
  14258. }
  14259. return fill;
  14260. };
  14261. /* 数据结构:表示一个访问控制列表记录 */
  14262. function Acl(user, file, access) {
  14263. this.user = user;
  14264. this.file = file;
  14265. this.access = access || 0;
  14266. }
  14267. /* 数据结构:表示一个文件操作请求 */
  14268. function FileRequest(path, method, user) {
  14269. this.path = path;
  14270. this.method = method;
  14271. this.user = user;
  14272. this.dupPolicy = fio.file.DUP_FAIL;
  14273. this.newPath = null;
  14274. this.acl = null;
  14275. this.extra = null;
  14276. this.dataType = fio.file.TYPE_TEXT;
  14277. }
  14278. /* 暴露需要的数据结构 */
  14279. fio.user.User = User;
  14280. fio.file.Data = Data;
  14281. fio.file.File = File;
  14282. fio.file.Acl = Acl;
  14283. fio.file.FileRequest = FileRequest;
  14284. /* 数据类型常量枚举 */
  14285. fio.file.TYPE_TEXT = 'text';
  14286. fio.file.TYPE_JSON = 'json';
  14287. fio.file.TYPE_BLOB = 'blob';
  14288. fio.file.TYPE_UNKNOWN = 'unknown';
  14289. /* 文件操作常量枚举 */
  14290. fio.file.METHOD_READ = 'read';
  14291. fio.file.METHOD_WRITE = 'write';
  14292. fio.file.METHOD_LIST = 'list';
  14293. fio.file.METHOD_MOVE = 'move';
  14294. fio.file.METHOD_DELETE = 'delete';
  14295. fio.file.METHOD_MKDIR = 'mkdir';
  14296. fio.file.METHOD_ACL_READ = 'readAcl';
  14297. fio.file.METHOD_ACL_WRITE = 'writeAcl';
  14298. /* 文件重复处理策略枚举 */
  14299. fio.file.DUP_OVERWRITE = 'overwrite';
  14300. fio.file.DUP_FAIL = 'fail';
  14301. fio.file.DUP_RENAME = 'rename';
  14302. /* 权限枚举 */
  14303. fio.file.ACCESS_PUBLIC = 0x0001;
  14304. fio.file.ACCESS_READ = 0x0002;
  14305. fio.file.ACCESS_WRITE = 0x0004;
  14306. fio.file.ACCESS_CREATE = 0x0008;
  14307. fio.file.ACCESS_DELETE = 0x0010;
  14308. fio.file.ACCESS_ACL_READ = 0x0020;
  14309. fio.file.ACCESS_ACL_WRITE = 0x0040;
  14310. fio.file.ACCESS_ALL = 0xfffe;
  14311. /**
  14312. * 注册一个 IO 提供方
  14313. *
  14314. * @method fio.provider.register
  14315. *
  14316. * @grammer fio.provider.register(name, provider)
  14317. *
  14318. * @param {string} name
  14319. * 提供方的名称
  14320. *
  14321. * @param {object} provider
  14322. * 提供方的实现
  14323. *
  14324. * provider.init(opt) {function(object)}
  14325. * 提供方的初始化方法,客户调用 fio.provider.init() 的时候会调用
  14326. *
  14327. * provider.handle(request) {function(fio.file.FileRequest)}
  14328. * 提供方处理文件请求的方法,根据 request.method 的不同取值返回不同的 Promise:
  14329. *
  14330. * 取值为 `fio.file.METHOD_LIST` 返回 Promise<fio.file.File[]>
  14331. * 取值为 `fio.file.METHOD_ACL_READ` 返回 Promise<fio.file.ACL[]>
  14332. * 取值为 `fio.file.METHOD_ACL_WRITE` 返回 Promise<fio.file.ACL[]>
  14333. * 其他取值返回 `Promise<fio.file.File>`
  14334. *
  14335. * @see #fio.file.FileRequest
  14336. *
  14337. * @example
  14338. *
  14339. * fio.provider.register('netdisk', {
  14340. *
  14341. * init: function(opt) {
  14342. * // init provider
  14343. * },
  14344. *
  14345. * handle: function(request) {
  14346. * // handle request
  14347. * }
  14348. *
  14349. * });
  14350. *
  14351. */
  14352. fio.provider.register = function(name, provider) {
  14353. providerMap[name] = provider;
  14354. if (!currentProvider) currentProvider = provider;
  14355. // implement check
  14356. if (typeof(provider.handle) != 'function') {
  14357. throw new Error('Not implement: provider.handle()');
  14358. }
  14359. };
  14360. /**
  14361. * 切换 FIO 使用的默认 IO 提供方
  14362. *
  14363. * @method fio.provider.use
  14364. *
  14365. * @grammar fio.provider.use(name)
  14366. *
  14367. * @param {string} name
  14368. * 要使用的提供方的名称
  14369. */
  14370. fio.provider.use = function(name) {
  14371. currentProvider = providerMap[name];
  14372. };
  14373. /**
  14374. * 初始化指定的 IO 提供方
  14375. *
  14376. * @param {string} name
  14377. * 要初始化的提供方的名称
  14378. *
  14379. * @param {object} opt
  14380. * 初始化选项
  14381. */
  14382. fio.provider.init = function(name, opt) {
  14383. var provider = providerMap[name];
  14384. if (provider && typeof(provider.init) == 'function') {
  14385. return provider.init.call(provider, opt);
  14386. }
  14387. return null;
  14388. };
  14389. /**
  14390. * 实现 FIO 用户系统
  14391. *
  14392. * @method fio.user.impl
  14393. *
  14394. * @grammar fio.user.impl(impl)
  14395. *
  14396. * @param {object} impl
  14397. * 实现的代码,需要实现的方法包括:
  14398. *
  14399. * impl.init(opt): null
  14400. * 用户系统需要初始化的入口
  14401. *
  14402. * impl.check(): fio.user.User
  14403. * 返回当前用户
  14404. *
  14405. * impl.login(): Promise<fio.user.User>
  14406. * 进行用户的登陆
  14407. *
  14408. * impl.logout(): Promise<fio.user.User>
  14409. * 登出当前用户
  14410. *
  14411. * impl.current(): fio.user.User
  14412. * 返回当前用户(如果已登录)
  14413. *
  14414. */
  14415. fio.user.impl = function(impl) {
  14416. userImpl = impl;
  14417. };
  14418. ['check', 'login', 'logout', 'init', 'current'].forEach(function(operation) {
  14419. fio.user[operation] = function() {
  14420. return userImpl[operation].apply(userImpl, arguments);
  14421. };
  14422. });
  14423. /**
  14424. * 读取文件
  14425. *
  14426. * @method fio.file.read
  14427. *
  14428. * @grammar fio.file.read(opt)
  14429. *
  14430. * @param {object} opt 选项
  14431. *
  14432. * opt.path {string}
  14433. * 读取的文件的路径
  14434. *
  14435. * @return {Promise<fio.file.File>} 读取的文件
  14436. *
  14437. * @example
  14438. *
  14439. * ```js
  14440. * fio.file.read({
  14441. * path: 'a.txt'
  14442. * }).then(function(file) {
  14443. * console.log(file.data.content);
  14444. * }).catch(function(e) {
  14445. * console.log(e.message);
  14446. * });
  14447. * ```
  14448. */
  14449. /**
  14450. * 写入文件
  14451. *
  14452. * @method fio.file.write
  14453. *
  14454. * @grammar fio.file.write(opt)
  14455. *
  14456. * @param {object} opt 选项
  14457. *
  14458. * opt.path {string}
  14459. * 要写入文件的位置
  14460. *
  14461. * opt.content {string|object|blob}
  14462. * 要写入的文件的内容
  14463. *
  14464. * opt.ondup {Enum}
  14465. * 存在同名文件时采取的策略
  14466. *
  14467. * @return {Promise<fio.file.File>} 返回已写入的文件
  14468. *
  14469. * @example
  14470. *
  14471. * ```js
  14472. * fio.file.write({
  14473. * path: 'hello.txt',
  14474. * content: 'hello, fio!'
  14475. * }).then(function(file) {
  14476. * console.log('the file size is ' + file.size);
  14477. * }).catch(function(e) {
  14478. * console.log(e);
  14479. * });
  14480. * ```
  14481. */
  14482. /**
  14483. * 列出指定目录的文件
  14484. *
  14485. * @method fio.file.list
  14486. *
  14487. * @grammar fio.file.list(opt)
  14488. *
  14489. * @param {object} opt 选项
  14490. * opt.path {string} 要列出文件的路径
  14491. *
  14492. * @return {Promise<fio.file.File[]>} 列出的文件列表
  14493. *
  14494. * @example
  14495. *
  14496. * ```js
  14497. * fio.file.list({
  14498. * path: '/kityminder/'
  14499. * }).then(function(files) {
  14500. * console.table(files);
  14501. * });
  14502. * ``
  14503. */
  14504. /**
  14505. * 移动指定的文件
  14506. *
  14507. * @method fio.file.move
  14508. *
  14509. * @grammar fio.file.move(opt)
  14510. *
  14511. * @param {object} opt 选项
  14512. * opt.path {string} 要移动的文件或目录的路径
  14513. * opt.newPath {string} 目标位置
  14514. *
  14515. * @return {Promise<fio.file.File>}
  14516. *
  14517. * @example
  14518. *
  14519. * ```js
  14520. * fio.file.move({
  14521. * path: '/kityminder/a.xmind',
  14522. * newPath: '/kityminder/b.xmind'
  14523. * }).then(function(file) {
  14524. * console.log('file moved to' + file.path);
  14525. * });
  14526. * ``
  14527. */
  14528. /**
  14529. * 删除文件
  14530. *
  14531. * @method fio.file.delete
  14532. *
  14533. * @grammar fio.file.delete(opt)
  14534. *
  14535. * @param {object} opt 选项
  14536. *
  14537. * opt.path {string}
  14538. * 要删除的文件的路径
  14539. *
  14540. * @return {Promise<fio.file.File>} 读取的文件
  14541. *
  14542. * @example
  14543. *
  14544. * ```js
  14545. * fio.file.delete({
  14546. * path: 'a.txt'
  14547. * }).then(function(file) {
  14548. * console.log('file deleted: ' + file.path);
  14549. * }).catch(function(e) {
  14550. * console.log(e.message);
  14551. * });
  14552. * ```
  14553. */
  14554. /**
  14555. * 创建目录
  14556. *
  14557. * @method fio.file.mkdir
  14558. *
  14559. * @grammar fio.file.mkdir(opt)
  14560. *
  14561. * @param {object} opt 选项
  14562. *
  14563. * opt.path {string}
  14564. * 要创建的目录的路径
  14565. *
  14566. * @return {Promise<fio.file.File>} 已创建的目录
  14567. *
  14568. * @example
  14569. *
  14570. * ```js
  14571. * fio.file.mkdir({
  14572. * path: '/kityminder/a'
  14573. * }).then(function(file) {
  14574. * console.log('dir created: ' + file.path);
  14575. * }).catch(function(e) {
  14576. * console.log(e.message);
  14577. * });
  14578. * ```
  14579. */
  14580. /**
  14581. * 读取指定路径的 ACL
  14582. *
  14583. * @method fio.file.readAcl
  14584. *
  14585. * @grammar fio.file.readAcl(opt)
  14586. *
  14587. * @param {object} opt 选项
  14588. *
  14589. * opt.path {string}
  14590. * 要读取 ACL 的路径
  14591. *
  14592. * @return {Promise<fio.file.Acl[]>} 读取的 ACL 集合
  14593. *
  14594. * @example
  14595. *
  14596. * ```js
  14597. * fio.file.readAcl({
  14598. * path: 'a.txt'
  14599. * }).then(function(acl) {
  14600. * console.table(acl);
  14601. * }).catch(function(e) {
  14602. * console.log(e.message);
  14603. * });
  14604. * ```
  14605. */
  14606. /**
  14607. * 写入指定路径的 ACL
  14608. *
  14609. * @method fio.file.writeAcl
  14610. *
  14611. * @grammar fio.file.write(opt)
  14612. *
  14613. * @param {object} opt 选项
  14614. *
  14615. * opt.path {string}
  14616. * 要写入 ACL 的路径
  14617. * option.acl {object}
  14618. * 要写入的 ACL(username => access)
  14619. *
  14620. * @return {Promise<fio.file.Acl[]>} 写入后 ACL 后,指定路径的 ACL 集合
  14621. *
  14622. * @example
  14623. *
  14624. * ```js
  14625. * fio.file.writeAcl({
  14626. * path: 'a.txt',
  14627. * acl: {
  14628. * techird: fio.file.ACCESS_READ | fio.file.ACCESS_WRITE
  14629. * }
  14630. * }).then(function(acl) {
  14631. * console.table(acl);
  14632. * }).catch(function(e) {
  14633. * console.log(e.message);
  14634. * });
  14635. * ```
  14636. */
  14637. ['read', 'write', 'list', 'move', 'delete', 'mkdir', 'readAcl', 'writeAcl'].forEach(function(operation) {
  14638. fio.file[operation] = function(opt) {
  14639. return fio.user.check().then(function(user) {
  14640. var provider = opt.provider ? providerMap[opt.provider] : currentProvider;
  14641. var request = new FileRequest(opt.path, operation, user);
  14642. if (operation == 'read') {
  14643. request.dataType = opt.dataType || fio.file.TYPE_TEXT;
  14644. }
  14645. if (operation == 'write') {
  14646. request.dupPolicy = opt.ondup;
  14647. request.data = new fio.file.Data(opt.content);
  14648. delete opt.ondup;
  14649. }
  14650. if (operation == 'move') {
  14651. request.dupPolicy = opt.ondup;
  14652. request.newPath = opt.newPath;
  14653. delete opt.newPath;
  14654. }
  14655. if (operation == 'writeAcl') {
  14656. request.acl = opt.acl;
  14657. delete opt.acl;
  14658. }
  14659. delete opt.provider;
  14660. delete opt.path;
  14661. request.extra = opt;
  14662. var response = provider.handle(request);
  14663. // 确保返回的是一个 Promise 对象
  14664. return Promise.resolve(response);
  14665. });
  14666. };
  14667. });
  14668. // export
  14669. window.fio = fio;
  14670. })(Promise);
  14671. /**
  14672. * @fileOverview
  14673. *
  14674. * 为 FIO 提供百度第三方平台用户系统
  14675. *
  14676. * @author: techird
  14677. * @copyright: Baidu FEX, 2014
  14678. */
  14679. /* global fio: true, jQuery: true */
  14680. (function(window, $) {
  14681. /**
  14682. * 保存应用的 Api Key
  14683. */
  14684. var apiKey;
  14685. /**
  14686. * 登录后会有 access_token,验证后保存的当前用户
  14687. *
  14688. * 因为 API 中的 access_token 都是下划线命名法,所以这里不用骆驼,免得混淆
  14689. */
  14690. var access_token, user;
  14691. /**
  14692. * 用到的 URL 地址
  14693. */
  14694. var urls = {
  14695. /**
  14696. * Baidu OAuth 2.0 授权地址
  14697. */
  14698. 'authorize': 'https://openapi.baidu.com/oauth/2.0/authorize',
  14699. /**
  14700. * 用户信息查询 API
  14701. */
  14702. 'getLoggedInUser': 'https://openapi.baidu.com/rest/2.0/passport/users/getLoggedInUser',
  14703. /**
  14704. * 当前 URL
  14705. */
  14706. 'current': window.location.href
  14707. };
  14708. /**
  14709. * 提供方的初始化方法
  14710. *
  14711. * @param {object} opt 选项
  14712. *
  14713. * opt.apiKey {string} 应用的 api key
  14714. *
  14715. */
  14716. function init(opt) {
  14717. apiKey = opt.apiKey || apiKey;
  14718. }
  14719. /**
  14720. * 网络请求
  14721. */
  14722. function ajax(opt) {
  14723. return new Promise(function(resolve, reject) {
  14724. $.ajax(opt).done(resolve).fail(reject);
  14725. });
  14726. }
  14727. /**
  14728. * 解析 URL 上传递的参数
  14729. * @return {object}
  14730. */
  14731. function urlFragment() {
  14732. var url = urls.current;
  14733. var pattern = /[&\?#](\w+?)=([^&]+)/g;
  14734. var fragment = {};
  14735. var match;
  14736. while ((match = pattern.exec(url))) fragment[match[1]] = match[2];
  14737. return fragment;
  14738. }
  14739. /**
  14740. * 从 Cookie 中读取应用对应的 access_key
  14741. */
  14742. function readAK() {
  14743. var cookie = document.cookie;
  14744. var pattern = new RegExp(apiKey + '_ak=(.*?)(;|$)');
  14745. var match = pattern.exec(cookie);
  14746. return match && decodeURIComponent(match[1]) || null;
  14747. }
  14748. /**
  14749. * 写入 access_key 到 cookie
  14750. */
  14751. function writeAK(ak, remember) {
  14752. var cookie = apiKey + '_ak=' + encodeURIComponent(ak);
  14753. cookie += '; max-age=' + (remember || 60);
  14754. document.cookie = cookie;
  14755. }
  14756. /**
  14757. * 清空 cookie 中对应的 ak
  14758. */
  14759. function clearAK() {
  14760. document.cookie = apiKey + '_ak=';
  14761. }
  14762. /**
  14763. * 返回当前用户
  14764. *
  14765. * @return {fio.user.User}
  14766. */
  14767. function current() {
  14768. return user;
  14769. }
  14770. /**
  14771. * 检查用户登录状态
  14772. *
  14773. * @return {Promise<fio.user.User>}
  14774. */
  14775. function check() {
  14776. // 缓存检测
  14777. if (user && +new Date() - user.validateTime < 60 * 60 * 1000) return Promise.resolve(user);
  14778. if (check.pendingRequest) return check.pendingRequest;
  14779. var fragment = urlFragment();
  14780. // 登录回调;会在参数上有 AK
  14781. if (fragment.access_token) {
  14782. // 把 AK 保存在 Cookie 里
  14783. writeAK(fragment.access_token, fragment.state);
  14784. // 清掉登录回调参数
  14785. document.location.href = urls.current.substr(0, document.location.href.indexOf('#'));
  14786. return (check.pendingRequest = new Promise(function() {}));
  14787. }
  14788. // 非登录回调,读取 AK
  14789. else {
  14790. // 尝试从 Cookie 读取 AK
  14791. access_token = readAK();
  14792. // 读取失败返回
  14793. if (!access_token) return Promise.resolve(null);
  14794. }
  14795. function getUserInfo() {
  14796. return new Promise(function(resolve, reject) {
  14797. // 超时重试
  14798. var resolved = false;
  14799. var timeouts = [1000, 2000, 3000];
  14800. var timer = 0;
  14801. function request() {
  14802. clearTimeout(timer);
  14803. if (!resolved && timeouts.length) {
  14804. timer = setTimeout(request, timeouts.shift());
  14805. }
  14806. return ajax({
  14807. url: urls.getLoggedInUser,
  14808. data: {
  14809. access_token: access_token
  14810. },
  14811. dataType: 'jsonp'
  14812. }).then(function(ret) {
  14813. clearTimeout(timer);
  14814. if (!resolved) resolve(ret);
  14815. resolved = true;
  14816. });
  14817. }
  14818. request();
  14819. });
  14820. }
  14821. // 使用 AK 获得用户信息
  14822. return check.pendingRequest = getUserInfo().then(function(ret) {
  14823. // 授权错误,可能是 AK 过时了
  14824. if (ret.error_code) {
  14825. access_token = null;
  14826. clearAK();
  14827. return null;
  14828. }
  14829. user = new fio.user.User(ret.uid, ret.uname);
  14830. user.smallImage = 'http://tb.himg.baidu.com/sys/portraitn/item/' + ret.portrait;
  14831. user.largeImage = 'http://tb.himg.baidu.com/sys/portrait/item/' + ret.portrait;
  14832. user.access_token = access_token;
  14833. user.validateTime = +new Date();
  14834. check.pendingRequest = null;
  14835. return user;
  14836. });
  14837. }
  14838. /**
  14839. * 登录,直接跳到百度授权登录页面
  14840. *
  14841. * @param {Object} opt 登录选项
  14842. *
  14843. * opt.force {boolean}
  14844. * 表示是否强制显示登录面板,而不是自动登录。默认为 false
  14845. *
  14846. * opt.remember {int}
  14847. * 表示是否记住用户登录状态,值表示记住的时间(秒)
  14848. */
  14849. function login(opt) {
  14850. window.location.href = urls.authorize + '?' + [
  14851. 'client_id=' + apiKey,
  14852. 'response_type=token',
  14853. 'scope=basic netdisk',
  14854. 'redirect_uri=' + (opt.redirectUrl || urls.current), // 调回到当前页面,check 的时候就能捕获 AK
  14855. 'display=page',
  14856. 'force_login=' + (opt && opt.force ? 1 : 0),
  14857. 'state=' + (opt.remember || 60) // remember second
  14858. ].join('&');
  14859. return new Promise(function() {}); // never fullfilled
  14860. }
  14861. /**
  14862. * 注销
  14863. * @return {[type]} [description]
  14864. */
  14865. function logout() {
  14866. var logouted = user;
  14867. user = null;
  14868. access_token = null;
  14869. clearAK();
  14870. return Promise.resolve(logouted);
  14871. }
  14872. // 用户系统实现
  14873. fio.user.impl({
  14874. check: check,
  14875. login: login,
  14876. logout: logout,
  14877. init: init,
  14878. current: current
  14879. });
  14880. })(window, jQuery);
  14881. /* global fio:true, jQuery: true */
  14882. /**
  14883. *
  14884. * @fileOverview
  14885. *
  14886. * 为 FIO 提供网盘 IO 支持
  14887. *
  14888. * @author techird
  14889. *
  14890. * 使用网盘的 IO,需要:
  14891. *
  14892. * 1. 在 http://dev.baidu.com 上创建应用。创建应用后,就有相应的 API Key
  14893. * 2. 设置登录回调地址为使用的页面,设置位置:其他API -> 安全设置
  14894. * 3. 申请 PCS API 权限
  14895. *
  14896. */
  14897. /* TODO: 脱离 jQuery 依赖 */
  14898. (function(window, $) {
  14899. /**
  14900. * 用到的 URL 地址
  14901. */
  14902. var urls = {
  14903. /**
  14904. * PCS API 接口
  14905. *
  14906. * @see http://developer.baidu.com/wiki/index.php?title=docs/pcs/rest/file_data_apis_list
  14907. */
  14908. 'file': 'https://pcs.baidu.com/rest/2.0/pcs/file'
  14909. };
  14910. /**
  14911. * 网络请求
  14912. */
  14913. function ajax(opt) {
  14914. opt.cache = false;
  14915. return new Promise(function(resolve, reject) {
  14916. $.ajax(opt).done(resolve).fail(reject);
  14917. });
  14918. }
  14919. /**
  14920. * 延时执行
  14921. */
  14922. function wait(delay) {
  14923. return new Promise(function(resolve) {
  14924. setTimeout(function() {
  14925. resolve();
  14926. }, delay);
  14927. });
  14928. }
  14929. // 转换 PCS 的文件数据为 fio.file.File
  14930. function pcs2file(pcs_file) {
  14931. var file = new fio.file.File(pcs_file.path);
  14932. file.createTime = new Date(pcs_file.ctime * 1000);
  14933. file.modifyTime = new Date(pcs_file.mtime * 1000);
  14934. file.size = pcs_file.size;
  14935. file.isDir = !!pcs_file.isdir;
  14936. file.provider = 'netdisk';
  14937. return file;
  14938. }
  14939. function getMeta(path) {
  14940. var user = fio.user.current();
  14941. var access_token = user && user.access_token;
  14942. if (!access_token) throw new Error('Not Authorized');
  14943. function request() {
  14944. return ajax({
  14945. url: urls.file,
  14946. data: {
  14947. method: 'meta',
  14948. access_token: access_token,
  14949. path: path
  14950. },
  14951. dataType: 'json'
  14952. })['catch'](function(e) {
  14953. if (request.retry++ > 2) throw e;
  14954. return new Promise(function(resolve) {
  14955. setTimeout(function() {
  14956. resolve(request());
  14957. }, 200 * request.retry);
  14958. });
  14959. });
  14960. }
  14961. request.retry = 0;
  14962. return request();
  14963. }
  14964. // 根据文件请求分发处理
  14965. function handle(request) {
  14966. var user = fio.user.current();
  14967. var access_token = user && user.access_token;
  14968. if (!access_token) throw new Error('Not Authorized');
  14969. var param = {};
  14970. // 默认参数
  14971. var opt = {
  14972. url: urls.file,
  14973. type: 'GET',
  14974. dataType: 'JSON'
  14975. };
  14976. // 处理其他参数
  14977. switch (request.method) {
  14978. case fio.file.METHOD_ACL_READ:
  14979. case fio.file.METHOD_ACL_WRITE:
  14980. throw new Error('Not Supported File Request:' + request.method);
  14981. case fio.file.METHOD_READ:
  14982. opt.dataType = request.dataType;
  14983. param.method = 'download';
  14984. break;
  14985. case fio.file.METHOD_WRITE:
  14986. opt.type = 'POST';
  14987. param.method = 'upload';
  14988. param.ondup = request.dupPolicy == fio.file.DUP_OVERWRITE ? 'overwrite' : 'newcopy';
  14989. var form = new FormData();
  14990. if (request.data.type == fio.file.TYPE_BLOB) {
  14991. form.append('file', request.data.content);
  14992. } else {
  14993. form.append('file', new Blob([request.data.content], {
  14994. type: 'text/plain'
  14995. }));
  14996. }
  14997. opt.data = form;
  14998. opt.processData = false;
  14999. opt.contentType = false;
  15000. break;
  15001. case fio.file.METHOD_LIST:
  15002. param.method = 'list';
  15003. break;
  15004. case fio.file.METHOD_MKDIR:
  15005. opt.type = 'POST';
  15006. param.method = 'mkdir';
  15007. break;
  15008. case fio.file.METHOD_MOVE:
  15009. opt.type = 'POST';
  15010. param.method = 'move';
  15011. param.to = request.newPath;
  15012. if (request.dupPolicy == fio.file.DUP_RENAME) {
  15013. param.ondup = 'newcopy';
  15014. }
  15015. break;
  15016. case fio.file.METHOD_DELETE:
  15017. opt.type = 'POST';
  15018. param.method = 'delete';
  15019. break;
  15020. }
  15021. // 处理 path 参数
  15022. if (request.method == fio.file.METHOD_MOVE) {
  15023. param.from = request.path;
  15024. } else {
  15025. param.path = request.path;
  15026. }
  15027. // 参数拼接到 URL 中
  15028. opt.url += '?' + $.param(param) + '&access_token=' + access_token;
  15029. // 重试次数
  15030. var retry = request.extra.retry === undefined ? 3 : parseInt(request.extra.retry, 10);
  15031. var failed = 0;
  15032. function tryRequest() {
  15033. // 捕捉到错误后重试或抛异常
  15034. function retryOrThrow(e) {
  15035. window.console.warn('PCS Fail(' + (++failed) + '): ', {
  15036. request: request,
  15037. error: e
  15038. });
  15039. if (retry--) {
  15040. return wait(1000 * failed).then(tryRequest);
  15041. } else {
  15042. e.requestMethod = request.method;
  15043. e.requestPath = request.path;
  15044. e.requestUser = request.user && request.user.username || null;
  15045. e.requestParam = param;
  15046. if (request.dataType)
  15047. e.requestDataType = request.dataType;
  15048. throw e;
  15049. }
  15050. }
  15051. function success(response) {
  15052. function meta2pcs(meta) {
  15053. return meta.list[0];
  15054. }
  15055. // 调用失败
  15056. if (response.error_code) {
  15057. throw new fio.FileRequestError(response);
  15058. }
  15059. // 读取操作需要抓取文件元数据后返回
  15060. if (request.method === fio.file.METHOD_READ) {
  15061. return getMeta(param.path).then(meta2pcs).then(pcs2file).then(function(file) {
  15062. file.data = new fio.file.Data(response);
  15063. return file;
  15064. });
  15065. }
  15066. // 列文件返回
  15067. if (request.method == fio.file.METHOD_LIST) {
  15068. return response.list.map(pcs2file);
  15069. }
  15070. // 移动文件返回
  15071. if (request.method == fio.file.METHOD_MOVE) {
  15072. return new Promise(function(resolve) {
  15073. setTimeout(function() {
  15074. resolve(getMeta(response.extra.list[0].to).then(meta2pcs).then(pcs2file));
  15075. }, 200);
  15076. });
  15077. }
  15078. // 删除文件返回
  15079. if (request.method == fio.file.METHOD_DELETE) {
  15080. return new fio.file.File(request.path);
  15081. }
  15082. var file = pcs2file(response);
  15083. // 写文件返回
  15084. if (request.method === fio.file.METHOD_WRITE) {
  15085. file.data = request.data;
  15086. }
  15087. return file;
  15088. }
  15089. function fail($xhr) {
  15090. var response = $xhr.responseText;
  15091. var responseInfo = {
  15092. readyState: $xhr.readyState,
  15093. status: $xhr.status,
  15094. statusText: $xhr.statusText,
  15095. headers: $xhr.getAllResponseHeaders(),
  15096. responseText: response
  15097. };
  15098. if (response) try {
  15099. responseInfo.detail = JSON.parse(response);
  15100. } catch (ignore) {}
  15101. return retryOrThrow(new fio.FileRequestError(responseInfo));
  15102. }
  15103. return ajax(opt).then(success, fail);
  15104. }
  15105. return tryRequest();
  15106. }
  15107. // 网盘 IO 提供实现
  15108. fio.provider.register('netdisk', {
  15109. handle: handle
  15110. });
  15111. })(window, jQuery);
  15112. /**
  15113. * marked - a markdown parser
  15114. * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
  15115. * https://github.com/chjj/marked
  15116. */
  15117. ;(function() {
  15118. /**
  15119. * Block-Level Grammar
  15120. */
  15121. var block = {
  15122. newline: /^\n+/,
  15123. code: /^( {4}[^\n]+\n*)+/,
  15124. fences: noop,
  15125. hr: /^( *[-*_]){3,} *(?:\n+|$)/,
  15126. heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
  15127. nptable: noop,
  15128. lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
  15129. blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
  15130. list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
  15131. html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
  15132. def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
  15133. table: noop,
  15134. paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
  15135. text: /^[^\n]+/
  15136. };
  15137. block.bullet = /(?:[*+-]|\d+\.)/;
  15138. block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
  15139. block.item = replace(block.item, 'gm')
  15140. (/bull/g, block.bullet)
  15141. ();
  15142. block.list = replace(block.list)
  15143. (/bull/g, block.bullet)
  15144. ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
  15145. ('def', '\\n+(?=' + block.def.source + ')')
  15146. ();
  15147. block.blockquote = replace(block.blockquote)
  15148. ('def', block.def)
  15149. ();
  15150. block._tag = '(?!(?:'
  15151. + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
  15152. + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
  15153. + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
  15154. block.html = replace(block.html)
  15155. ('comment', /<!--[\s\S]*?-->/)
  15156. ('closed', /<(tag)[\s\S]+?<\/\1>/)
  15157. ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
  15158. (/tag/g, block._tag)
  15159. ();
  15160. block.paragraph = replace(block.paragraph)
  15161. ('hr', block.hr)
  15162. ('heading', block.heading)
  15163. ('lheading', block.lheading)
  15164. ('blockquote', block.blockquote)
  15165. ('tag', '<' + block._tag)
  15166. ('def', block.def)
  15167. ();
  15168. /**
  15169. * Normal Block Grammar
  15170. */
  15171. block.normal = merge({}, block);
  15172. /**
  15173. * GFM Block Grammar
  15174. */
  15175. block.gfm = merge({}, block.normal, {
  15176. fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
  15177. paragraph: /^/
  15178. });
  15179. block.gfm.paragraph = replace(block.paragraph)
  15180. ('(?!', '(?!'
  15181. + block.gfm.fences.source.replace('\\1', '\\2') + '|'
  15182. + block.list.source.replace('\\1', '\\3') + '|')
  15183. ();
  15184. /**
  15185. * GFM + Tables Block Grammar
  15186. */
  15187. block.tables = merge({}, block.gfm, {
  15188. nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
  15189. table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
  15190. });
  15191. /**
  15192. * Block Lexer
  15193. */
  15194. function Lexer(options) {
  15195. this.tokens = [];
  15196. this.tokens.links = {};
  15197. this.options = options || marked.defaults;
  15198. this.rules = block.normal;
  15199. if (this.options.gfm) {
  15200. if (this.options.tables) {
  15201. this.rules = block.tables;
  15202. } else {
  15203. this.rules = block.gfm;
  15204. }
  15205. }
  15206. }
  15207. /**
  15208. * Expose Block Rules
  15209. */
  15210. Lexer.rules = block;
  15211. /**
  15212. * Static Lex Method
  15213. */
  15214. Lexer.lex = function(src, options) {
  15215. var lexer = new Lexer(options);
  15216. return lexer.lex(src);
  15217. };
  15218. /**
  15219. * Preprocessing
  15220. */
  15221. Lexer.prototype.lex = function(src) {
  15222. src = src
  15223. .replace(/\r\n|\r/g, '\n')
  15224. .replace(/\t/g, ' ')
  15225. .replace(/\u00a0/g, ' ')
  15226. .replace(/\u2424/g, '\n');
  15227. return this.token(src, true);
  15228. };
  15229. /**
  15230. * Lexing
  15231. */
  15232. Lexer.prototype.token = function(src, top, bq) {
  15233. var src = src.replace(/^ +$/gm, '')
  15234. , next
  15235. , loose
  15236. , cap
  15237. , bull
  15238. , b
  15239. , item
  15240. , space
  15241. , i
  15242. , l;
  15243. while (src) {
  15244. // newline
  15245. if (cap = this.rules.newline.exec(src)) {
  15246. src = src.substring(cap[0].length);
  15247. if (cap[0].length > 1) {
  15248. this.tokens.push({
  15249. type: 'space'
  15250. });
  15251. }
  15252. }
  15253. // code
  15254. if (cap = this.rules.code.exec(src)) {
  15255. src = src.substring(cap[0].length);
  15256. cap = cap[0].replace(/^ {4}/gm, '');
  15257. this.tokens.push({
  15258. type: 'code',
  15259. text: !this.options.pedantic
  15260. ? cap.replace(/\n+$/, '')
  15261. : cap
  15262. });
  15263. continue;
  15264. }
  15265. // fences (gfm)
  15266. if (cap = this.rules.fences.exec(src)) {
  15267. src = src.substring(cap[0].length);
  15268. this.tokens.push({
  15269. type: 'code',
  15270. lang: cap[2],
  15271. text: cap[3]
  15272. });
  15273. continue;
  15274. }
  15275. // heading
  15276. if (cap = this.rules.heading.exec(src)) {
  15277. src = src.substring(cap[0].length);
  15278. this.tokens.push({
  15279. type: 'heading',
  15280. depth: cap[1].length,
  15281. text: cap[2]
  15282. });
  15283. continue;
  15284. }
  15285. // table no leading pipe (gfm)
  15286. if (top && (cap = this.rules.nptable.exec(src))) {
  15287. src = src.substring(cap[0].length);
  15288. item = {
  15289. type: 'table',
  15290. header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
  15291. align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
  15292. cells: cap[3].replace(/\n$/, '').split('\n')
  15293. };
  15294. for (i = 0; i < item.align.length; i++) {
  15295. if (/^ *-+: *$/.test(item.align[i])) {
  15296. item.align[i] = 'right';
  15297. } else if (/^ *:-+: *$/.test(item.align[i])) {
  15298. item.align[i] = 'center';
  15299. } else if (/^ *:-+ *$/.test(item.align[i])) {
  15300. item.align[i] = 'left';
  15301. } else {
  15302. item.align[i] = null;
  15303. }
  15304. }
  15305. for (i = 0; i < item.cells.length; i++) {
  15306. item.cells[i] = item.cells[i].split(/ *\| */);
  15307. }
  15308. this.tokens.push(item);
  15309. continue;
  15310. }
  15311. // lheading
  15312. if (cap = this.rules.lheading.exec(src)) {
  15313. src = src.substring(cap[0].length);
  15314. this.tokens.push({
  15315. type: 'heading',
  15316. depth: cap[2] === '=' ? 1 : 2,
  15317. text: cap[1]
  15318. });
  15319. continue;
  15320. }
  15321. // hr
  15322. if (cap = this.rules.hr.exec(src)) {
  15323. src = src.substring(cap[0].length);
  15324. this.tokens.push({
  15325. type: 'hr'
  15326. });
  15327. continue;
  15328. }
  15329. // blockquote
  15330. if (cap = this.rules.blockquote.exec(src)) {
  15331. src = src.substring(cap[0].length);
  15332. this.tokens.push({
  15333. type: 'blockquote_start'
  15334. });
  15335. cap = cap[0].replace(/^ *> ?/gm, '');
  15336. // Pass `top` to keep the current
  15337. // "toplevel" state. This is exactly
  15338. // how markdown.pl works.
  15339. this.token(cap, top, true);
  15340. this.tokens.push({
  15341. type: 'blockquote_end'
  15342. });
  15343. continue;
  15344. }
  15345. // list
  15346. if (cap = this.rules.list.exec(src)) {
  15347. src = src.substring(cap[0].length);
  15348. bull = cap[2];
  15349. this.tokens.push({
  15350. type: 'list_start',
  15351. ordered: bull.length > 1
  15352. });
  15353. // Get each top-level item.
  15354. cap = cap[0].match(this.rules.item);
  15355. next = false;
  15356. l = cap.length;
  15357. i = 0;
  15358. for (; i < l; i++) {
  15359. item = cap[i];
  15360. // Remove the list item's bullet
  15361. // so it is seen as the next token.
  15362. space = item.length;
  15363. item = item.replace(/^ *([*+-]|\d+\.) +/, '');
  15364. // Outdent whatever the
  15365. // list item contains. Hacky.
  15366. if (~item.indexOf('\n ')) {
  15367. space -= item.length;
  15368. item = !this.options.pedantic
  15369. ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
  15370. : item.replace(/^ {1,4}/gm, '');
  15371. }
  15372. // Determine whether the next list item belongs here.
  15373. // Backpedal if it does not belong in this list.
  15374. if (this.options.smartLists && i !== l - 1) {
  15375. b = block.bullet.exec(cap[i + 1])[0];
  15376. if (bull !== b && !(bull.length > 1 && b.length > 1)) {
  15377. src = cap.slice(i + 1).join('\n') + src;
  15378. i = l - 1;
  15379. }
  15380. }
  15381. // Determine whether item is loose or not.
  15382. // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
  15383. // for discount behavior.
  15384. loose = next || /\n\n(?!\s*$)/.test(item);
  15385. if (i !== l - 1) {
  15386. next = item.charAt(item.length - 1) === '\n';
  15387. if (!loose) loose = next;
  15388. }
  15389. this.tokens.push({
  15390. type: loose
  15391. ? 'loose_item_start'
  15392. : 'list_item_start'
  15393. });
  15394. // Recurse.
  15395. this.token(item, false, bq);
  15396. this.tokens.push({
  15397. type: 'list_item_end'
  15398. });
  15399. }
  15400. this.tokens.push({
  15401. type: 'list_end'
  15402. });
  15403. continue;
  15404. }
  15405. // html
  15406. if (cap = this.rules.html.exec(src)) {
  15407. src = src.substring(cap[0].length);
  15408. this.tokens.push({
  15409. type: this.options.sanitize
  15410. ? 'paragraph'
  15411. : 'html',
  15412. pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
  15413. text: cap[0]
  15414. });
  15415. continue;
  15416. }
  15417. // def
  15418. if ((!bq && top) && (cap = this.rules.def.exec(src))) {
  15419. src = src.substring(cap[0].length);
  15420. this.tokens.links[cap[1].toLowerCase()] = {
  15421. href: cap[2],
  15422. title: cap[3]
  15423. };
  15424. continue;
  15425. }
  15426. // table (gfm)
  15427. if (top && (cap = this.rules.table.exec(src))) {
  15428. src = src.substring(cap[0].length);
  15429. item = {
  15430. type: 'table',
  15431. header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
  15432. align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
  15433. cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
  15434. };
  15435. for (i = 0; i < item.align.length; i++) {
  15436. if (/^ *-+: *$/.test(item.align[i])) {
  15437. item.align[i] = 'right';
  15438. } else if (/^ *:-+: *$/.test(item.align[i])) {
  15439. item.align[i] = 'center';
  15440. } else if (/^ *:-+ *$/.test(item.align[i])) {
  15441. item.align[i] = 'left';
  15442. } else {
  15443. item.align[i] = null;
  15444. }
  15445. }
  15446. for (i = 0; i < item.cells.length; i++) {
  15447. item.cells[i] = item.cells[i]
  15448. .replace(/^ *\| *| *\| *$/g, '')
  15449. .split(/ *\| */);
  15450. }
  15451. this.tokens.push(item);
  15452. continue;
  15453. }
  15454. // top-level paragraph
  15455. if (top && (cap = this.rules.paragraph.exec(src))) {
  15456. src = src.substring(cap[0].length);
  15457. this.tokens.push({
  15458. type: 'paragraph',
  15459. text: cap[1].charAt(cap[1].length - 1) === '\n'
  15460. ? cap[1].slice(0, -1)
  15461. : cap[1]
  15462. });
  15463. continue;
  15464. }
  15465. // text
  15466. if (cap = this.rules.text.exec(src)) {
  15467. // Top-level should never reach here.
  15468. src = src.substring(cap[0].length);
  15469. this.tokens.push({
  15470. type: 'text',
  15471. text: cap[0]
  15472. });
  15473. continue;
  15474. }
  15475. if (src) {
  15476. throw new
  15477. Error('Infinite loop on byte: ' + src.charCodeAt(0));
  15478. }
  15479. }
  15480. return this.tokens;
  15481. };
  15482. /**
  15483. * Inline-Level Grammar
  15484. */
  15485. var inline = {
  15486. escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
  15487. autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
  15488. url: noop,
  15489. tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
  15490. link: /^!?\[(inside)\]\(href\)/,
  15491. reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
  15492. nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
  15493. strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
  15494. em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
  15495. code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
  15496. br: /^ {2,}\n(?!\s*$)/,
  15497. del: noop,
  15498. text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
  15499. };
  15500. inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
  15501. inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
  15502. inline.link = replace(inline.link)
  15503. ('inside', inline._inside)
  15504. ('href', inline._href)
  15505. ();
  15506. inline.reflink = replace(inline.reflink)
  15507. ('inside', inline._inside)
  15508. ();
  15509. /**
  15510. * Normal Inline Grammar
  15511. */
  15512. inline.normal = merge({}, inline);
  15513. /**
  15514. * Pedantic Inline Grammar
  15515. */
  15516. inline.pedantic = merge({}, inline.normal, {
  15517. strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
  15518. em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
  15519. });
  15520. /**
  15521. * GFM Inline Grammar
  15522. */
  15523. inline.gfm = merge({}, inline.normal, {
  15524. escape: replace(inline.escape)('])', '~|])')(),
  15525. url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
  15526. del: /^~~(?=\S)([\s\S]*?\S)~~/,
  15527. text: replace(inline.text)
  15528. (']|', '~]|')
  15529. ('|', '|https?://|')
  15530. ()
  15531. });
  15532. /**
  15533. * GFM + Line Breaks Inline Grammar
  15534. */
  15535. inline.breaks = merge({}, inline.gfm, {
  15536. br: replace(inline.br)('{2,}', '*')(),
  15537. text: replace(inline.gfm.text)('{2,}', '*')()
  15538. });
  15539. /**
  15540. * Inline Lexer & Compiler
  15541. */
  15542. function InlineLexer(links, options) {
  15543. this.options = options || marked.defaults;
  15544. this.links = links;
  15545. this.rules = inline.normal;
  15546. this.renderer = this.options.renderer || new Renderer;
  15547. this.renderer.options = this.options;
  15548. if (!this.links) {
  15549. throw new
  15550. Error('Tokens array requires a `links` property.');
  15551. }
  15552. if (this.options.gfm) {
  15553. if (this.options.breaks) {
  15554. this.rules = inline.breaks;
  15555. } else {
  15556. this.rules = inline.gfm;
  15557. }
  15558. } else if (this.options.pedantic) {
  15559. this.rules = inline.pedantic;
  15560. }
  15561. }
  15562. /**
  15563. * Expose Inline Rules
  15564. */
  15565. InlineLexer.rules = inline;
  15566. /**
  15567. * Static Lexing/Compiling Method
  15568. */
  15569. InlineLexer.output = function(src, links, options) {
  15570. var inline = new InlineLexer(links, options);
  15571. return inline.output(src);
  15572. };
  15573. /**
  15574. * Lexing/Compiling
  15575. */
  15576. InlineLexer.prototype.output = function(src) {
  15577. var out = ''
  15578. , link
  15579. , text
  15580. , href
  15581. , cap;
  15582. while (src) {
  15583. // escape
  15584. if (cap = this.rules.escape.exec(src)) {
  15585. src = src.substring(cap[0].length);
  15586. out += cap[1];
  15587. continue;
  15588. }
  15589. // autolink
  15590. if (cap = this.rules.autolink.exec(src)) {
  15591. src = src.substring(cap[0].length);
  15592. if (cap[2] === '@') {
  15593. text = cap[1].charAt(6) === ':'
  15594. ? this.mangle(cap[1].substring(7))
  15595. : this.mangle(cap[1]);
  15596. href = this.mangle('mailto:') + text;
  15597. } else {
  15598. text = escape(cap[1]);
  15599. href = text;
  15600. }
  15601. out += this.renderer.link(href, null, text);
  15602. continue;
  15603. }
  15604. // url (gfm)
  15605. if (!this.inLink && (cap = this.rules.url.exec(src))) {
  15606. src = src.substring(cap[0].length);
  15607. text = escape(cap[1]);
  15608. href = text;
  15609. out += this.renderer.link(href, null, text);
  15610. continue;
  15611. }
  15612. // tag
  15613. if (cap = this.rules.tag.exec(src)) {
  15614. if (!this.inLink && /^<a /i.test(cap[0])) {
  15615. this.inLink = true;
  15616. } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
  15617. this.inLink = false;
  15618. }
  15619. src = src.substring(cap[0].length);
  15620. out += this.options.sanitize
  15621. ? escape(cap[0])
  15622. : cap[0];
  15623. continue;
  15624. }
  15625. // link
  15626. if (cap = this.rules.link.exec(src)) {
  15627. src = src.substring(cap[0].length);
  15628. this.inLink = true;
  15629. out += this.outputLink(cap, {
  15630. href: cap[2],
  15631. title: cap[3]
  15632. });
  15633. this.inLink = false;
  15634. continue;
  15635. }
  15636. // reflink, nolink
  15637. if ((cap = this.rules.reflink.exec(src))
  15638. || (cap = this.rules.nolink.exec(src))) {
  15639. src = src.substring(cap[0].length);
  15640. link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
  15641. link = this.links[link.toLowerCase()];
  15642. if (!link || !link.href) {
  15643. out += cap[0].charAt(0);
  15644. src = cap[0].substring(1) + src;
  15645. continue;
  15646. }
  15647. this.inLink = true;
  15648. out += this.outputLink(cap, link);
  15649. this.inLink = false;
  15650. continue;
  15651. }
  15652. // strong
  15653. if (cap = this.rules.strong.exec(src)) {
  15654. src = src.substring(cap[0].length);
  15655. out += this.renderer.strong(this.output(cap[2] || cap[1]));
  15656. continue;
  15657. }
  15658. // em
  15659. if (cap = this.rules.em.exec(src)) {
  15660. src = src.substring(cap[0].length);
  15661. out += this.renderer.em(this.output(cap[2] || cap[1]));
  15662. continue;
  15663. }
  15664. // code
  15665. if (cap = this.rules.code.exec(src)) {
  15666. src = src.substring(cap[0].length);
  15667. out += this.renderer.codespan(escape(cap[2], true));
  15668. continue;
  15669. }
  15670. // br
  15671. if (cap = this.rules.br.exec(src)) {
  15672. src = src.substring(cap[0].length);
  15673. out += this.renderer.br();
  15674. continue;
  15675. }
  15676. // del (gfm)
  15677. if (cap = this.rules.del.exec(src)) {
  15678. src = src.substring(cap[0].length);
  15679. out += this.renderer.del(this.output(cap[1]));
  15680. continue;
  15681. }
  15682. // text
  15683. if (cap = this.rules.text.exec(src)) {
  15684. src = src.substring(cap[0].length);
  15685. out += escape(this.smartypants(cap[0]));
  15686. continue;
  15687. }
  15688. if (src) {
  15689. throw new
  15690. Error('Infinite loop on byte: ' + src.charCodeAt(0));
  15691. }
  15692. }
  15693. return out;
  15694. };
  15695. /**
  15696. * Compile Link
  15697. */
  15698. InlineLexer.prototype.outputLink = function(cap, link) {
  15699. var href = escape(link.href)
  15700. , title = link.title ? escape(link.title) : null;
  15701. return cap[0].charAt(0) !== '!'
  15702. ? this.renderer.link(href, title, this.output(cap[1]))
  15703. : this.renderer.image(href, title, escape(cap[1]));
  15704. };
  15705. /**
  15706. * Smartypants Transformations
  15707. */
  15708. InlineLexer.prototype.smartypants = function(text) {
  15709. if (!this.options.smartypants) return text;
  15710. return text
  15711. // em-dashes
  15712. .replace(/--/g, '\u2014')
  15713. // opening singles
  15714. .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
  15715. // closing singles & apostrophes
  15716. .replace(/'/g, '\u2019')
  15717. // opening doubles
  15718. .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
  15719. // closing doubles
  15720. .replace(/"/g, '\u201d')
  15721. // ellipses
  15722. .replace(/\.{3}/g, '\u2026');
  15723. };
  15724. /**
  15725. * Mangle Links
  15726. */
  15727. InlineLexer.prototype.mangle = function(text) {
  15728. var out = ''
  15729. , l = text.length
  15730. , i = 0
  15731. , ch;
  15732. for (; i < l; i++) {
  15733. ch = text.charCodeAt(i);
  15734. if (Math.random() > 0.5) {
  15735. ch = 'x' + ch.toString(16);
  15736. }
  15737. out += '&#' + ch + ';';
  15738. }
  15739. return out;
  15740. };
  15741. /**
  15742. * Renderer
  15743. */
  15744. function Renderer(options) {
  15745. this.options = options || {};
  15746. }
  15747. Renderer.prototype.code = function(code, lang, escaped) {
  15748. if (this.options.highlight) {
  15749. var out = this.options.highlight(code, lang);
  15750. if (out != null && out !== code) {
  15751. escaped = true;
  15752. code = out;
  15753. }
  15754. }
  15755. if (!lang) {
  15756. return '<pre><code>'
  15757. + (escaped ? code : escape(code, true))
  15758. + '\n</code></pre>';
  15759. }
  15760. return '<pre><code class="'
  15761. + this.options.langPrefix
  15762. + escape(lang, true)
  15763. + '">'
  15764. + (escaped ? code : escape(code, true))
  15765. + '\n</code></pre>\n';
  15766. };
  15767. Renderer.prototype.blockquote = function(quote) {
  15768. return '<blockquote>\n' + quote + '</blockquote>\n';
  15769. };
  15770. Renderer.prototype.html = function(html) {
  15771. return html;
  15772. };
  15773. Renderer.prototype.heading = function(text, level, raw) {
  15774. return '<h'
  15775. + level
  15776. + ' id="'
  15777. + this.options.headerPrefix
  15778. + raw.toLowerCase().replace(/[^\w]+/g, '-')
  15779. + '">'
  15780. + text
  15781. + '</h'
  15782. + level
  15783. + '>\n';
  15784. };
  15785. Renderer.prototype.hr = function() {
  15786. return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
  15787. };
  15788. Renderer.prototype.list = function(body, ordered) {
  15789. var type = ordered ? 'ol' : 'ul';
  15790. return '<' + type + '>\n' + body + '</' + type + '>\n';
  15791. };
  15792. Renderer.prototype.listitem = function(text) {
  15793. return '<li>' + text + '</li>\n';
  15794. };
  15795. Renderer.prototype.paragraph = function(text) {
  15796. return '<p>' + text + '</p>\n';
  15797. };
  15798. Renderer.prototype.table = function(header, body) {
  15799. return '<table>\n'
  15800. + '<thead>\n'
  15801. + header
  15802. + '</thead>\n'
  15803. + '<tbody>\n'
  15804. + body
  15805. + '</tbody>\n'
  15806. + '</table>\n';
  15807. };
  15808. Renderer.prototype.tablerow = function(content) {
  15809. return '<tr>\n' + content + '</tr>\n';
  15810. };
  15811. Renderer.prototype.tablecell = function(content, flags) {
  15812. var type = flags.header ? 'th' : 'td';
  15813. var tag = flags.align
  15814. ? '<' + type + ' style="text-align:' + flags.align + '">'
  15815. : '<' + type + '>';
  15816. return tag + content + '</' + type + '>\n';
  15817. };
  15818. // span level renderer
  15819. Renderer.prototype.strong = function(text) {
  15820. return '<strong>' + text + '</strong>';
  15821. };
  15822. Renderer.prototype.em = function(text) {
  15823. return '<em>' + text + '</em>';
  15824. };
  15825. Renderer.prototype.codespan = function(text) {
  15826. return '<code>' + text + '</code>';
  15827. };
  15828. Renderer.prototype.br = function() {
  15829. return this.options.xhtml ? '<br/>' : '<br>';
  15830. };
  15831. Renderer.prototype.del = function(text) {
  15832. return '<del>' + text + '</del>';
  15833. };
  15834. Renderer.prototype.link = function(href, title, text) {
  15835. if (this.options.sanitize) {
  15836. try {
  15837. var prot = decodeURIComponent(unescape(href))
  15838. .replace(/[^\w:]/g, '')
  15839. .toLowerCase();
  15840. } catch (e) {
  15841. return '';
  15842. }
  15843. if (prot.indexOf('javascript:') === 0) {
  15844. return '';
  15845. }
  15846. }
  15847. var out = '<a href="' + href + '"';
  15848. if (title) {
  15849. out += ' title="' + title + '"';
  15850. }
  15851. out += '>' + text + '</a>';
  15852. return out;
  15853. };
  15854. Renderer.prototype.image = function(href, title, text) {
  15855. var out = '<img src="' + href + '" alt="' + text + '"';
  15856. if (title) {
  15857. out += ' title="' + title + '"';
  15858. }
  15859. out += this.options.xhtml ? '/>' : '>';
  15860. return out;
  15861. };
  15862. /**
  15863. * Parsing & Compiling
  15864. */
  15865. function Parser(options) {
  15866. this.tokens = [];
  15867. this.token = null;
  15868. this.options = options || marked.defaults;
  15869. this.options.renderer = this.options.renderer || new Renderer;
  15870. this.renderer = this.options.renderer;
  15871. this.renderer.options = this.options;
  15872. }
  15873. /**
  15874. * Static Parse Method
  15875. */
  15876. Parser.parse = function(src, options, renderer) {
  15877. var parser = new Parser(options, renderer);
  15878. return parser.parse(src);
  15879. };
  15880. /**
  15881. * Parse Loop
  15882. */
  15883. Parser.prototype.parse = function(src) {
  15884. this.inline = new InlineLexer(src.links, this.options, this.renderer);
  15885. this.tokens = src.reverse();
  15886. var out = '';
  15887. while (this.next()) {
  15888. out += this.tok();
  15889. }
  15890. return out;
  15891. };
  15892. /**
  15893. * Next Token
  15894. */
  15895. Parser.prototype.next = function() {
  15896. return this.token = this.tokens.pop();
  15897. };
  15898. /**
  15899. * Preview Next Token
  15900. */
  15901. Parser.prototype.peek = function() {
  15902. return this.tokens[this.tokens.length - 1] || 0;
  15903. };
  15904. /**
  15905. * Parse Text Tokens
  15906. */
  15907. Parser.prototype.parseText = function() {
  15908. var body = this.token.text;
  15909. while (this.peek().type === 'text') {
  15910. body += '\n' + this.next().text;
  15911. }
  15912. return this.inline.output(body);
  15913. };
  15914. /**
  15915. * Parse Current Token
  15916. */
  15917. Parser.prototype.tok = function() {
  15918. switch (this.token.type) {
  15919. case 'space': {
  15920. return '';
  15921. }
  15922. case 'hr': {
  15923. return this.renderer.hr();
  15924. }
  15925. case 'heading': {
  15926. return this.renderer.heading(
  15927. this.inline.output(this.token.text),
  15928. this.token.depth,
  15929. this.token.text);
  15930. }
  15931. case 'code': {
  15932. return this.renderer.code(this.token.text,
  15933. this.token.lang,
  15934. this.token.escaped);
  15935. }
  15936. case 'table': {
  15937. var header = ''
  15938. , body = ''
  15939. , i
  15940. , row
  15941. , cell
  15942. , flags
  15943. , j;
  15944. // header
  15945. cell = '';
  15946. for (i = 0; i < this.token.header.length; i++) {
  15947. flags = { header: true, align: this.token.align[i] };
  15948. cell += this.renderer.tablecell(
  15949. this.inline.output(this.token.header[i]),
  15950. { header: true, align: this.token.align[i] }
  15951. );
  15952. }
  15953. header += this.renderer.tablerow(cell);
  15954. for (i = 0; i < this.token.cells.length; i++) {
  15955. row = this.token.cells[i];
  15956. cell = '';
  15957. for (j = 0; j < row.length; j++) {
  15958. cell += this.renderer.tablecell(
  15959. this.inline.output(row[j]),
  15960. { header: false, align: this.token.align[j] }
  15961. );
  15962. }
  15963. body += this.renderer.tablerow(cell);
  15964. }
  15965. return this.renderer.table(header, body);
  15966. }
  15967. case 'blockquote_start': {
  15968. var body = '';
  15969. while (this.next().type !== 'blockquote_end') {
  15970. body += this.tok();
  15971. }
  15972. return this.renderer.blockquote(body);
  15973. }
  15974. case 'list_start': {
  15975. var body = ''
  15976. , ordered = this.token.ordered;
  15977. while (this.next().type !== 'list_end') {
  15978. body += this.tok();
  15979. }
  15980. return this.renderer.list(body, ordered);
  15981. }
  15982. case 'list_item_start': {
  15983. var body = '';
  15984. while (this.next().type !== 'list_item_end') {
  15985. body += this.token.type === 'text'
  15986. ? this.parseText()
  15987. : this.tok();
  15988. }
  15989. return this.renderer.listitem(body);
  15990. }
  15991. case 'loose_item_start': {
  15992. var body = '';
  15993. while (this.next().type !== 'list_item_end') {
  15994. body += this.tok();
  15995. }
  15996. return this.renderer.listitem(body);
  15997. }
  15998. case 'html': {
  15999. var html = !this.token.pre && !this.options.pedantic
  16000. ? this.inline.output(this.token.text)
  16001. : this.token.text;
  16002. return this.renderer.html(html);
  16003. }
  16004. case 'paragraph': {
  16005. return this.renderer.paragraph(this.inline.output(this.token.text));
  16006. }
  16007. case 'text': {
  16008. return this.renderer.paragraph(this.parseText());
  16009. }
  16010. }
  16011. };
  16012. /**
  16013. * Helpers
  16014. */
  16015. function escape(html, encode) {
  16016. return html
  16017. .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
  16018. .replace(/</g, '&lt;')
  16019. .replace(/>/g, '&gt;')
  16020. .replace(/"/g, '&quot;')
  16021. .replace(/'/g, '&#39;');
  16022. }
  16023. function unescape(html) {
  16024. return html.replace(/&([#\w]+);/g, function(_, n) {
  16025. n = n.toLowerCase();
  16026. if (n === 'colon') return ':';
  16027. if (n.charAt(0) === '#') {
  16028. return n.charAt(1) === 'x'
  16029. ? String.fromCharCode(parseInt(n.substring(2), 16))
  16030. : String.fromCharCode(+n.substring(1));
  16031. }
  16032. return '';
  16033. });
  16034. }
  16035. function replace(regex, opt) {
  16036. regex = regex.source;
  16037. opt = opt || '';
  16038. return function self(name, val) {
  16039. if (!name) return new RegExp(regex, opt);
  16040. val = val.source || val;
  16041. val = val.replace(/(^|[^\[])\^/g, '$1');
  16042. regex = regex.replace(name, val);
  16043. return self;
  16044. };
  16045. }
  16046. function noop() {}
  16047. noop.exec = noop;
  16048. function merge(obj) {
  16049. var i = 1
  16050. , target
  16051. , key;
  16052. for (; i < arguments.length; i++) {
  16053. target = arguments[i];
  16054. for (key in target) {
  16055. if (Object.prototype.hasOwnProperty.call(target, key)) {
  16056. obj[key] = target[key];
  16057. }
  16058. }
  16059. }
  16060. return obj;
  16061. }
  16062. /**
  16063. * Marked
  16064. */
  16065. function marked(src, opt, callback) {
  16066. if (callback || typeof opt === 'function') {
  16067. if (!callback) {
  16068. callback = opt;
  16069. opt = null;
  16070. }
  16071. opt = merge({}, marked.defaults, opt || {});
  16072. var highlight = opt.highlight
  16073. , tokens
  16074. , pending
  16075. , i = 0;
  16076. try {
  16077. tokens = Lexer.lex(src, opt)
  16078. } catch (e) {
  16079. return callback(e);
  16080. }
  16081. pending = tokens.length;
  16082. var done = function(err) {
  16083. if (err) {
  16084. opt.highlight = highlight;
  16085. return callback(err);
  16086. }
  16087. var out;
  16088. try {
  16089. out = Parser.parse(tokens, opt);
  16090. } catch (e) {
  16091. err = e;
  16092. }
  16093. opt.highlight = highlight;
  16094. return err
  16095. ? callback(err)
  16096. : callback(null, out);
  16097. };
  16098. if (!highlight || highlight.length < 3) {
  16099. return done();
  16100. }
  16101. delete opt.highlight;
  16102. if (!pending) return done();
  16103. for (; i < tokens.length; i++) {
  16104. (function(token) {
  16105. if (token.type !== 'code') {
  16106. return --pending || done();
  16107. }
  16108. return highlight(token.text, token.lang, function(err, code) {
  16109. if (err) return done(err);
  16110. if (code == null || code === token.text) {
  16111. return --pending || done();
  16112. }
  16113. token.text = code;
  16114. token.escaped = true;
  16115. --pending || done();
  16116. });
  16117. })(tokens[i]);
  16118. }
  16119. return;
  16120. }
  16121. try {
  16122. if (opt) opt = merge({}, marked.defaults, opt);
  16123. return Parser.parse(Lexer.lex(src, opt), opt);
  16124. } catch (e) {
  16125. e.message += '\nPlease report this to https://github.com/chjj/marked.';
  16126. if ((opt || marked.defaults).silent) {
  16127. return '<p>An error occured:</p><pre>'
  16128. + escape(e.message + '', true)
  16129. + '</pre>';
  16130. }
  16131. throw e;
  16132. }
  16133. }
  16134. /**
  16135. * Options
  16136. */
  16137. marked.options =
  16138. marked.setOptions = function(opt) {
  16139. merge(marked.defaults, opt);
  16140. return marked;
  16141. };
  16142. marked.defaults = {
  16143. gfm: true,
  16144. tables: true,
  16145. breaks: false,
  16146. pedantic: false,
  16147. sanitize: false,
  16148. smartLists: false,
  16149. silent: false,
  16150. highlight: null,
  16151. langPrefix: 'lang-',
  16152. smartypants: false,
  16153. headerPrefix: '',
  16154. renderer: new Renderer,
  16155. xhtml: false
  16156. };
  16157. /**
  16158. * Expose
  16159. */
  16160. marked.Parser = Parser;
  16161. marked.parser = Parser.parse;
  16162. marked.Renderer = Renderer;
  16163. marked.Lexer = Lexer;
  16164. marked.lexer = Lexer.lex;
  16165. marked.InlineLexer = InlineLexer;
  16166. marked.inlineLexer = InlineLexer.output;
  16167. marked.parse = marked;
  16168. if (typeof module !== 'undefined' && typeof exports === 'object') {
  16169. module.exports = marked;
  16170. } else if (typeof define === 'function' && define.amd) {
  16171. define(function() { return marked; });
  16172. } else {
  16173. this.marked = marked;
  16174. }
  16175. }).call(function() {
  16176. return this || (typeof window !== 'undefined' ? window : global);
  16177. }());
  16178. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  16179. // Distributed under an MIT license: http://codemirror.net/LICENSE
  16180. // This is CodeMirror (http://codemirror.net), a code editor
  16181. // implemented in JavaScript on top of the browser's DOM.
  16182. //
  16183. // You can find some technical background for some of the code below
  16184. // at http://marijnhaverbeke.nl/blog/#cm-internals .
  16185. (function(mod) {
  16186. if (typeof exports == "object" && typeof module == "object") // CommonJS
  16187. module.exports = mod();
  16188. else if (typeof define == "function" && define.amd) // AMD
  16189. return define([], mod);
  16190. else // Plain browser env
  16191. this.CodeMirror = mod();
  16192. })(function() {
  16193. "use strict";
  16194. // BROWSER SNIFFING
  16195. // Kludges for bugs and behavior differences that can't be feature
  16196. // detected are enabled based on userAgent etc sniffing.
  16197. var gecko = /gecko\/\d/i.test(navigator.userAgent);
  16198. // ie_uptoN means Internet Explorer version N or lower
  16199. var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
  16200. var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
  16201. var ie = ie_upto10 || ie_11up;
  16202. var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
  16203. var webkit = /WebKit\//.test(navigator.userAgent);
  16204. var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
  16205. var chrome = /Chrome\//.test(navigator.userAgent);
  16206. var presto = /Opera\//.test(navigator.userAgent);
  16207. var safari = /Apple Computer/.test(navigator.vendor);
  16208. var khtml = /KHTML\//.test(navigator.userAgent);
  16209. var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
  16210. var phantom = /PhantomJS/.test(navigator.userAgent);
  16211. var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
  16212. // This is woefully incomplete. Suggestions for alternative methods welcome.
  16213. var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
  16214. var mac = ios || /Mac/.test(navigator.platform);
  16215. var windows = /win/i.test(navigator.platform);
  16216. var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
  16217. if (presto_version) presto_version = Number(presto_version[1]);
  16218. if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
  16219. // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
  16220. var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
  16221. var captureRightClick = gecko || (ie && ie_version >= 9);
  16222. // Optimize some code when these features are not used.
  16223. var sawReadOnlySpans = false, sawCollapsedSpans = false;
  16224. // EDITOR CONSTRUCTOR
  16225. // A CodeMirror instance represents an editor. This is the object
  16226. // that user code is usually dealing with.
  16227. function CodeMirror(place, options) {
  16228. if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
  16229. this.options = options = options ? copyObj(options) : {};
  16230. // Determine effective options based on given values and defaults.
  16231. copyObj(defaults, options, false);
  16232. setGuttersForLineNumbers(options);
  16233. var doc = options.value;
  16234. if (typeof doc == "string") doc = new Doc(doc, options.mode);
  16235. this.doc = doc;
  16236. var display = this.display = new Display(place, doc);
  16237. display.wrapper.CodeMirror = this;
  16238. updateGutters(this);
  16239. themeChanged(this);
  16240. if (options.lineWrapping)
  16241. this.display.wrapper.className += " CodeMirror-wrap";
  16242. if (options.autofocus && !mobile) focusInput(this);
  16243. this.state = {
  16244. keyMaps: [], // stores maps added by addKeyMap
  16245. overlays: [], // highlighting overlays, as added by addOverlay
  16246. modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
  16247. overwrite: false, focused: false,
  16248. suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
  16249. pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in readInput
  16250. draggingText: false,
  16251. highlight: new Delayed() // stores highlight worker timeout
  16252. };
  16253. // Override magic textarea content restore that IE sometimes does
  16254. // on our hidden textarea on reload
  16255. if (ie && ie_version < 11) setTimeout(bind(resetInput, this, true), 20);
  16256. registerEventHandlers(this);
  16257. ensureGlobalHandlers();
  16258. startOperation(this);
  16259. this.curOp.forceUpdate = true;
  16260. attachDoc(this, doc);
  16261. if ((options.autofocus && !mobile) || activeElt() == display.input)
  16262. setTimeout(bind(onFocus, this), 20);
  16263. else
  16264. onBlur(this);
  16265. for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
  16266. optionHandlers[opt](this, options[opt], Init);
  16267. maybeUpdateLineNumberWidth(this);
  16268. for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
  16269. endOperation(this);
  16270. }
  16271. // DISPLAY CONSTRUCTOR
  16272. // The display handles the DOM integration, both for input reading
  16273. // and content drawing. It holds references to DOM nodes and
  16274. // display-related state.
  16275. function Display(place, doc) {
  16276. var d = this;
  16277. // The semihidden textarea that is focused when the editor is
  16278. // focused, and receives input.
  16279. var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
  16280. // The textarea is kept positioned near the cursor to prevent the
  16281. // fact that it'll be scrolled into view on input from scrolling
  16282. // our fake cursor out of view. On webkit, when wrap=off, paste is
  16283. // very slow. So make the area wide instead.
  16284. if (webkit) input.style.width = "1000px";
  16285. else input.setAttribute("wrap", "off");
  16286. // If border: 0; -- iOS fails to open keyboard (issue #1287)
  16287. if (ios) input.style.border = "1px solid black";
  16288. input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false");
  16289. // Wraps and hides input textarea
  16290. d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
  16291. // The fake scrollbar elements.
  16292. d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
  16293. d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
  16294. // Covers bottom-right square when both scrollbars are present.
  16295. d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
  16296. // Covers bottom of gutter when coverGutterNextToScrollbar is on
  16297. // and h scrollbar is present.
  16298. d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
  16299. // Will contain the actual code, positioned to cover the viewport.
  16300. d.lineDiv = elt("div", null, "CodeMirror-code");
  16301. // Elements are added to these to represent selection and cursors.
  16302. d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
  16303. d.cursorDiv = elt("div", null, "CodeMirror-cursors");
  16304. // A visibility: hidden element used to find the size of things.
  16305. d.measure = elt("div", null, "CodeMirror-measure");
  16306. // When lines outside of the viewport are measured, they are drawn in this.
  16307. d.lineMeasure = elt("div", null, "CodeMirror-measure");
  16308. // Wraps everything that needs to exist inside the vertically-padded coordinate system
  16309. d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
  16310. null, "position: relative; outline: none");
  16311. // Moved around its parent to cover visible view.
  16312. d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
  16313. // Set to the height of the document, allowing scrolling.
  16314. d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
  16315. // Behavior of elts with overflow: auto and padding is
  16316. // inconsistent across browsers. This is used to ensure the
  16317. // scrollable area is big enough.
  16318. d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
  16319. // Will contain the gutters, if any.
  16320. d.gutters = elt("div", null, "CodeMirror-gutters");
  16321. d.lineGutter = null;
  16322. // Actual scrollable element.
  16323. d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
  16324. d.scroller.setAttribute("tabIndex", "-1");
  16325. // The element in which the editor lives.
  16326. d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
  16327. d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
  16328. // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
  16329. if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
  16330. // Needed to hide big blue blinking cursor on Mobile Safari
  16331. if (ios) input.style.width = "0px";
  16332. if (!webkit) d.scroller.draggable = true;
  16333. // Needed to handle Tab key in KHTML
  16334. if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
  16335. // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
  16336. if (ie && ie_version < 8) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px";
  16337. if (place.appendChild) place.appendChild(d.wrapper);
  16338. else place(d.wrapper);
  16339. // Current rendered range (may be bigger than the view window).
  16340. d.viewFrom = d.viewTo = doc.first;
  16341. // Information about the rendered lines.
  16342. d.view = [];
  16343. // Holds info about a single rendered line when it was rendered
  16344. // for measurement, while not in view.
  16345. d.externalMeasured = null;
  16346. // Empty space (in pixels) above the view
  16347. d.viewOffset = 0;
  16348. d.lastSizeC = 0;
  16349. d.updateLineNumbers = null;
  16350. // Used to only resize the line number gutter when necessary (when
  16351. // the amount of lines crosses a boundary that makes its width change)
  16352. d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
  16353. // See readInput and resetInput
  16354. d.prevInput = "";
  16355. // Set to true when a non-horizontal-scrolling line widget is
  16356. // added. As an optimization, line widget aligning is skipped when
  16357. // this is false.
  16358. d.alignWidgets = false;
  16359. // Flag that indicates whether we expect input to appear real soon
  16360. // now (after some event like 'keypress' or 'input') and are
  16361. // polling intensively.
  16362. d.pollingFast = false;
  16363. // Self-resetting timeout for the poller
  16364. d.poll = new Delayed();
  16365. d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
  16366. // Tracks when resetInput has punted to just putting a short
  16367. // string into the textarea instead of the full selection.
  16368. d.inaccurateSelection = false;
  16369. // Tracks the maximum line length so that the horizontal scrollbar
  16370. // can be kept static when scrolling.
  16371. d.maxLine = null;
  16372. d.maxLineLength = 0;
  16373. d.maxLineChanged = false;
  16374. // Used for measuring wheel scrolling granularity
  16375. d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
  16376. // True when shift is held down.
  16377. d.shift = false;
  16378. // Used to track whether anything happened since the context menu
  16379. // was opened.
  16380. d.selForContextMenu = null;
  16381. }
  16382. // STATE UPDATES
  16383. // Used to get the editor into a consistent state again when options change.
  16384. function loadMode(cm) {
  16385. cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
  16386. resetModeState(cm);
  16387. }
  16388. function resetModeState(cm) {
  16389. cm.doc.iter(function(line) {
  16390. if (line.stateAfter) line.stateAfter = null;
  16391. if (line.styles) line.styles = null;
  16392. });
  16393. cm.doc.frontier = cm.doc.first;
  16394. startWorker(cm, 100);
  16395. cm.state.modeGen++;
  16396. if (cm.curOp) regChange(cm);
  16397. }
  16398. function wrappingChanged(cm) {
  16399. if (cm.options.lineWrapping) {
  16400. addClass(cm.display.wrapper, "CodeMirror-wrap");
  16401. cm.display.sizer.style.minWidth = "";
  16402. } else {
  16403. rmClass(cm.display.wrapper, "CodeMirror-wrap");
  16404. findMaxLine(cm);
  16405. }
  16406. estimateLineHeights(cm);
  16407. regChange(cm);
  16408. clearCaches(cm);
  16409. setTimeout(function(){updateScrollbars(cm);}, 100);
  16410. }
  16411. // Returns a function that estimates the height of a line, to use as
  16412. // first approximation until the line becomes visible (and is thus
  16413. // properly measurable).
  16414. function estimateHeight(cm) {
  16415. var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
  16416. var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
  16417. return function(line) {
  16418. if (lineIsHidden(cm.doc, line)) return 0;
  16419. var widgetsHeight = 0;
  16420. if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
  16421. if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
  16422. }
  16423. if (wrapping)
  16424. return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
  16425. else
  16426. return widgetsHeight + th;
  16427. };
  16428. }
  16429. function estimateLineHeights(cm) {
  16430. var doc = cm.doc, est = estimateHeight(cm);
  16431. doc.iter(function(line) {
  16432. var estHeight = est(line);
  16433. if (estHeight != line.height) updateLineHeight(line, estHeight);
  16434. });
  16435. }
  16436. function keyMapChanged(cm) {
  16437. var map = keyMap[cm.options.keyMap], style = map.style;
  16438. cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
  16439. (style ? " cm-keymap-" + style : "");
  16440. }
  16441. function themeChanged(cm) {
  16442. cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
  16443. cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
  16444. clearCaches(cm);
  16445. }
  16446. function guttersChanged(cm) {
  16447. updateGutters(cm);
  16448. regChange(cm);
  16449. setTimeout(function(){alignHorizontally(cm);}, 20);
  16450. }
  16451. // Rebuild the gutter elements, ensure the margin to the left of the
  16452. // code matches their width.
  16453. function updateGutters(cm) {
  16454. var gutters = cm.display.gutters, specs = cm.options.gutters;
  16455. removeChildren(gutters);
  16456. for (var i = 0; i < specs.length; ++i) {
  16457. var gutterClass = specs[i];
  16458. var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
  16459. if (gutterClass == "CodeMirror-linenumbers") {
  16460. cm.display.lineGutter = gElt;
  16461. gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
  16462. }
  16463. }
  16464. gutters.style.display = i ? "" : "none";
  16465. updateGutterSpace(cm);
  16466. }
  16467. function updateGutterSpace(cm) {
  16468. var width = cm.display.gutters.offsetWidth;
  16469. cm.display.sizer.style.marginLeft = width + "px";
  16470. cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
  16471. }
  16472. // Compute the character length of a line, taking into account
  16473. // collapsed ranges (see markText) that might hide parts, and join
  16474. // other lines onto it.
  16475. function lineLength(line) {
  16476. if (line.height == 0) return 0;
  16477. var len = line.text.length, merged, cur = line;
  16478. while (merged = collapsedSpanAtStart(cur)) {
  16479. var found = merged.find(0, true);
  16480. cur = found.from.line;
  16481. len += found.from.ch - found.to.ch;
  16482. }
  16483. cur = line;
  16484. while (merged = collapsedSpanAtEnd(cur)) {
  16485. var found = merged.find(0, true);
  16486. len -= cur.text.length - found.from.ch;
  16487. cur = found.to.line;
  16488. len += cur.text.length - found.to.ch;
  16489. }
  16490. return len;
  16491. }
  16492. // Find the longest line in the document.
  16493. function findMaxLine(cm) {
  16494. var d = cm.display, doc = cm.doc;
  16495. d.maxLine = getLine(doc, doc.first);
  16496. d.maxLineLength = lineLength(d.maxLine);
  16497. d.maxLineChanged = true;
  16498. doc.iter(function(line) {
  16499. var len = lineLength(line);
  16500. if (len > d.maxLineLength) {
  16501. d.maxLineLength = len;
  16502. d.maxLine = line;
  16503. }
  16504. });
  16505. }
  16506. // Make sure the gutters options contains the element
  16507. // "CodeMirror-linenumbers" when the lineNumbers option is true.
  16508. function setGuttersForLineNumbers(options) {
  16509. var found = indexOf(options.gutters, "CodeMirror-linenumbers");
  16510. if (found == -1 && options.lineNumbers) {
  16511. options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
  16512. } else if (found > -1 && !options.lineNumbers) {
  16513. options.gutters = options.gutters.slice(0);
  16514. options.gutters.splice(found, 1);
  16515. }
  16516. }
  16517. // SCROLLBARS
  16518. function hScrollbarTakesSpace(cm) {
  16519. return cm.display.scroller.clientHeight - cm.display.wrapper.clientHeight < scrollerCutOff - 3;
  16520. }
  16521. // Prepare DOM reads needed to update the scrollbars. Done in one
  16522. // shot to minimize update/measure roundtrips.
  16523. function measureForScrollbars(cm) {
  16524. var scroll = cm.display.scroller;
  16525. return {
  16526. clientHeight: scroll.clientHeight,
  16527. barHeight: cm.display.scrollbarV.clientHeight,
  16528. scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
  16529. hScrollbarTakesSpace: hScrollbarTakesSpace(cm),
  16530. barWidth: cm.display.scrollbarH.clientWidth,
  16531. docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
  16532. };
  16533. }
  16534. // Re-synchronize the fake scrollbars with the actual size of the
  16535. // content.
  16536. function updateScrollbars(cm, measure) {
  16537. if (!measure) measure = measureForScrollbars(cm);
  16538. var d = cm.display, sWidth = scrollbarWidth(d.measure);
  16539. var scrollHeight = measure.docHeight + scrollerCutOff;
  16540. var needsH = measure.scrollWidth > measure.clientWidth;
  16541. if (needsH && measure.scrollWidth <= measure.clientWidth + 1 &&
  16542. sWidth > 0 && !measure.hScrollbarTakesSpace)
  16543. needsH = false; // (Issue #2562)
  16544. var needsV = scrollHeight > measure.clientHeight;
  16545. if (needsV) {
  16546. d.scrollbarV.style.display = "block";
  16547. d.scrollbarV.style.bottom = needsH ? sWidth + "px" : "0";
  16548. // A bug in IE8 can cause this value to be negative, so guard it.
  16549. d.scrollbarV.firstChild.style.height =
  16550. Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px";
  16551. } else {
  16552. d.scrollbarV.style.display = "";
  16553. d.scrollbarV.firstChild.style.height = "0";
  16554. }
  16555. if (needsH) {
  16556. d.scrollbarH.style.display = "block";
  16557. d.scrollbarH.style.right = needsV ? sWidth + "px" : "0";
  16558. d.scrollbarH.firstChild.style.width =
  16559. (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + "px";
  16560. } else {
  16561. d.scrollbarH.style.display = "";
  16562. d.scrollbarH.firstChild.style.width = "0";
  16563. }
  16564. if (needsH && needsV) {
  16565. d.scrollbarFiller.style.display = "block";
  16566. d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = sWidth + "px";
  16567. } else d.scrollbarFiller.style.display = "";
  16568. if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
  16569. d.gutterFiller.style.display = "block";
  16570. d.gutterFiller.style.height = sWidth + "px";
  16571. d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
  16572. } else d.gutterFiller.style.display = "";
  16573. if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) {
  16574. if (sWidth === 0) {
  16575. var w = mac && !mac_geMountainLion ? "12px" : "18px";
  16576. d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
  16577. var barMouseDown = function(e) {
  16578. if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
  16579. operation(cm, onMouseDown)(e);
  16580. };
  16581. on(d.scrollbarV, "mousedown", barMouseDown);
  16582. on(d.scrollbarH, "mousedown", barMouseDown);
  16583. }
  16584. cm.state.checkedOverlayScrollbar = true;
  16585. }
  16586. }
  16587. // Compute the lines that are visible in a given viewport (defaults
  16588. // the the current scroll position). viewport may contain top,
  16589. // height, and ensure (see op.scrollToPos) properties.
  16590. function visibleLines(display, doc, viewport) {
  16591. var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
  16592. top = Math.floor(top - paddingTop(display));
  16593. var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
  16594. var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
  16595. // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
  16596. // forces those lines into the viewport (if possible).
  16597. if (viewport && viewport.ensure) {
  16598. var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
  16599. if (ensureFrom < from)
  16600. return {from: ensureFrom,
  16601. to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
  16602. if (Math.min(ensureTo, doc.lastLine()) >= to)
  16603. return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
  16604. to: ensureTo};
  16605. }
  16606. return {from: from, to: Math.max(to, from + 1)};
  16607. }
  16608. // LINE NUMBERS
  16609. // Re-align line numbers and gutter marks to compensate for
  16610. // horizontal scrolling.
  16611. function alignHorizontally(cm) {
  16612. var display = cm.display, view = display.view;
  16613. if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
  16614. var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
  16615. var gutterW = display.gutters.offsetWidth, left = comp + "px";
  16616. for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
  16617. if (cm.options.fixedGutter && view[i].gutter)
  16618. view[i].gutter.style.left = left;
  16619. var align = view[i].alignable;
  16620. if (align) for (var j = 0; j < align.length; j++)
  16621. align[j].style.left = left;
  16622. }
  16623. if (cm.options.fixedGutter)
  16624. display.gutters.style.left = (comp + gutterW) + "px";
  16625. }
  16626. // Used to ensure that the line number gutter is still the right
  16627. // size for the current document size. Returns true when an update
  16628. // is needed.
  16629. function maybeUpdateLineNumberWidth(cm) {
  16630. if (!cm.options.lineNumbers) return false;
  16631. var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
  16632. if (last.length != display.lineNumChars) {
  16633. var test = display.measure.appendChild(elt("div", [elt("div", last)],
  16634. "CodeMirror-linenumber CodeMirror-gutter-elt"));
  16635. var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
  16636. display.lineGutter.style.width = "";
  16637. display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
  16638. display.lineNumWidth = display.lineNumInnerWidth + padding;
  16639. display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
  16640. display.lineGutter.style.width = display.lineNumWidth + "px";
  16641. updateGutterSpace(cm);
  16642. return true;
  16643. }
  16644. return false;
  16645. }
  16646. function lineNumberFor(options, i) {
  16647. return String(options.lineNumberFormatter(i + options.firstLineNumber));
  16648. }
  16649. // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
  16650. // but using getBoundingClientRect to get a sub-pixel-accurate
  16651. // result.
  16652. function compensateForHScroll(display) {
  16653. return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
  16654. }
  16655. // DISPLAY DRAWING
  16656. function DisplayUpdate(cm, viewport, force) {
  16657. var display = cm.display;
  16658. this.viewport = viewport;
  16659. // Store some values that we'll need later (but don't want to force a relayout for)
  16660. this.visible = visibleLines(display, cm.doc, viewport);
  16661. this.editorIsHidden = !display.wrapper.offsetWidth;
  16662. this.wrapperHeight = display.wrapper.clientHeight;
  16663. this.oldViewFrom = display.viewFrom; this.oldViewTo = display.viewTo;
  16664. this.oldScrollerWidth = display.scroller.clientWidth;
  16665. this.force = force;
  16666. this.dims = getDimensions(cm);
  16667. }
  16668. // Does the actual updating of the line display. Bails out
  16669. // (returning false) when there is nothing to be done and forced is
  16670. // false.
  16671. function updateDisplayIfNeeded(cm, update) {
  16672. var display = cm.display, doc = cm.doc;
  16673. if (update.editorIsHidden) {
  16674. resetView(cm);
  16675. return false;
  16676. }
  16677. // Bail out if the visible area is already rendered and nothing changed.
  16678. if (!update.force &&
  16679. update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
  16680. (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
  16681. countDirtyView(cm) == 0)
  16682. return false;
  16683. if (maybeUpdateLineNumberWidth(cm)) {
  16684. resetView(cm);
  16685. update.dims = getDimensions(cm);
  16686. }
  16687. // Compute a suitable new viewport (from & to)
  16688. var end = doc.first + doc.size;
  16689. var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
  16690. var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
  16691. if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
  16692. if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
  16693. if (sawCollapsedSpans) {
  16694. from = visualLineNo(cm.doc, from);
  16695. to = visualLineEndNo(cm.doc, to);
  16696. }
  16697. var different = from != display.viewFrom || to != display.viewTo ||
  16698. display.lastSizeC != update.wrapperHeight;
  16699. adjustView(cm, from, to);
  16700. display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
  16701. // Position the mover div to align with the current scroll position
  16702. cm.display.mover.style.top = display.viewOffset + "px";
  16703. var toUpdate = countDirtyView(cm);
  16704. if (!different && toUpdate == 0 && !update.force &&
  16705. (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
  16706. return false;
  16707. // For big changes, we hide the enclosing element during the
  16708. // update, since that speeds up the operations on most browsers.
  16709. var focused = activeElt();
  16710. if (toUpdate > 4) display.lineDiv.style.display = "none";
  16711. patchDisplay(cm, display.updateLineNumbers, update.dims);
  16712. if (toUpdate > 4) display.lineDiv.style.display = "";
  16713. // There might have been a widget with a focused element that got
  16714. // hidden or updated, if so re-focus it.
  16715. if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
  16716. // Prevent selection and cursors from interfering with the scroll
  16717. // width.
  16718. removeChildren(display.cursorDiv);
  16719. removeChildren(display.selectionDiv);
  16720. if (different) {
  16721. display.lastSizeC = update.wrapperHeight;
  16722. startWorker(cm, 400);
  16723. }
  16724. display.updateLineNumbers = null;
  16725. return true;
  16726. }
  16727. function postUpdateDisplay(cm, update) {
  16728. var force = update.force, viewport = update.viewport;
  16729. for (var first = true;; first = false) {
  16730. if (first && cm.options.lineWrapping && update.oldScrollerWidth != cm.display.scroller.clientWidth) {
  16731. force = true;
  16732. } else {
  16733. force = false;
  16734. // Clip forced viewport to actual scrollable area.
  16735. if (viewport && viewport.top != null)
  16736. viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - scrollerCutOff -
  16737. cm.display.scroller.clientHeight, viewport.top)};
  16738. // Updated line heights might result in the drawn area not
  16739. // actually covering the viewport. Keep looping until it does.
  16740. update.visible = visibleLines(cm.display, cm.doc, viewport);
  16741. if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
  16742. break;
  16743. }
  16744. if (!updateDisplayIfNeeded(cm, update)) break;
  16745. updateHeightsInViewport(cm);
  16746. var barMeasure = measureForScrollbars(cm);
  16747. updateSelection(cm);
  16748. setDocumentHeight(cm, barMeasure);
  16749. updateScrollbars(cm, barMeasure);
  16750. }
  16751. signalLater(cm, "update", cm);
  16752. if (cm.display.viewFrom != update.oldViewFrom || cm.display.viewTo != update.oldViewTo)
  16753. signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
  16754. }
  16755. function updateDisplaySimple(cm, viewport) {
  16756. var update = new DisplayUpdate(cm, viewport);
  16757. if (updateDisplayIfNeeded(cm, update)) {
  16758. updateHeightsInViewport(cm);
  16759. postUpdateDisplay(cm, update);
  16760. var barMeasure = measureForScrollbars(cm);
  16761. updateSelection(cm);
  16762. setDocumentHeight(cm, barMeasure);
  16763. updateScrollbars(cm, barMeasure);
  16764. }
  16765. }
  16766. function setDocumentHeight(cm, measure) {
  16767. cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
  16768. cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
  16769. }
  16770. function checkForWebkitWidthBug(cm, measure) {
  16771. // Work around Webkit bug where it sometimes reserves space for a
  16772. // non-existing phantom scrollbar in the scroller (Issue #2420)
  16773. if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
  16774. cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
  16775. cm.display.gutters.style.height = measure.docHeight + "px";
  16776. }
  16777. }
  16778. // Read the actual heights of the rendered lines, and update their
  16779. // stored heights to match.
  16780. function updateHeightsInViewport(cm) {
  16781. var display = cm.display;
  16782. var prevBottom = display.lineDiv.offsetTop;
  16783. for (var i = 0; i < display.view.length; i++) {
  16784. var cur = display.view[i], height;
  16785. if (cur.hidden) continue;
  16786. if (ie && ie_version < 8) {
  16787. var bot = cur.node.offsetTop + cur.node.offsetHeight;
  16788. height = bot - prevBottom;
  16789. prevBottom = bot;
  16790. } else {
  16791. var box = cur.node.getBoundingClientRect();
  16792. height = box.bottom - box.top;
  16793. }
  16794. var diff = cur.line.height - height;
  16795. if (height < 2) height = textHeight(display);
  16796. if (diff > .001 || diff < -.001) {
  16797. updateLineHeight(cur.line, height);
  16798. updateWidgetHeight(cur.line);
  16799. if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
  16800. updateWidgetHeight(cur.rest[j]);
  16801. }
  16802. }
  16803. }
  16804. // Read and store the height of line widgets associated with the
  16805. // given line.
  16806. function updateWidgetHeight(line) {
  16807. if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
  16808. line.widgets[i].height = line.widgets[i].node.offsetHeight;
  16809. }
  16810. // Do a bulk-read of the DOM positions and sizes needed to draw the
  16811. // view, so that we don't interleave reading and writing to the DOM.
  16812. function getDimensions(cm) {
  16813. var d = cm.display, left = {}, width = {};
  16814. var gutterLeft = d.gutters.clientLeft;
  16815. for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
  16816. left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
  16817. width[cm.options.gutters[i]] = n.clientWidth;
  16818. }
  16819. return {fixedPos: compensateForHScroll(d),
  16820. gutterTotalWidth: d.gutters.offsetWidth,
  16821. gutterLeft: left,
  16822. gutterWidth: width,
  16823. wrapperWidth: d.wrapper.clientWidth};
  16824. }
  16825. // Sync the actual display DOM structure with display.view, removing
  16826. // nodes for lines that are no longer in view, and creating the ones
  16827. // that are not there yet, and updating the ones that are out of
  16828. // date.
  16829. function patchDisplay(cm, updateNumbersFrom, dims) {
  16830. var display = cm.display, lineNumbers = cm.options.lineNumbers;
  16831. var container = display.lineDiv, cur = container.firstChild;
  16832. function rm(node) {
  16833. var next = node.nextSibling;
  16834. // Works around a throw-scroll bug in OS X Webkit
  16835. if (webkit && mac && cm.display.currentWheelTarget == node)
  16836. node.style.display = "none";
  16837. else
  16838. node.parentNode.removeChild(node);
  16839. return next;
  16840. }
  16841. var view = display.view, lineN = display.viewFrom;
  16842. // Loop over the elements in the view, syncing cur (the DOM nodes
  16843. // in display.lineDiv) with the view as we go.
  16844. for (var i = 0; i < view.length; i++) {
  16845. var lineView = view[i];
  16846. if (lineView.hidden) {
  16847. } else if (!lineView.node) { // Not drawn yet
  16848. var node = buildLineElement(cm, lineView, lineN, dims);
  16849. container.insertBefore(node, cur);
  16850. } else { // Already drawn
  16851. while (cur != lineView.node) cur = rm(cur);
  16852. var updateNumber = lineNumbers && updateNumbersFrom != null &&
  16853. updateNumbersFrom <= lineN && lineView.lineNumber;
  16854. if (lineView.changes) {
  16855. if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
  16856. updateLineForChanges(cm, lineView, lineN, dims);
  16857. }
  16858. if (updateNumber) {
  16859. removeChildren(lineView.lineNumber);
  16860. lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
  16861. }
  16862. cur = lineView.node.nextSibling;
  16863. }
  16864. lineN += lineView.size;
  16865. }
  16866. while (cur) cur = rm(cur);
  16867. }
  16868. // When an aspect of a line changes, a string is added to
  16869. // lineView.changes. This updates the relevant part of the line's
  16870. // DOM structure.
  16871. function updateLineForChanges(cm, lineView, lineN, dims) {
  16872. for (var j = 0; j < lineView.changes.length; j++) {
  16873. var type = lineView.changes[j];
  16874. if (type == "text") updateLineText(cm, lineView);
  16875. else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
  16876. else if (type == "class") updateLineClasses(lineView);
  16877. else if (type == "widget") updateLineWidgets(lineView, dims);
  16878. }
  16879. lineView.changes = null;
  16880. }
  16881. // Lines with gutter elements, widgets or a background class need to
  16882. // be wrapped, and have the extra elements added to the wrapper div
  16883. function ensureLineWrapped(lineView) {
  16884. if (lineView.node == lineView.text) {
  16885. lineView.node = elt("div", null, null, "position: relative");
  16886. if (lineView.text.parentNode)
  16887. lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
  16888. lineView.node.appendChild(lineView.text);
  16889. if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
  16890. }
  16891. return lineView.node;
  16892. }
  16893. function updateLineBackground(lineView) {
  16894. var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
  16895. if (cls) cls += " CodeMirror-linebackground";
  16896. if (lineView.background) {
  16897. if (cls) lineView.background.className = cls;
  16898. else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
  16899. } else if (cls) {
  16900. var wrap = ensureLineWrapped(lineView);
  16901. lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
  16902. }
  16903. }
  16904. // Wrapper around buildLineContent which will reuse the structure
  16905. // in display.externalMeasured when possible.
  16906. function getLineContent(cm, lineView) {
  16907. var ext = cm.display.externalMeasured;
  16908. if (ext && ext.line == lineView.line) {
  16909. cm.display.externalMeasured = null;
  16910. lineView.measure = ext.measure;
  16911. return ext.built;
  16912. }
  16913. return buildLineContent(cm, lineView);
  16914. }
  16915. // Redraw the line's text. Interacts with the background and text
  16916. // classes because the mode may output tokens that influence these
  16917. // classes.
  16918. function updateLineText(cm, lineView) {
  16919. var cls = lineView.text.className;
  16920. var built = getLineContent(cm, lineView);
  16921. if (lineView.text == lineView.node) lineView.node = built.pre;
  16922. lineView.text.parentNode.replaceChild(built.pre, lineView.text);
  16923. lineView.text = built.pre;
  16924. if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
  16925. lineView.bgClass = built.bgClass;
  16926. lineView.textClass = built.textClass;
  16927. updateLineClasses(lineView);
  16928. } else if (cls) {
  16929. lineView.text.className = cls;
  16930. }
  16931. }
  16932. function updateLineClasses(lineView) {
  16933. updateLineBackground(lineView);
  16934. if (lineView.line.wrapClass)
  16935. ensureLineWrapped(lineView).className = lineView.line.wrapClass;
  16936. else if (lineView.node != lineView.text)
  16937. lineView.node.className = "";
  16938. var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
  16939. lineView.text.className = textClass || "";
  16940. }
  16941. function updateLineGutter(cm, lineView, lineN, dims) {
  16942. if (lineView.gutter) {
  16943. lineView.node.removeChild(lineView.gutter);
  16944. lineView.gutter = null;
  16945. }
  16946. var markers = lineView.line.gutterMarkers;
  16947. if (cm.options.lineNumbers || markers) {
  16948. var wrap = ensureLineWrapped(lineView);
  16949. var gutterWrap = lineView.gutter =
  16950. wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
  16951. (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
  16952. lineView.text);
  16953. if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
  16954. lineView.lineNumber = gutterWrap.appendChild(
  16955. elt("div", lineNumberFor(cm.options, lineN),
  16956. "CodeMirror-linenumber CodeMirror-gutter-elt",
  16957. "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
  16958. + cm.display.lineNumInnerWidth + "px"));
  16959. if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
  16960. var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
  16961. if (found)
  16962. gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
  16963. dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
  16964. }
  16965. }
  16966. }
  16967. function updateLineWidgets(lineView, dims) {
  16968. if (lineView.alignable) lineView.alignable = null;
  16969. for (var node = lineView.node.firstChild, next; node; node = next) {
  16970. var next = node.nextSibling;
  16971. if (node.className == "CodeMirror-linewidget")
  16972. lineView.node.removeChild(node);
  16973. }
  16974. insertLineWidgets(lineView, dims);
  16975. }
  16976. // Build a line's DOM representation from scratch
  16977. function buildLineElement(cm, lineView, lineN, dims) {
  16978. var built = getLineContent(cm, lineView);
  16979. lineView.text = lineView.node = built.pre;
  16980. if (built.bgClass) lineView.bgClass = built.bgClass;
  16981. if (built.textClass) lineView.textClass = built.textClass;
  16982. updateLineClasses(lineView);
  16983. updateLineGutter(cm, lineView, lineN, dims);
  16984. insertLineWidgets(lineView, dims);
  16985. return lineView.node;
  16986. }
  16987. // A lineView may contain multiple logical lines (when merged by
  16988. // collapsed spans). The widgets for all of them need to be drawn.
  16989. function insertLineWidgets(lineView, dims) {
  16990. insertLineWidgetsFor(lineView.line, lineView, dims, true);
  16991. if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
  16992. insertLineWidgetsFor(lineView.rest[i], lineView, dims, false);
  16993. }
  16994. function insertLineWidgetsFor(line, lineView, dims, allowAbove) {
  16995. if (!line.widgets) return;
  16996. var wrap = ensureLineWrapped(lineView);
  16997. for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
  16998. var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
  16999. if (!widget.handleMouseEvents) node.ignoreEvents = true;
  17000. positionLineWidget(widget, node, lineView, dims);
  17001. if (allowAbove && widget.above)
  17002. wrap.insertBefore(node, lineView.gutter || lineView.text);
  17003. else
  17004. wrap.appendChild(node);
  17005. signalLater(widget, "redraw");
  17006. }
  17007. }
  17008. function positionLineWidget(widget, node, lineView, dims) {
  17009. if (widget.noHScroll) {
  17010. (lineView.alignable || (lineView.alignable = [])).push(node);
  17011. var width = dims.wrapperWidth;
  17012. node.style.left = dims.fixedPos + "px";
  17013. if (!widget.coverGutter) {
  17014. width -= dims.gutterTotalWidth;
  17015. node.style.paddingLeft = dims.gutterTotalWidth + "px";
  17016. }
  17017. node.style.width = width + "px";
  17018. }
  17019. if (widget.coverGutter) {
  17020. node.style.zIndex = 5;
  17021. node.style.position = "relative";
  17022. if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
  17023. }
  17024. }
  17025. // POSITION OBJECT
  17026. // A Pos instance represents a position within the text.
  17027. var Pos = CodeMirror.Pos = function(line, ch) {
  17028. if (!(this instanceof Pos)) return new Pos(line, ch);
  17029. this.line = line; this.ch = ch;
  17030. };
  17031. // Compare two positions, return 0 if they are the same, a negative
  17032. // number when a is less, and a positive number otherwise.
  17033. var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
  17034. function copyPos(x) {return Pos(x.line, x.ch);}
  17035. function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
  17036. function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
  17037. // SELECTION / CURSOR
  17038. // Selection objects are immutable. A new one is created every time
  17039. // the selection changes. A selection is one or more non-overlapping
  17040. // (and non-touching) ranges, sorted, and an integer that indicates
  17041. // which one is the primary selection (the one that's scrolled into
  17042. // view, that getCursor returns, etc).
  17043. function Selection(ranges, primIndex) {
  17044. this.ranges = ranges;
  17045. this.primIndex = primIndex;
  17046. }
  17047. Selection.prototype = {
  17048. primary: function() { return this.ranges[this.primIndex]; },
  17049. equals: function(other) {
  17050. if (other == this) return true;
  17051. if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
  17052. for (var i = 0; i < this.ranges.length; i++) {
  17053. var here = this.ranges[i], there = other.ranges[i];
  17054. if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
  17055. }
  17056. return true;
  17057. },
  17058. deepCopy: function() {
  17059. for (var out = [], i = 0; i < this.ranges.length; i++)
  17060. out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
  17061. return new Selection(out, this.primIndex);
  17062. },
  17063. somethingSelected: function() {
  17064. for (var i = 0; i < this.ranges.length; i++)
  17065. if (!this.ranges[i].empty()) return true;
  17066. return false;
  17067. },
  17068. contains: function(pos, end) {
  17069. if (!end) end = pos;
  17070. for (var i = 0; i < this.ranges.length; i++) {
  17071. var range = this.ranges[i];
  17072. if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
  17073. return i;
  17074. }
  17075. return -1;
  17076. }
  17077. };
  17078. function Range(anchor, head) {
  17079. this.anchor = anchor; this.head = head;
  17080. }
  17081. Range.prototype = {
  17082. from: function() { return minPos(this.anchor, this.head); },
  17083. to: function() { return maxPos(this.anchor, this.head); },
  17084. empty: function() {
  17085. return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
  17086. }
  17087. };
  17088. // Take an unsorted, potentially overlapping set of ranges, and
  17089. // build a selection out of it. 'Consumes' ranges array (modifying
  17090. // it).
  17091. function normalizeSelection(ranges, primIndex) {
  17092. var prim = ranges[primIndex];
  17093. ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
  17094. primIndex = indexOf(ranges, prim);
  17095. for (var i = 1; i < ranges.length; i++) {
  17096. var cur = ranges[i], prev = ranges[i - 1];
  17097. if (cmp(prev.to(), cur.from()) >= 0) {
  17098. var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
  17099. var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
  17100. if (i <= primIndex) --primIndex;
  17101. ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
  17102. }
  17103. }
  17104. return new Selection(ranges, primIndex);
  17105. }
  17106. function simpleSelection(anchor, head) {
  17107. return new Selection([new Range(anchor, head || anchor)], 0);
  17108. }
  17109. // Most of the external API clips given positions to make sure they
  17110. // actually exist within the document.
  17111. function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
  17112. function clipPos(doc, pos) {
  17113. if (pos.line < doc.first) return Pos(doc.first, 0);
  17114. var last = doc.first + doc.size - 1;
  17115. if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
  17116. return clipToLen(pos, getLine(doc, pos.line).text.length);
  17117. }
  17118. function clipToLen(pos, linelen) {
  17119. var ch = pos.ch;
  17120. if (ch == null || ch > linelen) return Pos(pos.line, linelen);
  17121. else if (ch < 0) return Pos(pos.line, 0);
  17122. else return pos;
  17123. }
  17124. function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
  17125. function clipPosArray(doc, array) {
  17126. for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
  17127. return out;
  17128. }
  17129. // SELECTION UPDATES
  17130. // The 'scroll' parameter given to many of these indicated whether
  17131. // the new cursor position should be scrolled into view after
  17132. // modifying the selection.
  17133. // If shift is held or the extend flag is set, extends a range to
  17134. // include a given position (and optionally a second position).
  17135. // Otherwise, simply returns the range between the given positions.
  17136. // Used for cursor motion and such.
  17137. function extendRange(doc, range, head, other) {
  17138. if (doc.cm && doc.cm.display.shift || doc.extend) {
  17139. var anchor = range.anchor;
  17140. if (other) {
  17141. var posBefore = cmp(head, anchor) < 0;
  17142. if (posBefore != (cmp(other, anchor) < 0)) {
  17143. anchor = head;
  17144. head = other;
  17145. } else if (posBefore != (cmp(head, other) < 0)) {
  17146. head = other;
  17147. }
  17148. }
  17149. return new Range(anchor, head);
  17150. } else {
  17151. return new Range(other || head, head);
  17152. }
  17153. }
  17154. // Extend the primary selection range, discard the rest.
  17155. function extendSelection(doc, head, other, options) {
  17156. setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
  17157. }
  17158. // Extend all selections (pos is an array of selections with length
  17159. // equal the number of selections)
  17160. function extendSelections(doc, heads, options) {
  17161. for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
  17162. out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
  17163. var newSel = normalizeSelection(out, doc.sel.primIndex);
  17164. setSelection(doc, newSel, options);
  17165. }
  17166. // Updates a single range in the selection.
  17167. function replaceOneSelection(doc, i, range, options) {
  17168. var ranges = doc.sel.ranges.slice(0);
  17169. ranges[i] = range;
  17170. setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
  17171. }
  17172. // Reset the selection to a single range.
  17173. function setSimpleSelection(doc, anchor, head, options) {
  17174. setSelection(doc, simpleSelection(anchor, head), options);
  17175. }
  17176. // Give beforeSelectionChange handlers a change to influence a
  17177. // selection update.
  17178. function filterSelectionChange(doc, sel) {
  17179. var obj = {
  17180. ranges: sel.ranges,
  17181. update: function(ranges) {
  17182. this.ranges = [];
  17183. for (var i = 0; i < ranges.length; i++)
  17184. this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
  17185. clipPos(doc, ranges[i].head));
  17186. }
  17187. };
  17188. signal(doc, "beforeSelectionChange", doc, obj);
  17189. if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
  17190. if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
  17191. else return sel;
  17192. }
  17193. function setSelectionReplaceHistory(doc, sel, options) {
  17194. var done = doc.history.done, last = lst(done);
  17195. if (last && last.ranges) {
  17196. done[done.length - 1] = sel;
  17197. setSelectionNoUndo(doc, sel, options);
  17198. } else {
  17199. setSelection(doc, sel, options);
  17200. }
  17201. }
  17202. // Set a new selection.
  17203. function setSelection(doc, sel, options) {
  17204. setSelectionNoUndo(doc, sel, options);
  17205. addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
  17206. }
  17207. function setSelectionNoUndo(doc, sel, options) {
  17208. if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
  17209. sel = filterSelectionChange(doc, sel);
  17210. var bias = options && options.bias ||
  17211. (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
  17212. setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
  17213. if (!(options && options.scroll === false) && doc.cm)
  17214. ensureCursorVisible(doc.cm);
  17215. }
  17216. function setSelectionInner(doc, sel) {
  17217. if (sel.equals(doc.sel)) return;
  17218. doc.sel = sel;
  17219. if (doc.cm) {
  17220. doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
  17221. signalCursorActivity(doc.cm);
  17222. }
  17223. signalLater(doc, "cursorActivity", doc);
  17224. }
  17225. // Verify that the selection does not partially select any atomic
  17226. // marked ranges.
  17227. function reCheckSelection(doc) {
  17228. setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
  17229. }
  17230. // Return a selection that does not partially select any atomic
  17231. // ranges.
  17232. function skipAtomicInSelection(doc, sel, bias, mayClear) {
  17233. var out;
  17234. for (var i = 0; i < sel.ranges.length; i++) {
  17235. var range = sel.ranges[i];
  17236. var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
  17237. var newHead = skipAtomic(doc, range.head, bias, mayClear);
  17238. if (out || newAnchor != range.anchor || newHead != range.head) {
  17239. if (!out) out = sel.ranges.slice(0, i);
  17240. out[i] = new Range(newAnchor, newHead);
  17241. }
  17242. }
  17243. return out ? normalizeSelection(out, sel.primIndex) : sel;
  17244. }
  17245. // Ensure a given position is not inside an atomic range.
  17246. function skipAtomic(doc, pos, bias, mayClear) {
  17247. var flipped = false, curPos = pos;
  17248. var dir = bias || 1;
  17249. doc.cantEdit = false;
  17250. search: for (;;) {
  17251. var line = getLine(doc, curPos.line);
  17252. if (line.markedSpans) {
  17253. for (var i = 0; i < line.markedSpans.length; ++i) {
  17254. var sp = line.markedSpans[i], m = sp.marker;
  17255. if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
  17256. (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
  17257. if (mayClear) {
  17258. signal(m, "beforeCursorEnter");
  17259. if (m.explicitlyCleared) {
  17260. if (!line.markedSpans) break;
  17261. else {--i; continue;}
  17262. }
  17263. }
  17264. if (!m.atomic) continue;
  17265. var newPos = m.find(dir < 0 ? -1 : 1);
  17266. if (cmp(newPos, curPos) == 0) {
  17267. newPos.ch += dir;
  17268. if (newPos.ch < 0) {
  17269. if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
  17270. else newPos = null;
  17271. } else if (newPos.ch > line.text.length) {
  17272. if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
  17273. else newPos = null;
  17274. }
  17275. if (!newPos) {
  17276. if (flipped) {
  17277. // Driven in a corner -- no valid cursor position found at all
  17278. // -- try again *with* clearing, if we didn't already
  17279. if (!mayClear) return skipAtomic(doc, pos, bias, true);
  17280. // Otherwise, turn off editing until further notice, and return the start of the doc
  17281. doc.cantEdit = true;
  17282. return Pos(doc.first, 0);
  17283. }
  17284. flipped = true; newPos = pos; dir = -dir;
  17285. }
  17286. }
  17287. curPos = newPos;
  17288. continue search;
  17289. }
  17290. }
  17291. }
  17292. return curPos;
  17293. }
  17294. }
  17295. // SELECTION DRAWING
  17296. // Redraw the selection and/or cursor
  17297. function drawSelection(cm) {
  17298. var display = cm.display, doc = cm.doc, result = {};
  17299. var curFragment = result.cursors = document.createDocumentFragment();
  17300. var selFragment = result.selection = document.createDocumentFragment();
  17301. for (var i = 0; i < doc.sel.ranges.length; i++) {
  17302. var range = doc.sel.ranges[i];
  17303. var collapsed = range.empty();
  17304. if (collapsed || cm.options.showCursorWhenSelecting)
  17305. drawSelectionCursor(cm, range, curFragment);
  17306. if (!collapsed)
  17307. drawSelectionRange(cm, range, selFragment);
  17308. }
  17309. // Move the hidden textarea near the cursor to prevent scrolling artifacts
  17310. if (cm.options.moveInputWithCursor) {
  17311. var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
  17312. var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
  17313. result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
  17314. headPos.top + lineOff.top - wrapOff.top));
  17315. result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
  17316. headPos.left + lineOff.left - wrapOff.left));
  17317. }
  17318. return result;
  17319. }
  17320. function showSelection(cm, drawn) {
  17321. removeChildrenAndAdd(cm.display.cursorDiv, drawn.cursors);
  17322. removeChildrenAndAdd(cm.display.selectionDiv, drawn.selection);
  17323. if (drawn.teTop != null) {
  17324. cm.display.inputDiv.style.top = drawn.teTop + "px";
  17325. cm.display.inputDiv.style.left = drawn.teLeft + "px";
  17326. }
  17327. }
  17328. function updateSelection(cm) {
  17329. showSelection(cm, drawSelection(cm));
  17330. }
  17331. // Draws a cursor for the given range
  17332. function drawSelectionCursor(cm, range, output) {
  17333. var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
  17334. var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
  17335. cursor.style.left = pos.left + "px";
  17336. cursor.style.top = pos.top + "px";
  17337. cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
  17338. if (pos.other) {
  17339. // Secondary cursor, shown when on a 'jump' in bi-directional text
  17340. var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
  17341. otherCursor.style.display = "";
  17342. otherCursor.style.left = pos.other.left + "px";
  17343. otherCursor.style.top = pos.other.top + "px";
  17344. otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
  17345. }
  17346. }
  17347. // Draws the given range as a highlighted selection
  17348. function drawSelectionRange(cm, range, output) {
  17349. var display = cm.display, doc = cm.doc;
  17350. var fragment = document.createDocumentFragment();
  17351. var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
  17352. function add(left, top, width, bottom) {
  17353. if (top < 0) top = 0;
  17354. top = Math.round(top);
  17355. bottom = Math.round(bottom);
  17356. fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
  17357. "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
  17358. "px; height: " + (bottom - top) + "px"));
  17359. }
  17360. function drawForLine(line, fromArg, toArg) {
  17361. var lineObj = getLine(doc, line);
  17362. var lineLen = lineObj.text.length;
  17363. var start, end;
  17364. function coords(ch, bias) {
  17365. return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
  17366. }
  17367. iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
  17368. var leftPos = coords(from, "left"), rightPos, left, right;
  17369. if (from == to) {
  17370. rightPos = leftPos;
  17371. left = right = leftPos.left;
  17372. } else {
  17373. rightPos = coords(to - 1, "right");
  17374. if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
  17375. left = leftPos.left;
  17376. right = rightPos.right;
  17377. }
  17378. if (fromArg == null && from == 0) left = leftSide;
  17379. if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
  17380. add(left, leftPos.top, null, leftPos.bottom);
  17381. left = leftSide;
  17382. if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
  17383. }
  17384. if (toArg == null && to == lineLen) right = rightSide;
  17385. if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
  17386. start = leftPos;
  17387. if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
  17388. end = rightPos;
  17389. if (left < leftSide + 1) left = leftSide;
  17390. add(left, rightPos.top, right - left, rightPos.bottom);
  17391. });
  17392. return {start: start, end: end};
  17393. }
  17394. var sFrom = range.from(), sTo = range.to();
  17395. if (sFrom.line == sTo.line) {
  17396. drawForLine(sFrom.line, sFrom.ch, sTo.ch);
  17397. } else {
  17398. var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
  17399. var singleVLine = visualLine(fromLine) == visualLine(toLine);
  17400. var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
  17401. var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
  17402. if (singleVLine) {
  17403. if (leftEnd.top < rightStart.top - 2) {
  17404. add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
  17405. add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
  17406. } else {
  17407. add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
  17408. }
  17409. }
  17410. if (leftEnd.bottom < rightStart.top)
  17411. add(leftSide, leftEnd.bottom, null, rightStart.top);
  17412. }
  17413. output.appendChild(fragment);
  17414. }
  17415. // Cursor-blinking
  17416. function restartBlink(cm) {
  17417. if (!cm.state.focused) return;
  17418. var display = cm.display;
  17419. clearInterval(display.blinker);
  17420. var on = true;
  17421. display.cursorDiv.style.visibility = "";
  17422. if (cm.options.cursorBlinkRate > 0)
  17423. display.blinker = setInterval(function() {
  17424. display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
  17425. }, cm.options.cursorBlinkRate);
  17426. else if (cm.options.cursorBlinkRate < 0)
  17427. display.cursorDiv.style.visibility = "hidden";
  17428. }
  17429. // HIGHLIGHT WORKER
  17430. function startWorker(cm, time) {
  17431. if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
  17432. cm.state.highlight.set(time, bind(highlightWorker, cm));
  17433. }
  17434. function highlightWorker(cm) {
  17435. var doc = cm.doc;
  17436. if (doc.frontier < doc.first) doc.frontier = doc.first;
  17437. if (doc.frontier >= cm.display.viewTo) return;
  17438. var end = +new Date + cm.options.workTime;
  17439. var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
  17440. var changedLines = [];
  17441. doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
  17442. if (doc.frontier >= cm.display.viewFrom) { // Visible
  17443. var oldStyles = line.styles;
  17444. var highlighted = highlightLine(cm, line, state, true);
  17445. line.styles = highlighted.styles;
  17446. var oldCls = line.styleClasses, newCls = highlighted.classes;
  17447. if (newCls) line.styleClasses = newCls;
  17448. else if (oldCls) line.styleClasses = null;
  17449. var ischange = !oldStyles || oldStyles.length != line.styles.length ||
  17450. oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
  17451. for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
  17452. if (ischange) changedLines.push(doc.frontier);
  17453. line.stateAfter = copyState(doc.mode, state);
  17454. } else {
  17455. processLine(cm, line.text, state);
  17456. line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
  17457. }
  17458. ++doc.frontier;
  17459. if (+new Date > end) {
  17460. startWorker(cm, cm.options.workDelay);
  17461. return true;
  17462. }
  17463. });
  17464. if (changedLines.length) runInOp(cm, function() {
  17465. for (var i = 0; i < changedLines.length; i++)
  17466. regLineChange(cm, changedLines[i], "text");
  17467. });
  17468. }
  17469. // Finds the line to start with when starting a parse. Tries to
  17470. // find a line with a stateAfter, so that it can start with a
  17471. // valid state. If that fails, it returns the line with the
  17472. // smallest indentation, which tends to need the least context to
  17473. // parse correctly.
  17474. function findStartLine(cm, n, precise) {
  17475. var minindent, minline, doc = cm.doc;
  17476. var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
  17477. for (var search = n; search > lim; --search) {
  17478. if (search <= doc.first) return doc.first;
  17479. var line = getLine(doc, search - 1);
  17480. if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
  17481. var indented = countColumn(line.text, null, cm.options.tabSize);
  17482. if (minline == null || minindent > indented) {
  17483. minline = search - 1;
  17484. minindent = indented;
  17485. }
  17486. }
  17487. return minline;
  17488. }
  17489. function getStateBefore(cm, n, precise) {
  17490. var doc = cm.doc, display = cm.display;
  17491. if (!doc.mode.startState) return true;
  17492. var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
  17493. if (!state) state = startState(doc.mode);
  17494. else state = copyState(doc.mode, state);
  17495. doc.iter(pos, n, function(line) {
  17496. processLine(cm, line.text, state);
  17497. var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
  17498. line.stateAfter = save ? copyState(doc.mode, state) : null;
  17499. ++pos;
  17500. });
  17501. if (precise) doc.frontier = pos;
  17502. return state;
  17503. }
  17504. // POSITION MEASUREMENT
  17505. function paddingTop(display) {return display.lineSpace.offsetTop;}
  17506. function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
  17507. function paddingH(display) {
  17508. if (display.cachedPaddingH) return display.cachedPaddingH;
  17509. var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
  17510. var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
  17511. var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
  17512. if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
  17513. return data;
  17514. }
  17515. // Ensure the lineView.wrapping.heights array is populated. This is
  17516. // an array of bottom offsets for the lines that make up a drawn
  17517. // line. When lineWrapping is on, there might be more than one
  17518. // height.
  17519. function ensureLineHeights(cm, lineView, rect) {
  17520. var wrapping = cm.options.lineWrapping;
  17521. var curWidth = wrapping && cm.display.scroller.clientWidth;
  17522. if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
  17523. var heights = lineView.measure.heights = [];
  17524. if (wrapping) {
  17525. lineView.measure.width = curWidth;
  17526. var rects = lineView.text.firstChild.getClientRects();
  17527. for (var i = 0; i < rects.length - 1; i++) {
  17528. var cur = rects[i], next = rects[i + 1];
  17529. if (Math.abs(cur.bottom - next.bottom) > 2)
  17530. heights.push((cur.bottom + next.top) / 2 - rect.top);
  17531. }
  17532. }
  17533. heights.push(rect.bottom - rect.top);
  17534. }
  17535. }
  17536. // Find a line map (mapping character offsets to text nodes) and a
  17537. // measurement cache for the given line number. (A line view might
  17538. // contain multiple lines when collapsed ranges are present.)
  17539. function mapFromLineView(lineView, line, lineN) {
  17540. if (lineView.line == line)
  17541. return {map: lineView.measure.map, cache: lineView.measure.cache};
  17542. for (var i = 0; i < lineView.rest.length; i++)
  17543. if (lineView.rest[i] == line)
  17544. return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
  17545. for (var i = 0; i < lineView.rest.length; i++)
  17546. if (lineNo(lineView.rest[i]) > lineN)
  17547. return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
  17548. }
  17549. // Render a line into the hidden node display.externalMeasured. Used
  17550. // when measurement is needed for a line that's not in the viewport.
  17551. function updateExternalMeasurement(cm, line) {
  17552. line = visualLine(line);
  17553. var lineN = lineNo(line);
  17554. var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
  17555. view.lineN = lineN;
  17556. var built = view.built = buildLineContent(cm, view);
  17557. view.text = built.pre;
  17558. removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
  17559. return view;
  17560. }
  17561. // Get a {top, bottom, left, right} box (in line-local coordinates)
  17562. // for a given character.
  17563. function measureChar(cm, line, ch, bias) {
  17564. return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
  17565. }
  17566. // Find a line view that corresponds to the given line number.
  17567. function findViewForLine(cm, lineN) {
  17568. if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
  17569. return cm.display.view[findViewIndex(cm, lineN)];
  17570. var ext = cm.display.externalMeasured;
  17571. if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
  17572. return ext;
  17573. }
  17574. // Measurement can be split in two steps, the set-up work that
  17575. // applies to the whole line, and the measurement of the actual
  17576. // character. Functions like coordsChar, that need to do a lot of
  17577. // measurements in a row, can thus ensure that the set-up work is
  17578. // only done once.
  17579. function prepareMeasureForLine(cm, line) {
  17580. var lineN = lineNo(line);
  17581. var view = findViewForLine(cm, lineN);
  17582. if (view && !view.text)
  17583. view = null;
  17584. else if (view && view.changes)
  17585. updateLineForChanges(cm, view, lineN, getDimensions(cm));
  17586. if (!view)
  17587. view = updateExternalMeasurement(cm, line);
  17588. var info = mapFromLineView(view, line, lineN);
  17589. return {
  17590. line: line, view: view, rect: null,
  17591. map: info.map, cache: info.cache, before: info.before,
  17592. hasHeights: false
  17593. };
  17594. }
  17595. // Given a prepared measurement object, measures the position of an
  17596. // actual character (or fetches it from the cache).
  17597. function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
  17598. if (prepared.before) ch = -1;
  17599. var key = ch + (bias || ""), found;
  17600. if (prepared.cache.hasOwnProperty(key)) {
  17601. found = prepared.cache[key];
  17602. } else {
  17603. if (!prepared.rect)
  17604. prepared.rect = prepared.view.text.getBoundingClientRect();
  17605. if (!prepared.hasHeights) {
  17606. ensureLineHeights(cm, prepared.view, prepared.rect);
  17607. prepared.hasHeights = true;
  17608. }
  17609. found = measureCharInner(cm, prepared, ch, bias);
  17610. if (!found.bogus) prepared.cache[key] = found;
  17611. }
  17612. return {left: found.left, right: found.right,
  17613. top: varHeight ? found.rtop : found.top,
  17614. bottom: varHeight ? found.rbottom : found.bottom};
  17615. }
  17616. var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
  17617. function measureCharInner(cm, prepared, ch, bias) {
  17618. var map = prepared.map;
  17619. var node, start, end, collapse;
  17620. // First, search the line map for the text node corresponding to,
  17621. // or closest to, the target character.
  17622. for (var i = 0; i < map.length; i += 3) {
  17623. var mStart = map[i], mEnd = map[i + 1];
  17624. if (ch < mStart) {
  17625. start = 0; end = 1;
  17626. collapse = "left";
  17627. } else if (ch < mEnd) {
  17628. start = ch - mStart;
  17629. end = start + 1;
  17630. } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
  17631. end = mEnd - mStart;
  17632. start = end - 1;
  17633. if (ch >= mEnd) collapse = "right";
  17634. }
  17635. if (start != null) {
  17636. node = map[i + 2];
  17637. if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
  17638. collapse = bias;
  17639. if (bias == "left" && start == 0)
  17640. while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
  17641. node = map[(i -= 3) + 2];
  17642. collapse = "left";
  17643. }
  17644. if (bias == "right" && start == mEnd - mStart)
  17645. while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
  17646. node = map[(i += 3) + 2];
  17647. collapse = "right";
  17648. }
  17649. break;
  17650. }
  17651. }
  17652. var rect;
  17653. if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
  17654. for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
  17655. while (start && isExtendingChar(prepared.line.text.charAt(mStart + start))) --start;
  17656. while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mStart + end))) ++end;
  17657. if (ie && ie_version < 9 && start == 0 && end == mEnd - mStart) {
  17658. rect = node.parentNode.getBoundingClientRect();
  17659. } else if (ie && cm.options.lineWrapping) {
  17660. var rects = range(node, start, end).getClientRects();
  17661. if (rects.length)
  17662. rect = rects[bias == "right" ? rects.length - 1 : 0];
  17663. else
  17664. rect = nullRect;
  17665. } else {
  17666. rect = range(node, start, end).getBoundingClientRect() || nullRect;
  17667. }
  17668. if (rect.left || rect.right || start == 0) break;
  17669. end = start;
  17670. start = start - 1;
  17671. collapse = "right";
  17672. }
  17673. if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
  17674. } else { // If it is a widget, simply get the box for the whole widget.
  17675. if (start > 0) collapse = bias = "right";
  17676. var rects;
  17677. if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
  17678. rect = rects[bias == "right" ? rects.length - 1 : 0];
  17679. else
  17680. rect = node.getBoundingClientRect();
  17681. }
  17682. if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
  17683. var rSpan = node.parentNode.getClientRects()[0];
  17684. if (rSpan)
  17685. rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
  17686. else
  17687. rect = nullRect;
  17688. }
  17689. var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
  17690. var mid = (rtop + rbot) / 2;
  17691. var heights = prepared.view.measure.heights;
  17692. for (var i = 0; i < heights.length - 1; i++)
  17693. if (mid < heights[i]) break;
  17694. var top = i ? heights[i - 1] : 0, bot = heights[i];
  17695. var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
  17696. right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
  17697. top: top, bottom: bot};
  17698. if (!rect.left && !rect.right) result.bogus = true;
  17699. if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
  17700. return result;
  17701. }
  17702. // Work around problem with bounding client rects on ranges being
  17703. // returned incorrectly when zoomed on IE10 and below.
  17704. function maybeUpdateRectForZooming(measure, rect) {
  17705. if (!window.screen || screen.logicalXDPI == null ||
  17706. screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
  17707. return rect;
  17708. var scaleX = screen.logicalXDPI / screen.deviceXDPI;
  17709. var scaleY = screen.logicalYDPI / screen.deviceYDPI;
  17710. return {left: rect.left * scaleX, right: rect.right * scaleX,
  17711. top: rect.top * scaleY, bottom: rect.bottom * scaleY};
  17712. }
  17713. function clearLineMeasurementCacheFor(lineView) {
  17714. if (lineView.measure) {
  17715. lineView.measure.cache = {};
  17716. lineView.measure.heights = null;
  17717. if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
  17718. lineView.measure.caches[i] = {};
  17719. }
  17720. }
  17721. function clearLineMeasurementCache(cm) {
  17722. cm.display.externalMeasure = null;
  17723. removeChildren(cm.display.lineMeasure);
  17724. for (var i = 0; i < cm.display.view.length; i++)
  17725. clearLineMeasurementCacheFor(cm.display.view[i]);
  17726. }
  17727. function clearCaches(cm) {
  17728. clearLineMeasurementCache(cm);
  17729. cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
  17730. if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
  17731. cm.display.lineNumChars = null;
  17732. }
  17733. function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
  17734. function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
  17735. // Converts a {top, bottom, left, right} box from line-local
  17736. // coordinates into another coordinate system. Context may be one of
  17737. // "line", "div" (display.lineDiv), "local"/null (editor), or "page".
  17738. function intoCoordSystem(cm, lineObj, rect, context) {
  17739. if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
  17740. var size = widgetHeight(lineObj.widgets[i]);
  17741. rect.top += size; rect.bottom += size;
  17742. }
  17743. if (context == "line") return rect;
  17744. if (!context) context = "local";
  17745. var yOff = heightAtLine(lineObj);
  17746. if (context == "local") yOff += paddingTop(cm.display);
  17747. else yOff -= cm.display.viewOffset;
  17748. if (context == "page" || context == "window") {
  17749. var lOff = cm.display.lineSpace.getBoundingClientRect();
  17750. yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
  17751. var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
  17752. rect.left += xOff; rect.right += xOff;
  17753. }
  17754. rect.top += yOff; rect.bottom += yOff;
  17755. return rect;
  17756. }
  17757. // Coverts a box from "div" coords to another coordinate system.
  17758. // Context may be "window", "page", "div", or "local"/null.
  17759. function fromCoordSystem(cm, coords, context) {
  17760. if (context == "div") return coords;
  17761. var left = coords.left, top = coords.top;
  17762. // First move into "page" coordinate system
  17763. if (context == "page") {
  17764. left -= pageScrollX();
  17765. top -= pageScrollY();
  17766. } else if (context == "local" || !context) {
  17767. var localBox = cm.display.sizer.getBoundingClientRect();
  17768. left += localBox.left;
  17769. top += localBox.top;
  17770. }
  17771. var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
  17772. return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
  17773. }
  17774. function charCoords(cm, pos, context, lineObj, bias) {
  17775. if (!lineObj) lineObj = getLine(cm.doc, pos.line);
  17776. return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
  17777. }
  17778. // Returns a box for a given cursor position, which may have an
  17779. // 'other' property containing the position of the secondary cursor
  17780. // on a bidi boundary.
  17781. function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
  17782. lineObj = lineObj || getLine(cm.doc, pos.line);
  17783. if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
  17784. function get(ch, right) {
  17785. var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
  17786. if (right) m.left = m.right; else m.right = m.left;
  17787. return intoCoordSystem(cm, lineObj, m, context);
  17788. }
  17789. function getBidi(ch, partPos) {
  17790. var part = order[partPos], right = part.level % 2;
  17791. if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
  17792. part = order[--partPos];
  17793. ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
  17794. right = true;
  17795. } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
  17796. part = order[++partPos];
  17797. ch = bidiLeft(part) - part.level % 2;
  17798. right = false;
  17799. }
  17800. if (right && ch == part.to && ch > part.from) return get(ch - 1);
  17801. return get(ch, right);
  17802. }
  17803. var order = getOrder(lineObj), ch = pos.ch;
  17804. if (!order) return get(ch);
  17805. var partPos = getBidiPartAt(order, ch);
  17806. var val = getBidi(ch, partPos);
  17807. if (bidiOther != null) val.other = getBidi(ch, bidiOther);
  17808. return val;
  17809. }
  17810. // Used to cheaply estimate the coordinates for a position. Used for
  17811. // intermediate scroll updates.
  17812. function estimateCoords(cm, pos) {
  17813. var left = 0, pos = clipPos(cm.doc, pos);
  17814. if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
  17815. var lineObj = getLine(cm.doc, pos.line);
  17816. var top = heightAtLine(lineObj) + paddingTop(cm.display);
  17817. return {left: left, right: left, top: top, bottom: top + lineObj.height};
  17818. }
  17819. // Positions returned by coordsChar contain some extra information.
  17820. // xRel is the relative x position of the input coordinates compared
  17821. // to the found position (so xRel > 0 means the coordinates are to
  17822. // the right of the character position, for example). When outside
  17823. // is true, that means the coordinates lie outside the line's
  17824. // vertical range.
  17825. function PosWithInfo(line, ch, outside, xRel) {
  17826. var pos = Pos(line, ch);
  17827. pos.xRel = xRel;
  17828. if (outside) pos.outside = true;
  17829. return pos;
  17830. }
  17831. // Compute the character position closest to the given coordinates.
  17832. // Input must be lineSpace-local ("div" coordinate system).
  17833. function coordsChar(cm, x, y) {
  17834. var doc = cm.doc;
  17835. y += cm.display.viewOffset;
  17836. if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
  17837. var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
  17838. if (lineN > last)
  17839. return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
  17840. if (x < 0) x = 0;
  17841. var lineObj = getLine(doc, lineN);
  17842. for (;;) {
  17843. var found = coordsCharInner(cm, lineObj, lineN, x, y);
  17844. var merged = collapsedSpanAtEnd(lineObj);
  17845. var mergedPos = merged && merged.find(0, true);
  17846. if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
  17847. lineN = lineNo(lineObj = mergedPos.to.line);
  17848. else
  17849. return found;
  17850. }
  17851. }
  17852. function coordsCharInner(cm, lineObj, lineNo, x, y) {
  17853. var innerOff = y - heightAtLine(lineObj);
  17854. var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
  17855. var preparedMeasure = prepareMeasureForLine(cm, lineObj);
  17856. function getX(ch) {
  17857. var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
  17858. wrongLine = true;
  17859. if (innerOff > sp.bottom) return sp.left - adjust;
  17860. else if (innerOff < sp.top) return sp.left + adjust;
  17861. else wrongLine = false;
  17862. return sp.left;
  17863. }
  17864. var bidi = getOrder(lineObj), dist = lineObj.text.length;
  17865. var from = lineLeft(lineObj), to = lineRight(lineObj);
  17866. var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
  17867. if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
  17868. // Do a binary search between these bounds.
  17869. for (;;) {
  17870. if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
  17871. var ch = x < fromX || x - fromX <= toX - x ? from : to;
  17872. var xDiff = x - (ch == from ? fromX : toX);
  17873. while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
  17874. var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
  17875. xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
  17876. return pos;
  17877. }
  17878. var step = Math.ceil(dist / 2), middle = from + step;
  17879. if (bidi) {
  17880. middle = from;
  17881. for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
  17882. }
  17883. var middleX = getX(middle);
  17884. if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
  17885. else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
  17886. }
  17887. }
  17888. var measureText;
  17889. // Compute the default text height.
  17890. function textHeight(display) {
  17891. if (display.cachedTextHeight != null) return display.cachedTextHeight;
  17892. if (measureText == null) {
  17893. measureText = elt("pre");
  17894. // Measure a bunch of lines, for browsers that compute
  17895. // fractional heights.
  17896. for (var i = 0; i < 49; ++i) {
  17897. measureText.appendChild(document.createTextNode("x"));
  17898. measureText.appendChild(elt("br"));
  17899. }
  17900. measureText.appendChild(document.createTextNode("x"));
  17901. }
  17902. removeChildrenAndAdd(display.measure, measureText);
  17903. var height = measureText.offsetHeight / 50;
  17904. if (height > 3) display.cachedTextHeight = height;
  17905. removeChildren(display.measure);
  17906. return height || 1;
  17907. }
  17908. // Compute the default character width.
  17909. function charWidth(display) {
  17910. if (display.cachedCharWidth != null) return display.cachedCharWidth;
  17911. var anchor = elt("span", "xxxxxxxxxx");
  17912. var pre = elt("pre", [anchor]);
  17913. removeChildrenAndAdd(display.measure, pre);
  17914. var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
  17915. if (width > 2) display.cachedCharWidth = width;
  17916. return width || 10;
  17917. }
  17918. // OPERATIONS
  17919. // Operations are used to wrap a series of changes to the editor
  17920. // state in such a way that each change won't have to update the
  17921. // cursor and display (which would be awkward, slow, and
  17922. // error-prone). Instead, display updates are batched and then all
  17923. // combined and executed at once.
  17924. var operationGroup = null;
  17925. var nextOpId = 0;
  17926. // Start a new operation.
  17927. function startOperation(cm) {
  17928. cm.curOp = {
  17929. cm: cm,
  17930. viewChanged: false, // Flag that indicates that lines might need to be redrawn
  17931. startHeight: cm.doc.height, // Used to detect need to update scrollbar
  17932. forceUpdate: false, // Used to force a redraw
  17933. updateInput: null, // Whether to reset the input textarea
  17934. typing: false, // Whether this reset should be careful to leave existing text (for compositing)
  17935. changeObjs: null, // Accumulated changes, for firing change events
  17936. cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
  17937. cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
  17938. selectionChanged: false, // Whether the selection needs to be redrawn
  17939. updateMaxLine: false, // Set when the widest line needs to be determined anew
  17940. scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
  17941. scrollToPos: null, // Used to scroll to a specific position
  17942. id: ++nextOpId // Unique ID
  17943. };
  17944. if (operationGroup) {
  17945. operationGroup.ops.push(cm.curOp);
  17946. } else {
  17947. cm.curOp.ownsGroup = operationGroup = {
  17948. ops: [cm.curOp],
  17949. delayedCallbacks: []
  17950. };
  17951. }
  17952. }
  17953. function fireCallbacksForOps(group) {
  17954. // Calls delayed callbacks and cursorActivity handlers until no
  17955. // new ones appear
  17956. var callbacks = group.delayedCallbacks, i = 0;
  17957. do {
  17958. for (; i < callbacks.length; i++)
  17959. callbacks[i]();
  17960. for (var j = 0; j < group.ops.length; j++) {
  17961. var op = group.ops[j];
  17962. if (op.cursorActivityHandlers)
  17963. while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
  17964. op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
  17965. }
  17966. } while (i < callbacks.length);
  17967. }
  17968. // Finish an operation, updating the display and signalling delayed events
  17969. function endOperation(cm) {
  17970. var op = cm.curOp, group = op.ownsGroup;
  17971. if (!group) return;
  17972. try { fireCallbacksForOps(group); }
  17973. finally {
  17974. operationGroup = null;
  17975. for (var i = 0; i < group.ops.length; i++)
  17976. group.ops[i].cm.curOp = null;
  17977. endOperations(group);
  17978. }
  17979. }
  17980. // The DOM updates done when an operation finishes are batched so
  17981. // that the minimum number of relayouts are required.
  17982. function endOperations(group) {
  17983. var ops = group.ops;
  17984. for (var i = 0; i < ops.length; i++) // Read DOM
  17985. endOperation_R1(ops[i]);
  17986. for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
  17987. endOperation_W1(ops[i]);
  17988. for (var i = 0; i < ops.length; i++) // Read DOM
  17989. endOperation_R2(ops[i]);
  17990. for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
  17991. endOperation_W2(ops[i]);
  17992. for (var i = 0; i < ops.length; i++) // Read DOM
  17993. endOperation_finish(ops[i]);
  17994. }
  17995. function endOperation_R1(op) {
  17996. var cm = op.cm, display = cm.display;
  17997. if (op.updateMaxLine) findMaxLine(cm);
  17998. op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
  17999. op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
  18000. op.scrollToPos.to.line >= display.viewTo) ||
  18001. display.maxLineChanged && cm.options.lineWrapping;
  18002. op.update = op.mustUpdate &&
  18003. new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
  18004. }
  18005. function endOperation_W1(op) {
  18006. op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
  18007. }
  18008. function endOperation_R2(op) {
  18009. var cm = op.cm, display = cm.display;
  18010. if (op.updatedDisplay) updateHeightsInViewport(cm);
  18011. op.barMeasure = measureForScrollbars(cm);
  18012. // If the max line changed since it was last measured, measure it,
  18013. // and ensure the document's width matches it.
  18014. // updateDisplay_W2 will use these properties to do the actual resizing
  18015. if (display.maxLineChanged && !cm.options.lineWrapping) {
  18016. op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
  18017. op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo +
  18018. scrollerCutOff - display.scroller.clientWidth);
  18019. }
  18020. if (op.updatedDisplay || op.selectionChanged)
  18021. op.newSelectionNodes = drawSelection(cm);
  18022. }
  18023. function endOperation_W2(op) {
  18024. var cm = op.cm;
  18025. if (op.adjustWidthTo != null) {
  18026. cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
  18027. if (op.maxScrollLeft < cm.doc.scrollLeft)
  18028. setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
  18029. cm.display.maxLineChanged = false;
  18030. }
  18031. if (op.newSelectionNodes)
  18032. showSelection(cm, op.newSelectionNodes);
  18033. if (op.updatedDisplay)
  18034. setDocumentHeight(cm, op.barMeasure);
  18035. if (op.updatedDisplay || op.startHeight != cm.doc.height)
  18036. updateScrollbars(cm, op.barMeasure);
  18037. if (op.selectionChanged) restartBlink(cm);
  18038. if (cm.state.focused && op.updateInput)
  18039. resetInput(cm, op.typing);
  18040. }
  18041. function endOperation_finish(op) {
  18042. var cm = op.cm, display = cm.display, doc = cm.doc;
  18043. if (op.adjustWidthTo != null && Math.abs(op.barMeasure.scrollWidth - cm.display.scroller.scrollWidth) > 1)
  18044. updateScrollbars(cm);
  18045. if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
  18046. // Abort mouse wheel delta measurement, when scrolling explicitly
  18047. if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
  18048. display.wheelStartX = display.wheelStartY = null;
  18049. // Propagate the scroll position to the actual DOM scroller
  18050. if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
  18051. var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
  18052. display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
  18053. }
  18054. if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
  18055. var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
  18056. display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
  18057. alignHorizontally(cm);
  18058. }
  18059. // If we need to scroll a specific position into view, do so.
  18060. if (op.scrollToPos) {
  18061. var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
  18062. clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
  18063. if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
  18064. }
  18065. // Fire events for markers that are hidden/unidden by editing or
  18066. // undoing
  18067. var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
  18068. if (hidden) for (var i = 0; i < hidden.length; ++i)
  18069. if (!hidden[i].lines.length) signal(hidden[i], "hide");
  18070. if (unhidden) for (var i = 0; i < unhidden.length; ++i)
  18071. if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
  18072. if (display.wrapper.offsetHeight)
  18073. doc.scrollTop = cm.display.scroller.scrollTop;
  18074. // Apply workaround for two webkit bugs
  18075. if (op.updatedDisplay && webkit) {
  18076. if (cm.options.lineWrapping)
  18077. checkForWebkitWidthBug(cm, op.barMeasure); // (Issue #2420)
  18078. if (op.barMeasure.scrollWidth > op.barMeasure.clientWidth &&
  18079. op.barMeasure.scrollWidth < op.barMeasure.clientWidth + 1 &&
  18080. !hScrollbarTakesSpace(cm))
  18081. updateScrollbars(cm); // (Issue #2562)
  18082. }
  18083. // Fire change events, and delayed event handlers
  18084. if (op.changeObjs)
  18085. signal(cm, "changes", cm, op.changeObjs);
  18086. }
  18087. // Run the given function in an operation
  18088. function runInOp(cm, f) {
  18089. if (cm.curOp) return f();
  18090. startOperation(cm);
  18091. try { return f(); }
  18092. finally { endOperation(cm); }
  18093. }
  18094. // Wraps a function in an operation. Returns the wrapped function.
  18095. function operation(cm, f) {
  18096. return function() {
  18097. if (cm.curOp) return f.apply(cm, arguments);
  18098. startOperation(cm);
  18099. try { return f.apply(cm, arguments); }
  18100. finally { endOperation(cm); }
  18101. };
  18102. }
  18103. // Used to add methods to editor and doc instances, wrapping them in
  18104. // operations.
  18105. function methodOp(f) {
  18106. return function() {
  18107. if (this.curOp) return f.apply(this, arguments);
  18108. startOperation(this);
  18109. try { return f.apply(this, arguments); }
  18110. finally { endOperation(this); }
  18111. };
  18112. }
  18113. function docMethodOp(f) {
  18114. return function() {
  18115. var cm = this.cm;
  18116. if (!cm || cm.curOp) return f.apply(this, arguments);
  18117. startOperation(cm);
  18118. try { return f.apply(this, arguments); }
  18119. finally { endOperation(cm); }
  18120. };
  18121. }
  18122. // VIEW TRACKING
  18123. // These objects are used to represent the visible (currently drawn)
  18124. // part of the document. A LineView may correspond to multiple
  18125. // logical lines, if those are connected by collapsed ranges.
  18126. function LineView(doc, line, lineN) {
  18127. // The starting line
  18128. this.line = line;
  18129. // Continuing lines, if any
  18130. this.rest = visualLineContinued(line);
  18131. // Number of logical lines in this visual line
  18132. this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
  18133. this.node = this.text = null;
  18134. this.hidden = lineIsHidden(doc, line);
  18135. }
  18136. // Create a range of LineView objects for the given lines.
  18137. function buildViewArray(cm, from, to) {
  18138. var array = [], nextPos;
  18139. for (var pos = from; pos < to; pos = nextPos) {
  18140. var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
  18141. nextPos = pos + view.size;
  18142. array.push(view);
  18143. }
  18144. return array;
  18145. }
  18146. // Updates the display.view data structure for a given change to the
  18147. // document. From and to are in pre-change coordinates. Lendiff is
  18148. // the amount of lines added or subtracted by the change. This is
  18149. // used for changes that span multiple lines, or change the way
  18150. // lines are divided into visual lines. regLineChange (below)
  18151. // registers single-line changes.
  18152. function regChange(cm, from, to, lendiff) {
  18153. if (from == null) from = cm.doc.first;
  18154. if (to == null) to = cm.doc.first + cm.doc.size;
  18155. if (!lendiff) lendiff = 0;
  18156. var display = cm.display;
  18157. if (lendiff && to < display.viewTo &&
  18158. (display.updateLineNumbers == null || display.updateLineNumbers > from))
  18159. display.updateLineNumbers = from;
  18160. cm.curOp.viewChanged = true;
  18161. if (from >= display.viewTo) { // Change after
  18162. if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
  18163. resetView(cm);
  18164. } else if (to <= display.viewFrom) { // Change before
  18165. if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
  18166. resetView(cm);
  18167. } else {
  18168. display.viewFrom += lendiff;
  18169. display.viewTo += lendiff;
  18170. }
  18171. } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
  18172. resetView(cm);
  18173. } else if (from <= display.viewFrom) { // Top overlap
  18174. var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
  18175. if (cut) {
  18176. display.view = display.view.slice(cut.index);
  18177. display.viewFrom = cut.lineN;
  18178. display.viewTo += lendiff;
  18179. } else {
  18180. resetView(cm);
  18181. }
  18182. } else if (to >= display.viewTo) { // Bottom overlap
  18183. var cut = viewCuttingPoint(cm, from, from, -1);
  18184. if (cut) {
  18185. display.view = display.view.slice(0, cut.index);
  18186. display.viewTo = cut.lineN;
  18187. } else {
  18188. resetView(cm);
  18189. }
  18190. } else { // Gap in the middle
  18191. var cutTop = viewCuttingPoint(cm, from, from, -1);
  18192. var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
  18193. if (cutTop && cutBot) {
  18194. display.view = display.view.slice(0, cutTop.index)
  18195. .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
  18196. .concat(display.view.slice(cutBot.index));
  18197. display.viewTo += lendiff;
  18198. } else {
  18199. resetView(cm);
  18200. }
  18201. }
  18202. var ext = display.externalMeasured;
  18203. if (ext) {
  18204. if (to < ext.lineN)
  18205. ext.lineN += lendiff;
  18206. else if (from < ext.lineN + ext.size)
  18207. display.externalMeasured = null;
  18208. }
  18209. }
  18210. // Register a change to a single line. Type must be one of "text",
  18211. // "gutter", "class", "widget"
  18212. function regLineChange(cm, line, type) {
  18213. cm.curOp.viewChanged = true;
  18214. var display = cm.display, ext = cm.display.externalMeasured;
  18215. if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
  18216. display.externalMeasured = null;
  18217. if (line < display.viewFrom || line >= display.viewTo) return;
  18218. var lineView = display.view[findViewIndex(cm, line)];
  18219. if (lineView.node == null) return;
  18220. var arr = lineView.changes || (lineView.changes = []);
  18221. if (indexOf(arr, type) == -1) arr.push(type);
  18222. }
  18223. // Clear the view.
  18224. function resetView(cm) {
  18225. cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
  18226. cm.display.view = [];
  18227. cm.display.viewOffset = 0;
  18228. }
  18229. // Find the view element corresponding to a given line. Return null
  18230. // when the line isn't visible.
  18231. function findViewIndex(cm, n) {
  18232. if (n >= cm.display.viewTo) return null;
  18233. n -= cm.display.viewFrom;
  18234. if (n < 0) return null;
  18235. var view = cm.display.view;
  18236. for (var i = 0; i < view.length; i++) {
  18237. n -= view[i].size;
  18238. if (n < 0) return i;
  18239. }
  18240. }
  18241. function viewCuttingPoint(cm, oldN, newN, dir) {
  18242. var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
  18243. if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
  18244. return {index: index, lineN: newN};
  18245. for (var i = 0, n = cm.display.viewFrom; i < index; i++)
  18246. n += view[i].size;
  18247. if (n != oldN) {
  18248. if (dir > 0) {
  18249. if (index == view.length - 1) return null;
  18250. diff = (n + view[index].size) - oldN;
  18251. index++;
  18252. } else {
  18253. diff = n - oldN;
  18254. }
  18255. oldN += diff; newN += diff;
  18256. }
  18257. while (visualLineNo(cm.doc, newN) != newN) {
  18258. if (index == (dir < 0 ? 0 : view.length - 1)) return null;
  18259. newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
  18260. index += dir;
  18261. }
  18262. return {index: index, lineN: newN};
  18263. }
  18264. // Force the view to cover a given range, adding empty view element
  18265. // or clipping off existing ones as needed.
  18266. function adjustView(cm, from, to) {
  18267. var display = cm.display, view = display.view;
  18268. if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
  18269. display.view = buildViewArray(cm, from, to);
  18270. display.viewFrom = from;
  18271. } else {
  18272. if (display.viewFrom > from)
  18273. display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
  18274. else if (display.viewFrom < from)
  18275. display.view = display.view.slice(findViewIndex(cm, from));
  18276. display.viewFrom = from;
  18277. if (display.viewTo < to)
  18278. display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
  18279. else if (display.viewTo > to)
  18280. display.view = display.view.slice(0, findViewIndex(cm, to));
  18281. }
  18282. display.viewTo = to;
  18283. }
  18284. // Count the number of lines in the view whose DOM representation is
  18285. // out of date (or nonexistent).
  18286. function countDirtyView(cm) {
  18287. var view = cm.display.view, dirty = 0;
  18288. for (var i = 0; i < view.length; i++) {
  18289. var lineView = view[i];
  18290. if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
  18291. }
  18292. return dirty;
  18293. }
  18294. // INPUT HANDLING
  18295. // Poll for input changes, using the normal rate of polling. This
  18296. // runs as long as the editor is focused.
  18297. function slowPoll(cm) {
  18298. if (cm.display.pollingFast) return;
  18299. cm.display.poll.set(cm.options.pollInterval, function() {
  18300. readInput(cm);
  18301. if (cm.state.focused) slowPoll(cm);
  18302. });
  18303. }
  18304. // When an event has just come in that is likely to add or change
  18305. // something in the input textarea, we poll faster, to ensure that
  18306. // the change appears on the screen quickly.
  18307. function fastPoll(cm) {
  18308. var missed = false;
  18309. cm.display.pollingFast = true;
  18310. function p() {
  18311. var changed = readInput(cm);
  18312. if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
  18313. else {cm.display.pollingFast = false; slowPoll(cm);}
  18314. }
  18315. cm.display.poll.set(20, p);
  18316. }
  18317. // This will be set to an array of strings when copying, so that,
  18318. // when pasting, we know what kind of selections the copied text
  18319. // was made out of.
  18320. var lastCopied = null;
  18321. // Read input from the textarea, and update the document to match.
  18322. // When something is selected, it is present in the textarea, and
  18323. // selected (unless it is huge, in which case a placeholder is
  18324. // used). When nothing is selected, the cursor sits after previously
  18325. // seen text (can be empty), which is stored in prevInput (we must
  18326. // not reset the textarea when typing, because that breaks IME).
  18327. function readInput(cm) {
  18328. var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc;
  18329. // Since this is called a *lot*, try to bail out as cheaply as
  18330. // possible when it is clear that nothing happened. hasSelection
  18331. // will be the case when there is a lot of text in the textarea,
  18332. // in which case reading its value would be expensive.
  18333. if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput)
  18334. return false;
  18335. // See paste handler for more on the fakedLastChar kludge
  18336. if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
  18337. input.value = input.value.substring(0, input.value.length - 1);
  18338. cm.state.fakedLastChar = false;
  18339. }
  18340. var text = input.value;
  18341. // If nothing changed, bail.
  18342. if (text == prevInput && !cm.somethingSelected()) return false;
  18343. // Work around nonsensical selection resetting in IE9/10, and
  18344. // inexplicable appearance of private area unicode characters on
  18345. // some key combos in Mac (#2689).
  18346. if (ie && ie_version >= 9 && cm.display.inputHasSelection === text ||
  18347. mac && /[\uf700-\uf7ff]/.test(text)) {
  18348. resetInput(cm);
  18349. return false;
  18350. }
  18351. var withOp = !cm.curOp;
  18352. if (withOp) startOperation(cm);
  18353. cm.display.shift = false;
  18354. if (text.charCodeAt(0) == 0x200b && doc.sel == cm.display.selForContextMenu && !prevInput)
  18355. prevInput = "\u200b";
  18356. // Find the part of the input that is actually new
  18357. var same = 0, l = Math.min(prevInput.length, text.length);
  18358. while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
  18359. var inserted = text.slice(same), textLines = splitLines(inserted);
  18360. // When pasing N lines into N selections, insert one line per selection
  18361. var multiPaste = null;
  18362. if (cm.state.pasteIncoming && doc.sel.ranges.length > 1) {
  18363. if (lastCopied && lastCopied.join("\n") == inserted)
  18364. multiPaste = doc.sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines);
  18365. else if (textLines.length == doc.sel.ranges.length)
  18366. multiPaste = map(textLines, function(l) { return [l]; });
  18367. }
  18368. // Normal behavior is to insert the new text into every selection
  18369. for (var i = doc.sel.ranges.length - 1; i >= 0; i--) {
  18370. var range = doc.sel.ranges[i];
  18371. var from = range.from(), to = range.to();
  18372. // Handle deletion
  18373. if (same < prevInput.length)
  18374. from = Pos(from.line, from.ch - (prevInput.length - same));
  18375. // Handle overwrite
  18376. else if (cm.state.overwrite && range.empty() && !cm.state.pasteIncoming)
  18377. to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
  18378. var updateInput = cm.curOp.updateInput;
  18379. var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
  18380. origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"};
  18381. makeChange(cm.doc, changeEvent);
  18382. signalLater(cm, "inputRead", cm, changeEvent);
  18383. // When an 'electric' character is inserted, immediately trigger a reindent
  18384. if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
  18385. cm.options.smartIndent && range.head.ch < 100 &&
  18386. (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) {
  18387. var mode = cm.getModeAt(range.head);
  18388. var end = changeEnd(changeEvent);
  18389. if (mode.electricChars) {
  18390. for (var j = 0; j < mode.electricChars.length; j++)
  18391. if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
  18392. indentLine(cm, end.line, "smart");
  18393. break;
  18394. }
  18395. } else if (mode.electricInput) {
  18396. if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
  18397. indentLine(cm, end.line, "smart");
  18398. }
  18399. }
  18400. }
  18401. ensureCursorVisible(cm);
  18402. cm.curOp.updateInput = updateInput;
  18403. cm.curOp.typing = true;
  18404. // Don't leave long text in the textarea, since it makes further polling slow
  18405. if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
  18406. else cm.display.prevInput = text;
  18407. if (withOp) endOperation(cm);
  18408. cm.state.pasteIncoming = cm.state.cutIncoming = false;
  18409. return true;
  18410. }
  18411. // Reset the input to correspond to the selection (or to be empty,
  18412. // when not typing and nothing is selected)
  18413. function resetInput(cm, typing) {
  18414. var minimal, selected, doc = cm.doc;
  18415. if (cm.somethingSelected()) {
  18416. cm.display.prevInput = "";
  18417. var range = doc.sel.primary();
  18418. minimal = hasCopyEvent &&
  18419. (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
  18420. var content = minimal ? "-" : selected || cm.getSelection();
  18421. cm.display.input.value = content;
  18422. if (cm.state.focused) selectInput(cm.display.input);
  18423. if (ie && ie_version >= 9) cm.display.inputHasSelection = content;
  18424. } else if (!typing) {
  18425. cm.display.prevInput = cm.display.input.value = "";
  18426. if (ie && ie_version >= 9) cm.display.inputHasSelection = null;
  18427. }
  18428. cm.display.inaccurateSelection = minimal;
  18429. }
  18430. function focusInput(cm) {
  18431. if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.display.input))
  18432. cm.display.input.focus();
  18433. }
  18434. function ensureFocus(cm) {
  18435. if (!cm.state.focused) { focusInput(cm); onFocus(cm); }
  18436. }
  18437. function isReadOnly(cm) {
  18438. return cm.options.readOnly || cm.doc.cantEdit;
  18439. }
  18440. // EVENT HANDLERS
  18441. // Attach the necessary event handlers when initializing the editor
  18442. function registerEventHandlers(cm) {
  18443. var d = cm.display;
  18444. on(d.scroller, "mousedown", operation(cm, onMouseDown));
  18445. // Older IE's will not fire a second mousedown for a double click
  18446. if (ie && ie_version < 11)
  18447. on(d.scroller, "dblclick", operation(cm, function(e) {
  18448. if (signalDOMEvent(cm, e)) return;
  18449. var pos = posFromMouse(cm, e);
  18450. if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
  18451. e_preventDefault(e);
  18452. var word = cm.findWordAt(pos);
  18453. extendSelection(cm.doc, word.anchor, word.head);
  18454. }));
  18455. else
  18456. on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
  18457. // Prevent normal selection in the editor (we handle our own)
  18458. on(d.lineSpace, "selectstart", function(e) {
  18459. if (!eventInWidget(d, e)) e_preventDefault(e);
  18460. });
  18461. // Some browsers fire contextmenu *after* opening the menu, at
  18462. // which point we can't mess with it anymore. Context menu is
  18463. // handled in onMouseDown for these browsers.
  18464. if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
  18465. // Sync scrolling between fake scrollbars and real scrollable
  18466. // area, ensure viewport is updated when scrolling.
  18467. on(d.scroller, "scroll", function() {
  18468. if (d.scroller.clientHeight) {
  18469. setScrollTop(cm, d.scroller.scrollTop);
  18470. setScrollLeft(cm, d.scroller.scrollLeft, true);
  18471. signal(cm, "scroll", cm);
  18472. }
  18473. });
  18474. on(d.scrollbarV, "scroll", function() {
  18475. if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
  18476. });
  18477. on(d.scrollbarH, "scroll", function() {
  18478. if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
  18479. });
  18480. // Listen to wheel events in order to try and update the viewport on time.
  18481. on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
  18482. on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
  18483. // Prevent clicks in the scrollbars from killing focus
  18484. function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
  18485. on(d.scrollbarH, "mousedown", reFocus);
  18486. on(d.scrollbarV, "mousedown", reFocus);
  18487. // Prevent wrapper from ever scrolling
  18488. on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
  18489. on(d.input, "keyup", function(e) { onKeyUp.call(cm, e); });
  18490. on(d.input, "input", function() {
  18491. if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
  18492. fastPoll(cm);
  18493. });
  18494. on(d.input, "keydown", operation(cm, onKeyDown));
  18495. on(d.input, "keypress", operation(cm, onKeyPress));
  18496. on(d.input, "focus", bind(onFocus, cm));
  18497. on(d.input, "blur", bind(onBlur, cm));
  18498. function drag_(e) {
  18499. if (!signalDOMEvent(cm, e)) e_stop(e);
  18500. }
  18501. if (cm.options.dragDrop) {
  18502. on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
  18503. on(d.scroller, "dragenter", drag_);
  18504. on(d.scroller, "dragover", drag_);
  18505. on(d.scroller, "drop", operation(cm, onDrop));
  18506. }
  18507. on(d.scroller, "paste", function(e) {
  18508. if (eventInWidget(d, e)) return;
  18509. cm.state.pasteIncoming = true;
  18510. focusInput(cm);
  18511. fastPoll(cm);
  18512. });
  18513. on(d.input, "paste", function() {
  18514. // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
  18515. // Add a char to the end of textarea before paste occur so that
  18516. // selection doesn't span to the end of textarea.
  18517. if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
  18518. var start = d.input.selectionStart, end = d.input.selectionEnd;
  18519. d.input.value += "$";
  18520. // The selection end needs to be set before the start, otherwise there
  18521. // can be an intermediate non-empty selection between the two, which
  18522. // can override the middle-click paste buffer on linux and cause the
  18523. // wrong thing to get pasted.
  18524. d.input.selectionEnd = end;
  18525. d.input.selectionStart = start;
  18526. cm.state.fakedLastChar = true;
  18527. }
  18528. cm.state.pasteIncoming = true;
  18529. fastPoll(cm);
  18530. });
  18531. function prepareCopyCut(e) {
  18532. if (cm.somethingSelected()) {
  18533. lastCopied = cm.getSelections();
  18534. if (d.inaccurateSelection) {
  18535. d.prevInput = "";
  18536. d.inaccurateSelection = false;
  18537. d.input.value = lastCopied.join("\n");
  18538. selectInput(d.input);
  18539. }
  18540. } else {
  18541. var text = [], ranges = [];
  18542. for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
  18543. var line = cm.doc.sel.ranges[i].head.line;
  18544. var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
  18545. ranges.push(lineRange);
  18546. text.push(cm.getRange(lineRange.anchor, lineRange.head));
  18547. }
  18548. if (e.type == "cut") {
  18549. cm.setSelections(ranges, null, sel_dontScroll);
  18550. } else {
  18551. d.prevInput = "";
  18552. d.input.value = text.join("\n");
  18553. selectInput(d.input);
  18554. }
  18555. lastCopied = text;
  18556. }
  18557. if (e.type == "cut") cm.state.cutIncoming = true;
  18558. }
  18559. on(d.input, "cut", prepareCopyCut);
  18560. on(d.input, "copy", prepareCopyCut);
  18561. // Needed to handle Tab key in KHTML
  18562. if (khtml) on(d.sizer, "mouseup", function() {
  18563. if (activeElt() == d.input) d.input.blur();
  18564. focusInput(cm);
  18565. });
  18566. }
  18567. // Called when the window resizes
  18568. function onResize(cm) {
  18569. // Might be a text scaling operation, clear size caches.
  18570. var d = cm.display;
  18571. d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
  18572. cm.setSize();
  18573. }
  18574. // MOUSE EVENTS
  18575. // Return true when the given mouse event happened in a widget
  18576. function eventInWidget(display, e) {
  18577. for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
  18578. if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
  18579. }
  18580. }
  18581. // Given a mouse event, find the corresponding position. If liberal
  18582. // is false, it checks whether a gutter or scrollbar was clicked,
  18583. // and returns null if it was. forRect is used by rectangular
  18584. // selections, and tries to estimate a character position even for
  18585. // coordinates beyond the right of the text.
  18586. function posFromMouse(cm, e, liberal, forRect) {
  18587. var display = cm.display;
  18588. if (!liberal) {
  18589. var target = e_target(e);
  18590. if (target == display.scrollbarH || target == display.scrollbarV ||
  18591. target == display.scrollbarFiller || target == display.gutterFiller) return null;
  18592. }
  18593. var x, y, space = display.lineSpace.getBoundingClientRect();
  18594. // Fails unpredictably on IE[67] when mouse is dragged around quickly.
  18595. try { x = e.clientX - space.left; y = e.clientY - space.top; }
  18596. catch (e) { return null; }
  18597. var coords = coordsChar(cm, x, y), line;
  18598. if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
  18599. var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
  18600. coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
  18601. }
  18602. return coords;
  18603. }
  18604. // A mouse down can be a single click, double click, triple click,
  18605. // start of selection drag, start of text drag, new cursor
  18606. // (ctrl-click), rectangle drag (alt-drag), or xwin
  18607. // middle-click-paste. Or it might be a click on something we should
  18608. // not interfere with, such as a scrollbar or widget.
  18609. function onMouseDown(e) {
  18610. if (signalDOMEvent(this, e)) return;
  18611. var cm = this, display = cm.display;
  18612. display.shift = e.shiftKey;
  18613. if (eventInWidget(display, e)) {
  18614. if (!webkit) {
  18615. // Briefly turn off draggability, to allow widgets to do
  18616. // normal dragging things.
  18617. display.scroller.draggable = false;
  18618. setTimeout(function(){display.scroller.draggable = true;}, 100);
  18619. }
  18620. return;
  18621. }
  18622. if (clickInGutter(cm, e)) return;
  18623. var start = posFromMouse(cm, e);
  18624. window.focus();
  18625. switch (e_button(e)) {
  18626. case 1:
  18627. if (start)
  18628. leftButtonDown(cm, e, start);
  18629. else if (e_target(e) == display.scroller)
  18630. e_preventDefault(e);
  18631. break;
  18632. case 2:
  18633. if (webkit) cm.state.lastMiddleDown = +new Date;
  18634. if (start) extendSelection(cm.doc, start);
  18635. setTimeout(bind(focusInput, cm), 20);
  18636. e_preventDefault(e);
  18637. break;
  18638. case 3:
  18639. if (captureRightClick) onContextMenu(cm, e);
  18640. break;
  18641. }
  18642. }
  18643. var lastClick, lastDoubleClick;
  18644. function leftButtonDown(cm, e, start) {
  18645. setTimeout(bind(ensureFocus, cm), 0);
  18646. var now = +new Date, type;
  18647. if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
  18648. type = "triple";
  18649. } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
  18650. type = "double";
  18651. lastDoubleClick = {time: now, pos: start};
  18652. } else {
  18653. type = "single";
  18654. lastClick = {time: now, pos: start};
  18655. }
  18656. var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey;
  18657. if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
  18658. type == "single" && sel.contains(start) > -1 && sel.somethingSelected())
  18659. leftButtonStartDrag(cm, e, start, modifier);
  18660. else
  18661. leftButtonSelect(cm, e, start, type, modifier);
  18662. }
  18663. // Start a text drag. When it ends, see if any dragging actually
  18664. // happen, and treat as a click if it didn't.
  18665. function leftButtonStartDrag(cm, e, start, modifier) {
  18666. var display = cm.display;
  18667. var dragEnd = operation(cm, function(e2) {
  18668. if (webkit) display.scroller.draggable = false;
  18669. cm.state.draggingText = false;
  18670. off(document, "mouseup", dragEnd);
  18671. off(display.scroller, "drop", dragEnd);
  18672. if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
  18673. e_preventDefault(e2);
  18674. if (!modifier)
  18675. extendSelection(cm.doc, start);
  18676. focusInput(cm);
  18677. // Work around unexplainable focus problem in IE9 (#2127)
  18678. if (ie && ie_version == 9)
  18679. setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
  18680. }
  18681. });
  18682. // Let the drag handler handle this.
  18683. if (webkit) display.scroller.draggable = true;
  18684. cm.state.draggingText = dragEnd;
  18685. // IE's approach to draggable
  18686. if (display.scroller.dragDrop) display.scroller.dragDrop();
  18687. on(document, "mouseup", dragEnd);
  18688. on(display.scroller, "drop", dragEnd);
  18689. }
  18690. // Normal selection, as opposed to text dragging.
  18691. function leftButtonSelect(cm, e, start, type, addNew) {
  18692. var display = cm.display, doc = cm.doc;
  18693. e_preventDefault(e);
  18694. var ourRange, ourIndex, startSel = doc.sel;
  18695. if (addNew && !e.shiftKey) {
  18696. ourIndex = doc.sel.contains(start);
  18697. if (ourIndex > -1)
  18698. ourRange = doc.sel.ranges[ourIndex];
  18699. else
  18700. ourRange = new Range(start, start);
  18701. } else {
  18702. ourRange = doc.sel.primary();
  18703. }
  18704. if (e.altKey) {
  18705. type = "rect";
  18706. if (!addNew) ourRange = new Range(start, start);
  18707. start = posFromMouse(cm, e, true, true);
  18708. ourIndex = -1;
  18709. } else if (type == "double") {
  18710. var word = cm.findWordAt(start);
  18711. if (cm.display.shift || doc.extend)
  18712. ourRange = extendRange(doc, ourRange, word.anchor, word.head);
  18713. else
  18714. ourRange = word;
  18715. } else if (type == "triple") {
  18716. var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
  18717. if (cm.display.shift || doc.extend)
  18718. ourRange = extendRange(doc, ourRange, line.anchor, line.head);
  18719. else
  18720. ourRange = line;
  18721. } else {
  18722. ourRange = extendRange(doc, ourRange, start);
  18723. }
  18724. if (!addNew) {
  18725. ourIndex = 0;
  18726. setSelection(doc, new Selection([ourRange], 0), sel_mouse);
  18727. startSel = doc.sel;
  18728. } else if (ourIndex > -1) {
  18729. replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
  18730. } else {
  18731. ourIndex = doc.sel.ranges.length;
  18732. setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
  18733. {scroll: false, origin: "*mouse"});
  18734. }
  18735. var lastPos = start;
  18736. function extendTo(pos) {
  18737. if (cmp(lastPos, pos) == 0) return;
  18738. lastPos = pos;
  18739. if (type == "rect") {
  18740. var ranges = [], tabSize = cm.options.tabSize;
  18741. var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
  18742. var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
  18743. var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
  18744. for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
  18745. line <= end; line++) {
  18746. var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
  18747. if (left == right)
  18748. ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
  18749. else if (text.length > leftPos)
  18750. ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
  18751. }
  18752. if (!ranges.length) ranges.push(new Range(start, start));
  18753. setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
  18754. {origin: "*mouse", scroll: false});
  18755. cm.scrollIntoView(pos);
  18756. } else {
  18757. var oldRange = ourRange;
  18758. var anchor = oldRange.anchor, head = pos;
  18759. if (type != "single") {
  18760. if (type == "double")
  18761. var range = cm.findWordAt(pos);
  18762. else
  18763. var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
  18764. if (cmp(range.anchor, anchor) > 0) {
  18765. head = range.head;
  18766. anchor = minPos(oldRange.from(), range.anchor);
  18767. } else {
  18768. head = range.anchor;
  18769. anchor = maxPos(oldRange.to(), range.head);
  18770. }
  18771. }
  18772. var ranges = startSel.ranges.slice(0);
  18773. ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
  18774. setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
  18775. }
  18776. }
  18777. var editorSize = display.wrapper.getBoundingClientRect();
  18778. // Used to ensure timeout re-tries don't fire when another extend
  18779. // happened in the meantime (clearTimeout isn't reliable -- at
  18780. // least on Chrome, the timeouts still happen even when cleared,
  18781. // if the clear happens after their scheduled firing time).
  18782. var counter = 0;
  18783. function extend(e) {
  18784. var curCount = ++counter;
  18785. var cur = posFromMouse(cm, e, true, type == "rect");
  18786. if (!cur) return;
  18787. if (cmp(cur, lastPos) != 0) {
  18788. ensureFocus(cm);
  18789. extendTo(cur);
  18790. var visible = visibleLines(display, doc);
  18791. if (cur.line >= visible.to || cur.line < visible.from)
  18792. setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
  18793. } else {
  18794. var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
  18795. if (outside) setTimeout(operation(cm, function() {
  18796. if (counter != curCount) return;
  18797. display.scroller.scrollTop += outside;
  18798. extend(e);
  18799. }), 50);
  18800. }
  18801. }
  18802. function done(e) {
  18803. counter = Infinity;
  18804. e_preventDefault(e);
  18805. focusInput(cm);
  18806. off(document, "mousemove", move);
  18807. off(document, "mouseup", up);
  18808. doc.history.lastSelOrigin = null;
  18809. }
  18810. var move = operation(cm, function(e) {
  18811. if (!e_button(e)) done(e);
  18812. else extend(e);
  18813. });
  18814. var up = operation(cm, done);
  18815. on(document, "mousemove", move);
  18816. on(document, "mouseup", up);
  18817. }
  18818. // Determines whether an event happened in the gutter, and fires the
  18819. // handlers for the corresponding event.
  18820. function gutterEvent(cm, e, type, prevent, signalfn) {
  18821. try { var mX = e.clientX, mY = e.clientY; }
  18822. catch(e) { return false; }
  18823. if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
  18824. if (prevent) e_preventDefault(e);
  18825. var display = cm.display;
  18826. var lineBox = display.lineDiv.getBoundingClientRect();
  18827. if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
  18828. mY -= lineBox.top - display.viewOffset;
  18829. for (var i = 0; i < cm.options.gutters.length; ++i) {
  18830. var g = display.gutters.childNodes[i];
  18831. if (g && g.getBoundingClientRect().right >= mX) {
  18832. var line = lineAtHeight(cm.doc, mY);
  18833. var gutter = cm.options.gutters[i];
  18834. signalfn(cm, type, cm, line, gutter, e);
  18835. return e_defaultPrevented(e);
  18836. }
  18837. }
  18838. }
  18839. function clickInGutter(cm, e) {
  18840. return gutterEvent(cm, e, "gutterClick", true, signalLater);
  18841. }
  18842. // Kludge to work around strange IE behavior where it'll sometimes
  18843. // re-fire a series of drag-related events right after the drop (#1551)
  18844. var lastDrop = 0;
  18845. function onDrop(e) {
  18846. var cm = this;
  18847. if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
  18848. return;
  18849. e_preventDefault(e);
  18850. if (ie) lastDrop = +new Date;
  18851. var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
  18852. if (!pos || isReadOnly(cm)) return;
  18853. // Might be a file drop, in which case we simply extract the text
  18854. // and insert it.
  18855. if (files && files.length && window.FileReader && window.File) {
  18856. var n = files.length, text = Array(n), read = 0;
  18857. var loadFile = function(file, i) {
  18858. var reader = new FileReader;
  18859. reader.onload = operation(cm, function() {
  18860. text[i] = reader.result;
  18861. if (++read == n) {
  18862. pos = clipPos(cm.doc, pos);
  18863. var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
  18864. makeChange(cm.doc, change);
  18865. setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
  18866. }
  18867. });
  18868. reader.readAsText(file);
  18869. };
  18870. for (var i = 0; i < n; ++i) loadFile(files[i], i);
  18871. } else { // Normal drop
  18872. // Don't do a replace if the drop happened inside of the selected text.
  18873. if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
  18874. cm.state.draggingText(e);
  18875. // Ensure the editor is re-focused
  18876. setTimeout(bind(focusInput, cm), 20);
  18877. return;
  18878. }
  18879. try {
  18880. var text = e.dataTransfer.getData("Text");
  18881. if (text) {
  18882. if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey))
  18883. var selected = cm.listSelections();
  18884. setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
  18885. if (selected) for (var i = 0; i < selected.length; ++i)
  18886. replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
  18887. cm.replaceSelection(text, "around", "paste");
  18888. focusInput(cm);
  18889. }
  18890. }
  18891. catch(e){}
  18892. }
  18893. }
  18894. function onDragStart(cm, e) {
  18895. if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
  18896. if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
  18897. e.dataTransfer.setData("Text", cm.getSelection());
  18898. // Use dummy image instead of default browsers image.
  18899. // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
  18900. if (e.dataTransfer.setDragImage && !safari) {
  18901. var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
  18902. img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
  18903. if (presto) {
  18904. img.width = img.height = 1;
  18905. cm.display.wrapper.appendChild(img);
  18906. // Force a relayout, or Opera won't use our image for some obscure reason
  18907. img._top = img.offsetTop;
  18908. }
  18909. e.dataTransfer.setDragImage(img, 0, 0);
  18910. if (presto) img.parentNode.removeChild(img);
  18911. }
  18912. }
  18913. // SCROLL EVENTS
  18914. // Sync the scrollable area and scrollbars, ensure the viewport
  18915. // covers the visible area.
  18916. function setScrollTop(cm, val) {
  18917. if (Math.abs(cm.doc.scrollTop - val) < 2) return;
  18918. cm.doc.scrollTop = val;
  18919. if (!gecko) updateDisplaySimple(cm, {top: val});
  18920. if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
  18921. if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
  18922. if (gecko) updateDisplaySimple(cm);
  18923. startWorker(cm, 100);
  18924. }
  18925. // Sync scroller and scrollbar, ensure the gutter elements are
  18926. // aligned.
  18927. function setScrollLeft(cm, val, isScroller) {
  18928. if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
  18929. val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
  18930. cm.doc.scrollLeft = val;
  18931. alignHorizontally(cm);
  18932. if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
  18933. if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
  18934. }
  18935. // Since the delta values reported on mouse wheel events are
  18936. // unstandardized between browsers and even browser versions, and
  18937. // generally horribly unpredictable, this code starts by measuring
  18938. // the scroll effect that the first few mouse wheel events have,
  18939. // and, from that, detects the way it can convert deltas to pixel
  18940. // offsets afterwards.
  18941. //
  18942. // The reason we want to know the amount a wheel event will scroll
  18943. // is that it gives us a chance to update the display before the
  18944. // actual scrolling happens, reducing flickering.
  18945. var wheelSamples = 0, wheelPixelsPerUnit = null;
  18946. // Fill in a browser-detected starting value on browsers where we
  18947. // know one. These don't have to be accurate -- the result of them
  18948. // being wrong would just be a slight flicker on the first wheel
  18949. // scroll (if it is large enough).
  18950. if (ie) wheelPixelsPerUnit = -.53;
  18951. else if (gecko) wheelPixelsPerUnit = 15;
  18952. else if (chrome) wheelPixelsPerUnit = -.7;
  18953. else if (safari) wheelPixelsPerUnit = -1/3;
  18954. function onScrollWheel(cm, e) {
  18955. var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
  18956. if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
  18957. if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
  18958. else if (dy == null) dy = e.wheelDelta;
  18959. var display = cm.display, scroll = display.scroller;
  18960. // Quit if there's nothing to scroll here
  18961. if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
  18962. dy && scroll.scrollHeight > scroll.clientHeight)) return;
  18963. // Webkit browsers on OS X abort momentum scrolls when the target
  18964. // of the scroll event is removed from the scrollable element.
  18965. // This hack (see related code in patchDisplay) makes sure the
  18966. // element is kept around.
  18967. if (dy && mac && webkit) {
  18968. outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
  18969. for (var i = 0; i < view.length; i++) {
  18970. if (view[i].node == cur) {
  18971. cm.display.currentWheelTarget = cur;
  18972. break outer;
  18973. }
  18974. }
  18975. }
  18976. }
  18977. // On some browsers, horizontal scrolling will cause redraws to
  18978. // happen before the gutter has been realigned, causing it to
  18979. // wriggle around in a most unseemly way. When we have an
  18980. // estimated pixels/delta value, we just handle horizontal
  18981. // scrolling entirely here. It'll be slightly off from native, but
  18982. // better than glitching out.
  18983. if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
  18984. if (dy)
  18985. setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
  18986. setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
  18987. e_preventDefault(e);
  18988. display.wheelStartX = null; // Abort measurement, if in progress
  18989. return;
  18990. }
  18991. // 'Project' the visible viewport to cover the area that is being
  18992. // scrolled into view (if we know enough to estimate it).
  18993. if (dy && wheelPixelsPerUnit != null) {
  18994. var pixels = dy * wheelPixelsPerUnit;
  18995. var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
  18996. if (pixels < 0) top = Math.max(0, top + pixels - 50);
  18997. else bot = Math.min(cm.doc.height, bot + pixels + 50);
  18998. updateDisplaySimple(cm, {top: top, bottom: bot});
  18999. }
  19000. if (wheelSamples < 20) {
  19001. if (display.wheelStartX == null) {
  19002. display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
  19003. display.wheelDX = dx; display.wheelDY = dy;
  19004. setTimeout(function() {
  19005. if (display.wheelStartX == null) return;
  19006. var movedX = scroll.scrollLeft - display.wheelStartX;
  19007. var movedY = scroll.scrollTop - display.wheelStartY;
  19008. var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
  19009. (movedX && display.wheelDX && movedX / display.wheelDX);
  19010. display.wheelStartX = display.wheelStartY = null;
  19011. if (!sample) return;
  19012. wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
  19013. ++wheelSamples;
  19014. }, 200);
  19015. } else {
  19016. display.wheelDX += dx; display.wheelDY += dy;
  19017. }
  19018. }
  19019. }
  19020. // KEY EVENTS
  19021. // Run a handler that was bound to a key.
  19022. function doHandleBinding(cm, bound, dropShift) {
  19023. if (typeof bound == "string") {
  19024. bound = commands[bound];
  19025. if (!bound) return false;
  19026. }
  19027. // Ensure previous input has been read, so that the handler sees a
  19028. // consistent view of the document
  19029. if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false;
  19030. var prevShift = cm.display.shift, done = false;
  19031. try {
  19032. if (isReadOnly(cm)) cm.state.suppressEdits = true;
  19033. if (dropShift) cm.display.shift = false;
  19034. done = bound(cm) != Pass;
  19035. } finally {
  19036. cm.display.shift = prevShift;
  19037. cm.state.suppressEdits = false;
  19038. }
  19039. return done;
  19040. }
  19041. // Collect the currently active keymaps.
  19042. function allKeyMaps(cm) {
  19043. var maps = cm.state.keyMaps.slice(0);
  19044. if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
  19045. maps.push(cm.options.keyMap);
  19046. return maps;
  19047. }
  19048. var maybeTransition;
  19049. // Handle a key from the keydown event.
  19050. function handleKeyBinding(cm, e) {
  19051. // Handle automatic keymap transitions
  19052. var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
  19053. clearTimeout(maybeTransition);
  19054. if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
  19055. if (getKeyMap(cm.options.keyMap) == startMap) {
  19056. cm.options.keyMap = (next.call ? next.call(null, cm) : next);
  19057. keyMapChanged(cm);
  19058. }
  19059. }, 50);
  19060. var name = keyName(e, true), handled = false;
  19061. if (!name) return false;
  19062. var keymaps = allKeyMaps(cm);
  19063. if (e.shiftKey) {
  19064. // First try to resolve full name (including 'Shift-'). Failing
  19065. // that, see if there is a cursor-motion command (starting with
  19066. // 'go') bound to the keyname without 'Shift-'.
  19067. handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
  19068. || lookupKey(name, keymaps, function(b) {
  19069. if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
  19070. return doHandleBinding(cm, b);
  19071. });
  19072. } else {
  19073. handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
  19074. }
  19075. if (handled) {
  19076. e_preventDefault(e);
  19077. restartBlink(cm);
  19078. signalLater(cm, "keyHandled", cm, name, e);
  19079. }
  19080. return handled;
  19081. }
  19082. // Handle a key from the keypress event
  19083. function handleCharBinding(cm, e, ch) {
  19084. var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
  19085. function(b) { return doHandleBinding(cm, b, true); });
  19086. if (handled) {
  19087. e_preventDefault(e);
  19088. restartBlink(cm);
  19089. signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
  19090. }
  19091. return handled;
  19092. }
  19093. var lastStoppedKey = null;
  19094. function onKeyDown(e) {
  19095. var cm = this;
  19096. ensureFocus(cm);
  19097. if (signalDOMEvent(cm, e)) return;
  19098. // IE does strange things with escape.
  19099. if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
  19100. var code = e.keyCode;
  19101. cm.display.shift = code == 16 || e.shiftKey;
  19102. var handled = handleKeyBinding(cm, e);
  19103. if (presto) {
  19104. lastStoppedKey = handled ? code : null;
  19105. // Opera has no cut event... we try to at least catch the key combo
  19106. if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
  19107. cm.replaceSelection("", null, "cut");
  19108. }
  19109. // Turn mouse into crosshair when Alt is held on Mac.
  19110. if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
  19111. showCrossHair(cm);
  19112. }
  19113. function showCrossHair(cm) {
  19114. var lineDiv = cm.display.lineDiv;
  19115. addClass(lineDiv, "CodeMirror-crosshair");
  19116. function up(e) {
  19117. if (e.keyCode == 18 || !e.altKey) {
  19118. rmClass(lineDiv, "CodeMirror-crosshair");
  19119. off(document, "keyup", up);
  19120. off(document, "mouseover", up);
  19121. }
  19122. }
  19123. on(document, "keyup", up);
  19124. on(document, "mouseover", up);
  19125. }
  19126. function onKeyUp(e) {
  19127. if (e.keyCode == 16) this.doc.sel.shift = false;
  19128. signalDOMEvent(this, e);
  19129. }
  19130. function onKeyPress(e) {
  19131. var cm = this;
  19132. if (signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
  19133. var keyCode = e.keyCode, charCode = e.charCode;
  19134. if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
  19135. if (((presto && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
  19136. var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
  19137. if (handleCharBinding(cm, e, ch)) return;
  19138. if (ie && ie_version >= 9) cm.display.inputHasSelection = null;
  19139. fastPoll(cm);
  19140. }
  19141. // FOCUS/BLUR EVENTS
  19142. function onFocus(cm) {
  19143. if (cm.options.readOnly == "nocursor") return;
  19144. if (!cm.state.focused) {
  19145. signal(cm, "focus", cm);
  19146. cm.state.focused = true;
  19147. addClass(cm.display.wrapper, "CodeMirror-focused");
  19148. // The prevInput test prevents this from firing when a context
  19149. // menu is closed (since the resetInput would kill the
  19150. // select-all detection hack)
  19151. if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
  19152. resetInput(cm);
  19153. if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
  19154. }
  19155. }
  19156. slowPoll(cm);
  19157. restartBlink(cm);
  19158. }
  19159. function onBlur(cm) {
  19160. if (cm.state.focused) {
  19161. signal(cm, "blur", cm);
  19162. cm.state.focused = false;
  19163. rmClass(cm.display.wrapper, "CodeMirror-focused");
  19164. }
  19165. clearInterval(cm.display.blinker);
  19166. setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
  19167. }
  19168. // CONTEXT MENU HANDLING
  19169. // To make the context menu work, we need to briefly unhide the
  19170. // textarea (making it as unobtrusive as possible) to let the
  19171. // right-click take effect on it.
  19172. function onContextMenu(cm, e) {
  19173. if (signalDOMEvent(cm, e, "contextmenu")) return;
  19174. var display = cm.display;
  19175. if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
  19176. var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
  19177. if (!pos || presto) return; // Opera is difficult.
  19178. // Reset the current text selection only if the click is done outside of the selection
  19179. // and 'resetSelectionOnContextMenu' option is true.
  19180. var reset = cm.options.resetSelectionOnContextMenu;
  19181. if (reset && cm.doc.sel.contains(pos) == -1)
  19182. operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
  19183. var oldCSS = display.input.style.cssText;
  19184. display.inputDiv.style.position = "absolute";
  19185. display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
  19186. "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
  19187. (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
  19188. "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
  19189. if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
  19190. focusInput(cm);
  19191. if (webkit) window.scrollTo(null, oldScrollY);
  19192. resetInput(cm);
  19193. // Adds "Select all" to context menu in FF
  19194. if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
  19195. display.selForContextMenu = cm.doc.sel;
  19196. clearTimeout(display.detectingSelectAll);
  19197. // Select-all will be greyed out if there's nothing to select, so
  19198. // this adds a zero-width space so that we can later check whether
  19199. // it got selected.
  19200. function prepareSelectAllHack() {
  19201. if (display.input.selectionStart != null) {
  19202. var selected = cm.somethingSelected();
  19203. var extval = display.input.value = "\u200b" + (selected ? display.input.value : "");
  19204. display.prevInput = selected ? "" : "\u200b";
  19205. display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
  19206. // Re-set this, in case some other handler touched the
  19207. // selection in the meantime.
  19208. display.selForContextMenu = cm.doc.sel;
  19209. }
  19210. }
  19211. function rehide() {
  19212. display.inputDiv.style.position = "relative";
  19213. display.input.style.cssText = oldCSS;
  19214. if (ie && ie_version < 9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
  19215. slowPoll(cm);
  19216. // Try to detect the user choosing select-all
  19217. if (display.input.selectionStart != null) {
  19218. if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
  19219. var i = 0, poll = function() {
  19220. if (display.selForContextMenu == cm.doc.sel && display.input.selectionStart == 0)
  19221. operation(cm, commands.selectAll)(cm);
  19222. else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
  19223. else resetInput(cm);
  19224. };
  19225. display.detectingSelectAll = setTimeout(poll, 200);
  19226. }
  19227. }
  19228. if (ie && ie_version >= 9) prepareSelectAllHack();
  19229. if (captureRightClick) {
  19230. e_stop(e);
  19231. var mouseup = function() {
  19232. off(window, "mouseup", mouseup);
  19233. setTimeout(rehide, 20);
  19234. };
  19235. on(window, "mouseup", mouseup);
  19236. } else {
  19237. setTimeout(rehide, 50);
  19238. }
  19239. }
  19240. function contextMenuInGutter(cm, e) {
  19241. if (!hasHandler(cm, "gutterContextMenu")) return false;
  19242. return gutterEvent(cm, e, "gutterContextMenu", false, signal);
  19243. }
  19244. // UPDATING
  19245. // Compute the position of the end of a change (its 'to' property
  19246. // refers to the pre-change end).
  19247. var changeEnd = CodeMirror.changeEnd = function(change) {
  19248. if (!change.text) return change.to;
  19249. return Pos(change.from.line + change.text.length - 1,
  19250. lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
  19251. };
  19252. // Adjust a position to refer to the post-change position of the
  19253. // same text, or the end of the change if the change covers it.
  19254. function adjustForChange(pos, change) {
  19255. if (cmp(pos, change.from) < 0) return pos;
  19256. if (cmp(pos, change.to) <= 0) return changeEnd(change);
  19257. var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
  19258. if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
  19259. return Pos(line, ch);
  19260. }
  19261. function computeSelAfterChange(doc, change) {
  19262. var out = [];
  19263. for (var i = 0; i < doc.sel.ranges.length; i++) {
  19264. var range = doc.sel.ranges[i];
  19265. out.push(new Range(adjustForChange(range.anchor, change),
  19266. adjustForChange(range.head, change)));
  19267. }
  19268. return normalizeSelection(out, doc.sel.primIndex);
  19269. }
  19270. function offsetPos(pos, old, nw) {
  19271. if (pos.line == old.line)
  19272. return Pos(nw.line, pos.ch - old.ch + nw.ch);
  19273. else
  19274. return Pos(nw.line + (pos.line - old.line), pos.ch);
  19275. }
  19276. // Used by replaceSelections to allow moving the selection to the
  19277. // start or around the replaced test. Hint may be "start" or "around".
  19278. function computeReplacedSel(doc, changes, hint) {
  19279. var out = [];
  19280. var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
  19281. for (var i = 0; i < changes.length; i++) {
  19282. var change = changes[i];
  19283. var from = offsetPos(change.from, oldPrev, newPrev);
  19284. var to = offsetPos(changeEnd(change), oldPrev, newPrev);
  19285. oldPrev = change.to;
  19286. newPrev = to;
  19287. if (hint == "around") {
  19288. var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
  19289. out[i] = new Range(inv ? to : from, inv ? from : to);
  19290. } else {
  19291. out[i] = new Range(from, from);
  19292. }
  19293. }
  19294. return new Selection(out, doc.sel.primIndex);
  19295. }
  19296. // Allow "beforeChange" event handlers to influence a change
  19297. function filterChange(doc, change, update) {
  19298. var obj = {
  19299. canceled: false,
  19300. from: change.from,
  19301. to: change.to,
  19302. text: change.text,
  19303. origin: change.origin,
  19304. cancel: function() { this.canceled = true; }
  19305. };
  19306. if (update) obj.update = function(from, to, text, origin) {
  19307. if (from) this.from = clipPos(doc, from);
  19308. if (to) this.to = clipPos(doc, to);
  19309. if (text) this.text = text;
  19310. if (origin !== undefined) this.origin = origin;
  19311. };
  19312. signal(doc, "beforeChange", doc, obj);
  19313. if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
  19314. if (obj.canceled) return null;
  19315. return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
  19316. }
  19317. // Apply a change to a document, and add it to the document's
  19318. // history, and propagating it to all linked documents.
  19319. function makeChange(doc, change, ignoreReadOnly) {
  19320. if (doc.cm) {
  19321. if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
  19322. if (doc.cm.state.suppressEdits) return;
  19323. }
  19324. if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
  19325. change = filterChange(doc, change, true);
  19326. if (!change) return;
  19327. }
  19328. // Possibly split or suppress the update based on the presence
  19329. // of read-only spans in its range.
  19330. var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
  19331. if (split) {
  19332. for (var i = split.length - 1; i >= 0; --i)
  19333. makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
  19334. } else {
  19335. makeChangeInner(doc, change);
  19336. }
  19337. }
  19338. function makeChangeInner(doc, change) {
  19339. if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
  19340. var selAfter = computeSelAfterChange(doc, change);
  19341. addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
  19342. makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
  19343. var rebased = [];
  19344. linkedDocs(doc, function(doc, sharedHist) {
  19345. if (!sharedHist && indexOf(rebased, doc.history) == -1) {
  19346. rebaseHist(doc.history, change);
  19347. rebased.push(doc.history);
  19348. }
  19349. makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
  19350. });
  19351. }
  19352. // Revert a change stored in a document's history.
  19353. function makeChangeFromHistory(doc, type, allowSelectionOnly) {
  19354. if (doc.cm && doc.cm.state.suppressEdits) return;
  19355. var hist = doc.history, event, selAfter = doc.sel;
  19356. var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
  19357. // Verify that there is a useable event (so that ctrl-z won't
  19358. // needlessly clear selection events)
  19359. for (var i = 0; i < source.length; i++) {
  19360. event = source[i];
  19361. if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
  19362. break;
  19363. }
  19364. if (i == source.length) return;
  19365. hist.lastOrigin = hist.lastSelOrigin = null;
  19366. for (;;) {
  19367. event = source.pop();
  19368. if (event.ranges) {
  19369. pushSelectionToHistory(event, dest);
  19370. if (allowSelectionOnly && !event.equals(doc.sel)) {
  19371. setSelection(doc, event, {clearRedo: false});
  19372. return;
  19373. }
  19374. selAfter = event;
  19375. }
  19376. else break;
  19377. }
  19378. // Build up a reverse change object to add to the opposite history
  19379. // stack (redo when undoing, and vice versa).
  19380. var antiChanges = [];
  19381. pushSelectionToHistory(selAfter, dest);
  19382. dest.push({changes: antiChanges, generation: hist.generation});
  19383. hist.generation = event.generation || ++hist.maxGeneration;
  19384. var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
  19385. for (var i = event.changes.length - 1; i >= 0; --i) {
  19386. var change = event.changes[i];
  19387. change.origin = type;
  19388. if (filter && !filterChange(doc, change, false)) {
  19389. source.length = 0;
  19390. return;
  19391. }
  19392. antiChanges.push(historyChangeFromChange(doc, change));
  19393. var after = i ? computeSelAfterChange(doc, change) : lst(source);
  19394. makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
  19395. if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
  19396. var rebased = [];
  19397. // Propagate to the linked documents
  19398. linkedDocs(doc, function(doc, sharedHist) {
  19399. if (!sharedHist && indexOf(rebased, doc.history) == -1) {
  19400. rebaseHist(doc.history, change);
  19401. rebased.push(doc.history);
  19402. }
  19403. makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
  19404. });
  19405. }
  19406. }
  19407. // Sub-views need their line numbers shifted when text is added
  19408. // above or below them in the parent document.
  19409. function shiftDoc(doc, distance) {
  19410. if (distance == 0) return;
  19411. doc.first += distance;
  19412. doc.sel = new Selection(map(doc.sel.ranges, function(range) {
  19413. return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
  19414. Pos(range.head.line + distance, range.head.ch));
  19415. }), doc.sel.primIndex);
  19416. if (doc.cm) {
  19417. regChange(doc.cm, doc.first, doc.first - distance, distance);
  19418. for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
  19419. regLineChange(doc.cm, l, "gutter");
  19420. }
  19421. }
  19422. // More lower-level change function, handling only a single document
  19423. // (not linked ones).
  19424. function makeChangeSingleDoc(doc, change, selAfter, spans) {
  19425. if (doc.cm && !doc.cm.curOp)
  19426. return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
  19427. if (change.to.line < doc.first) {
  19428. shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
  19429. return;
  19430. }
  19431. if (change.from.line > doc.lastLine()) return;
  19432. // Clip the change to the size of this doc
  19433. if (change.from.line < doc.first) {
  19434. var shift = change.text.length - 1 - (doc.first - change.from.line);
  19435. shiftDoc(doc, shift);
  19436. change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
  19437. text: [lst(change.text)], origin: change.origin};
  19438. }
  19439. var last = doc.lastLine();
  19440. if (change.to.line > last) {
  19441. change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
  19442. text: [change.text[0]], origin: change.origin};
  19443. }
  19444. change.removed = getBetween(doc, change.from, change.to);
  19445. if (!selAfter) selAfter = computeSelAfterChange(doc, change);
  19446. if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
  19447. else updateDoc(doc, change, spans);
  19448. setSelectionNoUndo(doc, selAfter, sel_dontScroll);
  19449. }
  19450. // Handle the interaction of a change to a document with the editor
  19451. // that this document is part of.
  19452. function makeChangeSingleDocInEditor(cm, change, spans) {
  19453. var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
  19454. var recomputeMaxLength = false, checkWidthStart = from.line;
  19455. if (!cm.options.lineWrapping) {
  19456. checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
  19457. doc.iter(checkWidthStart, to.line + 1, function(line) {
  19458. if (line == display.maxLine) {
  19459. recomputeMaxLength = true;
  19460. return true;
  19461. }
  19462. });
  19463. }
  19464. if (doc.sel.contains(change.from, change.to) > -1)
  19465. signalCursorActivity(cm);
  19466. updateDoc(doc, change, spans, estimateHeight(cm));
  19467. if (!cm.options.lineWrapping) {
  19468. doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
  19469. var len = lineLength(line);
  19470. if (len > display.maxLineLength) {
  19471. display.maxLine = line;
  19472. display.maxLineLength = len;
  19473. display.maxLineChanged = true;
  19474. recomputeMaxLength = false;
  19475. }
  19476. });
  19477. if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
  19478. }
  19479. // Adjust frontier, schedule worker
  19480. doc.frontier = Math.min(doc.frontier, from.line);
  19481. startWorker(cm, 400);
  19482. var lendiff = change.text.length - (to.line - from.line) - 1;
  19483. // Remember that these lines changed, for updating the display
  19484. if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
  19485. regLineChange(cm, from.line, "text");
  19486. else
  19487. regChange(cm, from.line, to.line + 1, lendiff);
  19488. var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
  19489. if (changeHandler || changesHandler) {
  19490. var obj = {
  19491. from: from, to: to,
  19492. text: change.text,
  19493. removed: change.removed,
  19494. origin: change.origin
  19495. };
  19496. if (changeHandler) signalLater(cm, "change", cm, obj);
  19497. if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
  19498. }
  19499. cm.display.selForContextMenu = null;
  19500. }
  19501. function replaceRange(doc, code, from, to, origin) {
  19502. if (!to) to = from;
  19503. if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
  19504. if (typeof code == "string") code = splitLines(code);
  19505. makeChange(doc, {from: from, to: to, text: code, origin: origin});
  19506. }
  19507. // SCROLLING THINGS INTO VIEW
  19508. // If an editor sits on the top or bottom of the window, partially
  19509. // scrolled out of view, this ensures that the cursor is visible.
  19510. function maybeScrollWindow(cm, coords) {
  19511. var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
  19512. if (coords.top + box.top < 0) doScroll = true;
  19513. else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
  19514. if (doScroll != null && !phantom) {
  19515. var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
  19516. (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
  19517. (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
  19518. coords.left + "px; width: 2px;");
  19519. cm.display.lineSpace.appendChild(scrollNode);
  19520. scrollNode.scrollIntoView(doScroll);
  19521. cm.display.lineSpace.removeChild(scrollNode);
  19522. }
  19523. }
  19524. // Scroll a given position into view (immediately), verifying that
  19525. // it actually became visible (as line heights are accurately
  19526. // measured, the position of something may 'drift' during drawing).
  19527. function scrollPosIntoView(cm, pos, end, margin) {
  19528. if (margin == null) margin = 0;
  19529. for (var limit = 0; limit < 5; limit++) {
  19530. var changed = false, coords = cursorCoords(cm, pos);
  19531. var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
  19532. var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
  19533. Math.min(coords.top, endCoords.top) - margin,
  19534. Math.max(coords.left, endCoords.left),
  19535. Math.max(coords.bottom, endCoords.bottom) + margin);
  19536. var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
  19537. if (scrollPos.scrollTop != null) {
  19538. setScrollTop(cm, scrollPos.scrollTop);
  19539. if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
  19540. }
  19541. if (scrollPos.scrollLeft != null) {
  19542. setScrollLeft(cm, scrollPos.scrollLeft);
  19543. if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
  19544. }
  19545. if (!changed) return coords;
  19546. }
  19547. }
  19548. // Scroll a given set of coordinates into view (immediately).
  19549. function scrollIntoView(cm, x1, y1, x2, y2) {
  19550. var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
  19551. if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
  19552. if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
  19553. }
  19554. // Calculate a new scroll position needed to scroll the given
  19555. // rectangle into view. Returns an object with scrollTop and
  19556. // scrollLeft properties. When these are undefined, the
  19557. // vertical/horizontal position does not need to be adjusted.
  19558. function calculateScrollPos(cm, x1, y1, x2, y2) {
  19559. var display = cm.display, snapMargin = textHeight(cm.display);
  19560. if (y1 < 0) y1 = 0;
  19561. var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
  19562. var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
  19563. if (y2 - y1 > screen) y2 = y1 + screen;
  19564. var docBottom = cm.doc.height + paddingVert(display);
  19565. var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
  19566. if (y1 < screentop) {
  19567. result.scrollTop = atTop ? 0 : y1;
  19568. } else if (y2 > screentop + screen) {
  19569. var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
  19570. if (newTop != screentop) result.scrollTop = newTop;
  19571. }
  19572. var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
  19573. var screenw = display.scroller.clientWidth - scrollerCutOff - display.gutters.offsetWidth;
  19574. var tooWide = x2 - x1 > screenw;
  19575. if (tooWide) x2 = x1 + screenw;
  19576. if (x1 < 10)
  19577. result.scrollLeft = 0;
  19578. else if (x1 < screenleft)
  19579. result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
  19580. else if (x2 > screenw + screenleft - 3)
  19581. result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
  19582. return result;
  19583. }
  19584. // Store a relative adjustment to the scroll position in the current
  19585. // operation (to be applied when the operation finishes).
  19586. function addToScrollPos(cm, left, top) {
  19587. if (left != null || top != null) resolveScrollToPos(cm);
  19588. if (left != null)
  19589. cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
  19590. if (top != null)
  19591. cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
  19592. }
  19593. // Make sure that at the end of the operation the current cursor is
  19594. // shown.
  19595. function ensureCursorVisible(cm) {
  19596. resolveScrollToPos(cm);
  19597. var cur = cm.getCursor(), from = cur, to = cur;
  19598. if (!cm.options.lineWrapping) {
  19599. from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
  19600. to = Pos(cur.line, cur.ch + 1);
  19601. }
  19602. cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
  19603. }
  19604. // When an operation has its scrollToPos property set, and another
  19605. // scroll action is applied before the end of the operation, this
  19606. // 'simulates' scrolling that position into view in a cheap way, so
  19607. // that the effect of intermediate scroll commands is not ignored.
  19608. function resolveScrollToPos(cm) {
  19609. var range = cm.curOp.scrollToPos;
  19610. if (range) {
  19611. cm.curOp.scrollToPos = null;
  19612. var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
  19613. var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
  19614. Math.min(from.top, to.top) - range.margin,
  19615. Math.max(from.right, to.right),
  19616. Math.max(from.bottom, to.bottom) + range.margin);
  19617. cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
  19618. }
  19619. }
  19620. // API UTILITIES
  19621. // Indent the given line. The how parameter can be "smart",
  19622. // "add"/null, "subtract", or "prev". When aggressive is false
  19623. // (typically set to true for forced single-line indents), empty
  19624. // lines are not indented, and places where the mode returns Pass
  19625. // are left alone.
  19626. function indentLine(cm, n, how, aggressive) {
  19627. var doc = cm.doc, state;
  19628. if (how == null) how = "add";
  19629. if (how == "smart") {
  19630. // Fall back to "prev" when the mode doesn't have an indentation
  19631. // method.
  19632. if (!doc.mode.indent) how = "prev";
  19633. else state = getStateBefore(cm, n);
  19634. }
  19635. var tabSize = cm.options.tabSize;
  19636. var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
  19637. if (line.stateAfter) line.stateAfter = null;
  19638. var curSpaceString = line.text.match(/^\s*/)[0], indentation;
  19639. if (!aggressive && !/\S/.test(line.text)) {
  19640. indentation = 0;
  19641. how = "not";
  19642. } else if (how == "smart") {
  19643. indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
  19644. if (indentation == Pass || indentation > 150) {
  19645. if (!aggressive) return;
  19646. how = "prev";
  19647. }
  19648. }
  19649. if (how == "prev") {
  19650. if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
  19651. else indentation = 0;
  19652. } else if (how == "add") {
  19653. indentation = curSpace + cm.options.indentUnit;
  19654. } else if (how == "subtract") {
  19655. indentation = curSpace - cm.options.indentUnit;
  19656. } else if (typeof how == "number") {
  19657. indentation = curSpace + how;
  19658. }
  19659. indentation = Math.max(0, indentation);
  19660. var indentString = "", pos = 0;
  19661. if (cm.options.indentWithTabs)
  19662. for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
  19663. if (pos < indentation) indentString += spaceStr(indentation - pos);
  19664. if (indentString != curSpaceString) {
  19665. replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
  19666. } else {
  19667. // Ensure that, if the cursor was in the whitespace at the start
  19668. // of the line, it is moved to the end of that space.
  19669. for (var i = 0; i < doc.sel.ranges.length; i++) {
  19670. var range = doc.sel.ranges[i];
  19671. if (range.head.line == n && range.head.ch < curSpaceString.length) {
  19672. var pos = Pos(n, curSpaceString.length);
  19673. replaceOneSelection(doc, i, new Range(pos, pos));
  19674. break;
  19675. }
  19676. }
  19677. }
  19678. line.stateAfter = null;
  19679. }
  19680. // Utility for applying a change to a line by handle or number,
  19681. // returning the number and optionally registering the line as
  19682. // changed.
  19683. function changeLine(doc, handle, changeType, op) {
  19684. var no = handle, line = handle;
  19685. if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
  19686. else no = lineNo(handle);
  19687. if (no == null) return null;
  19688. if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
  19689. return line;
  19690. }
  19691. // Helper for deleting text near the selection(s), used to implement
  19692. // backspace, delete, and similar functionality.
  19693. function deleteNearSelection(cm, compute) {
  19694. var ranges = cm.doc.sel.ranges, kill = [];
  19695. // Build up a set of ranges to kill first, merging overlapping
  19696. // ranges.
  19697. for (var i = 0; i < ranges.length; i++) {
  19698. var toKill = compute(ranges[i]);
  19699. while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
  19700. var replaced = kill.pop();
  19701. if (cmp(replaced.from, toKill.from) < 0) {
  19702. toKill.from = replaced.from;
  19703. break;
  19704. }
  19705. }
  19706. kill.push(toKill);
  19707. }
  19708. // Next, remove those actual ranges.
  19709. runInOp(cm, function() {
  19710. for (var i = kill.length - 1; i >= 0; i--)
  19711. replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
  19712. ensureCursorVisible(cm);
  19713. });
  19714. }
  19715. // Used for horizontal relative motion. Dir is -1 or 1 (left or
  19716. // right), unit can be "char", "column" (like char, but doesn't
  19717. // cross line boundaries), "word" (across next word), or "group" (to
  19718. // the start of next group of word or non-word-non-whitespace
  19719. // chars). The visually param controls whether, in right-to-left
  19720. // text, direction 1 means to move towards the next index in the
  19721. // string, or towards the character to the right of the current
  19722. // position. The resulting position will have a hitSide=true
  19723. // property if it reached the end of the document.
  19724. function findPosH(doc, pos, dir, unit, visually) {
  19725. var line = pos.line, ch = pos.ch, origDir = dir;
  19726. var lineObj = getLine(doc, line);
  19727. var possible = true;
  19728. function findNextLine() {
  19729. var l = line + dir;
  19730. if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
  19731. line = l;
  19732. return lineObj = getLine(doc, l);
  19733. }
  19734. function moveOnce(boundToLine) {
  19735. var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
  19736. if (next == null) {
  19737. if (!boundToLine && findNextLine()) {
  19738. if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
  19739. else ch = dir < 0 ? lineObj.text.length : 0;
  19740. } else return (possible = false);
  19741. } else ch = next;
  19742. return true;
  19743. }
  19744. if (unit == "char") moveOnce();
  19745. else if (unit == "column") moveOnce(true);
  19746. else if (unit == "word" || unit == "group") {
  19747. var sawType = null, group = unit == "group";
  19748. var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
  19749. for (var first = true;; first = false) {
  19750. if (dir < 0 && !moveOnce(!first)) break;
  19751. var cur = lineObj.text.charAt(ch) || "\n";
  19752. var type = isWordChar(cur, helper) ? "w"
  19753. : group && cur == "\n" ? "n"
  19754. : !group || /\s/.test(cur) ? null
  19755. : "p";
  19756. if (group && !first && !type) type = "s";
  19757. if (sawType && sawType != type) {
  19758. if (dir < 0) {dir = 1; moveOnce();}
  19759. break;
  19760. }
  19761. if (type) sawType = type;
  19762. if (dir > 0 && !moveOnce(!first)) break;
  19763. }
  19764. }
  19765. var result = skipAtomic(doc, Pos(line, ch), origDir, true);
  19766. if (!possible) result.hitSide = true;
  19767. return result;
  19768. }
  19769. // For relative vertical movement. Dir may be -1 or 1. Unit can be
  19770. // "page" or "line". The resulting position will have a hitSide=true
  19771. // property if it reached the end of the document.
  19772. function findPosV(cm, pos, dir, unit) {
  19773. var doc = cm.doc, x = pos.left, y;
  19774. if (unit == "page") {
  19775. var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
  19776. y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
  19777. } else if (unit == "line") {
  19778. y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
  19779. }
  19780. for (;;) {
  19781. var target = coordsChar(cm, x, y);
  19782. if (!target.outside) break;
  19783. if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
  19784. y += dir * 5;
  19785. }
  19786. return target;
  19787. }
  19788. // EDITOR METHODS
  19789. // The publicly visible API. Note that methodOp(f) means
  19790. // 'wrap f in an operation, performed on its `this` parameter'.
  19791. // This is not the complete set of editor methods. Most of the
  19792. // methods defined on the Doc type are also injected into
  19793. // CodeMirror.prototype, for backwards compatibility and
  19794. // convenience.
  19795. CodeMirror.prototype = {
  19796. constructor: CodeMirror,
  19797. focus: function(){window.focus(); focusInput(this); fastPoll(this);},
  19798. setOption: function(option, value) {
  19799. var options = this.options, old = options[option];
  19800. if (options[option] == value && option != "mode") return;
  19801. options[option] = value;
  19802. if (optionHandlers.hasOwnProperty(option))
  19803. operation(this, optionHandlers[option])(this, value, old);
  19804. },
  19805. getOption: function(option) {return this.options[option];},
  19806. getDoc: function() {return this.doc;},
  19807. addKeyMap: function(map, bottom) {
  19808. this.state.keyMaps[bottom ? "push" : "unshift"](map);
  19809. },
  19810. removeKeyMap: function(map) {
  19811. var maps = this.state.keyMaps;
  19812. for (var i = 0; i < maps.length; ++i)
  19813. if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) {
  19814. maps.splice(i, 1);
  19815. return true;
  19816. }
  19817. },
  19818. addOverlay: methodOp(function(spec, options) {
  19819. var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
  19820. if (mode.startState) throw new Error("Overlays may not be stateful.");
  19821. this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
  19822. this.state.modeGen++;
  19823. regChange(this);
  19824. }),
  19825. removeOverlay: methodOp(function(spec) {
  19826. var overlays = this.state.overlays;
  19827. for (var i = 0; i < overlays.length; ++i) {
  19828. var cur = overlays[i].modeSpec;
  19829. if (cur == spec || typeof spec == "string" && cur.name == spec) {
  19830. overlays.splice(i, 1);
  19831. this.state.modeGen++;
  19832. regChange(this);
  19833. return;
  19834. }
  19835. }
  19836. }),
  19837. indentLine: methodOp(function(n, dir, aggressive) {
  19838. if (typeof dir != "string" && typeof dir != "number") {
  19839. if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
  19840. else dir = dir ? "add" : "subtract";
  19841. }
  19842. if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
  19843. }),
  19844. indentSelection: methodOp(function(how) {
  19845. var ranges = this.doc.sel.ranges, end = -1;
  19846. for (var i = 0; i < ranges.length; i++) {
  19847. var range = ranges[i];
  19848. if (!range.empty()) {
  19849. var from = range.from(), to = range.to();
  19850. var start = Math.max(end, from.line);
  19851. end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
  19852. for (var j = start; j < end; ++j)
  19853. indentLine(this, j, how);
  19854. var newRanges = this.doc.sel.ranges;
  19855. if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
  19856. replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
  19857. } else if (range.head.line > end) {
  19858. indentLine(this, range.head.line, how, true);
  19859. end = range.head.line;
  19860. if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
  19861. }
  19862. }
  19863. }),
  19864. // Fetch the parser token for a given character. Useful for hacks
  19865. // that want to inspect the mode state (say, for completion).
  19866. getTokenAt: function(pos, precise) {
  19867. var doc = this.doc;
  19868. pos = clipPos(doc, pos);
  19869. var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
  19870. var line = getLine(doc, pos.line);
  19871. var stream = new StringStream(line.text, this.options.tabSize);
  19872. while (stream.pos < pos.ch && !stream.eol()) {
  19873. stream.start = stream.pos;
  19874. var style = readToken(mode, stream, state);
  19875. }
  19876. return {start: stream.start,
  19877. end: stream.pos,
  19878. string: stream.current(),
  19879. type: style || null,
  19880. state: state};
  19881. },
  19882. getTokenTypeAt: function(pos) {
  19883. pos = clipPos(this.doc, pos);
  19884. var styles = getLineStyles(this, getLine(this.doc, pos.line));
  19885. var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
  19886. var type;
  19887. if (ch == 0) type = styles[2];
  19888. else for (;;) {
  19889. var mid = (before + after) >> 1;
  19890. if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
  19891. else if (styles[mid * 2 + 1] < ch) before = mid + 1;
  19892. else { type = styles[mid * 2 + 2]; break; }
  19893. }
  19894. var cut = type ? type.indexOf("cm-overlay ") : -1;
  19895. return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
  19896. },
  19897. getModeAt: function(pos) {
  19898. var mode = this.doc.mode;
  19899. if (!mode.innerMode) return mode;
  19900. return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
  19901. },
  19902. getHelper: function(pos, type) {
  19903. return this.getHelpers(pos, type)[0];
  19904. },
  19905. getHelpers: function(pos, type) {
  19906. var found = [];
  19907. if (!helpers.hasOwnProperty(type)) return helpers;
  19908. var help = helpers[type], mode = this.getModeAt(pos);
  19909. if (typeof mode[type] == "string") {
  19910. if (help[mode[type]]) found.push(help[mode[type]]);
  19911. } else if (mode[type]) {
  19912. for (var i = 0; i < mode[type].length; i++) {
  19913. var val = help[mode[type][i]];
  19914. if (val) found.push(val);
  19915. }
  19916. } else if (mode.helperType && help[mode.helperType]) {
  19917. found.push(help[mode.helperType]);
  19918. } else if (help[mode.name]) {
  19919. found.push(help[mode.name]);
  19920. }
  19921. for (var i = 0; i < help._global.length; i++) {
  19922. var cur = help._global[i];
  19923. if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
  19924. found.push(cur.val);
  19925. }
  19926. return found;
  19927. },
  19928. getStateAfter: function(line, precise) {
  19929. var doc = this.doc;
  19930. line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
  19931. return getStateBefore(this, line + 1, precise);
  19932. },
  19933. cursorCoords: function(start, mode) {
  19934. var pos, range = this.doc.sel.primary();
  19935. if (start == null) pos = range.head;
  19936. else if (typeof start == "object") pos = clipPos(this.doc, start);
  19937. else pos = start ? range.from() : range.to();
  19938. return cursorCoords(this, pos, mode || "page");
  19939. },
  19940. charCoords: function(pos, mode) {
  19941. return charCoords(this, clipPos(this.doc, pos), mode || "page");
  19942. },
  19943. coordsChar: function(coords, mode) {
  19944. coords = fromCoordSystem(this, coords, mode || "page");
  19945. return coordsChar(this, coords.left, coords.top);
  19946. },
  19947. lineAtHeight: function(height, mode) {
  19948. height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
  19949. return lineAtHeight(this.doc, height + this.display.viewOffset);
  19950. },
  19951. heightAtLine: function(line, mode) {
  19952. var end = false, last = this.doc.first + this.doc.size - 1;
  19953. if (line < this.doc.first) line = this.doc.first;
  19954. else if (line > last) { line = last; end = true; }
  19955. var lineObj = getLine(this.doc, line);
  19956. return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
  19957. (end ? this.doc.height - heightAtLine(lineObj) : 0);
  19958. },
  19959. defaultTextHeight: function() { return textHeight(this.display); },
  19960. defaultCharWidth: function() { return charWidth(this.display); },
  19961. setGutterMarker: methodOp(function(line, gutterID, value) {
  19962. return changeLine(this.doc, line, "gutter", function(line) {
  19963. var markers = line.gutterMarkers || (line.gutterMarkers = {});
  19964. markers[gutterID] = value;
  19965. if (!value && isEmpty(markers)) line.gutterMarkers = null;
  19966. return true;
  19967. });
  19968. }),
  19969. clearGutter: methodOp(function(gutterID) {
  19970. var cm = this, doc = cm.doc, i = doc.first;
  19971. doc.iter(function(line) {
  19972. if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
  19973. line.gutterMarkers[gutterID] = null;
  19974. regLineChange(cm, i, "gutter");
  19975. if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
  19976. }
  19977. ++i;
  19978. });
  19979. }),
  19980. addLineWidget: methodOp(function(handle, node, options) {
  19981. return addLineWidget(this, handle, node, options);
  19982. }),
  19983. removeLineWidget: function(widget) { widget.clear(); },
  19984. lineInfo: function(line) {
  19985. if (typeof line == "number") {
  19986. if (!isLine(this.doc, line)) return null;
  19987. var n = line;
  19988. line = getLine(this.doc, line);
  19989. if (!line) return null;
  19990. } else {
  19991. var n = lineNo(line);
  19992. if (n == null) return null;
  19993. }
  19994. return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
  19995. textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
  19996. widgets: line.widgets};
  19997. },
  19998. getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
  19999. addWidget: function(pos, node, scroll, vert, horiz) {
  20000. var display = this.display;
  20001. pos = cursorCoords(this, clipPos(this.doc, pos));
  20002. var top = pos.bottom, left = pos.left;
  20003. node.style.position = "absolute";
  20004. display.sizer.appendChild(node);
  20005. if (vert == "over") {
  20006. top = pos.top;
  20007. } else if (vert == "above" || vert == "near") {
  20008. var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
  20009. hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
  20010. // Default to positioning above (if specified and possible); otherwise default to positioning below
  20011. if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
  20012. top = pos.top - node.offsetHeight;
  20013. else if (pos.bottom + node.offsetHeight <= vspace)
  20014. top = pos.bottom;
  20015. if (left + node.offsetWidth > hspace)
  20016. left = hspace - node.offsetWidth;
  20017. }
  20018. node.style.top = top + "px";
  20019. node.style.left = node.style.right = "";
  20020. if (horiz == "right") {
  20021. left = display.sizer.clientWidth - node.offsetWidth;
  20022. node.style.right = "0px";
  20023. } else {
  20024. if (horiz == "left") left = 0;
  20025. else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
  20026. node.style.left = left + "px";
  20027. }
  20028. if (scroll)
  20029. scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
  20030. },
  20031. triggerOnKeyDown: methodOp(onKeyDown),
  20032. triggerOnKeyPress: methodOp(onKeyPress),
  20033. triggerOnKeyUp: onKeyUp,
  20034. execCommand: function(cmd) {
  20035. if (commands.hasOwnProperty(cmd))
  20036. return commands[cmd](this);
  20037. },
  20038. findPosH: function(from, amount, unit, visually) {
  20039. var dir = 1;
  20040. if (amount < 0) { dir = -1; amount = -amount; }
  20041. for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
  20042. cur = findPosH(this.doc, cur, dir, unit, visually);
  20043. if (cur.hitSide) break;
  20044. }
  20045. return cur;
  20046. },
  20047. moveH: methodOp(function(dir, unit) {
  20048. var cm = this;
  20049. cm.extendSelectionsBy(function(range) {
  20050. if (cm.display.shift || cm.doc.extend || range.empty())
  20051. return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
  20052. else
  20053. return dir < 0 ? range.from() : range.to();
  20054. }, sel_move);
  20055. }),
  20056. deleteH: methodOp(function(dir, unit) {
  20057. var sel = this.doc.sel, doc = this.doc;
  20058. if (sel.somethingSelected())
  20059. doc.replaceSelection("", null, "+delete");
  20060. else
  20061. deleteNearSelection(this, function(range) {
  20062. var other = findPosH(doc, range.head, dir, unit, false);
  20063. return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
  20064. });
  20065. }),
  20066. findPosV: function(from, amount, unit, goalColumn) {
  20067. var dir = 1, x = goalColumn;
  20068. if (amount < 0) { dir = -1; amount = -amount; }
  20069. for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
  20070. var coords = cursorCoords(this, cur, "div");
  20071. if (x == null) x = coords.left;
  20072. else coords.left = x;
  20073. cur = findPosV(this, coords, dir, unit);
  20074. if (cur.hitSide) break;
  20075. }
  20076. return cur;
  20077. },
  20078. moveV: methodOp(function(dir, unit) {
  20079. var cm = this, doc = this.doc, goals = [];
  20080. var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
  20081. doc.extendSelectionsBy(function(range) {
  20082. if (collapse)
  20083. return dir < 0 ? range.from() : range.to();
  20084. var headPos = cursorCoords(cm, range.head, "div");
  20085. if (range.goalColumn != null) headPos.left = range.goalColumn;
  20086. goals.push(headPos.left);
  20087. var pos = findPosV(cm, headPos, dir, unit);
  20088. if (unit == "page" && range == doc.sel.primary())
  20089. addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
  20090. return pos;
  20091. }, sel_move);
  20092. if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
  20093. doc.sel.ranges[i].goalColumn = goals[i];
  20094. }),
  20095. // Find the word at the given position (as returned by coordsChar).
  20096. findWordAt: function(pos) {
  20097. var doc = this.doc, line = getLine(doc, pos.line).text;
  20098. var start = pos.ch, end = pos.ch;
  20099. if (line) {
  20100. var helper = this.getHelper(pos, "wordChars");
  20101. if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
  20102. var startChar = line.charAt(start);
  20103. var check = isWordChar(startChar, helper)
  20104. ? function(ch) { return isWordChar(ch, helper); }
  20105. : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
  20106. : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
  20107. while (start > 0 && check(line.charAt(start - 1))) --start;
  20108. while (end < line.length && check(line.charAt(end))) ++end;
  20109. }
  20110. return new Range(Pos(pos.line, start), Pos(pos.line, end));
  20111. },
  20112. toggleOverwrite: function(value) {
  20113. if (value != null && value == this.state.overwrite) return;
  20114. if (this.state.overwrite = !this.state.overwrite)
  20115. addClass(this.display.cursorDiv, "CodeMirror-overwrite");
  20116. else
  20117. rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
  20118. signal(this, "overwriteToggle", this, this.state.overwrite);
  20119. },
  20120. hasFocus: function() { return activeElt() == this.display.input; },
  20121. scrollTo: methodOp(function(x, y) {
  20122. if (x != null || y != null) resolveScrollToPos(this);
  20123. if (x != null) this.curOp.scrollLeft = x;
  20124. if (y != null) this.curOp.scrollTop = y;
  20125. }),
  20126. getScrollInfo: function() {
  20127. var scroller = this.display.scroller, co = scrollerCutOff;
  20128. return {left: scroller.scrollLeft, top: scroller.scrollTop,
  20129. height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
  20130. clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
  20131. },
  20132. scrollIntoView: methodOp(function(range, margin) {
  20133. if (range == null) {
  20134. range = {from: this.doc.sel.primary().head, to: null};
  20135. if (margin == null) margin = this.options.cursorScrollMargin;
  20136. } else if (typeof range == "number") {
  20137. range = {from: Pos(range, 0), to: null};
  20138. } else if (range.from == null) {
  20139. range = {from: range, to: null};
  20140. }
  20141. if (!range.to) range.to = range.from;
  20142. range.margin = margin || 0;
  20143. if (range.from.line != null) {
  20144. resolveScrollToPos(this);
  20145. this.curOp.scrollToPos = range;
  20146. } else {
  20147. var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
  20148. Math.min(range.from.top, range.to.top) - range.margin,
  20149. Math.max(range.from.right, range.to.right),
  20150. Math.max(range.from.bottom, range.to.bottom) + range.margin);
  20151. this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
  20152. }
  20153. }),
  20154. setSize: methodOp(function(width, height) {
  20155. var cm = this;
  20156. function interpret(val) {
  20157. return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
  20158. }
  20159. if (width != null) cm.display.wrapper.style.width = interpret(width);
  20160. if (height != null) cm.display.wrapper.style.height = interpret(height);
  20161. if (cm.options.lineWrapping) clearLineMeasurementCache(this);
  20162. var lineNo = cm.display.viewFrom;
  20163. cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
  20164. if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
  20165. if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
  20166. ++lineNo;
  20167. });
  20168. cm.curOp.forceUpdate = true;
  20169. signal(cm, "refresh", this);
  20170. }),
  20171. operation: function(f){return runInOp(this, f);},
  20172. refresh: methodOp(function() {
  20173. var oldHeight = this.display.cachedTextHeight;
  20174. regChange(this);
  20175. this.curOp.forceUpdate = true;
  20176. clearCaches(this);
  20177. this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
  20178. updateGutterSpace(this);
  20179. if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
  20180. estimateLineHeights(this);
  20181. signal(this, "refresh", this);
  20182. }),
  20183. swapDoc: methodOp(function(doc) {
  20184. var old = this.doc;
  20185. old.cm = null;
  20186. attachDoc(this, doc);
  20187. clearCaches(this);
  20188. resetInput(this);
  20189. this.scrollTo(doc.scrollLeft, doc.scrollTop);
  20190. this.curOp.forceScroll = true;
  20191. signalLater(this, "swapDoc", this, old);
  20192. return old;
  20193. }),
  20194. getInputField: function(){return this.display.input;},
  20195. getWrapperElement: function(){return this.display.wrapper;},
  20196. getScrollerElement: function(){return this.display.scroller;},
  20197. getGutterElement: function(){return this.display.gutters;}
  20198. };
  20199. eventMixin(CodeMirror);
  20200. // OPTION DEFAULTS
  20201. // The default configuration options.
  20202. var defaults = CodeMirror.defaults = {};
  20203. // Functions to run when options are changed.
  20204. var optionHandlers = CodeMirror.optionHandlers = {};
  20205. function option(name, deflt, handle, notOnInit) {
  20206. CodeMirror.defaults[name] = deflt;
  20207. if (handle) optionHandlers[name] =
  20208. notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
  20209. }
  20210. // Passed to option handlers when there is no old value.
  20211. var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
  20212. // These two are, on init, called from the constructor because they
  20213. // have to be initialized before the editor can start at all.
  20214. option("value", "", function(cm, val) {
  20215. cm.setValue(val);
  20216. }, true);
  20217. option("mode", null, function(cm, val) {
  20218. cm.doc.modeOption = val;
  20219. loadMode(cm);
  20220. }, true);
  20221. option("indentUnit", 2, loadMode, true);
  20222. option("indentWithTabs", false);
  20223. option("smartIndent", true);
  20224. option("tabSize", 4, function(cm) {
  20225. resetModeState(cm);
  20226. clearCaches(cm);
  20227. regChange(cm);
  20228. }, true);
  20229. option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val) {
  20230. cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
  20231. cm.refresh();
  20232. }, true);
  20233. option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
  20234. option("electricChars", true);
  20235. option("rtlMoveVisually", !windows);
  20236. option("wholeLineUpdateBefore", true);
  20237. option("theme", "default", function(cm) {
  20238. themeChanged(cm);
  20239. guttersChanged(cm);
  20240. }, true);
  20241. option("keyMap", "default", keyMapChanged);
  20242. option("extraKeys", null);
  20243. option("lineWrapping", false, wrappingChanged, true);
  20244. option("gutters", [], function(cm) {
  20245. setGuttersForLineNumbers(cm.options);
  20246. guttersChanged(cm);
  20247. }, true);
  20248. option("fixedGutter", true, function(cm, val) {
  20249. cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
  20250. cm.refresh();
  20251. }, true);
  20252. option("coverGutterNextToScrollbar", false, updateScrollbars, true);
  20253. option("lineNumbers", false, function(cm) {
  20254. setGuttersForLineNumbers(cm.options);
  20255. guttersChanged(cm);
  20256. }, true);
  20257. option("firstLineNumber", 1, guttersChanged, true);
  20258. option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
  20259. option("showCursorWhenSelecting", false, updateSelection, true);
  20260. option("resetSelectionOnContextMenu", true);
  20261. option("readOnly", false, function(cm, val) {
  20262. if (val == "nocursor") {
  20263. onBlur(cm);
  20264. cm.display.input.blur();
  20265. cm.display.disabled = true;
  20266. } else {
  20267. cm.display.disabled = false;
  20268. if (!val) resetInput(cm);
  20269. }
  20270. });
  20271. option("disableInput", false, function(cm, val) {if (!val) resetInput(cm);}, true);
  20272. option("dragDrop", true);
  20273. option("cursorBlinkRate", 530);
  20274. option("cursorScrollMargin", 0);
  20275. option("cursorHeight", 1, updateSelection, true);
  20276. option("singleCursorHeightPerLine", true, updateSelection, true);
  20277. option("workTime", 100);
  20278. option("workDelay", 100);
  20279. option("flattenSpans", true, resetModeState, true);
  20280. option("addModeClass", false, resetModeState, true);
  20281. option("pollInterval", 100);
  20282. option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
  20283. option("historyEventDelay", 1250);
  20284. option("viewportMargin", 10, function(cm){cm.refresh();}, true);
  20285. option("maxHighlightLength", 10000, resetModeState, true);
  20286. option("moveInputWithCursor", true, function(cm, val) {
  20287. if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
  20288. });
  20289. option("tabindex", null, function(cm, val) {
  20290. cm.display.input.tabIndex = val || "";
  20291. });
  20292. option("autofocus", null);
  20293. // MODE DEFINITION AND QUERYING
  20294. // Known modes, by name and by MIME
  20295. var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
  20296. // Extra arguments are stored as the mode's dependencies, which is
  20297. // used by (legacy) mechanisms like loadmode.js to automatically
  20298. // load a mode. (Preferred mechanism is the require/define calls.)
  20299. CodeMirror.defineMode = function(name, mode) {
  20300. if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
  20301. if (arguments.length > 2)
  20302. mode.dependencies = Array.prototype.slice.call(arguments, 2);
  20303. modes[name] = mode;
  20304. };
  20305. CodeMirror.defineMIME = function(mime, spec) {
  20306. mimeModes[mime] = spec;
  20307. };
  20308. // Given a MIME type, a {name, ...options} config object, or a name
  20309. // string, return a mode config object.
  20310. CodeMirror.resolveMode = function(spec) {
  20311. if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
  20312. spec = mimeModes[spec];
  20313. } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
  20314. var found = mimeModes[spec.name];
  20315. if (typeof found == "string") found = {name: found};
  20316. spec = createObj(found, spec);
  20317. spec.name = found.name;
  20318. } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
  20319. return CodeMirror.resolveMode("application/xml");
  20320. }
  20321. if (typeof spec == "string") return {name: spec};
  20322. else return spec || {name: "null"};
  20323. };
  20324. // Given a mode spec (anything that resolveMode accepts), find and
  20325. // initialize an actual mode object.
  20326. CodeMirror.getMode = function(options, spec) {
  20327. var spec = CodeMirror.resolveMode(spec);
  20328. var mfactory = modes[spec.name];
  20329. if (!mfactory) return CodeMirror.getMode(options, "text/plain");
  20330. var modeObj = mfactory(options, spec);
  20331. if (modeExtensions.hasOwnProperty(spec.name)) {
  20332. var exts = modeExtensions[spec.name];
  20333. for (var prop in exts) {
  20334. if (!exts.hasOwnProperty(prop)) continue;
  20335. if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
  20336. modeObj[prop] = exts[prop];
  20337. }
  20338. }
  20339. modeObj.name = spec.name;
  20340. if (spec.helperType) modeObj.helperType = spec.helperType;
  20341. if (spec.modeProps) for (var prop in spec.modeProps)
  20342. modeObj[prop] = spec.modeProps[prop];
  20343. return modeObj;
  20344. };
  20345. // Minimal default mode.
  20346. CodeMirror.defineMode("null", function() {
  20347. return {token: function(stream) {stream.skipToEnd();}};
  20348. });
  20349. CodeMirror.defineMIME("text/plain", "null");
  20350. // This can be used to attach properties to mode objects from
  20351. // outside the actual mode definition.
  20352. var modeExtensions = CodeMirror.modeExtensions = {};
  20353. CodeMirror.extendMode = function(mode, properties) {
  20354. var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
  20355. copyObj(properties, exts);
  20356. };
  20357. // EXTENSIONS
  20358. CodeMirror.defineExtension = function(name, func) {
  20359. CodeMirror.prototype[name] = func;
  20360. };
  20361. CodeMirror.defineDocExtension = function(name, func) {
  20362. Doc.prototype[name] = func;
  20363. };
  20364. CodeMirror.defineOption = option;
  20365. var initHooks = [];
  20366. CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
  20367. var helpers = CodeMirror.helpers = {};
  20368. CodeMirror.registerHelper = function(type, name, value) {
  20369. if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
  20370. helpers[type][name] = value;
  20371. };
  20372. CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
  20373. CodeMirror.registerHelper(type, name, value);
  20374. helpers[type]._global.push({pred: predicate, val: value});
  20375. };
  20376. // MODE STATE HANDLING
  20377. // Utility functions for working with state. Exported because nested
  20378. // modes need to do this for their inner modes.
  20379. var copyState = CodeMirror.copyState = function(mode, state) {
  20380. if (state === true) return state;
  20381. if (mode.copyState) return mode.copyState(state);
  20382. var nstate = {};
  20383. for (var n in state) {
  20384. var val = state[n];
  20385. if (val instanceof Array) val = val.concat([]);
  20386. nstate[n] = val;
  20387. }
  20388. return nstate;
  20389. };
  20390. var startState = CodeMirror.startState = function(mode, a1, a2) {
  20391. return mode.startState ? mode.startState(a1, a2) : true;
  20392. };
  20393. // Given a mode and a state (for that mode), find the inner mode and
  20394. // state at the position that the state refers to.
  20395. CodeMirror.innerMode = function(mode, state) {
  20396. while (mode.innerMode) {
  20397. var info = mode.innerMode(state);
  20398. if (!info || info.mode == mode) break;
  20399. state = info.state;
  20400. mode = info.mode;
  20401. }
  20402. return info || {mode: mode, state: state};
  20403. };
  20404. // STANDARD COMMANDS
  20405. // Commands are parameter-less actions that can be performed on an
  20406. // editor, mostly used for keybindings.
  20407. var commands = CodeMirror.commands = {
  20408. selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
  20409. singleSelection: function(cm) {
  20410. cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
  20411. },
  20412. killLine: function(cm) {
  20413. deleteNearSelection(cm, function(range) {
  20414. if (range.empty()) {
  20415. var len = getLine(cm.doc, range.head.line).text.length;
  20416. if (range.head.ch == len && range.head.line < cm.lastLine())
  20417. return {from: range.head, to: Pos(range.head.line + 1, 0)};
  20418. else
  20419. return {from: range.head, to: Pos(range.head.line, len)};
  20420. } else {
  20421. return {from: range.from(), to: range.to()};
  20422. }
  20423. });
  20424. },
  20425. deleteLine: function(cm) {
  20426. deleteNearSelection(cm, function(range) {
  20427. return {from: Pos(range.from().line, 0),
  20428. to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
  20429. });
  20430. },
  20431. delLineLeft: function(cm) {
  20432. deleteNearSelection(cm, function(range) {
  20433. return {from: Pos(range.from().line, 0), to: range.from()};
  20434. });
  20435. },
  20436. delWrappedLineLeft: function(cm) {
  20437. deleteNearSelection(cm, function(range) {
  20438. var top = cm.charCoords(range.head, "div").top + 5;
  20439. var leftPos = cm.coordsChar({left: 0, top: top}, "div");
  20440. return {from: leftPos, to: range.from()};
  20441. });
  20442. },
  20443. delWrappedLineRight: function(cm) {
  20444. deleteNearSelection(cm, function(range) {
  20445. var top = cm.charCoords(range.head, "div").top + 5;
  20446. var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
  20447. return {from: range.from(), to: rightPos };
  20448. });
  20449. },
  20450. undo: function(cm) {cm.undo();},
  20451. redo: function(cm) {cm.redo();},
  20452. undoSelection: function(cm) {cm.undoSelection();},
  20453. redoSelection: function(cm) {cm.redoSelection();},
  20454. goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
  20455. goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
  20456. goLineStart: function(cm) {
  20457. cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
  20458. {origin: "+move", bias: 1});
  20459. },
  20460. goLineStartSmart: function(cm) {
  20461. cm.extendSelectionsBy(function(range) {
  20462. return lineStartSmart(cm, range.head);
  20463. }, {origin: "+move", bias: 1});
  20464. },
  20465. goLineEnd: function(cm) {
  20466. cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
  20467. {origin: "+move", bias: -1});
  20468. },
  20469. goLineRight: function(cm) {
  20470. cm.extendSelectionsBy(function(range) {
  20471. var top = cm.charCoords(range.head, "div").top + 5;
  20472. return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
  20473. }, sel_move);
  20474. },
  20475. goLineLeft: function(cm) {
  20476. cm.extendSelectionsBy(function(range) {
  20477. var top = cm.charCoords(range.head, "div").top + 5;
  20478. return cm.coordsChar({left: 0, top: top}, "div");
  20479. }, sel_move);
  20480. },
  20481. goLineLeftSmart: function(cm) {
  20482. cm.extendSelectionsBy(function(range) {
  20483. var top = cm.charCoords(range.head, "div").top + 5;
  20484. var pos = cm.coordsChar({left: 0, top: top}, "div");
  20485. if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
  20486. return pos;
  20487. }, sel_move);
  20488. },
  20489. goLineUp: function(cm) {cm.moveV(-1, "line");},
  20490. goLineDown: function(cm) {cm.moveV(1, "line");},
  20491. goPageUp: function(cm) {cm.moveV(-1, "page");},
  20492. goPageDown: function(cm) {cm.moveV(1, "page");},
  20493. goCharLeft: function(cm) {cm.moveH(-1, "char");},
  20494. goCharRight: function(cm) {cm.moveH(1, "char");},
  20495. goColumnLeft: function(cm) {cm.moveH(-1, "column");},
  20496. goColumnRight: function(cm) {cm.moveH(1, "column");},
  20497. goWordLeft: function(cm) {cm.moveH(-1, "word");},
  20498. goGroupRight: function(cm) {cm.moveH(1, "group");},
  20499. goGroupLeft: function(cm) {cm.moveH(-1, "group");},
  20500. goWordRight: function(cm) {cm.moveH(1, "word");},
  20501. delCharBefore: function(cm) {cm.deleteH(-1, "char");},
  20502. delCharAfter: function(cm) {cm.deleteH(1, "char");},
  20503. delWordBefore: function(cm) {cm.deleteH(-1, "word");},
  20504. delWordAfter: function(cm) {cm.deleteH(1, "word");},
  20505. delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
  20506. delGroupAfter: function(cm) {cm.deleteH(1, "group");},
  20507. indentAuto: function(cm) {cm.indentSelection("smart");},
  20508. indentMore: function(cm) {cm.indentSelection("add");},
  20509. indentLess: function(cm) {cm.indentSelection("subtract");},
  20510. insertTab: function(cm) {cm.replaceSelection("\t");},
  20511. insertSoftTab: function(cm) {
  20512. var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
  20513. for (var i = 0; i < ranges.length; i++) {
  20514. var pos = ranges[i].from();
  20515. var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
  20516. spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
  20517. }
  20518. cm.replaceSelections(spaces);
  20519. },
  20520. defaultTab: function(cm) {
  20521. if (cm.somethingSelected()) cm.indentSelection("add");
  20522. else cm.execCommand("insertTab");
  20523. },
  20524. transposeChars: function(cm) {
  20525. runInOp(cm, function() {
  20526. var ranges = cm.listSelections(), newSel = [];
  20527. for (var i = 0; i < ranges.length; i++) {
  20528. var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
  20529. if (line) {
  20530. if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
  20531. if (cur.ch > 0) {
  20532. cur = new Pos(cur.line, cur.ch + 1);
  20533. cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
  20534. Pos(cur.line, cur.ch - 2), cur, "+transpose");
  20535. } else if (cur.line > cm.doc.first) {
  20536. var prev = getLine(cm.doc, cur.line - 1).text;
  20537. if (prev)
  20538. cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1),
  20539. Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
  20540. }
  20541. }
  20542. newSel.push(new Range(cur, cur));
  20543. }
  20544. cm.setSelections(newSel);
  20545. });
  20546. },
  20547. newlineAndIndent: function(cm) {
  20548. runInOp(cm, function() {
  20549. var len = cm.listSelections().length;
  20550. for (var i = 0; i < len; i++) {
  20551. var range = cm.listSelections()[i];
  20552. cm.replaceRange("\n", range.anchor, range.head, "+input");
  20553. cm.indentLine(range.from().line + 1, null, true);
  20554. ensureCursorVisible(cm);
  20555. }
  20556. });
  20557. },
  20558. toggleOverwrite: function(cm) {cm.toggleOverwrite();}
  20559. };
  20560. // STANDARD KEYMAPS
  20561. var keyMap = CodeMirror.keyMap = {};
  20562. keyMap.basic = {
  20563. "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
  20564. "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
  20565. "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
  20566. "Tab": "defaultTab", "Shift-Tab": "indentAuto",
  20567. "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
  20568. "Esc": "singleSelection"
  20569. };
  20570. // Note that the save and find-related commands aren't defined by
  20571. // default. User code or addons can define them. Unknown commands
  20572. // are simply ignored.
  20573. keyMap.pcDefault = {
  20574. "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
  20575. "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
  20576. "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
  20577. "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
  20578. "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
  20579. "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
  20580. "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
  20581. fallthrough: "basic"
  20582. };
  20583. keyMap.macDefault = {
  20584. "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
  20585. "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
  20586. "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
  20587. "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
  20588. "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
  20589. "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
  20590. "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
  20591. fallthrough: ["basic", "emacsy"]
  20592. };
  20593. // Very basic readline/emacs-style bindings, which are standard on Mac.
  20594. keyMap.emacsy = {
  20595. "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
  20596. "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
  20597. "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
  20598. "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
  20599. };
  20600. keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
  20601. // KEYMAP DISPATCH
  20602. function getKeyMap(val) {
  20603. if (typeof val == "string") return keyMap[val];
  20604. else return val;
  20605. }
  20606. // Given an array of keymaps and a key name, call handle on any
  20607. // bindings found, until that returns a truthy value, at which point
  20608. // we consider the key handled. Implements things like binding a key
  20609. // to false stopping further handling and keymap fallthrough.
  20610. var lookupKey = CodeMirror.lookupKey = function(name, maps, handle) {
  20611. function lookup(map) {
  20612. map = getKeyMap(map);
  20613. var found = map[name];
  20614. if (found === false) return "stop";
  20615. if (found != null && handle(found)) return true;
  20616. if (map.nofallthrough) return "stop";
  20617. var fallthrough = map.fallthrough;
  20618. if (fallthrough == null) return false;
  20619. if (Object.prototype.toString.call(fallthrough) != "[object Array]")
  20620. return lookup(fallthrough);
  20621. for (var i = 0; i < fallthrough.length; ++i) {
  20622. var done = lookup(fallthrough[i]);
  20623. if (done) return done;
  20624. }
  20625. return false;
  20626. }
  20627. for (var i = 0; i < maps.length; ++i) {
  20628. var done = lookup(maps[i]);
  20629. if (done) return done != "stop";
  20630. }
  20631. };
  20632. // Modifier key presses don't count as 'real' key presses for the
  20633. // purpose of keymap fallthrough.
  20634. var isModifierKey = CodeMirror.isModifierKey = function(event) {
  20635. var name = keyNames[event.keyCode];
  20636. return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
  20637. };
  20638. // Look up the name of a key as indicated by an event object.
  20639. var keyName = CodeMirror.keyName = function(event, noShift) {
  20640. if (presto && event.keyCode == 34 && event["char"]) return false;
  20641. var name = keyNames[event.keyCode];
  20642. if (name == null || event.altGraphKey) return false;
  20643. if (event.altKey) name = "Alt-" + name;
  20644. if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name;
  20645. if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name;
  20646. if (!noShift && event.shiftKey) name = "Shift-" + name;
  20647. return name;
  20648. };
  20649. // FROMTEXTAREA
  20650. CodeMirror.fromTextArea = function(textarea, options) {
  20651. if (!options) options = {};
  20652. options.value = textarea.value;
  20653. if (!options.tabindex && textarea.tabindex)
  20654. options.tabindex = textarea.tabindex;
  20655. if (!options.placeholder && textarea.placeholder)
  20656. options.placeholder = textarea.placeholder;
  20657. // Set autofocus to true if this textarea is focused, or if it has
  20658. // autofocus and no other element is focused.
  20659. if (options.autofocus == null) {
  20660. var hasFocus = activeElt();
  20661. options.autofocus = hasFocus == textarea ||
  20662. textarea.getAttribute("autofocus") != null && hasFocus == document.body;
  20663. }
  20664. function save() {textarea.value = cm.getValue();}
  20665. if (textarea.form) {
  20666. on(textarea.form, "submit", save);
  20667. // Deplorable hack to make the submit method do the right thing.
  20668. if (!options.leaveSubmitMethodAlone) {
  20669. var form = textarea.form, realSubmit = form.submit;
  20670. try {
  20671. var wrappedSubmit = form.submit = function() {
  20672. save();
  20673. form.submit = realSubmit;
  20674. form.submit();
  20675. form.submit = wrappedSubmit;
  20676. };
  20677. } catch(e) {}
  20678. }
  20679. }
  20680. textarea.style.display = "none";
  20681. var cm = CodeMirror(function(node) {
  20682. textarea.parentNode.insertBefore(node, textarea.nextSibling);
  20683. }, options);
  20684. cm.save = save;
  20685. cm.getTextArea = function() { return textarea; };
  20686. cm.toTextArea = function() {
  20687. cm.toTextArea = isNaN; // Prevent this from being ran twice
  20688. save();
  20689. textarea.parentNode.removeChild(cm.getWrapperElement());
  20690. textarea.style.display = "";
  20691. if (textarea.form) {
  20692. off(textarea.form, "submit", save);
  20693. if (typeof textarea.form.submit == "function")
  20694. textarea.form.submit = realSubmit;
  20695. }
  20696. };
  20697. return cm;
  20698. };
  20699. // STRING STREAM
  20700. // Fed to the mode parsers, provides helper functions to make
  20701. // parsers more succinct.
  20702. var StringStream = CodeMirror.StringStream = function(string, tabSize) {
  20703. this.pos = this.start = 0;
  20704. this.string = string;
  20705. this.tabSize = tabSize || 8;
  20706. this.lastColumnPos = this.lastColumnValue = 0;
  20707. this.lineStart = 0;
  20708. };
  20709. StringStream.prototype = {
  20710. eol: function() {return this.pos >= this.string.length;},
  20711. sol: function() {return this.pos == this.lineStart;},
  20712. peek: function() {return this.string.charAt(this.pos) || undefined;},
  20713. next: function() {
  20714. if (this.pos < this.string.length)
  20715. return this.string.charAt(this.pos++);
  20716. },
  20717. eat: function(match) {
  20718. var ch = this.string.charAt(this.pos);
  20719. if (typeof match == "string") var ok = ch == match;
  20720. else var ok = ch && (match.test ? match.test(ch) : match(ch));
  20721. if (ok) {++this.pos; return ch;}
  20722. },
  20723. eatWhile: function(match) {
  20724. var start = this.pos;
  20725. while (this.eat(match)){}
  20726. return this.pos > start;
  20727. },
  20728. eatSpace: function() {
  20729. var start = this.pos;
  20730. while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
  20731. return this.pos > start;
  20732. },
  20733. skipToEnd: function() {this.pos = this.string.length;},
  20734. skipTo: function(ch) {
  20735. var found = this.string.indexOf(ch, this.pos);
  20736. if (found > -1) {this.pos = found; return true;}
  20737. },
  20738. backUp: function(n) {this.pos -= n;},
  20739. column: function() {
  20740. if (this.lastColumnPos < this.start) {
  20741. this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
  20742. this.lastColumnPos = this.start;
  20743. }
  20744. return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
  20745. },
  20746. indentation: function() {
  20747. return countColumn(this.string, null, this.tabSize) -
  20748. (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
  20749. },
  20750. match: function(pattern, consume, caseInsensitive) {
  20751. if (typeof pattern == "string") {
  20752. var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
  20753. var substr = this.string.substr(this.pos, pattern.length);
  20754. if (cased(substr) == cased(pattern)) {
  20755. if (consume !== false) this.pos += pattern.length;
  20756. return true;
  20757. }
  20758. } else {
  20759. var match = this.string.slice(this.pos).match(pattern);
  20760. if (match && match.index > 0) return null;
  20761. if (match && consume !== false) this.pos += match[0].length;
  20762. return match;
  20763. }
  20764. },
  20765. current: function(){return this.string.slice(this.start, this.pos);},
  20766. hideFirstChars: function(n, inner) {
  20767. this.lineStart += n;
  20768. try { return inner(); }
  20769. finally { this.lineStart -= n; }
  20770. }
  20771. };
  20772. // TEXTMARKERS
  20773. // Created with markText and setBookmark methods. A TextMarker is a
  20774. // handle that can be used to clear or find a marked position in the
  20775. // document. Line objects hold arrays (markedSpans) containing
  20776. // {from, to, marker} object pointing to such marker objects, and
  20777. // indicating that such a marker is present on that line. Multiple
  20778. // lines may point to the same marker when it spans across lines.
  20779. // The spans will have null for their from/to properties when the
  20780. // marker continues beyond the start/end of the line. Markers have
  20781. // links back to the lines they currently touch.
  20782. var TextMarker = CodeMirror.TextMarker = function(doc, type) {
  20783. this.lines = [];
  20784. this.type = type;
  20785. this.doc = doc;
  20786. };
  20787. eventMixin(TextMarker);
  20788. // Clear the marker.
  20789. TextMarker.prototype.clear = function() {
  20790. if (this.explicitlyCleared) return;
  20791. var cm = this.doc.cm, withOp = cm && !cm.curOp;
  20792. if (withOp) startOperation(cm);
  20793. if (hasHandler(this, "clear")) {
  20794. var found = this.find();
  20795. if (found) signalLater(this, "clear", found.from, found.to);
  20796. }
  20797. var min = null, max = null;
  20798. for (var i = 0; i < this.lines.length; ++i) {
  20799. var line = this.lines[i];
  20800. var span = getMarkedSpanFor(line.markedSpans, this);
  20801. if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
  20802. else if (cm) {
  20803. if (span.to != null) max = lineNo(line);
  20804. if (span.from != null) min = lineNo(line);
  20805. }
  20806. line.markedSpans = removeMarkedSpan(line.markedSpans, span);
  20807. if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
  20808. updateLineHeight(line, textHeight(cm.display));
  20809. }
  20810. if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
  20811. var visual = visualLine(this.lines[i]), len = lineLength(visual);
  20812. if (len > cm.display.maxLineLength) {
  20813. cm.display.maxLine = visual;
  20814. cm.display.maxLineLength = len;
  20815. cm.display.maxLineChanged = true;
  20816. }
  20817. }
  20818. if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
  20819. this.lines.length = 0;
  20820. this.explicitlyCleared = true;
  20821. if (this.atomic && this.doc.cantEdit) {
  20822. this.doc.cantEdit = false;
  20823. if (cm) reCheckSelection(cm.doc);
  20824. }
  20825. if (cm) signalLater(cm, "markerCleared", cm, this);
  20826. if (withOp) endOperation(cm);
  20827. if (this.parent) this.parent.clear();
  20828. };
  20829. // Find the position of the marker in the document. Returns a {from,
  20830. // to} object by default. Side can be passed to get a specific side
  20831. // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
  20832. // Pos objects returned contain a line object, rather than a line
  20833. // number (used to prevent looking up the same line twice).
  20834. TextMarker.prototype.find = function(side, lineObj) {
  20835. if (side == null && this.type == "bookmark") side = 1;
  20836. var from, to;
  20837. for (var i = 0; i < this.lines.length; ++i) {
  20838. var line = this.lines[i];
  20839. var span = getMarkedSpanFor(line.markedSpans, this);
  20840. if (span.from != null) {
  20841. from = Pos(lineObj ? line : lineNo(line), span.from);
  20842. if (side == -1) return from;
  20843. }
  20844. if (span.to != null) {
  20845. to = Pos(lineObj ? line : lineNo(line), span.to);
  20846. if (side == 1) return to;
  20847. }
  20848. }
  20849. return from && {from: from, to: to};
  20850. };
  20851. // Signals that the marker's widget changed, and surrounding layout
  20852. // should be recomputed.
  20853. TextMarker.prototype.changed = function() {
  20854. var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
  20855. if (!pos || !cm) return;
  20856. runInOp(cm, function() {
  20857. var line = pos.line, lineN = lineNo(pos.line);
  20858. var view = findViewForLine(cm, lineN);
  20859. if (view) {
  20860. clearLineMeasurementCacheFor(view);
  20861. cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
  20862. }
  20863. cm.curOp.updateMaxLine = true;
  20864. if (!lineIsHidden(widget.doc, line) && widget.height != null) {
  20865. var oldHeight = widget.height;
  20866. widget.height = null;
  20867. var dHeight = widgetHeight(widget) - oldHeight;
  20868. if (dHeight)
  20869. updateLineHeight(line, line.height + dHeight);
  20870. }
  20871. });
  20872. };
  20873. TextMarker.prototype.attachLine = function(line) {
  20874. if (!this.lines.length && this.doc.cm) {
  20875. var op = this.doc.cm.curOp;
  20876. if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
  20877. (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
  20878. }
  20879. this.lines.push(line);
  20880. };
  20881. TextMarker.prototype.detachLine = function(line) {
  20882. this.lines.splice(indexOf(this.lines, line), 1);
  20883. if (!this.lines.length && this.doc.cm) {
  20884. var op = this.doc.cm.curOp;
  20885. (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
  20886. }
  20887. };
  20888. // Collapsed markers have unique ids, in order to be able to order
  20889. // them, which is needed for uniquely determining an outer marker
  20890. // when they overlap (they may nest, but not partially overlap).
  20891. var nextMarkerId = 0;
  20892. // Create a marker, wire it up to the right lines, and
  20893. function markText(doc, from, to, options, type) {
  20894. // Shared markers (across linked documents) are handled separately
  20895. // (markTextShared will call out to this again, once per
  20896. // document).
  20897. if (options && options.shared) return markTextShared(doc, from, to, options, type);
  20898. // Ensure we are in an operation.
  20899. if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
  20900. var marker = new TextMarker(doc, type), diff = cmp(from, to);
  20901. if (options) copyObj(options, marker, false);
  20902. // Don't connect empty markers unless clearWhenEmpty is false
  20903. if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
  20904. return marker;
  20905. if (marker.replacedWith) {
  20906. // Showing up as a widget implies collapsed (widget replaces text)
  20907. marker.collapsed = true;
  20908. marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
  20909. if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true;
  20910. if (options.insertLeft) marker.widgetNode.insertLeft = true;
  20911. }
  20912. if (marker.collapsed) {
  20913. if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
  20914. from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
  20915. throw new Error("Inserting collapsed marker partially overlapping an existing one");
  20916. sawCollapsedSpans = true;
  20917. }
  20918. if (marker.addToHistory)
  20919. addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
  20920. var curLine = from.line, cm = doc.cm, updateMaxLine;
  20921. doc.iter(curLine, to.line + 1, function(line) {
  20922. if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
  20923. updateMaxLine = true;
  20924. if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
  20925. addMarkedSpan(line, new MarkedSpan(marker,
  20926. curLine == from.line ? from.ch : null,
  20927. curLine == to.line ? to.ch : null));
  20928. ++curLine;
  20929. });
  20930. // lineIsHidden depends on the presence of the spans, so needs a second pass
  20931. if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
  20932. if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
  20933. });
  20934. if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
  20935. if (marker.readOnly) {
  20936. sawReadOnlySpans = true;
  20937. if (doc.history.done.length || doc.history.undone.length)
  20938. doc.clearHistory();
  20939. }
  20940. if (marker.collapsed) {
  20941. marker.id = ++nextMarkerId;
  20942. marker.atomic = true;
  20943. }
  20944. if (cm) {
  20945. // Sync editor state
  20946. if (updateMaxLine) cm.curOp.updateMaxLine = true;
  20947. if (marker.collapsed)
  20948. regChange(cm, from.line, to.line + 1);
  20949. else if (marker.className || marker.title || marker.startStyle || marker.endStyle)
  20950. for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
  20951. if (marker.atomic) reCheckSelection(cm.doc);
  20952. signalLater(cm, "markerAdded", cm, marker);
  20953. }
  20954. return marker;
  20955. }
  20956. // SHARED TEXTMARKERS
  20957. // A shared marker spans multiple linked documents. It is
  20958. // implemented as a meta-marker-object controlling multiple normal
  20959. // markers.
  20960. var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
  20961. this.markers = markers;
  20962. this.primary = primary;
  20963. for (var i = 0; i < markers.length; ++i)
  20964. markers[i].parent = this;
  20965. };
  20966. eventMixin(SharedTextMarker);
  20967. SharedTextMarker.prototype.clear = function() {
  20968. if (this.explicitlyCleared) return;
  20969. this.explicitlyCleared = true;
  20970. for (var i = 0; i < this.markers.length; ++i)
  20971. this.markers[i].clear();
  20972. signalLater(this, "clear");
  20973. };
  20974. SharedTextMarker.prototype.find = function(side, lineObj) {
  20975. return this.primary.find(side, lineObj);
  20976. };
  20977. function markTextShared(doc, from, to, options, type) {
  20978. options = copyObj(options);
  20979. options.shared = false;
  20980. var markers = [markText(doc, from, to, options, type)], primary = markers[0];
  20981. var widget = options.widgetNode;
  20982. linkedDocs(doc, function(doc) {
  20983. if (widget) options.widgetNode = widget.cloneNode(true);
  20984. markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
  20985. for (var i = 0; i < doc.linked.length; ++i)
  20986. if (doc.linked[i].isParent) return;
  20987. primary = lst(markers);
  20988. });
  20989. return new SharedTextMarker(markers, primary);
  20990. }
  20991. function findSharedMarkers(doc) {
  20992. return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
  20993. function(m) { return m.parent; });
  20994. }
  20995. function copySharedMarkers(doc, markers) {
  20996. for (var i = 0; i < markers.length; i++) {
  20997. var marker = markers[i], pos = marker.find();
  20998. var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
  20999. if (cmp(mFrom, mTo)) {
  21000. var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
  21001. marker.markers.push(subMark);
  21002. subMark.parent = marker;
  21003. }
  21004. }
  21005. }
  21006. function detachSharedMarkers(markers) {
  21007. for (var i = 0; i < markers.length; i++) {
  21008. var marker = markers[i], linked = [marker.primary.doc];;
  21009. linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
  21010. for (var j = 0; j < marker.markers.length; j++) {
  21011. var subMarker = marker.markers[j];
  21012. if (indexOf(linked, subMarker.doc) == -1) {
  21013. subMarker.parent = null;
  21014. marker.markers.splice(j--, 1);
  21015. }
  21016. }
  21017. }
  21018. }
  21019. // TEXTMARKER SPANS
  21020. function MarkedSpan(marker, from, to) {
  21021. this.marker = marker;
  21022. this.from = from; this.to = to;
  21023. }
  21024. // Search an array of spans for a span matching the given marker.
  21025. function getMarkedSpanFor(spans, marker) {
  21026. if (spans) for (var i = 0; i < spans.length; ++i) {
  21027. var span = spans[i];
  21028. if (span.marker == marker) return span;
  21029. }
  21030. }
  21031. // Remove a span from an array, returning undefined if no spans are
  21032. // left (we don't store arrays for lines without spans).
  21033. function removeMarkedSpan(spans, span) {
  21034. for (var r, i = 0; i < spans.length; ++i)
  21035. if (spans[i] != span) (r || (r = [])).push(spans[i]);
  21036. return r;
  21037. }
  21038. // Add a span to a line.
  21039. function addMarkedSpan(line, span) {
  21040. line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
  21041. span.marker.attachLine(line);
  21042. }
  21043. // Used for the algorithm that adjusts markers for a change in the
  21044. // document. These functions cut an array of spans at a given
  21045. // character position, returning an array of remaining chunks (or
  21046. // undefined if nothing remains).
  21047. function markedSpansBefore(old, startCh, isInsert) {
  21048. if (old) for (var i = 0, nw; i < old.length; ++i) {
  21049. var span = old[i], marker = span.marker;
  21050. var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
  21051. if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
  21052. var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
  21053. (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
  21054. }
  21055. }
  21056. return nw;
  21057. }
  21058. function markedSpansAfter(old, endCh, isInsert) {
  21059. if (old) for (var i = 0, nw; i < old.length; ++i) {
  21060. var span = old[i], marker = span.marker;
  21061. var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
  21062. if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
  21063. var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
  21064. (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
  21065. span.to == null ? null : span.to - endCh));
  21066. }
  21067. }
  21068. return nw;
  21069. }
  21070. // Given a change object, compute the new set of marker spans that
  21071. // cover the line in which the change took place. Removes spans
  21072. // entirely within the change, reconnects spans belonging to the
  21073. // same marker that appear on both sides of the change, and cuts off
  21074. // spans partially within the change. Returns an array of span
  21075. // arrays with one element for each line in (after) the change.
  21076. function stretchSpansOverChange(doc, change) {
  21077. var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
  21078. var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
  21079. if (!oldFirst && !oldLast) return null;
  21080. var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
  21081. // Get the spans that 'stick out' on both sides
  21082. var first = markedSpansBefore(oldFirst, startCh, isInsert);
  21083. var last = markedSpansAfter(oldLast, endCh, isInsert);
  21084. // Next, merge those two ends
  21085. var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
  21086. if (first) {
  21087. // Fix up .to properties of first
  21088. for (var i = 0; i < first.length; ++i) {
  21089. var span = first[i];
  21090. if (span.to == null) {
  21091. var found = getMarkedSpanFor(last, span.marker);
  21092. if (!found) span.to = startCh;
  21093. else if (sameLine) span.to = found.to == null ? null : found.to + offset;
  21094. }
  21095. }
  21096. }
  21097. if (last) {
  21098. // Fix up .from in last (or move them into first in case of sameLine)
  21099. for (var i = 0; i < last.length; ++i) {
  21100. var span = last[i];
  21101. if (span.to != null) span.to += offset;
  21102. if (span.from == null) {
  21103. var found = getMarkedSpanFor(first, span.marker);
  21104. if (!found) {
  21105. span.from = offset;
  21106. if (sameLine) (first || (first = [])).push(span);
  21107. }
  21108. } else {
  21109. span.from += offset;
  21110. if (sameLine) (first || (first = [])).push(span);
  21111. }
  21112. }
  21113. }
  21114. // Make sure we didn't create any zero-length spans
  21115. if (first) first = clearEmptySpans(first);
  21116. if (last && last != first) last = clearEmptySpans(last);
  21117. var newMarkers = [first];
  21118. if (!sameLine) {
  21119. // Fill gap with whole-line-spans
  21120. var gap = change.text.length - 2, gapMarkers;
  21121. if (gap > 0 && first)
  21122. for (var i = 0; i < first.length; ++i)
  21123. if (first[i].to == null)
  21124. (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
  21125. for (var i = 0; i < gap; ++i)
  21126. newMarkers.push(gapMarkers);
  21127. newMarkers.push(last);
  21128. }
  21129. return newMarkers;
  21130. }
  21131. // Remove spans that are empty and don't have a clearWhenEmpty
  21132. // option of false.
  21133. function clearEmptySpans(spans) {
  21134. for (var i = 0; i < spans.length; ++i) {
  21135. var span = spans[i];
  21136. if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
  21137. spans.splice(i--, 1);
  21138. }
  21139. if (!spans.length) return null;
  21140. return spans;
  21141. }
  21142. // Used for un/re-doing changes from the history. Combines the
  21143. // result of computing the existing spans with the set of spans that
  21144. // existed in the history (so that deleting around a span and then
  21145. // undoing brings back the span).
  21146. function mergeOldSpans(doc, change) {
  21147. var old = getOldSpans(doc, change);
  21148. var stretched = stretchSpansOverChange(doc, change);
  21149. if (!old) return stretched;
  21150. if (!stretched) return old;
  21151. for (var i = 0; i < old.length; ++i) {
  21152. var oldCur = old[i], stretchCur = stretched[i];
  21153. if (oldCur && stretchCur) {
  21154. spans: for (var j = 0; j < stretchCur.length; ++j) {
  21155. var span = stretchCur[j];
  21156. for (var k = 0; k < oldCur.length; ++k)
  21157. if (oldCur[k].marker == span.marker) continue spans;
  21158. oldCur.push(span);
  21159. }
  21160. } else if (stretchCur) {
  21161. old[i] = stretchCur;
  21162. }
  21163. }
  21164. return old;
  21165. }
  21166. // Used to 'clip' out readOnly ranges when making a change.
  21167. function removeReadOnlyRanges(doc, from, to) {
  21168. var markers = null;
  21169. doc.iter(from.line, to.line + 1, function(line) {
  21170. if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
  21171. var mark = line.markedSpans[i].marker;
  21172. if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
  21173. (markers || (markers = [])).push(mark);
  21174. }
  21175. });
  21176. if (!markers) return null;
  21177. var parts = [{from: from, to: to}];
  21178. for (var i = 0; i < markers.length; ++i) {
  21179. var mk = markers[i], m = mk.find(0);
  21180. for (var j = 0; j < parts.length; ++j) {
  21181. var p = parts[j];
  21182. if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
  21183. var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
  21184. if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
  21185. newParts.push({from: p.from, to: m.from});
  21186. if (dto > 0 || !mk.inclusiveRight && !dto)
  21187. newParts.push({from: m.to, to: p.to});
  21188. parts.splice.apply(parts, newParts);
  21189. j += newParts.length - 1;
  21190. }
  21191. }
  21192. return parts;
  21193. }
  21194. // Connect or disconnect spans from a line.
  21195. function detachMarkedSpans(line) {
  21196. var spans = line.markedSpans;
  21197. if (!spans) return;
  21198. for (var i = 0; i < spans.length; ++i)
  21199. spans[i].marker.detachLine(line);
  21200. line.markedSpans = null;
  21201. }
  21202. function attachMarkedSpans(line, spans) {
  21203. if (!spans) return;
  21204. for (var i = 0; i < spans.length; ++i)
  21205. spans[i].marker.attachLine(line);
  21206. line.markedSpans = spans;
  21207. }
  21208. // Helpers used when computing which overlapping collapsed span
  21209. // counts as the larger one.
  21210. function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
  21211. function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
  21212. // Returns a number indicating which of two overlapping collapsed
  21213. // spans is larger (and thus includes the other). Falls back to
  21214. // comparing ids when the spans cover exactly the same range.
  21215. function compareCollapsedMarkers(a, b) {
  21216. var lenDiff = a.lines.length - b.lines.length;
  21217. if (lenDiff != 0) return lenDiff;
  21218. var aPos = a.find(), bPos = b.find();
  21219. var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
  21220. if (fromCmp) return -fromCmp;
  21221. var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
  21222. if (toCmp) return toCmp;
  21223. return b.id - a.id;
  21224. }
  21225. // Find out whether a line ends or starts in a collapsed span. If
  21226. // so, return the marker for that span.
  21227. function collapsedSpanAtSide(line, start) {
  21228. var sps = sawCollapsedSpans && line.markedSpans, found;
  21229. if (sps) for (var sp, i = 0; i < sps.length; ++i) {
  21230. sp = sps[i];
  21231. if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
  21232. (!found || compareCollapsedMarkers(found, sp.marker) < 0))
  21233. found = sp.marker;
  21234. }
  21235. return found;
  21236. }
  21237. function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
  21238. function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
  21239. // Test whether there exists a collapsed span that partially
  21240. // overlaps (covers the start or end, but not both) of a new span.
  21241. // Such overlap is not allowed.
  21242. function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
  21243. var line = getLine(doc, lineNo);
  21244. var sps = sawCollapsedSpans && line.markedSpans;
  21245. if (sps) for (var i = 0; i < sps.length; ++i) {
  21246. var sp = sps[i];
  21247. if (!sp.marker.collapsed) continue;
  21248. var found = sp.marker.find(0);
  21249. var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
  21250. var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
  21251. if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
  21252. if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
  21253. fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
  21254. return true;
  21255. }
  21256. }
  21257. // A visual line is a line as drawn on the screen. Folding, for
  21258. // example, can cause multiple logical lines to appear on the same
  21259. // visual line. This finds the start of the visual line that the
  21260. // given line is part of (usually that is the line itself).
  21261. function visualLine(line) {
  21262. var merged;
  21263. while (merged = collapsedSpanAtStart(line))
  21264. line = merged.find(-1, true).line;
  21265. return line;
  21266. }
  21267. // Returns an array of logical lines that continue the visual line
  21268. // started by the argument, or undefined if there are no such lines.
  21269. function visualLineContinued(line) {
  21270. var merged, lines;
  21271. while (merged = collapsedSpanAtEnd(line)) {
  21272. line = merged.find(1, true).line;
  21273. (lines || (lines = [])).push(line);
  21274. }
  21275. return lines;
  21276. }
  21277. // Get the line number of the start of the visual line that the
  21278. // given line number is part of.
  21279. function visualLineNo(doc, lineN) {
  21280. var line = getLine(doc, lineN), vis = visualLine(line);
  21281. if (line == vis) return lineN;
  21282. return lineNo(vis);
  21283. }
  21284. // Get the line number of the start of the next visual line after
  21285. // the given line.
  21286. function visualLineEndNo(doc, lineN) {
  21287. if (lineN > doc.lastLine()) return lineN;
  21288. var line = getLine(doc, lineN), merged;
  21289. if (!lineIsHidden(doc, line)) return lineN;
  21290. while (merged = collapsedSpanAtEnd(line))
  21291. line = merged.find(1, true).line;
  21292. return lineNo(line) + 1;
  21293. }
  21294. // Compute whether a line is hidden. Lines count as hidden when they
  21295. // are part of a visual line that starts with another line, or when
  21296. // they are entirely covered by collapsed, non-widget span.
  21297. function lineIsHidden(doc, line) {
  21298. var sps = sawCollapsedSpans && line.markedSpans;
  21299. if (sps) for (var sp, i = 0; i < sps.length; ++i) {
  21300. sp = sps[i];
  21301. if (!sp.marker.collapsed) continue;
  21302. if (sp.from == null) return true;
  21303. if (sp.marker.widgetNode) continue;
  21304. if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
  21305. return true;
  21306. }
  21307. }
  21308. function lineIsHiddenInner(doc, line, span) {
  21309. if (span.to == null) {
  21310. var end = span.marker.find(1, true);
  21311. return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
  21312. }
  21313. if (span.marker.inclusiveRight && span.to == line.text.length)
  21314. return true;
  21315. for (var sp, i = 0; i < line.markedSpans.length; ++i) {
  21316. sp = line.markedSpans[i];
  21317. if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
  21318. (sp.to == null || sp.to != span.from) &&
  21319. (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
  21320. lineIsHiddenInner(doc, line, sp)) return true;
  21321. }
  21322. }
  21323. // LINE WIDGETS
  21324. // Line widgets are block elements displayed above or below a line.
  21325. var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
  21326. if (options) for (var opt in options) if (options.hasOwnProperty(opt))
  21327. this[opt] = options[opt];
  21328. this.cm = cm;
  21329. this.node = node;
  21330. };
  21331. eventMixin(LineWidget);
  21332. function adjustScrollWhenAboveVisible(cm, line, diff) {
  21333. if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
  21334. addToScrollPos(cm, null, diff);
  21335. }
  21336. LineWidget.prototype.clear = function() {
  21337. var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
  21338. if (no == null || !ws) return;
  21339. for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
  21340. if (!ws.length) line.widgets = null;
  21341. var height = widgetHeight(this);
  21342. runInOp(cm, function() {
  21343. adjustScrollWhenAboveVisible(cm, line, -height);
  21344. regLineChange(cm, no, "widget");
  21345. updateLineHeight(line, Math.max(0, line.height - height));
  21346. });
  21347. };
  21348. LineWidget.prototype.changed = function() {
  21349. var oldH = this.height, cm = this.cm, line = this.line;
  21350. this.height = null;
  21351. var diff = widgetHeight(this) - oldH;
  21352. if (!diff) return;
  21353. runInOp(cm, function() {
  21354. cm.curOp.forceUpdate = true;
  21355. adjustScrollWhenAboveVisible(cm, line, diff);
  21356. updateLineHeight(line, line.height + diff);
  21357. });
  21358. };
  21359. function widgetHeight(widget) {
  21360. if (widget.height != null) return widget.height;
  21361. if (!contains(document.body, widget.node)) {
  21362. var parentStyle = "position: relative;";
  21363. if (widget.coverGutter)
  21364. parentStyle += "margin-left: -" + widget.cm.getGutterElement().offsetWidth + "px;";
  21365. removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, parentStyle));
  21366. }
  21367. return widget.height = widget.node.offsetHeight;
  21368. }
  21369. function addLineWidget(cm, handle, node, options) {
  21370. var widget = new LineWidget(cm, node, options);
  21371. if (widget.noHScroll) cm.display.alignWidgets = true;
  21372. changeLine(cm.doc, handle, "widget", function(line) {
  21373. var widgets = line.widgets || (line.widgets = []);
  21374. if (widget.insertAt == null) widgets.push(widget);
  21375. else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
  21376. widget.line = line;
  21377. if (!lineIsHidden(cm.doc, line)) {
  21378. var aboveVisible = heightAtLine(line) < cm.doc.scrollTop;
  21379. updateLineHeight(line, line.height + widgetHeight(widget));
  21380. if (aboveVisible) addToScrollPos(cm, null, widget.height);
  21381. cm.curOp.forceUpdate = true;
  21382. }
  21383. return true;
  21384. });
  21385. return widget;
  21386. }
  21387. // LINE DATA STRUCTURE
  21388. // Line objects. These hold state related to a line, including
  21389. // highlighting info (the styles array).
  21390. var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
  21391. this.text = text;
  21392. attachMarkedSpans(this, markedSpans);
  21393. this.height = estimateHeight ? estimateHeight(this) : 1;
  21394. };
  21395. eventMixin(Line);
  21396. Line.prototype.lineNo = function() { return lineNo(this); };
  21397. // Change the content (text, markers) of a line. Automatically
  21398. // invalidates cached information and tries to re-estimate the
  21399. // line's height.
  21400. function updateLine(line, text, markedSpans, estimateHeight) {
  21401. line.text = text;
  21402. if (line.stateAfter) line.stateAfter = null;
  21403. if (line.styles) line.styles = null;
  21404. if (line.order != null) line.order = null;
  21405. detachMarkedSpans(line);
  21406. attachMarkedSpans(line, markedSpans);
  21407. var estHeight = estimateHeight ? estimateHeight(line) : 1;
  21408. if (estHeight != line.height) updateLineHeight(line, estHeight);
  21409. }
  21410. // Detach a line from the document tree and its markers.
  21411. function cleanUpLine(line) {
  21412. line.parent = null;
  21413. detachMarkedSpans(line);
  21414. }
  21415. function extractLineClasses(type, output) {
  21416. if (type) for (;;) {
  21417. var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
  21418. if (!lineClass) break;
  21419. type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
  21420. var prop = lineClass[1] ? "bgClass" : "textClass";
  21421. if (output[prop] == null)
  21422. output[prop] = lineClass[2];
  21423. else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
  21424. output[prop] += " " + lineClass[2];
  21425. }
  21426. return type;
  21427. }
  21428. function callBlankLine(mode, state) {
  21429. if (mode.blankLine) return mode.blankLine(state);
  21430. if (!mode.innerMode) return;
  21431. var inner = CodeMirror.innerMode(mode, state);
  21432. if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
  21433. }
  21434. function readToken(mode, stream, state) {
  21435. for (var i = 0; i < 10; i++) {
  21436. var style = mode.token(stream, state);
  21437. if (stream.pos > stream.start) return style;
  21438. }
  21439. throw new Error("Mode " + mode.name + " failed to advance stream.");
  21440. }
  21441. // Run the given mode's parser over a line, calling f for each token.
  21442. function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
  21443. var flattenSpans = mode.flattenSpans;
  21444. if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
  21445. var curStart = 0, curStyle = null;
  21446. var stream = new StringStream(text, cm.options.tabSize), style;
  21447. if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
  21448. while (!stream.eol()) {
  21449. if (stream.pos > cm.options.maxHighlightLength) {
  21450. flattenSpans = false;
  21451. if (forceToEnd) processLine(cm, text, state, stream.pos);
  21452. stream.pos = text.length;
  21453. style = null;
  21454. } else {
  21455. style = extractLineClasses(readToken(mode, stream, state), lineClasses);
  21456. }
  21457. if (cm.options.addModeClass) {
  21458. var mName = CodeMirror.innerMode(mode, state).mode.name;
  21459. if (mName) style = "m-" + (style ? mName + " " + style : mName);
  21460. }
  21461. if (!flattenSpans || curStyle != style) {
  21462. if (curStart < stream.start) f(stream.start, curStyle);
  21463. curStart = stream.start; curStyle = style;
  21464. }
  21465. stream.start = stream.pos;
  21466. }
  21467. while (curStart < stream.pos) {
  21468. // Webkit seems to refuse to render text nodes longer than 57444 characters
  21469. var pos = Math.min(stream.pos, curStart + 50000);
  21470. f(pos, curStyle);
  21471. curStart = pos;
  21472. }
  21473. }
  21474. // Compute a style array (an array starting with a mode generation
  21475. // -- for invalidation -- followed by pairs of end positions and
  21476. // style strings), which is used to highlight the tokens on the
  21477. // line.
  21478. function highlightLine(cm, line, state, forceToEnd) {
  21479. // A styles array always starts with a number identifying the
  21480. // mode/overlays that it is based on (for easy invalidation).
  21481. var st = [cm.state.modeGen], lineClasses = {};
  21482. // Compute the base array of styles
  21483. runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
  21484. st.push(end, style);
  21485. }, lineClasses, forceToEnd);
  21486. // Run overlays, adjust style array.
  21487. for (var o = 0; o < cm.state.overlays.length; ++o) {
  21488. var overlay = cm.state.overlays[o], i = 1, at = 0;
  21489. runMode(cm, line.text, overlay.mode, true, function(end, style) {
  21490. var start = i;
  21491. // Ensure there's a token end at the current position, and that i points at it
  21492. while (at < end) {
  21493. var i_end = st[i];
  21494. if (i_end > end)
  21495. st.splice(i, 1, end, st[i+1], i_end);
  21496. i += 2;
  21497. at = Math.min(end, i_end);
  21498. }
  21499. if (!style) return;
  21500. if (overlay.opaque) {
  21501. st.splice(start, i - start, end, "cm-overlay " + style);
  21502. i = start + 2;
  21503. } else {
  21504. for (; start < i; start += 2) {
  21505. var cur = st[start+1];
  21506. st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
  21507. }
  21508. }
  21509. }, lineClasses);
  21510. }
  21511. return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
  21512. }
  21513. function getLineStyles(cm, line) {
  21514. if (!line.styles || line.styles[0] != cm.state.modeGen) {
  21515. var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
  21516. line.styles = result.styles;
  21517. if (result.classes) line.styleClasses = result.classes;
  21518. else if (line.styleClasses) line.styleClasses = null;
  21519. }
  21520. return line.styles;
  21521. }
  21522. // Lightweight form of highlight -- proceed over this line and
  21523. // update state, but don't save a style array. Used for lines that
  21524. // aren't currently visible.
  21525. function processLine(cm, text, state, startAt) {
  21526. var mode = cm.doc.mode;
  21527. var stream = new StringStream(text, cm.options.tabSize);
  21528. stream.start = stream.pos = startAt || 0;
  21529. if (text == "") callBlankLine(mode, state);
  21530. while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
  21531. readToken(mode, stream, state);
  21532. stream.start = stream.pos;
  21533. }
  21534. }
  21535. // Convert a style as returned by a mode (either null, or a string
  21536. // containing one or more styles) to a CSS style. This is cached,
  21537. // and also looks for line-wide styles.
  21538. var styleToClassCache = {}, styleToClassCacheWithMode = {};
  21539. function interpretTokenStyle(style, options) {
  21540. if (!style || /^\s*$/.test(style)) return null;
  21541. var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
  21542. return cache[style] ||
  21543. (cache[style] = style.replace(/\S+/g, "cm-$&"));
  21544. }
  21545. // Render the DOM representation of the text of a line. Also builds
  21546. // up a 'line map', which points at the DOM nodes that represent
  21547. // specific stretches of text, and is used by the measuring code.
  21548. // The returned object contains the DOM node, this map, and
  21549. // information about line-wide styles that were set by the mode.
  21550. function buildLineContent(cm, lineView) {
  21551. // The padding-right forces the element to have a 'border', which
  21552. // is needed on Webkit to be able to get line-level bounding
  21553. // rectangles for it (in measureChar).
  21554. var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
  21555. var builder = {pre: elt("pre", [content]), content: content, col: 0, pos: 0, cm: cm};
  21556. lineView.measure = {};
  21557. // Iterate over the logical lines that make up this visual line.
  21558. for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
  21559. var line = i ? lineView.rest[i - 1] : lineView.line, order;
  21560. builder.pos = 0;
  21561. builder.addToken = buildToken;
  21562. // Optionally wire in some hacks into the token-rendering
  21563. // algorithm, to deal with browser quirks.
  21564. if ((ie || webkit) && cm.getOption("lineWrapping"))
  21565. builder.addToken = buildTokenSplitSpaces(builder.addToken);
  21566. if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
  21567. builder.addToken = buildTokenBadBidi(builder.addToken, order);
  21568. builder.map = [];
  21569. insertLineContent(line, builder, getLineStyles(cm, line));
  21570. if (line.styleClasses) {
  21571. if (line.styleClasses.bgClass)
  21572. builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
  21573. if (line.styleClasses.textClass)
  21574. builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
  21575. }
  21576. // Ensure at least a single node is present, for measuring.
  21577. if (builder.map.length == 0)
  21578. builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
  21579. // Store the map and a cache object for the current logical line
  21580. if (i == 0) {
  21581. lineView.measure.map = builder.map;
  21582. lineView.measure.cache = {};
  21583. } else {
  21584. (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
  21585. (lineView.measure.caches || (lineView.measure.caches = [])).push({});
  21586. }
  21587. }
  21588. signal(cm, "renderLine", cm, lineView.line, builder.pre);
  21589. if (builder.pre.className)
  21590. builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
  21591. return builder;
  21592. }
  21593. function defaultSpecialCharPlaceholder(ch) {
  21594. var token = elt("span", "\u2022", "cm-invalidchar");
  21595. token.title = "\\u" + ch.charCodeAt(0).toString(16);
  21596. return token;
  21597. }
  21598. // Build up the DOM representation for a single token, and add it to
  21599. // the line map. Takes care to render special characters separately.
  21600. function buildToken(builder, text, style, startStyle, endStyle, title) {
  21601. if (!text) return;
  21602. var special = builder.cm.options.specialChars, mustWrap = false;
  21603. if (!special.test(text)) {
  21604. builder.col += text.length;
  21605. var content = document.createTextNode(text);
  21606. builder.map.push(builder.pos, builder.pos + text.length, content);
  21607. if (ie && ie_version < 9) mustWrap = true;
  21608. builder.pos += text.length;
  21609. } else {
  21610. var content = document.createDocumentFragment(), pos = 0;
  21611. while (true) {
  21612. special.lastIndex = pos;
  21613. var m = special.exec(text);
  21614. var skipped = m ? m.index - pos : text.length - pos;
  21615. if (skipped) {
  21616. var txt = document.createTextNode(text.slice(pos, pos + skipped));
  21617. if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
  21618. else content.appendChild(txt);
  21619. builder.map.push(builder.pos, builder.pos + skipped, txt);
  21620. builder.col += skipped;
  21621. builder.pos += skipped;
  21622. }
  21623. if (!m) break;
  21624. pos += skipped + 1;
  21625. if (m[0] == "\t") {
  21626. var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
  21627. var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
  21628. builder.col += tabWidth;
  21629. } else {
  21630. var txt = builder.cm.options.specialCharPlaceholder(m[0]);
  21631. if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
  21632. else content.appendChild(txt);
  21633. builder.col += 1;
  21634. }
  21635. builder.map.push(builder.pos, builder.pos + 1, txt);
  21636. builder.pos++;
  21637. }
  21638. }
  21639. if (style || startStyle || endStyle || mustWrap) {
  21640. var fullStyle = style || "";
  21641. if (startStyle) fullStyle += startStyle;
  21642. if (endStyle) fullStyle += endStyle;
  21643. var token = elt("span", [content], fullStyle);
  21644. if (title) token.title = title;
  21645. return builder.content.appendChild(token);
  21646. }
  21647. builder.content.appendChild(content);
  21648. }
  21649. function buildTokenSplitSpaces(inner) {
  21650. function split(old) {
  21651. var out = " ";
  21652. for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
  21653. out += " ";
  21654. return out;
  21655. }
  21656. return function(builder, text, style, startStyle, endStyle, title) {
  21657. inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);
  21658. };
  21659. }
  21660. // Work around nonsense dimensions being reported for stretches of
  21661. // right-to-left text.
  21662. function buildTokenBadBidi(inner, order) {
  21663. return function(builder, text, style, startStyle, endStyle, title) {
  21664. style = style ? style + " cm-force-border" : "cm-force-border";
  21665. var start = builder.pos, end = start + text.length;
  21666. for (;;) {
  21667. // Find the part that overlaps with the start of this text
  21668. for (var i = 0; i < order.length; i++) {
  21669. var part = order[i];
  21670. if (part.to > start && part.from <= start) break;
  21671. }
  21672. if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title);
  21673. inner(builder, text.slice(0, part.to - start), style, startStyle, null, title);
  21674. startStyle = null;
  21675. text = text.slice(part.to - start);
  21676. start = part.to;
  21677. }
  21678. };
  21679. }
  21680. function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
  21681. var widget = !ignoreWidget && marker.widgetNode;
  21682. if (widget) {
  21683. builder.map.push(builder.pos, builder.pos + size, widget);
  21684. builder.content.appendChild(widget);
  21685. }
  21686. builder.pos += size;
  21687. }
  21688. // Outputs a number of spans to make up a line, taking highlighting
  21689. // and marked text into account.
  21690. function insertLineContent(line, builder, styles) {
  21691. var spans = line.markedSpans, allText = line.text, at = 0;
  21692. if (!spans) {
  21693. for (var i = 1; i < styles.length; i+=2)
  21694. builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
  21695. return;
  21696. }
  21697. var len = allText.length, pos = 0, i = 1, text = "", style;
  21698. var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
  21699. for (;;) {
  21700. if (nextChange == pos) { // Update current marker set
  21701. spanStyle = spanEndStyle = spanStartStyle = title = "";
  21702. collapsed = null; nextChange = Infinity;
  21703. var foundBookmarks = [];
  21704. for (var j = 0; j < spans.length; ++j) {
  21705. var sp = spans[j], m = sp.marker;
  21706. if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
  21707. if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
  21708. if (m.className) spanStyle += " " + m.className;
  21709. if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
  21710. if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
  21711. if (m.title && !title) title = m.title;
  21712. if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
  21713. collapsed = sp;
  21714. } else if (sp.from > pos && nextChange > sp.from) {
  21715. nextChange = sp.from;
  21716. }
  21717. if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m);
  21718. }
  21719. if (collapsed && (collapsed.from || 0) == pos) {
  21720. buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
  21721. collapsed.marker, collapsed.from == null);
  21722. if (collapsed.to == null) return;
  21723. }
  21724. if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
  21725. buildCollapsedSpan(builder, 0, foundBookmarks[j]);
  21726. }
  21727. if (pos >= len) break;
  21728. var upto = Math.min(len, nextChange);
  21729. while (true) {
  21730. if (text) {
  21731. var end = pos + text.length;
  21732. if (!collapsed) {
  21733. var tokenText = end > upto ? text.slice(0, upto - pos) : text;
  21734. builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
  21735. spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
  21736. }
  21737. if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
  21738. pos = end;
  21739. spanStartStyle = "";
  21740. }
  21741. text = allText.slice(at, at = styles[i++]);
  21742. style = interpretTokenStyle(styles[i++], builder.cm.options);
  21743. }
  21744. }
  21745. }
  21746. // DOCUMENT DATA STRUCTURE
  21747. // By default, updates that start and end at the beginning of a line
  21748. // are treated specially, in order to make the association of line
  21749. // widgets and marker elements with the text behave more intuitive.
  21750. function isWholeLineUpdate(doc, change) {
  21751. return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
  21752. (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
  21753. }
  21754. // Perform a change on the document data structure.
  21755. function updateDoc(doc, change, markedSpans, estimateHeight) {
  21756. function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
  21757. function update(line, text, spans) {
  21758. updateLine(line, text, spans, estimateHeight);
  21759. signalLater(line, "change", line, change);
  21760. }
  21761. var from = change.from, to = change.to, text = change.text;
  21762. var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
  21763. var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
  21764. // Adjust the line structure
  21765. if (isWholeLineUpdate(doc, change)) {
  21766. // This is a whole-line replace. Treated specially to make
  21767. // sure line objects move the way they are supposed to.
  21768. for (var i = 0, added = []; i < text.length - 1; ++i)
  21769. added.push(new Line(text[i], spansFor(i), estimateHeight));
  21770. update(lastLine, lastLine.text, lastSpans);
  21771. if (nlines) doc.remove(from.line, nlines);
  21772. if (added.length) doc.insert(from.line, added);
  21773. } else if (firstLine == lastLine) {
  21774. if (text.length == 1) {
  21775. update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
  21776. } else {
  21777. for (var added = [], i = 1; i < text.length - 1; ++i)
  21778. added.push(new Line(text[i], spansFor(i), estimateHeight));
  21779. added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
  21780. update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
  21781. doc.insert(from.line + 1, added);
  21782. }
  21783. } else if (text.length == 1) {
  21784. update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
  21785. doc.remove(from.line + 1, nlines);
  21786. } else {
  21787. update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
  21788. update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
  21789. for (var i = 1, added = []; i < text.length - 1; ++i)
  21790. added.push(new Line(text[i], spansFor(i), estimateHeight));
  21791. if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
  21792. doc.insert(from.line + 1, added);
  21793. }
  21794. signalLater(doc, "change", doc, change);
  21795. }
  21796. // The document is represented as a BTree consisting of leaves, with
  21797. // chunk of lines in them, and branches, with up to ten leaves or
  21798. // other branch nodes below them. The top node is always a branch
  21799. // node, and is the document object itself (meaning it has
  21800. // additional methods and properties).
  21801. //
  21802. // All nodes have parent links. The tree is used both to go from
  21803. // line numbers to line objects, and to go from objects to numbers.
  21804. // It also indexes by height, and is used to convert between height
  21805. // and line object, and to find the total height of the document.
  21806. //
  21807. // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
  21808. function LeafChunk(lines) {
  21809. this.lines = lines;
  21810. this.parent = null;
  21811. for (var i = 0, height = 0; i < lines.length; ++i) {
  21812. lines[i].parent = this;
  21813. height += lines[i].height;
  21814. }
  21815. this.height = height;
  21816. }
  21817. LeafChunk.prototype = {
  21818. chunkSize: function() { return this.lines.length; },
  21819. // Remove the n lines at offset 'at'.
  21820. removeInner: function(at, n) {
  21821. for (var i = at, e = at + n; i < e; ++i) {
  21822. var line = this.lines[i];
  21823. this.height -= line.height;
  21824. cleanUpLine(line);
  21825. signalLater(line, "delete");
  21826. }
  21827. this.lines.splice(at, n);
  21828. },
  21829. // Helper used to collapse a small branch into a single leaf.
  21830. collapse: function(lines) {
  21831. lines.push.apply(lines, this.lines);
  21832. },
  21833. // Insert the given array of lines at offset 'at', count them as
  21834. // having the given height.
  21835. insertInner: function(at, lines, height) {
  21836. this.height += height;
  21837. this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
  21838. for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
  21839. },
  21840. // Used to iterate over a part of the tree.
  21841. iterN: function(at, n, op) {
  21842. for (var e = at + n; at < e; ++at)
  21843. if (op(this.lines[at])) return true;
  21844. }
  21845. };
  21846. function BranchChunk(children) {
  21847. this.children = children;
  21848. var size = 0, height = 0;
  21849. for (var i = 0; i < children.length; ++i) {
  21850. var ch = children[i];
  21851. size += ch.chunkSize(); height += ch.height;
  21852. ch.parent = this;
  21853. }
  21854. this.size = size;
  21855. this.height = height;
  21856. this.parent = null;
  21857. }
  21858. BranchChunk.prototype = {
  21859. chunkSize: function() { return this.size; },
  21860. removeInner: function(at, n) {
  21861. this.size -= n;
  21862. for (var i = 0; i < this.children.length; ++i) {
  21863. var child = this.children[i], sz = child.chunkSize();
  21864. if (at < sz) {
  21865. var rm = Math.min(n, sz - at), oldHeight = child.height;
  21866. child.removeInner(at, rm);
  21867. this.height -= oldHeight - child.height;
  21868. if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
  21869. if ((n -= rm) == 0) break;
  21870. at = 0;
  21871. } else at -= sz;
  21872. }
  21873. // If the result is smaller than 25 lines, ensure that it is a
  21874. // single leaf node.
  21875. if (this.size - n < 25 &&
  21876. (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
  21877. var lines = [];
  21878. this.collapse(lines);
  21879. this.children = [new LeafChunk(lines)];
  21880. this.children[0].parent = this;
  21881. }
  21882. },
  21883. collapse: function(lines) {
  21884. for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
  21885. },
  21886. insertInner: function(at, lines, height) {
  21887. this.size += lines.length;
  21888. this.height += height;
  21889. for (var i = 0; i < this.children.length; ++i) {
  21890. var child = this.children[i], sz = child.chunkSize();
  21891. if (at <= sz) {
  21892. child.insertInner(at, lines, height);
  21893. if (child.lines && child.lines.length > 50) {
  21894. while (child.lines.length > 50) {
  21895. var spilled = child.lines.splice(child.lines.length - 25, 25);
  21896. var newleaf = new LeafChunk(spilled);
  21897. child.height -= newleaf.height;
  21898. this.children.splice(i + 1, 0, newleaf);
  21899. newleaf.parent = this;
  21900. }
  21901. this.maybeSpill();
  21902. }
  21903. break;
  21904. }
  21905. at -= sz;
  21906. }
  21907. },
  21908. // When a node has grown, check whether it should be split.
  21909. maybeSpill: function() {
  21910. if (this.children.length <= 10) return;
  21911. var me = this;
  21912. do {
  21913. var spilled = me.children.splice(me.children.length - 5, 5);
  21914. var sibling = new BranchChunk(spilled);
  21915. if (!me.parent) { // Become the parent node
  21916. var copy = new BranchChunk(me.children);
  21917. copy.parent = me;
  21918. me.children = [copy, sibling];
  21919. me = copy;
  21920. } else {
  21921. me.size -= sibling.size;
  21922. me.height -= sibling.height;
  21923. var myIndex = indexOf(me.parent.children, me);
  21924. me.parent.children.splice(myIndex + 1, 0, sibling);
  21925. }
  21926. sibling.parent = me.parent;
  21927. } while (me.children.length > 10);
  21928. me.parent.maybeSpill();
  21929. },
  21930. iterN: function(at, n, op) {
  21931. for (var i = 0; i < this.children.length; ++i) {
  21932. var child = this.children[i], sz = child.chunkSize();
  21933. if (at < sz) {
  21934. var used = Math.min(n, sz - at);
  21935. if (child.iterN(at, used, op)) return true;
  21936. if ((n -= used) == 0) break;
  21937. at = 0;
  21938. } else at -= sz;
  21939. }
  21940. }
  21941. };
  21942. var nextDocId = 0;
  21943. var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
  21944. if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
  21945. if (firstLine == null) firstLine = 0;
  21946. BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
  21947. this.first = firstLine;
  21948. this.scrollTop = this.scrollLeft = 0;
  21949. this.cantEdit = false;
  21950. this.cleanGeneration = 1;
  21951. this.frontier = firstLine;
  21952. var start = Pos(firstLine, 0);
  21953. this.sel = simpleSelection(start);
  21954. this.history = new History(null);
  21955. this.id = ++nextDocId;
  21956. this.modeOption = mode;
  21957. if (typeof text == "string") text = splitLines(text);
  21958. updateDoc(this, {from: start, to: start, text: text});
  21959. setSelection(this, simpleSelection(start), sel_dontScroll);
  21960. };
  21961. Doc.prototype = createObj(BranchChunk.prototype, {
  21962. constructor: Doc,
  21963. // Iterate over the document. Supports two forms -- with only one
  21964. // argument, it calls that for each line in the document. With
  21965. // three, it iterates over the range given by the first two (with
  21966. // the second being non-inclusive).
  21967. iter: function(from, to, op) {
  21968. if (op) this.iterN(from - this.first, to - from, op);
  21969. else this.iterN(this.first, this.first + this.size, from);
  21970. },
  21971. // Non-public interface for adding and removing lines.
  21972. insert: function(at, lines) {
  21973. var height = 0;
  21974. for (var i = 0; i < lines.length; ++i) height += lines[i].height;
  21975. this.insertInner(at - this.first, lines, height);
  21976. },
  21977. remove: function(at, n) { this.removeInner(at - this.first, n); },
  21978. // From here, the methods are part of the public interface. Most
  21979. // are also available from CodeMirror (editor) instances.
  21980. getValue: function(lineSep) {
  21981. var lines = getLines(this, this.first, this.first + this.size);
  21982. if (lineSep === false) return lines;
  21983. return lines.join(lineSep || "\n");
  21984. },
  21985. setValue: docMethodOp(function(code) {
  21986. var top = Pos(this.first, 0), last = this.first + this.size - 1;
  21987. makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
  21988. text: splitLines(code), origin: "setValue"}, true);
  21989. setSelection(this, simpleSelection(top));
  21990. }),
  21991. replaceRange: function(code, from, to, origin) {
  21992. from = clipPos(this, from);
  21993. to = to ? clipPos(this, to) : from;
  21994. replaceRange(this, code, from, to, origin);
  21995. },
  21996. getRange: function(from, to, lineSep) {
  21997. var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
  21998. if (lineSep === false) return lines;
  21999. return lines.join(lineSep || "\n");
  22000. },
  22001. getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
  22002. getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
  22003. getLineNumber: function(line) {return lineNo(line);},
  22004. getLineHandleVisualStart: function(line) {
  22005. if (typeof line == "number") line = getLine(this, line);
  22006. return visualLine(line);
  22007. },
  22008. lineCount: function() {return this.size;},
  22009. firstLine: function() {return this.first;},
  22010. lastLine: function() {return this.first + this.size - 1;},
  22011. clipPos: function(pos) {return clipPos(this, pos);},
  22012. getCursor: function(start) {
  22013. var range = this.sel.primary(), pos;
  22014. if (start == null || start == "head") pos = range.head;
  22015. else if (start == "anchor") pos = range.anchor;
  22016. else if (start == "end" || start == "to" || start === false) pos = range.to();
  22017. else pos = range.from();
  22018. return pos;
  22019. },
  22020. listSelections: function() { return this.sel.ranges; },
  22021. somethingSelected: function() {return this.sel.somethingSelected();},
  22022. setCursor: docMethodOp(function(line, ch, options) {
  22023. setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
  22024. }),
  22025. setSelection: docMethodOp(function(anchor, head, options) {
  22026. setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
  22027. }),
  22028. extendSelection: docMethodOp(function(head, other, options) {
  22029. extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
  22030. }),
  22031. extendSelections: docMethodOp(function(heads, options) {
  22032. extendSelections(this, clipPosArray(this, heads, options));
  22033. }),
  22034. extendSelectionsBy: docMethodOp(function(f, options) {
  22035. extendSelections(this, map(this.sel.ranges, f), options);
  22036. }),
  22037. setSelections: docMethodOp(function(ranges, primary, options) {
  22038. if (!ranges.length) return;
  22039. for (var i = 0, out = []; i < ranges.length; i++)
  22040. out[i] = new Range(clipPos(this, ranges[i].anchor),
  22041. clipPos(this, ranges[i].head));
  22042. if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
  22043. setSelection(this, normalizeSelection(out, primary), options);
  22044. }),
  22045. addSelection: docMethodOp(function(anchor, head, options) {
  22046. var ranges = this.sel.ranges.slice(0);
  22047. ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
  22048. setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
  22049. }),
  22050. getSelection: function(lineSep) {
  22051. var ranges = this.sel.ranges, lines;
  22052. for (var i = 0; i < ranges.length; i++) {
  22053. var sel = getBetween(this, ranges[i].from(), ranges[i].to());
  22054. lines = lines ? lines.concat(sel) : sel;
  22055. }
  22056. if (lineSep === false) return lines;
  22057. else return lines.join(lineSep || "\n");
  22058. },
  22059. getSelections: function(lineSep) {
  22060. var parts = [], ranges = this.sel.ranges;
  22061. for (var i = 0; i < ranges.length; i++) {
  22062. var sel = getBetween(this, ranges[i].from(), ranges[i].to());
  22063. if (lineSep !== false) sel = sel.join(lineSep || "\n");
  22064. parts[i] = sel;
  22065. }
  22066. return parts;
  22067. },
  22068. replaceSelection: function(code, collapse, origin) {
  22069. var dup = [];
  22070. for (var i = 0; i < this.sel.ranges.length; i++)
  22071. dup[i] = code;
  22072. this.replaceSelections(dup, collapse, origin || "+input");
  22073. },
  22074. replaceSelections: docMethodOp(function(code, collapse, origin) {
  22075. var changes = [], sel = this.sel;
  22076. for (var i = 0; i < sel.ranges.length; i++) {
  22077. var range = sel.ranges[i];
  22078. changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
  22079. }
  22080. var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
  22081. for (var i = changes.length - 1; i >= 0; i--)
  22082. makeChange(this, changes[i]);
  22083. if (newSel) setSelectionReplaceHistory(this, newSel);
  22084. else if (this.cm) ensureCursorVisible(this.cm);
  22085. }),
  22086. undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
  22087. redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
  22088. undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
  22089. redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
  22090. setExtending: function(val) {this.extend = val;},
  22091. getExtending: function() {return this.extend;},
  22092. historySize: function() {
  22093. var hist = this.history, done = 0, undone = 0;
  22094. for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
  22095. for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
  22096. return {undo: done, redo: undone};
  22097. },
  22098. clearHistory: function() {this.history = new History(this.history.maxGeneration);},
  22099. markClean: function() {
  22100. this.cleanGeneration = this.changeGeneration(true);
  22101. },
  22102. changeGeneration: function(forceSplit) {
  22103. if (forceSplit)
  22104. this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
  22105. return this.history.generation;
  22106. },
  22107. isClean: function (gen) {
  22108. return this.history.generation == (gen || this.cleanGeneration);
  22109. },
  22110. getHistory: function() {
  22111. return {done: copyHistoryArray(this.history.done),
  22112. undone: copyHistoryArray(this.history.undone)};
  22113. },
  22114. setHistory: function(histData) {
  22115. var hist = this.history = new History(this.history.maxGeneration);
  22116. hist.done = copyHistoryArray(histData.done.slice(0), null, true);
  22117. hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
  22118. },
  22119. addLineClass: docMethodOp(function(handle, where, cls) {
  22120. return changeLine(this, handle, "class", function(line) {
  22121. var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
  22122. if (!line[prop]) line[prop] = cls;
  22123. else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false;
  22124. else line[prop] += " " + cls;
  22125. return true;
  22126. });
  22127. }),
  22128. removeLineClass: docMethodOp(function(handle, where, cls) {
  22129. return changeLine(this, handle, "class", function(line) {
  22130. var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
  22131. var cur = line[prop];
  22132. if (!cur) return false;
  22133. else if (cls == null) line[prop] = null;
  22134. else {
  22135. var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
  22136. if (!found) return false;
  22137. var end = found.index + found[0].length;
  22138. line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
  22139. }
  22140. return true;
  22141. });
  22142. }),
  22143. markText: function(from, to, options) {
  22144. return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
  22145. },
  22146. setBookmark: function(pos, options) {
  22147. var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
  22148. insertLeft: options && options.insertLeft,
  22149. clearWhenEmpty: false, shared: options && options.shared};
  22150. pos = clipPos(this, pos);
  22151. return markText(this, pos, pos, realOpts, "bookmark");
  22152. },
  22153. findMarksAt: function(pos) {
  22154. pos = clipPos(this, pos);
  22155. var markers = [], spans = getLine(this, pos.line).markedSpans;
  22156. if (spans) for (var i = 0; i < spans.length; ++i) {
  22157. var span = spans[i];
  22158. if ((span.from == null || span.from <= pos.ch) &&
  22159. (span.to == null || span.to >= pos.ch))
  22160. markers.push(span.marker.parent || span.marker);
  22161. }
  22162. return markers;
  22163. },
  22164. findMarks: function(from, to, filter) {
  22165. from = clipPos(this, from); to = clipPos(this, to);
  22166. var found = [], lineNo = from.line;
  22167. this.iter(from.line, to.line + 1, function(line) {
  22168. var spans = line.markedSpans;
  22169. if (spans) for (var i = 0; i < spans.length; i++) {
  22170. var span = spans[i];
  22171. if (!(lineNo == from.line && from.ch > span.to ||
  22172. span.from == null && lineNo != from.line||
  22173. lineNo == to.line && span.from > to.ch) &&
  22174. (!filter || filter(span.marker)))
  22175. found.push(span.marker.parent || span.marker);
  22176. }
  22177. ++lineNo;
  22178. });
  22179. return found;
  22180. },
  22181. getAllMarks: function() {
  22182. var markers = [];
  22183. this.iter(function(line) {
  22184. var sps = line.markedSpans;
  22185. if (sps) for (var i = 0; i < sps.length; ++i)
  22186. if (sps[i].from != null) markers.push(sps[i].marker);
  22187. });
  22188. return markers;
  22189. },
  22190. posFromIndex: function(off) {
  22191. var ch, lineNo = this.first;
  22192. this.iter(function(line) {
  22193. var sz = line.text.length + 1;
  22194. if (sz > off) { ch = off; return true; }
  22195. off -= sz;
  22196. ++lineNo;
  22197. });
  22198. return clipPos(this, Pos(lineNo, ch));
  22199. },
  22200. indexFromPos: function (coords) {
  22201. coords = clipPos(this, coords);
  22202. var index = coords.ch;
  22203. if (coords.line < this.first || coords.ch < 0) return 0;
  22204. this.iter(this.first, coords.line, function (line) {
  22205. index += line.text.length + 1;
  22206. });
  22207. return index;
  22208. },
  22209. copy: function(copyHistory) {
  22210. var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
  22211. doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
  22212. doc.sel = this.sel;
  22213. doc.extend = false;
  22214. if (copyHistory) {
  22215. doc.history.undoDepth = this.history.undoDepth;
  22216. doc.setHistory(this.getHistory());
  22217. }
  22218. return doc;
  22219. },
  22220. linkedDoc: function(options) {
  22221. if (!options) options = {};
  22222. var from = this.first, to = this.first + this.size;
  22223. if (options.from != null && options.from > from) from = options.from;
  22224. if (options.to != null && options.to < to) to = options.to;
  22225. var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
  22226. if (options.sharedHist) copy.history = this.history;
  22227. (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
  22228. copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
  22229. copySharedMarkers(copy, findSharedMarkers(this));
  22230. return copy;
  22231. },
  22232. unlinkDoc: function(other) {
  22233. if (other instanceof CodeMirror) other = other.doc;
  22234. if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
  22235. var link = this.linked[i];
  22236. if (link.doc != other) continue;
  22237. this.linked.splice(i, 1);
  22238. other.unlinkDoc(this);
  22239. detachSharedMarkers(findSharedMarkers(this));
  22240. break;
  22241. }
  22242. // If the histories were shared, split them again
  22243. if (other.history == this.history) {
  22244. var splitIds = [other.id];
  22245. linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
  22246. other.history = new History(null);
  22247. other.history.done = copyHistoryArray(this.history.done, splitIds);
  22248. other.history.undone = copyHistoryArray(this.history.undone, splitIds);
  22249. }
  22250. },
  22251. iterLinkedDocs: function(f) {linkedDocs(this, f);},
  22252. getMode: function() {return this.mode;},
  22253. getEditor: function() {return this.cm;}
  22254. });
  22255. // Public alias.
  22256. Doc.prototype.eachLine = Doc.prototype.iter;
  22257. // Set up methods on CodeMirror's prototype to redirect to the editor's document.
  22258. var dontDelegate = "iter insert remove copy getEditor".split(" ");
  22259. for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
  22260. CodeMirror.prototype[prop] = (function(method) {
  22261. return function() {return method.apply(this.doc, arguments);};
  22262. })(Doc.prototype[prop]);
  22263. eventMixin(Doc);
  22264. // Call f for all linked documents.
  22265. function linkedDocs(doc, f, sharedHistOnly) {
  22266. function propagate(doc, skip, sharedHist) {
  22267. if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
  22268. var rel = doc.linked[i];
  22269. if (rel.doc == skip) continue;
  22270. var shared = sharedHist && rel.sharedHist;
  22271. if (sharedHistOnly && !shared) continue;
  22272. f(rel.doc, shared);
  22273. propagate(rel.doc, doc, shared);
  22274. }
  22275. }
  22276. propagate(doc, null, true);
  22277. }
  22278. // Attach a document to an editor.
  22279. function attachDoc(cm, doc) {
  22280. if (doc.cm) throw new Error("This document is already in use.");
  22281. cm.doc = doc;
  22282. doc.cm = cm;
  22283. estimateLineHeights(cm);
  22284. loadMode(cm);
  22285. if (!cm.options.lineWrapping) findMaxLine(cm);
  22286. cm.options.mode = doc.modeOption;
  22287. regChange(cm);
  22288. }
  22289. // LINE UTILITIES
  22290. // Find the line object corresponding to the given line number.
  22291. function getLine(doc, n) {
  22292. n -= doc.first;
  22293. if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
  22294. for (var chunk = doc; !chunk.lines;) {
  22295. for (var i = 0;; ++i) {
  22296. var child = chunk.children[i], sz = child.chunkSize();
  22297. if (n < sz) { chunk = child; break; }
  22298. n -= sz;
  22299. }
  22300. }
  22301. return chunk.lines[n];
  22302. }
  22303. // Get the part of a document between two positions, as an array of
  22304. // strings.
  22305. function getBetween(doc, start, end) {
  22306. var out = [], n = start.line;
  22307. doc.iter(start.line, end.line + 1, function(line) {
  22308. var text = line.text;
  22309. if (n == end.line) text = text.slice(0, end.ch);
  22310. if (n == start.line) text = text.slice(start.ch);
  22311. out.push(text);
  22312. ++n;
  22313. });
  22314. return out;
  22315. }
  22316. // Get the lines between from and to, as array of strings.
  22317. function getLines(doc, from, to) {
  22318. var out = [];
  22319. doc.iter(from, to, function(line) { out.push(line.text); });
  22320. return out;
  22321. }
  22322. // Update the height of a line, propagating the height change
  22323. // upwards to parent nodes.
  22324. function updateLineHeight(line, height) {
  22325. var diff = height - line.height;
  22326. if (diff) for (var n = line; n; n = n.parent) n.height += diff;
  22327. }
  22328. // Given a line object, find its line number by walking up through
  22329. // its parent links.
  22330. function lineNo(line) {
  22331. if (line.parent == null) return null;
  22332. var cur = line.parent, no = indexOf(cur.lines, line);
  22333. for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
  22334. for (var i = 0;; ++i) {
  22335. if (chunk.children[i] == cur) break;
  22336. no += chunk.children[i].chunkSize();
  22337. }
  22338. }
  22339. return no + cur.first;
  22340. }
  22341. // Find the line at the given vertical position, using the height
  22342. // information in the document tree.
  22343. function lineAtHeight(chunk, h) {
  22344. var n = chunk.first;
  22345. outer: do {
  22346. for (var i = 0; i < chunk.children.length; ++i) {
  22347. var child = chunk.children[i], ch = child.height;
  22348. if (h < ch) { chunk = child; continue outer; }
  22349. h -= ch;
  22350. n += child.chunkSize();
  22351. }
  22352. return n;
  22353. } while (!chunk.lines);
  22354. for (var i = 0; i < chunk.lines.length; ++i) {
  22355. var line = chunk.lines[i], lh = line.height;
  22356. if (h < lh) break;
  22357. h -= lh;
  22358. }
  22359. return n + i;
  22360. }
  22361. // Find the height above the given line.
  22362. function heightAtLine(lineObj) {
  22363. lineObj = visualLine(lineObj);
  22364. var h = 0, chunk = lineObj.parent;
  22365. for (var i = 0; i < chunk.lines.length; ++i) {
  22366. var line = chunk.lines[i];
  22367. if (line == lineObj) break;
  22368. else h += line.height;
  22369. }
  22370. for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
  22371. for (var i = 0; i < p.children.length; ++i) {
  22372. var cur = p.children[i];
  22373. if (cur == chunk) break;
  22374. else h += cur.height;
  22375. }
  22376. }
  22377. return h;
  22378. }
  22379. // Get the bidi ordering for the given line (and cache it). Returns
  22380. // false for lines that are fully left-to-right, and an array of
  22381. // BidiSpan objects otherwise.
  22382. function getOrder(line) {
  22383. var order = line.order;
  22384. if (order == null) order = line.order = bidiOrdering(line.text);
  22385. return order;
  22386. }
  22387. // HISTORY
  22388. function History(startGen) {
  22389. // Arrays of change events and selections. Doing something adds an
  22390. // event to done and clears undo. Undoing moves events from done
  22391. // to undone, redoing moves them in the other direction.
  22392. this.done = []; this.undone = [];
  22393. this.undoDepth = Infinity;
  22394. // Used to track when changes can be merged into a single undo
  22395. // event
  22396. this.lastModTime = this.lastSelTime = 0;
  22397. this.lastOp = this.lastSelOp = null;
  22398. this.lastOrigin = this.lastSelOrigin = null;
  22399. // Used by the isClean() method
  22400. this.generation = this.maxGeneration = startGen || 1;
  22401. }
  22402. // Create a history change event from an updateDoc-style change
  22403. // object.
  22404. function historyChangeFromChange(doc, change) {
  22405. var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
  22406. attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
  22407. linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
  22408. return histChange;
  22409. }
  22410. // Pop all selection events off the end of a history array. Stop at
  22411. // a change event.
  22412. function clearSelectionEvents(array) {
  22413. while (array.length) {
  22414. var last = lst(array);
  22415. if (last.ranges) array.pop();
  22416. else break;
  22417. }
  22418. }
  22419. // Find the top change event in the history. Pop off selection
  22420. // events that are in the way.
  22421. function lastChangeEvent(hist, force) {
  22422. if (force) {
  22423. clearSelectionEvents(hist.done);
  22424. return lst(hist.done);
  22425. } else if (hist.done.length && !lst(hist.done).ranges) {
  22426. return lst(hist.done);
  22427. } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
  22428. hist.done.pop();
  22429. return lst(hist.done);
  22430. }
  22431. }
  22432. // Register a change in the history. Merges changes that are within
  22433. // a single operation, ore are close together with an origin that
  22434. // allows merging (starting with "+") into a single event.
  22435. function addChangeToHistory(doc, change, selAfter, opId) {
  22436. var hist = doc.history;
  22437. hist.undone.length = 0;
  22438. var time = +new Date, cur;
  22439. if ((hist.lastOp == opId ||
  22440. hist.lastOrigin == change.origin && change.origin &&
  22441. ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
  22442. change.origin.charAt(0) == "*")) &&
  22443. (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
  22444. // Merge this change into the last event
  22445. var last = lst(cur.changes);
  22446. if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
  22447. // Optimized case for simple insertion -- don't want to add
  22448. // new changesets for every character typed
  22449. last.to = changeEnd(change);
  22450. } else {
  22451. // Add new sub-event
  22452. cur.changes.push(historyChangeFromChange(doc, change));
  22453. }
  22454. } else {
  22455. // Can not be merged, start a new event.
  22456. var before = lst(hist.done);
  22457. if (!before || !before.ranges)
  22458. pushSelectionToHistory(doc.sel, hist.done);
  22459. cur = {changes: [historyChangeFromChange(doc, change)],
  22460. generation: hist.generation};
  22461. hist.done.push(cur);
  22462. while (hist.done.length > hist.undoDepth) {
  22463. hist.done.shift();
  22464. if (!hist.done[0].ranges) hist.done.shift();
  22465. }
  22466. }
  22467. hist.done.push(selAfter);
  22468. hist.generation = ++hist.maxGeneration;
  22469. hist.lastModTime = hist.lastSelTime = time;
  22470. hist.lastOp = hist.lastSelOp = opId;
  22471. hist.lastOrigin = hist.lastSelOrigin = change.origin;
  22472. if (!last) signal(doc, "historyAdded");
  22473. }
  22474. function selectionEventCanBeMerged(doc, origin, prev, sel) {
  22475. var ch = origin.charAt(0);
  22476. return ch == "*" ||
  22477. ch == "+" &&
  22478. prev.ranges.length == sel.ranges.length &&
  22479. prev.somethingSelected() == sel.somethingSelected() &&
  22480. new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
  22481. }
  22482. // Called whenever the selection changes, sets the new selection as
  22483. // the pending selection in the history, and pushes the old pending
  22484. // selection into the 'done' array when it was significantly
  22485. // different (in number of selected ranges, emptiness, or time).
  22486. function addSelectionToHistory(doc, sel, opId, options) {
  22487. var hist = doc.history, origin = options && options.origin;
  22488. // A new event is started when the previous origin does not match
  22489. // the current, or the origins don't allow matching. Origins
  22490. // starting with * are always merged, those starting with + are
  22491. // merged when similar and close together in time.
  22492. if (opId == hist.lastSelOp ||
  22493. (origin && hist.lastSelOrigin == origin &&
  22494. (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
  22495. selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
  22496. hist.done[hist.done.length - 1] = sel;
  22497. else
  22498. pushSelectionToHistory(sel, hist.done);
  22499. hist.lastSelTime = +new Date;
  22500. hist.lastSelOrigin = origin;
  22501. hist.lastSelOp = opId;
  22502. if (options && options.clearRedo !== false)
  22503. clearSelectionEvents(hist.undone);
  22504. }
  22505. function pushSelectionToHistory(sel, dest) {
  22506. var top = lst(dest);
  22507. if (!(top && top.ranges && top.equals(sel)))
  22508. dest.push(sel);
  22509. }
  22510. // Used to store marked span information in the history.
  22511. function attachLocalSpans(doc, change, from, to) {
  22512. var existing = change["spans_" + doc.id], n = 0;
  22513. doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
  22514. if (line.markedSpans)
  22515. (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
  22516. ++n;
  22517. });
  22518. }
  22519. // When un/re-doing restores text containing marked spans, those
  22520. // that have been explicitly cleared should not be restored.
  22521. function removeClearedSpans(spans) {
  22522. if (!spans) return null;
  22523. for (var i = 0, out; i < spans.length; ++i) {
  22524. if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
  22525. else if (out) out.push(spans[i]);
  22526. }
  22527. return !out ? spans : out.length ? out : null;
  22528. }
  22529. // Retrieve and filter the old marked spans stored in a change event.
  22530. function getOldSpans(doc, change) {
  22531. var found = change["spans_" + doc.id];
  22532. if (!found) return null;
  22533. for (var i = 0, nw = []; i < change.text.length; ++i)
  22534. nw.push(removeClearedSpans(found[i]));
  22535. return nw;
  22536. }
  22537. // Used both to provide a JSON-safe object in .getHistory, and, when
  22538. // detaching a document, to split the history in two
  22539. function copyHistoryArray(events, newGroup, instantiateSel) {
  22540. for (var i = 0, copy = []; i < events.length; ++i) {
  22541. var event = events[i];
  22542. if (event.ranges) {
  22543. copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
  22544. continue;
  22545. }
  22546. var changes = event.changes, newChanges = [];
  22547. copy.push({changes: newChanges});
  22548. for (var j = 0; j < changes.length; ++j) {
  22549. var change = changes[j], m;
  22550. newChanges.push({from: change.from, to: change.to, text: change.text});
  22551. if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
  22552. if (indexOf(newGroup, Number(m[1])) > -1) {
  22553. lst(newChanges)[prop] = change[prop];
  22554. delete change[prop];
  22555. }
  22556. }
  22557. }
  22558. }
  22559. return copy;
  22560. }
  22561. // Rebasing/resetting history to deal with externally-sourced changes
  22562. function rebaseHistSelSingle(pos, from, to, diff) {
  22563. if (to < pos.line) {
  22564. pos.line += diff;
  22565. } else if (from < pos.line) {
  22566. pos.line = from;
  22567. pos.ch = 0;
  22568. }
  22569. }
  22570. // Tries to rebase an array of history events given a change in the
  22571. // document. If the change touches the same lines as the event, the
  22572. // event, and everything 'behind' it, is discarded. If the change is
  22573. // before the event, the event's positions are updated. Uses a
  22574. // copy-on-write scheme for the positions, to avoid having to
  22575. // reallocate them all on every rebase, but also avoid problems with
  22576. // shared position objects being unsafely updated.
  22577. function rebaseHistArray(array, from, to, diff) {
  22578. for (var i = 0; i < array.length; ++i) {
  22579. var sub = array[i], ok = true;
  22580. if (sub.ranges) {
  22581. if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
  22582. for (var j = 0; j < sub.ranges.length; j++) {
  22583. rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
  22584. rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
  22585. }
  22586. continue;
  22587. }
  22588. for (var j = 0; j < sub.changes.length; ++j) {
  22589. var cur = sub.changes[j];
  22590. if (to < cur.from.line) {
  22591. cur.from = Pos(cur.from.line + diff, cur.from.ch);
  22592. cur.to = Pos(cur.to.line + diff, cur.to.ch);
  22593. } else if (from <= cur.to.line) {
  22594. ok = false;
  22595. break;
  22596. }
  22597. }
  22598. if (!ok) {
  22599. array.splice(0, i + 1);
  22600. i = 0;
  22601. }
  22602. }
  22603. }
  22604. function rebaseHist(hist, change) {
  22605. var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
  22606. rebaseHistArray(hist.done, from, to, diff);
  22607. rebaseHistArray(hist.undone, from, to, diff);
  22608. }
  22609. // EVENT UTILITIES
  22610. // Due to the fact that we still support jurassic IE versions, some
  22611. // compatibility wrappers are needed.
  22612. var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
  22613. if (e.preventDefault) e.preventDefault();
  22614. else e.returnValue = false;
  22615. };
  22616. var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
  22617. if (e.stopPropagation) e.stopPropagation();
  22618. else e.cancelBubble = true;
  22619. };
  22620. function e_defaultPrevented(e) {
  22621. return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
  22622. }
  22623. var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
  22624. function e_target(e) {return e.target || e.srcElement;}
  22625. function e_button(e) {
  22626. var b = e.which;
  22627. if (b == null) {
  22628. if (e.button & 1) b = 1;
  22629. else if (e.button & 2) b = 3;
  22630. else if (e.button & 4) b = 2;
  22631. }
  22632. if (mac && e.ctrlKey && b == 1) b = 3;
  22633. return b;
  22634. }
  22635. // EVENT HANDLING
  22636. // Lightweight event framework. on/off also work on DOM nodes,
  22637. // registering native DOM handlers.
  22638. var on = CodeMirror.on = function(emitter, type, f) {
  22639. if (emitter.addEventListener)
  22640. emitter.addEventListener(type, f, false);
  22641. else if (emitter.attachEvent)
  22642. emitter.attachEvent("on" + type, f);
  22643. else {
  22644. var map = emitter._handlers || (emitter._handlers = {});
  22645. var arr = map[type] || (map[type] = []);
  22646. arr.push(f);
  22647. }
  22648. };
  22649. var off = CodeMirror.off = function(emitter, type, f) {
  22650. if (emitter.removeEventListener)
  22651. emitter.removeEventListener(type, f, false);
  22652. else if (emitter.detachEvent)
  22653. emitter.detachEvent("on" + type, f);
  22654. else {
  22655. var arr = emitter._handlers && emitter._handlers[type];
  22656. if (!arr) return;
  22657. for (var i = 0; i < arr.length; ++i)
  22658. if (arr[i] == f) { arr.splice(i, 1); break; }
  22659. }
  22660. };
  22661. var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
  22662. var arr = emitter._handlers && emitter._handlers[type];
  22663. if (!arr) return;
  22664. var args = Array.prototype.slice.call(arguments, 2);
  22665. for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
  22666. };
  22667. var orphanDelayedCallbacks = null;
  22668. // Often, we want to signal events at a point where we are in the
  22669. // middle of some work, but don't want the handler to start calling
  22670. // other methods on the editor, which might be in an inconsistent
  22671. // state or simply not expect any other events to happen.
  22672. // signalLater looks whether there are any handlers, and schedules
  22673. // them to be executed when the last operation ends, or, if no
  22674. // operation is active, when a timeout fires.
  22675. function signalLater(emitter, type /*, values...*/) {
  22676. var arr = emitter._handlers && emitter._handlers[type];
  22677. if (!arr) return;
  22678. var args = Array.prototype.slice.call(arguments, 2), list;
  22679. if (operationGroup) {
  22680. list = operationGroup.delayedCallbacks;
  22681. } else if (orphanDelayedCallbacks) {
  22682. list = orphanDelayedCallbacks;
  22683. } else {
  22684. list = orphanDelayedCallbacks = [];
  22685. setTimeout(fireOrphanDelayed, 0);
  22686. }
  22687. function bnd(f) {return function(){f.apply(null, args);};};
  22688. for (var i = 0; i < arr.length; ++i)
  22689. list.push(bnd(arr[i]));
  22690. }
  22691. function fireOrphanDelayed() {
  22692. var delayed = orphanDelayedCallbacks;
  22693. orphanDelayedCallbacks = null;
  22694. for (var i = 0; i < delayed.length; ++i) delayed[i]();
  22695. }
  22696. // The DOM events that CodeMirror handles can be overridden by
  22697. // registering a (non-DOM) handler on the editor for the event name,
  22698. // and preventDefault-ing the event in that handler.
  22699. function signalDOMEvent(cm, e, override) {
  22700. signal(cm, override || e.type, cm, e);
  22701. return e_defaultPrevented(e) || e.codemirrorIgnore;
  22702. }
  22703. function signalCursorActivity(cm) {
  22704. var arr = cm._handlers && cm._handlers.cursorActivity;
  22705. if (!arr) return;
  22706. var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
  22707. for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
  22708. set.push(arr[i]);
  22709. }
  22710. function hasHandler(emitter, type) {
  22711. var arr = emitter._handlers && emitter._handlers[type];
  22712. return arr && arr.length > 0;
  22713. }
  22714. // Add on and off methods to a constructor's prototype, to make
  22715. // registering events on such objects more convenient.
  22716. function eventMixin(ctor) {
  22717. ctor.prototype.on = function(type, f) {on(this, type, f);};
  22718. ctor.prototype.off = function(type, f) {off(this, type, f);};
  22719. }
  22720. // MISC UTILITIES
  22721. // Number of pixels added to scroller and sizer to hide scrollbar
  22722. var scrollerCutOff = 30;
  22723. // Returned or thrown by various protocols to signal 'I'm not
  22724. // handling this'.
  22725. var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
  22726. // Reused option objects for setSelection & friends
  22727. var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
  22728. function Delayed() {this.id = null;}
  22729. Delayed.prototype.set = function(ms, f) {
  22730. clearTimeout(this.id);
  22731. this.id = setTimeout(f, ms);
  22732. };
  22733. // Counts the column offset in a string, taking tabs into account.
  22734. // Used mostly to find indentation.
  22735. var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
  22736. if (end == null) {
  22737. end = string.search(/[^\s\u00a0]/);
  22738. if (end == -1) end = string.length;
  22739. }
  22740. for (var i = startIndex || 0, n = startValue || 0;;) {
  22741. var nextTab = string.indexOf("\t", i);
  22742. if (nextTab < 0 || nextTab >= end)
  22743. return n + (end - i);
  22744. n += nextTab - i;
  22745. n += tabSize - (n % tabSize);
  22746. i = nextTab + 1;
  22747. }
  22748. };
  22749. // The inverse of countColumn -- find the offset that corresponds to
  22750. // a particular column.
  22751. function findColumn(string, goal, tabSize) {
  22752. for (var pos = 0, col = 0;;) {
  22753. var nextTab = string.indexOf("\t", pos);
  22754. if (nextTab == -1) nextTab = string.length;
  22755. var skipped = nextTab - pos;
  22756. if (nextTab == string.length || col + skipped >= goal)
  22757. return pos + Math.min(skipped, goal - col);
  22758. col += nextTab - pos;
  22759. col += tabSize - (col % tabSize);
  22760. pos = nextTab + 1;
  22761. if (col >= goal) return pos;
  22762. }
  22763. }
  22764. var spaceStrs = [""];
  22765. function spaceStr(n) {
  22766. while (spaceStrs.length <= n)
  22767. spaceStrs.push(lst(spaceStrs) + " ");
  22768. return spaceStrs[n];
  22769. }
  22770. function lst(arr) { return arr[arr.length-1]; }
  22771. var selectInput = function(node) { node.select(); };
  22772. if (ios) // Mobile Safari apparently has a bug where select() is broken.
  22773. selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
  22774. else if (ie) // Suppress mysterious IE10 errors
  22775. selectInput = function(node) { try { node.select(); } catch(_e) {} };
  22776. function indexOf(array, elt) {
  22777. for (var i = 0; i < array.length; ++i)
  22778. if (array[i] == elt) return i;
  22779. return -1;
  22780. }
  22781. if ([].indexOf) indexOf = function(array, elt) { return array.indexOf(elt); };
  22782. function map(array, f) {
  22783. var out = [];
  22784. for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
  22785. return out;
  22786. }
  22787. if ([].map) map = function(array, f) { return array.map(f); };
  22788. function createObj(base, props) {
  22789. var inst;
  22790. if (Object.create) {
  22791. inst = Object.create(base);
  22792. } else {
  22793. var ctor = function() {};
  22794. ctor.prototype = base;
  22795. inst = new ctor();
  22796. }
  22797. if (props) copyObj(props, inst);
  22798. return inst;
  22799. };
  22800. function copyObj(obj, target, overwrite) {
  22801. if (!target) target = {};
  22802. for (var prop in obj)
  22803. if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
  22804. target[prop] = obj[prop];
  22805. return target;
  22806. }
  22807. function bind(f) {
  22808. var args = Array.prototype.slice.call(arguments, 1);
  22809. return function(){return f.apply(null, args);};
  22810. }
  22811. var nonASCIISingleCaseWordChar = /[\u00df\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
  22812. var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
  22813. return /\w/.test(ch) || ch > "\x80" &&
  22814. (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
  22815. };
  22816. function isWordChar(ch, helper) {
  22817. if (!helper) return isWordCharBasic(ch);
  22818. if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
  22819. return helper.test(ch);
  22820. }
  22821. function isEmpty(obj) {
  22822. for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
  22823. return true;
  22824. }
  22825. // Extending unicode characters. A series of a non-extending char +
  22826. // any number of extending chars is treated as a single unit as far
  22827. // as editing and measuring is concerned. This is not fully correct,
  22828. // since some scripts/fonts/browsers also treat other configurations
  22829. // of code points as a group.
  22830. var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
  22831. function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
  22832. // DOM UTILITIES
  22833. function elt(tag, content, className, style) {
  22834. var e = document.createElement(tag);
  22835. if (className) e.className = className;
  22836. if (style) e.style.cssText = style;
  22837. if (typeof content == "string") e.appendChild(document.createTextNode(content));
  22838. else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
  22839. return e;
  22840. }
  22841. var range;
  22842. if (document.createRange) range = function(node, start, end) {
  22843. var r = document.createRange();
  22844. r.setEnd(node, end);
  22845. r.setStart(node, start);
  22846. return r;
  22847. };
  22848. else range = function(node, start, end) {
  22849. var r = document.body.createTextRange();
  22850. r.moveToElementText(node.parentNode);
  22851. r.collapse(true);
  22852. r.moveEnd("character", end);
  22853. r.moveStart("character", start);
  22854. return r;
  22855. };
  22856. function removeChildren(e) {
  22857. for (var count = e.childNodes.length; count > 0; --count)
  22858. e.removeChild(e.firstChild);
  22859. return e;
  22860. }
  22861. function removeChildrenAndAdd(parent, e) {
  22862. return removeChildren(parent).appendChild(e);
  22863. }
  22864. function contains(parent, child) {
  22865. if (parent.contains)
  22866. return parent.contains(child);
  22867. while (child = child.parentNode)
  22868. if (child == parent) return true;
  22869. }
  22870. function activeElt() { return document.activeElement; }
  22871. // Older versions of IE throws unspecified error when touching
  22872. // document.activeElement in some cases (during loading, in iframe)
  22873. if (ie && ie_version < 11) activeElt = function() {
  22874. try { return document.activeElement; }
  22875. catch(e) { return document.body; }
  22876. };
  22877. function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); }
  22878. function rmClass(node, cls) {
  22879. var test = classTest(cls);
  22880. if (test.test(node.className)) node.className = node.className.replace(test, "");
  22881. }
  22882. function addClass(node, cls) {
  22883. if (!classTest(cls).test(node.className)) node.className += " " + cls;
  22884. }
  22885. function joinClasses(a, b) {
  22886. var as = a.split(" ");
  22887. for (var i = 0; i < as.length; i++)
  22888. if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
  22889. return b;
  22890. }
  22891. // WINDOW-WIDE EVENTS
  22892. // These must be handled carefully, because naively registering a
  22893. // handler for each editor will cause the editors to never be
  22894. // garbage collected.
  22895. function forEachCodeMirror(f) {
  22896. if (!document.body.getElementsByClassName) return;
  22897. var byClass = document.body.getElementsByClassName("CodeMirror");
  22898. for (var i = 0; i < byClass.length; i++) {
  22899. var cm = byClass[i].CodeMirror;
  22900. if (cm) f(cm);
  22901. }
  22902. }
  22903. var globalsRegistered = false;
  22904. function ensureGlobalHandlers() {
  22905. if (globalsRegistered) return;
  22906. registerGlobalHandlers();
  22907. globalsRegistered = true;
  22908. }
  22909. function registerGlobalHandlers() {
  22910. // When the window resizes, we need to refresh active editors.
  22911. var resizeTimer;
  22912. on(window, "resize", function() {
  22913. if (resizeTimer == null) resizeTimer = setTimeout(function() {
  22914. resizeTimer = null;
  22915. knownScrollbarWidth = null;
  22916. forEachCodeMirror(onResize);
  22917. }, 100);
  22918. });
  22919. // When the window loses focus, we want to show the editor as blurred
  22920. on(window, "blur", function() {
  22921. forEachCodeMirror(onBlur);
  22922. });
  22923. }
  22924. // FEATURE DETECTION
  22925. // Detect drag-and-drop
  22926. var dragAndDrop = function() {
  22927. // There is *some* kind of drag-and-drop support in IE6-8, but I
  22928. // couldn't get it to work yet.
  22929. if (ie && ie_version < 9) return false;
  22930. var div = elt('div');
  22931. return "draggable" in div || "dragDrop" in div;
  22932. }();
  22933. var knownScrollbarWidth;
  22934. function scrollbarWidth(measure) {
  22935. if (knownScrollbarWidth != null) return knownScrollbarWidth;
  22936. var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
  22937. removeChildrenAndAdd(measure, test);
  22938. if (test.offsetWidth)
  22939. knownScrollbarWidth = test.offsetHeight - test.clientHeight;
  22940. return knownScrollbarWidth || 0;
  22941. }
  22942. var zwspSupported;
  22943. function zeroWidthElement(measure) {
  22944. if (zwspSupported == null) {
  22945. var test = elt("span", "\u200b");
  22946. removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
  22947. if (measure.firstChild.offsetHeight != 0)
  22948. zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
  22949. }
  22950. if (zwspSupported) return elt("span", "\u200b");
  22951. else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
  22952. }
  22953. // Feature-detect IE's crummy client rect reporting for bidi text
  22954. var badBidiRects;
  22955. function hasBadBidiRects(measure) {
  22956. if (badBidiRects != null) return badBidiRects;
  22957. var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
  22958. var r0 = range(txt, 0, 1).getBoundingClientRect();
  22959. if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
  22960. var r1 = range(txt, 1, 2).getBoundingClientRect();
  22961. return badBidiRects = (r1.right - r0.right < 3);
  22962. }
  22963. // See if "".split is the broken IE version, if so, provide an
  22964. // alternative way to split lines.
  22965. var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
  22966. var pos = 0, result = [], l = string.length;
  22967. while (pos <= l) {
  22968. var nl = string.indexOf("\n", pos);
  22969. if (nl == -1) nl = string.length;
  22970. var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
  22971. var rt = line.indexOf("\r");
  22972. if (rt != -1) {
  22973. result.push(line.slice(0, rt));
  22974. pos += rt + 1;
  22975. } else {
  22976. result.push(line);
  22977. pos = nl + 1;
  22978. }
  22979. }
  22980. return result;
  22981. } : function(string){return string.split(/\r\n?|\n/);};
  22982. var hasSelection = window.getSelection ? function(te) {
  22983. try { return te.selectionStart != te.selectionEnd; }
  22984. catch(e) { return false; }
  22985. } : function(te) {
  22986. try {var range = te.ownerDocument.selection.createRange();}
  22987. catch(e) {}
  22988. if (!range || range.parentElement() != te) return false;
  22989. return range.compareEndPoints("StartToEnd", range) != 0;
  22990. };
  22991. var hasCopyEvent = (function() {
  22992. var e = elt("div");
  22993. if ("oncopy" in e) return true;
  22994. e.setAttribute("oncopy", "return;");
  22995. return typeof e.oncopy == "function";
  22996. })();
  22997. var badZoomedRects = null;
  22998. function hasBadZoomedRects(measure) {
  22999. if (badZoomedRects != null) return badZoomedRects;
  23000. var node = removeChildrenAndAdd(measure, elt("span", "x"));
  23001. var normal = node.getBoundingClientRect();
  23002. var fromRange = range(node, 0, 1).getBoundingClientRect();
  23003. return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
  23004. }
  23005. // KEY NAMES
  23006. var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
  23007. 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
  23008. 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
  23009. 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
  23010. 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
  23011. 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
  23012. 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
  23013. CodeMirror.keyNames = keyNames;
  23014. (function() {
  23015. // Number keys
  23016. for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
  23017. // Alphabetic keys
  23018. for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
  23019. // Function keys
  23020. for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
  23021. })();
  23022. // BIDI HELPERS
  23023. function iterateBidiSections(order, from, to, f) {
  23024. if (!order) return f(from, to, "ltr");
  23025. var found = false;
  23026. for (var i = 0; i < order.length; ++i) {
  23027. var part = order[i];
  23028. if (part.from < to && part.to > from || from == to && part.to == from) {
  23029. f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
  23030. found = true;
  23031. }
  23032. }
  23033. if (!found) f(from, to, "ltr");
  23034. }
  23035. function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
  23036. function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
  23037. function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
  23038. function lineRight(line) {
  23039. var order = getOrder(line);
  23040. if (!order) return line.text.length;
  23041. return bidiRight(lst(order));
  23042. }
  23043. function lineStart(cm, lineN) {
  23044. var line = getLine(cm.doc, lineN);
  23045. var visual = visualLine(line);
  23046. if (visual != line) lineN = lineNo(visual);
  23047. var order = getOrder(visual);
  23048. var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
  23049. return Pos(lineN, ch);
  23050. }
  23051. function lineEnd(cm, lineN) {
  23052. var merged, line = getLine(cm.doc, lineN);
  23053. while (merged = collapsedSpanAtEnd(line)) {
  23054. line = merged.find(1, true).line;
  23055. lineN = null;
  23056. }
  23057. var order = getOrder(line);
  23058. var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
  23059. return Pos(lineN == null ? lineNo(line) : lineN, ch);
  23060. }
  23061. function lineStartSmart(cm, pos) {
  23062. var start = lineStart(cm, pos.line);
  23063. var line = getLine(cm.doc, start.line);
  23064. var order = getOrder(line);
  23065. if (!order || order[0].level == 0) {
  23066. var firstNonWS = Math.max(0, line.text.search(/\S/));
  23067. var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
  23068. return Pos(start.line, inWS ? 0 : firstNonWS);
  23069. }
  23070. return start;
  23071. }
  23072. function compareBidiLevel(order, a, b) {
  23073. var linedir = order[0].level;
  23074. if (a == linedir) return true;
  23075. if (b == linedir) return false;
  23076. return a < b;
  23077. }
  23078. var bidiOther;
  23079. function getBidiPartAt(order, pos) {
  23080. bidiOther = null;
  23081. for (var i = 0, found; i < order.length; ++i) {
  23082. var cur = order[i];
  23083. if (cur.from < pos && cur.to > pos) return i;
  23084. if ((cur.from == pos || cur.to == pos)) {
  23085. if (found == null) {
  23086. found = i;
  23087. } else if (compareBidiLevel(order, cur.level, order[found].level)) {
  23088. if (cur.from != cur.to) bidiOther = found;
  23089. return i;
  23090. } else {
  23091. if (cur.from != cur.to) bidiOther = i;
  23092. return found;
  23093. }
  23094. }
  23095. }
  23096. return found;
  23097. }
  23098. function moveInLine(line, pos, dir, byUnit) {
  23099. if (!byUnit) return pos + dir;
  23100. do pos += dir;
  23101. while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
  23102. return pos;
  23103. }
  23104. // This is needed in order to move 'visually' through bi-directional
  23105. // text -- i.e., pressing left should make the cursor go left, even
  23106. // when in RTL text. The tricky part is the 'jumps', where RTL and
  23107. // LTR text touch each other. This often requires the cursor offset
  23108. // to move more than one unit, in order to visually move one unit.
  23109. function moveVisually(line, start, dir, byUnit) {
  23110. var bidi = getOrder(line);
  23111. if (!bidi) return moveLogically(line, start, dir, byUnit);
  23112. var pos = getBidiPartAt(bidi, start), part = bidi[pos];
  23113. var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
  23114. for (;;) {
  23115. if (target > part.from && target < part.to) return target;
  23116. if (target == part.from || target == part.to) {
  23117. if (getBidiPartAt(bidi, target) == pos) return target;
  23118. part = bidi[pos += dir];
  23119. return (dir > 0) == part.level % 2 ? part.to : part.from;
  23120. } else {
  23121. part = bidi[pos += dir];
  23122. if (!part) return null;
  23123. if ((dir > 0) == part.level % 2)
  23124. target = moveInLine(line, part.to, -1, byUnit);
  23125. else
  23126. target = moveInLine(line, part.from, 1, byUnit);
  23127. }
  23128. }
  23129. }
  23130. function moveLogically(line, start, dir, byUnit) {
  23131. var target = start + dir;
  23132. if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
  23133. return target < 0 || target > line.text.length ? null : target;
  23134. }
  23135. // Bidirectional ordering algorithm
  23136. // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
  23137. // that this (partially) implements.
  23138. // One-char codes used for character types:
  23139. // L (L): Left-to-Right
  23140. // R (R): Right-to-Left
  23141. // r (AL): Right-to-Left Arabic
  23142. // 1 (EN): European Number
  23143. // + (ES): European Number Separator
  23144. // % (ET): European Number Terminator
  23145. // n (AN): Arabic Number
  23146. // , (CS): Common Number Separator
  23147. // m (NSM): Non-Spacing Mark
  23148. // b (BN): Boundary Neutral
  23149. // s (B): Paragraph Separator
  23150. // t (S): Segment Separator
  23151. // w (WS): Whitespace
  23152. // N (ON): Other Neutrals
  23153. // Returns null if characters are ordered as they appear
  23154. // (left-to-right), or an array of sections ({from, to, level}
  23155. // objects) in the order in which they occur visually.
  23156. var bidiOrdering = (function() {
  23157. // Character types for codepoints 0 to 0xff
  23158. var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
  23159. // Character types for codepoints 0x600 to 0x6ff
  23160. var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
  23161. function charType(code) {
  23162. if (code <= 0xf7) return lowTypes.charAt(code);
  23163. else if (0x590 <= code && code <= 0x5f4) return "R";
  23164. else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
  23165. else if (0x6ee <= code && code <= 0x8ac) return "r";
  23166. else if (0x2000 <= code && code <= 0x200b) return "w";
  23167. else if (code == 0x200c) return "b";
  23168. else return "L";
  23169. }
  23170. var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
  23171. var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
  23172. // Browsers seem to always treat the boundaries of block elements as being L.
  23173. var outerType = "L";
  23174. function BidiSpan(level, from, to) {
  23175. this.level = level;
  23176. this.from = from; this.to = to;
  23177. }
  23178. return function(str) {
  23179. if (!bidiRE.test(str)) return false;
  23180. var len = str.length, types = [];
  23181. for (var i = 0, type; i < len; ++i)
  23182. types.push(type = charType(str.charCodeAt(i)));
  23183. // W1. Examine each non-spacing mark (NSM) in the level run, and
  23184. // change the type of the NSM to the type of the previous
  23185. // character. If the NSM is at the start of the level run, it will
  23186. // get the type of sor.
  23187. for (var i = 0, prev = outerType; i < len; ++i) {
  23188. var type = types[i];
  23189. if (type == "m") types[i] = prev;
  23190. else prev = type;
  23191. }
  23192. // W2. Search backwards from each instance of a European number
  23193. // until the first strong type (R, L, AL, or sor) is found. If an
  23194. // AL is found, change the type of the European number to Arabic
  23195. // number.
  23196. // W3. Change all ALs to R.
  23197. for (var i = 0, cur = outerType; i < len; ++i) {
  23198. var type = types[i];
  23199. if (type == "1" && cur == "r") types[i] = "n";
  23200. else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
  23201. }
  23202. // W4. A single European separator between two European numbers
  23203. // changes to a European number. A single common separator between
  23204. // two numbers of the same type changes to that type.
  23205. for (var i = 1, prev = types[0]; i < len - 1; ++i) {
  23206. var type = types[i];
  23207. if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
  23208. else if (type == "," && prev == types[i+1] &&
  23209. (prev == "1" || prev == "n")) types[i] = prev;
  23210. prev = type;
  23211. }
  23212. // W5. A sequence of European terminators adjacent to European
  23213. // numbers changes to all European numbers.
  23214. // W6. Otherwise, separators and terminators change to Other
  23215. // Neutral.
  23216. for (var i = 0; i < len; ++i) {
  23217. var type = types[i];
  23218. if (type == ",") types[i] = "N";
  23219. else if (type == "%") {
  23220. for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
  23221. var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
  23222. for (var j = i; j < end; ++j) types[j] = replace;
  23223. i = end - 1;
  23224. }
  23225. }
  23226. // W7. Search backwards from each instance of a European number
  23227. // until the first strong type (R, L, or sor) is found. If an L is
  23228. // found, then change the type of the European number to L.
  23229. for (var i = 0, cur = outerType; i < len; ++i) {
  23230. var type = types[i];
  23231. if (cur == "L" && type == "1") types[i] = "L";
  23232. else if (isStrong.test(type)) cur = type;
  23233. }
  23234. // N1. A sequence of neutrals takes the direction of the
  23235. // surrounding strong text if the text on both sides has the same
  23236. // direction. European and Arabic numbers act as if they were R in
  23237. // terms of their influence on neutrals. Start-of-level-run (sor)
  23238. // and end-of-level-run (eor) are used at level run boundaries.
  23239. // N2. Any remaining neutrals take the embedding direction.
  23240. for (var i = 0; i < len; ++i) {
  23241. if (isNeutral.test(types[i])) {
  23242. for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
  23243. var before = (i ? types[i-1] : outerType) == "L";
  23244. var after = (end < len ? types[end] : outerType) == "L";
  23245. var replace = before || after ? "L" : "R";
  23246. for (var j = i; j < end; ++j) types[j] = replace;
  23247. i = end - 1;
  23248. }
  23249. }
  23250. // Here we depart from the documented algorithm, in order to avoid
  23251. // building up an actual levels array. Since there are only three
  23252. // levels (0, 1, 2) in an implementation that doesn't take
  23253. // explicit embedding into account, we can build up the order on
  23254. // the fly, without following the level-based algorithm.
  23255. var order = [], m;
  23256. for (var i = 0; i < len;) {
  23257. if (countsAsLeft.test(types[i])) {
  23258. var start = i;
  23259. for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
  23260. order.push(new BidiSpan(0, start, i));
  23261. } else {
  23262. var pos = i, at = order.length;
  23263. for (++i; i < len && types[i] != "L"; ++i) {}
  23264. for (var j = pos; j < i;) {
  23265. if (countsAsNum.test(types[j])) {
  23266. if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
  23267. var nstart = j;
  23268. for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
  23269. order.splice(at, 0, new BidiSpan(2, nstart, j));
  23270. pos = j;
  23271. } else ++j;
  23272. }
  23273. if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
  23274. }
  23275. }
  23276. if (order[0].level == 1 && (m = str.match(/^\s+/))) {
  23277. order[0].from = m[0].length;
  23278. order.unshift(new BidiSpan(0, 0, m[0].length));
  23279. }
  23280. if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
  23281. lst(order).to -= m[0].length;
  23282. order.push(new BidiSpan(0, len - m[0].length, len));
  23283. }
  23284. if (order[0].level != lst(order).level)
  23285. order.push(new BidiSpan(order[0].level, len, len));
  23286. return order;
  23287. };
  23288. })();
  23289. // THE END
  23290. CodeMirror.version = "4.7.0";
  23291. return CodeMirror;
  23292. });
  23293. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  23294. // Distributed under an MIT license: http://codemirror.net/LICENSE
  23295. (function(mod) {
  23296. if (typeof exports == "object" && typeof module == "object") // CommonJS
  23297. mod(require("../../lib/codemirror"));
  23298. else if (typeof define == "function" && define.amd) // AMD
  23299. define(["../../lib/codemirror"], mod);
  23300. else // Plain browser env
  23301. mod(CodeMirror);
  23302. })(function(CodeMirror) {
  23303. "use strict";
  23304. CodeMirror.defineMode("xml", function(config, parserConfig) {
  23305. var indentUnit = config.indentUnit;
  23306. var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
  23307. var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
  23308. if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
  23309. var Kludges = parserConfig.htmlMode ? {
  23310. autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
  23311. 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
  23312. 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
  23313. 'track': true, 'wbr': true, 'menuitem': true},
  23314. implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
  23315. 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
  23316. 'th': true, 'tr': true},
  23317. contextGrabbers: {
  23318. 'dd': {'dd': true, 'dt': true},
  23319. 'dt': {'dd': true, 'dt': true},
  23320. 'li': {'li': true},
  23321. 'option': {'option': true, 'optgroup': true},
  23322. 'optgroup': {'optgroup': true},
  23323. 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
  23324. 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
  23325. 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
  23326. 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
  23327. 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
  23328. 'rp': {'rp': true, 'rt': true},
  23329. 'rt': {'rp': true, 'rt': true},
  23330. 'tbody': {'tbody': true, 'tfoot': true},
  23331. 'td': {'td': true, 'th': true},
  23332. 'tfoot': {'tbody': true},
  23333. 'th': {'td': true, 'th': true},
  23334. 'thead': {'tbody': true, 'tfoot': true},
  23335. 'tr': {'tr': true}
  23336. },
  23337. doNotIndent: {"pre": true},
  23338. allowUnquoted: true,
  23339. allowMissing: true,
  23340. caseFold: true
  23341. } : {
  23342. autoSelfClosers: {},
  23343. implicitlyClosed: {},
  23344. contextGrabbers: {},
  23345. doNotIndent: {},
  23346. allowUnquoted: false,
  23347. allowMissing: false,
  23348. caseFold: false
  23349. };
  23350. var alignCDATA = parserConfig.alignCDATA;
  23351. // Return variables for tokenizers
  23352. var type, setStyle;
  23353. function inText(stream, state) {
  23354. function chain(parser) {
  23355. state.tokenize = parser;
  23356. return parser(stream, state);
  23357. }
  23358. var ch = stream.next();
  23359. if (ch == "<") {
  23360. if (stream.eat("!")) {
  23361. if (stream.eat("[")) {
  23362. if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
  23363. else return null;
  23364. } else if (stream.match("--")) {
  23365. return chain(inBlock("comment", "-->"));
  23366. } else if (stream.match("DOCTYPE", true, true)) {
  23367. stream.eatWhile(/[\w\._\-]/);
  23368. return chain(doctype(1));
  23369. } else {
  23370. return null;
  23371. }
  23372. } else if (stream.eat("?")) {
  23373. stream.eatWhile(/[\w\._\-]/);
  23374. state.tokenize = inBlock("meta", "?>");
  23375. return "meta";
  23376. } else {
  23377. type = stream.eat("/") ? "closeTag" : "openTag";
  23378. state.tokenize = inTag;
  23379. return "tag bracket";
  23380. }
  23381. } else if (ch == "&") {
  23382. var ok;
  23383. if (stream.eat("#")) {
  23384. if (stream.eat("x")) {
  23385. ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
  23386. } else {
  23387. ok = stream.eatWhile(/[\d]/) && stream.eat(";");
  23388. }
  23389. } else {
  23390. ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
  23391. }
  23392. return ok ? "atom" : "error";
  23393. } else {
  23394. stream.eatWhile(/[^&<]/);
  23395. return null;
  23396. }
  23397. }
  23398. function inTag(stream, state) {
  23399. var ch = stream.next();
  23400. if (ch == ">" || (ch == "/" && stream.eat(">"))) {
  23401. state.tokenize = inText;
  23402. type = ch == ">" ? "endTag" : "selfcloseTag";
  23403. return "tag bracket";
  23404. } else if (ch == "=") {
  23405. type = "equals";
  23406. return null;
  23407. } else if (ch == "<") {
  23408. state.tokenize = inText;
  23409. state.state = baseState;
  23410. state.tagName = state.tagStart = null;
  23411. var next = state.tokenize(stream, state);
  23412. return next ? next + " tag error" : "tag error";
  23413. } else if (/[\'\"]/.test(ch)) {
  23414. state.tokenize = inAttribute(ch);
  23415. state.stringStartCol = stream.column();
  23416. return state.tokenize(stream, state);
  23417. } else {
  23418. stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
  23419. return "word";
  23420. }
  23421. }
  23422. function inAttribute(quote) {
  23423. var closure = function(stream, state) {
  23424. while (!stream.eol()) {
  23425. if (stream.next() == quote) {
  23426. state.tokenize = inTag;
  23427. break;
  23428. }
  23429. }
  23430. return "string";
  23431. };
  23432. closure.isInAttribute = true;
  23433. return closure;
  23434. }
  23435. function inBlock(style, terminator) {
  23436. return function(stream, state) {
  23437. while (!stream.eol()) {
  23438. if (stream.match(terminator)) {
  23439. state.tokenize = inText;
  23440. break;
  23441. }
  23442. stream.next();
  23443. }
  23444. return style;
  23445. };
  23446. }
  23447. function doctype(depth) {
  23448. return function(stream, state) {
  23449. var ch;
  23450. while ((ch = stream.next()) != null) {
  23451. if (ch == "<") {
  23452. state.tokenize = doctype(depth + 1);
  23453. return state.tokenize(stream, state);
  23454. } else if (ch == ">") {
  23455. if (depth == 1) {
  23456. state.tokenize = inText;
  23457. break;
  23458. } else {
  23459. state.tokenize = doctype(depth - 1);
  23460. return state.tokenize(stream, state);
  23461. }
  23462. }
  23463. }
  23464. return "meta";
  23465. };
  23466. }
  23467. function Context(state, tagName, startOfLine) {
  23468. this.prev = state.context;
  23469. this.tagName = tagName;
  23470. this.indent = state.indented;
  23471. this.startOfLine = startOfLine;
  23472. if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
  23473. this.noIndent = true;
  23474. }
  23475. function popContext(state) {
  23476. if (state.context) state.context = state.context.prev;
  23477. }
  23478. function maybePopContext(state, nextTagName) {
  23479. var parentTagName;
  23480. while (true) {
  23481. if (!state.context) {
  23482. return;
  23483. }
  23484. parentTagName = state.context.tagName;
  23485. if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
  23486. !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
  23487. return;
  23488. }
  23489. popContext(state);
  23490. }
  23491. }
  23492. function baseState(type, stream, state) {
  23493. if (type == "openTag") {
  23494. state.tagStart = stream.column();
  23495. return tagNameState;
  23496. } else if (type == "closeTag") {
  23497. return closeTagNameState;
  23498. } else {
  23499. return baseState;
  23500. }
  23501. }
  23502. function tagNameState(type, stream, state) {
  23503. if (type == "word") {
  23504. state.tagName = stream.current();
  23505. setStyle = "tag";
  23506. return attrState;
  23507. } else {
  23508. setStyle = "error";
  23509. return tagNameState;
  23510. }
  23511. }
  23512. function closeTagNameState(type, stream, state) {
  23513. if (type == "word") {
  23514. var tagName = stream.current();
  23515. if (state.context && state.context.tagName != tagName &&
  23516. Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
  23517. popContext(state);
  23518. if (state.context && state.context.tagName == tagName) {
  23519. setStyle = "tag";
  23520. return closeState;
  23521. } else {
  23522. setStyle = "tag error";
  23523. return closeStateErr;
  23524. }
  23525. } else {
  23526. setStyle = "error";
  23527. return closeStateErr;
  23528. }
  23529. }
  23530. function closeState(type, _stream, state) {
  23531. if (type != "endTag") {
  23532. setStyle = "error";
  23533. return closeState;
  23534. }
  23535. popContext(state);
  23536. return baseState;
  23537. }
  23538. function closeStateErr(type, stream, state) {
  23539. setStyle = "error";
  23540. return closeState(type, stream, state);
  23541. }
  23542. function attrState(type, _stream, state) {
  23543. if (type == "word") {
  23544. setStyle = "attribute";
  23545. return attrEqState;
  23546. } else if (type == "endTag" || type == "selfcloseTag") {
  23547. var tagName = state.tagName, tagStart = state.tagStart;
  23548. state.tagName = state.tagStart = null;
  23549. if (type == "selfcloseTag" ||
  23550. Kludges.autoSelfClosers.hasOwnProperty(tagName)) {
  23551. maybePopContext(state, tagName);
  23552. } else {
  23553. maybePopContext(state, tagName);
  23554. state.context = new Context(state, tagName, tagStart == state.indented);
  23555. }
  23556. return baseState;
  23557. }
  23558. setStyle = "error";
  23559. return attrState;
  23560. }
  23561. function attrEqState(type, stream, state) {
  23562. if (type == "equals") return attrValueState;
  23563. if (!Kludges.allowMissing) setStyle = "error";
  23564. return attrState(type, stream, state);
  23565. }
  23566. function attrValueState(type, stream, state) {
  23567. if (type == "string") return attrContinuedState;
  23568. if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
  23569. setStyle = "error";
  23570. return attrState(type, stream, state);
  23571. }
  23572. function attrContinuedState(type, stream, state) {
  23573. if (type == "string") return attrContinuedState;
  23574. return attrState(type, stream, state);
  23575. }
  23576. return {
  23577. startState: function() {
  23578. return {tokenize: inText,
  23579. state: baseState,
  23580. indented: 0,
  23581. tagName: null, tagStart: null,
  23582. context: null};
  23583. },
  23584. token: function(stream, state) {
  23585. if (!state.tagName && stream.sol())
  23586. state.indented = stream.indentation();
  23587. if (stream.eatSpace()) return null;
  23588. type = null;
  23589. var style = state.tokenize(stream, state);
  23590. if ((style || type) && style != "comment") {
  23591. setStyle = null;
  23592. state.state = state.state(type || style, stream, state);
  23593. if (setStyle)
  23594. style = setStyle == "error" ? style + " error" : setStyle;
  23595. }
  23596. return style;
  23597. },
  23598. indent: function(state, textAfter, fullLine) {
  23599. var context = state.context;
  23600. // Indent multi-line strings (e.g. css).
  23601. if (state.tokenize.isInAttribute) {
  23602. if (state.tagStart == state.indented)
  23603. return state.stringStartCol + 1;
  23604. else
  23605. return state.indented + indentUnit;
  23606. }
  23607. if (context && context.noIndent) return CodeMirror.Pass;
  23608. if (state.tokenize != inTag && state.tokenize != inText)
  23609. return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
  23610. // Indent the starts of attribute names.
  23611. if (state.tagName) {
  23612. if (multilineTagIndentPastTag)
  23613. return state.tagStart + state.tagName.length + 2;
  23614. else
  23615. return state.tagStart + indentUnit * multilineTagIndentFactor;
  23616. }
  23617. if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
  23618. var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
  23619. if (tagAfter && tagAfter[1]) { // Closing tag spotted
  23620. while (context) {
  23621. if (context.tagName == tagAfter[2]) {
  23622. context = context.prev;
  23623. break;
  23624. } else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
  23625. context = context.prev;
  23626. } else {
  23627. break;
  23628. }
  23629. }
  23630. } else if (tagAfter) { // Opening tag spotted
  23631. while (context) {
  23632. var grabbers = Kludges.contextGrabbers[context.tagName];
  23633. if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
  23634. context = context.prev;
  23635. else
  23636. break;
  23637. }
  23638. }
  23639. while (context && !context.startOfLine)
  23640. context = context.prev;
  23641. if (context) return context.indent + indentUnit;
  23642. else return 0;
  23643. },
  23644. electricInput: /<\/[\s\w:]+>$/,
  23645. blockCommentStart: "<!--",
  23646. blockCommentEnd: "-->",
  23647. configuration: parserConfig.htmlMode ? "html" : "xml",
  23648. helperType: parserConfig.htmlMode ? "html" : "xml"
  23649. };
  23650. });
  23651. CodeMirror.defineMIME("text/xml", "xml");
  23652. CodeMirror.defineMIME("application/xml", "xml");
  23653. if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
  23654. CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
  23655. });
  23656. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  23657. // Distributed under an MIT license: http://codemirror.net/LICENSE
  23658. // TODO actually recognize syntax of TypeScript constructs
  23659. (function(mod) {
  23660. if (typeof exports == "object" && typeof module == "object") // CommonJS
  23661. mod(require("../../lib/codemirror"));
  23662. else if (typeof define == "function" && define.amd) // AMD
  23663. define(["../../lib/codemirror"], mod);
  23664. else // Plain browser env
  23665. mod(CodeMirror);
  23666. })(function(CodeMirror) {
  23667. "use strict";
  23668. CodeMirror.defineMode("javascript", function(config, parserConfig) {
  23669. var indentUnit = config.indentUnit;
  23670. var statementIndent = parserConfig.statementIndent;
  23671. var jsonldMode = parserConfig.jsonld;
  23672. var jsonMode = parserConfig.json || jsonldMode;
  23673. var isTS = parserConfig.typescript;
  23674. var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
  23675. // Tokenizer
  23676. var keywords = function(){
  23677. function kw(type) {return {type: type, style: "keyword"};}
  23678. var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
  23679. var operator = kw("operator"), atom = {type: "atom", style: "atom"};
  23680. var jsKeywords = {
  23681. "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
  23682. "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
  23683. "var": kw("var"), "const": kw("var"), "let": kw("var"),
  23684. "function": kw("function"), "catch": kw("catch"),
  23685. "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
  23686. "in": operator, "typeof": operator, "instanceof": operator,
  23687. "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
  23688. "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
  23689. "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
  23690. };
  23691. // Extend the 'normal' keywords with the TypeScript language extensions
  23692. if (isTS) {
  23693. var type = {type: "variable", style: "variable-3"};
  23694. var tsKeywords = {
  23695. // object-like things
  23696. "interface": kw("interface"),
  23697. "extends": kw("extends"),
  23698. "constructor": kw("constructor"),
  23699. // scope modifiers
  23700. "public": kw("public"),
  23701. "private": kw("private"),
  23702. "protected": kw("protected"),
  23703. "static": kw("static"),
  23704. // types
  23705. "string": type, "number": type, "bool": type, "any": type
  23706. };
  23707. for (var attr in tsKeywords) {
  23708. jsKeywords[attr] = tsKeywords[attr];
  23709. }
  23710. }
  23711. return jsKeywords;
  23712. }();
  23713. var isOperatorChar = /[+\-*&%=<>!?|~^]/;
  23714. var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
  23715. function readRegexp(stream) {
  23716. var escaped = false, next, inSet = false;
  23717. while ((next = stream.next()) != null) {
  23718. if (!escaped) {
  23719. if (next == "/" && !inSet) return;
  23720. if (next == "[") inSet = true;
  23721. else if (inSet && next == "]") inSet = false;
  23722. }
  23723. escaped = !escaped && next == "\\";
  23724. }
  23725. }
  23726. // Used as scratch variables to communicate multiple values without
  23727. // consing up tons of objects.
  23728. var type, content;
  23729. function ret(tp, style, cont) {
  23730. type = tp; content = cont;
  23731. return style;
  23732. }
  23733. function tokenBase(stream, state) {
  23734. var ch = stream.next();
  23735. if (ch == '"' || ch == "'") {
  23736. state.tokenize = tokenString(ch);
  23737. return state.tokenize(stream, state);
  23738. } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
  23739. return ret("number", "number");
  23740. } else if (ch == "." && stream.match("..")) {
  23741. return ret("spread", "meta");
  23742. } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
  23743. return ret(ch);
  23744. } else if (ch == "=" && stream.eat(">")) {
  23745. return ret("=>", "operator");
  23746. } else if (ch == "0" && stream.eat(/x/i)) {
  23747. stream.eatWhile(/[\da-f]/i);
  23748. return ret("number", "number");
  23749. } else if (/\d/.test(ch)) {
  23750. stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
  23751. return ret("number", "number");
  23752. } else if (ch == "/") {
  23753. if (stream.eat("*")) {
  23754. state.tokenize = tokenComment;
  23755. return tokenComment(stream, state);
  23756. } else if (stream.eat("/")) {
  23757. stream.skipToEnd();
  23758. return ret("comment", "comment");
  23759. } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
  23760. state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
  23761. readRegexp(stream);
  23762. stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
  23763. return ret("regexp", "string-2");
  23764. } else {
  23765. stream.eatWhile(isOperatorChar);
  23766. return ret("operator", "operator", stream.current());
  23767. }
  23768. } else if (ch == "`") {
  23769. state.tokenize = tokenQuasi;
  23770. return tokenQuasi(stream, state);
  23771. } else if (ch == "#") {
  23772. stream.skipToEnd();
  23773. return ret("error", "error");
  23774. } else if (isOperatorChar.test(ch)) {
  23775. stream.eatWhile(isOperatorChar);
  23776. return ret("operator", "operator", stream.current());
  23777. } else if (wordRE.test(ch)) {
  23778. stream.eatWhile(wordRE);
  23779. var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
  23780. return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
  23781. ret("variable", "variable", word);
  23782. }
  23783. }
  23784. function tokenString(quote) {
  23785. return function(stream, state) {
  23786. var escaped = false, next;
  23787. if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
  23788. state.tokenize = tokenBase;
  23789. return ret("jsonld-keyword", "meta");
  23790. }
  23791. while ((next = stream.next()) != null) {
  23792. if (next == quote && !escaped) break;
  23793. escaped = !escaped && next == "\\";
  23794. }
  23795. if (!escaped) state.tokenize = tokenBase;
  23796. return ret("string", "string");
  23797. };
  23798. }
  23799. function tokenComment(stream, state) {
  23800. var maybeEnd = false, ch;
  23801. while (ch = stream.next()) {
  23802. if (ch == "/" && maybeEnd) {
  23803. state.tokenize = tokenBase;
  23804. break;
  23805. }
  23806. maybeEnd = (ch == "*");
  23807. }
  23808. return ret("comment", "comment");
  23809. }
  23810. function tokenQuasi(stream, state) {
  23811. var escaped = false, next;
  23812. while ((next = stream.next()) != null) {
  23813. if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
  23814. state.tokenize = tokenBase;
  23815. break;
  23816. }
  23817. escaped = !escaped && next == "\\";
  23818. }
  23819. return ret("quasi", "string-2", stream.current());
  23820. }
  23821. var brackets = "([{}])";
  23822. // This is a crude lookahead trick to try and notice that we're
  23823. // parsing the argument patterns for a fat-arrow function before we
  23824. // actually hit the arrow token. It only works if the arrow is on
  23825. // the same line as the arguments and there's no strange noise
  23826. // (comments) in between. Fallback is to only notice when we hit the
  23827. // arrow, and not declare the arguments as locals for the arrow
  23828. // body.
  23829. function findFatArrow(stream, state) {
  23830. if (state.fatArrowAt) state.fatArrowAt = null;
  23831. var arrow = stream.string.indexOf("=>", stream.start);
  23832. if (arrow < 0) return;
  23833. var depth = 0, sawSomething = false;
  23834. for (var pos = arrow - 1; pos >= 0; --pos) {
  23835. var ch = stream.string.charAt(pos);
  23836. var bracket = brackets.indexOf(ch);
  23837. if (bracket >= 0 && bracket < 3) {
  23838. if (!depth) { ++pos; break; }
  23839. if (--depth == 0) break;
  23840. } else if (bracket >= 3 && bracket < 6) {
  23841. ++depth;
  23842. } else if (wordRE.test(ch)) {
  23843. sawSomething = true;
  23844. } else if (sawSomething && !depth) {
  23845. ++pos;
  23846. break;
  23847. }
  23848. }
  23849. if (sawSomething && !depth) state.fatArrowAt = pos;
  23850. }
  23851. // Parser
  23852. var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
  23853. function JSLexical(indented, column, type, align, prev, info) {
  23854. this.indented = indented;
  23855. this.column = column;
  23856. this.type = type;
  23857. this.prev = prev;
  23858. this.info = info;
  23859. if (align != null) this.align = align;
  23860. }
  23861. function inScope(state, varname) {
  23862. for (var v = state.localVars; v; v = v.next)
  23863. if (v.name == varname) return true;
  23864. for (var cx = state.context; cx; cx = cx.prev) {
  23865. for (var v = cx.vars; v; v = v.next)
  23866. if (v.name == varname) return true;
  23867. }
  23868. }
  23869. function parseJS(state, style, type, content, stream) {
  23870. var cc = state.cc;
  23871. // Communicate our context to the combinators.
  23872. // (Less wasteful than consing up a hundred closures on every call.)
  23873. cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
  23874. if (!state.lexical.hasOwnProperty("align"))
  23875. state.lexical.align = true;
  23876. while(true) {
  23877. var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
  23878. if (combinator(type, content)) {
  23879. while(cc.length && cc[cc.length - 1].lex)
  23880. cc.pop()();
  23881. if (cx.marked) return cx.marked;
  23882. if (type == "variable" && inScope(state, content)) return "variable-2";
  23883. return style;
  23884. }
  23885. }
  23886. }
  23887. // Combinator utils
  23888. var cx = {state: null, column: null, marked: null, cc: null};
  23889. function pass() {
  23890. for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
  23891. }
  23892. function cont() {
  23893. pass.apply(null, arguments);
  23894. return true;
  23895. }
  23896. function register(varname) {
  23897. function inList(list) {
  23898. for (var v = list; v; v = v.next)
  23899. if (v.name == varname) return true;
  23900. return false;
  23901. }
  23902. var state = cx.state;
  23903. if (state.context) {
  23904. cx.marked = "def";
  23905. if (inList(state.localVars)) return;
  23906. state.localVars = {name: varname, next: state.localVars};
  23907. } else {
  23908. if (inList(state.globalVars)) return;
  23909. if (parserConfig.globalVars)
  23910. state.globalVars = {name: varname, next: state.globalVars};
  23911. }
  23912. }
  23913. // Combinators
  23914. var defaultVars = {name: "this", next: {name: "arguments"}};
  23915. function pushcontext() {
  23916. cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
  23917. cx.state.localVars = defaultVars;
  23918. }
  23919. function popcontext() {
  23920. cx.state.localVars = cx.state.context.vars;
  23921. cx.state.context = cx.state.context.prev;
  23922. }
  23923. function pushlex(type, info) {
  23924. var result = function() {
  23925. var state = cx.state, indent = state.indented;
  23926. if (state.lexical.type == "stat") indent = state.lexical.indented;
  23927. else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
  23928. indent = outer.indented;
  23929. state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
  23930. };
  23931. result.lex = true;
  23932. return result;
  23933. }
  23934. function poplex() {
  23935. var state = cx.state;
  23936. if (state.lexical.prev) {
  23937. if (state.lexical.type == ")")
  23938. state.indented = state.lexical.indented;
  23939. state.lexical = state.lexical.prev;
  23940. }
  23941. }
  23942. poplex.lex = true;
  23943. function expect(wanted) {
  23944. function exp(type) {
  23945. if (type == wanted) return cont();
  23946. else if (wanted == ";") return pass();
  23947. else return cont(exp);
  23948. };
  23949. return exp;
  23950. }
  23951. function statement(type, value) {
  23952. if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
  23953. if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
  23954. if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
  23955. if (type == "{") return cont(pushlex("}"), block, poplex);
  23956. if (type == ";") return cont();
  23957. if (type == "if") {
  23958. if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
  23959. cx.state.cc.pop()();
  23960. return cont(pushlex("form"), expression, statement, poplex, maybeelse);
  23961. }
  23962. if (type == "function") return cont(functiondef);
  23963. if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
  23964. if (type == "variable") return cont(pushlex("stat"), maybelabel);
  23965. if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
  23966. block, poplex, poplex);
  23967. if (type == "case") return cont(expression, expect(":"));
  23968. if (type == "default") return cont(expect(":"));
  23969. if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
  23970. statement, poplex, popcontext);
  23971. if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
  23972. if (type == "class") return cont(pushlex("form"), className, poplex);
  23973. if (type == "export") return cont(pushlex("form"), afterExport, poplex);
  23974. if (type == "import") return cont(pushlex("form"), afterImport, poplex);
  23975. return pass(pushlex("stat"), expression, expect(";"), poplex);
  23976. }
  23977. function expression(type) {
  23978. return expressionInner(type, false);
  23979. }
  23980. function expressionNoComma(type) {
  23981. return expressionInner(type, true);
  23982. }
  23983. function expressionInner(type, noComma) {
  23984. if (cx.state.fatArrowAt == cx.stream.start) {
  23985. var body = noComma ? arrowBodyNoComma : arrowBody;
  23986. if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
  23987. else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
  23988. }
  23989. var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
  23990. if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
  23991. if (type == "function") return cont(functiondef, maybeop);
  23992. if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
  23993. if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
  23994. if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
  23995. if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
  23996. if (type == "{") return contCommasep(objprop, "}", null, maybeop);
  23997. if (type == "quasi") { return pass(quasi, maybeop); }
  23998. return cont();
  23999. }
  24000. function maybeexpression(type) {
  24001. if (type.match(/[;\}\)\],]/)) return pass();
  24002. return pass(expression);
  24003. }
  24004. function maybeexpressionNoComma(type) {
  24005. if (type.match(/[;\}\)\],]/)) return pass();
  24006. return pass(expressionNoComma);
  24007. }
  24008. function maybeoperatorComma(type, value) {
  24009. if (type == ",") return cont(expression);
  24010. return maybeoperatorNoComma(type, value, false);
  24011. }
  24012. function maybeoperatorNoComma(type, value, noComma) {
  24013. var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
  24014. var expr = noComma == false ? expression : expressionNoComma;
  24015. if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
  24016. if (type == "operator") {
  24017. if (/\+\+|--/.test(value)) return cont(me);
  24018. if (value == "?") return cont(expression, expect(":"), expr);
  24019. return cont(expr);
  24020. }
  24021. if (type == "quasi") { return pass(quasi, me); }
  24022. if (type == ";") return;
  24023. if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
  24024. if (type == ".") return cont(property, me);
  24025. if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
  24026. }
  24027. function quasi(type, value) {
  24028. if (type != "quasi") return pass();
  24029. if (value.slice(value.length - 2) != "${") return cont(quasi);
  24030. return cont(expression, continueQuasi);
  24031. }
  24032. function continueQuasi(type) {
  24033. if (type == "}") {
  24034. cx.marked = "string-2";
  24035. cx.state.tokenize = tokenQuasi;
  24036. return cont(quasi);
  24037. }
  24038. }
  24039. function arrowBody(type) {
  24040. findFatArrow(cx.stream, cx.state);
  24041. return pass(type == "{" ? statement : expression);
  24042. }
  24043. function arrowBodyNoComma(type) {
  24044. findFatArrow(cx.stream, cx.state);
  24045. return pass(type == "{" ? statement : expressionNoComma);
  24046. }
  24047. function maybelabel(type) {
  24048. if (type == ":") return cont(poplex, statement);
  24049. return pass(maybeoperatorComma, expect(";"), poplex);
  24050. }
  24051. function property(type) {
  24052. if (type == "variable") {cx.marked = "property"; return cont();}
  24053. }
  24054. function objprop(type, value) {
  24055. if (type == "variable" || cx.style == "keyword") {
  24056. cx.marked = "property";
  24057. if (value == "get" || value == "set") return cont(getterSetter);
  24058. return cont(afterprop);
  24059. } else if (type == "number" || type == "string") {
  24060. cx.marked = jsonldMode ? "property" : (cx.style + " property");
  24061. return cont(afterprop);
  24062. } else if (type == "jsonld-keyword") {
  24063. return cont(afterprop);
  24064. } else if (type == "[") {
  24065. return cont(expression, expect("]"), afterprop);
  24066. }
  24067. }
  24068. function getterSetter(type) {
  24069. if (type != "variable") return pass(afterprop);
  24070. cx.marked = "property";
  24071. return cont(functiondef);
  24072. }
  24073. function afterprop(type) {
  24074. if (type == ":") return cont(expressionNoComma);
  24075. if (type == "(") return pass(functiondef);
  24076. }
  24077. function commasep(what, end) {
  24078. function proceed(type) {
  24079. if (type == ",") {
  24080. var lex = cx.state.lexical;
  24081. if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
  24082. return cont(what, proceed);
  24083. }
  24084. if (type == end) return cont();
  24085. return cont(expect(end));
  24086. }
  24087. return function(type) {
  24088. if (type == end) return cont();
  24089. return pass(what, proceed);
  24090. };
  24091. }
  24092. function contCommasep(what, end, info) {
  24093. for (var i = 3; i < arguments.length; i++)
  24094. cx.cc.push(arguments[i]);
  24095. return cont(pushlex(end, info), commasep(what, end), poplex);
  24096. }
  24097. function block(type) {
  24098. if (type == "}") return cont();
  24099. return pass(statement, block);
  24100. }
  24101. function maybetype(type) {
  24102. if (isTS && type == ":") return cont(typedef);
  24103. }
  24104. function typedef(type) {
  24105. if (type == "variable"){cx.marked = "variable-3"; return cont();}
  24106. }
  24107. function vardef() {
  24108. return pass(pattern, maybetype, maybeAssign, vardefCont);
  24109. }
  24110. function pattern(type, value) {
  24111. if (type == "variable") { register(value); return cont(); }
  24112. if (type == "[") return contCommasep(pattern, "]");
  24113. if (type == "{") return contCommasep(proppattern, "}");
  24114. }
  24115. function proppattern(type, value) {
  24116. if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
  24117. register(value);
  24118. return cont(maybeAssign);
  24119. }
  24120. if (type == "variable") cx.marked = "property";
  24121. return cont(expect(":"), pattern, maybeAssign);
  24122. }
  24123. function maybeAssign(_type, value) {
  24124. if (value == "=") return cont(expressionNoComma);
  24125. }
  24126. function vardefCont(type) {
  24127. if (type == ",") return cont(vardef);
  24128. }
  24129. function maybeelse(type, value) {
  24130. if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
  24131. }
  24132. function forspec(type) {
  24133. if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
  24134. }
  24135. function forspec1(type) {
  24136. if (type == "var") return cont(vardef, expect(";"), forspec2);
  24137. if (type == ";") return cont(forspec2);
  24138. if (type == "variable") return cont(formaybeinof);
  24139. return pass(expression, expect(";"), forspec2);
  24140. }
  24141. function formaybeinof(_type, value) {
  24142. if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
  24143. return cont(maybeoperatorComma, forspec2);
  24144. }
  24145. function forspec2(type, value) {
  24146. if (type == ";") return cont(forspec3);
  24147. if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
  24148. return pass(expression, expect(";"), forspec3);
  24149. }
  24150. function forspec3(type) {
  24151. if (type != ")") cont(expression);
  24152. }
  24153. function functiondef(type, value) {
  24154. if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
  24155. if (type == "variable") {register(value); return cont(functiondef);}
  24156. if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
  24157. }
  24158. function funarg(type) {
  24159. if (type == "spread") return cont(funarg);
  24160. return pass(pattern, maybetype);
  24161. }
  24162. function className(type, value) {
  24163. if (type == "variable") {register(value); return cont(classNameAfter);}
  24164. }
  24165. function classNameAfter(type, value) {
  24166. if (value == "extends") return cont(expression, classNameAfter);
  24167. if (type == "{") return cont(pushlex("}"), classBody, poplex);
  24168. }
  24169. function classBody(type, value) {
  24170. if (type == "variable" || cx.style == "keyword") {
  24171. cx.marked = "property";
  24172. if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
  24173. return cont(functiondef, classBody);
  24174. }
  24175. if (value == "*") {
  24176. cx.marked = "keyword";
  24177. return cont(classBody);
  24178. }
  24179. if (type == ";") return cont(classBody);
  24180. if (type == "}") return cont();
  24181. }
  24182. function classGetterSetter(type) {
  24183. if (type != "variable") return pass();
  24184. cx.marked = "property";
  24185. return cont();
  24186. }
  24187. function afterModule(type, value) {
  24188. if (type == "string") return cont(statement);
  24189. if (type == "variable") { register(value); return cont(maybeFrom); }
  24190. }
  24191. function afterExport(_type, value) {
  24192. if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
  24193. if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
  24194. return pass(statement);
  24195. }
  24196. function afterImport(type) {
  24197. if (type == "string") return cont();
  24198. return pass(importSpec, maybeFrom);
  24199. }
  24200. function importSpec(type, value) {
  24201. if (type == "{") return contCommasep(importSpec, "}");
  24202. if (type == "variable") register(value);
  24203. return cont();
  24204. }
  24205. function maybeFrom(_type, value) {
  24206. if (value == "from") { cx.marked = "keyword"; return cont(expression); }
  24207. }
  24208. function arrayLiteral(type) {
  24209. if (type == "]") return cont();
  24210. return pass(expressionNoComma, maybeArrayComprehension);
  24211. }
  24212. function maybeArrayComprehension(type) {
  24213. if (type == "for") return pass(comprehension, expect("]"));
  24214. if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
  24215. return pass(commasep(expressionNoComma, "]"));
  24216. }
  24217. function comprehension(type) {
  24218. if (type == "for") return cont(forspec, comprehension);
  24219. if (type == "if") return cont(expression, comprehension);
  24220. }
  24221. // Interface
  24222. return {
  24223. startState: function(basecolumn) {
  24224. var state = {
  24225. tokenize: tokenBase,
  24226. lastType: "sof",
  24227. cc: [],
  24228. lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
  24229. localVars: parserConfig.localVars,
  24230. context: parserConfig.localVars && {vars: parserConfig.localVars},
  24231. indented: 0
  24232. };
  24233. if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
  24234. state.globalVars = parserConfig.globalVars;
  24235. return state;
  24236. },
  24237. token: function(stream, state) {
  24238. if (stream.sol()) {
  24239. if (!state.lexical.hasOwnProperty("align"))
  24240. state.lexical.align = false;
  24241. state.indented = stream.indentation();
  24242. findFatArrow(stream, state);
  24243. }
  24244. if (state.tokenize != tokenComment && stream.eatSpace()) return null;
  24245. var style = state.tokenize(stream, state);
  24246. if (type == "comment") return style;
  24247. state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
  24248. return parseJS(state, style, type, content, stream);
  24249. },
  24250. indent: function(state, textAfter) {
  24251. if (state.tokenize == tokenComment) return CodeMirror.Pass;
  24252. if (state.tokenize != tokenBase) return 0;
  24253. var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
  24254. // Kludge to prevent 'maybelse' from blocking lexical scope pops
  24255. if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
  24256. var c = state.cc[i];
  24257. if (c == poplex) lexical = lexical.prev;
  24258. else if (c != maybeelse) break;
  24259. }
  24260. if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
  24261. if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
  24262. lexical = lexical.prev;
  24263. var type = lexical.type, closing = firstChar == type;
  24264. if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
  24265. else if (type == "form" && firstChar == "{") return lexical.indented;
  24266. else if (type == "form") return lexical.indented + indentUnit;
  24267. else if (type == "stat")
  24268. return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
  24269. else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
  24270. return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
  24271. else if (lexical.align) return lexical.column + (closing ? 0 : 1);
  24272. else return lexical.indented + (closing ? 0 : indentUnit);
  24273. },
  24274. electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
  24275. blockCommentStart: jsonMode ? null : "/*",
  24276. blockCommentEnd: jsonMode ? null : "*/",
  24277. lineComment: jsonMode ? null : "//",
  24278. fold: "brace",
  24279. helperType: jsonMode ? "json" : "javascript",
  24280. jsonldMode: jsonldMode,
  24281. jsonMode: jsonMode
  24282. };
  24283. });
  24284. CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
  24285. CodeMirror.defineMIME("text/javascript", "javascript");
  24286. CodeMirror.defineMIME("text/ecmascript", "javascript");
  24287. CodeMirror.defineMIME("application/javascript", "javascript");
  24288. CodeMirror.defineMIME("application/x-javascript", "javascript");
  24289. CodeMirror.defineMIME("application/ecmascript", "javascript");
  24290. CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
  24291. CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
  24292. CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
  24293. CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
  24294. CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
  24295. });
  24296. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  24297. // Distributed under an MIT license: http://codemirror.net/LICENSE
  24298. (function(mod) {
  24299. if (typeof exports == "object" && typeof module == "object") // CommonJS
  24300. mod(require("../../lib/codemirror"));
  24301. else if (typeof define == "function" && define.amd) // AMD
  24302. define(["../../lib/codemirror"], mod);
  24303. else // Plain browser env
  24304. mod(CodeMirror);
  24305. })(function(CodeMirror) {
  24306. "use strict";
  24307. CodeMirror.defineMode("css", function(config, parserConfig) {
  24308. if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
  24309. var indentUnit = config.indentUnit,
  24310. tokenHooks = parserConfig.tokenHooks,
  24311. mediaTypes = parserConfig.mediaTypes || {},
  24312. mediaFeatures = parserConfig.mediaFeatures || {},
  24313. propertyKeywords = parserConfig.propertyKeywords || {},
  24314. nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
  24315. colorKeywords = parserConfig.colorKeywords || {},
  24316. valueKeywords = parserConfig.valueKeywords || {},
  24317. fontProperties = parserConfig.fontProperties || {},
  24318. allowNested = parserConfig.allowNested;
  24319. var type, override;
  24320. function ret(style, tp) { type = tp; return style; }
  24321. // Tokenizers
  24322. function tokenBase(stream, state) {
  24323. var ch = stream.next();
  24324. if (tokenHooks[ch]) {
  24325. var result = tokenHooks[ch](stream, state);
  24326. if (result !== false) return result;
  24327. }
  24328. if (ch == "@") {
  24329. stream.eatWhile(/[\w\\\-]/);
  24330. return ret("def", stream.current());
  24331. } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
  24332. return ret(null, "compare");
  24333. } else if (ch == "\"" || ch == "'") {
  24334. state.tokenize = tokenString(ch);
  24335. return state.tokenize(stream, state);
  24336. } else if (ch == "#") {
  24337. stream.eatWhile(/[\w\\\-]/);
  24338. return ret("atom", "hash");
  24339. } else if (ch == "!") {
  24340. stream.match(/^\s*\w*/);
  24341. return ret("keyword", "important");
  24342. } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
  24343. stream.eatWhile(/[\w.%]/);
  24344. return ret("number", "unit");
  24345. } else if (ch === "-") {
  24346. if (/[\d.]/.test(stream.peek())) {
  24347. stream.eatWhile(/[\w.%]/);
  24348. return ret("number", "unit");
  24349. } else if (stream.match(/^\w+-/)) {
  24350. return ret("meta", "meta");
  24351. }
  24352. } else if (/[,+>*\/]/.test(ch)) {
  24353. return ret(null, "select-op");
  24354. } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
  24355. return ret("qualifier", "qualifier");
  24356. } else if (/[:;{}\[\]\(\)]/.test(ch)) {
  24357. return ret(null, ch);
  24358. } else if (ch == "u" && stream.match("rl(")) {
  24359. stream.backUp(1);
  24360. state.tokenize = tokenParenthesized;
  24361. return ret("property", "word");
  24362. } else if (/[\w\\\-]/.test(ch)) {
  24363. stream.eatWhile(/[\w\\\-]/);
  24364. return ret("property", "word");
  24365. } else {
  24366. return ret(null, null);
  24367. }
  24368. }
  24369. function tokenString(quote) {
  24370. return function(stream, state) {
  24371. var escaped = false, ch;
  24372. while ((ch = stream.next()) != null) {
  24373. if (ch == quote && !escaped) {
  24374. if (quote == ")") stream.backUp(1);
  24375. break;
  24376. }
  24377. escaped = !escaped && ch == "\\";
  24378. }
  24379. if (ch == quote || !escaped && quote != ")") state.tokenize = null;
  24380. return ret("string", "string");
  24381. };
  24382. }
  24383. function tokenParenthesized(stream, state) {
  24384. stream.next(); // Must be '('
  24385. if (!stream.match(/\s*[\"\')]/, false))
  24386. state.tokenize = tokenString(")");
  24387. else
  24388. state.tokenize = null;
  24389. return ret(null, "(");
  24390. }
  24391. // Context management
  24392. function Context(type, indent, prev) {
  24393. this.type = type;
  24394. this.indent = indent;
  24395. this.prev = prev;
  24396. }
  24397. function pushContext(state, stream, type) {
  24398. state.context = new Context(type, stream.indentation() + indentUnit, state.context);
  24399. return type;
  24400. }
  24401. function popContext(state) {
  24402. state.context = state.context.prev;
  24403. return state.context.type;
  24404. }
  24405. function pass(type, stream, state) {
  24406. return states[state.context.type](type, stream, state);
  24407. }
  24408. function popAndPass(type, stream, state, n) {
  24409. for (var i = n || 1; i > 0; i--)
  24410. state.context = state.context.prev;
  24411. return pass(type, stream, state);
  24412. }
  24413. // Parser
  24414. function wordAsValue(stream) {
  24415. var word = stream.current().toLowerCase();
  24416. if (valueKeywords.hasOwnProperty(word))
  24417. override = "atom";
  24418. else if (colorKeywords.hasOwnProperty(word))
  24419. override = "keyword";
  24420. else
  24421. override = "variable";
  24422. }
  24423. var states = {};
  24424. states.top = function(type, stream, state) {
  24425. if (type == "{") {
  24426. return pushContext(state, stream, "block");
  24427. } else if (type == "}" && state.context.prev) {
  24428. return popContext(state);
  24429. } else if (type == "@media") {
  24430. return pushContext(state, stream, "media");
  24431. } else if (type == "@font-face") {
  24432. return "font_face_before";
  24433. } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
  24434. return "keyframes";
  24435. } else if (type && type.charAt(0) == "@") {
  24436. return pushContext(state, stream, "at");
  24437. } else if (type == "hash") {
  24438. override = "builtin";
  24439. } else if (type == "word") {
  24440. override = "tag";
  24441. } else if (type == "variable-definition") {
  24442. return "maybeprop";
  24443. } else if (type == "interpolation") {
  24444. return pushContext(state, stream, "interpolation");
  24445. } else if (type == ":") {
  24446. return "pseudo";
  24447. } else if (allowNested && type == "(") {
  24448. return pushContext(state, stream, "parens");
  24449. }
  24450. return state.context.type;
  24451. };
  24452. states.block = function(type, stream, state) {
  24453. if (type == "word") {
  24454. var word = stream.current().toLowerCase();
  24455. if (propertyKeywords.hasOwnProperty(word)) {
  24456. override = "property";
  24457. return "maybeprop";
  24458. } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
  24459. override = "string-2";
  24460. return "maybeprop";
  24461. } else if (allowNested) {
  24462. override = stream.match(/^\s*:/, false) ? "property" : "tag";
  24463. return "block";
  24464. } else {
  24465. override += " error";
  24466. return "maybeprop";
  24467. }
  24468. } else if (type == "meta") {
  24469. return "block";
  24470. } else if (!allowNested && (type == "hash" || type == "qualifier")) {
  24471. override = "error";
  24472. return "block";
  24473. } else {
  24474. return states.top(type, stream, state);
  24475. }
  24476. };
  24477. states.maybeprop = function(type, stream, state) {
  24478. if (type == ":") return pushContext(state, stream, "prop");
  24479. return pass(type, stream, state);
  24480. };
  24481. states.prop = function(type, stream, state) {
  24482. if (type == ";") return popContext(state);
  24483. if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
  24484. if (type == "}" || type == "{") return popAndPass(type, stream, state);
  24485. if (type == "(") return pushContext(state, stream, "parens");
  24486. if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
  24487. override += " error";
  24488. } else if (type == "word") {
  24489. wordAsValue(stream);
  24490. } else if (type == "interpolation") {
  24491. return pushContext(state, stream, "interpolation");
  24492. }
  24493. return "prop";
  24494. };
  24495. states.propBlock = function(type, _stream, state) {
  24496. if (type == "}") return popContext(state);
  24497. if (type == "word") { override = "property"; return "maybeprop"; }
  24498. return state.context.type;
  24499. };
  24500. states.parens = function(type, stream, state) {
  24501. if (type == "{" || type == "}") return popAndPass(type, stream, state);
  24502. if (type == ")") return popContext(state);
  24503. if (type == "(") return pushContext(state, stream, "parens");
  24504. if (type == "word") wordAsValue(stream);
  24505. return "parens";
  24506. };
  24507. states.pseudo = function(type, stream, state) {
  24508. if (type == "word") {
  24509. override = "variable-3";
  24510. return state.context.type;
  24511. }
  24512. return pass(type, stream, state);
  24513. };
  24514. states.media = function(type, stream, state) {
  24515. if (type == "(") return pushContext(state, stream, "media_parens");
  24516. if (type == "}") return popAndPass(type, stream, state);
  24517. if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
  24518. if (type == "word") {
  24519. var word = stream.current().toLowerCase();
  24520. if (word == "only" || word == "not" || word == "and")
  24521. override = "keyword";
  24522. else if (mediaTypes.hasOwnProperty(word))
  24523. override = "attribute";
  24524. else if (mediaFeatures.hasOwnProperty(word))
  24525. override = "property";
  24526. else
  24527. override = "error";
  24528. }
  24529. return state.context.type;
  24530. };
  24531. states.media_parens = function(type, stream, state) {
  24532. if (type == ")") return popContext(state);
  24533. if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
  24534. return states.media(type, stream, state);
  24535. };
  24536. states.font_face_before = function(type, stream, state) {
  24537. if (type == "{")
  24538. return pushContext(state, stream, "font_face");
  24539. return pass(type, stream, state);
  24540. };
  24541. states.font_face = function(type, stream, state) {
  24542. if (type == "}") return popContext(state);
  24543. if (type == "word") {
  24544. if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
  24545. override = "error";
  24546. else
  24547. override = "property";
  24548. return "maybeprop";
  24549. }
  24550. return "font_face";
  24551. };
  24552. states.keyframes = function(type, stream, state) {
  24553. if (type == "word") { override = "variable"; return "keyframes"; }
  24554. if (type == "{") return pushContext(state, stream, "top");
  24555. return pass(type, stream, state);
  24556. };
  24557. states.at = function(type, stream, state) {
  24558. if (type == ";") return popContext(state);
  24559. if (type == "{" || type == "}") return popAndPass(type, stream, state);
  24560. if (type == "word") override = "tag";
  24561. else if (type == "hash") override = "builtin";
  24562. return "at";
  24563. };
  24564. states.interpolation = function(type, stream, state) {
  24565. if (type == "}") return popContext(state);
  24566. if (type == "{" || type == ";") return popAndPass(type, stream, state);
  24567. if (type != "variable") override = "error";
  24568. return "interpolation";
  24569. };
  24570. return {
  24571. startState: function(base) {
  24572. return {tokenize: null,
  24573. state: "top",
  24574. context: new Context("top", base || 0, null)};
  24575. },
  24576. token: function(stream, state) {
  24577. if (!state.tokenize && stream.eatSpace()) return null;
  24578. var style = (state.tokenize || tokenBase)(stream, state);
  24579. if (style && typeof style == "object") {
  24580. type = style[1];
  24581. style = style[0];
  24582. }
  24583. override = style;
  24584. state.state = states[state.state](type, stream, state);
  24585. return override;
  24586. },
  24587. indent: function(state, textAfter) {
  24588. var cx = state.context, ch = textAfter && textAfter.charAt(0);
  24589. var indent = cx.indent;
  24590. if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
  24591. if (cx.prev &&
  24592. (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
  24593. ch == ")" && (cx.type == "parens" || cx.type == "media_parens") ||
  24594. ch == "{" && (cx.type == "at" || cx.type == "media"))) {
  24595. indent = cx.indent - indentUnit;
  24596. cx = cx.prev;
  24597. }
  24598. return indent;
  24599. },
  24600. electricChars: "}",
  24601. blockCommentStart: "/*",
  24602. blockCommentEnd: "*/",
  24603. fold: "brace"
  24604. };
  24605. });
  24606. function keySet(array) {
  24607. var keys = {};
  24608. for (var i = 0; i < array.length; ++i) {
  24609. keys[array[i]] = true;
  24610. }
  24611. return keys;
  24612. }
  24613. var mediaTypes_ = [
  24614. "all", "aural", "braille", "handheld", "print", "projection", "screen",
  24615. "tty", "tv", "embossed"
  24616. ], mediaTypes = keySet(mediaTypes_);
  24617. var mediaFeatures_ = [
  24618. "width", "min-width", "max-width", "height", "min-height", "max-height",
  24619. "device-width", "min-device-width", "max-device-width", "device-height",
  24620. "min-device-height", "max-device-height", "aspect-ratio",
  24621. "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
  24622. "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
  24623. "max-color", "color-index", "min-color-index", "max-color-index",
  24624. "monochrome", "min-monochrome", "max-monochrome", "resolution",
  24625. "min-resolution", "max-resolution", "scan", "grid"
  24626. ], mediaFeatures = keySet(mediaFeatures_);
  24627. var propertyKeywords_ = [
  24628. "align-content", "align-items", "align-self", "alignment-adjust",
  24629. "alignment-baseline", "anchor-point", "animation", "animation-delay",
  24630. "animation-direction", "animation-duration", "animation-fill-mode",
  24631. "animation-iteration-count", "animation-name", "animation-play-state",
  24632. "animation-timing-function", "appearance", "azimuth", "backface-visibility",
  24633. "background", "background-attachment", "background-clip", "background-color",
  24634. "background-image", "background-origin", "background-position",
  24635. "background-repeat", "background-size", "baseline-shift", "binding",
  24636. "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
  24637. "bookmark-target", "border", "border-bottom", "border-bottom-color",
  24638. "border-bottom-left-radius", "border-bottom-right-radius",
  24639. "border-bottom-style", "border-bottom-width", "border-collapse",
  24640. "border-color", "border-image", "border-image-outset",
  24641. "border-image-repeat", "border-image-slice", "border-image-source",
  24642. "border-image-width", "border-left", "border-left-color",
  24643. "border-left-style", "border-left-width", "border-radius", "border-right",
  24644. "border-right-color", "border-right-style", "border-right-width",
  24645. "border-spacing", "border-style", "border-top", "border-top-color",
  24646. "border-top-left-radius", "border-top-right-radius", "border-top-style",
  24647. "border-top-width", "border-width", "bottom", "box-decoration-break",
  24648. "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
  24649. "caption-side", "clear", "clip", "color", "color-profile", "column-count",
  24650. "column-fill", "column-gap", "column-rule", "column-rule-color",
  24651. "column-rule-style", "column-rule-width", "column-span", "column-width",
  24652. "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
  24653. "cue-after", "cue-before", "cursor", "direction", "display",
  24654. "dominant-baseline", "drop-initial-after-adjust",
  24655. "drop-initial-after-align", "drop-initial-before-adjust",
  24656. "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
  24657. "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
  24658. "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
  24659. "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
  24660. "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
  24661. "font-stretch", "font-style", "font-synthesis", "font-variant",
  24662. "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
  24663. "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
  24664. "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
  24665. "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
  24666. "grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
  24667. "grid-template", "grid-template-areas", "grid-template-columns",
  24668. "grid-template-rows", "hanging-punctuation", "height", "hyphens",
  24669. "icon", "image-orientation", "image-rendering", "image-resolution",
  24670. "inline-box-align", "justify-content", "left", "letter-spacing",
  24671. "line-break", "line-height", "line-stacking", "line-stacking-ruby",
  24672. "line-stacking-shift", "line-stacking-strategy", "list-style",
  24673. "list-style-image", "list-style-position", "list-style-type", "margin",
  24674. "margin-bottom", "margin-left", "margin-right", "margin-top",
  24675. "marker-offset", "marks", "marquee-direction", "marquee-loop",
  24676. "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
  24677. "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
  24678. "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
  24679. "opacity", "order", "orphans", "outline",
  24680. "outline-color", "outline-offset", "outline-style", "outline-width",
  24681. "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
  24682. "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
  24683. "page", "page-break-after", "page-break-before", "page-break-inside",
  24684. "page-policy", "pause", "pause-after", "pause-before", "perspective",
  24685. "perspective-origin", "pitch", "pitch-range", "play-during", "position",
  24686. "presentation-level", "punctuation-trim", "quotes", "region-break-after",
  24687. "region-break-before", "region-break-inside", "region-fragment",
  24688. "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
  24689. "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
  24690. "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
  24691. "shape-outside", "size", "speak", "speak-as", "speak-header",
  24692. "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
  24693. "tab-size", "table-layout", "target", "target-name", "target-new",
  24694. "target-position", "text-align", "text-align-last", "text-decoration",
  24695. "text-decoration-color", "text-decoration-line", "text-decoration-skip",
  24696. "text-decoration-style", "text-emphasis", "text-emphasis-color",
  24697. "text-emphasis-position", "text-emphasis-style", "text-height",
  24698. "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
  24699. "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
  24700. "text-wrap", "top", "transform", "transform-origin", "transform-style",
  24701. "transition", "transition-delay", "transition-duration",
  24702. "transition-property", "transition-timing-function", "unicode-bidi",
  24703. "vertical-align", "visibility", "voice-balance", "voice-duration",
  24704. "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
  24705. "voice-volume", "volume", "white-space", "widows", "width", "word-break",
  24706. "word-spacing", "word-wrap", "z-index",
  24707. // SVG-specific
  24708. "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
  24709. "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
  24710. "color-interpolation", "color-interpolation-filters",
  24711. "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
  24712. "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
  24713. "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
  24714. "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
  24715. "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
  24716. "glyph-orientation-vertical", "text-anchor", "writing-mode"
  24717. ], propertyKeywords = keySet(propertyKeywords_);
  24718. var nonStandardPropertyKeywords_ = [
  24719. "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
  24720. "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
  24721. "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
  24722. "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
  24723. "searchfield-results-decoration", "zoom"
  24724. ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
  24725. var colorKeywords_ = [
  24726. "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
  24727. "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
  24728. "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
  24729. "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
  24730. "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
  24731. "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
  24732. "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
  24733. "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
  24734. "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
  24735. "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
  24736. "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
  24737. "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
  24738. "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
  24739. "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
  24740. "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
  24741. "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
  24742. "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
  24743. "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
  24744. "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
  24745. "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
  24746. "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
  24747. "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
  24748. "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
  24749. "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
  24750. "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
  24751. "whitesmoke", "yellow", "yellowgreen"
  24752. ], colorKeywords = keySet(colorKeywords_);
  24753. var valueKeywords_ = [
  24754. "above", "absolute", "activeborder", "activecaption", "afar",
  24755. "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
  24756. "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
  24757. "arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page",
  24758. "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
  24759. "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
  24760. "both", "bottom", "break", "break-all", "break-word", "button", "button-bevel",
  24761. "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
  24762. "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
  24763. "cell", "center", "checkbox", "circle", "cjk-earthly-branch",
  24764. "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
  24765. "col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
  24766. "content-box", "context-menu", "continuous", "copy", "cover", "crop",
  24767. "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
  24768. "decimal-leading-zero", "default", "default-button", "destination-atop",
  24769. "destination-in", "destination-out", "destination-over", "devanagari",
  24770. "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
  24771. "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
  24772. "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
  24773. "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
  24774. "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
  24775. "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
  24776. "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
  24777. "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
  24778. "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
  24779. "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
  24780. "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
  24781. "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
  24782. "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
  24783. "help", "hidden", "hide", "higher", "highlight", "highlighttext",
  24784. "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
  24785. "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
  24786. "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
  24787. "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
  24788. "italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer",
  24789. "landscape", "lao", "large", "larger", "left", "level", "lighter",
  24790. "line-through", "linear", "lines", "list-item", "listbox", "listitem",
  24791. "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
  24792. "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
  24793. "lower-roman", "lowercase", "ltr", "malayalam", "match",
  24794. "media-controls-background", "media-current-time-display",
  24795. "media-fullscreen-button", "media-mute-button", "media-play-button",
  24796. "media-return-to-realtime-button", "media-rewind-button",
  24797. "media-seek-back-button", "media-seek-forward-button", "media-slider",
  24798. "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
  24799. "media-volume-slider-container", "media-volume-sliderthumb", "medium",
  24800. "menu", "menulist", "menulist-button", "menulist-text",
  24801. "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
  24802. "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
  24803. "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
  24804. "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
  24805. "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
  24806. "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
  24807. "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
  24808. "painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer",
  24809. "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
  24810. "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region",
  24811. "relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
  24812. "ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
  24813. "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
  24814. "searchfield-cancel-button", "searchfield-decoration",
  24815. "searchfield-results-button", "searchfield-results-decoration",
  24816. "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
  24817. "single", "skip-white-space", "slide", "slider-horizontal",
  24818. "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
  24819. "small", "small-caps", "small-caption", "smaller", "solid", "somali",
  24820. "source-atop", "source-in", "source-out", "source-over", "space", "square",
  24821. "square-button", "start", "static", "status-bar", "stretch", "stroke",
  24822. "sub", "subpixel-antialiased", "super", "sw-resize", "table",
  24823. "table-caption", "table-cell", "table-column", "table-column-group",
  24824. "table-footer-group", "table-header-group", "table-row", "table-row-group",
  24825. "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
  24826. "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
  24827. "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
  24828. "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
  24829. "transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
  24830. "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
  24831. "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
  24832. "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
  24833. "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
  24834. "window", "windowframe", "windowtext", "x-large", "x-small", "xor",
  24835. "xx-large", "xx-small"
  24836. ], valueKeywords = keySet(valueKeywords_);
  24837. var fontProperties_ = [
  24838. "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
  24839. "font-stretch", "font-weight", "font-style"
  24840. ], fontProperties = keySet(fontProperties_);
  24841. var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_)
  24842. .concat(nonStandardPropertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
  24843. CodeMirror.registerHelper("hintWords", "css", allWords);
  24844. function tokenCComment(stream, state) {
  24845. var maybeEnd = false, ch;
  24846. while ((ch = stream.next()) != null) {
  24847. if (maybeEnd && ch == "/") {
  24848. state.tokenize = null;
  24849. break;
  24850. }
  24851. maybeEnd = (ch == "*");
  24852. }
  24853. return ["comment", "comment"];
  24854. }
  24855. function tokenSGMLComment(stream, state) {
  24856. if (stream.skipTo("-->")) {
  24857. stream.match("-->");
  24858. state.tokenize = null;
  24859. } else {
  24860. stream.skipToEnd();
  24861. }
  24862. return ["comment", "comment"];
  24863. }
  24864. CodeMirror.defineMIME("text/css", {
  24865. mediaTypes: mediaTypes,
  24866. mediaFeatures: mediaFeatures,
  24867. propertyKeywords: propertyKeywords,
  24868. nonStandardPropertyKeywords: nonStandardPropertyKeywords,
  24869. colorKeywords: colorKeywords,
  24870. valueKeywords: valueKeywords,
  24871. fontProperties: fontProperties,
  24872. tokenHooks: {
  24873. "<": function(stream, state) {
  24874. if (!stream.match("!--")) return false;
  24875. state.tokenize = tokenSGMLComment;
  24876. return tokenSGMLComment(stream, state);
  24877. },
  24878. "/": function(stream, state) {
  24879. if (!stream.eat("*")) return false;
  24880. state.tokenize = tokenCComment;
  24881. return tokenCComment(stream, state);
  24882. }
  24883. },
  24884. name: "css"
  24885. });
  24886. CodeMirror.defineMIME("text/x-scss", {
  24887. mediaTypes: mediaTypes,
  24888. mediaFeatures: mediaFeatures,
  24889. propertyKeywords: propertyKeywords,
  24890. nonStandardPropertyKeywords: nonStandardPropertyKeywords,
  24891. colorKeywords: colorKeywords,
  24892. valueKeywords: valueKeywords,
  24893. fontProperties: fontProperties,
  24894. allowNested: true,
  24895. tokenHooks: {
  24896. "/": function(stream, state) {
  24897. if (stream.eat("/")) {
  24898. stream.skipToEnd();
  24899. return ["comment", "comment"];
  24900. } else if (stream.eat("*")) {
  24901. state.tokenize = tokenCComment;
  24902. return tokenCComment(stream, state);
  24903. } else {
  24904. return ["operator", "operator"];
  24905. }
  24906. },
  24907. ":": function(stream) {
  24908. if (stream.match(/\s*\{/))
  24909. return [null, "{"];
  24910. return false;
  24911. },
  24912. "$": function(stream) {
  24913. stream.match(/^[\w-]+/);
  24914. if (stream.match(/^\s*:/, false))
  24915. return ["variable-2", "variable-definition"];
  24916. return ["variable-2", "variable"];
  24917. },
  24918. "#": function(stream) {
  24919. if (!stream.eat("{")) return false;
  24920. return [null, "interpolation"];
  24921. }
  24922. },
  24923. name: "css",
  24924. helperType: "scss"
  24925. });
  24926. CodeMirror.defineMIME("text/x-less", {
  24927. mediaTypes: mediaTypes,
  24928. mediaFeatures: mediaFeatures,
  24929. propertyKeywords: propertyKeywords,
  24930. nonStandardPropertyKeywords: nonStandardPropertyKeywords,
  24931. colorKeywords: colorKeywords,
  24932. valueKeywords: valueKeywords,
  24933. fontProperties: fontProperties,
  24934. allowNested: true,
  24935. tokenHooks: {
  24936. "/": function(stream, state) {
  24937. if (stream.eat("/")) {
  24938. stream.skipToEnd();
  24939. return ["comment", "comment"];
  24940. } else if (stream.eat("*")) {
  24941. state.tokenize = tokenCComment;
  24942. return tokenCComment(stream, state);
  24943. } else {
  24944. return ["operator", "operator"];
  24945. }
  24946. },
  24947. "@": function(stream) {
  24948. if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
  24949. stream.eatWhile(/[\w\\\-]/);
  24950. if (stream.match(/^\s*:/, false))
  24951. return ["variable-2", "variable-definition"];
  24952. return ["variable-2", "variable"];
  24953. },
  24954. "&": function() {
  24955. return ["atom", "atom"];
  24956. }
  24957. },
  24958. name: "css",
  24959. helperType: "less"
  24960. });
  24961. });
  24962. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  24963. // Distributed under an MIT license: http://codemirror.net/LICENSE
  24964. (function(mod) {
  24965. if (typeof exports == "object" && typeof module == "object") // CommonJS
  24966. mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
  24967. else if (typeof define == "function" && define.amd) // AMD
  24968. define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
  24969. else // Plain browser env
  24970. mod(CodeMirror);
  24971. })(function(CodeMirror) {
  24972. "use strict";
  24973. CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
  24974. var htmlMode = CodeMirror.getMode(config, {name: "xml",
  24975. htmlMode: true,
  24976. multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
  24977. multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
  24978. var cssMode = CodeMirror.getMode(config, "css");
  24979. var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
  24980. scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
  24981. mode: CodeMirror.getMode(config, "javascript")});
  24982. if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
  24983. var conf = scriptTypesConf[i];
  24984. scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
  24985. }
  24986. scriptTypes.push({matches: /./,
  24987. mode: CodeMirror.getMode(config, "text/plain")});
  24988. function html(stream, state) {
  24989. var tagName = state.htmlState.tagName;
  24990. if (tagName) tagName = tagName.toLowerCase();
  24991. var style = htmlMode.token(stream, state.htmlState);
  24992. if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
  24993. // Script block: mode to change to depends on type attribute
  24994. var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
  24995. scriptType = scriptType ? scriptType[1] : "";
  24996. if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
  24997. for (var i = 0; i < scriptTypes.length; ++i) {
  24998. var tp = scriptTypes[i];
  24999. if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
  25000. if (tp.mode) {
  25001. state.token = script;
  25002. state.localMode = tp.mode;
  25003. state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
  25004. }
  25005. break;
  25006. }
  25007. }
  25008. } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
  25009. state.token = css;
  25010. state.localMode = cssMode;
  25011. state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
  25012. }
  25013. return style;
  25014. }
  25015. function maybeBackup(stream, pat, style) {
  25016. var cur = stream.current();
  25017. var close = cur.search(pat), m;
  25018. if (close > -1) stream.backUp(cur.length - close);
  25019. else if (m = cur.match(/<\/?$/)) {
  25020. stream.backUp(cur.length);
  25021. if (!stream.match(pat, false)) stream.match(cur);
  25022. }
  25023. return style;
  25024. }
  25025. function script(stream, state) {
  25026. if (stream.match(/^<\/\s*script\s*>/i, false)) {
  25027. state.token = html;
  25028. state.localState = state.localMode = null;
  25029. return html(stream, state);
  25030. }
  25031. return maybeBackup(stream, /<\/\s*script\s*>/,
  25032. state.localMode.token(stream, state.localState));
  25033. }
  25034. function css(stream, state) {
  25035. if (stream.match(/^<\/\s*style\s*>/i, false)) {
  25036. state.token = html;
  25037. state.localState = state.localMode = null;
  25038. return html(stream, state);
  25039. }
  25040. return maybeBackup(stream, /<\/\s*style\s*>/,
  25041. cssMode.token(stream, state.localState));
  25042. }
  25043. return {
  25044. startState: function() {
  25045. var state = htmlMode.startState();
  25046. return {token: html, localMode: null, localState: null, htmlState: state};
  25047. },
  25048. copyState: function(state) {
  25049. if (state.localState)
  25050. var local = CodeMirror.copyState(state.localMode, state.localState);
  25051. return {token: state.token, localMode: state.localMode, localState: local,
  25052. htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
  25053. },
  25054. token: function(stream, state) {
  25055. return state.token(stream, state);
  25056. },
  25057. indent: function(state, textAfter) {
  25058. if (!state.localMode || /^\s*<\//.test(textAfter))
  25059. return htmlMode.indent(state.htmlState, textAfter);
  25060. else if (state.localMode.indent)
  25061. return state.localMode.indent(state.localState, textAfter);
  25062. else
  25063. return CodeMirror.Pass;
  25064. },
  25065. innerMode: function(state) {
  25066. return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
  25067. }
  25068. };
  25069. }, "xml", "javascript", "css");
  25070. CodeMirror.defineMIME("text/html", "htmlmixed");
  25071. });
  25072. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  25073. // Distributed under an MIT license: http://codemirror.net/LICENSE
  25074. (function(mod) {
  25075. if (typeof exports == "object" && typeof module == "object") // CommonJS
  25076. mod(require("../../lib/codemirror", require("../xml/xml")));
  25077. else if (typeof define == "function" && define.amd) // AMD
  25078. define(["../../lib/codemirror", "../xml/xml"], mod);
  25079. else // Plain browser env
  25080. mod(CodeMirror);
  25081. })(function(CodeMirror) {
  25082. "use strict";
  25083. CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
  25084. var htmlFound = CodeMirror.modes.hasOwnProperty("xml");
  25085. var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain");
  25086. var aliases = {
  25087. html: "htmlmixed",
  25088. js: "javascript",
  25089. json: "application/json",
  25090. c: "text/x-csrc",
  25091. "c++": "text/x-c++src",
  25092. java: "text/x-java",
  25093. csharp: "text/x-csharp",
  25094. "c#": "text/x-csharp",
  25095. scala: "text/x-scala"
  25096. };
  25097. var getMode = (function () {
  25098. var i, modes = {}, mimes = {}, mime;
  25099. var list = [];
  25100. for (var m in CodeMirror.modes)
  25101. if (CodeMirror.modes.propertyIsEnumerable(m)) list.push(m);
  25102. for (i = 0; i < list.length; i++) {
  25103. modes[list[i]] = list[i];
  25104. }
  25105. var mimesList = [];
  25106. for (var m in CodeMirror.mimeModes)
  25107. if (CodeMirror.mimeModes.propertyIsEnumerable(m))
  25108. mimesList.push({mime: m, mode: CodeMirror.mimeModes[m]});
  25109. for (i = 0; i < mimesList.length; i++) {
  25110. mime = mimesList[i].mime;
  25111. mimes[mime] = mimesList[i].mime;
  25112. }
  25113. for (var a in aliases) {
  25114. if (aliases[a] in modes || aliases[a] in mimes)
  25115. modes[a] = aliases[a];
  25116. }
  25117. return function (lang) {
  25118. return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
  25119. };
  25120. }());
  25121. // Should characters that affect highlighting be highlighted separate?
  25122. // Does not include characters that will be output (such as `1.` and `-` for lists)
  25123. if (modeCfg.highlightFormatting === undefined)
  25124. modeCfg.highlightFormatting = false;
  25125. // Maximum number of nested blockquotes. Set to 0 for infinite nesting.
  25126. // Excess `>` will emit `error` token.
  25127. if (modeCfg.maxBlockquoteDepth === undefined)
  25128. modeCfg.maxBlockquoteDepth = 0;
  25129. // Should underscores in words open/close em/strong?
  25130. if (modeCfg.underscoresBreakWords === undefined)
  25131. modeCfg.underscoresBreakWords = true;
  25132. // Turn on fenced code blocks? ("```" to start/end)
  25133. if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
  25134. // Turn on task lists? ("- [ ] " and "- [x] ")
  25135. if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
  25136. var codeDepth = 0;
  25137. var header = 'header'
  25138. , code = 'comment'
  25139. , quote = 'quote'
  25140. , list1 = 'variable-2'
  25141. , list2 = 'variable-3'
  25142. , list3 = 'keyword'
  25143. , hr = 'hr'
  25144. , image = 'tag'
  25145. , formatting = 'formatting'
  25146. , linkinline = 'link'
  25147. , linkemail = 'link'
  25148. , linktext = 'link'
  25149. , linkhref = 'string'
  25150. , em = 'em'
  25151. , strong = 'strong';
  25152. var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
  25153. , ulRE = /^[*\-+]\s+/
  25154. , olRE = /^[0-9]+\.\s+/
  25155. , taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
  25156. , atxHeaderRE = /^#+/
  25157. , setextHeaderRE = /^(?:\={1,}|-{1,})$/
  25158. , textRE = /^[^#!\[\]*_\\<>` "'(]+/;
  25159. function switchInline(stream, state, f) {
  25160. state.f = state.inline = f;
  25161. return f(stream, state);
  25162. }
  25163. function switchBlock(stream, state, f) {
  25164. state.f = state.block = f;
  25165. return f(stream, state);
  25166. }
  25167. // Blocks
  25168. function blankLine(state) {
  25169. // Reset linkTitle state
  25170. state.linkTitle = false;
  25171. // Reset EM state
  25172. state.em = false;
  25173. // Reset STRONG state
  25174. state.strong = false;
  25175. // Reset state.quote
  25176. state.quote = 0;
  25177. if (!htmlFound && state.f == htmlBlock) {
  25178. state.f = inlineNormal;
  25179. state.block = blockNormal;
  25180. }
  25181. // Reset state.trailingSpace
  25182. state.trailingSpace = 0;
  25183. state.trailingSpaceNewLine = false;
  25184. // Mark this line as blank
  25185. state.thisLineHasContent = false;
  25186. return null;
  25187. }
  25188. function blockNormal(stream, state) {
  25189. var sol = stream.sol();
  25190. var prevLineIsList = (state.list !== false);
  25191. if (state.list !== false && state.indentationDiff >= 0) { // Continued list
  25192. if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
  25193. state.indentation -= state.indentationDiff;
  25194. }
  25195. state.list = null;
  25196. } else if (state.list !== false && state.indentation > 0) {
  25197. state.list = null;
  25198. state.listDepth = Math.floor(state.indentation / 4);
  25199. } else if (state.list !== false) { // No longer a list
  25200. state.list = false;
  25201. state.listDepth = 0;
  25202. }
  25203. var match = null;
  25204. if (state.indentationDiff >= 4) {
  25205. state.indentation -= 4;
  25206. stream.skipToEnd();
  25207. return code;
  25208. } else if (stream.eatSpace()) {
  25209. return null;
  25210. } else if (match = stream.match(atxHeaderRE)) {
  25211. state.header = match[0].length <= 6 ? match[0].length : 6;
  25212. if (modeCfg.highlightFormatting) state.formatting = "header";
  25213. state.f = state.inline;
  25214. return getType(state);
  25215. } else if (state.prevLineHasContent && (match = stream.match(setextHeaderRE))) {
  25216. state.header = match[0].charAt(0) == '=' ? 1 : 2;
  25217. if (modeCfg.highlightFormatting) state.formatting = "header";
  25218. state.f = state.inline;
  25219. return getType(state);
  25220. } else if (stream.eat('>')) {
  25221. state.indentation++;
  25222. state.quote = sol ? 1 : state.quote + 1;
  25223. if (modeCfg.highlightFormatting) state.formatting = "quote";
  25224. stream.eatSpace();
  25225. return getType(state);
  25226. } else if (stream.peek() === '[') {
  25227. return switchInline(stream, state, footnoteLink);
  25228. } else if (stream.match(hrRE, true)) {
  25229. return hr;
  25230. } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) {
  25231. var listType = null;
  25232. if (stream.match(ulRE, true)) {
  25233. listType = 'ul';
  25234. } else {
  25235. stream.match(olRE, true);
  25236. listType = 'ol';
  25237. }
  25238. state.indentation += 4;
  25239. state.list = true;
  25240. state.listDepth++;
  25241. if (modeCfg.taskLists && stream.match(taskListRE, false)) {
  25242. state.taskList = true;
  25243. }
  25244. state.f = state.inline;
  25245. if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
  25246. return getType(state);
  25247. } else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
  25248. // try switching mode
  25249. state.localMode = getMode(RegExp.$1);
  25250. if (state.localMode) state.localState = state.localMode.startState();
  25251. switchBlock(stream, state, local);
  25252. if (modeCfg.highlightFormatting) state.formatting = "code-block";
  25253. state.code = true;
  25254. return getType(state);
  25255. }
  25256. return switchInline(stream, state, state.inline);
  25257. }
  25258. function htmlBlock(stream, state) {
  25259. var style = htmlMode.token(stream, state.htmlState);
  25260. if ((htmlFound && state.htmlState.tagStart === null && !state.htmlState.context) ||
  25261. (state.md_inside && stream.current().indexOf(">") > -1)) {
  25262. state.f = inlineNormal;
  25263. state.block = blockNormal;
  25264. state.htmlState = null;
  25265. }
  25266. return style;
  25267. }
  25268. function local(stream, state) {
  25269. if (stream.sol() && stream.match(/^```/, true)) {
  25270. state.localMode = state.localState = null;
  25271. state.f = inlineNormal;
  25272. state.block = blockNormal;
  25273. if (modeCfg.highlightFormatting) state.formatting = "code-block";
  25274. state.code = true;
  25275. var returnType = getType(state);
  25276. state.code = false;
  25277. return returnType;
  25278. } else if (state.localMode) {
  25279. return state.localMode.token(stream, state.localState);
  25280. } else {
  25281. stream.skipToEnd();
  25282. return code;
  25283. }
  25284. }
  25285. // Inline
  25286. function getType(state) {
  25287. var styles = [];
  25288. if (state.formatting) {
  25289. styles.push(formatting);
  25290. if (typeof state.formatting === "string") state.formatting = [state.formatting];
  25291. for (var i = 0; i < state.formatting.length; i++) {
  25292. styles.push(formatting + "-" + state.formatting[i]);
  25293. if (state.formatting[i] === "header") {
  25294. styles.push(formatting + "-" + state.formatting[i] + "-" + state.header);
  25295. }
  25296. // Add `formatting-quote` and `formatting-quote-#` for blockquotes
  25297. // Add `error` instead if the maximum blockquote nesting depth is passed
  25298. if (state.formatting[i] === "quote") {
  25299. if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
  25300. styles.push(formatting + "-" + state.formatting[i] + "-" + state.quote);
  25301. } else {
  25302. styles.push("error");
  25303. }
  25304. }
  25305. }
  25306. }
  25307. if (state.taskOpen) {
  25308. styles.push("meta");
  25309. return styles.length ? styles.join(' ') : null;
  25310. }
  25311. if (state.taskClosed) {
  25312. styles.push("property");
  25313. return styles.length ? styles.join(' ') : null;
  25314. }
  25315. if (state.linkHref) {
  25316. styles.push(linkhref);
  25317. return styles.length ? styles.join(' ') : null;
  25318. }
  25319. if (state.strong) { styles.push(strong); }
  25320. if (state.em) { styles.push(em); }
  25321. if (state.linkText) { styles.push(linktext); }
  25322. if (state.code) { styles.push(code); }
  25323. if (state.header) { styles.push(header); styles.push(header + "-" + state.header); }
  25324. if (state.quote) {
  25325. styles.push(quote);
  25326. // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
  25327. if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
  25328. styles.push(quote + "-" + state.quote);
  25329. } else {
  25330. styles.push(quote + "-" + modeCfg.maxBlockquoteDepth);
  25331. }
  25332. }
  25333. if (state.list !== false) {
  25334. var listMod = (state.listDepth - 1) % 3;
  25335. if (!listMod) {
  25336. styles.push(list1);
  25337. } else if (listMod === 1) {
  25338. styles.push(list2);
  25339. } else {
  25340. styles.push(list3);
  25341. }
  25342. }
  25343. if (state.trailingSpaceNewLine) {
  25344. styles.push("trailing-space-new-line");
  25345. } else if (state.trailingSpace) {
  25346. styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
  25347. }
  25348. return styles.length ? styles.join(' ') : null;
  25349. }
  25350. function handleText(stream, state) {
  25351. if (stream.match(textRE, true)) {
  25352. return getType(state);
  25353. }
  25354. return undefined;
  25355. }
  25356. function inlineNormal(stream, state) {
  25357. var style = state.text(stream, state);
  25358. if (typeof style !== 'undefined')
  25359. return style;
  25360. if (state.list) { // List marker (*, +, -, 1., etc)
  25361. state.list = null;
  25362. return getType(state);
  25363. }
  25364. if (state.taskList) {
  25365. var taskOpen = stream.match(taskListRE, true)[1] !== "x";
  25366. if (taskOpen) state.taskOpen = true;
  25367. else state.taskClosed = true;
  25368. if (modeCfg.highlightFormatting) state.formatting = "task";
  25369. state.taskList = false;
  25370. return getType(state);
  25371. }
  25372. state.taskOpen = false;
  25373. state.taskClosed = false;
  25374. if (state.header && stream.match(/^#+$/, true)) {
  25375. if (modeCfg.highlightFormatting) state.formatting = "header";
  25376. return getType(state);
  25377. }
  25378. // Get sol() value now, before character is consumed
  25379. var sol = stream.sol();
  25380. var ch = stream.next();
  25381. if (ch === '\\') {
  25382. stream.next();
  25383. if (modeCfg.highlightFormatting) {
  25384. var type = getType(state);
  25385. return type ? type + " formatting-escape" : "formatting-escape";
  25386. }
  25387. }
  25388. // Matches link titles present on next line
  25389. if (state.linkTitle) {
  25390. state.linkTitle = false;
  25391. var matchCh = ch;
  25392. if (ch === '(') {
  25393. matchCh = ')';
  25394. }
  25395. matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
  25396. var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
  25397. if (stream.match(new RegExp(regex), true)) {
  25398. return linkhref;
  25399. }
  25400. }
  25401. // If this block is changed, it may need to be updated in GFM mode
  25402. if (ch === '`') {
  25403. var previousFormatting = state.formatting;
  25404. if (modeCfg.highlightFormatting) state.formatting = "code";
  25405. var t = getType(state);
  25406. var before = stream.pos;
  25407. stream.eatWhile('`');
  25408. var difference = 1 + stream.pos - before;
  25409. if (!state.code) {
  25410. codeDepth = difference;
  25411. state.code = true;
  25412. return getType(state);
  25413. } else {
  25414. if (difference === codeDepth) { // Must be exact
  25415. state.code = false;
  25416. return t;
  25417. }
  25418. state.formatting = previousFormatting;
  25419. return getType(state);
  25420. }
  25421. } else if (state.code) {
  25422. return getType(state);
  25423. }
  25424. if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
  25425. stream.match(/\[[^\]]*\]/);
  25426. state.inline = state.f = linkHref;
  25427. return image;
  25428. }
  25429. if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
  25430. state.linkText = true;
  25431. if (modeCfg.highlightFormatting) state.formatting = "link";
  25432. return getType(state);
  25433. }
  25434. if (ch === ']' && state.linkText) {
  25435. if (modeCfg.highlightFormatting) state.formatting = "link";
  25436. var type = getType(state);
  25437. state.linkText = false;
  25438. state.inline = state.f = linkHref;
  25439. return type;
  25440. }
  25441. if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
  25442. state.f = state.inline = linkInline;
  25443. if (modeCfg.highlightFormatting) state.formatting = "link";
  25444. var type = getType(state);
  25445. if (type){
  25446. type += " ";
  25447. } else {
  25448. type = "";
  25449. }
  25450. return type + linkinline;
  25451. }
  25452. if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
  25453. state.f = state.inline = linkInline;
  25454. if (modeCfg.highlightFormatting) state.formatting = "link";
  25455. var type = getType(state);
  25456. if (type){
  25457. type += " ";
  25458. } else {
  25459. type = "";
  25460. }
  25461. return type + linkemail;
  25462. }
  25463. if (ch === '<' && stream.match(/^\w/, false)) {
  25464. if (stream.string.indexOf(">") != -1) {
  25465. var atts = stream.string.substring(1,stream.string.indexOf(">"));
  25466. if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
  25467. state.md_inside = true;
  25468. }
  25469. }
  25470. stream.backUp(1);
  25471. state.htmlState = CodeMirror.startState(htmlMode);
  25472. return switchBlock(stream, state, htmlBlock);
  25473. }
  25474. if (ch === '<' && stream.match(/^\/\w*?>/)) {
  25475. state.md_inside = false;
  25476. return "tag";
  25477. }
  25478. var ignoreUnderscore = false;
  25479. if (!modeCfg.underscoresBreakWords) {
  25480. if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
  25481. var prevPos = stream.pos - 2;
  25482. if (prevPos >= 0) {
  25483. var prevCh = stream.string.charAt(prevPos);
  25484. if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
  25485. ignoreUnderscore = true;
  25486. }
  25487. }
  25488. }
  25489. }
  25490. if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
  25491. if (sol && stream.peek() === ' ') {
  25492. // Do nothing, surrounded by newline and space
  25493. } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
  25494. if (modeCfg.highlightFormatting) state.formatting = "strong";
  25495. var t = getType(state);
  25496. state.strong = false;
  25497. return t;
  25498. } else if (!state.strong && stream.eat(ch)) { // Add STRONG
  25499. state.strong = ch;
  25500. if (modeCfg.highlightFormatting) state.formatting = "strong";
  25501. return getType(state);
  25502. } else if (state.em === ch) { // Remove EM
  25503. if (modeCfg.highlightFormatting) state.formatting = "em";
  25504. var t = getType(state);
  25505. state.em = false;
  25506. return t;
  25507. } else if (!state.em) { // Add EM
  25508. state.em = ch;
  25509. if (modeCfg.highlightFormatting) state.formatting = "em";
  25510. return getType(state);
  25511. }
  25512. } else if (ch === ' ') {
  25513. if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
  25514. if (stream.peek() === ' ') { // Surrounded by spaces, ignore
  25515. return getType(state);
  25516. } else { // Not surrounded by spaces, back up pointer
  25517. stream.backUp(1);
  25518. }
  25519. }
  25520. }
  25521. if (ch === ' ') {
  25522. if (stream.match(/ +$/, false)) {
  25523. state.trailingSpace++;
  25524. } else if (state.trailingSpace) {
  25525. state.trailingSpaceNewLine = true;
  25526. }
  25527. }
  25528. return getType(state);
  25529. }
  25530. function linkInline(stream, state) {
  25531. var ch = stream.next();
  25532. if (ch === ">") {
  25533. state.f = state.inline = inlineNormal;
  25534. if (modeCfg.highlightFormatting) state.formatting = "link";
  25535. var type = getType(state);
  25536. if (type){
  25537. type += " ";
  25538. } else {
  25539. type = "";
  25540. }
  25541. return type + linkinline;
  25542. }
  25543. stream.match(/^[^>]+/, true);
  25544. return linkinline;
  25545. }
  25546. function linkHref(stream, state) {
  25547. // Check if space, and return NULL if so (to avoid marking the space)
  25548. if(stream.eatSpace()){
  25549. return null;
  25550. }
  25551. var ch = stream.next();
  25552. if (ch === '(' || ch === '[') {
  25553. state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]");
  25554. if (modeCfg.highlightFormatting) state.formatting = "link-string";
  25555. state.linkHref = true;
  25556. return getType(state);
  25557. }
  25558. return 'error';
  25559. }
  25560. function getLinkHrefInside(endChar) {
  25561. return function(stream, state) {
  25562. var ch = stream.next();
  25563. if (ch === endChar) {
  25564. state.f = state.inline = inlineNormal;
  25565. if (modeCfg.highlightFormatting) state.formatting = "link-string";
  25566. var returnState = getType(state);
  25567. state.linkHref = false;
  25568. return returnState;
  25569. }
  25570. if (stream.match(inlineRE(endChar), true)) {
  25571. stream.backUp(1);
  25572. }
  25573. state.linkHref = true;
  25574. return getType(state);
  25575. };
  25576. }
  25577. function footnoteLink(stream, state) {
  25578. if (stream.match(/^[^\]]*\]:/, false)) {
  25579. state.f = footnoteLinkInside;
  25580. stream.next(); // Consume [
  25581. if (modeCfg.highlightFormatting) state.formatting = "link";
  25582. state.linkText = true;
  25583. return getType(state);
  25584. }
  25585. return switchInline(stream, state, inlineNormal);
  25586. }
  25587. function footnoteLinkInside(stream, state) {
  25588. if (stream.match(/^\]:/, true)) {
  25589. state.f = state.inline = footnoteUrl;
  25590. if (modeCfg.highlightFormatting) state.formatting = "link";
  25591. var returnType = getType(state);
  25592. state.linkText = false;
  25593. return returnType;
  25594. }
  25595. stream.match(/^[^\]]+/, true);
  25596. return linktext;
  25597. }
  25598. function footnoteUrl(stream, state) {
  25599. // Check if space, and return NULL if so (to avoid marking the space)
  25600. if(stream.eatSpace()){
  25601. return null;
  25602. }
  25603. // Match URL
  25604. stream.match(/^[^\s]+/, true);
  25605. // Check for link title
  25606. if (stream.peek() === undefined) { // End of line, set flag to check next line
  25607. state.linkTitle = true;
  25608. } else { // More content on line, check if link title
  25609. stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
  25610. }
  25611. state.f = state.inline = inlineNormal;
  25612. return linkhref;
  25613. }
  25614. var savedInlineRE = [];
  25615. function inlineRE(endChar) {
  25616. if (!savedInlineRE[endChar]) {
  25617. // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
  25618. endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
  25619. // Match any non-endChar, escaped character, as well as the closing
  25620. // endChar.
  25621. savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
  25622. }
  25623. return savedInlineRE[endChar];
  25624. }
  25625. var mode = {
  25626. startState: function() {
  25627. return {
  25628. f: blockNormal,
  25629. prevLineHasContent: false,
  25630. thisLineHasContent: false,
  25631. block: blockNormal,
  25632. htmlState: null,
  25633. indentation: 0,
  25634. inline: inlineNormal,
  25635. text: handleText,
  25636. formatting: false,
  25637. linkText: false,
  25638. linkHref: false,
  25639. linkTitle: false,
  25640. em: false,
  25641. strong: false,
  25642. header: 0,
  25643. taskList: false,
  25644. list: false,
  25645. listDepth: 0,
  25646. quote: 0,
  25647. trailingSpace: 0,
  25648. trailingSpaceNewLine: false
  25649. };
  25650. },
  25651. copyState: function(s) {
  25652. return {
  25653. f: s.f,
  25654. prevLineHasContent: s.prevLineHasContent,
  25655. thisLineHasContent: s.thisLineHasContent,
  25656. block: s.block,
  25657. htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),
  25658. indentation: s.indentation,
  25659. localMode: s.localMode,
  25660. localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
  25661. inline: s.inline,
  25662. text: s.text,
  25663. formatting: false,
  25664. linkTitle: s.linkTitle,
  25665. em: s.em,
  25666. strong: s.strong,
  25667. header: s.header,
  25668. taskList: s.taskList,
  25669. list: s.list,
  25670. listDepth: s.listDepth,
  25671. quote: s.quote,
  25672. trailingSpace: s.trailingSpace,
  25673. trailingSpaceNewLine: s.trailingSpaceNewLine,
  25674. md_inside: s.md_inside
  25675. };
  25676. },
  25677. token: function(stream, state) {
  25678. // Reset state.formatting
  25679. state.formatting = false;
  25680. if (stream.sol()) {
  25681. var forceBlankLine = !!state.header;
  25682. // Reset state.header
  25683. state.header = 0;
  25684. if (stream.match(/^\s*$/, true) || forceBlankLine) {
  25685. state.prevLineHasContent = false;
  25686. blankLine(state);
  25687. return forceBlankLine ? this.token(stream, state) : null;
  25688. } else {
  25689. state.prevLineHasContent = state.thisLineHasContent;
  25690. state.thisLineHasContent = true;
  25691. }
  25692. // Reset state.taskList
  25693. state.taskList = false;
  25694. // Reset state.code
  25695. state.code = false;
  25696. // Reset state.trailingSpace
  25697. state.trailingSpace = 0;
  25698. state.trailingSpaceNewLine = false;
  25699. state.f = state.block;
  25700. var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
  25701. var difference = Math.floor((indentation - state.indentation) / 4) * 4;
  25702. if (difference > 4) difference = 4;
  25703. var adjustedIndentation = state.indentation + difference;
  25704. state.indentationDiff = adjustedIndentation - state.indentation;
  25705. state.indentation = adjustedIndentation;
  25706. if (indentation > 0) return null;
  25707. }
  25708. var result = state.f(stream, state);
  25709. if (stream.start == stream.pos) return this.token(stream, state);
  25710. else return result;
  25711. },
  25712. innerMode: function(state) {
  25713. if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};
  25714. if (state.localState) return {state: state.localState, mode: state.localMode};
  25715. return {state: state, mode: mode};
  25716. },
  25717. blankLine: blankLine,
  25718. getType: getType,
  25719. fold: "markdown"
  25720. };
  25721. return mode;
  25722. }, "xml");
  25723. CodeMirror.defineMIME("text/x-markdown", "markdown");
  25724. });
  25725. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  25726. // Distributed under an MIT license: http://codemirror.net/LICENSE
  25727. // Utility function that allows modes to be combined. The mode given
  25728. // as the base argument takes care of most of the normal mode
  25729. // functionality, but a second (typically simple) mode is used, which
  25730. // can override the style of text. Both modes get to parse all of the
  25731. // text, but when both assign a non-null style to a piece of code, the
  25732. // overlay wins, unless the combine argument was true and not overridden,
  25733. // or state.overlay.combineTokens was true, in which case the styles are
  25734. // combined.
  25735. (function(mod) {
  25736. if (typeof exports == "object" && typeof module == "object") // CommonJS
  25737. mod(require("../../lib/codemirror"));
  25738. else if (typeof define == "function" && define.amd) // AMD
  25739. define(["../../lib/codemirror"], mod);
  25740. else // Plain browser env
  25741. mod(CodeMirror);
  25742. })(function(CodeMirror) {
  25743. "use strict";
  25744. CodeMirror.overlayMode = function(base, overlay, combine) {
  25745. return {
  25746. startState: function() {
  25747. return {
  25748. base: CodeMirror.startState(base),
  25749. overlay: CodeMirror.startState(overlay),
  25750. basePos: 0, baseCur: null,
  25751. overlayPos: 0, overlayCur: null,
  25752. lineSeen: null
  25753. };
  25754. },
  25755. copyState: function(state) {
  25756. return {
  25757. base: CodeMirror.copyState(base, state.base),
  25758. overlay: CodeMirror.copyState(overlay, state.overlay),
  25759. basePos: state.basePos, baseCur: null,
  25760. overlayPos: state.overlayPos, overlayCur: null
  25761. };
  25762. },
  25763. token: function(stream, state) {
  25764. if (stream.sol() || stream.string != state.lineSeen ||
  25765. Math.min(state.basePos, state.overlayPos) < stream.start) {
  25766. state.lineSeen = stream.string;
  25767. state.basePos = state.overlayPos = stream.start;
  25768. }
  25769. if (stream.start == state.basePos) {
  25770. state.baseCur = base.token(stream, state.base);
  25771. state.basePos = stream.pos;
  25772. }
  25773. if (stream.start == state.overlayPos) {
  25774. stream.pos = stream.start;
  25775. state.overlayCur = overlay.token(stream, state.overlay);
  25776. state.overlayPos = stream.pos;
  25777. }
  25778. stream.pos = Math.min(state.basePos, state.overlayPos);
  25779. // state.overlay.combineTokens always takes precedence over combine,
  25780. // unless set to null
  25781. if (state.overlayCur == null) return state.baseCur;
  25782. else if (state.baseCur != null &&
  25783. state.overlay.combineTokens ||
  25784. combine && state.overlay.combineTokens == null)
  25785. return state.baseCur + " " + state.overlayCur;
  25786. else return state.overlayCur;
  25787. },
  25788. indent: base.indent && function(state, textAfter) {
  25789. return base.indent(state.base, textAfter);
  25790. },
  25791. electricChars: base.electricChars,
  25792. innerMode: function(state) { return {state: state.base, mode: base}; },
  25793. blankLine: function(state) {
  25794. if (base.blankLine) base.blankLine(state.base);
  25795. if (overlay.blankLine) overlay.blankLine(state.overlay);
  25796. }
  25797. };
  25798. };
  25799. });
  25800. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  25801. // Distributed under an MIT license: http://codemirror.net/LICENSE
  25802. (function(mod) {
  25803. if (typeof exports == "object" && typeof module == "object") // CommonJS
  25804. mod(require("../../lib/codemirror"), require("../markdown/markdown"), require("../../addon/mode/overlay"));
  25805. else if (typeof define == "function" && define.amd) // AMD
  25806. define(["../../lib/codemirror", "../markdown/markdown", "../../addon/mode/overlay"], mod);
  25807. else // Plain browser env
  25808. mod(CodeMirror);
  25809. })(function(CodeMirror) {
  25810. "use strict";
  25811. CodeMirror.defineMode("gfm", function(config, modeConfig) {
  25812. var codeDepth = 0;
  25813. function blankLine(state) {
  25814. state.code = false;
  25815. return null;
  25816. }
  25817. var gfmOverlay = {
  25818. startState: function() {
  25819. return {
  25820. code: false,
  25821. codeBlock: false,
  25822. ateSpace: false
  25823. };
  25824. },
  25825. copyState: function(s) {
  25826. return {
  25827. code: s.code,
  25828. codeBlock: s.codeBlock,
  25829. ateSpace: s.ateSpace
  25830. };
  25831. },
  25832. token: function(stream, state) {
  25833. state.combineTokens = null;
  25834. // Hack to prevent formatting override inside code blocks (block and inline)
  25835. if (state.codeBlock) {
  25836. if (stream.match(/^```/)) {
  25837. state.codeBlock = false;
  25838. return null;
  25839. }
  25840. stream.skipToEnd();
  25841. return null;
  25842. }
  25843. if (stream.sol()) {
  25844. state.code = false;
  25845. }
  25846. if (stream.sol() && stream.match(/^```/)) {
  25847. stream.skipToEnd();
  25848. state.codeBlock = true;
  25849. return null;
  25850. }
  25851. // If this block is changed, it may need to be updated in Markdown mode
  25852. if (stream.peek() === '`') {
  25853. stream.next();
  25854. var before = stream.pos;
  25855. stream.eatWhile('`');
  25856. var difference = 1 + stream.pos - before;
  25857. if (!state.code) {
  25858. codeDepth = difference;
  25859. state.code = true;
  25860. } else {
  25861. if (difference === codeDepth) { // Must be exact
  25862. state.code = false;
  25863. }
  25864. }
  25865. return null;
  25866. } else if (state.code) {
  25867. stream.next();
  25868. return null;
  25869. }
  25870. // Check if space. If so, links can be formatted later on
  25871. if (stream.eatSpace()) {
  25872. state.ateSpace = true;
  25873. return null;
  25874. }
  25875. if (stream.sol() || state.ateSpace) {
  25876. state.ateSpace = false;
  25877. if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
  25878. // User/Project@SHA
  25879. // User@SHA
  25880. // SHA
  25881. state.combineTokens = true;
  25882. return "link";
  25883. } else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) {
  25884. // User/Project#Num
  25885. // User#Num
  25886. // #Num
  25887. state.combineTokens = true;
  25888. return "link";
  25889. }
  25890. }
  25891. if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i) &&
  25892. stream.string.slice(stream.start - 2, stream.start) != "](") {
  25893. // URLs
  25894. // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
  25895. // And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
  25896. state.combineTokens = true;
  25897. return "link";
  25898. }
  25899. stream.next();
  25900. return null;
  25901. },
  25902. blankLine: blankLine
  25903. };
  25904. var markdownConfig = {
  25905. underscoresBreakWords: false,
  25906. taskLists: true,
  25907. fencedCodeBlocks: true
  25908. };
  25909. for (var attr in modeConfig) {
  25910. markdownConfig[attr] = modeConfig[attr];
  25911. }
  25912. markdownConfig.name = "markdown";
  25913. CodeMirror.defineMIME("gfmBase", markdownConfig);
  25914. return CodeMirror.overlayMode(CodeMirror.getMode(config, "gfmBase"), gfmOverlay);
  25915. }, "markdown");
  25916. });
  25917. /*!
  25918. * ====================================================
  25919. * kity - v2.0.0 - 2015-01-12
  25920. * https://github.com/fex-team/kity
  25921. * GitHub: https://github.com/fex-team/kity.git
  25922. * Copyright (c) 2015 Baidu FEX; Licensed BSD
  25923. * ====================================================
  25924. */
  25925. (function () {
  25926. var _p = {
  25927. r: function(index) {
  25928. if (_p[index].inited) {
  25929. return _p[index].value;
  25930. }
  25931. if (typeof _p[index].value === "function") {
  25932. var module = {
  25933. exports: {}
  25934. }, returnValue = _p[index].value(null, module.exports, module);
  25935. _p[index].inited = true;
  25936. _p[index].value = returnValue;
  25937. if (returnValue !== undefined) {
  25938. return returnValue;
  25939. } else {
  25940. for (var key in module.exports) {
  25941. if (module.exports.hasOwnProperty(key)) {
  25942. _p[index].inited = true;
  25943. _p[index].value = module.exports;
  25944. return module.exports;
  25945. }
  25946. }
  25947. }
  25948. } else {
  25949. _p[index].inited = true;
  25950. return _p[index].value;
  25951. }
  25952. }
  25953. };
  25954. //src/animate/animator.js
  25955. /**
  25956. * @fileOverview
  25957. *
  25958. * 提供基本的动画支持
  25959. */
  25960. _p[0] = {
  25961. value: function(require) {
  25962. function parseTime(str) {
  25963. var value = parseFloat(str, 10);
  25964. if (/ms/.test(str)) {
  25965. return value;
  25966. }
  25967. if (/s/.test(str)) {
  25968. return value * 1e3;
  25969. }
  25970. if (/min/.test(str)) {
  25971. return value * 60 * 1e3;
  25972. }
  25973. return value;
  25974. }
  25975. var Timeline = _p.r(8);
  25976. var easingTable = _p.r(1);
  25977. /**
  25978. * @class kity.Animator
  25979. * @catalog animate
  25980. * @description 表示一个动画启动器,可以作用于不同的对象进行动画
  25981. */
  25982. var Animator = _p.r(11).createClass("Animator", {
  25983. /**
  25984. * @constructor
  25985. * @for kity.Animator
  25986. * @catalog animate
  25987. *
  25988. * @grammar new kity.Animator(beginValue, finishValue, setter)
  25989. * @grammar new kity.Animator(option)
  25990. *
  25991. * @param {any} beginValue|opt.beginValue
  25992. * 动画的起始值,允许的类型有数字、数组、字面量、kity.Point、kity.Vector、kity.Box、kity.Matrix
  25993. *
  25994. * @param {any} finishValue|opt.beginValue
  25995. * 动画的结束值,类型应于起始值相同
  25996. *
  25997. * @param {Function} setter|opt.setter
  25998. * 值的使用函数,接受三个参数: function(target, value, timeline)
  25999. * target {object} 动画的目标
  26000. * value {any} 动画的当前值
  26001. * timeline {kity.Timeline} 动画当前的时间线对象
  26002. */
  26003. constructor: function(beginValue, finishValue, setter) {
  26004. if (arguments.length == 1) {
  26005. var opt = arguments[0];
  26006. this.beginValue = opt.beginValue;
  26007. this.finishValue = opt.finishValue;
  26008. this.setter = opt.setter;
  26009. } else {
  26010. this.beginValue = beginValue;
  26011. this.finishValue = finishValue;
  26012. this.setter = setter;
  26013. }
  26014. },
  26015. /**
  26016. * @method start()
  26017. * @for kity.Animator
  26018. * @description 使用当前的动画器启动在指定目标上启动动画
  26019. *
  26020. * @grammar start(target, duration, easing, delay, callback) => {kity.Timeline}
  26021. * @grammar start(target, option) => {kity.Timeline}
  26022. *
  26023. * @param {object} target
  26024. * 启动动画的目标
  26025. *
  26026. * @param {Number|String} duration|option.duration
  26027. * [Optional] 动画的持续时间,如 300、"300ms"、"1.5min"
  26028. *
  26029. * @param {String|Function} easing|option.easing
  26030. * [Optional] 动画使用的缓动函数,如 "ease"、"linear"、"swing"
  26031. *
  26032. * @param {Number|String} delay|option.delay
  26033. * [Optional] 动画的播放延迟时间
  26034. *
  26035. * @param {Function} callback|option.callback
  26036. * [Optional] 动画结束后的回调函数
  26037. *
  26038. * @example
  26039. *
  26040. * ```js
  26041. * var turnRed = new kity.Animator(
  26042. * new kity.Color('yellow'),
  26043. * new kity.Color('red'),
  26044. * function(target, value) {
  26045. * target.fill(value);
  26046. * });
  26047. *
  26048. * turnRed.start(rect, 300, 'ease', function() {
  26049. * console.log('I am red!');
  26050. * });
  26051. * ```
  26052. */
  26053. start: function(target, duration, easing, delay, callback) {
  26054. if (arguments.length === 2 && typeof duration == "object") {
  26055. easing = duration.easing;
  26056. delay = duration.delay;
  26057. callback = duration.callback;
  26058. duration = duration.duration;
  26059. }
  26060. if (arguments.length === 4 && typeof delay == "function") {
  26061. callback = delay;
  26062. delay = 0;
  26063. }
  26064. var timeline = this.create(target, duration, easing, callback);
  26065. delay = parseTime(delay);
  26066. if (delay > 0) {
  26067. setTimeout(function() {
  26068. timeline.play();
  26069. }, delay);
  26070. } else {
  26071. timeline.play();
  26072. }
  26073. return timeline;
  26074. },
  26075. /**
  26076. * @method create()
  26077. * @for kity.Animator
  26078. * @description 使用当前的动画器为指定目标创建时间线
  26079. *
  26080. * @grammar create(target, duration, easing, callback) => {kity.Timeline}
  26081. *
  26082. * @param {object} target 要创建的时间线的目标
  26083. * @param {Number|String} duration 要创建的时间线的长度,如 300、"5s"、"0.5min"
  26084. * @param {String|Function} easing 要创建的时间线的缓动函数,如 'ease'、'linear'、'swing'
  26085. * @param {Function} callback 时间线播放结束之后的回调函数
  26086. *
  26087. * @example
  26088. *
  26089. * ```js
  26090. * var expand = new kity.Animator({
  26091. * beginValue: function(target) {
  26092. * return target.getBox();
  26093. * },
  26094. * finishValue: function(target) {
  26095. * return target.getBox().expand(100, 100, 100, 100);
  26096. * },
  26097. * setter: function(target, value) {
  26098. * target.setBox(value)
  26099. * }
  26100. * });
  26101. *
  26102. * var timeline = expand.create(rect, 300);
  26103. * timeline.repeat(3).play();
  26104. * ```
  26105. */
  26106. create: function(target, duration, easing, callback) {
  26107. var timeline;
  26108. duration = duration && parseTime(duration) || Animator.DEFAULT_DURATION;
  26109. easing = easing || Animator.DEFAULT_EASING;
  26110. if (typeof easing == "string") {
  26111. easing = easingTable[easing];
  26112. }
  26113. timeline = new Timeline(this, target, duration, easing);
  26114. if (typeof callback == "function") {
  26115. timeline.on("finish", callback);
  26116. }
  26117. return timeline;
  26118. },
  26119. /**
  26120. * @method reverse()
  26121. * @for kity.Animator
  26122. * @grammar reverse() => {kity.Animator}
  26123. * @description 创建一个与当前动画器相反的动画器
  26124. *
  26125. * @example
  26126. *
  26127. * ```js
  26128. * var turnYellow = turnRed.reverse();
  26129. * ```
  26130. */
  26131. reverse: function() {
  26132. return new Animator(this.finishValue, this.beginValue, this.setter);
  26133. }
  26134. });
  26135. Animator.DEFAULT_DURATION = 300;
  26136. Animator.DEFAULT_EASING = "linear";
  26137. var Shape = _p.r(60);
  26138. _p.r(11).extendClass(Shape, {
  26139. /**
  26140. * @method animate()
  26141. * @for kity.Shape
  26142. * @description 在图形上播放使用指定的动画器播放动画,如果图形当前有动画正在播放,则会加入播放队列
  26143. *
  26144. * @grammar animate(animator, duration, easing, delay, callback)
  26145. *
  26146. * @param {object} animator 播放动画使用的动画器
  26147. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26148. * @param {Number|String} delay 动画播放前的延时
  26149. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26150. * @param {Function} callback 播放结束之后的回调函数
  26151. *
  26152. * @example
  26153. *
  26154. * ```js
  26155. * rect.animate(turnRed, 300); // turnRect 是一个动画器
  26156. * rect.animate(expand, 500); // turnRect 播放结束后播放 expand
  26157. * ```
  26158. */
  26159. animate: function(animator, duration, easing, delay, callback) {
  26160. var queue = this._KityAnimateQueue = this._KityAnimateQueue || [];
  26161. var timeline = animator.create(this, duration, easing, callback);
  26162. function dequeue() {
  26163. queue.shift();
  26164. if (queue.length) {
  26165. setTimeout(queue[0].t.play.bind(queue[0].t), queue[0].d);
  26166. }
  26167. }
  26168. timeline.on("finish", dequeue);
  26169. queue.push({
  26170. t: timeline,
  26171. d: delay
  26172. });
  26173. if (queue.length == 1) {
  26174. setTimeout(timeline.play.bind(timeline), delay);
  26175. }
  26176. return this;
  26177. },
  26178. /**
  26179. * @method timeline()
  26180. * @for kity.Shape
  26181. * @description 获得当前正在播放的动画的时间线
  26182. *
  26183. * @grammar timeline() => {kity.Timeline}
  26184. *
  26185. * @example
  26186. *
  26187. * ```js
  26188. * rect.timeline().repeat(2);
  26189. * ```
  26190. */
  26191. timeline: function() {
  26192. return this._KityAnimateQueue[0].t;
  26193. },
  26194. /**
  26195. * @method stop()
  26196. * @for kity.Shape
  26197. * @description 停止当前正在播放的动画
  26198. *
  26199. * @grammar stop() => {this}
  26200. *
  26201. * @example
  26202. *
  26203. * ```js
  26204. * rect.stop(); // 停止 rect 上的动画
  26205. * ```
  26206. */
  26207. stop: function() {
  26208. var queue = this._KityAnimateQueue;
  26209. if (queue) {
  26210. while (queue.length) {
  26211. queue.shift().t.stop();
  26212. }
  26213. }
  26214. return this;
  26215. }
  26216. });
  26217. return Animator;
  26218. }
  26219. };
  26220. //src/animate/easing.js
  26221. /**
  26222. * Kity Animate Easing modified from jQuery Easing
  26223. * Author: techird
  26224. * Changes:
  26225. * 1. make easing functions standalone
  26226. * 2. remove the 'x' parameter
  26227. */
  26228. /* ============================================================
  26229. * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
  26230. *
  26231. * Open source under the BSD License.
  26232. *
  26233. * Copyright © 2008 George McGinley Smith
  26234. * All rights reserved.
  26235. * https://raw.github.com/danro/jquery-easing/master/LICENSE
  26236. * ======================================================== */
  26237. _p[1] = {
  26238. value: function(require, exports, module) {
  26239. var easings = {
  26240. // t: current_time, b: begin_value, c: change_value, d: duration
  26241. linear: function(t, b, c, d) {
  26242. return c * (t / d) + b;
  26243. },
  26244. swing: function(t, b, c, d) {
  26245. return easings.easeOutQuad(t, b, c, d);
  26246. },
  26247. ease: function(t, b, c, d) {
  26248. return easings.easeInOutCubic(t, b, c, d);
  26249. },
  26250. easeInQuad: function(t, b, c, d) {
  26251. return c * (t /= d) * t + b;
  26252. },
  26253. easeOutQuad: function(t, b, c, d) {
  26254. return -c * (t /= d) * (t - 2) + b;
  26255. },
  26256. easeInOutQuad: function(t, b, c, d) {
  26257. if ((t /= d / 2) < 1) return c / 2 * t * t + b;
  26258. return -c / 2 * (--t * (t - 2) - 1) + b;
  26259. },
  26260. easeInCubic: function(t, b, c, d) {
  26261. return c * (t /= d) * t * t + b;
  26262. },
  26263. easeOutCubic: function(t, b, c, d) {
  26264. return c * ((t = t / d - 1) * t * t + 1) + b;
  26265. },
  26266. easeInOutCubic: function(t, b, c, d) {
  26267. if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
  26268. return c / 2 * ((t -= 2) * t * t + 2) + b;
  26269. },
  26270. easeInQuart: function(t, b, c, d) {
  26271. return c * (t /= d) * t * t * t + b;
  26272. },
  26273. easeOutQuart: function(t, b, c, d) {
  26274. return -c * ((t = t / d - 1) * t * t * t - 1) + b;
  26275. },
  26276. easeInOutQuart: function(t, b, c, d) {
  26277. if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
  26278. return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
  26279. },
  26280. easeInQuint: function(t, b, c, d) {
  26281. return c * (t /= d) * t * t * t * t + b;
  26282. },
  26283. easeOutQuint: function(t, b, c, d) {
  26284. return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
  26285. },
  26286. easeInOutQuint: function(t, b, c, d) {
  26287. if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
  26288. return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
  26289. },
  26290. easeInSine: function(t, b, c, d) {
  26291. return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
  26292. },
  26293. easeOutSine: function(t, b, c, d) {
  26294. return c * Math.sin(t / d * (Math.PI / 2)) + b;
  26295. },
  26296. easeInOutSine: function(t, b, c, d) {
  26297. return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
  26298. },
  26299. easeInExpo: function(t, b, c, d) {
  26300. return t === 0 ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
  26301. },
  26302. easeOutExpo: function(t, b, c, d) {
  26303. return t == d ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
  26304. },
  26305. easeInOutExpo: function(t, b, c, d) {
  26306. if (t === 0) return b;
  26307. if (t == d) return b + c;
  26308. if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
  26309. return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
  26310. },
  26311. easeInCirc: function(t, b, c, d) {
  26312. return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
  26313. },
  26314. easeOutCirc: function(t, b, c, d) {
  26315. return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
  26316. },
  26317. easeInOutCirc: function(t, b, c, d) {
  26318. if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
  26319. return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
  26320. },
  26321. easeInElastic: function(t, b, c, d) {
  26322. var s = 1.70158;
  26323. var p = 0;
  26324. var a = c;
  26325. if (t === 0) return b;
  26326. if ((t /= d) == 1) return b + c;
  26327. if (!p) p = d * .3;
  26328. if (a < Math.abs(c)) {
  26329. a = c;
  26330. s = p / 4;
  26331. } else s = p / (2 * Math.PI) * Math.asin(c / a);
  26332. return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
  26333. },
  26334. easeOutElastic: function(t, b, c, d) {
  26335. var s = 1.70158;
  26336. var p = 0;
  26337. var a = c;
  26338. if (t === 0) return b;
  26339. if ((t /= d) == 1) return b + c;
  26340. if (!p) p = d * .3;
  26341. if (a < Math.abs(c)) {
  26342. a = c;
  26343. s = p / 4;
  26344. } else s = p / (2 * Math.PI) * Math.asin(c / a);
  26345. return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
  26346. },
  26347. easeInOutElastic: function(t, b, c, d) {
  26348. var s = 1.70158;
  26349. var p = 0;
  26350. var a = c;
  26351. if (t === 0) return b;
  26352. if ((t /= d / 2) == 2) return b + c;
  26353. if (!p) p = d * (.3 * 1.5);
  26354. if (a < Math.abs(c)) {
  26355. a = c;
  26356. var s = p / 4;
  26357. } else var s = p / (2 * Math.PI) * Math.asin(c / a);
  26358. if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
  26359. return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
  26360. },
  26361. easeInBack: function(t, b, c, d, s) {
  26362. if (s == undefined) s = 1.70158;
  26363. return c * (t /= d) * t * ((s + 1) * t - s) + b;
  26364. },
  26365. easeOutBack: function(t, b, c, d, s) {
  26366. if (s == undefined) s = 1.70158;
  26367. return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
  26368. },
  26369. easeInOutBack: function(t, b, c, d, s) {
  26370. if (s == undefined) s = 1.70158;
  26371. if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= 1.525) + 1) * t - s)) + b;
  26372. return c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b;
  26373. },
  26374. easeInBounce: function(t, b, c, d) {
  26375. return c - easings.easeOutBounce(d - t, 0, c, d) + b;
  26376. },
  26377. easeOutBounce: function(t, b, c, d) {
  26378. if ((t /= d) < 1 / 2.75) {
  26379. return c * (7.5625 * t * t) + b;
  26380. } else if (t < 2 / 2.75) {
  26381. return c * (7.5625 * (t -= 1.5 / 2.75) * t + .75) + b;
  26382. } else if (t < 2.5 / 2.75) {
  26383. return c * (7.5625 * (t -= 2.25 / 2.75) * t + .9375) + b;
  26384. } else {
  26385. return c * (7.5625 * (t -= 2.625 / 2.75) * t + .984375) + b;
  26386. }
  26387. },
  26388. easeInOutBounce: function(t, b, c, d) {
  26389. if (t < d / 2) return easings.easeInBounce(t * 2, 0, c, d) * .5 + b;
  26390. return easings.easeOutBounce(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
  26391. }
  26392. };
  26393. return easings;
  26394. }
  26395. };
  26396. /*
  26397. *
  26398. * TERMS OF USE - EASING EQUATIONS
  26399. *
  26400. * Open source under the BSD License.
  26401. *
  26402. * Copyright © 2001 Robert Penner
  26403. * All rights reserved.
  26404. *
  26405. * Redistribution and use in source and binary forms, with or without modification,
  26406. * are permitted provided that the following conditions are met:
  26407. *
  26408. * Redistributions of source code must retain the above copyright notice, this list of
  26409. * conditions and the following disclaimer.
  26410. * Redistributions in binary form must reproduce the above copyright notice, this list
  26411. * of conditions and the following disclaimer in the documentation and/or other materials
  26412. * provided with the distribution.
  26413. *
  26414. * Neither the name of the author nor the names of contributors may be used to endorse
  26415. * or promote products derived from this software without specific prior written permission.
  26416. *
  26417. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  26418. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  26419. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26420. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26421. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  26422. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  26423. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  26424. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  26425. * OF THE POSSIBILITY OF SUCH DAMAGE.
  26426. *
  26427. */
  26428. //src/animate/frame.js
  26429. /**
  26430. * @fileOverview
  26431. *
  26432. * 提供动画帧的基本支持
  26433. */
  26434. _p[2] = {
  26435. value: function(require, exports) {
  26436. // 原生动画帧方法 polyfill
  26437. var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(fn) {
  26438. return setTimeout(fn, 1e3 / 60);
  26439. };
  26440. var cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame || window.clearTimeout;
  26441. // 上一个请求的原生动画帧 id
  26442. var frameRequestId;
  26443. // 等待执行的帧动作的集合,这些帧的方法将在下个原生动画帧同步执行
  26444. var pendingFrames = [];
  26445. /**
  26446. * 添加一个帧到等待集合中
  26447. *
  26448. * 如果添加的帧是序列的第一个,至少有一个帧需要被执行,则会请求一个原生动画帧来执行
  26449. */
  26450. function pushFrame(frame) {
  26451. if (pendingFrames.push(frame) === 1) {
  26452. frameRequestId = requestAnimationFrame(executePendingFrames);
  26453. }
  26454. }
  26455. /**
  26456. * 执行所有等待帧
  26457. */
  26458. function executePendingFrames() {
  26459. var frames = pendingFrames;
  26460. pendingFrames = [];
  26461. while (frames.length) {
  26462. executeFrame(frames.pop());
  26463. }
  26464. frameRequestId = 0;
  26465. }
  26466. /**
  26467. * @method kity.requestFrame
  26468. * @catalog animate
  26469. * @grammar kity.requestFrame(action) => {frame}
  26470. * @description 请求一个帧,执行指定的动作。动作回调提供一些有用的信息
  26471. *
  26472. * @param {Function} action
  26473. *
  26474. * 要执行的动作,该动作回调有一个参数 frame,其中:
  26475. *
  26476. * frame.time {Number}
  26477. * 动作执行时的时间戳(ms)
  26478. *
  26479. * frame.index {Number}
  26480. * 当前执行的帧的编号(首帧为 0)
  26481. *
  26482. * frame.dur {Number}
  26483. * 上一帧至当前帧经过的时间,单位 ms
  26484. *
  26485. * frame.elapsed {Number}
  26486. * 从首帧开始到当前帧经过的时间,单位 ms
  26487. *
  26488. * frame.action {Number}
  26489. * 指向当前的帧处理函数
  26490. *
  26491. * frame.next()
  26492. * 表示下一帧继续执行。如果不调用该方法,将不会执行下一帧。
  26493. *
  26494. * @example
  26495. *
  26496. * ```js
  26497. * kity.requestFrame(function(frame) {
  26498. * console.log('平均帧率:' + frame.elapsed / (frame.index + 1));
  26499. *
  26500. * // 更新或渲染动作
  26501. *
  26502. * frame.next(); //继续执行下一帧
  26503. * });
  26504. * ```
  26505. */
  26506. function requestFrame(action) {
  26507. var frame = initFrame(action);
  26508. pushFrame(frame);
  26509. return frame;
  26510. }
  26511. /**
  26512. * @method kity.releaseFrame
  26513. * @catalog animate
  26514. * @grammar kity.releaseFrame(frame)
  26515. * @description 释放一个已经请求过的帧,如果该帧在等待集合里,将移除,下个动画帧不会执行释放的帧
  26516. *
  26517. * @param {frame} frame 使用 kity.requestFrame() 返回的帧
  26518. *
  26519. * @example
  26520. *
  26521. * ```js
  26522. * var frame = kity.requestFrame(function() {....});
  26523. * kity.releaseFrame(frame);
  26524. * ```
  26525. */
  26526. function releaseFrame(frame) {
  26527. var index = pendingFrames.indexOf(frame);
  26528. if (~index) {
  26529. pendingFrames.splice(index, 1);
  26530. }
  26531. if (pendingFrames.length === 0) {
  26532. cancelAnimationFrame(frameRequestId);
  26533. }
  26534. }
  26535. /**
  26536. * 初始化一个帧,主要用于后续计算
  26537. */
  26538. function initFrame(action) {
  26539. var frame = {
  26540. index: 0,
  26541. time: +new Date(),
  26542. elapsed: 0,
  26543. action: action,
  26544. next: function() {
  26545. pushFrame(frame);
  26546. }
  26547. };
  26548. return frame;
  26549. }
  26550. /**
  26551. * 执行一个帧动作
  26552. */
  26553. function executeFrame(frame) {
  26554. // 当前帧时间错
  26555. var time = +new Date();
  26556. // 当上一帧到当前帧经过的时间
  26557. var dur = time - frame.time;
  26558. //
  26559. // http://stackoverflow.com/questions/13133434/requestanimationframe-detect-stop
  26560. // 浏览器最小化或切换标签,requestAnimationFrame 不会执行。
  26561. // 检测时间超过 200 ms(频率小于 5Hz ) 判定为计时器暂停,重置为一帧长度
  26562. //
  26563. if (dur > 200) {
  26564. dur = 1e3 / 60;
  26565. }
  26566. frame.dur = dur;
  26567. frame.elapsed += dur;
  26568. frame.time = time;
  26569. frame.action.call(null, frame);
  26570. frame.index++;
  26571. }
  26572. // 暴露
  26573. exports.requestFrame = requestFrame;
  26574. exports.releaseFrame = releaseFrame;
  26575. }
  26576. };
  26577. //src/animate/motionanimator.js
  26578. /**
  26579. * @fileOverview
  26580. *
  26581. * 路径动画器,可以让一个物体沿着某个轨迹运动
  26582. */
  26583. _p[3] = {
  26584. value: function(require) {
  26585. var Animator = _p.r(0);
  26586. var g = _p.r(34);
  26587. var Path = _p.r(46);
  26588. var Shape = _p.r(60);
  26589. /**
  26590. * @class kity.MotionAnimator
  26591. * @catalog animate
  26592. * @base kity.Animator
  26593. * @description 路径动画器,可以让一个物体沿着某个轨迹运动
  26594. *
  26595. * @example
  26596. *
  26597. * ```js
  26598. * var motionAnimator = new MotionAnimator('M0,0C100,0,100,0,100,100L200,200');
  26599. * motionAnimator.start(rect, 3000);
  26600. * ```
  26601. */
  26602. var MotionAnimator = _p.r(11).createClass("MotionAnimator", {
  26603. base: Animator,
  26604. /**
  26605. * @constructor
  26606. * @for kity.MotionAnimator
  26607. * @grammar new kity.MotionAnimator(path, doRotate)
  26608. * @param {kity.Path|String|PathSegment} path 运动的轨迹,或者是 kity.Path 对象
  26609. * @param {boolean} doRotate 是否让运动的目标沿着路径的切线方向旋转
  26610. */
  26611. constructor: function(path, doRotate) {
  26612. var me = this;
  26613. this.callBase({
  26614. beginValue: 0,
  26615. finishValue: 1,
  26616. setter: function(target, value) {
  26617. var path = me.motionPath instanceof Path ? me.motionPath.getPathData() : me.motionPath;
  26618. var point = g.pointAtPath(path, value);
  26619. target.setTranslate(point.x, point.y);
  26620. if (this.doRotate) target.setRotate(point.tan.getAngle());
  26621. }
  26622. });
  26623. /**
  26624. * @property doRotate
  26625. * @for kity.MotionAnimator
  26626. * @type {boolean}
  26627. * @description 是否让运动的目标沿着路径的切线方向旋转
  26628. *
  26629. * @example
  26630. *
  26631. * ```js
  26632. * motionAnimator.doRotate = true; // 目标沿着切线方向旋转
  26633. * ```
  26634. */
  26635. this.doRotate = doRotate;
  26636. /**
  26637. * @property motionPath
  26638. * @for kity.MotionAnimator
  26639. * @type {kity.Path|String|PathSegment}
  26640. * @description 运动沿着的路径,可以在动画过程中更新
  26641. */
  26642. this.motionPath = path;
  26643. }
  26644. });
  26645. _p.r(11).extendClass(Shape, {
  26646. /**
  26647. * @method motion()
  26648. * @catalog animate
  26649. * @for kity.Shape
  26650. * @description 让图形沿着指定的路径运动
  26651. *
  26652. * @grammar motion(path, duration, easing, delay, callback) => this
  26653. *
  26654. * @param {kity.Path|String|PathSegment} path 运动的轨迹,或者是 kity.Path 对象
  26655. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26656. * @param {Number|String} delay 动画播放前的延时
  26657. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26658. * @param {Function} callback 播放结束之后的回调函数
  26659. */
  26660. motion: function(path, duration, easing, delay, callback) {
  26661. return this.animate(new MotionAnimator(path), duration, easing, delay, callback);
  26662. }
  26663. });
  26664. return MotionAnimator;
  26665. }
  26666. };
  26667. //src/animate/opacityanimator.js
  26668. /**
  26669. * @fileOverview
  26670. *
  26671. * 透明度动画器,让图形动画过度到指定的透明度。
  26672. */
  26673. _p[4] = {
  26674. value: function(require) {
  26675. var Animator = _p.r(0);
  26676. /**
  26677. * @class kity.OpacityAnimator
  26678. * @catalog animate
  26679. * @base kity.Animator
  26680. * @description 透明度动画器,让图形动画过度到指定的透明度
  26681. */
  26682. var OpacityAnimator = _p.r(11).createClass("OpacityAnimator", {
  26683. base: Animator,
  26684. /**
  26685. * @constructor
  26686. * @for kity.OpacityAnimator
  26687. * @grammar new kity.OpacityAnimator(opacity)
  26688. *
  26689. * @param {Number} opacity 目标透明度,取值范围 0 - 1
  26690. */
  26691. constructor: function(opacity) {
  26692. this.callBase({
  26693. beginValue: function(target) {
  26694. return target.getOpacity();
  26695. },
  26696. finishValue: opacity,
  26697. setter: function(target, value) {
  26698. target.setOpacity(value);
  26699. }
  26700. });
  26701. }
  26702. });
  26703. var Shape = _p.r(60);
  26704. _p.r(11).extendClass(Shape, {
  26705. /**
  26706. * @method fxOpacity()
  26707. * @catalog animate
  26708. * @for kity.Shape
  26709. * @description 让图形的透明度以动画的形式过渡到指定的值
  26710. *
  26711. * @grammar fxOpacity(opacity, duration, easing, delay, callback) => {this}
  26712. *
  26713. * @param {Number} opacity 动画的目标透明度
  26714. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26715. * @param {Number|String} delay 动画播放前的延时
  26716. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26717. * @param {Function} callback 播放结束之后的回调函数
  26718. */
  26719. fxOpacity: function(opacity, duration, easing, delay, callback) {
  26720. return this.animate(new OpacityAnimator(opacity), duration, easing, delay, callback);
  26721. },
  26722. /**
  26723. * @method fadeTo()
  26724. * @catalog animate
  26725. * @for kity.Shape
  26726. * @description 让图形的透明度以动画的形式过渡到指定的值
  26727. *
  26728. * @grammar fadeTo(opacity, duration, easing, delay, callback) => {this}
  26729. *
  26730. * @param {Number} opacity 动画的目标透明度
  26731. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26732. * @param {Number|String} delay 动画播放前的延时
  26733. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26734. * @param {Function} callback 播放结束之后的回调函数
  26735. */
  26736. fadeTo: function() {
  26737. return this.fxOpacity.apply(this, arguments);
  26738. },
  26739. /**
  26740. * @method fadeIn()
  26741. * @catalog animate
  26742. * @for kity.Shape
  26743. * @description 让图形淡入
  26744. *
  26745. * @grammar fadeIn(duration, easing, delay, callback) => {this}
  26746. *
  26747. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26748. * @param {Number|String} delay 动画播放前的延时
  26749. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26750. * @param {Function} callback 播放结束之后的回调函数
  26751. */
  26752. fadeIn: function() {
  26753. return this.fxOpacity.apply(this, [ 1 ].concat([].slice.call(arguments)));
  26754. },
  26755. /**
  26756. * @method fadeOut()
  26757. * @catalog animate
  26758. * @for kity.Shape
  26759. * @description 让图形淡出
  26760. *
  26761. * @grammar fadeIn(duration, easing, delay, callback) => {this}
  26762. *
  26763. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26764. * @param {Number|String} delay 动画播放前的延时
  26765. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26766. * @param {Function} callback 播放结束之后的回调函数
  26767. */
  26768. fadeOut: function() {
  26769. return this.fxOpacity.apply(this, [ 0 ].concat([].slice.call(arguments)));
  26770. }
  26771. });
  26772. return OpacityAnimator;
  26773. }
  26774. };
  26775. //src/animate/pathanimator.js
  26776. /**
  26777. * @fileOverview
  26778. *
  26779. * 路径补间动画器,让图形从一个形状变为另一个形状
  26780. */
  26781. _p[5] = {
  26782. value: function(require) {
  26783. var Animator = _p.r(0);
  26784. var g = _p.r(34);
  26785. /**
  26786. * @catalog animate
  26787. *
  26788. * @class kity.PathAnimator
  26789. * @base kity.Animator
  26790. * @description 路径补间动画器,让图形从一个形状变为另一个形状
  26791. *
  26792. * @example
  26793. *
  26794. * ```js
  26795. * var path = new kity.Path('M0,0L0,100');
  26796. * var pa = new kity.PathAnimator('M0,0C100,0,100,0,100,100');
  26797. * pa.start(path, 300);
  26798. * ```
  26799. */
  26800. var PathAnimator = _p.r(11).createClass("OpacityAnimator", {
  26801. base: Animator,
  26802. /**
  26803. * @constructor
  26804. * @for kity.PathAnimator
  26805. *
  26806. * @grammar new kity.Path.Animator(path)
  26807. *
  26808. * @param {String|PathSegment} path 目标形状的路径数据
  26809. *
  26810. */
  26811. constructor: function(path) {
  26812. this.callBase({
  26813. beginValue: function(target) {
  26814. this.beginPath = target.getPathData();
  26815. return 0;
  26816. },
  26817. finishValue: 1,
  26818. setter: function(target, value) {
  26819. target.setPathData(g.pathTween(this.beginPath, path, value));
  26820. }
  26821. });
  26822. }
  26823. });
  26824. var Path = _p.r(46);
  26825. _p.r(11).extendClass(Path, {
  26826. /**
  26827. * @catalog animate
  26828. *
  26829. * @method fxPath()
  26830. * @for kity.Shape
  26831. * @description 以动画的形式把路径变换为新路径
  26832. *
  26833. * @grammar fxPath(path, duration, easing, delay, callback) => {this}
  26834. *
  26835. * @param {String|PathSegment} path 要变换新路径
  26836. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26837. * @param {Number|String} delay 动画播放前的延时
  26838. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26839. * @param {Function} callback 播放结束之后的回调函数
  26840. */
  26841. fxPath: function(path, duration, easing, delay, callback) {
  26842. return this.animate(new PathAnimator(path), duration, easing, delay, callback);
  26843. }
  26844. });
  26845. return PathAnimator;
  26846. }
  26847. };
  26848. //src/animate/rotateanimator.js
  26849. /**
  26850. * @fileOverview
  26851. *
  26852. * 提供支持目标旋转的动画器
  26853. */
  26854. _p[6] = {
  26855. value: function(require) {
  26856. var Animator = _p.r(0);
  26857. /**
  26858. * @class kity.RotateAnimator
  26859. * @base Animator
  26860. * @description 提供支持目标旋转的动画器
  26861. */
  26862. var RotateAnimator = _p.r(11).createClass("RotateAnimator", {
  26863. base: Animator,
  26864. /**
  26865. * @constructor
  26866. * @for kity.RotateAnimator
  26867. *
  26868. * @grammar new kity.RotateAnimator(deg, ax, ay)
  26869. *
  26870. * @param {Number} deg 要旋转的角度
  26871. */
  26872. constructor: function(deg) {
  26873. this.callBase({
  26874. beginValue: 0,
  26875. finishValue: deg,
  26876. setter: function(target, value, timeline) {
  26877. var delta = timeline.getDelta();
  26878. target.rotate(delta, ax, ay);
  26879. }
  26880. });
  26881. }
  26882. });
  26883. var Shape = _p.r(60);
  26884. _p.r(11).extendClass(Shape, {
  26885. /**
  26886. * @method fxRotate()
  26887. * @for kity.Shape
  26888. * @description 让目标以动画旋转指定的角度
  26889. *
  26890. * @grammar fxRotate(deg, duration, easing, delay) => {this}
  26891. *
  26892. * @param {Number} deg 要旋转的角度
  26893. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26894. * @param {Number|String} delay 动画播放前的延时
  26895. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26896. * @param {Function} callback 播放结束之后的回调函数
  26897. */
  26898. fxRotate: function(deg, duration, easing, delay, callback) {
  26899. return this.animate(new RotateAnimator(deg), duration, easing, delay, callback);
  26900. }
  26901. });
  26902. return RotateAnimator;
  26903. }
  26904. };
  26905. //src/animate/scaleanimator.js
  26906. /**
  26907. * @fileOverview
  26908. *
  26909. * 提供支持目标缩放的动画器
  26910. */
  26911. _p[7] = {
  26912. value: function(require) {
  26913. var Animator = _p.r(0);
  26914. /**
  26915. * @class kity.ScaleAnimator
  26916. * @base kity.Animator
  26917. * @description 提供支持目标缩放的动画器
  26918. */
  26919. var ScaleAnimator = _p.r(11).createClass("ScaleAnimator", {
  26920. base: Animator,
  26921. /**
  26922. * @constructor
  26923. * @for kity.ScaleAnimator
  26924. *
  26925. * @grammar new kity.ScaleAnimator(sx, sy)
  26926. * @param {Number} sx x 轴的缩放比例
  26927. * @param {Number} sy y 轴的缩放比例
  26928. */
  26929. constructor: function(sx, sy) {
  26930. this.callBase({
  26931. beginValue: 0,
  26932. finishValue: 1,
  26933. setter: function(target, value, timeline) {
  26934. var delta = timeline.getDelta();
  26935. var kx = Math.pow(sx, delta);
  26936. var ky = Math.pow(sy, delta);
  26937. target.scale(ky, kx);
  26938. }
  26939. });
  26940. }
  26941. });
  26942. var Shape = _p.r(60);
  26943. _p.r(11).extendClass(Shape, {
  26944. /**
  26945. * @method fxScale
  26946. * @for kity.Shape
  26947. * @description 动画缩放当前的图形
  26948. *
  26949. * @grammar fxScale(sx, sy, duration, easing, delay, callback) => {this}
  26950. *
  26951. * @param {Number} sx x 轴的缩放比例
  26952. * @param {Number} sy y 轴的缩放比例
  26953. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  26954. * @param {Number|String} delay 动画播放前的延时
  26955. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  26956. * @param {Function} callback 播放结束之后的回调函数
  26957. */
  26958. fxScale: function(sx, sy, duration, easing, delay, callback) {
  26959. return this.animate(new ScaleAnimator(sx, sy), duration, easing, delay, callback);
  26960. }
  26961. });
  26962. return ScaleAnimator;
  26963. }
  26964. };
  26965. //src/animate/timeline.js
  26966. /**
  26967. * @fileOverview
  26968. *
  26969. * 动画时间线的实现
  26970. */
  26971. _p[8] = {
  26972. value: function(require) {
  26973. var EventHandler = _p.r(33);
  26974. var utils = _p.r(12);
  26975. var frame = _p.r(2);
  26976. function getPercentValue(b, f, p) {
  26977. return utils.paralle(b, f, function(b, f) {
  26978. return b + (f - b) * p;
  26979. });
  26980. }
  26981. function getDelta(v1, v2) {
  26982. return utils.paralle(v1, v2, function(v1, v2) {
  26983. return v2 - v1;
  26984. });
  26985. }
  26986. function TimelineEvent(timeline, type, param) {
  26987. this.timeline = timeline;
  26988. this.target = timeline.target;
  26989. this.type = type;
  26990. for (var name in param) {
  26991. if (param.hasOwnProperty(name)) {
  26992. this[name] = param[name];
  26993. }
  26994. }
  26995. }
  26996. /**
  26997. * @class kity.Timeline
  26998. * @catalog animate
  26999. * @mixins EventHandler
  27000. * @description 动画时间线
  27001. */
  27002. var Timeline = _p.r(11).createClass("Timeline", {
  27003. mixins: [ EventHandler ],
  27004. /**
  27005. * @constructor
  27006. * @for kity.Timeline
  27007. * @private
  27008. * @description 时间线应该由动画器进行构造,不应手动创建
  27009. *
  27010. */
  27011. constructor: function(animator, target, duration, easing) {
  27012. this.callMixin();
  27013. this.target = target;
  27014. this.time = 0;
  27015. this.duration = duration;
  27016. this.easing = easing;
  27017. this.animator = animator;
  27018. this.beginValue = animator.beginValue;
  27019. this.finishValue = animator.finishValue;
  27020. this.setter = animator.setter;
  27021. this.status = "ready";
  27022. },
  27023. /**
  27024. * @private
  27025. *
  27026. * 让时间线进入下一帧
  27027. */
  27028. nextFrame: function(frame) {
  27029. if (this.status != "playing") {
  27030. return;
  27031. }
  27032. this.time += frame.dur;
  27033. this.setValue(this.getValue());
  27034. if (this.time >= this.duration) {
  27035. this.timeUp();
  27036. }
  27037. frame.next();
  27038. },
  27039. /**
  27040. * @method getPlayTime()
  27041. * @for kity.Timeline
  27042. * @grammar getPlayTime() => {Number}
  27043. * @description 获得当前播放的时间,取值区间为 [0, duration]
  27044. */
  27045. getPlayTime: function() {
  27046. return this.rollbacking ? this.duration - this.time : this.time;
  27047. },
  27048. /**
  27049. * @method getTimeProportion()
  27050. * @for kity.Timeline
  27051. * @grammar getTimeProportion() => {Number}
  27052. * @description 获得当前播放时间的比例,取值区间为 [0, 1]
  27053. */
  27054. getTimeProportion: function() {
  27055. return this.getPlayTime() / this.duration;
  27056. },
  27057. /**
  27058. * @method getValueProportion()
  27059. * @for kity.Timeline
  27060. * @grammar getValueProportion() => {Number}
  27061. * @description 获得当前播放时间对应值的比例,取值区间为 [0, 1];该值实际上是时间比例值经过缓动函数计算之后的值。
  27062. */
  27063. getValueProportion: function() {
  27064. return this.easing(this.getPlayTime(), 0, 1, this.duration);
  27065. },
  27066. /**
  27067. * @method getValue()
  27068. * @for kity.Timeline
  27069. * @grammar getValue() => {any}
  27070. * @description 返回当前播放时间对应的值。
  27071. */
  27072. getValue: function() {
  27073. var b = this.beginValue;
  27074. var f = this.finishValue;
  27075. var p = this.getValueProportion();
  27076. return getPercentValue(b, f, p);
  27077. },
  27078. /**
  27079. * @private
  27080. *
  27081. * 把值通过动画器的 setter 设置到目标上
  27082. */
  27083. setValue: function(value) {
  27084. this.lastValue = this.currentValue;
  27085. this.currentValue = value;
  27086. this.setter.call(this.target, this.target, value, this);
  27087. },
  27088. /**
  27089. * @method getDelta()
  27090. * @for kity.Timeline
  27091. * @grammar getDelta() => {any}
  27092. * @description 返回当前值和上一帧的值的差值
  27093. */
  27094. getDelta: function() {
  27095. this.lastValue = this.lastValue === undefined ? this.beginValue : this.lastValue;
  27096. return getDelta(this.lastValue, this.currentValue);
  27097. },
  27098. /**
  27099. * @method play()
  27100. * @for kity.Timeline
  27101. * @grammar play() => {this}
  27102. * @description 让时间线播放,如果时间线还没开始,或者已停止、已结束,则重头播放;如果是已暂停,从暂停的位置继续播放
  27103. */
  27104. play: function() {
  27105. var lastStatus = this.status;
  27106. this.status = "playing";
  27107. switch (lastStatus) {
  27108. case "ready":
  27109. if (utils.isFunction(this.beginValue)) {
  27110. this.beginValue = this.beginValue.call(this.target, this.target);
  27111. }
  27112. if (utils.isFunction(this.finishValue)) {
  27113. this.finishValue = this.finishValue.call(this.target, this.target);
  27114. }
  27115. this.time = 0;
  27116. this.setValue(this.beginValue);
  27117. this.frame = frame.requestFrame(this.nextFrame.bind(this));
  27118. break;
  27119. case "finished":
  27120. case "stoped":
  27121. this.time = 0;
  27122. this.frame = frame.requestFrame(this.nextFrame.bind(this));
  27123. break;
  27124. case "paused":
  27125. this.frame.next();
  27126. }
  27127. /**
  27128. * @event play
  27129. * @for kity.Timeline
  27130. * @description 在时间线播放后触发
  27131. *
  27132. * @param {String} event.lastStatus
  27133. * 表示播放前的上一个状态,可能取值为 'ready'、'finished'、'stoped'、'paused'
  27134. */
  27135. this.fire("play", new TimelineEvent(this, "play", {
  27136. lastStatus: lastStatus
  27137. }));
  27138. return this;
  27139. },
  27140. /**
  27141. * @method pause()
  27142. * @for kity.Timeline
  27143. * @description 暂停当前的时间线
  27144. *
  27145. * @grammar pause() => {this}
  27146. */
  27147. pause: function() {
  27148. this.status = "paused";
  27149. /**
  27150. * @event pause
  27151. * @for kity.Timeline
  27152. * @description 暂停事件,在时间线暂停时触发
  27153. */
  27154. this.fire("pause", new TimelineEvent(this, "pause"));
  27155. frame.releaseFrame(this.frame);
  27156. return this;
  27157. },
  27158. /**
  27159. * @method stop()
  27160. * @for kity.Timeline
  27161. * @description 停止当前时间线
  27162. *
  27163. * @grammar stop() => {this}
  27164. */
  27165. stop: function() {
  27166. this.status = "stoped";
  27167. this.setValue(this.finishValue);
  27168. this.rollbacking = false;
  27169. /**
  27170. * @event stop
  27171. * @for kity.Timeline
  27172. * @description 停止时间,在时间线停止时触发
  27173. */
  27174. this.fire("stop", new TimelineEvent(this, "stop"));
  27175. frame.releaseFrame(this.frame);
  27176. return this;
  27177. },
  27178. /**
  27179. * @private
  27180. *
  27181. * 播放结束之后的处理
  27182. */
  27183. timeUp: function() {
  27184. if (this.repeatOption) {
  27185. this.time = 0;
  27186. if (this.rollback) {
  27187. if (this.rollbacking) {
  27188. this.decreaseRepeat();
  27189. this.rollbacking = false;
  27190. } else {
  27191. this.rollbacking = true;
  27192. /**
  27193. * @event rollback
  27194. * @for kity.Timeline
  27195. * @description 回滚事件,在时间线回滚播放开始的时候触发
  27196. */
  27197. this.fire("rollback", new TimelineEvent(this, "rollback"));
  27198. }
  27199. } else {
  27200. this.decreaseRepeat();
  27201. }
  27202. if (!this.repeatOption) {
  27203. this.finish();
  27204. } else {
  27205. /**
  27206. * @event repeat
  27207. * @for kity.Timeline
  27208. * @description 循环事件,在时间线循环播放开始的时候触发
  27209. */
  27210. this.fire("repeat", new TimelineEvent(this, "repeat"));
  27211. }
  27212. } else {
  27213. this.finish();
  27214. }
  27215. },
  27216. /**
  27217. * @private
  27218. *
  27219. * 决定播放结束的处理
  27220. */
  27221. finish: function() {
  27222. this.setValue(this.finishValue);
  27223. this.status = "finished";
  27224. /**
  27225. * @event finish
  27226. * @for kity.Timeline
  27227. * @description 结束事件,在时间线播放结束后触发(包括重复和回滚都结束)
  27228. */
  27229. this.fire("finish", new TimelineEvent(this, "finish"));
  27230. frame.releaseFrame(this.frame);
  27231. },
  27232. /**
  27233. * @private
  27234. *
  27235. * 循环次数递减
  27236. */
  27237. decreaseRepeat: function() {
  27238. if (this.repeatOption !== true) {
  27239. this.repeatOption--;
  27240. }
  27241. },
  27242. /**
  27243. * @method repeat()
  27244. * @for kity.Timeline
  27245. * @description 设置时间线的重复选项
  27246. *
  27247. * @grammar repeat(repeat, rollback) => {this}
  27248. *
  27249. * @param {Number|Boolean} repeat
  27250. * 是否重复播放,设置为 true 无限循环播放,设置数值则循环指定的次数
  27251. * @param {Boolean} rollback
  27252. * 指示是否要回滚播放。
  27253. * 如果设置为真,一次事件到 duration 则一个来回算一次循环次数,否则播放完成一次算一次循环次数
  27254. *
  27255. */
  27256. repeat: function(repeat, rollback) {
  27257. this.repeatOption = repeat;
  27258. this.rollback = rollback;
  27259. return this;
  27260. }
  27261. });
  27262. Timeline.requestFrame = frame.requestFrame;
  27263. Timeline.releaseFrame = frame.releaseFrame;
  27264. return Timeline;
  27265. }
  27266. };
  27267. //src/animate/translateanimator.js
  27268. /**
  27269. * @fileOverview
  27270. *
  27271. * 提供让图形移动的动画器
  27272. */
  27273. _p[9] = {
  27274. value: function(require) {
  27275. var Animator = _p.r(0);
  27276. /**
  27277. * @class kity.TranslateAnimator
  27278. * @base kity.Animator
  27279. * @description 提供让图形移动的动画器
  27280. */
  27281. var TranslateAnimator = _p.r(11).createClass("TranslateAnimator", {
  27282. base: Animator,
  27283. /**
  27284. * @constructor
  27285. * @for kity.TranslateAnimator
  27286. * @grammar new kity.TranslateAnimator(x, y)
  27287. * @param {Number} x x 方向上需要移动的距离
  27288. * @param {Number} y y 方向上需要移动的距离
  27289. */
  27290. constructor: function(x, y) {
  27291. this.callBase({
  27292. x: 0,
  27293. y: 0
  27294. }, {
  27295. x: x,
  27296. y: y
  27297. }, function(target, value, timeline) {
  27298. var delta = timeline.getDelta();
  27299. target.translate(delta.x, delta.y);
  27300. });
  27301. }
  27302. });
  27303. var Shape = _p.r(60);
  27304. _p.r(11).extendClass(Shape, {
  27305. /**
  27306. * @method fxTranslate()
  27307. * @for kity.Shape
  27308. * @description 让目标以动画平移指定的距离
  27309. *
  27310. * @grammar fxTranslate(x, y, duration, easing, delay, callback) => {this}
  27311. *
  27312. * @param {Number} x x 方向上需要移动的距离
  27313. * @param {Number} y y 方向上需要移动的距离
  27314. * @param {Number|String} duration 动画的播放长度,如 300、"5s"、"0.5min"
  27315. * @param {Number|String} delay 动画播放前的延时
  27316. * @param {String|Function} easing 动画播放使用的缓动函数,如 'ease'、'linear'、'swing'
  27317. * @param {Function} callback 播放结束之后的回调函数
  27318. */
  27319. fxTranslate: function(x, y, duration, easing, delay, callback) {
  27320. return this.animate(new TranslateAnimator(x, y), duration, easing, delay, callback);
  27321. }
  27322. });
  27323. return TranslateAnimator;
  27324. }
  27325. };
  27326. //src/core/browser.js
  27327. /**
  27328. * @fileOverview
  27329. *
  27330. * 提供浏览器判断的一些字段
  27331. */
  27332. _p[10] = {
  27333. value: function() {
  27334. /**
  27335. * @class kity.Browser
  27336. * @catalog core
  27337. * @static
  27338. * @description 提供浏览器信息
  27339. */
  27340. var browser = function() {
  27341. var agent = navigator.userAgent.toLowerCase(), opera = window.opera, browser;
  27342. // 浏览器对象
  27343. browser = {
  27344. /**
  27345. * @property ie
  27346. * @for kity.Browser
  27347. * @description 判断是否为 IE 浏览器
  27348. * @type {boolean}
  27349. */
  27350. ie: /(msie\s|trident.*rv:)([\w.]+)/.test(agent),
  27351. /**
  27352. * @property opera
  27353. * @for kity.Browser
  27354. * @description 判断是否为 Opera 浏览器
  27355. * @type {boolean}
  27356. */
  27357. opera: !!opera && opera.version,
  27358. /**
  27359. * @property webkit
  27360. * @for kity.Browser
  27361. * @description 判断是否为 Webkit 内核的浏览器
  27362. * @type {boolean}
  27363. */
  27364. webkit: agent.indexOf(" applewebkit/") > -1,
  27365. /**
  27366. * @property mac
  27367. * @for kity.Browser
  27368. * @description 判断是否为 Mac 下的浏览器
  27369. * @type {boolean}
  27370. */
  27371. mac: agent.indexOf("macintosh") > -1
  27372. };
  27373. browser.gecko = navigator.product == "Gecko" && !browser.webkit && !browser.opera && !browser.ie;
  27374. var version = 0;
  27375. // Internet Explorer 6.0+
  27376. if (browser.ie) {
  27377. version = (agent.match(/(msie\s|trident.*rv:)([\w.]+)/)[2] || 0) * 1;
  27378. browser.ie11Compat = document.documentMode == 11;
  27379. browser.ie9Compat = document.documentMode == 9;
  27380. }
  27381. // Gecko.
  27382. if (browser.gecko) {
  27383. var geckoRelease = agent.match(/rv:([\d\.]+)/);
  27384. if (geckoRelease) {
  27385. geckoRelease = geckoRelease[1].split(".");
  27386. version = geckoRelease[0] * 1e4 + (geckoRelease[1] || 0) * 100 + (geckoRelease[2] || 0) * 1;
  27387. }
  27388. }
  27389. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  27390. /**
  27391. * @property chrome
  27392. * @for kity.Browser
  27393. * @description 判断是否为 Chrome 浏览器
  27394. * @type {boolean}
  27395. */
  27396. browser.chrome = +RegExp["$1"];
  27397. }
  27398. if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)) {
  27399. browser.safari = +(RegExp["$1"] || RegExp["$2"]);
  27400. }
  27401. // Opera 9.50+
  27402. if (browser.opera) version = parseFloat(opera.version());
  27403. // WebKit 522+ (Safari 3+)
  27404. if (browser.webkit) version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]);
  27405. /**
  27406. * @property version
  27407. * @for kity.Browser
  27408. * @description 获取当前浏览器的版本
  27409. * @type {Number}
  27410. */
  27411. browser.version = version;
  27412. browser.isCompatible = !browser.mobile && (browser.ie && version >= 6 || browser.gecko && version >= 10801 || browser.opera && version >= 9.5 || browser.air && version >= 1 || browser.webkit && version >= 522 || false);
  27413. return browser;
  27414. }();
  27415. return browser;
  27416. }
  27417. };
  27418. //src/core/class.js
  27419. /**
  27420. * @fileOverview
  27421. *
  27422. * 提供 Kity 的 OOP 支持
  27423. */
  27424. _p[11] = {
  27425. value: function(require, exports) {
  27426. /**
  27427. * @class kity.Class
  27428. * @catalog core
  27429. * @description 所有 kity 类的基类
  27430. * @abstract
  27431. */
  27432. function Class() {}
  27433. exports.Class = Class;
  27434. Class.__KityClassName = "Class";
  27435. /**
  27436. * @method base()
  27437. * @for kity.Class
  27438. * @protected
  27439. * @grammar base(name, args...) => {any}
  27440. * @description 调用父类指定名称的函数
  27441. * @param {string} name 函数的名称
  27442. * @param {parameter} args... 传递给父类函数的参数
  27443. *
  27444. * @example
  27445. *
  27446. * ```js
  27447. * var Person = kity.createClass('Person', {
  27448. * toString: function() {
  27449. * return 'I am a person';
  27450. * }
  27451. * });
  27452. *
  27453. * var Male = kity.createClass('Male', {
  27454. * base: Person,
  27455. *
  27456. * toString: function() {
  27457. * return 'I am a man';
  27458. * },
  27459. *
  27460. * speak: function() {
  27461. * return this.base('toString') + ',' + this.toString();
  27462. * }
  27463. * })
  27464. * ```
  27465. */
  27466. Class.prototype.base = function(name) {
  27467. var caller = arguments.callee.caller;
  27468. var method = caller.__KityMethodClass.__KityBaseClass.prototype[name];
  27469. return method.apply(this, Array.prototype.slice.call(arguments, 1));
  27470. };
  27471. /**
  27472. * @method callBase()
  27473. * @for kity.Class
  27474. * @protected
  27475. * @grammar callBase(args...) => {any}
  27476. * @description 调用父类同名函数
  27477. * @param {parameter} args... 传递到父类同名函数的参数
  27478. *
  27479. * @example
  27480. *
  27481. * ```js
  27482. * var Animal = kity.createClass('Animal', {
  27483. * constructor: function(name) {
  27484. * this.name = name;
  27485. * },
  27486. * toString: function() {
  27487. * return 'I am an animal name ' + this.name;
  27488. * }
  27489. * });
  27490. *
  27491. * var Dog = kity.createClass('Dog', {
  27492. * constructor: function(name) {
  27493. * this.callBase(name);
  27494. * },
  27495. * toString: function() {
  27496. * return this.callBase() + ', a dog';
  27497. * }
  27498. * });
  27499. *
  27500. * var dog = new Dog('Dummy');
  27501. * console.log(dog.toString()); // "I am an animal name Dummy, a dog";
  27502. * ```
  27503. */
  27504. Class.prototype.callBase = function() {
  27505. var caller = arguments.callee.caller;
  27506. var method = caller.__KityMethodClass.__KityBaseClass.prototype[caller.__KityMethodName];
  27507. return method.apply(this, arguments);
  27508. };
  27509. Class.prototype.mixin = function(name) {
  27510. var caller = arguments.callee.caller;
  27511. var mixins = caller.__KityMethodClass.__KityMixins;
  27512. if (!mixins) {
  27513. return this;
  27514. }
  27515. var method = mixins[name];
  27516. return method.apply(this, Array.prototype.slice.call(arguments, 1));
  27517. };
  27518. Class.prototype.callMixin = function() {
  27519. var caller = arguments.callee.caller;
  27520. var methodName = caller.__KityMethodName;
  27521. var mixins = caller.__KityMethodClass.__KityMixins;
  27522. if (!mixins) {
  27523. return this;
  27524. }
  27525. var method = mixins[methodName];
  27526. if (methodName == "constructor") {
  27527. for (var i = 0, l = method.length; i < l; i++) {
  27528. method[i].call(this);
  27529. }
  27530. return this;
  27531. } else {
  27532. return method.apply(this, arguments);
  27533. }
  27534. };
  27535. /**
  27536. * @method pipe()
  27537. * @for kity.Class
  27538. * @grammar pipe() => {this}
  27539. * @description 以当前对象为上线文以及管道函数的第一个参数,执行一个管道函数
  27540. * @param {Function} fn 进行管道操作的函数
  27541. *
  27542. * @example
  27543. *
  27544. * ```js
  27545. * var rect = new kity.Rect().pipe(function() {
  27546. * this.setWidth(500);
  27547. * this.setHeight(300);
  27548. * });
  27549. * ```
  27550. */
  27551. Class.prototype.pipe = function(fn) {
  27552. if (typeof fn == "function") {
  27553. fn.call(this, this);
  27554. }
  27555. return this;
  27556. };
  27557. /**
  27558. * @method getType()
  27559. * @for kity.Class
  27560. * @grammar getType() => {string}
  27561. * @description 获得对象的类型
  27562. *
  27563. * @example
  27564. *
  27565. * ```js
  27566. * var rect = new kity.Rect();
  27567. * var circle = new kity.Circle();
  27568. *
  27569. * console.log(rect.getType()); // "Rect"
  27570. * console.log(rect.getType()); // "Circle"
  27571. * ```
  27572. */
  27573. Class.prototype.getType = function() {
  27574. return this.__KityClassName;
  27575. };
  27576. /**
  27577. * @method getClass()
  27578. * @for kity.Class
  27579. * @grammar getClass() => {Class}
  27580. * @description 获得对象的类
  27581. *
  27582. * @example
  27583. *
  27584. * ```js
  27585. * var rect = new kity.Rect();
  27586. *
  27587. * console.log(rect.getClass() === kity.Rect); // true
  27588. * console.log(rect instanceof kity.Rect); // true
  27589. * ```
  27590. */
  27591. Class.prototype.getClass = function() {
  27592. return this.constructor;
  27593. };
  27594. // 检查基类是否调用了父类的构造函数
  27595. // 该检查是弱检查,假如调用的代码被注释了,同样能检查成功(这个特性可用于知道建议调用,但是出于某些原因不想调用的情况)
  27596. function checkBaseConstructorCall(targetClass, classname) {
  27597. var code = targetClass.toString();
  27598. if (!/this\.callBase/.test(code)) {
  27599. throw new Error(classname + " : 类构造函数没有调用父类的构造函数!为了安全,请调用父类的构造函数");
  27600. }
  27601. }
  27602. var KITY_INHERIT_FLAG = "__KITY_INHERIT_FLAG_" + +new Date();
  27603. function inherit(constructor, BaseClass, classname) {
  27604. var KityClass = eval("(function " + classname + "( __inherit__flag ) {" + "if( __inherit__flag != KITY_INHERIT_FLAG ) {" + "KityClass.__KityConstructor.apply(this, arguments);" + "}" + "this.__KityClassName = KityClass.__KityClassName;" + "})");
  27605. KityClass.__KityConstructor = constructor;
  27606. KityClass.prototype = new BaseClass(KITY_INHERIT_FLAG);
  27607. for (var methodName in BaseClass.prototype) {
  27608. if (BaseClass.prototype.hasOwnProperty(methodName) && methodName.indexOf("__Kity") !== 0) {
  27609. KityClass.prototype[methodName] = BaseClass.prototype[methodName];
  27610. }
  27611. }
  27612. KityClass.prototype.constructor = KityClass;
  27613. return KityClass;
  27614. }
  27615. function mixin(NewClass, mixins) {
  27616. if (false === mixins instanceof Array) {
  27617. return NewClass;
  27618. }
  27619. var i, length = mixins.length, proto, method;
  27620. NewClass.__KityMixins = {
  27621. constructor: []
  27622. };
  27623. for (i = 0; i < length; i++) {
  27624. proto = mixins[i].prototype;
  27625. for (method in proto) {
  27626. if (false === proto.hasOwnProperty(method) || method.indexOf("__Kity") === 0) {
  27627. continue;
  27628. }
  27629. if (method === "constructor") {
  27630. // constructor 特殊处理
  27631. NewClass.__KityMixins.constructor.push(proto[method]);
  27632. } else {
  27633. NewClass.prototype[method] = NewClass.__KityMixins[method] = proto[method];
  27634. }
  27635. }
  27636. }
  27637. return NewClass;
  27638. }
  27639. function extend(BaseClass, extension) {
  27640. if (extension.__KityClassName) {
  27641. extension = extension.prototype;
  27642. }
  27643. for (var methodName in extension) {
  27644. if (extension.hasOwnProperty(methodName) && methodName.indexOf("__Kity") && methodName != "constructor") {
  27645. var method = BaseClass.prototype[methodName] = extension[methodName];
  27646. method.__KityMethodClass = BaseClass;
  27647. method.__KityMethodName = methodName;
  27648. }
  27649. }
  27650. return BaseClass;
  27651. }
  27652. /**
  27653. * @method kity.createClass()
  27654. * @grammar kity.createClass(classname, defines) => {Class}
  27655. * @description 创建一个类
  27656. * @param {string} classname 类名,用于调试的时候查看,可选
  27657. * @param {object} defines 类定义
  27658. * defines.base {Class}
  27659. * 定义的类的基类,如果不配置,则表示基类为 kity.Class
  27660. * defines.mixins {Class[]}
  27661. * 定义的类要融合的类列表
  27662. * defines.constructor {Function}
  27663. * 定义类的构造函数,如果父类显式定义了构造函数,需要在构造函数中使用 callBase() 方法调用父类的构造函数
  27664. * defines.* {Function}
  27665. * 定义类的其它函数
  27666. *
  27667. * @example 创建一个类
  27668. *
  27669. * ```js
  27670. * var Animal = kity.createClass('Animal', {
  27671. * constructor: function(name) {
  27672. * this.name = name;
  27673. * },
  27674. * toString: function() {
  27675. * return this.name;
  27676. * }
  27677. * });
  27678. *
  27679. * var a = new Animal('kity');
  27680. * console.log(a.toString()); // "kity"
  27681. * ```
  27682. *
  27683. * @example 继承一个类
  27684. *
  27685. * ```js
  27686. * var Cat = kity.createClass('Cat', {
  27687. * base: Animal,
  27688. * constructor: function(name, color) {
  27689. * // 调用父类构造函数
  27690. * this.callBase(name);
  27691. * },
  27692. * toString: function() {
  27693. * return 'A ' + this.color + ' cat, ' + this.callBase();
  27694. * }
  27695. * });
  27696. *
  27697. * var cat = new Cat('kity', 'black');
  27698. * console.log(cat.toString()); // "A black cat, kity"
  27699. * ```
  27700. *
  27701. * @example 混合类的能力
  27702. * ```js
  27703. * var Walkable = kity.createClass('Walkable', {
  27704. * constructor: function() {
  27705. * this.speed = 'fast';
  27706. * },
  27707. * walk: function() {
  27708. * console.log('I am walking ' + this.speed);
  27709. * }
  27710. * });
  27711. *
  27712. * var Dog = kity.createClass('Dog', {
  27713. * base: Animal,
  27714. * mixins: [Walkable],
  27715. * constructor: function(name) {
  27716. * this.callBase(name);
  27717. * this.callMixins();
  27718. * }
  27719. * });
  27720. *
  27721. * var dog = new Dog('doggy');
  27722. * console.log(dog.toString() + ' say:');
  27723. * dog.walk();
  27724. * ```
  27725. */
  27726. exports.createClass = function(classname, defines) {
  27727. var constructor, NewClass, BaseClass;
  27728. if (arguments.length === 1) {
  27729. defines = arguments[0];
  27730. classname = "AnonymousClass";
  27731. }
  27732. BaseClass = defines.base || Class;
  27733. if (defines.hasOwnProperty("constructor")) {
  27734. constructor = defines.constructor;
  27735. if (BaseClass != Class) {
  27736. checkBaseConstructorCall(constructor, classname);
  27737. }
  27738. } else {
  27739. constructor = function() {
  27740. this.callBase.apply(this, arguments);
  27741. this.callMixin.apply(this, arguments);
  27742. };
  27743. }
  27744. NewClass = inherit(constructor, BaseClass, classname);
  27745. NewClass = mixin(NewClass, defines.mixins);
  27746. NewClass.__KityClassName = constructor.__KityClassName = classname;
  27747. NewClass.__KityBaseClass = constructor.__KityBaseClass = BaseClass;
  27748. NewClass.__KityMethodName = constructor.__KityMethodName = "constructor";
  27749. NewClass.__KityMethodClass = constructor.__KityMethodClass = NewClass;
  27750. // 下面这些不需要拷贝到原型链上
  27751. delete defines.mixins;
  27752. delete defines.constructor;
  27753. delete defines.base;
  27754. NewClass = extend(NewClass, defines);
  27755. return NewClass;
  27756. };
  27757. /**
  27758. * @method kity.extendClass()
  27759. * @grammar kity.extendClass(clazz, extension) => {Class}
  27760. * @description 拓展一个已有的类
  27761. *
  27762. * @example
  27763. *
  27764. * ```js
  27765. * kity.extendClass(Dog, {
  27766. * spark: function() {
  27767. * console.log('wao wao wao!');
  27768. * }
  27769. * });
  27770. *
  27771. * new Dog().spark(); // "wao wao wao!";
  27772. * ```
  27773. */
  27774. exports.extendClass = extend;
  27775. }
  27776. };
  27777. //src/core/utils.js
  27778. /**
  27779. * @fileOverview
  27780. *
  27781. * 一些常用的工具方法
  27782. */
  27783. _p[12] = {
  27784. value: function() {
  27785. /**
  27786. * @class kity.Utils
  27787. * @catalog core
  27788. * @static
  27789. * @description 提供常用的工具方法
  27790. */
  27791. var utils = {
  27792. /**
  27793. * @method each()
  27794. * @for kity.Utils
  27795. * @grammar each(obj, interator, context)
  27796. * @param {Object|Array} obj 要迭代的对象或数组
  27797. * @param {Function} iterator 迭代函数
  27798. * @param {Any} context 迭代函数的上下文
  27799. *
  27800. * @example 迭代数组
  27801. *
  27802. * ```js
  27803. * kity.Utils.each([1, 2, 3, 4, 5], function(value, index, array) {
  27804. * console.log(value, index);
  27805. * });
  27806. * // 1, 0
  27807. * // 2, 1
  27808. * // 3, 2
  27809. * // 4, 3
  27810. * // 5, 4
  27811. * ```
  27812. *
  27813. * @example 迭代对象
  27814. *
  27815. * ```js
  27816. * var obj = {
  27817. * name: 'kity',
  27818. * version: '1.2.1'
  27819. * };
  27820. * var param = [];
  27821. * kity.Utils.each(obj, function(value, key, obj) {
  27822. * param.push(key + '=' + value);
  27823. * });
  27824. * console.log(param.join('&')); // "name=kity&version=1.2.1"
  27825. * ```
  27826. */
  27827. each: function each(obj, iterator, context) {
  27828. if (obj === null) {
  27829. return;
  27830. }
  27831. if (obj.length === +obj.length) {
  27832. for (var i = 0, l = obj.length; i < l; i++) {
  27833. if (iterator.call(context, obj[i], i, obj) === false) {
  27834. return false;
  27835. }
  27836. }
  27837. } else {
  27838. for (var key in obj) {
  27839. if (obj.hasOwnProperty(key)) {
  27840. if (iterator.call(context, obj[key], key, obj) === false) {
  27841. return false;
  27842. }
  27843. }
  27844. }
  27845. }
  27846. },
  27847. /**
  27848. * @method extend()
  27849. * @for kity.Utils
  27850. * @grammar extend(target, sources..., notCover) => {object}
  27851. * @description 把源对象的属性合并到目标对象上
  27852. * @param {object} target 目标对象
  27853. * @param {parameter} sources 源对象
  27854. * @param {boolean} notCover 是否不要覆盖源对象已有的属性
  27855. *
  27856. * @example
  27857. *
  27858. * ```js
  27859. * var a = {
  27860. * key1: 'a1',
  27861. * key2: 'a2'
  27862. * };
  27863. *
  27864. * var b = {
  27865. * key2: 'b2',
  27866. * key3: 'b3'
  27867. * };
  27868. *
  27869. * var c = {
  27870. * key4: 'c4'
  27871. * };
  27872. *
  27873. * var d = kity.extend(a, b, c);
  27874. *
  27875. * console.log(d === a); // true
  27876. * console.log(a); // {key1: 'a1', key2: 'b2', key3: 'b3', key4: 'c4'}
  27877. * ```
  27878. */
  27879. extend: function extend(t) {
  27880. var a = arguments, notCover = this.isBoolean(a[a.length - 1]) ? a[a.length - 1] : false, len = this.isBoolean(a[a.length - 1]) ? a.length - 1 : a.length;
  27881. for (var i = 1; i < len; i++) {
  27882. var x = a[i];
  27883. for (var k in x) {
  27884. if (!notCover || !t.hasOwnProperty(k)) {
  27885. t[k] = x[k];
  27886. }
  27887. }
  27888. }
  27889. return t;
  27890. },
  27891. /**
  27892. * @method deepExtend()
  27893. * @for kity.Utils
  27894. * @grammar deepExtend(target, sources..., notCover)
  27895. * @description 把源对象的属性合并到目标对象上,如果属性是对象,会递归合并
  27896. * @param {object} target 目标对象
  27897. * @param {parameter} sources 源对象
  27898. * @param {boolean} notCover 是否不要覆盖源对象已有的属性
  27899. */
  27900. deepExtend: function(t, s) {
  27901. var a = arguments, notCover = this.isBoolean(a[a.length - 1]) ? a[a.length - 1] : false, len = this.isBoolean(a[a.length - 1]) ? a.length - 1 : a.length;
  27902. for (var i = 1; i < len; i++) {
  27903. var x = a[i];
  27904. for (var k in x) {
  27905. if (!notCover || !t.hasOwnProperty(k)) {
  27906. if (this.isObject(t[k]) && this.isObject(x[k])) {
  27907. this.deepExtend(t[k], x[k], notCover);
  27908. } else {
  27909. t[k] = x[k];
  27910. }
  27911. }
  27912. }
  27913. }
  27914. return t;
  27915. },
  27916. /**
  27917. * @method clone()
  27918. * @for kity.Utils
  27919. * @grammar clone(obj) => {object}
  27920. * @description 返回一个对象的克隆副本(非深度复制)
  27921. * @param {object} obj 要克隆的对象
  27922. *
  27923. * @example
  27924. *
  27925. * ```js
  27926. * var source = {
  27927. * key1: {
  27928. * key2: 'value2'
  27929. * },
  27930. * key3: 'value3'
  27931. * };
  27932. *
  27933. * var target = kity.Utils.clone(source);
  27934. *
  27935. * console.log(target === source); // false
  27936. * console.log(target.key1 === source.key1); // true
  27937. * console.log(target.key3 === source.key3); // true
  27938. * ```
  27939. */
  27940. clone: function clone(obj) {
  27941. var cloned = {};
  27942. for (var m in obj) {
  27943. if (obj.hasOwnProperty(m)) {
  27944. cloned[m] = obj[m];
  27945. }
  27946. }
  27947. return cloned;
  27948. },
  27949. /**
  27950. * @method copy()
  27951. * @for kity.Utils
  27952. * @grammar copy(obj) => {object}
  27953. * @description 返回一个对象的拷贝副本(深度复制)
  27954. * @param {object} obj 要拷贝的对象
  27955. *
  27956. * @example
  27957. *
  27958. * ```js
  27959. * var source = {
  27960. * key1: {
  27961. * key2: 'value2'
  27962. * },
  27963. * key3: 'value3'
  27964. * };
  27965. *
  27966. * var target = kity.Utils.copy(source);
  27967. *
  27968. * console.log(target === source); // false
  27969. * console.log(target.key1 === source.key1); // false
  27970. * console.log(target.key3 === source.key3); // true,因为是值类型
  27971. * ```
  27972. */
  27973. copy: function copy(obj) {
  27974. if (typeof obj !== "object") return obj;
  27975. if (typeof obj === "function") return null;
  27976. return JSON.parse(JSON.stringify(obj));
  27977. },
  27978. queryPath: function(path, obj) {
  27979. var arr = path.split(".");
  27980. var i = 0, tmp = obj, l = arr.length;
  27981. while (i < l) {
  27982. if (arr[i] in tmp) {
  27983. tmp = tmp[arr[i]];
  27984. i++;
  27985. if (i >= l || tmp === undefined) {
  27986. return tmp;
  27987. }
  27988. } else {
  27989. return undefined;
  27990. }
  27991. }
  27992. },
  27993. getValue: function(value, defaultValue) {
  27994. return value !== undefined ? value : defaultValue;
  27995. },
  27996. /**
  27997. * @method flatten()
  27998. * @for kity.Utils
  27999. * @grammar flatten(arr) => {Array}
  28000. * @description 返回给定数组的扁平化版本
  28001. * @param {Array} arr 要扁平化的数组
  28002. *
  28003. * @example
  28004. *
  28005. * ```js
  28006. * var flattened = kity.Utils.flatten([[1, 2], [2, 3], [[4, 5], [6, 7]]]);
  28007. * console.log(flattened); // [1, 2, 3, 4, 5, 6, 7];
  28008. * ```
  28009. */
  28010. flatten: function flatten(arr) {
  28011. var result = [], length = arr.length, i;
  28012. for (i = 0; i < length; i++) {
  28013. if (arr[i] instanceof Array) {
  28014. result = result.concat(utils.flatten(arr[i]));
  28015. } else {
  28016. result.push(arr[i]);
  28017. }
  28018. }
  28019. return result;
  28020. },
  28021. /**
  28022. * @method paralle()
  28023. * @for kity.Utils
  28024. * @grammar paralle() => {Any}
  28025. *
  28026. * @description 平行地对 v1 和 v2 进行指定的操作
  28027. *
  28028. * 如果 v1 是数字,那么直接进行 op 操作
  28029. * 如果 v1 是对象,那么返回一个对象,其元素是 v1 和 v2 同键值的每个元素平行地进行 op 操作的结果
  28030. * 如果 v1 是数组,那么返回一个数组,其元素是 v1 和 v2 同索引的每个元素平行地进行 op 操作的结果
  28031. *
  28032. * @param {Number|Object|Array} v1 第一个操作数
  28033. * @param {Number|Object|Array} v2 第二个操作数
  28034. * @param {Function} op 操作函数
  28035. *
  28036. *
  28037. *
  28038. * @example
  28039. *
  28040. * ```js
  28041. * var a = {
  28042. * value1: 1,
  28043. * value2: 2,
  28044. * value3: [3, 4, 5]
  28045. * };
  28046. *
  28047. * var b = {
  28048. * value1: 2,
  28049. * value2: 3,
  28050. * value3: [4, 5, 6]
  28051. * };
  28052. *
  28053. * var c = kity.Utils.paralle(a, b, function(v1, v2) {
  28054. * return v1 + v2;
  28055. * });
  28056. *
  28057. * console.log(c.value1); // 3
  28058. * console.log(c.value2); // 5
  28059. * console.log(c.value3); // [7, 9, 11]
  28060. *
  28061. * ```
  28062. */
  28063. paralle: function paralle(v1, v2, op) {
  28064. var Class, field, index, name, value;
  28065. // 数组
  28066. if (v1 instanceof Array) {
  28067. value = [];
  28068. for (index = 0; index < v1.length; index++) {
  28069. value.push(utils.paralle(v1[index], v2[index], op));
  28070. }
  28071. return value;
  28072. }
  28073. // 对象
  28074. if (v1 instanceof Object) {
  28075. // 如果值是一个支持原始表示的实例,获取其原始表示
  28076. Class = v1.getClass && v1.getClass();
  28077. if (Class && Class.parse) {
  28078. v1 = v1.valueOf();
  28079. v2 = v2.valueOf();
  28080. value = utils.paralle(v1, v2, op);
  28081. value = Class.parse(value);
  28082. } else {
  28083. value = {};
  28084. for (name in v1) {
  28085. if (v1.hasOwnProperty(name) && v2.hasOwnProperty(name)) {
  28086. value[name] = utils.paralle(v1[name], v2[name], op);
  28087. }
  28088. }
  28089. }
  28090. return value;
  28091. }
  28092. // 是否数字
  28093. if (false === isNaN(parseFloat(v1))) {
  28094. return op(v1, v2);
  28095. }
  28096. return value;
  28097. },
  28098. /**
  28099. * 创建 op 操作的一个平行化版本
  28100. */
  28101. parallelize: function parallelize(op) {
  28102. return function(v1, v2) {
  28103. return utils.paralle(v1, v2, op);
  28104. };
  28105. }
  28106. };
  28107. /**
  28108. * @method isString()
  28109. * @for kity.Utils
  28110. * @grammar isString(unknown) => {boolean}
  28111. * @description 判断一个值是否为字符串类型
  28112. * @param {any} unknown 要判断的值
  28113. */
  28114. /**
  28115. * @method isFunction()
  28116. * @for kity.Utils
  28117. * @grammar isFunction(unknown) => {boolean}
  28118. * @description 判断一个值是否为函数类型
  28119. * @param {any} unknown 要判断的值
  28120. */
  28121. /**
  28122. * @method isArray()
  28123. * @for kity.Utils
  28124. * @grammar isArray(unknown) => {boolean}
  28125. * @description 判断一个值是否为数组类型
  28126. * @param {any} unknown 要判断的值
  28127. */
  28128. /**
  28129. * @method isNumber()
  28130. * @for kity.Utils
  28131. * @grammar isNumber(unknown) => {boolean}
  28132. * @description 判断一个值是否为数字类型
  28133. * @param {any} unknown 要判断的值
  28134. */
  28135. /**
  28136. * @method isRegExp()
  28137. * @for kity.Utils
  28138. * @grammar isRegExp(unknown) => {boolean}
  28139. * @description 判断一个值是否为正则表达式类型
  28140. * @param {any} unknown 要判断的值
  28141. */
  28142. /**
  28143. * @method isObject()
  28144. * @for kity.Utils
  28145. * @grammar isObject(unknown) => {boolean}
  28146. * @description 判断一个值是否为对象类型
  28147. * @param {any} unknown 要判断的值
  28148. */
  28149. /**
  28150. * @method isBoolean()
  28151. * @for kity.Utils
  28152. * @grammar isBoolean(unknown) => {boolean}
  28153. * @description 判断一个值是否为布尔类型
  28154. * @param {any} unknown 要判断的值
  28155. */
  28156. utils.each([ "String", "Function", "Array", "Number", "RegExp", "Object", "Boolean" ], function(v) {
  28157. utils["is" + v] = function typeCheck(obj) {
  28158. return Object.prototype.toString.apply(obj) == "[object " + v + "]";
  28159. };
  28160. });
  28161. return utils;
  28162. }
  28163. };
  28164. //src/filter/effect/colormatrixeffect.js
  28165. /**
  28166. * 颜色矩阵运算效果封装
  28167. */
  28168. _p[13] = {
  28169. value: function(require, exports, module) {
  28170. var Effect = _p.r(16), Utils = _p.r(12);
  28171. var ColorMatrixEffect = _p.r(11).createClass("ColorMatrixEffect", {
  28172. base: Effect,
  28173. constructor: function(type, input) {
  28174. this.callBase(Effect.NAME_COLOR_MATRIX);
  28175. this.set("type", Utils.getValue(type, ColorMatrixEffect.TYPE_MATRIX));
  28176. this.set("in", Utils.getValue(input, Effect.INPUT_SOURCE_GRAPHIC));
  28177. }
  28178. });
  28179. Utils.extend(ColorMatrixEffect, {
  28180. // 类型常量
  28181. TYPE_MATRIX: "matrix",
  28182. TYPE_SATURATE: "saturate",
  28183. TYPE_HUE_ROTATE: "hueRotate",
  28184. TYPE_LUMINANCE_TO_ALPHA: "luminanceToAlpha",
  28185. // 矩阵常量
  28186. MATRIX_ORIGINAL: "10000010000010000010".split("").join(" "),
  28187. MATRIX_EMPTY: "00000000000000000000".split("").join(" ")
  28188. });
  28189. return ColorMatrixEffect;
  28190. }
  28191. };
  28192. //src/filter/effect/compositeeffect.js
  28193. /**
  28194. * 高斯模糊效果封装
  28195. */
  28196. _p[14] = {
  28197. value: function(require, exports, module) {
  28198. var Effect = _p.r(16), Utils = _p.r(12);
  28199. var CompositeEffect = _p.r(11).createClass("CompositeEffect", {
  28200. base: Effect,
  28201. constructor: function(operator, input, input2) {
  28202. this.callBase(Effect.NAME_COMPOSITE);
  28203. this.set("operator", Utils.getValue(operator, CompositeEffect.OPERATOR_OVER));
  28204. if (input) {
  28205. this.set("in", input);
  28206. }
  28207. if (input2) {
  28208. this.set("in2", input2);
  28209. }
  28210. }
  28211. });
  28212. Utils.extend(CompositeEffect, {
  28213. // operator 常量
  28214. OPERATOR_OVER: "over",
  28215. OPERATOR_IN: "in",
  28216. OPERATOR_OUT: "out",
  28217. OPERATOR_ATOP: "atop",
  28218. OPERATOR_XOR: "xor",
  28219. OPERATOR_ARITHMETIC: "arithmetic"
  28220. });
  28221. return CompositeEffect;
  28222. }
  28223. };
  28224. //src/filter/effect/convolvematrixeffect.js
  28225. /**
  28226. * 像素级别的矩阵卷积运算效果封装
  28227. */
  28228. _p[15] = {
  28229. value: function(require, exports, module) {
  28230. var Effect = _p.r(16), Utils = _p.r(12);
  28231. var ConvolveMatrixEffect = _p.r(11).createClass("ConvolveMatrixEffect", {
  28232. base: Effect,
  28233. constructor: function(edgeMode, input) {
  28234. this.callBase(Effect.NAME_CONVOLVE_MATRIX);
  28235. this.set("edgeMode", Utils.getValue(edgeMode, ConvolveMatrixEffect.MODE_DUPLICATE));
  28236. this.set("in", Utils.getValue(input, Effect.INPUT_SOURCE_GRAPHIC));
  28237. }
  28238. });
  28239. Utils.extend(ConvolveMatrixEffect, {
  28240. MODE_DUPLICATE: "duplicate",
  28241. MODE_WRAP: "wrap",
  28242. MODE_NONE: "none"
  28243. });
  28244. return ConvolveMatrixEffect;
  28245. }
  28246. };
  28247. //src/filter/effect/effect.js
  28248. /*
  28249. * 效果类
  28250. * 该类型的对象不存储任何内部属性, 所有操作都是针对该类对象所维护的节点进行的
  28251. */
  28252. _p[16] = {
  28253. value: function(require, exports, module) {
  28254. var svg = _p.r(67), Effect = _p.r(11).createClass("Effect", {
  28255. constructor: function(type) {
  28256. this.node = svg.createNode(type);
  28257. },
  28258. getId: function() {
  28259. return this.node.id;
  28260. },
  28261. setId: function(id) {
  28262. this.node.id = id;
  28263. return this;
  28264. },
  28265. set: function(key, value) {
  28266. this.node.setAttribute(key, value);
  28267. return this;
  28268. },
  28269. get: function(key) {
  28270. return this.node.getAttribute(key);
  28271. },
  28272. getNode: function() {
  28273. return this.node;
  28274. },
  28275. // 返回该效果的result
  28276. toString: function() {
  28277. return this.node.getAttribute("result") || "";
  28278. }
  28279. });
  28280. _p.r(12).extend(Effect, {
  28281. // 特效名称常量
  28282. NAME_GAUSSIAN_BLUR: "feGaussianBlur",
  28283. NAME_OFFSET: "feOffset",
  28284. NAME_COMPOSITE: "feComposite",
  28285. NAME_COLOR_MATRIX: "feColorMatrix",
  28286. NAME_CONVOLVE_MATRIX: "feConvolveMatrix",
  28287. // 输入常量
  28288. INPUT_SOURCE_GRAPHIC: "SourceGraphic",
  28289. INPUT_SOURCE_ALPHA: "SourceAlpha",
  28290. INPUT_BACKGROUND_IMAGE: "BackgroundImage",
  28291. INPUT_BACKGROUND_ALPHA: "BackgroundAlpha",
  28292. INPUT_FILL_PAINT: "FillPaint",
  28293. INPUT_STROKE_PAINT: "StrokePaint"
  28294. });
  28295. return Effect;
  28296. }
  28297. };
  28298. //src/filter/effect/gaussianblureffect.js
  28299. /**
  28300. * 高斯模糊效果封装
  28301. */
  28302. _p[17] = {
  28303. value: function(require, exports, module) {
  28304. var Effect = _p.r(16), Utils = _p.r(12);
  28305. return _p.r(11).createClass("GaussianblurEffect", {
  28306. base: Effect,
  28307. constructor: function(stdDeviation, input) {
  28308. this.callBase(Effect.NAME_GAUSSIAN_BLUR);
  28309. this.set("stdDeviation", Utils.getValue(stdDeviation, 1));
  28310. this.set("in", Utils.getValue(input, Effect.INPUT_SOURCE_GRAPHIC));
  28311. }
  28312. });
  28313. }
  28314. };
  28315. //src/filter/effect/offseteffect.js
  28316. /**
  28317. * 偏移效果封装
  28318. */
  28319. _p[18] = {
  28320. value: function(require, exports, module) {
  28321. var Effect = _p.r(16), Utils = _p.r(12);
  28322. return _p.r(11).createClass("OffsetEffect", {
  28323. base: Effect,
  28324. constructor: function(dx, dy, input) {
  28325. this.callBase(Effect.NAME_OFFSET);
  28326. this.set("dx", Utils.getValue(dx, 0));
  28327. this.set("dy", Utils.getValue(dy, 0));
  28328. this.set("in", Utils.getValue(input, Effect.INPUT_SOURCE_GRAPHIC));
  28329. }
  28330. });
  28331. }
  28332. };
  28333. //src/filter/effectcontainer.js
  28334. /*
  28335. * Effect所用的container
  28336. */
  28337. _p[19] = {
  28338. value: function(require) {
  28339. return _p.r(11).createClass("EffectContainer", {
  28340. base: _p.r(29),
  28341. addEffect: function(point, pos) {
  28342. return this.addItem.apply(this, arguments);
  28343. },
  28344. prependEffect: function() {
  28345. return this.prependItem.apply(this, arguments);
  28346. },
  28347. appendEffect: function() {
  28348. return this.appendItem.apply(this, arguments);
  28349. },
  28350. removeEffect: function(pos) {
  28351. return this.removeItem.apply(this, arguments);
  28352. },
  28353. addEffects: function() {
  28354. return this.addItems.apply(this, arguments);
  28355. },
  28356. setEffects: function() {
  28357. return this.setItems.apply(this, arguments);
  28358. },
  28359. getEffect: function() {
  28360. return this.getItem.apply(this, arguments);
  28361. },
  28362. getEffects: function() {
  28363. return this.getItems.apply(this, arguments);
  28364. },
  28365. getFirstEffect: function() {
  28366. return this.getFirstItem.apply(this, arguments);
  28367. },
  28368. getLastEffect: function() {
  28369. return this.getLastItem.apply(this, arguments);
  28370. },
  28371. handleAdd: function(effectItem, pos) {
  28372. var count = this.getEffects().length, nextEffectItem = this.getItem(pos + 1);
  28373. // 最后一个节点, 直接追加
  28374. if (count === pos + 1) {
  28375. this.node.appendChild(effectItem.getNode());
  28376. return;
  28377. }
  28378. this.node.insertBefore(effectItem.getNode(), nextEffectItem.getNode());
  28379. }
  28380. });
  28381. }
  28382. };
  28383. //src/filter/filter.js
  28384. /**
  28385. * Filter 基类
  28386. */
  28387. _p[20] = {
  28388. value: function(require, exports, module) {
  28389. var svg = _p.r(67);
  28390. var Class = _p.r(11);
  28391. var Filter = Class.createClass("Filter", {
  28392. mixins: [ _p.r(19) ],
  28393. constructor: function(x, y, width, height) {
  28394. this.node = svg.createNode("filter");
  28395. if (x !== undefined) {
  28396. this.set("x", x);
  28397. }
  28398. if (y !== undefined) {
  28399. this.set("y", y);
  28400. }
  28401. if (width !== undefined) {
  28402. this.set("width", width);
  28403. }
  28404. if (height !== undefined) {
  28405. this.set("height", height);
  28406. }
  28407. },
  28408. getId: function() {
  28409. return this.id;
  28410. },
  28411. setId: function(id) {
  28412. this.node.id = id;
  28413. return this;
  28414. },
  28415. set: function(key, value) {
  28416. this.node.setAttribute(key, value);
  28417. return this;
  28418. },
  28419. get: function(key) {
  28420. return this.node.getAttribute(key);
  28421. },
  28422. getNode: function() {
  28423. return this.node;
  28424. }
  28425. });
  28426. var Shape = _p.r(60);
  28427. Class.extendClass(Shape, {
  28428. applyFilter: function(filter) {
  28429. var filterId = filter.get("id");
  28430. if (filterId) {
  28431. this.node.setAttribute("filter", "url(#" + filterId + ")");
  28432. }
  28433. return this;
  28434. }
  28435. });
  28436. return Filter;
  28437. }
  28438. };
  28439. //src/filter/gaussianblurfilter.js
  28440. /*
  28441. * 高斯模糊滤镜
  28442. */
  28443. _p[21] = {
  28444. value: function(require, exports, module) {
  28445. var GaussianblurEffect = _p.r(17);
  28446. return _p.r(11).createClass("GaussianblurFilter", {
  28447. base: _p.r(20),
  28448. constructor: function(stdDeviation) {
  28449. this.callBase();
  28450. this.addEffect(new GaussianblurEffect(stdDeviation));
  28451. }
  28452. });
  28453. }
  28454. };
  28455. //src/filter/projectionfilter.js
  28456. /*
  28457. * 投影滤镜
  28458. */
  28459. _p[22] = {
  28460. value: function(require, exports, module) {
  28461. var GaussianblurEffect = _p.r(17), Effect = _p.r(16), ColorMatrixEffect = _p.r(13), Color = _p.r(28), Utils = _p.r(12), CompositeEffect = _p.r(14), OffsetEffect = _p.r(18);
  28462. return _p.r(11).createClass("ProjectionFilter", {
  28463. base: _p.r(20),
  28464. constructor: function(stdDeviation, dx, dy) {
  28465. this.callBase();
  28466. this.gaussianblurEffect = new GaussianblurEffect(stdDeviation, Effect.INPUT_SOURCE_ALPHA);
  28467. this.gaussianblurEffect.set("result", "gaussianblur");
  28468. this.addEffect(this.gaussianblurEffect);
  28469. this.offsetEffect = new OffsetEffect(dx, dy, this.gaussianblurEffect);
  28470. this.offsetEffect.set("result", "offsetBlur");
  28471. this.addEffect(this.offsetEffect);
  28472. this.colorMatrixEffect = new ColorMatrixEffect(ColorMatrixEffect.TYPE_MATRIX, this.offsetEffect);
  28473. this.colorMatrixEffect.set("values", ColorMatrixEffect.MATRIX_ORIGINAL);
  28474. this.colorMatrixEffect.set("result", "colorOffsetBlur");
  28475. this.addEffect(this.colorMatrixEffect);
  28476. this.compositeEffect = new CompositeEffect(CompositeEffect.OPERATOR_OVER, Effect.INPUT_SOURCE_GRAPHIC, this.colorMatrixEffect);
  28477. this.addEffect(this.compositeEffect);
  28478. },
  28479. // 设置投影颜色
  28480. setColor: function(color) {
  28481. var matrix = null, originMatrix = null, colorValue = [];
  28482. if (Utils.isString(color)) {
  28483. color = Color.parse(color);
  28484. }
  28485. if (!color) {
  28486. return this;
  28487. }
  28488. matrix = ColorMatrixEffect.MATRIX_EMPTY.split(" ");
  28489. colorValue.push(color.get("r"));
  28490. colorValue.push(color.get("g"));
  28491. colorValue.push(color.get("b"));
  28492. // rgb 分量更改
  28493. for (var i = 0, len = colorValue.length; i < len; i++) {
  28494. matrix[i * 5 + 3] = colorValue[i] / 255;
  28495. }
  28496. // alpha 分量更改
  28497. matrix[18] = color.get("a");
  28498. this.colorMatrixEffect.set("values", matrix.join(" "));
  28499. return this;
  28500. },
  28501. // 设置投影透明度
  28502. setOpacity: function(opacity) {
  28503. var matrix = this.colorMatrixEffect.get("values").split(" ");
  28504. matrix[18] = opacity;
  28505. this.colorMatrixEffect.set("values", matrix.join(" "));
  28506. return this;
  28507. },
  28508. // 设置阴影偏移量
  28509. setOffset: function(dx, dy) {
  28510. this.setOffsetX(dx);
  28511. this.setOffsetY(dy);
  28512. },
  28513. setOffsetX: function(dx) {
  28514. this.offsetEffect.set("dx", dx);
  28515. },
  28516. setOffsetY: function(dy) {
  28517. this.offsetEffect.set("dy", dy);
  28518. },
  28519. setDeviation: function(deviation) {
  28520. this.gaussianblurEffect.set("stdDeviation", deviation);
  28521. }
  28522. });
  28523. }
  28524. };
  28525. //src/graphic/bezier.js
  28526. /**
  28527. * @fileOverview
  28528. *
  28529. * 贝塞尔曲线
  28530. */
  28531. _p[23] = {
  28532. value: function(require, exports, module) {
  28533. /**
  28534. * @class kity.Bezier
  28535. * @mixins kity.PointContainer
  28536. * @base kity.Path
  28537. * @description 绘制和使用贝塞尔曲线。贝塞尔曲线作为一个贝塞尔点的容器,任何贝塞尔点的改变都会更改贝塞尔曲线的外观
  28538. */
  28539. return _p.r(11).createClass("Bezier", {
  28540. mixins: [ _p.r(51) ],
  28541. base: _p.r(46),
  28542. /**
  28543. * @constructor
  28544. * @for kity.Bezier
  28545. *
  28546. * @grammar new kity.Bezier(bezierPoints)
  28547. *
  28548. * @param {kity.BezierPoints[]} bezierPoints 贝塞尔点集合,每个元素应该是 {kity.BezierPoint} 类型
  28549. *
  28550. * @example
  28551. *
  28552. * ```js
  28553. * var bezier = new kity.Bezier([
  28554. * new kity.BezierPoint(0, 0).setForward(100, 0),
  28555. * new kity.BezierPoint(100, 100).setBackward(100, 0)
  28556. * ]);
  28557. * ```
  28558. */
  28559. constructor: function(bezierPoints) {
  28560. this.callBase();
  28561. bezierPoints = bezierPoints || [];
  28562. this.changeable = true;
  28563. this.setBezierPoints(bezierPoints);
  28564. },
  28565. /**
  28566. * @method getBezierPoints()
  28567. * @for kity.Bezier
  28568. * @description 返回当前贝塞尔曲线的贝塞尔点集合
  28569. *
  28570. * @grammar getBezierPoints() => {kity.BezierPoints[]}
  28571. *
  28572. */
  28573. getBezierPoints: function() {
  28574. return this.getPoints();
  28575. },
  28576. /**
  28577. * @method setBezierPoints()
  28578. * @for kity.Bezier
  28579. * @description 设置当前贝塞尔曲线的贝塞尔点集合
  28580. *
  28581. * @grammar setBeizerPoints(bezierPoints) => {this}
  28582. *
  28583. * @param {kity.BezierPoint[]} bezierPoints 贝塞尔点集合
  28584. */
  28585. setBezierPoints: function(bezierPoints) {
  28586. return this.setPoints(bezierPoints);
  28587. },
  28588. //当点集合发生变化时采取的动作
  28589. onContainerChanged: function() {
  28590. if (this.changeable) {
  28591. this.update();
  28592. }
  28593. },
  28594. update: function() {
  28595. var drawer = null, bezierPoints = this.getBezierPoints();
  28596. //单独的一个点不画任何图形
  28597. if (bezierPoints.length < 2) {
  28598. return;
  28599. }
  28600. drawer = this.getDrawer();
  28601. drawer.clear();
  28602. var vertex = bezierPoints[0].getVertex(), forward = null, backward = null;
  28603. drawer.moveTo(vertex.x, vertex.y);
  28604. for (var i = 1, len = bezierPoints.length; i < len; i++) {
  28605. vertex = bezierPoints[i].getVertex();
  28606. backward = bezierPoints[i].getBackward();
  28607. forward = bezierPoints[i - 1].getForward();
  28608. drawer.bezierTo(forward.x, forward.y, backward.x, backward.y, vertex.x, vertex.y);
  28609. }
  28610. return this;
  28611. }
  28612. });
  28613. }
  28614. };
  28615. //src/graphic/bezierpoint.js
  28616. /**
  28617. * @fileOverview
  28618. *
  28619. * 表示一个贝塞尔点
  28620. */
  28621. _p[24] = {
  28622. value: function(require, exports, module) {
  28623. var ShapePoint = _p.r(63);
  28624. var Vector = _p.r(73);
  28625. /**
  28626. * @class kity.BezierPoint
  28627. *
  28628. * @description 表示一个贝塞尔点
  28629. * 一个贝塞尔点由顶点坐标(曲线经过的点)、前方控制点、后方控制点表示
  28630. */
  28631. var BezierPoint = _p.r(11).createClass("BezierPoint", {
  28632. /**
  28633. * @constructor
  28634. * @for kity.BezierPoint
  28635. *
  28636. * @description 创建一个具有默认顶点坐标的贝塞尔点,两个控制点的坐标和顶点一致
  28637. *
  28638. * @param {Number} x 顶点的 x 坐标
  28639. * @param {Number} y 顶点的 y 坐标
  28640. * @param {Boolean} isSmooth 指示当前贝塞尔点是否光滑,光滑会约束顶点和两个控制点共线
  28641. */
  28642. constructor: function(x, y, isSmooth) {
  28643. //顶点
  28644. this.vertex = new ShapePoint(x, y);
  28645. //控制点
  28646. this.forward = new ShapePoint(x, y);
  28647. this.backward = new ShapePoint(x, y);
  28648. //是否平滑
  28649. this.setSmooth(isSmooth === undefined || isSmooth);
  28650. this.setSymReflaction(true);
  28651. },
  28652. /**
  28653. * @method clone()
  28654. * @for kity.BezierPoint
  28655. * @description 返回贝塞尔点的一份拷贝
  28656. *
  28657. * @grammar clone() => {kity.BezierPoint}
  28658. */
  28659. clone: function() {
  28660. var newPoint = new BezierPoint(), tmp = null;
  28661. tmp = this.getVertex();
  28662. newPoint.setVertex(tmp.x, tmp.y);
  28663. tmp = this.getForward();
  28664. newPoint.setForward(tmp.x, tmp.y);
  28665. tmp = this.getBackward();
  28666. newPoint.setBackward(tmp.x, tmp.y);
  28667. newPoint.setSymReflaction(this.isSymReflaction);
  28668. newPoint.setSmooth(this.isSmooth());
  28669. return newPoint;
  28670. },
  28671. /**
  28672. * @method setVertex()
  28673. * @for kity.BezierPoint
  28674. * @description 设置贝塞尔点的顶点坐标,注意,控制点的坐标不会跟着变化。希望控制点的坐标跟着变化,请用 moveTo() 方法
  28675. *
  28676. * @grammar setVertex(x, y) => {this}
  28677. *
  28678. * @param {Number} x 顶点的 x 坐标
  28679. * @param {Number} y 顶点的 y 坐标
  28680. */
  28681. setVertex: function(x, y) {
  28682. this.vertex.setPoint(x, y);
  28683. this.update();
  28684. return this;
  28685. },
  28686. /**
  28687. * @method moveTo()
  28688. * @for kity.BezierPoint
  28689. * @description 同步移动整个贝塞尔点,使顶点的移动到指定的坐标中。控制点的位置相对顶点坐标固定。
  28690. *
  28691. * @grammar moveTo() => {this}
  28692. *
  28693. * @param {Number} x 顶点的目标 x 坐标
  28694. * @param {Number} y 顶点的目标 y 坐标
  28695. *
  28696. */
  28697. moveTo: function(x, y) {
  28698. var oldForward = this.forward.getPoint(), oldBackward = this.backward.getPoint(), oldVertex = this.vertex.getPoint(), //移动距离
  28699. distance = {
  28700. left: x - oldVertex.x,
  28701. top: y - oldVertex.y
  28702. };
  28703. // 更新
  28704. this.forward.setPoint(oldForward.x + distance.left, oldForward.y + distance.top);
  28705. this.backward.setPoint(oldBackward.x + distance.left, oldBackward.y + distance.top);
  28706. this.vertex.setPoint(x, y);
  28707. this.update();
  28708. },
  28709. /**
  28710. * @method setForward()
  28711. * @for kity.BezierPoint
  28712. * @description 设置前方控制点的位置,如果贝塞尔点光滑,后方控制点会跟着联动
  28713. *
  28714. * @grammar setForward(x, y) => {this}
  28715. *
  28716. * @param {Number} x 前方控制点的 x 坐标
  28717. * @param {Number} y 前方控制点的 y 坐标
  28718. */
  28719. setForward: function(x, y) {
  28720. this.forward.setPoint(x, y);
  28721. //更新后置点
  28722. if (this.smooth) {
  28723. this.updateAnother(this.forward, this.backward);
  28724. }
  28725. this.update();
  28726. this.lastControlPointSet = this.forward;
  28727. return this;
  28728. },
  28729. /**
  28730. * @method setBackward()
  28731. * @for kity.BezierPoint
  28732. * @description 设置后方控制点的位置,如果贝塞尔点光滑,前方控制点会跟着联动
  28733. *
  28734. * @grammar setBackward(x, y) => {this}
  28735. *
  28736. * @param {Number} x 后方控制点的 x 坐标
  28737. * @param {Number} y 后方控制点的 y 坐标
  28738. */
  28739. setBackward: function(x, y) {
  28740. this.backward.setPoint(x, y);
  28741. //更新前置点
  28742. if (this.smooth) {
  28743. this.updateAnother(this.backward, this.forward);
  28744. }
  28745. this.update();
  28746. this.lastControlPointSet = this.backward;
  28747. return this;
  28748. },
  28749. /**
  28750. * @method setSymReflaction()
  28751. * @for kity.BezierPoint
  28752. * @description 设定是否镜像两个控制点的位置
  28753. *
  28754. * @grammar setSymReflaction(value) => {this}
  28755. *
  28756. * @param {boolean} value 如果设置为 true,且贝塞尔点光滑,两个控制点离顶点的距离相等
  28757. */
  28758. setSymReflaction: function(value) {
  28759. this.symReflaction = value;
  28760. if (this.smooth) this.setSmooth(true);
  28761. return this;
  28762. },
  28763. /**
  28764. * @method isSymReflaction()
  28765. * @for kity.BezierPoint
  28766. * @description 当前贝塞尔点的两个控制点是否被镜像约束
  28767. *
  28768. * @grammar isSymReflaction() => {boolean}
  28769. */
  28770. isSymReflaction: function() {
  28771. return this.symReflaction;
  28772. },
  28773. /**
  28774. * @private
  28775. *
  28776. * 根据前方控制点或后方控制点更新另一方
  28777. */
  28778. updateAnother: function(p, q) {
  28779. var v = this.getVertex(), pv = Vector.fromPoints(p.getPoint(), v), vq = Vector.fromPoints(v, q.getPoint());
  28780. vq = pv.normalize(this.isSymReflaction() ? pv.length() : vq.length());
  28781. q.setPoint(v.x + vq.x, v.y + vq.y);
  28782. return this;
  28783. },
  28784. /**
  28785. * @method setSmooth()
  28786. * @for kity.BezierPoint
  28787. * @description 设置贝塞尔点是否光滑,光滑会约束顶点和两个控制点共线
  28788. *
  28789. * @param {Boolean} isSmooth 设置为 true 让贝塞尔点光滑
  28790. */
  28791. setSmooth: function(isSmooth) {
  28792. var lc;
  28793. this.smooth = !!isSmooth;
  28794. if (this.smooth && (lc = this.lastControlPointSet)) {
  28795. this.updateAnother(lc, lc == this.forward ? this.backward : this.forward);
  28796. }
  28797. return this;
  28798. },
  28799. /**
  28800. * @method isSmooth()
  28801. * @for kity.BezierPoint
  28802. * @description 判断贝塞尔点是否光滑
  28803. *
  28804. * @grammar isSmooth() => {boolean}
  28805. */
  28806. isSmooth: function() {
  28807. return this.smooth;
  28808. },
  28809. /**
  28810. * @method getVertex()
  28811. * @for kity.BezierPoint
  28812. * @description 获得当前贝塞尔点的顶点
  28813. *
  28814. * @grammar getVertex() => {kity.ShapePoint}
  28815. */
  28816. getVertex: function() {
  28817. return this.vertex.getPoint();
  28818. },
  28819. /**
  28820. * @method getForward()
  28821. * @for kity.BezierPoint
  28822. * @description 获得当前贝塞尔点的前方控制点
  28823. *
  28824. * @grammar getForward() => {kity.ShapePoint}
  28825. */
  28826. getForward: function() {
  28827. return this.forward.getPoint();
  28828. },
  28829. /**
  28830. * @method getBackward()
  28831. * @for kity.BezierPoint
  28832. * @description 获得当前贝塞尔点的后方控制点
  28833. *
  28834. * @grammar getBackward() => {kity.ShapePoint}
  28835. */
  28836. getBackward: function() {
  28837. return this.backward.getPoint();
  28838. },
  28839. /**
  28840. * @private
  28841. *
  28842. * 联动更新相关的贝塞尔曲线
  28843. */
  28844. update: function() {
  28845. if (!this.container) {
  28846. return this;
  28847. }
  28848. //新增参数 this, 把当前引起变化的点传递过去, 以便有需要的地方可以获取到引起变化的源
  28849. if (this.container.update) this.container.update(this);
  28850. }
  28851. });
  28852. return BezierPoint;
  28853. }
  28854. };
  28855. //src/graphic/box.js
  28856. /**
  28857. * @fileOverview
  28858. *
  28859. * 表示一个矩形区域
  28860. */
  28861. _p[25] = {
  28862. value: function(require, exports, module) {
  28863. /**
  28864. * @class kity.Box
  28865. * @description 表示一个矩形区域
  28866. */
  28867. var Box = _p.r(11).createClass("Box", {
  28868. /**
  28869. * @constructor
  28870. * @for kity.Box
  28871. *
  28872. * @grammar new kity.Box(x, y, width, height)
  28873. * @grammar new kity.Box(box)
  28874. *
  28875. * @param {Number} x|box.x 矩形区域的 x 坐标
  28876. * @param {Number} y|box.y 矩形区域的 y 坐标
  28877. * @param {Number} width|box.width 矩形区域的宽度
  28878. * @param {Number} height|box.height 矩形区域的高度
  28879. *
  28880. * @example
  28881. *
  28882. * ```js
  28883. * var box = new kity.Box(10, 20, 50, 50);
  28884. * var box2 = new kity.Box({x: 10, y: 20, width: 50, height: 50});
  28885. * ```
  28886. */
  28887. constructor: function(x, y, width, height) {
  28888. var box = arguments[0];
  28889. if (box && typeof box === "object") {
  28890. x = box.x;
  28891. y = box.y;
  28892. width = box.width;
  28893. height = box.height;
  28894. }
  28895. if (width < 0) {
  28896. x -= width = -width;
  28897. }
  28898. if (height < 0) {
  28899. y -= height = -height;
  28900. }
  28901. /**
  28902. * @property x
  28903. * @for kity.Box
  28904. * @type {Number}
  28905. * @readOnly
  28906. * @description 矩形区域的 x 坐标
  28907. */
  28908. this.x = x || 0;
  28909. /**
  28910. * @property y
  28911. * @for kity.Box
  28912. * @type {Number}
  28913. * @readOnly
  28914. * @description 矩形区域的 y 坐标
  28915. */
  28916. this.y = y || 0;
  28917. /**
  28918. * @property width
  28919. * @for kity.Box
  28920. * @type {Number}
  28921. * @readOnly
  28922. * @description 矩形区域的宽度
  28923. */
  28924. this.width = width || 0;
  28925. /**
  28926. * @property height
  28927. * @for kity.Box
  28928. * @type {Number}
  28929. * @readOnly
  28930. * @description 矩形区域的高度
  28931. */
  28932. this.height = height || 0;
  28933. /**
  28934. * @property left
  28935. * @for kity.Box
  28936. * @type {Number}
  28937. * @readOnly
  28938. * @description 矩形区域的最左侧坐标,等价于 x 的值
  28939. */
  28940. this.left = this.x;
  28941. /**
  28942. * @property right
  28943. * @for kity.Box
  28944. * @type {Number}
  28945. * @readOnly
  28946. * @description 矩形区域的最右侧坐标,等价于 x + width 的值
  28947. */
  28948. this.right = this.x + this.width;
  28949. /**
  28950. * @property top
  28951. * @for kity.Box
  28952. * @type {Number}
  28953. * @readOnly
  28954. * @description 矩形区域的最上侧坐标,等价于 y 的值
  28955. */
  28956. this.top = this.y;
  28957. /**
  28958. * @property bottom
  28959. * @for kity.Box
  28960. * @type {Number}
  28961. * @readOnly
  28962. * @description 矩形区域的最下侧坐标,等价于 y + height 的值
  28963. */
  28964. this.bottom = this.y + this.height;
  28965. /**
  28966. * @property cx
  28967. * @for kity.Box
  28968. * @type {Number}
  28969. * @readOnly
  28970. * @description 矩形区域的中心 x 坐标
  28971. */
  28972. this.cx = this.x + this.width / 2;
  28973. /**
  28974. * @property cy
  28975. * @for kity.Box
  28976. * @type {Number}
  28977. * @readOnly
  28978. * @description 矩形区域的中心 y 坐标
  28979. */
  28980. this.cy = this.y + this.height / 2;
  28981. },
  28982. /**
  28983. * @method getRangeX()
  28984. * @for kity.Box
  28985. * @description 获得矩形区域的 x 值域
  28986. *
  28987. * @grammar getRangeX() => {Number[]}
  28988. *
  28989. * @example
  28990. *
  28991. * var box = new kity.Box(10, 10, 30, 50);
  28992. * console.log(box.getRangeX()); // [10, 40]
  28993. */
  28994. getRangeX: function() {
  28995. return [ this.left, this.right ];
  28996. },
  28997. /**
  28998. * @method getRangeY()
  28999. * @for kity.Box
  29000. * @description 获得矩形区域的 y 值域
  29001. *
  29002. * @grammar getRangeY() => {Number[]}
  29003. *
  29004. * @example
  29005. *
  29006. * var box = new kity.Box(10, 10, 30, 50);
  29007. * console.log(box.getRangeY()); // [10, 60]
  29008. */
  29009. getRangeY: function() {
  29010. return [ this.top, this.bottom ];
  29011. },
  29012. /**
  29013. * @method merge()
  29014. * @for kity.Box
  29015. * @description 把当前矩形区域和指定的矩形区域合并,返回一个新的矩形区域(即包含两个源矩形区域的最小矩形区域)
  29016. *
  29017. * @grammar merge(another) => {kity.Box}
  29018. * @param {kity.Box} another 要合并的矩形区域
  29019. *
  29020. * @example
  29021. *
  29022. * ```js
  29023. * var box1 = new kity.Box(10, 10, 50, 50);
  29024. * var box2 = new kity.Box(30, 30, 50, 50);
  29025. * var box3 = box1.merge(box2);
  29026. * console.log(box3.valueOf()); // [10, 10, 70, 70]
  29027. * ```
  29028. */
  29029. merge: function(another) {
  29030. if (this.isEmpty()) {
  29031. return new Box(another.x, another.y, another.width, another.height);
  29032. }
  29033. var left = Math.min(this.left, another.left), right = Math.max(this.right, another.right), top = Math.min(this.top, another.top), bottom = Math.max(this.bottom, another.bottom);
  29034. return new Box(left, top, right - left, bottom - top);
  29035. },
  29036. /**
  29037. * @method intersect()
  29038. * @for kity.Box
  29039. * @description 求当前矩形区域和指定的矩形区域重叠的矩形区域
  29040. *
  29041. * @grammar intersect(another) => {kity.Box}
  29042. * @param {kity.Box} another 要求重叠的矩形区域
  29043. *
  29044. * @example
  29045. *
  29046. * ```js
  29047. * var box1 = new kity.Box(10, 10, 50, 50);
  29048. * var box2 = new kity.Box(30, 30, 50, 50);
  29049. * var box3 = box1.intersect(box2);
  29050. * console.log(box3.valueOf()); // [30, 30, 20, 20]
  29051. * ```
  29052. */
  29053. intersect: function(another) {
  29054. if (!another instanceof Box) {
  29055. another = new Box(another);
  29056. }
  29057. var left = Math.max(this.left, another.left), right = Math.min(this.right, another.right), top = Math.max(this.top, another.top), bottom = Math.min(this.bottom, another.bottom);
  29058. if (left > right || top > bottom) return new Box();
  29059. return new Box(left, top, right - left, bottom - top);
  29060. },
  29061. /**
  29062. * @method expand()
  29063. * @for kity.Box
  29064. * @description 扩展(或收缩)当前的盒子,返回新的盒子
  29065. *
  29066. * @param {Number} top
  29067. * 矩形区域的上边界往上扩展的值;如果是负数,则上边界往下收缩
  29068. *
  29069. * @param {Number} right
  29070. * [Optional] 矩形区域的右边界往右拓展的值;
  29071. * 如果是负数,则右边界往左收缩;
  29072. * 如果不设置该值,使用和 top 同样的值。
  29073. *
  29074. * @param {Number} bottom
  29075. * [Optional] 矩形区域的下边界往下拓展的值;
  29076. * 如果是负数,则下边界往上收缩;
  29077. * 如果不设置该值,使用和 top 同样的值。
  29078. *
  29079. * @param {Number} left
  29080. * [Optional] 矩形区域的左边界往左拓展的值;
  29081. * 如果是负数,则左边界往右收缩;
  29082. * 如果不设置该值,使用和 right 同样的值。
  29083. *
  29084. * @example
  29085. *
  29086. * ```js
  29087. * var box = new kity.Box(10, 10, 20, 20);
  29088. * var box1 = box.expand(10); // [0, 0, 40, 40]
  29089. * var box2 = box.expand(10, 20); // [0, -10, 40, 60]
  29090. * var box3 = box.expand(1, 2, 3, 4); // [9, 8, 24, 26]
  29091. * ```
  29092. */
  29093. expand: function(top, right, bottom, left) {
  29094. if (arguments.length < 1) {
  29095. return new Box(this);
  29096. }
  29097. if (arguments.length < 2) {
  29098. right = top;
  29099. }
  29100. if (arguments.length < 3) {
  29101. bottom = top;
  29102. }
  29103. if (arguments.length < 4) {
  29104. left = right;
  29105. }
  29106. var x = this.left - left, y = this.top - top, width = this.width + right, height = this.height + top;
  29107. return new Box(x, y, width, height);
  29108. },
  29109. /**
  29110. * @method valueOf()
  29111. * @for kity.Box
  29112. * @description 返回当前盒子的数组表示
  29113. *
  29114. * @grammar valueOf() => {Number[]}
  29115. *
  29116. * @example
  29117. *
  29118. * ```js
  29119. * var box = new kity.Box(0, 0, 200, 50);
  29120. * console.log(box.valueOf()); // [0, 0, 200, 50]
  29121. * ```
  29122. */
  29123. valueOf: function() {
  29124. return [ this.x, this.y, this.width, this.height ];
  29125. },
  29126. /**
  29127. * @method toString()
  29128. * @for kity.Box
  29129. * @description 返回当前盒子的字符串表示
  29130. *
  29131. * @grammar toString() => {String}
  29132. *
  29133. * @example
  29134. *
  29135. * ```js
  29136. * var box = new kity.Box(0, 0, 200, 50);
  29137. * console.log(box.toString()); // "0 0 200 50"
  29138. */
  29139. toString: function() {
  29140. return this.valueOf().join(" ");
  29141. },
  29142. /**
  29143. * @method isEmpty()
  29144. * @for kity.Box
  29145. * @description 判断当前盒子是否具有尺寸(面积大
  29146. *
  29147. * @grammar isEmpty() => {boolean}
  29148. *
  29149. * @example
  29150. * ```js
  29151. * var box = new kity.Box(0, 0, 0, 100000);
  29152. * console.log(box.isEmpty()); // true
  29153. * ```
  29154. */
  29155. isEmpty: function() {
  29156. return !this.width || !this.height;
  29157. }
  29158. });
  29159. /**
  29160. * @method parse()
  29161. * @static
  29162. * @for kity.Box
  29163. * @description 解析一个字符串或数组为 kity.Box 对象
  29164. *
  29165. * @grammar kity.Box.parse(any) => {kity.Box}
  29166. *
  29167. * @param {Number[]|String} any 要解析的字符串或数组
  29168. *
  29169. * @example
  29170. *
  29171. * ```js
  29172. * console.log(kity.Box.parse('0 0 100 200'));
  29173. * console.log(kity.Box.parse([0, 0, 100, 200]));
  29174. * ```
  29175. */
  29176. Box.parse = function(any) {
  29177. if (typeof any == "string") {
  29178. return Box.parse(any.split(/[\s,]+/).map(parseFloat));
  29179. }
  29180. if (any instanceof Array) {
  29181. return new Box(any[0], any[1], any[2], any[3]);
  29182. }
  29183. if ("x" in any) return new Box(any);
  29184. return null;
  29185. };
  29186. return Box;
  29187. }
  29188. };
  29189. //src/graphic/circle.js
  29190. /**
  29191. * @fileOverview
  29192. *
  29193. * 绘制和使用圆形
  29194. */
  29195. _p[26] = {
  29196. value: function(require, exports, module) {
  29197. /**
  29198. * @class kity.Circle
  29199. * @base kity.Ellipse
  29200. * @description 表示一个圆形
  29201. */
  29202. return _p.r(11).createClass("Circle", {
  29203. base: _p.r(32),
  29204. /**
  29205. * @constructor
  29206. * @for kity.Circle
  29207. *
  29208. * @grammar new kity.Circle(radius, cx, cy)
  29209. *
  29210. * @param {Number} radius 半径
  29211. * @param {Number} cx 圆心 x 坐标
  29212. * @param {Number} cy 圆心 y 坐标
  29213. */
  29214. constructor: function(radius, cx, cy) {
  29215. this.callBase(radius, radius, cx, cy);
  29216. },
  29217. /**
  29218. * @method
  29219. * @for kity.Circle
  29220. * @description 获取圆形的半径
  29221. *
  29222. * @grammar getRadius() => {Number}
  29223. */
  29224. getRadius: function() {
  29225. return this.getRadiusX();
  29226. },
  29227. /**
  29228. * @method
  29229. * @for kity.Circle
  29230. * @description 设置圆形的半径
  29231. *
  29232. * @grammar setRadius() => {this}
  29233. *
  29234. * @param {Number} radius 半径大小
  29235. */
  29236. setRadius: function(radius) {
  29237. return this.callBase(radius, radius);
  29238. }
  29239. });
  29240. }
  29241. };
  29242. //src/graphic/clip.js
  29243. /**
  29244. * @fileOverview
  29245. *
  29246. * 支持图形裁切
  29247. */
  29248. _p[27] = {
  29249. value: function(require, exports, module) {
  29250. var Class = _p.r(11);
  29251. var Shape = _p.r(60);
  29252. /**
  29253. * @class kity.Clip
  29254. * @base kity.Resource
  29255. * @mixins kity.ShapeContainer
  29256. *
  29257. * @description 创建图形裁切,用于裁切目标图形
  29258. */
  29259. var Clip = Class.createClass("Clip", {
  29260. base: Shape,
  29261. mixins: [ _p.r(61) ],
  29262. /**
  29263. * @constructor
  29264. * @for kity.Clip
  29265. *
  29266. * @grammar new kity.Clip(paper)
  29267. *
  29268. * @param {kity.Paper} paper 资源所属的文档
  29269. *
  29270. * @example
  29271. *
  29272. * ```js
  29273. * var circle = paper.put(new kity.Circle(100).fill('yellow'));
  29274. * var clip = new kity.Clip(paper);
  29275. * clip.addShape(new kity.Circle(100, 50, 0));
  29276. * clip.clip(circle);
  29277. * ```
  29278. */
  29279. constructor: function(paper) {
  29280. this.callBase("clipPath", paper);
  29281. },
  29282. /**
  29283. * @method clip()
  29284. * @for kity.Clip
  29285. * @description 将裁切应用到指定的图形上,应用之后,目标图形将显示与裁切形状重合的部分
  29286. *
  29287. * @grammar clip(shape) => {this}
  29288. *
  29289. * @param {kity.Shape} shape 要应用裁切的图形
  29290. */
  29291. clip: function(shape) {
  29292. shape.getNode().setAttribute("clip-path", this);
  29293. return this;
  29294. }
  29295. });
  29296. Class.extendClass(Shape, {
  29297. /**
  29298. * @method clipWidth()
  29299. * @for kity.Shape
  29300. *
  29301. * @grammar clipWidth(clip) => {this}
  29302. *
  29303. * @param {kity.Clip|kity.Shape} clip 要用于裁切当前图形的图形;
  29304. * 如果 clip 本身是一个裁切对象(kity.Clip 类型),则直接裁切;
  29305. * 否则将创建新的裁切包含给定的图形,然后对当前图形进行裁切
  29306. *
  29307. * @example
  29308. *
  29309. * ```js
  29310. * var circle = paper.put(new kity.Circle(100));
  29311. * var rect = paper.put(new kity.Rect(100, 100, -100, 0));
  29312. *
  29313. * circle.clipWidth(rect);
  29314. * ```
  29315. */
  29316. clipWith: function(clip) {
  29317. if (clip instanceof Shape) {
  29318. clip = new Clip(clip.getPaper()).addShape(clip);
  29319. }
  29320. clip.clip(this);
  29321. return this;
  29322. }
  29323. });
  29324. return Clip;
  29325. }
  29326. };
  29327. //src/graphic/color.js
  29328. /**
  29329. * @fileOverview
  29330. *
  29331. * 提供颜色支持
  29332. */
  29333. _p[28] = {
  29334. value: function(require, exports, module) {
  29335. var Utils = _p.r(12), StandardColor = _p.r(64), ColorUtils = {}, /**
  29336. * @class kity.Color
  29337. * @description 表示一个颜色
  29338. */
  29339. Color = _p.r(11).createClass("Color", {
  29340. /**
  29341. * @constructor
  29342. * @for kity.Color
  29343. *
  29344. * @grammar new kity.Color(r, g, b)
  29345. * @grammar new kity.Color(r, g, b, a)
  29346. * @grammar new kity.Color(colorString)
  29347. *
  29348. * @param {Number} r 红色分量,取值 0 - 255
  29349. * @param {Number} g 绿色分量,取值 0 - 255
  29350. * @param {Number} b 蓝色分量,取值 0 - 255
  29351. * @param {Number} a 透明度(可选),取值 0 - 100
  29352. * @param {String} colorString 一个代表颜色的字符串,可以是:
  29353. * 熟知颜色表:如 'red', 'yellow'
  29354. * HEX 表示:如 '#368', '#123456'
  29355. * RGB 表示:如 'RGB(200, 200, 0)', 'RGBA(200, 200, 200, .5)'
  29356. * HSL 表示:如 'HSL(100, 60%, 80%)', 'HSLA(100, 60%, 80%, .5)'
  29357. */
  29358. constructor: function() {
  29359. var colorValue = null;
  29360. //parse构造
  29361. if (typeof arguments[0] === "string") {
  29362. colorValue = ColorUtils.parseToValue(arguments[0]);
  29363. //解析失败
  29364. if (colorValue === null) {
  29365. colorValue = {
  29366. r: 0,
  29367. g: 0,
  29368. b: 0,
  29369. h: 0,
  29370. s: 0,
  29371. l: 0,
  29372. a: 1
  29373. };
  29374. }
  29375. } else {
  29376. colorValue = {
  29377. r: arguments[0] | 0,
  29378. g: arguments[1] | 0,
  29379. b: arguments[2] | 0,
  29380. //alpha 默认为1
  29381. a: arguments[3] === undefined ? 1 : parseFloat(arguments[3])
  29382. };
  29383. colorValue = ColorUtils.overflowFormat(colorValue);
  29384. //获取hsl分量
  29385. colorValue = Utils.extend(colorValue, ColorUtils.rgbValueToHslValue(colorValue));
  29386. }
  29387. this._color = colorValue;
  29388. },
  29389. /**
  29390. * @method set()
  29391. * @for kity.Color
  29392. *
  29393. * @description 设置当前颜色某个分量的值
  29394. *
  29395. * @grammar set(name, value) => {this}
  29396. *
  29397. * @param {string} name 要设置的颜色通道的名称
  29398. * r: 红色(Red),取值范围 [0, 255]
  29399. * g: 绿色(Green),取值范围 [0, 255]
  29400. * b: 蓝色(Blue),取值范围 [0, 255]
  29401. * a: 透明度(Alpha),取值范围 [0, 1]
  29402. * h: 色环角度(Hue),取值范围 [0, 359]
  29403. * s: 饱和度(Saturation),取值范围 [0, 100]
  29404. * l: 亮度(Lightness),取值范围 [0, 100]
  29405. * r、g、b 值和 h、s、l 值会联动修改
  29406. * @param {number} value 要设置的值
  29407. */
  29408. set: function(name, value) {
  29409. var values = null;
  29410. //设置的值非法
  29411. if (!Color._MAX_VALUE[name]) {
  29412. throw new Error("Color set(): Illegal parameter");
  29413. }
  29414. if (name !== "a") {
  29415. value = Math.floor(value);
  29416. }
  29417. if (name == "h") {
  29418. value = (value + 360) % 360;
  29419. }
  29420. this._color[name] = Math.max(Color._MIN_VALUE[name], Math.min(Color._MAX_VALUE[name], value));
  29421. if ("rgb".indexOf(name) !== -1) {
  29422. this._color = Utils.extend(this._color, ColorUtils.rgbValueToHslValue(this._color));
  29423. } else if ("hsl".indexOf(name) !== -1) {
  29424. this._color = Utils.extend(this._color, ColorUtils.hslValueToRGBValue(this._color));
  29425. }
  29426. return this;
  29427. },
  29428. /**
  29429. * @method inc()
  29430. *
  29431. * @description 返回新的颜色,表示当前颜色增加指定通道的值之后的颜色
  29432. *
  29433. * @grammar inc(name, value) => {this}
  29434. *
  29435. * @param {string} name 要增加的通道的名称,具体含义请查看 set 方法
  29436. * @param {number} value 增量值
  29437. */
  29438. inc: function(name, value) {
  29439. value = this.get(name) + value;
  29440. if (name == "h") {
  29441. value = (value + 360) % 360;
  29442. } else {
  29443. value = Math.min(Color._MAX_VALUE[name], value);
  29444. value = Math.max(Color._MIN_VALUE[name], value);
  29445. }
  29446. return this.clone().set(name, value);
  29447. },
  29448. /**
  29449. * @method dec()
  29450. * @for kity.Color
  29451. *
  29452. * @description 返回新的颜色,表示当前颜色减少指定通道的值之后的颜色
  29453. *
  29454. * @grammar dec(name, value) => {this}
  29455. *
  29456. * @param {string} name 要减少值的通道的名称,具体含义请查看 set 方法
  29457. * @param {number} value 减量值
  29458. */
  29459. dec: function(name, value) {
  29460. return this.inc(name, -value);
  29461. },
  29462. /**
  29463. * @method clone()
  29464. * @for kity.Color
  29465. *
  29466. * @description 返回当前颜色的一个拷贝
  29467. *
  29468. * @grammar clone() => {kity.Color}
  29469. */
  29470. clone: function() {
  29471. return new Color(this.toRGBA());
  29472. },
  29473. /**
  29474. * @method get()
  29475. * @for kity.Color
  29476. *
  29477. * @description 返回当前颜色指定的分量
  29478. *
  29479. * @grammar get() => {number}
  29480. */
  29481. get: function(name) {
  29482. if (!Color._MAX_VALUE[name]) {
  29483. return null;
  29484. }
  29485. return this._color[name];
  29486. },
  29487. getValues: function() {
  29488. return Utils.clone(this._color);
  29489. },
  29490. /**
  29491. * @method valueOf()
  29492. * @for kity.Color
  29493. *
  29494. * @description 返回当前颜色的一个字面量表示
  29495. *
  29496. * @return {plain} 颜色字面量,其结构为:
  29497. * {
  29498. * r: 0,
  29499. * g: 0,
  29500. * b: 0,
  29501. * a: 0,
  29502. * h: 0,
  29503. * s: 0,
  29504. * l: 0
  29505. * }
  29506. */
  29507. valueOf: function() {
  29508. return this.getValues();
  29509. },
  29510. /**
  29511. * @method toRGB()
  29512. * @for kity.Color
  29513. *
  29514. * @description 返回当前颜色的 RGB 表示,如果颜色有透明度,将抛弃透明度属性(想要保留请使用 toRGBA())方法。
  29515. *
  29516. * @grammar toRGB() => {string}
  29517. */
  29518. toRGB: function() {
  29519. return ColorUtils.toString(this._color, "rgb");
  29520. },
  29521. /**
  29522. * @method toRGBA()
  29523. * @for kity.Color
  29524. *
  29525. * @description 返回当前颜色的 RGBA 表示
  29526. *
  29527. * @grammar toRGBA() => {string}
  29528. */
  29529. toRGBA: function() {
  29530. return ColorUtils.toString(this._color, "rgba");
  29531. },
  29532. /**
  29533. * @method toHEX()
  29534. * @for kity.Color
  29535. *
  29536. * @description 返回当前颜色的 HEX 表示,如果颜色有透明度,将抛弃透明度属性(想要保留请使用 toRGBA())方法。
  29537. *
  29538. * @grammar toHEX() => {string}
  29539. */
  29540. toHEX: function() {
  29541. return ColorUtils.toString(this._color, "hex");
  29542. },
  29543. /**
  29544. * @method toHSL()
  29545. * @for kity.Color
  29546. *
  29547. * @description 返回当前颜色的 HSL 表示,如果颜色有透明度,将抛弃透明度属性(想要保留请使用 toHSLA())方法。
  29548. *
  29549. * @grammar toHSL() => {string}
  29550. */
  29551. toHSL: function() {
  29552. return ColorUtils.toString(this._color, "hsl");
  29553. },
  29554. /**
  29555. * @method toHSLA()
  29556. * @for kity.Color
  29557. *
  29558. * @description 返回当前颜色的 HSLA 表示
  29559. *
  29560. * @grammar toHSLA() => {string}
  29561. */
  29562. toHSLA: function() {
  29563. return ColorUtils.toString(this._color, "hsla");
  29564. },
  29565. /**
  29566. * @method toString()
  29567. * @for kity.Color
  29568. *
  29569. * @description 返回当前颜色的 RGB 或 RGBA 表示,如果颜色有透明度,将使用 RGBA 形式,否则是 RGB 形式
  29570. * @grammar toString() => {string}
  29571. */
  29572. toString: function() {
  29573. if (this._color.a === 1) {
  29574. return this.toRGB();
  29575. }
  29576. return this.toRGBA();
  29577. }
  29578. });
  29579. //Color 静态方法
  29580. Utils.extend(Color, {
  29581. //各分量可表示的最大值
  29582. _MAX_VALUE: {
  29583. r: 255,
  29584. g: 255,
  29585. b: 255,
  29586. h: 360,
  29587. s: 100,
  29588. l: 100,
  29589. a: 1
  29590. },
  29591. //各分量最小值
  29592. _MIN_VALUE: {
  29593. r: 0,
  29594. g: 0,
  29595. b: 0,
  29596. h: 0,
  29597. s: 0,
  29598. l: 0,
  29599. a: 0
  29600. },
  29601. //分量常量
  29602. R: "r",
  29603. G: "g",
  29604. B: "b",
  29605. H: "h",
  29606. S: "s",
  29607. L: "l",
  29608. A: "a",
  29609. /**
  29610. * @method parse()
  29611. * @static
  29612. * @for kity.Color
  29613. *
  29614. * @description 解析一个颜色字符串为 kity.Color 对象
  29615. *
  29616. * @grammar kity.Color.parse(valStr)
  29617. *
  29618. * @param {string} valStr 一个代表颜色的字符串,可以是:
  29619. * 熟知颜色表:如 'red', 'yellow'
  29620. * HEX 表示:如 '#368', '#123456'
  29621. * RGB 表示:如 'RGB(200, 200, 0)', 'RGBA(200, 200, 200, .5)'
  29622. * HSL 表示:如 'HSL(100, 60%, 80%)', 'HSLA(100, 60%, 80%, .5)'
  29623. */
  29624. parse: function(valStr) {
  29625. var rgbValue;
  29626. if (Utils.isString(valStr)) {
  29627. rgbValue = ColorUtils.parseToValue(valStr);
  29628. }
  29629. if (Utils.isObject(valStr) && "r" in valStr) {
  29630. rgbValue = valStr;
  29631. }
  29632. //解析失败, 返回一个默认color实例
  29633. if (rgbValue === null) {
  29634. return new Color();
  29635. }
  29636. return new Color(rgbValue.r, rgbValue.g, rgbValue.b, rgbValue.a);
  29637. },
  29638. /**
  29639. * @method createHSL()
  29640. * @for kity.Color
  29641. * @static
  29642. *
  29643. * @description 创建一个 HSL 颜色
  29644. *
  29645. * @grammar kity.Color.createHSL(h, s, l) => {kity.Color}
  29646. *
  29647. * @param {number} h 色环(Hue)分量值,取值范围 [0, 359]
  29648. * @param {number} s 饱和度(Saturation)分量值,取值范围 [0, 100]
  29649. * @param {number} l 亮度(Lighteness)分量值,取值范围 [0, 100]
  29650. */
  29651. createHSL: function(h, s, l) {
  29652. return Color.createHSLA(h, s, l, 1);
  29653. },
  29654. /**
  29655. * @method createHSLA()
  29656. * @for kity.Color
  29657. * @static
  29658. *
  29659. * @description 创建一个 HSLA 颜色
  29660. *
  29661. * @grammar kity.Color.createHSLA(h, s, l, a) => {kity.Color}
  29662. *
  29663. * @param {number} h 色环(Hue)分量值,取值范围 [0, 359]
  29664. * @param {number} s 饱和度(Saturation)分量值,取值范围 [0, 100]
  29665. * @param {number} l 亮度(Lighteness)分量值,取值范围 [0, 100]
  29666. * @param {number} a 透明度(Alpha)分量值,取值范围 [0, 1]
  29667. */
  29668. createHSLA: function(h, s, l, a) {
  29669. var colorValue = null;
  29670. s += "%";
  29671. l += "%";
  29672. colorValue = [ "hsla(" + h, s, l, a + ")" ];
  29673. return Color.parse(colorValue.join(", "));
  29674. },
  29675. /**
  29676. * @method createRGB()
  29677. * @for kity.Color
  29678. * @static
  29679. *
  29680. * @description 创建一个 RGB 颜色
  29681. *
  29682. * @grammar kity.Color.createRGB(r, g, b) => {kity.Color}
  29683. *
  29684. * @param {number} r 红色(Red)分量值,取值范围 [0, 255]
  29685. * @param {number} g 绿色(Green)分量值,取值范围 [0, 255]
  29686. * @param {number} b 蓝色(Blue)分量值,取值范围 [0, 255]
  29687. */
  29688. createRGB: function(r, g, b) {
  29689. return Color.createRGBA(r, g, b, 1);
  29690. },
  29691. /**
  29692. * @method createRGBA()
  29693. * @for kity.Color
  29694. * @static
  29695. *
  29696. * @description 创建一个 RGBA 颜色
  29697. *
  29698. * @grammar kity.Color.createRGBA(r, g, b, a) => {kity.Color}
  29699. *
  29700. * @param {number} r 红色(Red)分量值,取值范围 [0, 255]
  29701. * @param {number} g 绿色(Green)分量值,取值范围 [0, 255]
  29702. * @param {number} b 蓝色(Blue)分量值,取值范围 [0, 255]
  29703. * @param {number} a 透明度(Alpha)分量值,取值范围 [0, 1]
  29704. */
  29705. createRGBA: function(r, g, b, a) {
  29706. return new Color(r, g, b, a);
  29707. }
  29708. });
  29709. //内部工具对象
  29710. Utils.extend(ColorUtils, {
  29711. parseToValue: function(valStr) {
  29712. var rgbaValue = {};
  29713. /* 优先检测在调色板中是否有对应的颜色 */
  29714. valStr = StandardColor.EXTEND_STANDARD[valStr] || StandardColor.COLOR_STANDARD[valStr] || valStr;
  29715. /* 颜色转换 */
  29716. //hex格式
  29717. if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(valStr)) {
  29718. rgbaValue = ColorUtils.hexToValue(valStr);
  29719. } else if (/^(rgba?)/i.test(valStr)) {
  29720. rgbaValue = ColorUtils.rgbaToValue(valStr);
  29721. } else if (/^(hsla?)/i.test(valStr)) {
  29722. rgbaValue = ColorUtils.hslaToValue(valStr);
  29723. } else {
  29724. return null;
  29725. }
  29726. return ColorUtils.overflowFormat(rgbaValue);
  29727. },
  29728. hexToValue: function(hexStr) {
  29729. var result = {}, keys = [ "r", "g", "b" ];
  29730. if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(hexStr)) {
  29731. hexStr = RegExp.$1.split("");
  29732. Utils.each(keys, function(key, index) {
  29733. if (hexStr.length === 3) {
  29734. result[key] = ColorUtils.toNumber(hexStr[index] + hexStr[index]);
  29735. } else {
  29736. result[key] = ColorUtils.toNumber(hexStr[index * 2] + hexStr[index * 2 + 1]);
  29737. }
  29738. });
  29739. //转换出hsl值
  29740. result = Utils.extend(result, ColorUtils.rgbValueToHslValue(result));
  29741. result.a = 1;
  29742. return result;
  29743. }
  29744. return null;
  29745. },
  29746. rgbaToValue: function(rgbaStr) {
  29747. var result = {}, hasAlpha = false, keys = [ "r", "g", "b" ];
  29748. if (/^(rgba?)/i.test(rgbaStr)) {
  29749. hasAlpha = RegExp.$1.length === 4;
  29750. rgbaStr = rgbaStr.replace(/^rgba?/i, "").replace(/\s+/g, "").replace(/[^0-9,.]/g, "").split(",");
  29751. Utils.each(keys, function(key, index) {
  29752. result[key] = rgbaStr[index] | 0;
  29753. });
  29754. //转换出hsl值
  29755. result = Utils.extend(result, ColorUtils.rgbValueToHslValue(result));
  29756. result.a = hasAlpha ? parseFloat(rgbaStr[3]) : 1;
  29757. return result;
  29758. }
  29759. return null;
  29760. },
  29761. hslaToValue: function(hslaStr) {
  29762. var result = {}, hasAlpha = false;
  29763. if (/^(hsla?)/i.test(hslaStr)) {
  29764. hasAlpha = RegExp.$1.length === 4;
  29765. hslaStr = hslaStr.replace(/^hsla?/i, "").replace(/\s+/g, "").replace(/[^0-9,.]/g, "").split(",");
  29766. //记录hsl值
  29767. result.h = hslaStr[0] | 0;
  29768. result.s = hslaStr[1] | 0;
  29769. result.l = hslaStr[2] | 0;
  29770. //转换出rgb值
  29771. result = Utils.extend(result, ColorUtils.hslValueToRGBValue(result));
  29772. //hsl值转换为rgb值
  29773. result = ColorUtils.hslValueToRGBValue(result);
  29774. result.a = hasAlpha ? parseFloat(hslaStr[3]) : 1;
  29775. return result;
  29776. }
  29777. return null;
  29778. },
  29779. //hsl值对象转换为rgb值对象
  29780. hslValueToRGBValue: function(hslValue) {
  29781. function trans(v1, v2, vH) {
  29782. if (vH < 0) {
  29783. vH += 1;
  29784. } else if (vH > 1) {
  29785. vH -= 1;
  29786. }
  29787. if (6 * vH < 1) {
  29788. return v1 + (v2 - v1) * 6 * vH;
  29789. } else if (2 * vH < 1) {
  29790. return v2;
  29791. } else if (3 * vH < 2) {
  29792. return v1 + (v2 - v1) * ((2 / 3 - vH) * 6);
  29793. }
  29794. return v1;
  29795. }
  29796. var q = null, p = null, result = {};
  29797. hslValue = Utils.extend({}, hslValue);
  29798. hslValue.h = hslValue.h / 360;
  29799. hslValue.s = hslValue.s / 100;
  29800. hslValue.l = hslValue.l / 100;
  29801. //分量计算
  29802. if (hslValue.s === 0) {
  29803. result.r = result.g = result.b = hslValue.l;
  29804. } else {
  29805. if (hslValue.l < .5) {
  29806. q = hslValue.l * (1 + hslValue.s);
  29807. } else {
  29808. q = hslValue.l + hslValue.s - hslValue.l * hslValue.s;
  29809. }
  29810. p = 2 * hslValue.l - q;
  29811. result.r = trans(p, q, hslValue.h + 1 / 3);
  29812. result.g = trans(p, q, hslValue.h);
  29813. result.b = trans(p, q, hslValue.h - 1 / 3);
  29814. }
  29815. result.r = Math.min(Math.round(result.r * 255), 255);
  29816. result.g = Math.min(Math.round(result.g * 255), 255);
  29817. result.b = Math.min(Math.round(result.b * 255), 255);
  29818. return result;
  29819. },
  29820. //rgb值对象转换为hsl值对象
  29821. rgbValueToHslValue: function(rgbValue) {
  29822. var max = null, min = null, result = {};
  29823. rgbValue = Utils.extend({}, rgbValue);
  29824. rgbValue.r = rgbValue.r / 255;
  29825. rgbValue.g = rgbValue.g / 255;
  29826. rgbValue.b = rgbValue.b / 255;
  29827. max = Math.max(rgbValue.r, rgbValue.g, rgbValue.b);
  29828. min = Math.min(rgbValue.r, rgbValue.g, rgbValue.b);
  29829. //h分量计算
  29830. if (max === min) {
  29831. result.h = 0;
  29832. } else if (max === rgbValue.r) {
  29833. if (rgbValue.g >= rgbValue.b) {
  29834. result.h = 60 * (rgbValue.g - rgbValue.b) / (max - min);
  29835. } else {
  29836. result.h = 60 * (rgbValue.g - rgbValue.b) / (max - min) + 360;
  29837. }
  29838. } else if (max === rgbValue.g) {
  29839. result.h = 60 * (rgbValue.b - rgbValue.r) / (max - min) + 120;
  29840. } else if (max === rgbValue.b) {
  29841. result.h = 60 * (rgbValue.r - rgbValue.g) / (max - min) + 240;
  29842. }
  29843. //l分量计算
  29844. result.l = (max + min) / 2;
  29845. //s分量计算
  29846. if (result.l === 0 || max === min) {
  29847. result.s = 0;
  29848. } else if (result.l > 0 && result.l <= .5) {
  29849. result.s = (max - min) / (max + min);
  29850. } else {
  29851. result.s = (max - min) / (2 - max - min);
  29852. }
  29853. //格式化hsl结果
  29854. result.h = Math.round(result.h);
  29855. result.s = Math.round(result.s * 100);
  29856. result.l = Math.round(result.l * 100);
  29857. return result;
  29858. },
  29859. toString: function(colorValue, type) {
  29860. var vals = [];
  29861. colorValue = Utils.extend({}, colorValue);
  29862. if (type.indexOf("hsl") !== -1) {
  29863. colorValue.s += "%";
  29864. colorValue.l += "%";
  29865. }
  29866. if (type !== "hex") {
  29867. Utils.each(type.split(""), function(key) {
  29868. vals.push(colorValue[key]);
  29869. });
  29870. return (type + "(" + vals.join(", ") + ")").toLowerCase();
  29871. } else {
  29872. vals.push(ColorUtils.toHexValue(+colorValue.r));
  29873. vals.push(ColorUtils.toHexValue(+colorValue.g));
  29874. vals.push(ColorUtils.toHexValue(+colorValue.b));
  29875. return ("#" + vals.join("")).toLowerCase();
  29876. }
  29877. },
  29878. //16进制的2个数字转化为10进制, 如果转化失败, 返回0
  29879. toNumber: function(value) {
  29880. return Number("0x" + value) | 0;
  29881. },
  29882. toHexValue: function(value) {
  29883. var result = value.toString(16);
  29884. return result.length === 1 ? "0" + result : result;
  29885. },
  29886. //溢出控制
  29887. overflowFormat: function(value) {
  29888. var tmpValue = Utils.extend({}, value), keys = "rgba";
  29889. Utils.each(keys.split(""), function(key) {
  29890. if (!tmpValue.hasOwnProperty(key)) {
  29891. return;
  29892. }
  29893. //上溢出
  29894. tmpValue[key] = Math.min(Color._MAX_VALUE[key], tmpValue[key]);
  29895. //下溢出
  29896. tmpValue[key] = Math.max(Color._MIN_VALUE[key], tmpValue[key]);
  29897. });
  29898. return tmpValue;
  29899. }
  29900. });
  29901. return Color;
  29902. }
  29903. };
  29904. //src/graphic/container.js
  29905. _p[29] = {
  29906. value: function(require, exports, module) {
  29907. function itemRemove() {
  29908. this.container.removeItem(this);
  29909. return this;
  29910. }
  29911. return _p.r(11).createClass("Container", {
  29912. getItems: function() {
  29913. return this.items || (this.items = []);
  29914. },
  29915. getItem: function(index) {
  29916. return this.getItems()[index];
  29917. },
  29918. getFirstItem: function() {
  29919. return this.getItem(0);
  29920. },
  29921. getLastItem: function() {
  29922. return this.getItem(this.getItems().length - 1);
  29923. },
  29924. indexOf: function(item) {
  29925. return this.getItems().indexOf(item);
  29926. },
  29927. eachItem: function(fn) {
  29928. var items = this.getItems(), length = items.length, i;
  29929. for (i = 0; i < length; i++) {
  29930. fn.call(this, i, items[i]);
  29931. }
  29932. return this;
  29933. },
  29934. addItem: function(item, pos, noEvent) {
  29935. var items = this.getItems(), length = items.length;
  29936. if (~items.indexOf(item)) {
  29937. return this;
  29938. }
  29939. if (!(pos >= 0 && pos < length)) {
  29940. pos = length;
  29941. }
  29942. items.splice(pos, 0, item);
  29943. if (typeof item === "object") {
  29944. item.container = this;
  29945. item.remove = itemRemove;
  29946. }
  29947. this.handleAdd(item, pos);
  29948. if (!noEvent) {
  29949. this.onContainerChanged("add", [ item ]);
  29950. }
  29951. return this;
  29952. },
  29953. addItems: function(items) {
  29954. for (var i = 0, l = items.length; i < l; i++) {
  29955. this.addItem(items[i], -1, true);
  29956. }
  29957. this.onContainerChanged("add", items);
  29958. return this;
  29959. },
  29960. setItems: function(items) {
  29961. return this.clear().addItems(items);
  29962. },
  29963. appendItem: function(item) {
  29964. return this.addItem(item);
  29965. },
  29966. prependItem: function(item) {
  29967. return this.addItem(item, 0);
  29968. },
  29969. removeItem: function(pos, noEvent) {
  29970. if (typeof pos !== "number") {
  29971. return this.removeItem(this.indexOf(pos));
  29972. }
  29973. var items = this.getItems(), length = items.length, item = items[pos];
  29974. if (item === undefined) {
  29975. return this;
  29976. }
  29977. items.splice(pos, 1);
  29978. if (item.container) {
  29979. delete item.container;
  29980. }
  29981. if (item.remove) {
  29982. delete item.remove;
  29983. }
  29984. this.handleRemove(item, pos);
  29985. if (!noEvent) {
  29986. this.onContainerChanged("remove", [ item ]);
  29987. }
  29988. return this;
  29989. },
  29990. clear: function() {
  29991. var removed = [];
  29992. var item;
  29993. while (item = this.getFirstItem()) {
  29994. removed.push(item);
  29995. this.removeItem(0, true);
  29996. }
  29997. this.onContainerChanged("remove", removed);
  29998. return this;
  29999. },
  30000. onContainerChanged: function(type, items) {},
  30001. handleAdd: function(item, index) {},
  30002. handleRemove: function(item, index) {}
  30003. });
  30004. }
  30005. };
  30006. //src/graphic/curve.js
  30007. /*
  30008. * 曲线
  30009. * */
  30010. _p[30] = {
  30011. value: function(require, exports, module) {
  30012. var Utils = _p.r(12), CurveUtil = {
  30013. /*
  30014. * 获取由两个以上的点组成的曲线的平移线
  30015. * @param points 曲线上的点的集合, 集合中的点的数量必须大于2
  30016. * @return 平移线数组
  30017. */
  30018. getCurvePanLines: function(points, smoothFactor) {
  30019. //计算原始点的中点坐标
  30020. var centerPoints = CurveUtil.getCenterPoints(points), //注意:计算中点连线的中点坐标, 得出平移线
  30021. panLines = CurveUtil.getPanLine(points.length, centerPoints);
  30022. //平移线移动到顶点
  30023. return CurveUtil.getMovedPanLines(points, panLines, smoothFactor);
  30024. },
  30025. /*
  30026. * 计算给定点集合的连线的中点
  30027. * @param points
  30028. */
  30029. getCenterPoints: function(points) {
  30030. var centerPoints = {}, key = null;
  30031. for (var i = 0, j = 0, len = points.length; i < len; i++) {
  30032. //j是下一个点的索引
  30033. j = i === len - 1 ? 0 : i + 1;
  30034. key = i + "," + j;
  30035. //计算中点坐标
  30036. centerPoints[key] = {
  30037. x: (points[i].x + points[j].y) / 2,
  30038. y: (points[i].x + points[j].y) / 2
  30039. };
  30040. }
  30041. return centerPoints;
  30042. },
  30043. /*
  30044. * 对getCenterPoints()接口获取到的数据做处理, 计算出各个顶点对应的平移线数据
  30045. * @param length 集合中点的个数
  30046. * @param points 点集合, 该集合应该是getCenterPoints()接口返回的数据
  30047. */
  30048. getPanLine: function(length, points) {
  30049. var result = {}, //顶点索引
  30050. pointIndex = null;
  30051. for (var i = 0, j; i < length; i++) {
  30052. var point1 = null, point2 = null;
  30053. //计算当前点
  30054. j = (i + 1) % length;
  30055. //保存当前处理的顶点索引
  30056. pointIndex = j;
  30057. point1 = points[i + "," + j];
  30058. //计算下一个点
  30059. i = j;
  30060. j = (i + 1) % length;
  30061. point2 = points[i + "," + j];
  30062. result[pointIndex] = {
  30063. points: [ {
  30064. x: point1.x,
  30065. y: point1.y
  30066. }, {
  30067. x: point2.x,
  30068. y: point2.y
  30069. } ],
  30070. center: {
  30071. x: (point1.x + point2.x) / 2,
  30072. y: (point1.y + point2.y) / 2
  30073. }
  30074. };
  30075. //还原i值
  30076. i = (pointIndex + length - 1) % length;
  30077. }
  30078. return result;
  30079. },
  30080. /*
  30081. * 计算平移线移动到顶点后的位置
  30082. * @param points 顶点集合
  30083. * @param panLines 平移线集合
  30084. */
  30085. getMovedPanLines: function(points, panLines, smoothFactor) {
  30086. var result = {};
  30087. Utils.each(points, function(point, index) {
  30088. //当前平移线
  30089. var currentPanLine = panLines[index], //平移线中点
  30090. center = currentPanLine.center, //移动距离
  30091. distance = {
  30092. x: center.x - point.x,
  30093. y: center.y - point.y
  30094. };
  30095. var currentResult = result[index] = {
  30096. points: [],
  30097. center: {
  30098. x: point.x,
  30099. y: point.y
  30100. }
  30101. };
  30102. //计算控制点到顶点的距离, 并且应用平滑系数到距离上
  30103. Utils.each(currentPanLine.points, function(controlPoint, index) {
  30104. var moved = {
  30105. x: controlPoint.x - distance.x,
  30106. y: controlPoint.y - distance.y
  30107. };
  30108. var vertex = currentResult.center;
  30109. var dx = moved.x - vertex.x;
  30110. var dy = moved.y - vertex.y;
  30111. moved.x = vertex.x + smoothFactor * dx;
  30112. moved.y = vertex.y + smoothFactor * dy;
  30113. currentResult.points.push(moved);
  30114. });
  30115. });
  30116. return result;
  30117. }
  30118. };
  30119. return _p.r(11).createClass("Curve", {
  30120. base: _p.r(46),
  30121. mixins: [ _p.r(51) ],
  30122. constructor: function(points, isColse) {
  30123. this.callBase();
  30124. this.setPoints(points || []);
  30125. this.closeState = !!isColse;
  30126. this.changeable = true;
  30127. this.smoothFactor = 1;
  30128. this.update();
  30129. },
  30130. //当点集合发生变化时采取的动作
  30131. onContainerChanged: function() {
  30132. if (this.changeable) {
  30133. this.update();
  30134. }
  30135. },
  30136. setSmoothFactor: function(factor) {
  30137. this.smoothFactor = factor < 0 ? 0 : factor;
  30138. this.update();
  30139. return this;
  30140. },
  30141. getSmoothFactor: function() {
  30142. return this.smoothFactor;
  30143. },
  30144. update: function() {
  30145. var points = this.getPoints(), withControlPoints = null, drawer = this.getDrawer(), curPoint = null, curControlPoint = null, prevControlPoint = null;
  30146. drawer.clear();
  30147. if (points.length === 0) {
  30148. return this;
  30149. } else {
  30150. drawer.moveTo(points[0]);
  30151. }
  30152. if (points.length === 1) {
  30153. return this;
  30154. }
  30155. if (points.length === 2) {
  30156. drawer.lineTo(points[1]);
  30157. return this;
  30158. }
  30159. //获取已转换过后的带控制点的所有点
  30160. withControlPoints = CurveUtil.getCurvePanLines(points, this.getSmoothFactor());
  30161. for (var i = 1, len = points.length; i < len; i++) {
  30162. //当前顶点
  30163. curPoint = withControlPoints[i].center;
  30164. //当前控制点
  30165. if (this.closeState || i != len - 1) {
  30166. curControlPoint = withControlPoints[i].points[0];
  30167. } else {
  30168. //非闭合状态下最后一个点的处理
  30169. curControlPoint = withControlPoints[i].center;
  30170. }
  30171. if (this.closeState || i != 1) {
  30172. prevControlPoint = withControlPoints[i - 1].points[1];
  30173. } else {
  30174. //非闭合状态下第一个点的处理
  30175. prevControlPoint = withControlPoints[i - 1].center;
  30176. }
  30177. drawer.bezierTo(prevControlPoint.x, prevControlPoint.y, curControlPoint.x, curControlPoint.y, curPoint.x, curPoint.y);
  30178. }
  30179. //处理闭合
  30180. if (this.closeState) {
  30181. curPoint = withControlPoints[0].center;
  30182. curControlPoint = withControlPoints[0].points[0];
  30183. prevControlPoint = withControlPoints[points.length - 1].points[1];
  30184. drawer.bezierTo(prevControlPoint.x, prevControlPoint.y, curControlPoint.x, curControlPoint.y, curPoint.x, curPoint.y);
  30185. }
  30186. return this;
  30187. },
  30188. close: function() {
  30189. this.closeState = true;
  30190. return this.update();
  30191. },
  30192. open: function() {
  30193. this.closeState = false;
  30194. return this.update();
  30195. },
  30196. isClose: function() {
  30197. return !!this.closeState;
  30198. }
  30199. });
  30200. }
  30201. };
  30202. //src/graphic/data.js
  30203. _p[31] = {
  30204. value: function(require, exports, module) {
  30205. return _p.r(11).createClass("Data", {
  30206. constructor: function() {
  30207. this._data = {};
  30208. },
  30209. setData: function(name, value) {
  30210. this._data[name] = value;
  30211. return this;
  30212. },
  30213. getData: function(name) {
  30214. return this._data[name];
  30215. },
  30216. removeData: function(name) {
  30217. delete this._data[name];
  30218. return this;
  30219. }
  30220. });
  30221. }
  30222. };
  30223. //src/graphic/ellipse.js
  30224. _p[32] = {
  30225. value: function(require, exports, module) {
  30226. var Utils = _p.r(12), Point = _p.r(50);
  30227. return _p.r(11).createClass("Ellipse", {
  30228. base: _p.r(46),
  30229. constructor: function(rx, ry, cx, cy) {
  30230. this.callBase();
  30231. this.rx = rx || 0;
  30232. this.ry = ry || 0;
  30233. this.cx = cx || 0;
  30234. this.cy = cy || 0;
  30235. this.update();
  30236. },
  30237. update: function() {
  30238. var rx = this.rx, ry = this.ry, x1 = this.cx + rx, x2 = this.cx - rx, y = this.cy;
  30239. var drawer = this.getDrawer();
  30240. drawer.clear();
  30241. drawer.moveTo(x1, y);
  30242. drawer.arcTo(rx, ry, 0, 1, 1, x2, y);
  30243. drawer.arcTo(rx, ry, 0, 1, 1, x1, y);
  30244. return this;
  30245. },
  30246. getRadius: function() {
  30247. return {
  30248. x: this.rx,
  30249. y: this.ry
  30250. };
  30251. },
  30252. getRadiusX: function() {
  30253. return this.rx;
  30254. },
  30255. getRadiusY: function() {
  30256. return this.ry;
  30257. },
  30258. getCenter: function() {
  30259. return new Point(this.cx, this.cy);
  30260. },
  30261. getCenterX: function() {
  30262. return this.cx;
  30263. },
  30264. getCenterY: function() {
  30265. return this.cy;
  30266. },
  30267. setRadius: function(rx, ry) {
  30268. this.rx = rx;
  30269. this.ry = ry;
  30270. return this.update();
  30271. },
  30272. setRadiusX: function(rx) {
  30273. this.rx = rx;
  30274. return this.update();
  30275. },
  30276. setRadiusY: function(ry) {
  30277. this.ry = ry;
  30278. return this.update();
  30279. },
  30280. setCenter: function(cx, cy) {
  30281. if (arguments.length == 1) {
  30282. var p = Point.parse(arguments[0]);
  30283. cx = p.x;
  30284. cy = p.y;
  30285. }
  30286. this.cx = cx;
  30287. this.cy = cy;
  30288. return this.update();
  30289. },
  30290. setCenterX: function(cx) {
  30291. this.cx = cx;
  30292. return this.update();
  30293. },
  30294. setCenterY: function(cy) {
  30295. this.cy = cy;
  30296. return this.update();
  30297. }
  30298. });
  30299. }
  30300. };
  30301. //src/graphic/eventhandler.js
  30302. /*
  30303. * kity event 实现
  30304. */
  30305. _p[33] = {
  30306. value: function(require, exports, module) {
  30307. // polyfill
  30308. (function() {
  30309. function CustomEvent(event, params) {
  30310. params = params || {
  30311. bubbles: false,
  30312. cancelable: false,
  30313. detail: undefined
  30314. };
  30315. var evt = document.createEvent("CustomEvent");
  30316. evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
  30317. return evt;
  30318. }
  30319. CustomEvent.prototype = window.Event.prototype;
  30320. window.CustomEvent = CustomEvent;
  30321. })();
  30322. var Utils = _p.r(12), ShapeEvent = _p.r(62);
  30323. // 内部处理器缓存
  30324. var INNER_HANDLER_CACHE = {}, // 用户处理器缓存
  30325. USER_HANDLER_CACHE = {}, guid = 0;
  30326. // 添加事件统一入口
  30327. function _addEvent(type, handler, isOnce) {
  30328. isOnce = !!isOnce;
  30329. if (Utils.isString(type)) {
  30330. type = type.match(/\S+/g);
  30331. }
  30332. Utils.each(type, function(currentType) {
  30333. listen.call(this, this.node, currentType, handler, isOnce);
  30334. }, this);
  30335. return this;
  30336. }
  30337. // 移除事件统一入口
  30338. function _removeEvent(type, handler) {
  30339. var userHandlerList = null, eventId = this._EVNET_UID, isRemoveAll = handler === undefined;
  30340. userHandlerList = USER_HANDLER_CACHE[eventId][type];
  30341. //移除指定的监听器
  30342. if (!isRemoveAll) {
  30343. isRemoveAll = true;
  30344. Utils.each(userHandlerList, function removeKityEvent(fn, index) {
  30345. if (fn === handler) {
  30346. // 不能结束, 需要查找完整个list, 避免丢失移除多次绑定同一个处理器的情况
  30347. delete userHandlerList[index];
  30348. } else {
  30349. isRemoveAll = false;
  30350. }
  30351. });
  30352. }
  30353. //删除所有监听器
  30354. if (isRemoveAll) {
  30355. deleteDomEvent(this.node, type, INNER_HANDLER_CACHE[eventId][type]);
  30356. delete USER_HANDLER_CACHE[eventId][type];
  30357. delete INNER_HANDLER_CACHE[eventId][type];
  30358. }
  30359. return this;
  30360. }
  30361. // 执行绑定, 该方法context为shape或者mixin了eventhandler的对象
  30362. function listen(node, type, handler, isOnce) {
  30363. var eid = this._EVNET_UID, targetObject = this;
  30364. // 初始化内部监听器
  30365. if (!INNER_HANDLER_CACHE[eid]) {
  30366. INNER_HANDLER_CACHE[eid] = {};
  30367. }
  30368. if (!INNER_HANDLER_CACHE[eid][type]) {
  30369. // 内部监听器
  30370. INNER_HANDLER_CACHE[eid][type] = function kityEventHandler(e) {
  30371. e = new ShapeEvent(e || window.event);
  30372. Utils.each(USER_HANDLER_CACHE[eid][type], function executeKityEvent(fn) {
  30373. var result;
  30374. if (fn) {
  30375. result = fn.call(targetObject, e);
  30376. //once 绑定, 执行完后删除
  30377. if (isOnce) {
  30378. targetObject.off(type, fn);
  30379. }
  30380. }
  30381. // 如果用户handler里return了false, 则该节点上的此后的同类型事件将不再执行
  30382. return result;
  30383. }, targetObject);
  30384. };
  30385. }
  30386. // 初始化用户监听器列表
  30387. if (!USER_HANDLER_CACHE[eid]) {
  30388. USER_HANDLER_CACHE[eid] = {};
  30389. }
  30390. if (!USER_HANDLER_CACHE[eid][type]) {
  30391. USER_HANDLER_CACHE[eid][type] = [ handler ];
  30392. // 绑定对应类型的事件
  30393. // dom对象利用dom event进行处理, 非dom对象, 由消息分发机制处理
  30394. if (!!node && "on" + type in node) {
  30395. bindDomEvent(node, type, INNER_HANDLER_CACHE[eid][type]);
  30396. }
  30397. } else {
  30398. USER_HANDLER_CACHE[eid][type].push(handler);
  30399. }
  30400. }
  30401. // 绑定dom事件
  30402. function bindDomEvent(node, type, handler) {
  30403. if (node.addEventListener) {
  30404. node.addEventListener(type, handler, false);
  30405. } else {
  30406. node.attachEvent("on" + type, handler);
  30407. }
  30408. }
  30409. // 删除dom事件
  30410. function deleteDomEvent(node, type, handler) {
  30411. if (node.removeEventListener) {
  30412. node.removeEventListener(type, handler, false);
  30413. } else {
  30414. node.detachEvent(type, handler);
  30415. }
  30416. }
  30417. // 触发dom事件
  30418. function triggerDomEvent(node, type, params) {
  30419. var event = new CustomEvent(type, {
  30420. bubbles: true,
  30421. cancelable: true
  30422. });
  30423. event._kityParam = params;
  30424. node.dispatchEvent(event);
  30425. }
  30426. // 发送消息
  30427. function sendMessage(messageObj, type, msg) {
  30428. var event = null, handler = null;
  30429. var handlers = INNER_HANDLER_CACHE[messageObj._EVNET_UID];
  30430. if (!handlers) return;
  30431. handler = handlers[type];
  30432. if (!handler) {
  30433. return;
  30434. }
  30435. event = Utils.extend({
  30436. type: type,
  30437. target: messageObj
  30438. }, msg || {});
  30439. handler.call(messageObj, event);
  30440. }
  30441. // 对外接口
  30442. return _p.r(11).createClass("EventHandler", {
  30443. constructor: function() {
  30444. this._EVNET_UID = ++guid;
  30445. },
  30446. addEventListener: function(type, handler) {
  30447. return _addEvent.call(this, type, handler, false);
  30448. },
  30449. addOnceEventListener: function(type, handler) {
  30450. return _addEvent.call(this, type, handler, true);
  30451. },
  30452. removeEventListener: function(type, handler) {
  30453. return _removeEvent.call(this, type, handler);
  30454. },
  30455. on: function(type, handler) {
  30456. return this.addEventListener.apply(this, arguments);
  30457. },
  30458. once: function(type, handler) {
  30459. return this.addOnceEventListener.apply(this, arguments);
  30460. },
  30461. off: function() {
  30462. return this.removeEventListener.apply(this, arguments);
  30463. },
  30464. fire: function(type, params) {
  30465. return this.trigger.apply(this, arguments);
  30466. },
  30467. trigger: function(type, params) {
  30468. sendMessage(this, type, params);
  30469. return this;
  30470. }
  30471. });
  30472. }
  30473. };
  30474. //src/graphic/geometry.js
  30475. _p[34] = {
  30476. value: function(require) {
  30477. var utils = _p.r(12);
  30478. var Point = _p.r(50);
  30479. var Vector = _p.r(73);
  30480. var Matrix = _p.r(43);
  30481. var g = {};
  30482. var pathCommand = /([achlmrqstvz])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?\s*)+)/gi, pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)\s*,?\s*/gi, paramCounts = {
  30483. a: 7,
  30484. c: 6,
  30485. h: 1,
  30486. l: 2,
  30487. m: 2,
  30488. q: 4,
  30489. s: 4,
  30490. t: 2,
  30491. v: 1,
  30492. z: 0
  30493. };
  30494. function pathClone(path) {
  30495. var result, i, j, segment, segmentCopy;
  30496. result = [];
  30497. for (i = 0; i < path.length; i++) {
  30498. segment = path[i];
  30499. result.push(segmentCopy = []);
  30500. for (j = 0; j < segment.length; j++) {
  30501. segmentCopy.push(segment[j]);
  30502. }
  30503. }
  30504. if (path.isUniform) result.isUniform = true;
  30505. if (path.isAbsolute) result.isAbsolute = true;
  30506. if (path.isCurve) result.isCurve = true;
  30507. return result;
  30508. }
  30509. // 缓存函数
  30510. // from raphael.js
  30511. function cacher(f, scope, postprocessor) {
  30512. function repush(array, item) {
  30513. for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
  30514. return array.push(array.splice(i, 1)[0]);
  30515. }
  30516. }
  30517. function newf() {
  30518. var arg = Array.prototype.slice.call(arguments, 0), args = arg.join("␀"), cache = newf.cache = newf.cache || {}, count = newf.count = newf.count || [];
  30519. if (cache.hasOwnProperty(args)) {
  30520. repush(count, args);
  30521. return postprocessor ? postprocessor(cache[args]) : cache[args];
  30522. }
  30523. if (count.length >= 1e3) {
  30524. delete cache[count.shift()];
  30525. }
  30526. count.push(args);
  30527. cache[args] = f.apply(scope, arg);
  30528. return postprocessor ? postprocessor(cache[args]) : cache[args];
  30529. }
  30530. return newf;
  30531. }
  30532. /**
  30533. *
  30534. * kity.g.pathToString(pathSegment)
  30535. *
  30536. * 返回表示 PathSegment 的字符串
  30537. *
  30538. * @param {Array} pathSegment
  30539. * 要表示的 Path Segment
  30540. *
  30541. * @return {String} 表示该 Path 的字符串
  30542. *
  30543. * @example
  30544. *
  30545. * var pathSegment = [['M', 0, 0], ['L', 10, 10]]
  30546. * var pathString = kity.g.pathToString(pathSegment);
  30547. * // 返回 'M0,0L10,10'
  30548. */
  30549. g.pathToString = function(pathSegment) {
  30550. pathSegment = pathSegment || this;
  30551. if (typeof pathSegment == "string") return pathSegment;
  30552. if (pathSegment instanceof Array) {
  30553. pathSegment = utils.flatten(pathSegment);
  30554. return pathSegment.join(",").replace(/,?([achlmqrstvxz]),?/gi, "$1");
  30555. }
  30556. };
  30557. /**
  30558. * kity.g.parsePathString(pathString)
  30559. *
  30560. * 解析 Path 字符串成 PathSegment
  30561. *
  30562. * @copyright rapheal.js
  30563. *
  30564. * @example
  30565. *
  30566. * var seg = kity.g.parsePathString('M10,12l21-23-21.5,11z');
  30567. * // 返回: [['M', 10, 12], ['l', 21, -23], ['l', -21.5, 11], ['z']]
  30568. *
  30569. * @param {String} pathString Path 字符串
  30570. * @return {Array}
  30571. */
  30572. g.parsePathString = cacher(function(pathString) {
  30573. var data = [];
  30574. pathString.replace(pathCommand, function(a, b, c) {
  30575. var params = [], name = b.toLowerCase();
  30576. c.replace(pathValues, function(a, b) {
  30577. if (b) params.push(+b);
  30578. });
  30579. if (name == "m" && params.length > 2) {
  30580. data.push([ b ].concat(params.splice(0, 2)));
  30581. name = "l";
  30582. b = b == "m" ? "l" : "L";
  30583. }
  30584. if (name == "r") {
  30585. data.push([ b ].concat(params));
  30586. } else {
  30587. while (params.length >= paramCounts[name]) {
  30588. data.push([ b ].concat(params.splice(0, paramCounts[name])));
  30589. if (!paramCounts[name]) {
  30590. break;
  30591. }
  30592. }
  30593. }
  30594. });
  30595. data.isUniform = true;
  30596. data.toString = g.pathToString;
  30597. return data;
  30598. });
  30599. /**
  30600. * kity.g.pathToAbsolute(path)
  30601. *
  30602. * 把路径转换为绝对路径的形式
  30603. *
  30604. * @param {Array|String} path
  30605. * 要转换的 path 路径或者数组
  30606. *
  30607. * @return {Array}
  30608. * 转换后的 Path Segment
  30609. *
  30610. * @example
  30611. *
  30612. * var path = 'M10,10l50,50';
  30613. * var absPath = kity.g.pathToAbsolute(path);
  30614. * // 返回 [['M', 10, 10], ['L', 60, 60]]
  30615. */
  30616. g.pathToAbsolute = cacher(function(path) {
  30617. var pathArray = path.isUniform ? path : g.parsePathString(g.pathToString(path));
  30618. var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0;
  30619. var r, pa, i, j, k, ii, jj, kk;
  30620. if (pathArray[0][0] == "M") {
  30621. x = +pathArray[0][1];
  30622. y = +pathArray[0][2];
  30623. mx = x;
  30624. my = y;
  30625. start++;
  30626. res[0] = [ "M", x, y ];
  30627. }
  30628. for (r, pa, i = start, ii = pathArray.length; i < ii; i++) {
  30629. res.push(r = []);
  30630. pa = pathArray[i];
  30631. if (pa[0] != pa[0].toUpperCase()) {
  30632. r[0] = pa[0].toUpperCase();
  30633. switch (r[0]) {
  30634. case "A":
  30635. r[1] = pa[1];
  30636. r[2] = pa[2];
  30637. r[3] = pa[3];
  30638. r[4] = pa[4];
  30639. r[5] = pa[5];
  30640. r[6] = +(pa[6] + x);
  30641. r[7] = +(pa[7] + y);
  30642. break;
  30643. case "V":
  30644. r[1] = +pa[1] + y;
  30645. break;
  30646. case "H":
  30647. r[1] = +pa[1] + x;
  30648. break;
  30649. case "M":
  30650. mx = +pa[1] + x;
  30651. my = +pa[2] + y;
  30652. break;
  30653. default:
  30654. for (j = 1, jj = pa.length; j < jj; j++) {
  30655. r[j] = +pa[j] + (j % 2 ? x : y);
  30656. }
  30657. }
  30658. } else {
  30659. for (k = 0, kk = pa.length; k < kk; k++) {
  30660. r[k] = pa[k];
  30661. }
  30662. }
  30663. switch (r[0]) {
  30664. case "Z":
  30665. x = mx;
  30666. y = my;
  30667. break;
  30668. case "H":
  30669. x = r[1];
  30670. break;
  30671. case "V":
  30672. y = r[1];
  30673. break;
  30674. case "M":
  30675. mx = r[r.length - 2];
  30676. my = r[r.length - 1];
  30677. break;
  30678. default:
  30679. x = r[r.length - 2];
  30680. y = r[r.length - 1];
  30681. }
  30682. }
  30683. res.isUniform = true;
  30684. res.isAbsolute = true;
  30685. res.toString = g.pathToString;
  30686. return res;
  30687. });
  30688. // 把圆弧绘制的曲线转化为对应的三次贝塞尔形式
  30689. function a2c(x1, y1, rx, ry, angle, laf, sf, x2, y2, recursive) {
  30690. // copy from raphael.js
  30691. // for more information of where this math came from visit:
  30692. // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
  30693. var math = Math, PI = math.PI, abs = Math.abs, _120 = PI * 120 / 180, rad = PI / 180 * (+angle || 0), res = [], xy, rotate = function(x, y, rad) {
  30694. var X = x * math.cos(rad) - y * math.sin(rad), Y = x * math.sin(rad) + y * math.cos(rad);
  30695. return {
  30696. x: X,
  30697. y: Y
  30698. };
  30699. };
  30700. var cos, sin, h, x, y, rx2, ry2, k, cx, cy, f1, f2, df, f2old, x2old, y2old, c1, s1, c2, s2, t, hx, hy, m1, m2, m3, m4, newres, i, ii;
  30701. if (!recursive) {
  30702. xy = rotate(x1, y1, -rad);
  30703. x1 = xy.x;
  30704. y1 = xy.y;
  30705. xy = rotate(x2, y2, -rad);
  30706. x2 = xy.x;
  30707. y2 = xy.y;
  30708. cos = math.cos(PI / 180 * angle);
  30709. sin = math.sin(PI / 180 * angle);
  30710. x = (x1 - x2) / 2;
  30711. y = (y1 - y2) / 2;
  30712. h = x * x / (rx * rx) + y * y / (ry * ry);
  30713. if (h > 1) {
  30714. h = math.sqrt(h);
  30715. rx = h * rx;
  30716. ry = h * ry;
  30717. }
  30718. rx2 = rx * rx;
  30719. ry2 = ry * ry;
  30720. k = (laf == sf ? -1 : 1) * math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));
  30721. cx = k * rx * y / ry + (x1 + x2) / 2;
  30722. cy = k * -ry * x / rx + (y1 + y2) / 2;
  30723. f1 = math.asin(((y1 - cy) / ry).toFixed(9));
  30724. f2 = math.asin(((y2 - cy) / ry).toFixed(9));
  30725. f1 = x1 < cx ? PI - f1 : f1;
  30726. f2 = x2 < cx ? PI - f2 : f2;
  30727. if (f1 < 0) f1 = PI * 2 + f1;
  30728. if (f2 < 0) f2 = PI * 2 + f2;
  30729. if (sf && f1 > f2) {
  30730. f1 = f1 - PI * 2;
  30731. }
  30732. if (!sf && f2 > f1) {
  30733. f2 = f2 - PI * 2;
  30734. }
  30735. } else {
  30736. f1 = recursive[0];
  30737. f2 = recursive[1];
  30738. cx = recursive[2];
  30739. cy = recursive[3];
  30740. }
  30741. df = f2 - f1;
  30742. if (abs(df) > _120) {
  30743. f2old = f2;
  30744. x2old = x2;
  30745. y2old = y2;
  30746. f2 = f1 + _120 * (sf && f2 > f1 ? 1 : -1);
  30747. x2 = cx + rx * math.cos(f2);
  30748. y2 = cy + ry * math.sin(f2);
  30749. res = a2c(x2, y2, rx, ry, angle, 0, sf, x2old, y2old, [ f2, f2old, cx, cy ]);
  30750. }
  30751. df = f2 - f1;
  30752. c1 = math.cos(f1);
  30753. s1 = math.sin(f1);
  30754. c2 = math.cos(f2);
  30755. s2 = math.sin(f2);
  30756. t = math.tan(df / 4);
  30757. hx = 4 / 3 * rx * t;
  30758. hy = 4 / 3 * ry * t;
  30759. m1 = [ x1, y1 ];
  30760. m2 = [ x1 + hx * s1, y1 - hy * c1 ];
  30761. m3 = [ x2 + hx * s2, y2 - hy * c2 ];
  30762. m4 = [ x2, y2 ];
  30763. m2[0] = 2 * m1[0] - m2[0];
  30764. m2[1] = 2 * m1[1] - m2[1];
  30765. if (recursive) {
  30766. return [ m2, m3, m4 ].concat(res);
  30767. } else {
  30768. res = [ m2, m3, m4 ].concat(res).join().split(",");
  30769. newres = [];
  30770. for (i = 0, ii = res.length; i < ii; i++) {
  30771. newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
  30772. }
  30773. return newres;
  30774. }
  30775. }
  30776. // 把二次贝塞尔曲线参数转化为三次贝塞尔曲线参数
  30777. function q2c(x1, y1, ax, ay, x2, y2) {
  30778. // copy from raphael.js
  30779. var _13 = 1 / 3, _23 = 2 / 3;
  30780. return [ _13 * x1 + _23 * ax, _13 * y1 + _23 * ay, _13 * x2 + _23 * ax, _13 * y2 + _23 * ay, x2, y2 ];
  30781. }
  30782. /**
  30783. * kity.g.pathToCurve(path)
  30784. *
  30785. * 把路径转换为贝塞尔路径
  30786. *
  30787. * @param {Array|String} path
  30788. * 要转换的 path 路径或数组
  30789. *
  30790. * @return {Array}
  30791. * 转换后的 PathSegment,每一段都是 'C'
  30792. */
  30793. g.pathToCurve = cacher(function(path) {
  30794. var i, j, command, param;
  30795. var initPoint, currentPoint, endPoint, shouldClose, lastControlPoint, aussumedControlPoint;
  30796. var controlPoint1, controlPoint2;
  30797. var res = [];
  30798. // 处理的路径要求是一个绝对路径
  30799. if (!path.isAbsolute) path = g.pathToAbsolute(path);
  30800. for (i = 0; i < path.length; i++) {
  30801. command = path[i][0];
  30802. param = path[i].slice(1);
  30803. // 画笔移动
  30804. if (command == "M") {
  30805. initPoint = lastControlPoint = currentPoint = param;
  30806. res.push(path[i]);
  30807. continue;
  30808. }
  30809. // 路径闭合
  30810. if (command == "Z") {
  30811. shouldClose = true;
  30812. command = "L";
  30813. param = initPoint;
  30814. }
  30815. // 绘制命令的目的位置
  30816. endPoint = param.slice(param.length - 2);
  30817. // 对 'H' 命令的修正
  30818. if (command == "H") {
  30819. endPoint = [ param[0], currentPoint[1] ];
  30820. command = "L";
  30821. }
  30822. // 对 'V' 命令的修正
  30823. if (command == "V") {
  30824. endPoint = [ currentPoint[0], param[0] ];
  30825. command = "L";
  30826. }
  30827. // 对 'S' 命令求出隐含的控制点位置
  30828. if (command == "S" || command == "T") {
  30829. // 隐含控制点是上一个控制点关于当前位置的镜像
  30830. aussumedControlPoint = [ currentPoint[0] + (currentPoint[0] - lastControlPoint[0]), currentPoint[1] + (currentPoint[1] - lastControlPoint[1]) ];
  30831. }
  30832. // 针对不同的命令求控制点
  30833. switch (command) {
  30834. case "L":
  30835. controlPoint1 = currentPoint;
  30836. controlPoint2 = endPoint;
  30837. break;
  30838. case "C":
  30839. controlPoint1 = param.slice(0, 2);
  30840. controlPoint2 = param.slice(2, 4);
  30841. break;
  30842. case "S":
  30843. controlPoint1 = aussumedControlPoint.slice();
  30844. controlPoint2 = param.slice(0, 2);
  30845. break;
  30846. case "Q":
  30847. lastControlPoint = param.slice(0, 2);
  30848. param = q2c.apply(null, currentPoint.concat(param));
  30849. controlPoint1 = param.slice(0, 2);
  30850. controlPoint2 = param.slice(2, 4);
  30851. break;
  30852. case "T":
  30853. param = q2c.apply(null, currentPoint.concat(aussumedControlPoint).concat(param));
  30854. controlPoint1 = param.slice(0, 2);
  30855. controlPoint2 = param.slice(2, 4);
  30856. break;
  30857. case "A":
  30858. param = a2c.apply(null, currentPoint.concat(param));
  30859. j = 0;
  30860. while (j in param) {
  30861. controlPoint1 = param.slice(j, j + 2);
  30862. controlPoint2 = param.slice(j + 2, j + 4);
  30863. endPoint = param.slice(j + 4, j + 6);
  30864. // 写入当前一段曲线
  30865. res.push([ "C" ].concat(controlPoint1).concat(controlPoint2).concat(endPoint));
  30866. j += 6;
  30867. }
  30868. break;
  30869. }
  30870. if (command != "A") {
  30871. // 写入当前一段曲线
  30872. res.push([ "C" ].concat(controlPoint1).concat(controlPoint2).concat(endPoint));
  30873. }
  30874. // 为下次循环准备当前位置
  30875. currentPoint = endPoint;
  30876. // 二次贝塞尔曲线自己已经记录了上个控制点的位置,其它的记录控制点 2 的位置
  30877. if (command != "Q") {
  30878. lastControlPoint = controlPoint2;
  30879. }
  30880. if (shouldClose) {
  30881. res.push([ "Z" ]);
  30882. shouldClose = false;
  30883. }
  30884. }
  30885. res.isUniform = true;
  30886. res.isAbsolute = true;
  30887. res.isCurve = true;
  30888. res.toString = g.pathToString;
  30889. return res;
  30890. });
  30891. /**
  30892. * 将贝塞尔曲线切成两部分
  30893. *
  30894. * @see http://stackoverflow.com/questions/18655135/divide-bezier-curve-into-two-equal-halves
  30895. */
  30896. function cutBezier(bezierArray, t) {
  30897. function __(t) {
  30898. return function(p, q) {
  30899. return p + t * (q - p);
  30900. };
  30901. }
  30902. var _ = __(t || .5), ba = bezierArray, ax = ba[0], ay = ba[1], bx = ba[2], by = ba[3], cx = ba[4], cy = ba[5], dx = ba[6], dy = ba[7], ex = _(ax, bx), ey = _(ay, by), fx = _(bx, cx), fy = _(by, cy), gx = _(cx, dx), gy = _(cy, dy), hx = _(ex, fx), hy = _(ey, fy), jx = _(fx, gx), jy = _(fy, gy), kx = _(hx, jx), ky = _(hy, jy);
  30903. return [ [ ax, ay, ex, ey, hx, hy, kx, ky ], [ kx, ky, jx, jy, gx, gy, dx, dy ] ];
  30904. }
  30905. /**
  30906. * kity.g.cutBezier(bezierArray, t)
  30907. *
  30908. * 在指定位置把贝塞尔曲线切割为两部分
  30909. *
  30910. * @param {Array} bezierArray
  30911. * 表示贝塞尔曲线的一个数组 [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]
  30912. * p1 和 p2 是贝塞尔曲线的起点和终点,c1 和 c2 是两个控制点
  30913. *
  30914. * @param {Number} t
  30915. * 切割的位置(0 到 1)
  30916. *
  30917. * @return {Array}
  30918. * 切割的两个贝塞尔曲线:[
  30919. * [p1x1, p1y1, c1x1, c1y1, c2x1, c2y1, p2x1, p2y1],
  30920. * [p1x2, p1y2, c1x2, c1y2, c2x2, c2y2, p2x2, p2y2]
  30921. * ]
  30922. *
  30923. */
  30924. g.cutBezier = cacher(cutBezier);
  30925. /**
  30926. * 求一段贝塞尔曲线的子段
  30927. *
  30928. * @param {Array} bezierArray
  30929. * 长度为 8 的数组,表示 [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]
  30930. *
  30931. * @param {Number} t
  30932. * 子段的结束位置(0 到 1)
  30933. *
  30934. * @param {Number} t0
  30935. * 字段的开始位置(0 到 t),可不传,默认为 0
  30936. *
  30937. * @return {Array}
  30938. * 长度为 8 的数组,表示给定贝塞尔曲线的子段
  30939. */
  30940. g.subBezier = function(bezierArray, t, t0) {
  30941. var b2t = cutBezier(bezierArray, t)[0];
  30942. return t0 ? cutBezier(b2t, t0 / t)[1] : b2t;
  30943. };
  30944. /**
  30945. * 求贝塞尔曲线上的一个点
  30946. *
  30947. * @param {Array} bezierArray
  30948. * 长度为 8 的数组,表示 [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]
  30949. *
  30950. * @param {Number} t
  30951. * 所求点的开始位置(0 到 1)
  30952. *
  30953. * @return {Point} p
  30954. * p.x: x 坐标
  30955. * p.y: y 坐标
  30956. * p.tan: 在 t 处的切线方向(类型为 kity.Vector,模为 1)
  30957. */
  30958. g.pointAtBezier = function(bezierArray, t) {
  30959. var b2t = cutBezier(bezierArray, t)[0];
  30960. var p = Point.parse(b2t.slice(6)), c = Point.parse(b2t.slice(4, 2)), v = Vector.fromPoints(c, p);
  30961. if (t === 0) {
  30962. p.tan = g.pointAtBezier(bezierArray, .01).tan;
  30963. } else {
  30964. p.tan = v.normalize();
  30965. }
  30966. return p;
  30967. };
  30968. /**
  30969. * 求贝塞尔曲线的长度
  30970. *
  30971. * @param {Array} bezierArray
  30972. * 长度为 8 的数组,表示 [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]
  30973. *
  30974. * @param {Number} tolerate
  30975. * 允许的误差,默认是 0.1
  30976. *
  30977. * @return {Number} 贝塞尔曲线的长度
  30978. */
  30979. g.bezierLength = cacher(function bezierLength(bezierArray) {
  30980. // 表示(c[0]*t^4 + c[1]*t^3 + c[2]*t^2 + c[3]*t^1 + c[4])^(1/2)的函数
  30981. function f(x) {
  30982. var m = c0 * Math.pow(x, 4) + c1 * Math.pow(x, 3) + c2 * Math.pow(x, 2) + c3 * x + c4;
  30983. if (m < 0) {
  30984. m = 0;
  30985. }
  30986. return Math.pow(m, .5);
  30987. }
  30988. // 用Newton-Cotes型求积公式
  30989. var arr = bezierArray;
  30990. // 三次贝塞尔曲线函数求导后,求出对应的方程系数,用cx[],cy[]表示x`(t)和y`(t)的系数
  30991. var cx0, cx1, cx2;
  30992. var cy0, cy1, cy2;
  30993. // 用c[]表示x`(t)^2 + y`(t)^2的结果的系数
  30994. var c0, c1, c2, c3, c4;
  30995. // 求x`(t) 和 y`(t)的系数
  30996. cx0 = -3 * arr[0] + 9 * arr[2] - 9 * arr[4] + 3 * arr[6];
  30997. cx1 = 6 * arr[0] - 12 * arr[2] + 6 * arr[4];
  30998. cx2 = -3 * arr[0] + 3 * arr[2];
  30999. cy0 = -3 * arr[1] + 9 * arr[3] - 9 * arr[5] + 3 * arr[7];
  31000. cy1 = 6 * arr[1] - 12 * arr[3] + 6 * arr[5];
  31001. cy2 = -3 * arr[1] + 3 * arr[3];
  31002. // 求x`(t)^2 + y`(t)^2的结果的系数 c[]
  31003. c0 = Math.pow(cx0, 2) + Math.pow(cy0, 2);
  31004. c1 = 2 * (cx0 * cx1 + cy0 * cy1);
  31005. c2 = 2 * (cx0 * cx2 + cy0 * cy2) + Math.pow(cx1, 2) + Math.pow(cy1, 2);
  31006. c3 = 2 * (cx1 * cx2 + cy1 * cy2);
  31007. c4 = Math.pow(cx2, 2) + Math.pow(cy2, 2);
  31008. // 用cotes积分公式求值
  31009. return (f(0) + f(1) + 4 * (f(.125) + f(.375) + f(.625) + f(.875)) + 2 * (f(.25) + f(.5) + f(.75))) / 24;
  31010. });
  31011. // 计算一个 pathSegment 中每一段的在整体中所占的长度范围,以及总长度
  31012. // 方法要求每一段都是贝塞尔曲线
  31013. var getBezierPathSegmentRanges = cacher(function(pathSegment) {
  31014. var i, ii, segment, position, bezierLength, segmentRanges, totalLength;
  31015. segmentRanges = [];
  31016. // 总长度
  31017. totalLength = 0;
  31018. for (i = 0, ii = pathSegment.length; i < ii; i++) {
  31019. segment = pathSegment[i];
  31020. if (segment[0] == "M") {
  31021. position = segment.slice(1);
  31022. segmentRanges.push(null);
  31023. continue;
  31024. }
  31025. if (segment[0] == "Z") {
  31026. segmentRanges.push(null);
  31027. continue;
  31028. }
  31029. bezierLength = g.bezierLength(position.concat(segment.slice(1)));
  31030. segmentRanges.push([ totalLength, totalLength + bezierLength ]);
  31031. totalLength += bezierLength;
  31032. // 迭代当前位置
  31033. position = segment.slice(4);
  31034. }
  31035. segmentRanges.totalLength = totalLength;
  31036. return segmentRanges;
  31037. });
  31038. /**
  31039. * 求一段路径的子路径
  31040. *
  31041. * @param {Array|String} path
  31042. * 原路径
  31043. *
  31044. * @param {Number} t1
  31045. * 要求的子路径的结束位置(0 到 1)
  31046. *
  31047. * @param {Number} t0
  31048. * 要求的子路径的开始位置(0 到 t1),可不传,默认为 0
  31049. *
  31050. * @return {Array}
  31051. * 子路径的 PathSegment
  31052. */
  31053. g.subPath = function(path, t1, t0) {
  31054. var dt;
  31055. t0 = t0 || 0;
  31056. dt = t1 - t0;
  31057. dt = dt - (dt | 0);
  31058. t0 = t0 - (t0 | 0);
  31059. t1 = t0 + dt;
  31060. if (t1 > 1) {
  31061. return g.subPath(path, 1, t0).concat(g.subPath(path, t1 - 1));
  31062. }
  31063. if (!path.isCurve) {
  31064. path = g.pathToCurve(path);
  31065. }
  31066. // path 每一段在整体中的长度区间
  31067. var segmentRanges = getBezierPathSegmentRanges(path);
  31068. // path 总长度
  31069. var totalLength = segmentRanges.totalLength;
  31070. // t1 和 t0 位置命中的长度位置
  31071. var t1Length = totalLength * t1, t0Length = totalLength * (t0 || 0);
  31072. // 产生的子路径
  31073. var subPath = [];
  31074. // 迭代变量,a 是一段的长度区间左值,b 是右值,d 是区间长度
  31075. var i, ii, a, b, d;
  31076. var position;
  31077. var bezier, subBezier, stared;
  31078. for (i = 0, ii = path.length; i < ii; i++) {
  31079. if (path[i][0] == "M") {
  31080. position = path[i].slice(1);
  31081. if (stared) {
  31082. subPath.push(path[i].slice());
  31083. }
  31084. continue;
  31085. }
  31086. if (path[i][0] == "Z") {
  31087. // subpath 路径不闭合
  31088. continue;
  31089. }
  31090. a = segmentRanges[i][0];
  31091. b = segmentRanges[i][1];
  31092. d = b - a;
  31093. bezier = position.concat(path[i].slice(1));
  31094. if (t0Length > b) {
  31095. // t0 和 t1 都右溢出
  31096. // -----------------------------------
  31097. // t0 t1
  31098. // |________|
  31099. //
  31100. // 需要跳过当前块
  31101. position = bezier.slice(bezier.length - 2);
  31102. continue;
  31103. } else if (t0Length >= a) {
  31104. // 命中 t0;t1 可能命中或右溢出
  31105. // -----------------------------------
  31106. // t0 t1
  31107. // |______|__|
  31108. //
  31109. // or: |_|____|__|
  31110. //
  31111. // 取当前块 t0 到 t1 的部分
  31112. subBezier = g.subBezier(bezier, Math.min((t1Length - a) / d, 1), (t0Length - a) / d);
  31113. stared = true;
  31114. position = subBezier.slice(0, 2);
  31115. subPath.push([ "M" ].concat(subBezier.slice(0, 2)));
  31116. subPath.push([ "C" ].concat(subBezier.slice(2)));
  31117. } else if (t1Length >= b) {
  31118. // t0 左溢出;t1 右溢出,整个块是需要的
  31119. // -----------------------------------
  31120. // t0 t1
  31121. // |_________|
  31122. //
  31123. // 此时取整个块
  31124. subPath.push(path[i].slice());
  31125. } else if (t1Length >= a) {
  31126. // t0 左溢出;t1 命中,取当前块 t1 之前的部分
  31127. // -----------------------------------
  31128. // t0 t1
  31129. // |__|______|
  31130. // 取当前块 t1 之前的部分
  31131. subBezier = g.subBezier(bezier, (t1Length - a) / d);
  31132. subPath.push([ "C" ].concat(subBezier.slice(2)));
  31133. stared = false;
  31134. } else {
  31135. // 没有可以再要的了
  31136. break;
  31137. }
  31138. position = bezier.slice(bezier.length - 2);
  31139. }
  31140. subPath.isAbsolute = true;
  31141. subPath.isCurve = true;
  31142. subPath.isUniform = true;
  31143. subPath.toString = g.pathToString;
  31144. return subPath;
  31145. };
  31146. /**
  31147. * 求路径上的一个点
  31148. *
  31149. * @param {Array|String} path
  31150. * 要求点的路径
  31151. *
  31152. * @param {Number} t
  31153. * 要求的点的位置(0 到 1)
  31154. *
  31155. * @return {Point} p
  31156. * p.x: x 坐标
  31157. * p.y: y 坐标
  31158. * p.tan: 在 t 处的切线方向(类型为 kity.Vector,模为 1)
  31159. */
  31160. g.pointAtPath = function(path, t) {
  31161. if (!path.isCurve) {
  31162. path = g.pathToCurve(path);
  31163. }
  31164. var subPath = g.subPath(path, t);
  31165. var lastCurve = subPath[subPath.length - 1][0] == "Z" ? subPath[subPath.length - 2] : subPath[subPath.length - 1];
  31166. // 跳过 'C' 命令,只留参数
  31167. lastCurve = lastCurve.slice(1);
  31168. var p = Point.parse(lastCurve.slice(4)), c = Point.parse(lastCurve.slice(2, 4));
  31169. p.tan = Vector.fromPoints(c, p).normalize();
  31170. return p;
  31171. };
  31172. /**
  31173. * 求一段路径的长度
  31174. *
  31175. * @param {string|Array} path
  31176. * 要求的路径
  31177. *
  31178. * @return {Number}
  31179. * 路径的长度
  31180. */
  31181. g.pathLength = cacher(function(path) {
  31182. if (!path.isCurve) {
  31183. path = g.pathToCurve(path);
  31184. }
  31185. // path 每一段在整体中的长度区间
  31186. var segmentRanges = getBezierPathSegmentRanges(path);
  31187. return segmentRanges.totalLength;
  31188. });
  31189. /**
  31190. * 求一段路径的关键点
  31191. *
  31192. * @param {string|Array} path
  31193. * 要求的路径
  31194. *
  31195. * @return {Array}
  31196. * 关键点的集合
  31197. */
  31198. g.pathKeyPoints = cacher(function(path) {
  31199. var i, ii, command, keyPoints;
  31200. if (!path.isCurve) {
  31201. path = g.pathToCurve(path);
  31202. }
  31203. keyPoints = [];
  31204. for (i = 0, ii = path.length; i < ii; i++) {
  31205. if (path[i][0] == "z") continue;
  31206. keyPoints.push(path[i].slice(path[i].length - 2));
  31207. }
  31208. return keyPoints;
  31209. });
  31210. // 对比两个路径的关键位置,在合适的位置切割合适的路径,使得两个路径的段数一致
  31211. // TODO: 使用插值算法,使对应点更合理
  31212. var alignCurve = cacher(function(path1, path2) {
  31213. if (!path1.isCurve) path1 = g.pathToCurve(path1);
  31214. if (!path2.isCurve) path2 = g.pathToCurve(path2);
  31215. var p1 = pathClone(path1);
  31216. var p2 = pathClone(path2);
  31217. p1.i = 0;
  31218. p2.i = 0;
  31219. p1.o = p2;
  31220. p2.o = p1;
  31221. function command(p, i) {
  31222. return p[i || p.i] && p[i || p.i][0];
  31223. }
  31224. function param(p, i) {
  31225. return p[i || p.i] && p[i || p.i].slice(1);
  31226. }
  31227. function point(p, i) {
  31228. var _param = param(p, i);
  31229. return _param && _param.slice(-2);
  31230. }
  31231. function fixZ(p) {
  31232. if (command(p) == "Z") {
  31233. p.splice(p.i, 1);
  31234. return true;
  31235. }
  31236. return false;
  31237. }
  31238. function fixM(p) {
  31239. if (command(p) == "M") {
  31240. p.o.splice(p.o.i, 0, [ "M" ].concat(point(p.o, p.o.i - 1)));
  31241. p.i++;
  31242. p.o.i++;
  31243. return true;
  31244. }
  31245. return false;
  31246. }
  31247. function fill(p) {
  31248. var lastPoint;
  31249. var i = 1;
  31250. while (!lastPoint) {
  31251. lastPoint = point(p, p.length - i++);
  31252. }
  31253. p.o.i = p.i;
  31254. while (p.length < p.o.length) {
  31255. if (fixZ(p.o)) continue;
  31256. if (fixM(p.o)) continue;
  31257. p.push([ "C" ].concat(lastPoint).concat(lastPoint).concat(lastPoint));
  31258. p.i++;
  31259. p.o.i++;
  31260. }
  31261. }
  31262. while (p1.i < p1.length && p2.i < p2.length) {
  31263. if (fixZ(p1) || fixZ(p2)) continue;
  31264. if (command(p1) == command(p2)) {
  31265. p1.i++;
  31266. p2.i++;
  31267. continue;
  31268. }
  31269. if (fixM(p1) || fixM(p2)) continue;
  31270. p1.i++;
  31271. p2.i++;
  31272. }
  31273. if (p1.i == p1.length) fill(p1);
  31274. if (p2.i == p2.length) fill(p2);
  31275. delete p1.i;
  31276. delete p1.o;
  31277. delete p2.i;
  31278. delete p2.o;
  31279. return [ p1, p2 ];
  31280. });
  31281. g.alignCurve = alignCurve;
  31282. /**
  31283. * 获得两个路径的补间结果
  31284. *
  31285. * @param {string|Array} path1
  31286. * 补间起始路径
  31287. *
  31288. * @param {string|Array} path2
  31289. * 补间结束路径
  31290. *
  31291. * @param {Number} t
  31292. * 补间比例,0 返回跟 path1 等效的结果;1 返回跟 path2 等效的结果
  31293. *
  31294. * @return {PathSegment}
  31295. * 补间的结果
  31296. */
  31297. g.pathTween = function(path1, path2, t) {
  31298. if (t === 0) return path1;
  31299. if (t === 1) return path2;
  31300. var aligned = alignCurve(path1, path2);
  31301. var result = [], seg, i, j;
  31302. path1 = aligned[0];
  31303. path2 = aligned[1];
  31304. for (i = 0; i < path1.length; i++) {
  31305. result.push(seg = []);
  31306. seg.push(path1[i][0]);
  31307. for (j = 1; j < path1[i].length; j++) {
  31308. seg.push(path1[i][j] + t * (path2[i][j] - path1[i][j]));
  31309. }
  31310. }
  31311. result.isUniform = result.isCurve = result.isAbsolute = true;
  31312. return result;
  31313. };
  31314. /**
  31315. * 变换指定的路径
  31316. *
  31317. * @param {String|Array} path
  31318. * 需要变换的路径
  31319. *
  31320. * @param {kity.Matrix} matrix
  31321. * 使用的变换矩阵
  31322. *
  31323. * @return {Array}
  31324. * 变换后的路径
  31325. */
  31326. g.transformPath = cacher(function(path, matrix) {
  31327. var i, ii, j, result, seg, pair;
  31328. if (!path.isCurve) {
  31329. path = g.pathToCurve(path);
  31330. }
  31331. result = [];
  31332. for (i = 0, ii = path.length; i < ii; i++) {
  31333. result.push(seg = [ path[i][0] ]);
  31334. for (j = 1; j < path[i].length; j += 2) {
  31335. pair = path[i].slice(j, j + 2);
  31336. pair = matrix.transformPoint(Point.parse(pair));
  31337. result.push(pair);
  31338. }
  31339. }
  31340. return result;
  31341. });
  31342. // entend
  31343. _p.r(11).extendClass(Matrix, {
  31344. transformPath: function(path) {
  31345. return g.transformPath(path, this);
  31346. }
  31347. });
  31348. return g;
  31349. }
  31350. };
  31351. //src/graphic/gradient.js
  31352. _p[35] = {
  31353. value: function(require, exports, module) {
  31354. var svg = _p.r(67);
  31355. var Resource = _p.r(58);
  31356. var Color = _p.r(28);
  31357. return _p.r(11).createClass("GradientBrush", {
  31358. base: Resource,
  31359. constructor: function(gradientNodeType, paper) {
  31360. this.callBase(gradientNodeType, paper);
  31361. this.stops = [];
  31362. },
  31363. addStop: function(offset, color, opacity) {
  31364. var gstop = svg.createNode("stop");
  31365. if (!(color instanceof Color)) {
  31366. color = Color.parse(color);
  31367. }
  31368. if (opacity === undefined) {
  31369. opacity = color.get("a");
  31370. }
  31371. gstop.setAttribute("offset", offset);
  31372. gstop.setAttribute("stop-color", color.toRGB());
  31373. if (opacity < 1) {
  31374. gstop.setAttribute("stop-opacity", opacity);
  31375. }
  31376. this.node.appendChild(gstop);
  31377. return this;
  31378. }
  31379. });
  31380. }
  31381. };
  31382. //src/graphic/group.js
  31383. _p[36] = {
  31384. value: function(require, exports, module) {
  31385. var ShapeContainer = _p.r(61);
  31386. return _p.r(11).createClass("Group", {
  31387. mixins: [ ShapeContainer ],
  31388. base: _p.r(60),
  31389. constructor: function Group() {
  31390. this.callBase("g");
  31391. }
  31392. });
  31393. }
  31394. };
  31395. //src/graphic/hyperlink.js
  31396. _p[37] = {
  31397. value: function(require, exports, module) {
  31398. var ShapeContainer = _p.r(61);
  31399. return _p.r(11).createClass("HyperLink", {
  31400. mixins: [ ShapeContainer ],
  31401. base: _p.r(60),
  31402. constructor: function(url) {
  31403. this.callBase("a");
  31404. this.setHref(url);
  31405. },
  31406. setHref: function(href) {
  31407. this.node.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", href);
  31408. return this;
  31409. },
  31410. getHref: function() {
  31411. return this.node.getAttributeNS("xlink:href");
  31412. },
  31413. setTarget: function(target) {
  31414. this.node.setAttribute("target", target);
  31415. return this;
  31416. },
  31417. getTarget: function() {
  31418. return this.node.getAttribute("target");
  31419. }
  31420. });
  31421. }
  31422. };
  31423. //src/graphic/image.js
  31424. _p[38] = {
  31425. value: function(require, exports, module) {
  31426. return _p.r(11).createClass("Image", {
  31427. base: _p.r(60),
  31428. constructor: function(url, width, height, x, y) {
  31429. this.callBase("image");
  31430. this.url = url;
  31431. this.width = width || 0;
  31432. this.height = height || 0;
  31433. this.x = x || 0;
  31434. this.y = y || 0;
  31435. this.update();
  31436. },
  31437. update: function() {
  31438. this.node.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", this.url);
  31439. this.node.setAttribute("x", this.x);
  31440. this.node.setAttribute("y", this.y);
  31441. this.node.setAttribute("width", this.width);
  31442. this.node.setAttribute("height", this.height);
  31443. return this;
  31444. },
  31445. setUrl: function(url) {
  31446. this.url = url === "" ? null : url;
  31447. return this.update();
  31448. },
  31449. getUrl: function() {
  31450. return this.url;
  31451. },
  31452. setWidth: function(width) {
  31453. this.width = width;
  31454. return this.update();
  31455. },
  31456. getWidth: function() {
  31457. return this.width;
  31458. },
  31459. setHeight: function(height) {
  31460. this.height = height;
  31461. return this.update();
  31462. },
  31463. getHeight: function() {
  31464. return this.height;
  31465. },
  31466. setX: function(x) {
  31467. this.x = x;
  31468. return this.update();
  31469. },
  31470. getX: function() {
  31471. return this.x;
  31472. },
  31473. setY: function(y) {
  31474. this.y = y;
  31475. return this.update();
  31476. },
  31477. getY: function() {
  31478. return this.y;
  31479. }
  31480. });
  31481. }
  31482. };
  31483. //src/graphic/line.js
  31484. _p[39] = {
  31485. value: function(require, exports, module) {
  31486. return _p.r(11).createClass("Line", {
  31487. base: _p.r(46),
  31488. constructor: function(x1, y1, x2, y2) {
  31489. this.callBase();
  31490. this.point1 = {
  31491. x: x1 || 0,
  31492. y: y1 || 0
  31493. };
  31494. this.point2 = {
  31495. x: x2 || 0,
  31496. y: y2 || 0
  31497. };
  31498. this.update();
  31499. },
  31500. setPoint1: function(x, y) {
  31501. this.point1.x = x;
  31502. this.point1.y = y;
  31503. return this.update();
  31504. },
  31505. setPoint2: function(x, y) {
  31506. this.point2.x = x;
  31507. this.point2.y = y;
  31508. return this.update();
  31509. },
  31510. getPoint1: function() {
  31511. return {
  31512. x: this.point1.x,
  31513. y: this.point1.y
  31514. };
  31515. },
  31516. getPoint2: function() {
  31517. return {
  31518. x: this.point2.x,
  31519. y: this.point2.y
  31520. };
  31521. },
  31522. update: function() {
  31523. var drawer = this.getDrawer();
  31524. drawer.clear();
  31525. drawer.moveTo(this.point1.x, this.point1.y);
  31526. drawer.lineTo(this.point2.x, this.point2.y);
  31527. return this;
  31528. }
  31529. });
  31530. }
  31531. };
  31532. //src/graphic/lineargradient.js
  31533. _p[40] = {
  31534. value: function(require, exports, module) {
  31535. var svg = _p.r(67);
  31536. var Gradient = _p.r(35);
  31537. return _p.r(11).createClass("LinearGradientBrush", {
  31538. base: Gradient,
  31539. constructor: function(paper) {
  31540. this.callBase("linearGradient", paper);
  31541. this.setStartPosition(0, 0);
  31542. this.setEndPosition(1, 0);
  31543. },
  31544. setStartPosition: function(px, py) {
  31545. this.node.setAttribute("x1", px);
  31546. this.node.setAttribute("y1", py);
  31547. return this;
  31548. },
  31549. setEndPosition: function(px, py) {
  31550. this.node.setAttribute("x2", px);
  31551. this.node.setAttribute("y2", py);
  31552. return this;
  31553. },
  31554. getStartPosition: function() {
  31555. return {
  31556. x: +this.node.getAttribute("x1"),
  31557. y: +this.node.getAttribute("y1")
  31558. };
  31559. },
  31560. getEndPosition: function() {
  31561. return {
  31562. x: +this.node.getAttribute("x2"),
  31563. y: +this.node.getAttribute("y2")
  31564. };
  31565. }
  31566. });
  31567. }
  31568. };
  31569. //src/graphic/marker.js
  31570. _p[41] = {
  31571. value: function(require, exports, module) {
  31572. var Point = _p.r(50);
  31573. var Marker = _p.r(11).createClass("Marker", {
  31574. base: _p.r(58),
  31575. mixins: [ _p.r(61), _p.r(75) ],
  31576. constructor: function() {
  31577. this.callBase("marker");
  31578. this.setOrient("auto");
  31579. },
  31580. setRef: function(x, y) {
  31581. if (arguments.length === 1) {
  31582. y = x.y;
  31583. x = x.x;
  31584. }
  31585. this.node.setAttribute("refX", x);
  31586. this.node.setAttribute("refY", y);
  31587. return this;
  31588. },
  31589. getRef: function() {
  31590. return new Point(+this.node.getAttribute("refX"), +this.node.getAttribute("refY"));
  31591. },
  31592. setWidth: function(width) {
  31593. this.node.setAttribute("markerWidth", this.width = width);
  31594. return this;
  31595. },
  31596. setOrient: function(orient) {
  31597. this.node.setAttribute("orient", this.orient = orient);
  31598. return this;
  31599. },
  31600. getOrient: function() {
  31601. return this.orient;
  31602. },
  31603. getWidth: function() {
  31604. return +this.width;
  31605. },
  31606. setHeight: function(height) {
  31607. this.node.setAttribute("markerHeight", this.height = height);
  31608. return this;
  31609. },
  31610. getHeight: function() {
  31611. return +this.height;
  31612. }
  31613. });
  31614. var Path = _p.r(46);
  31615. _p.r(11).extendClass(Path, {
  31616. setMarker: function(marker, pos) {
  31617. pos = pos || "end";
  31618. if (!marker) {
  31619. this.node.removeAttribute("marker-" + pos);
  31620. } else {
  31621. this.node.setAttribute("marker-" + pos, marker.toString());
  31622. }
  31623. return this;
  31624. }
  31625. });
  31626. return Marker;
  31627. }
  31628. };
  31629. //src/graphic/mask.js
  31630. /**
  31631. * 蒙板
  31632. */
  31633. _p[42] = {
  31634. value: function(require, exports, module) {
  31635. var Class = _p.r(11);
  31636. var Shape = _p.r(60);
  31637. var Mask = Class.createClass("Mask", {
  31638. base: Shape,
  31639. mixins: [ _p.r(61) ],
  31640. constructor: function() {
  31641. this.callBase("mask");
  31642. },
  31643. mask: function(shape) {
  31644. shape.getNode().setAttribute("mask", "url(#" + this.getId() + ")");
  31645. return this;
  31646. }
  31647. });
  31648. Class.extendClass(Shape, {
  31649. maskWith: function(mask) {
  31650. mask.mask(this);
  31651. return this;
  31652. }
  31653. });
  31654. return Mask;
  31655. }
  31656. };
  31657. //src/graphic/matrix.js
  31658. _p[43] = {
  31659. value: function(require, exports, module) {
  31660. var utils = _p.r(12);
  31661. var Box = _p.r(25);
  31662. var mPattern = /matrix\s*\((.+)\)/i;
  31663. var Point = _p.r(50);
  31664. // 注意,合并的结果是先执行m2,再执行m1的结果
  31665. function mergeMatrixData(m2, m1) {
  31666. return {
  31667. a: m1.a * m2.a + m1.c * m2.b,
  31668. b: m1.b * m2.a + m1.d * m2.b,
  31669. c: m1.a * m2.c + m1.c * m2.d,
  31670. d: m1.b * m2.c + m1.d * m2.d,
  31671. e: m1.a * m2.e + m1.c * m2.f + m1.e,
  31672. f: m1.b * m2.e + m1.d * m2.f + m1.f
  31673. };
  31674. }
  31675. function d2r(deg) {
  31676. return deg * Math.PI / 180;
  31677. }
  31678. var Matrix = _p.r(11).createClass("Matrix", {
  31679. constructor: function() {
  31680. if (arguments.length) {
  31681. this.setMatrix.apply(this, arguments);
  31682. } else {
  31683. this.setMatrix(1, 0, 0, 1, 0, 0);
  31684. }
  31685. },
  31686. translate: function(x, y) {
  31687. this.m = mergeMatrixData(this.m, {
  31688. a: 1,
  31689. c: 0,
  31690. e: x,
  31691. b: 0,
  31692. d: 1,
  31693. f: y
  31694. });
  31695. return this;
  31696. },
  31697. rotate: function(deg) {
  31698. var rad = d2r(deg);
  31699. var sin = Math.sin(rad), cos = Math.cos(rad);
  31700. this.m = mergeMatrixData(this.m, {
  31701. a: cos,
  31702. c: -sin,
  31703. e: 0,
  31704. b: sin,
  31705. d: cos,
  31706. f: 0
  31707. });
  31708. return this;
  31709. },
  31710. scale: function(sx, sy) {
  31711. if (sy === undefined) {
  31712. sy = sx;
  31713. }
  31714. this.m = mergeMatrixData(this.m, {
  31715. a: sx,
  31716. c: 0,
  31717. e: 0,
  31718. b: 0,
  31719. d: sy,
  31720. f: 0
  31721. });
  31722. return this;
  31723. },
  31724. skew: function(degX, degY) {
  31725. if (degY === undefined) {
  31726. degY = degX;
  31727. }
  31728. var tx = Math.tan(d2r(degX)), ty = Math.tan(d2r(degY));
  31729. this.m = mergeMatrixData(this.m, {
  31730. a: 1,
  31731. c: tx,
  31732. e: 0,
  31733. b: ty,
  31734. d: 1,
  31735. f: 0
  31736. });
  31737. return this;
  31738. },
  31739. /**
  31740. * 获得反转矩阵
  31741. *
  31742. * 这是我解方程算出来的
  31743. */
  31744. inverse: function() {
  31745. var m = this.m, a = m.a, b = m.b, c = m.c, d = m.d, e = m.e, f = m.f, k, aa, bb, cc, dd, ee, ff;
  31746. k = a * d - b * c;
  31747. aa = d / k;
  31748. bb = -b / k;
  31749. cc = -c / k;
  31750. dd = a / k;
  31751. ee = (c * f - e * d) / k;
  31752. ff = (b * e - a * f) / k;
  31753. return new Matrix(aa, bb, cc, dd, ee, ff);
  31754. },
  31755. setMatrix: function(a, b, c, d, e, f) {
  31756. if (arguments.length === 1) {
  31757. this.m = utils.clone(arguments[0]);
  31758. } else {
  31759. this.m = {
  31760. a: a,
  31761. b: b,
  31762. c: c,
  31763. d: d,
  31764. e: e,
  31765. f: f
  31766. };
  31767. }
  31768. return this;
  31769. },
  31770. getMatrix: function() {
  31771. return utils.clone(this.m);
  31772. },
  31773. getTranslate: function() {
  31774. var m = this.m;
  31775. return {
  31776. x: m.e / m.a,
  31777. y: m.f / m.d
  31778. };
  31779. },
  31780. mergeMatrix: function(matrix) {
  31781. return new Matrix(mergeMatrixData(this.m, matrix.m));
  31782. },
  31783. merge: function(matrix) {
  31784. return this.mergeMatrix(matrix);
  31785. },
  31786. toString: function() {
  31787. return this.valueOf().join(" ");
  31788. },
  31789. valueOf: function() {
  31790. var m = this.m;
  31791. return [ m.a, m.b, m.c, m.d, m.e, m.f ];
  31792. },
  31793. equals: function(matrix) {
  31794. var m1 = this.m, m2 = matrix.m;
  31795. return m1.a == m2.a && m1.b == m2.b && m1.c == m2.c && m1.d == m2.d && m1.e == m2.e && m1.f == m2.f;
  31796. },
  31797. transformPoint: function() {
  31798. return Matrix.transformPoint.apply(null, [].slice.call(arguments).concat([ this.m ]));
  31799. },
  31800. transformBox: function(box) {
  31801. return Matrix.transformBox(box, this.m);
  31802. },
  31803. clone: function() {
  31804. return new Matrix(this.m);
  31805. }
  31806. });
  31807. Matrix.parse = function(str) {
  31808. var match;
  31809. var f = parseFloat;
  31810. if (str instanceof Array) {
  31811. return new Matrix({
  31812. a: str[0],
  31813. b: str[1],
  31814. c: str[2],
  31815. d: str[3],
  31816. e: str[4],
  31817. f: str[5]
  31818. });
  31819. }
  31820. if (match = mPattern.exec(str)) {
  31821. var values = match[1].split(",");
  31822. if (values.length != 6) {
  31823. values = match[1].split(" ");
  31824. }
  31825. return new Matrix({
  31826. a: f(values[0]),
  31827. b: f(values[1]),
  31828. c: f(values[2]),
  31829. d: f(values[3]),
  31830. e: f(values[4]),
  31831. f: f(values[5])
  31832. });
  31833. }
  31834. return new Matrix();
  31835. };
  31836. Matrix.transformPoint = function(x, y, m) {
  31837. if (arguments.length === 2) {
  31838. m = y;
  31839. y = x.y;
  31840. x = x.x;
  31841. }
  31842. return new Point(m.a * x + m.c * y + m.e, m.b * x + m.d * y + m.f);
  31843. };
  31844. Matrix.transformBox = function(box, matrix) {
  31845. var xMin = Number.MAX_VALUE, xMax = -Number.MAX_VALUE, yMin = Number.MAX_VALUE, yMax = -Number.MAX_VALUE;
  31846. var bps = [ [ box.x, box.y ], [ box.x + box.width, box.y ], [ box.x, box.y + box.height ], [ box.x + box.width, box.y + box.height ] ];
  31847. var bp, rp, rps = [];
  31848. while (bp = bps.pop()) {
  31849. rp = Matrix.transformPoint(bp[0], bp[1], matrix);
  31850. rps.push(rp);
  31851. xMin = Math.min(xMin, rp.x);
  31852. xMax = Math.max(xMax, rp.x);
  31853. yMin = Math.min(yMin, rp.y);
  31854. yMax = Math.max(yMax, rp.y);
  31855. }
  31856. box = new Box({
  31857. x: xMin,
  31858. y: yMin,
  31859. width: xMax - xMin,
  31860. height: yMax - yMin
  31861. });
  31862. utils.extend(box, {
  31863. closurePoints: rps
  31864. });
  31865. return box;
  31866. };
  31867. // 获得从 node 到 refer 的变换矩阵
  31868. Matrix.getCTM = function(target, refer) {
  31869. var ctm = {
  31870. a: 1,
  31871. b: 0,
  31872. c: 0,
  31873. d: 1,
  31874. e: 0,
  31875. f: 0
  31876. };
  31877. var node = target.shapeNode || target.node;
  31878. refer = refer || "parent";
  31879. // 根据参照坐标系选区的不一样,返回不同的结果
  31880. switch (refer) {
  31881. case "screen":
  31882. // 以浏览器屏幕为参照坐标系
  31883. ctm = node.getScreenCTM();
  31884. break;
  31885. case "doc":
  31886. case "paper":
  31887. // 以文档(Paper)为参照坐标系
  31888. ctm = node.getCTM();
  31889. break;
  31890. case "view":
  31891. case "top":
  31892. // 以顶层绘图容器(视野)为参照坐标系
  31893. if (target.getPaper()) {
  31894. ctm = node.getTransformToElement(target.getPaper().shapeNode);
  31895. }
  31896. break;
  31897. case "parent":
  31898. // 以父容器为参照坐标系
  31899. if (target.node.parentNode) {
  31900. ctm = node.getTransformToElement(target.node.parentNode);
  31901. }
  31902. break;
  31903. default:
  31904. // 其他情况,指定参照物
  31905. if (refer.node) {
  31906. ctm = node.getTransformToElement(refer.shapeNode || refer.node);
  31907. }
  31908. }
  31909. return ctm ? new Matrix(ctm.a, ctm.b, ctm.c, ctm.d, ctm.e, ctm.f) : new Matrix();
  31910. };
  31911. return Matrix;
  31912. }
  31913. };
  31914. //src/graphic/palette.js
  31915. /**
  31916. * 调色板
  31917. */
  31918. _p[44] = {
  31919. value: function(require, exports, module) {
  31920. //标准color
  31921. var StandardColor = _p.r(64), Color = _p.r(28), Utils = _p.r(12);
  31922. var Palette = _p.r(11).createClass("Palette", {
  31923. constructor: function() {
  31924. this.color = {};
  31925. },
  31926. /*
  31927. * 获取颜色名称所对应的颜色值的Color对象
  31928. * @param name 需要获取的颜色名称
  31929. * @return 对应颜色名称的color对象, 如果未找到对应的名称, 则返回null
  31930. */
  31931. get: function(name) {
  31932. var colorValue = this.color[name] || StandardColor.EXTEND_STANDARD[name] || StandardColor.COLOR_STANDARD[name] || "";
  31933. if (colorValue) {
  31934. return new Color(colorValue);
  31935. }
  31936. return null;
  31937. },
  31938. /*
  31939. * 获取给定名称的颜色的hex值表示
  31940. * @param name 需要获取的颜色名称
  31941. * @return 如果找到对应的名称, 则返回该名称所对应的hex格式的值, 否则, 返回一个空字符串
  31942. */
  31943. getColorValue: function(name) {
  31944. return this.color[name] || StandardColor.EXTEND_STANDARD[name] || StandardColor.COLOR_STANDARD[name] || "";
  31945. },
  31946. /*
  31947. * 向调色板实例添加自己独有的颜色名称,对已存在的颜色名称, 将会覆盖掉
  31948. * @param name 新添加的颜色名称
  31949. * @param value 新添加的颜色名称所对应的值, 可以是一个合法的颜色字符串或者是一个color对象
  31950. * @return 新添加的颜色的值
  31951. */
  31952. add: function(name, value) {
  31953. if (typeof value === "string") {
  31954. this.color[name] = new Color(value).toRGBA();
  31955. } else {
  31956. this.color[name] = value.toRGBA();
  31957. }
  31958. return value;
  31959. },
  31960. /*
  31961. * 删除调色板实例上用户自己添加的颜色, 该方法不能删除内置的颜色
  31962. * @param name 需要删除的颜色名称
  31963. * @return 删除是否成功的bool值
  31964. */
  31965. remove: function(name) {
  31966. if (this.color.hasOwnProperty(name)) {
  31967. delete this.color[name];
  31968. return true;
  31969. }
  31970. return false;
  31971. }
  31972. });
  31973. Utils.extend(Palette, {
  31974. getColor: function(name) {
  31975. var colorValue = StandardColor.EXTEND_STANDARD[name] || StandardColor.COLOR_STANDARD[name];
  31976. if (colorValue) {
  31977. return new Color(colorValue);
  31978. }
  31979. return null;
  31980. },
  31981. /*
  31982. * 通过给定的名字获取标准的颜色值表示, 返回的值以hex的方式提供
  31983. * @param name 需要获取的标准颜色名称
  31984. * @return 名字所对应的颜色值的hex表示, 如果未找到对应名称的值, 则返回一个空字符串
  31985. */
  31986. getColorValue: function(name) {
  31987. return StandardColor.EXTEND_STANDARD[name] || StandardColor.COLOR_STANDARD[name] || "";
  31988. },
  31989. /*
  31990. * 向调色板添加颜色名称,新添加的颜色对所有的调色板对象都可见
  31991. * 对已存在的颜色名称, 将会覆盖掉
  31992. * @param name 新添加的颜色名称
  31993. * @param value 新添加的颜色名称所对于的值, 应该是一个hex格式的颜色字符串, 如: ”#ff0000“
  31994. * @return 新添加的颜色的值
  31995. */
  31996. addColor: function(name, value) {
  31997. if (typeof value === "string") {
  31998. StandardColor.EXTEND_STANDARD[name] = new Color(value).toRGBA();
  31999. } else {
  32000. StandardColor.EXTEND_STANDARD[name] = value.toRGBA();
  32001. }
  32002. return value;
  32003. },
  32004. /*
  32005. * 删除用户自己添加的颜色, 该方法不能删除内置的颜色, 该方法不会影响调色板实例自由的颜色
  32006. * @param name 需要删除的颜色名称
  32007. * @return 删除是否成功的bool值
  32008. */
  32009. removeColor: function(name) {
  32010. if (StandardColor.EXTEND_STANDARD.hasOwnProperty(name)) {
  32011. delete StandardColor.EXTEND_STANDARD[name];
  32012. return true;
  32013. }
  32014. return false;
  32015. }
  32016. });
  32017. return Palette;
  32018. }
  32019. };
  32020. //src/graphic/paper.js
  32021. _p[45] = {
  32022. value: function(require, exports, module) {
  32023. var Class = _p.r(11);
  32024. var utils = _p.r(12);
  32025. var svg = _p.r(67);
  32026. var Container = _p.r(29);
  32027. var ShapeContainer = _p.r(61);
  32028. var ViewBox = _p.r(75);
  32029. var EventHandler = _p.r(33);
  32030. var Styled = _p.r(66);
  32031. var Matrix = _p.r(43);
  32032. var Paper = Class.createClass("Paper", {
  32033. mixins: [ ShapeContainer, EventHandler, Styled, ViewBox ],
  32034. constructor: function(container) {
  32035. this.callBase();
  32036. this.node = this.createSVGNode();
  32037. this.node.paper = this;
  32038. this.node.appendChild(this.resourceNode = svg.createNode("defs"));
  32039. this.node.appendChild(this.shapeNode = svg.createNode("g"));
  32040. this.resources = new Container();
  32041. this.setWidth("100%").setHeight("100%");
  32042. if (container) {
  32043. this.renderTo(container);
  32044. }
  32045. this.callMixin();
  32046. },
  32047. renderTo: function(container) {
  32048. if (utils.isString(container)) {
  32049. container = document.getElementById(container);
  32050. }
  32051. this.container = container;
  32052. container.appendChild(this.node);
  32053. },
  32054. createSVGNode: function() {
  32055. var node = svg.createNode("svg");
  32056. node.setAttribute("xmlns", "http://www.w3.org/2000/svg");
  32057. node.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
  32058. node.setAttribute("version", "1.1");
  32059. return node;
  32060. },
  32061. getNode: function() {
  32062. return this.node;
  32063. },
  32064. getContainer: function() {
  32065. return this.container;
  32066. },
  32067. getWidth: function() {
  32068. return this.node.clientWidth;
  32069. },
  32070. setWidth: function(width) {
  32071. this.node.setAttribute("width", width);
  32072. return this;
  32073. },
  32074. getHeight: function() {
  32075. return this.node.clientHeight;
  32076. },
  32077. setHeight: function(height) {
  32078. this.node.setAttribute("height", height);
  32079. return this;
  32080. },
  32081. setViewPort: function(cx, cy, zoom) {
  32082. var viewport, box;
  32083. if (arguments.length == 1) {
  32084. viewport = arguments[0];
  32085. cx = viewport.center.x;
  32086. cy = viewport.center.y;
  32087. zoom = viewport.zoom;
  32088. }
  32089. zoom = zoom || 1;
  32090. box = this.getViewBox();
  32091. var matrix = new Matrix();
  32092. var dx = box.x + box.width / 2 - cx, dy = box.y + box.height / 2 - cy;
  32093. matrix.translate(-cx, -cy);
  32094. matrix.scale(zoom);
  32095. matrix.translate(cx, cy);
  32096. matrix.translate(dx, dy);
  32097. this.shapeNode.setAttribute("transform", "matrix(" + matrix + ")");
  32098. this.viewport = {
  32099. center: {
  32100. x: cx,
  32101. y: cy
  32102. },
  32103. offset: {
  32104. x: dx,
  32105. y: dy
  32106. },
  32107. zoom: zoom
  32108. };
  32109. return this;
  32110. },
  32111. getViewPort: function() {
  32112. if (!this.viewport) {
  32113. var box = this.getViewBox();
  32114. return {
  32115. zoom: 1,
  32116. center: {
  32117. x: box.x + box.width / 2,
  32118. y: box.y + box.height / 2
  32119. },
  32120. offset: {
  32121. x: 0,
  32122. y: 0
  32123. }
  32124. };
  32125. }
  32126. return this.viewport;
  32127. },
  32128. getViewPortMatrix: function() {
  32129. return Matrix.parse(this.shapeNode.getAttribute("transform"));
  32130. },
  32131. getViewPortTransform: function() {
  32132. var m = this.shapeNode.getCTM();
  32133. return new Matrix(m.a, m.b, m.c, m.d, m.e, m.f);
  32134. },
  32135. getTransform: function() {
  32136. return this.getViewPortTransform().reverse();
  32137. },
  32138. addResource: function(resource) {
  32139. this.resources.appendItem(resource);
  32140. if (resource.node) {
  32141. this.resourceNode.appendChild(resource.node);
  32142. }
  32143. return this;
  32144. },
  32145. removeResource: function(resource) {
  32146. if (resource.remove) {
  32147. resource.remove();
  32148. }
  32149. if (resource.node) {
  32150. this.resourceNode.removeChild(resource.node);
  32151. }
  32152. return this;
  32153. },
  32154. getPaper: function() {
  32155. return this;
  32156. }
  32157. });
  32158. var Shape = _p.r(60);
  32159. Class.extendClass(Shape, {
  32160. getPaper: function() {
  32161. var parent = this.container;
  32162. while (parent && parent instanceof Paper === false) {
  32163. parent = parent.container;
  32164. }
  32165. return parent;
  32166. },
  32167. isAttached: function() {
  32168. return !!this.getPaper();
  32169. },
  32170. whenPaperReady: function(fn) {
  32171. var me = this;
  32172. function check() {
  32173. var paper = me.getPaper();
  32174. if (paper && fn) {
  32175. fn.call(me, paper);
  32176. }
  32177. return paper;
  32178. }
  32179. if (!check()) {
  32180. this.on("add treeadd", function listen() {
  32181. if (check()) {
  32182. me.off("add", listen);
  32183. me.off("treeadd", listen);
  32184. }
  32185. });
  32186. }
  32187. return this;
  32188. }
  32189. });
  32190. return Paper;
  32191. }
  32192. };
  32193. //src/graphic/path.js
  32194. _p[46] = {
  32195. value: function(require, exports, module) {
  32196. var Utils = _p.r(12);
  32197. var createClass = _p.r(11).createClass;
  32198. var Shape = _p.r(60);
  32199. var svg = _p.r(67);
  32200. var g = _p.r(34);
  32201. var slice = Array.prototype.slice, flatten = Utils.flatten;
  32202. var PathDrawer = createClass("PathDrawer", {
  32203. constructor: function(path) {
  32204. this.segment = [];
  32205. this.path = path;
  32206. this.__clear = false;
  32207. },
  32208. getPath: function() {
  32209. return this.path;
  32210. },
  32211. redraw: function() {
  32212. this._transation = this._transation || [];
  32213. return this.clear();
  32214. },
  32215. done: function() {
  32216. var transation = this._transation;
  32217. this._transation = null;
  32218. this.push(transation);
  32219. return this;
  32220. },
  32221. clear: function() {
  32222. if (this._transation) {
  32223. this._transation = [];
  32224. } else {
  32225. this.path.setPathData("M 0 0");
  32226. }
  32227. this._clear = true;
  32228. return this;
  32229. },
  32230. push: function() {
  32231. var segment = slice.call(arguments);
  32232. var originData;
  32233. if (this._transation) {
  32234. this._transation.push(segment);
  32235. return this;
  32236. }
  32237. if (this._clear) {
  32238. originData = "";
  32239. this._clear = false;
  32240. } else {
  32241. originData = this.path.getPathData();
  32242. }
  32243. originData = originData || "";
  32244. this.path.setPathData(originData + g.pathToString(segment));
  32245. return this;
  32246. },
  32247. moveTo: function(x, y) {
  32248. return this.push("M", slice.call(arguments));
  32249. },
  32250. moveBy: function(dx, dy) {
  32251. return this.push("m", slice.call(arguments));
  32252. },
  32253. lineTo: function(x, y) {
  32254. return this.push("L", slice.call(arguments));
  32255. },
  32256. lineBy: function(dx, dy) {
  32257. return this.push("l", slice.call(arguments));
  32258. },
  32259. arcTo: function(rx, ry, xr, laf, sf, x, y) {
  32260. return this.push("A", slice.call(arguments));
  32261. },
  32262. arcBy: function(rx, ry, xr, laf, sf, dx, dy) {
  32263. return this.push("a", arguments);
  32264. },
  32265. carcTo: function(r, laf, sf, x, y) {
  32266. return this.push("A", [ r, r, 0 ].concat(slice.call(arguments, 1)));
  32267. },
  32268. carcBy: function(r, laf, sf, dx, dy) {
  32269. return this.push("a", [ r, r, 0 ].concat(slice.call(arguments, 1)));
  32270. },
  32271. bezierTo: function(x1, y1, x2, y2, x, y) {
  32272. return this.push("C", slice.call(arguments));
  32273. },
  32274. bezierBy: function(dx1, dy1, dx2, dy2, dx, dy) {
  32275. return this.push("c", slice.call(arguments));
  32276. },
  32277. close: function() {
  32278. return this.push("z");
  32279. }
  32280. });
  32281. return createClass("Path", {
  32282. base: Shape,
  32283. constructor: function(data) {
  32284. this.callBase("path");
  32285. if (data) {
  32286. this.setPathData(data);
  32287. }
  32288. this.node.setAttribute("fill", svg.defaults.fill);
  32289. this.node.setAttribute("stroke", svg.defaults.stroke);
  32290. },
  32291. setPathData: function(data) {
  32292. data = data || "M0,0";
  32293. this.pathdata = g.pathToString(data);
  32294. this.node.setAttribute("d", this.pathdata);
  32295. this.trigger("shapeupdate", {
  32296. type: "pathdata"
  32297. });
  32298. return this;
  32299. },
  32300. getPathData: function() {
  32301. return this.pathdata || "";
  32302. },
  32303. getDrawer: function() {
  32304. return new PathDrawer(this);
  32305. },
  32306. isClosed: function() {
  32307. var data = this.getPathData();
  32308. return !!~data.indexOf("z") || !!~data.indexOf("Z");
  32309. }
  32310. });
  32311. }
  32312. };
  32313. //src/graphic/pattern.js
  32314. _p[47] = {
  32315. value: function(require, exports, module) {
  32316. var Resource = _p.r(58);
  32317. var ShapeContainer = _p.r(61);
  32318. var svg = _p.r(67);
  32319. return _p.r(11).createClass("PatternBrush", {
  32320. base: Resource,
  32321. mixins: [ ShapeContainer ],
  32322. constructor: function(paper) {
  32323. this.callBase("pattern", paper);
  32324. this.node.setAttribute("patternUnits", "userSpaceOnUse");
  32325. },
  32326. setX: function(x) {
  32327. this.x = x;
  32328. this.node.setAttribute("x", x);
  32329. return this;
  32330. },
  32331. setY: function(y) {
  32332. this.y = y;
  32333. this.node.setAttribute("y", y);
  32334. return this;
  32335. },
  32336. setWidth: function(width) {
  32337. this.width = width;
  32338. this.node.setAttribute("width", width);
  32339. return this;
  32340. },
  32341. setHeight: function(height) {
  32342. this.height = height;
  32343. this.node.setAttribute("height", height);
  32344. return this;
  32345. },
  32346. getWidth: function() {
  32347. return this.width;
  32348. },
  32349. getHeight: function() {
  32350. return this.height;
  32351. }
  32352. });
  32353. }
  32354. };
  32355. //src/graphic/pen.js
  32356. _p[48] = {
  32357. value: function(require, exports, module) {
  32358. var Color = _p.r(28);
  32359. return _p.r(11).createClass("Pen", {
  32360. constructor: function(brush, width) {
  32361. this.brush = brush;
  32362. this.width = width || 1;
  32363. this.linecap = null;
  32364. this.linejoin = null;
  32365. this.dashArray = null;
  32366. this.opacity = 1;
  32367. },
  32368. getBrush: function() {
  32369. return this.brush;
  32370. },
  32371. setBrush: function(brush) {
  32372. this.brush = brush;
  32373. return this;
  32374. },
  32375. setColor: function(color) {
  32376. return this.setBrush(color);
  32377. },
  32378. getColor: function() {
  32379. return this.brush instanceof Color ? this.brush : null;
  32380. },
  32381. getWidth: function() {
  32382. return this.width;
  32383. },
  32384. setWidth: function(width) {
  32385. this.width = width;
  32386. return this;
  32387. },
  32388. getOpacity: function() {
  32389. return this.opacity;
  32390. },
  32391. setOpacity: function(opacity) {
  32392. this.opacity = opacity;
  32393. },
  32394. getLineCap: function() {
  32395. return this.linecap;
  32396. },
  32397. setLineCap: function(linecap) {
  32398. this.linecap = linecap;
  32399. return this;
  32400. },
  32401. getLineJoin: function() {
  32402. return this.linejoin;
  32403. },
  32404. setLineJoin: function(linejoin) {
  32405. this.linejoin = linejoin;
  32406. return this;
  32407. },
  32408. getDashArray: function() {
  32409. return this.dashArray;
  32410. },
  32411. setDashArray: function(dashArray) {
  32412. this.dashArray = dashArray;
  32413. return this;
  32414. },
  32415. stroke: function(shape) {
  32416. var node = shape.node;
  32417. node.setAttribute("stroke", this.brush.toString());
  32418. node.setAttribute("stroke-width", this.getWidth());
  32419. if (this.getOpacity() < 1) {
  32420. node.setAttribute("stroke-opacity", this.getOpacity());
  32421. }
  32422. if (this.getLineCap()) {
  32423. node.setAttribute("stroke-linecap", this.getLineCap());
  32424. }
  32425. if (this.getLineJoin()) {
  32426. node.setAttribute("stroke-linejoin", this.getLineJoin());
  32427. }
  32428. if (this.getDashArray()) {
  32429. node.setAttribute("stroke-dasharray", this.getDashArray());
  32430. }
  32431. }
  32432. });
  32433. }
  32434. };
  32435. //src/graphic/pie.js
  32436. _p[49] = {
  32437. value: function(require, exports, module) {
  32438. return _p.r(11).createClass({
  32439. base: _p.r(68),
  32440. constructor: function(radius, angle, angleOffset) {
  32441. this.callBase([ 0, radius ], angle, angleOffset);
  32442. },
  32443. getRadius: function() {
  32444. return this.getSectionArray()[1];
  32445. },
  32446. setRadius: function(radius) {
  32447. this.setSectionArray([ 0, radius ]);
  32448. }
  32449. });
  32450. }
  32451. };
  32452. //src/graphic/point.js
  32453. /*
  32454. * 点对象抽象
  32455. */
  32456. _p[50] = {
  32457. value: function(require, exports, module) {
  32458. /**
  32459. * @class kity.Point
  32460. * @description 表示一个点
  32461. */
  32462. var Point = _p.r(11).createClass("Point", {
  32463. /**
  32464. * @constructor
  32465. * @for kity.Point
  32466. * @description 指定默认的 x 和 y 创建一个点
  32467. *
  32468. * @param {Number} x 点的 x 坐标
  32469. * @param {Number} y 点的 y 坐标
  32470. */
  32471. constructor: function(x, y) {
  32472. /**
  32473. * @property
  32474. * @for kity.Point
  32475. * @description 表示点的 x 坐标
  32476. * @type {Number}
  32477. */
  32478. this.x = x || 0;
  32479. /**
  32480. * @property
  32481. * @for kity.Point
  32482. * @description 表示点的 y 坐标
  32483. * @type {Number}
  32484. */
  32485. this.y = y || 0;
  32486. },
  32487. offset: function(dx, dy) {
  32488. if (arguments.length == 1) {
  32489. dy = dx.y;
  32490. dx = dx.x;
  32491. }
  32492. return new Point(this.x + dx, this.y + dy);
  32493. },
  32494. valueOf: function() {
  32495. return [ this.x, this.y ];
  32496. },
  32497. toString: function() {
  32498. return this.valueOf().join(" ");
  32499. },
  32500. spof: function() {
  32501. return new Point((this.x | 0) + .5, (this.y | 0) + .5);
  32502. },
  32503. round: function() {
  32504. return new Point(this.x | 0, this.y | 0);
  32505. },
  32506. isOrigin: function() {
  32507. return this.x === 0 && this.y === 0;
  32508. }
  32509. });
  32510. /**
  32511. * @static
  32512. * @method fromPolar()
  32513. * @for kity.Point
  32514. * @grammar kity.Point.fromPolar(radius, angle, unit) => kity.Point
  32515. * @param {Number} radius 极坐标中的半径
  32516. * @param {Number} angle 极坐标中的角度
  32517. * @param {String} unit 角度使用的单位,默认为 'deg' (角度),可以取值为 'rad',表示传入的是弧度值
  32518. */
  32519. Point.fromPolar = function(radius, angle, unit) {
  32520. if (unit != "rad") {
  32521. // deg to rad
  32522. angle = angle / 180 * Math.PI;
  32523. }
  32524. return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
  32525. };
  32526. Point.parse = function(unknown) {
  32527. if (!unknown) return new Point();
  32528. if (unknown instanceof Point) {
  32529. return unknown;
  32530. }
  32531. if (typeof unknown == "string") {
  32532. return Point.parse(unknown.split(/\s*[\s,]\s*/));
  32533. }
  32534. if ("0" in unknown && "1" in unknown) {
  32535. return new Point(unknown[0], unknown[1]);
  32536. }
  32537. };
  32538. return Point;
  32539. }
  32540. };
  32541. //src/graphic/pointcontainer.js
  32542. /**
  32543. * 点集合容器
  32544. */
  32545. _p[51] = {
  32546. value: function(require, exports, module) {
  32547. return _p.r(11).createClass("PointContainer", {
  32548. base: _p.r(29),
  32549. constructor: function() {
  32550. this.callBase();
  32551. },
  32552. addPoint: function(point, pos) {
  32553. return this.addItem.apply(this, arguments);
  32554. },
  32555. prependPoint: function() {
  32556. return this.prependItem.apply(this, arguments);
  32557. },
  32558. appendPoint: function() {
  32559. return this.appendItem.apply(this, arguments);
  32560. },
  32561. removePoint: function(pos) {
  32562. return this.removeItem.apply(this, arguments);
  32563. },
  32564. addPoints: function() {
  32565. return this.addItems.apply(this, arguments);
  32566. },
  32567. setPoints: function() {
  32568. return this.setItems.apply(this, arguments);
  32569. },
  32570. getPoint: function() {
  32571. return this.getItem.apply(this, arguments);
  32572. },
  32573. getPoints: function() {
  32574. return this.getItems.apply(this, arguments);
  32575. },
  32576. getFirstPoint: function() {
  32577. return this.getFirstItem.apply(this, arguments);
  32578. },
  32579. getLastPoint: function() {
  32580. return this.getLastItem.apply(this, arguments);
  32581. }
  32582. });
  32583. }
  32584. };
  32585. //src/graphic/poly.js
  32586. /*
  32587. * 通过点来决定图形的公共父类
  32588. */
  32589. _p[52] = {
  32590. value: function(require, exports, module) {
  32591. var Utils = _p.r(12);
  32592. return _p.r(11).createClass("Poly", {
  32593. base: _p.r(46),
  32594. mixins: [ _p.r(51) ],
  32595. constructor: function(points, closeable) {
  32596. this.callBase();
  32597. //是否可闭合
  32598. this.closeable = !!closeable;
  32599. this.setPoints(points || []);
  32600. this.changeable = true;
  32601. this.update();
  32602. },
  32603. //当点集合发生变化时采取的动作
  32604. onContainerChanged: function() {
  32605. if (this.changeable) {
  32606. this.update();
  32607. }
  32608. },
  32609. update: function() {
  32610. var drawer = this.getDrawer(), points = this.getPoints();
  32611. drawer.clear();
  32612. if (!points.length) {
  32613. return this;
  32614. }
  32615. drawer.moveTo(points[0]);
  32616. for (var i = 1, point, len = points.length; i < len; i++) {
  32617. point = points[i];
  32618. drawer.lineTo(point);
  32619. }
  32620. if (this.closeable && points.length > 2) {
  32621. drawer.close();
  32622. }
  32623. return this;
  32624. }
  32625. });
  32626. }
  32627. };
  32628. //src/graphic/polygon.js
  32629. _p[53] = {
  32630. value: function(require, exports, module) {
  32631. return _p.r(11).createClass("Polygon", {
  32632. base: _p.r(52),
  32633. constructor: function(points) {
  32634. this.callBase(points, true);
  32635. }
  32636. });
  32637. }
  32638. };
  32639. //src/graphic/polyline.js
  32640. _p[54] = {
  32641. value: function(require, exports, module) {
  32642. return _p.r(11).createClass("Polyline", {
  32643. base: _p.r(52),
  32644. constructor: function(points) {
  32645. this.callBase(points);
  32646. }
  32647. });
  32648. }
  32649. };
  32650. //src/graphic/radialgradient.js
  32651. _p[55] = {
  32652. value: function(require, exports, module) {
  32653. var Gradient = _p.r(35);
  32654. return _p.r(11).createClass("RadialGradientBrush", {
  32655. base: Gradient,
  32656. constructor: function(paper) {
  32657. this.callBase("radialGradient", paper);
  32658. this.setCenter(.5, .5);
  32659. this.setFocal(.5, .5);
  32660. this.setRadius(.5);
  32661. },
  32662. setCenter: function(cx, cy) {
  32663. this.node.setAttribute("cx", cx);
  32664. this.node.setAttribute("cy", cy);
  32665. return this;
  32666. },
  32667. getCenter: function() {
  32668. return {
  32669. x: +this.node.getAttribute("cx"),
  32670. y: +this.node.getAttribute("cy")
  32671. };
  32672. },
  32673. setFocal: function(fx, fy) {
  32674. this.node.setAttribute("fx", fx);
  32675. this.node.setAttribute("fy", fy);
  32676. return this;
  32677. },
  32678. getFocal: function() {
  32679. return {
  32680. x: +this.node.getAttribute("fx"),
  32681. y: +this.node.getAttribute("fy")
  32682. };
  32683. },
  32684. setRadius: function(r) {
  32685. this.node.setAttribute("r", r);
  32686. return this;
  32687. },
  32688. getRadius: function() {
  32689. return +this.node.getAttribute("r");
  32690. }
  32691. });
  32692. }
  32693. };
  32694. //src/graphic/rect.js
  32695. _p[56] = {
  32696. value: function(require, exports, module) {
  32697. var RectUtils = {}, Utils = _p.r(12), Point = _p.r(50), Box = _p.r(25);
  32698. Utils.extend(RectUtils, {
  32699. //根据传递进来的width、height和radius属性,
  32700. //获取最适合的radius值
  32701. formatRadius: function(width, height, radius) {
  32702. var minValue = Math.floor(Math.min(width / 2, height / 2));
  32703. return Math.min(minValue, radius);
  32704. }
  32705. });
  32706. /**
  32707. * @class kity.Rect
  32708. * @description 表示一个矩形
  32709. * @base kity.Path
  32710. */
  32711. var Rect = _p.r(11).createClass("Rect", {
  32712. base: _p.r(46),
  32713. /**
  32714. * @constructor
  32715. * @for kity.Rect
  32716. * @grammar new kity.Rect(width, height, x, y, radius)
  32717. * @param {Number} width 矩形的初始化宽度
  32718. * @param {Number} height 矩形的初始化高度
  32719. * @param {Number} x 矩形的初始化 x 坐标
  32720. * @param {Number} y 矩形的初始化 y 坐标
  32721. * @param {Number} radius 矩形的初始化圆角大小
  32722. */
  32723. constructor: function(width, height, x, y, radius) {
  32724. this.callBase();
  32725. this.x = x || 0;
  32726. this.y = y || 0;
  32727. this.width = width || 0;
  32728. this.height = height || 0;
  32729. this.radius = RectUtils.formatRadius(this.width, this.height, radius || 0);
  32730. this.update();
  32731. },
  32732. update: function() {
  32733. var x = this.x, y = this.y, w = this.width, h = this.height, r = this.radius;
  32734. var drawer = this.getDrawer().redraw();
  32735. if (!r) {
  32736. // 直角
  32737. drawer.push("M", x, y);
  32738. drawer.push("h", w);
  32739. drawer.push("v", h);
  32740. drawer.push("h", -w);
  32741. drawer.push("z");
  32742. } else {
  32743. //圆角
  32744. w -= 2 * r;
  32745. h -= 2 * r;
  32746. drawer.push("M", x + r, y);
  32747. drawer.push("h", w);
  32748. drawer.push("a", r, r, 0, 0, 1, r, r);
  32749. drawer.push("v", h);
  32750. drawer.push("a", r, r, 0, 0, 1, -r, r);
  32751. drawer.push("h", -w);
  32752. drawer.push("a", r, r, 0, 0, 1, -r, -r);
  32753. drawer.push("v", -h);
  32754. drawer.push("a", r, r, 0, 0, 1, r, -r);
  32755. drawer.push("z");
  32756. }
  32757. drawer.done();
  32758. return this;
  32759. },
  32760. /**
  32761. * @method setWidth
  32762. * @for kity.Rect
  32763. * @grammar setWidth(width) => kity.Rect
  32764. * @description 设置矩形的宽度,设置后返回矩形实例本身
  32765. * @param {Number} width 宽度值
  32766. *
  32767. * @example
  32768. * ```js
  32769. * rect.setWidth(300);
  32770. * ```
  32771. */
  32772. setWidth: function(width) {
  32773. this.width = width;
  32774. return this.update();
  32775. },
  32776. /**
  32777. * @method setHeight
  32778. * @for kity.Rect
  32779. * @grammar setHeight(height) => kity.Rect
  32780. * @description 设置矩形的高度,设置后返回矩形实例本身
  32781. * @param {Number} height 高度值
  32782. *
  32783. * @example
  32784. * ```js
  32785. * rect.setHeight(200);
  32786. * ```
  32787. */
  32788. setHeight: function(height) {
  32789. this.height = height;
  32790. return this.update();
  32791. },
  32792. /**
  32793. * @method setSize
  32794. * @for kity.Rect
  32795. * @grammar setSize(width, height) => kity.Rect
  32796. * @description 设置矩形的尺寸,设置后返回矩形本身
  32797. * @param {Number} width 矩形的宽度值
  32798. * @param {Number} height 矩形的高度值
  32799. *
  32800. * @example
  32801. * ```js
  32802. * rect.setSize(300, 200);
  32803. * ```
  32804. */
  32805. setSize: function(width, height) {
  32806. this.width = width;
  32807. this.height = height;
  32808. return this.update();
  32809. },
  32810. /**
  32811. * @method setBox
  32812. * @for kity.Rect
  32813. * @grammar setBox(box) => kity.Rect
  32814. * @description 使用一个 kity 的盒子数据,
  32815. * @param {kity.Box} box 盒子数据
  32816. */
  32817. setBox: function(box) {
  32818. this.x = box.x;
  32819. this.y = box.y;
  32820. this.width = box.width;
  32821. this.height = box.height;
  32822. return this.update();
  32823. },
  32824. getBox: function() {
  32825. return new Box(this.x, this.y, this.width, this.height);
  32826. },
  32827. getRadius: function() {
  32828. return this.radius;
  32829. },
  32830. setRadius: function(radius) {
  32831. this.radius = RectUtils.formatRadius(this.width, this.height, radius || 0);
  32832. return this.update();
  32833. },
  32834. getPosition: function() {
  32835. return new Point(this.x, this.y);
  32836. },
  32837. setPosition: function(x, y) {
  32838. if (arguments.length == 1) {
  32839. var p = Point.parse(arguments[0]);
  32840. y = p.y;
  32841. x = p.x;
  32842. }
  32843. this.x = x;
  32844. this.y = y;
  32845. return this.update();
  32846. },
  32847. getWidth: function() {
  32848. return this.width;
  32849. },
  32850. getHeight: function() {
  32851. return this.height;
  32852. },
  32853. getPositionX: function() {
  32854. return this.x;
  32855. },
  32856. getPositionY: function() {
  32857. return this.y;
  32858. },
  32859. setPositionX: function(x) {
  32860. this.x = x;
  32861. return this.update();
  32862. },
  32863. setPositionY: function(y) {
  32864. this.y = y;
  32865. return this.update();
  32866. }
  32867. });
  32868. return Rect;
  32869. }
  32870. };
  32871. //src/graphic/regularpolygon.js
  32872. _p[57] = {
  32873. value: function(require, exports, module) {
  32874. var Point = _p.r(50);
  32875. return _p.r(11).createClass("RegularPolygon", {
  32876. base: _p.r(46),
  32877. constructor: function(side, radius, x, y) {
  32878. this.callBase();
  32879. this.radius = radius || 0;
  32880. this.side = Math.max(side || 3, 3);
  32881. if (arguments.length > 2) {
  32882. if (arguments.length == 3) {
  32883. y = x.y;
  32884. x = x.x;
  32885. }
  32886. }
  32887. this.center = new Point(x, y);
  32888. this.draw();
  32889. },
  32890. getSide: function() {
  32891. return this.side;
  32892. },
  32893. setSide: function(side) {
  32894. this.side = side;
  32895. return this.draw();
  32896. },
  32897. getRadius: function() {
  32898. return this.radius;
  32899. },
  32900. setRadius: function(radius) {
  32901. this.radius = radius;
  32902. return this.draw();
  32903. },
  32904. draw: function() {
  32905. var radius = this.radius, side = this.side, step = Math.PI * 2 / side, drawer = this.getDrawer(), i;
  32906. drawer.clear();
  32907. drawer.moveTo(Point.fromPolar(radius, Math.PI / 2, "rad").offset(this.center));
  32908. for (i = 0; i <= side; i++) {
  32909. drawer.lineTo(Point.fromPolar(radius, step * i + Math.PI / 2, "rad").offset(this.center));
  32910. }
  32911. drawer.close();
  32912. return this;
  32913. }
  32914. });
  32915. }
  32916. };
  32917. //src/graphic/resource.js
  32918. /**
  32919. * @fileOverview
  32920. *
  32921. * 资源节点基类
  32922. *
  32923. * @author: techird
  32924. * @copyright: Baidu FEX, 2014
  32925. */
  32926. _p[58] = {
  32927. value: function(require, exports, module) {
  32928. var svg = _p.r(67);
  32929. return _p.r(11).createClass("Resource", {
  32930. constructor: function(nodeType, paper) {
  32931. this.callBase();
  32932. this.node = svg.createNode(nodeType);
  32933. if (paper) {
  32934. paper.addResource(this);
  32935. }
  32936. },
  32937. toString: function() {
  32938. return "url(#" + this.node.id + ")";
  32939. }
  32940. });
  32941. }
  32942. };
  32943. //src/graphic/ring.js
  32944. _p[59] = {
  32945. value: function(require, exports, module) {
  32946. return _p.r(11).createClass({
  32947. base: _p.r(68),
  32948. constructor: function(innerRadius, outerRadius) {
  32949. this.callBase([ innerRadius, outerRadius ], 360, 0);
  32950. },
  32951. getInnerRadius: function() {
  32952. return this.getSectionArray()[0];
  32953. },
  32954. getOuterRadius: function() {
  32955. return this.getSectionArray()[1];
  32956. },
  32957. setInnerRadius: function(value) {
  32958. this.setSectionArray([ value, this.getOuterRadius() ]);
  32959. },
  32960. setOuterRadius: function(value) {
  32961. this.setSectionArray([ this.getInnerRadius(), value ]);
  32962. }
  32963. });
  32964. }
  32965. };
  32966. //src/graphic/shape.js
  32967. _p[60] = {
  32968. value: function(require, exports, module) {
  32969. var svg = _p.r(67);
  32970. var utils = _p.r(12);
  32971. var EventHandler = _p.r(33);
  32972. var Styled = _p.r(66);
  32973. var Data = _p.r(31);
  32974. var Matrix = _p.r(43);
  32975. var Pen = _p.r(48);
  32976. var slice = Array.prototype.slice;
  32977. var Box = _p.r(25);
  32978. var Shape = _p.r(11).createClass("Shape", {
  32979. mixins: [ EventHandler, Styled, Data ],
  32980. constructor: function Shape(tagName) {
  32981. this.node = svg.createNode(tagName);
  32982. this.node.shape = this;
  32983. this.transform = {
  32984. translate: null,
  32985. rotate: null,
  32986. scale: null,
  32987. matrix: null
  32988. };
  32989. this.callMixin();
  32990. },
  32991. getId: function() {
  32992. return this.node.id;
  32993. },
  32994. setId: function(id) {
  32995. this.node.id = id;
  32996. return this;
  32997. },
  32998. getNode: function() {
  32999. return this.node;
  33000. },
  33001. getBoundaryBox: function() {
  33002. var box;
  33003. try {
  33004. box = this.node.getBBox();
  33005. } catch (e) {
  33006. box = {
  33007. x: this.node.clientLeft,
  33008. y: this.node.clientTop,
  33009. width: this.node.clientWidth,
  33010. height: this.node.clientHeight
  33011. };
  33012. }
  33013. return new Box(box);
  33014. },
  33015. getRenderBox: function(refer) {
  33016. var box = this.getBoundaryBox();
  33017. var matrix = this.getTransform(refer);
  33018. return matrix.transformBox(box);
  33019. },
  33020. getWidth: function() {
  33021. return this.getRenderBox().width;
  33022. },
  33023. getHeight: function() {
  33024. return this.getRenderBox().height;
  33025. },
  33026. getSize: function() {
  33027. var box = this.getRenderBox();
  33028. delete box.x;
  33029. delete box.y;
  33030. return box;
  33031. },
  33032. setOpacity: function(value) {
  33033. this.node.setAttribute("opacity", value);
  33034. return this;
  33035. },
  33036. getOpacity: function() {
  33037. var opacity = this.node.getAttribute("opacity");
  33038. return opacity ? +opacity : 1;
  33039. },
  33040. setVisible: function(value) {
  33041. if (value) {
  33042. this.node.removeAttribute("display");
  33043. } else {
  33044. this.node.setAttribute("display", "none");
  33045. }
  33046. return this;
  33047. },
  33048. getVisible: function() {
  33049. this.node.getAttribute("display");
  33050. },
  33051. hasAncestor: function(node) {
  33052. var parent = this.container;
  33053. while (parent) {
  33054. if (parent === node) {
  33055. return true;
  33056. }
  33057. parent = parent.container;
  33058. }
  33059. return false;
  33060. },
  33061. getTransform: function(refer) {
  33062. return Matrix.getCTM(this, refer);
  33063. },
  33064. clearTransform: function() {
  33065. this.node.removeAttribute("transform");
  33066. this.transform = {
  33067. translate: null,
  33068. rotate: null,
  33069. scale: null,
  33070. matrix: null
  33071. };
  33072. this.trigger("shapeupdate", {
  33073. type: "transform"
  33074. });
  33075. return this;
  33076. },
  33077. _applyTransform: function() {
  33078. var t = this.transform, result = [];
  33079. if (t.translate) {
  33080. result.push([ "translate(", t.translate, ")" ]);
  33081. }
  33082. if (t.rotate) {
  33083. result.push([ "rotate(", t.rotate, ")" ]);
  33084. }
  33085. if (t.scale) {
  33086. result.push([ "scale(", t.scale, ")" ]);
  33087. }
  33088. if (t.matrix) {
  33089. result.push([ "matrix(", t.matrix, ")" ]);
  33090. }
  33091. this.node.setAttribute("transform", utils.flatten(result).join(" "));
  33092. return this;
  33093. },
  33094. setMatrix: function(m) {
  33095. this.transform.matrix = m;
  33096. return this._applyTransform();
  33097. },
  33098. setTranslate: function(t) {
  33099. this.transform.translate = t !== null && slice.call(arguments) || null;
  33100. return this._applyTransform();
  33101. },
  33102. setRotate: function(r) {
  33103. this.transform.rotate = r !== null && slice.call(arguments) || null;
  33104. return this._applyTransform();
  33105. },
  33106. setScale: function(s) {
  33107. this.transform.scale = s !== null && slice.call(arguments) || null;
  33108. return this._applyTransform();
  33109. },
  33110. translate: function(dx, dy) {
  33111. var m = this.transform.matrix || new Matrix();
  33112. if (dy === undefined) {
  33113. dy = 0;
  33114. }
  33115. this.transform.matrix = m.translate(dx, dy);
  33116. return this._applyTransform();
  33117. },
  33118. rotate: function(deg) {
  33119. var m = this.transform.matrix || new Matrix();
  33120. this.transform.matrix = m.rotate(deg);
  33121. return this._applyTransform();
  33122. },
  33123. scale: function(sx, sy) {
  33124. var m = this.transform.matrix || new Matrix();
  33125. if (sy === undefined) {
  33126. sy = sx;
  33127. }
  33128. this.transform.matrix = m.scale(sx, sy);
  33129. return this._applyTransform();
  33130. },
  33131. skew: function(sx, sy) {
  33132. var m = this.transform.matrix || new Matrix();
  33133. if (sy === undefined) {
  33134. sy = sx;
  33135. }
  33136. this.transform.matrix = m.skew(sx, sy);
  33137. return this._applyTransform();
  33138. },
  33139. stroke: function(pen, width) {
  33140. if (pen && pen.stroke) {
  33141. pen.stroke(this);
  33142. } else if (pen) {
  33143. // 字符串或重写了 toString 的对象
  33144. this.node.setAttribute("stroke", pen.toString());
  33145. if (width) {
  33146. this.node.setAttribute("stroke-width", width);
  33147. }
  33148. } else if (pen === null) {
  33149. this.node.removeAttribute("stroe");
  33150. }
  33151. return this;
  33152. },
  33153. fill: function(brush) {
  33154. // 字符串或重写了 toString 的对象
  33155. if (brush) {
  33156. this.node.setAttribute("fill", brush.toString());
  33157. }
  33158. if (brush === null) {
  33159. this.node.removeAttribute("fill");
  33160. }
  33161. return this;
  33162. },
  33163. setAttr: function(a, v) {
  33164. var me = this;
  33165. if (utils.isObject(a)) {
  33166. utils.each(a, function(val, key) {
  33167. me.setAttr(key, val);
  33168. });
  33169. }
  33170. if (v === undefined || v === null || v === "") {
  33171. this.node.removeAttribute(a);
  33172. } else {
  33173. this.node.setAttribute(a, v);
  33174. }
  33175. return this;
  33176. },
  33177. getAttr: function(a) {
  33178. return this.node.getAttribute(a);
  33179. }
  33180. });
  33181. return Shape;
  33182. }
  33183. };
  33184. //src/graphic/shapecontainer.js
  33185. _p[61] = {
  33186. value: function(require, exports, module) {
  33187. var Container = _p.r(29);
  33188. var utils = _p.r(12);
  33189. var ShapeContainer = _p.r(11).createClass("ShapeContainer", {
  33190. base: Container,
  33191. isShapeContainer: true,
  33192. /* private */
  33193. handleAdd: function(shape, index) {
  33194. var parent = this.getShapeNode();
  33195. parent.insertBefore(shape.node, parent.childNodes[index] || null);
  33196. shape.trigger("add", {
  33197. container: this
  33198. });
  33199. if (shape.notifyTreeModification) {
  33200. shape.notifyTreeModification("treeadd", this);
  33201. }
  33202. },
  33203. /* private */
  33204. handleRemove: function(shape, index) {
  33205. var parent = this.getShapeNode();
  33206. parent.removeChild(shape.node);
  33207. shape.trigger("remove", {
  33208. container: this
  33209. });
  33210. if (shape.notifyTreeModification) {
  33211. shape.notifyTreeModification("treeremove", this);
  33212. }
  33213. },
  33214. /* private */
  33215. notifyTreeModification: function(type, container) {
  33216. this.eachItem(function(index, shape) {
  33217. if (shape.notifyTreeModification) {
  33218. shape.notifyTreeModification(type, container);
  33219. }
  33220. shape.trigger(type, {
  33221. container: container
  33222. });
  33223. });
  33224. },
  33225. /* public */
  33226. getShape: function(index) {
  33227. return this.getItem(index);
  33228. },
  33229. /* public */
  33230. addShape: function(shape, index) {
  33231. return this.addItem(shape, index);
  33232. },
  33233. put: function(shape) {
  33234. this.addShape(shape);
  33235. return shape;
  33236. },
  33237. appendShape: function(shape) {
  33238. return this.addShape(shape);
  33239. },
  33240. prependShape: function(shape) {
  33241. return this.addShape(shape, 0);
  33242. },
  33243. replaceShape: function(replacer, origin) {
  33244. var index = this.indexOf(origin);
  33245. if (index === -1) {
  33246. return;
  33247. }
  33248. this.removeShape(index);
  33249. this.addShape(replacer, index);
  33250. return this;
  33251. },
  33252. addShapeBefore: function(shape, refer) {
  33253. var index = this.indexOf(refer);
  33254. return this.addShape(shape, index);
  33255. },
  33256. addShapeAfter: function(shape, refer) {
  33257. var index = this.indexOf(refer);
  33258. return this.addShape(shape, index === -1 ? undefined : index + 1);
  33259. },
  33260. /* public */
  33261. addShapes: function(shapes) {
  33262. return this.addItems(shapes);
  33263. },
  33264. /* public */
  33265. removeShape: function(index) {
  33266. return this.removeItem(index);
  33267. },
  33268. getShapes: function() {
  33269. return this.getItems();
  33270. },
  33271. getShapesByType: function(name) {
  33272. var shapes = [];
  33273. function getShapes(shape) {
  33274. if (name.toLowerCase() == shape.getType().toLowerCase()) {
  33275. shapes.push(shape);
  33276. }
  33277. if (shape.isShapeContainer) {
  33278. utils.each(shape.getShapes(), function(n) {
  33279. getShapes(n);
  33280. });
  33281. }
  33282. }
  33283. getShapes(this);
  33284. return shapes;
  33285. },
  33286. /* public */
  33287. getShapeById: function(id) {
  33288. return this.getShapeNode().getElementById(id).shape;
  33289. },
  33290. arrangeShape: function(shape, index) {
  33291. return this.removeShape(shape).addShape(shape, index);
  33292. },
  33293. /* protected */
  33294. getShapeNode: function() {
  33295. return this.shapeNode || this.node;
  33296. }
  33297. });
  33298. var Shape = _p.r(60);
  33299. _p.r(11).extendClass(Shape, {
  33300. bringTo: function(index) {
  33301. this.container.arrangeShape(this, index);
  33302. return this;
  33303. },
  33304. bringFront: function() {
  33305. return this.bringTo(this.container.indexOf(this) + 1);
  33306. },
  33307. bringBack: function() {
  33308. return this.bringTo(this.container.indexOf(this) - 1);
  33309. },
  33310. bringTop: function() {
  33311. this.container.removeShape(this).addShape(this);
  33312. return this;
  33313. },
  33314. bringRear: function() {
  33315. return this.bringTo(0);
  33316. },
  33317. bringRefer: function(referShape, offset) {
  33318. if (referShape.container) {
  33319. if (this.remove) {
  33320. this.remove();
  33321. }
  33322. referShape.container.addShape(this, referShape.container.indexOf(referShape) + (offset || 0));
  33323. }
  33324. return this;
  33325. },
  33326. bringAbove: function(referShape) {
  33327. return this.bringRefer(referShape);
  33328. },
  33329. bringBelow: function(referShape) {
  33330. return this.bringRefer(referShape, 1);
  33331. },
  33332. replaceBy: function(newShape) {
  33333. if (this.container) {
  33334. newShape.bringAbove(this);
  33335. this.remove();
  33336. }
  33337. return this;
  33338. }
  33339. });
  33340. return ShapeContainer;
  33341. }
  33342. };
  33343. //src/graphic/shapeevent.js
  33344. /*
  33345. * 图形事件包装类
  33346. * */
  33347. _p[62] = {
  33348. value: function(require, exprots, module) {
  33349. var Matrix = _p.r(43), Utils = _p.r(12), Point = _p.r(50);
  33350. return _p.r(11).createClass("ShapeEvent", {
  33351. constructor: function(event) {
  33352. var target = null;
  33353. // dom 事件封装对象
  33354. if (!Utils.isObject(event.target)) {
  33355. this.type = event.type;
  33356. target = event.target;
  33357. // use标签有特殊属性, 需要区别对待
  33358. if (target.correspondingUseElement) {
  33359. target = target.correspondingUseElement;
  33360. }
  33361. this.originEvent = event;
  33362. this.targetShape = target.shape || target.paper || event.currentTarget && (event.currentTarget.shape || event.currentTarget.paper);
  33363. if (event._kityParam) {
  33364. Utils.extend(this, event._kityParam);
  33365. }
  33366. } else {
  33367. Utils.extend(this, event);
  33368. }
  33369. },
  33370. preventDefault: function() {
  33371. var evt = this.originEvent;
  33372. if (!evt) {
  33373. return true;
  33374. }
  33375. if (evt.preventDefault) {
  33376. evt.preventDefault();
  33377. return evt.cancelable;
  33378. } else {
  33379. evt.returnValue = false;
  33380. return true;
  33381. }
  33382. },
  33383. //当前鼠标事件在用户坐标系中点击的点的坐标位置
  33384. getPosition: function(refer, touchIndex) {
  33385. if (!this.originEvent) {
  33386. return null;
  33387. }
  33388. var eventClient = this.originEvent.touches ? this.originEvent.touches[touchIndex || 0] : this.originEvent;
  33389. var target = this.targetShape;
  33390. var targetNode = target.shapeNode || target.node;
  33391. var pScreen = new Point(eventClient && eventClient.clientX || 0, eventClient && eventClient.clientY || 0);
  33392. var pTarget = Matrix.transformPoint(pScreen, targetNode.getScreenCTM().inverse());
  33393. var pRefer = Matrix.getCTM(target, refer || "view").transformPoint(pTarget);
  33394. return pRefer;
  33395. },
  33396. stopPropagation: function() {
  33397. var evt = this.originEvent;
  33398. if (!evt) {
  33399. return true;
  33400. }
  33401. if (evt.stopPropagation) {
  33402. evt.stopPropagation();
  33403. } else {
  33404. evt.cancelBubble = false;
  33405. }
  33406. }
  33407. });
  33408. }
  33409. };
  33410. //src/graphic/shapepoint.js
  33411. /*
  33412. * 图形上的点抽象
  33413. */
  33414. _p[63] = {
  33415. value: function(require, exports, module) {
  33416. return _p.r(11).createClass("ShapePoint", {
  33417. base: _p.r(50),
  33418. constructor: function(px, py) {
  33419. this.callBase(px, py);
  33420. },
  33421. setX: function(x) {
  33422. return this.setPoint(x, this.y);
  33423. },
  33424. setY: function(y) {
  33425. return this.setPoint(this.x, y);
  33426. },
  33427. setPoint: function(x, y) {
  33428. this.x = x;
  33429. this.y = y;
  33430. this.update();
  33431. return this;
  33432. },
  33433. getPoint: function() {
  33434. return this;
  33435. },
  33436. update: function() {
  33437. if (this.container && this.container.update) {
  33438. this.container.update();
  33439. }
  33440. return this;
  33441. }
  33442. });
  33443. }
  33444. };
  33445. //src/graphic/standardcolor.js
  33446. /**
  33447. * 标准颜色映射
  33448. */
  33449. _p[64] = {
  33450. value: {
  33451. COLOR_STANDARD: {
  33452. aliceblue: "#f0f8ff",
  33453. antiquewhite: "#faebd7",
  33454. aqua: "#00ffff",
  33455. aquamarine: "#7fffd4",
  33456. azure: "#f0ffff",
  33457. beige: "#f5f5dc",
  33458. bisque: "#ffe4c4",
  33459. black: "#000000",
  33460. blanchedalmond: "#ffebcd",
  33461. blue: "#0000ff",
  33462. blueviolet: "#8a2be2",
  33463. brown: "#a52a2a",
  33464. burlywood: "#deb887",
  33465. cadetblue: "#5f9ea0",
  33466. chartreuse: "#7fff00",
  33467. chocolate: "#d2691e",
  33468. coral: "#ff7f50",
  33469. cornflowerblue: "#6495ed",
  33470. cornsilk: "#fff8dc",
  33471. crimson: "#dc143c",
  33472. cyan: "#00ffff",
  33473. darkblue: "#00008b",
  33474. darkcyan: "#008b8b",
  33475. darkgoldenrod: "#b8860b",
  33476. darkgray: "#a9a9a9",
  33477. darkgreen: "#006400",
  33478. darkgrey: "#a9a9a9",
  33479. darkkhaki: "#bdb76b",
  33480. darkmagenta: "#8b008b",
  33481. darkolivegreen: "#556b2f",
  33482. darkorange: "#ff8c00",
  33483. darkorchid: "#9932cc",
  33484. darkred: "#8b0000",
  33485. darksalmon: "#e9967a",
  33486. darkseagreen: "#8fbc8f",
  33487. darkslateblue: "#483d8b",
  33488. darkslategray: "#2f4f4f",
  33489. darkslategrey: "#2f4f4f",
  33490. darkturquoise: "#00ced1",
  33491. darkviolet: "#9400d3",
  33492. deeppink: "#ff1493",
  33493. deepskyblue: "#00bfff",
  33494. dimgray: "#696969",
  33495. dimgrey: "#696969",
  33496. dodgerblue: "#1e90ff",
  33497. firebrick: "#b22222",
  33498. floralwhite: "#fffaf0",
  33499. forestgreen: "#228b22",
  33500. fuchsia: "#ff00ff",
  33501. gainsboro: "#dcdcdc",
  33502. ghostwhite: "#f8f8ff",
  33503. gold: "#ffd700",
  33504. goldenrod: "#daa520",
  33505. gray: "#808080",
  33506. green: "#008000",
  33507. greenyellow: "#adff2f",
  33508. grey: "#808080",
  33509. honeydew: "#f0fff0",
  33510. hotpink: "#ff69b4",
  33511. indianred: "#cd5c5c",
  33512. indigo: "#4b0082",
  33513. ivory: "#fffff0",
  33514. khaki: "#f0e68c",
  33515. lavender: "#e6e6fa",
  33516. lavenderblush: "#fff0f5",
  33517. lawngreen: "#7cfc00",
  33518. lemonchiffon: "#fffacd",
  33519. lightblue: "#add8e6",
  33520. lightcoral: "#f08080",
  33521. lightcyan: "#e0ffff",
  33522. lightgoldenrodyellow: "#fafad2",
  33523. lightgray: "#d3d3d3",
  33524. lightgreen: "#90ee90",
  33525. lightgrey: "#d3d3d3",
  33526. lightpink: "#ffb6c1",
  33527. lightsalmon: "#ffa07a",
  33528. lightseagreen: "#20b2aa",
  33529. lightskyblue: "#87cefa",
  33530. lightslategray: "#778899",
  33531. lightslategrey: "#778899",
  33532. lightsteelblue: "#b0c4de",
  33533. lightyellow: "#ffffe0",
  33534. lime: "#00ff00",
  33535. limegreen: "#32cd32",
  33536. linen: "#faf0e6",
  33537. magenta: "#ff00ff",
  33538. maroon: "#800000",
  33539. mediumaquamarine: "#66cdaa",
  33540. mediumblue: "#0000cd",
  33541. mediumorchid: "#ba55d3",
  33542. mediumpurple: "#9370db",
  33543. mediumseagreen: "#3cb371",
  33544. mediumslateblue: "#7b68ee",
  33545. mediumspringgreen: "#00fa9a",
  33546. mediumturquoise: "#48d1cc",
  33547. mediumvioletred: "#c71585",
  33548. midnightblue: "#191970",
  33549. mintcream: "#f5fffa",
  33550. mistyrose: "#ffe4e1",
  33551. moccasin: "#ffe4b5",
  33552. navajowhite: "#ffdead",
  33553. navy: "#000080",
  33554. oldlace: "#fdf5e6",
  33555. olive: "#808000",
  33556. olivedrab: "#6b8e23",
  33557. orange: "#ffa500",
  33558. orangered: "#ff4500",
  33559. orchid: "#da70d6",
  33560. palegoldenrod: "#eee8aa",
  33561. palegreen: "#98fb98",
  33562. paleturquoise: "#afeeee",
  33563. palevioletred: "#db7093",
  33564. papayawhip: "#ffefd5",
  33565. peachpuff: "#ffdab9",
  33566. peru: "#cd853f",
  33567. pink: "#ffc0cb",
  33568. plum: "#dda0dd",
  33569. powderblue: "#b0e0e6",
  33570. purple: "#800080",
  33571. red: "#ff0000",
  33572. rosybrown: "#bc8f8f",
  33573. royalblue: "#4169e1",
  33574. saddlebrown: "#8b4513",
  33575. salmon: "#fa8072",
  33576. sandybrown: "#f4a460",
  33577. seagreen: "#2e8b57",
  33578. seashell: "#fff5ee",
  33579. sienna: "#a0522d",
  33580. silver: "#c0c0c0",
  33581. skyblue: "#87ceeb",
  33582. slateblue: "#6a5acd",
  33583. slategray: "#708090",
  33584. slategrey: "#708090",
  33585. snow: "#fffafa",
  33586. springgreen: "#00ff7f",
  33587. steelblue: "#4682b4",
  33588. tan: "#d2b48c",
  33589. teal: "#008080",
  33590. thistle: "#d8bfd8",
  33591. tomato: "#ff6347",
  33592. turquoise: "#40e0d0",
  33593. violet: "#ee82ee",
  33594. wheat: "#f5deb3",
  33595. white: "#ffffff",
  33596. whitesmoke: "#f5f5f5",
  33597. yellow: "#ffff00"
  33598. },
  33599. //标准扩展
  33600. EXTEND_STANDARD: {}
  33601. }
  33602. };
  33603. //src/graphic/star.js
  33604. _p[65] = {
  33605. value: function(require, exports, module) {
  33606. /**
  33607. * @see http://www.jdawiseman.com/papers/easymath/surds_star_inner_radius.html
  33608. */
  33609. var defaultRatioForStar = {
  33610. "3": .2,
  33611. // yy
  33612. "5": .38196601125,
  33613. "6": .57735026919,
  33614. "8": .541196100146,
  33615. "10": .726542528005,
  33616. "12": .707106781187
  33617. };
  33618. var Point = _p.r(50);
  33619. return _p.r(11).createClass("Star", {
  33620. base: _p.r(46),
  33621. constructor: function(vertex, radius, shrink, offset, angleOffset) {
  33622. this.callBase();
  33623. this.vertex = vertex || 3;
  33624. this.radius = radius || 0;
  33625. this.shrink = shrink;
  33626. this.offset = offset || new Point(0, 0);
  33627. this.angleOffset = angleOffset || 0;
  33628. this.draw();
  33629. },
  33630. getVertex: function() {
  33631. return this.vertex;
  33632. },
  33633. setVertex: function(value) {
  33634. this.vertex = value;
  33635. return this.draw();
  33636. },
  33637. getRadius: function() {
  33638. return this.radius;
  33639. },
  33640. setRadius: function(value) {
  33641. this.radius = value;
  33642. return this.draw();
  33643. },
  33644. getShrink: function() {
  33645. return this.shrink;
  33646. },
  33647. setShrink: function(value) {
  33648. this.shrink = value;
  33649. return this.draw();
  33650. },
  33651. getOffset: function() {
  33652. return this.offset;
  33653. },
  33654. setOffset: function(value) {
  33655. this.offset = value;
  33656. return this.draw();
  33657. },
  33658. getAngleOffset: function() {
  33659. return this.angleOffset;
  33660. },
  33661. setAngleOffset: function(value) {
  33662. this.angleOffset = value;
  33663. return this.draw();
  33664. },
  33665. draw: function() {
  33666. var innerRadius = this.radius, outerRadius = this.radius * (this.shrink || defaultRatioForStar[this.vertex] || .5), vertex = this.vertex, offset = this.offset, angleStart = 90, angleStep = 180 / vertex, angleOffset = this.angleOffset, drawer = this.getDrawer(), i, angle;
  33667. drawer.clear();
  33668. drawer.moveTo(Point.fromPolar(outerRadius, angleStart));
  33669. for (i = 1; i <= vertex * 2; i++) {
  33670. angle = angleStart + angleStep * i;
  33671. // 绘制内点
  33672. if (i % 2) {
  33673. drawer.lineTo(Point.fromPolar(innerRadius, angle + angleOffset).offset(offset));
  33674. } else {
  33675. drawer.lineTo(Point.fromPolar(outerRadius, angle));
  33676. }
  33677. }
  33678. drawer.close();
  33679. }
  33680. });
  33681. }
  33682. };
  33683. //src/graphic/styled.js
  33684. _p[66] = {
  33685. value: function(require, exports, module) {
  33686. // polyfill for ie
  33687. var ClassList = _p.r(11).createClass("ClassList", {
  33688. constructor: function(node) {
  33689. this._node = node;
  33690. this._list = node.className.toString().split(" ");
  33691. },
  33692. _update: function() {
  33693. this._node.className = this._list.join(" ");
  33694. },
  33695. add: function(name) {
  33696. this._list.push(name);
  33697. this._update();
  33698. },
  33699. remove: function(name) {
  33700. var index = this._list.indexOf(name);
  33701. if (~index) {
  33702. this._list.splice(index, 1);
  33703. }
  33704. this._update();
  33705. },
  33706. contains: function(name) {
  33707. return !!~this._list.indexOf(name);
  33708. }
  33709. });
  33710. function getClassList(node) {
  33711. if (!node.classList) {
  33712. node.classList = new ClassList(node);
  33713. }
  33714. return node.classList;
  33715. }
  33716. return _p.r(11).createClass("Styled", {
  33717. addClass: function(name) {
  33718. getClassList(this.node).add(name);
  33719. return this;
  33720. },
  33721. removeClass: function(name) {
  33722. getClassList(this.node).remove(name);
  33723. return this;
  33724. },
  33725. hasClass: function(name) {
  33726. return getClassList(this.node).contains(name);
  33727. },
  33728. setStyle: function(styles) {
  33729. if (arguments.length == 2) {
  33730. this.node.style[arguments[0]] = arguments[1];
  33731. return this;
  33732. }
  33733. for (var name in styles) {
  33734. if (styles.hasOwnProperty(name)) {
  33735. this.node.style[name] = styles[name];
  33736. }
  33737. }
  33738. return this;
  33739. }
  33740. });
  33741. }
  33742. };
  33743. //src/graphic/svg.js
  33744. _p[67] = {
  33745. value: function(require, exports, module) {
  33746. var doc = document;
  33747. var id = 0;
  33748. var svg = {
  33749. createNode: function(name) {
  33750. var node = doc.createElementNS(svg.ns, name);
  33751. node.id = "kity_" + name + "_" + id++;
  33752. return node;
  33753. },
  33754. defaults: {
  33755. stroke: "none",
  33756. fill: "none"
  33757. },
  33758. xlink: "http://www.w3.org/1999/xlink",
  33759. ns: "http://www.w3.org/2000/svg"
  33760. };
  33761. return svg;
  33762. }
  33763. };
  33764. //src/graphic/sweep.js
  33765. _p[68] = {
  33766. value: function(require, exports, module) {
  33767. var Point = _p.r(50);
  33768. return _p.r(11).createClass("Sweep", {
  33769. base: _p.r(46),
  33770. constructor: function(sectionArray, angle, angleOffset) {
  33771. this.callBase();
  33772. this.sectionArray = sectionArray || [];
  33773. this.angle = angle || 0;
  33774. this.angleOffset = angleOffset || 0;
  33775. this.draw();
  33776. },
  33777. getSectionArray: function() {
  33778. return this.sectionArray;
  33779. },
  33780. setSectionArray: function(value) {
  33781. this.sectionArray = value;
  33782. return this.draw();
  33783. },
  33784. getAngle: function() {
  33785. return this.angle;
  33786. },
  33787. setAngle: function(value) {
  33788. this.angle = value;
  33789. return this.draw();
  33790. },
  33791. getAngleOffset: function() {
  33792. return this.angleOffset;
  33793. },
  33794. setAngleOffset: function(value) {
  33795. this.angleOffset = value;
  33796. return this.draw();
  33797. },
  33798. draw: function() {
  33799. var sectionArray = this.sectionArray, i;
  33800. for (i = 0; i < sectionArray.length; i += 2) {
  33801. this.drawSection(sectionArray[i], sectionArray[i + 1]);
  33802. }
  33803. return this;
  33804. },
  33805. drawSection: function(from, to) {
  33806. var angleLength = this.angle && (this.angle % 360 ? this.angle % 360 : 360), angleStart = this.angleOffset, angleHalf = angleStart + angleLength / 2, angleEnd = angleStart + angleLength, sweepFlag = angleLength < 0 ? 0 : 1, drawer = this.getDrawer();
  33807. drawer.redraw();
  33808. if (angleLength === 0) {
  33809. drawer.done();
  33810. return;
  33811. }
  33812. drawer.moveTo(Point.fromPolar(from, angleStart));
  33813. drawer.lineTo(Point.fromPolar(to, angleStart));
  33814. if (to) {
  33815. drawer.carcTo(to, 0, sweepFlag, Point.fromPolar(to, angleHalf));
  33816. drawer.carcTo(to, 0, sweepFlag, Point.fromPolar(to, angleEnd));
  33817. }
  33818. drawer.lineTo(Point.fromPolar(from, angleEnd));
  33819. if (from) {
  33820. drawer.carcTo(from, 0, sweepFlag, Point.fromPolar(from, angleHalf));
  33821. drawer.carcTo(from, 0, sweepFlag, Point.fromPolar(from, angleStart));
  33822. }
  33823. drawer.close();
  33824. drawer.done();
  33825. }
  33826. });
  33827. }
  33828. };
  33829. //src/graphic/text.js
  33830. _p[69] = {
  33831. value: function(require, exports, module) {
  33832. var TextContent = _p.r(70);
  33833. var ShapeContainer = _p.r(61);
  33834. var svg = _p.r(67);
  33835. var utils = _p.r(12);
  33836. var offsetHash = {};
  33837. function getTextBoundOffset(text) {
  33838. var font = text._cachedFontHash;
  33839. if (offsetHash[font]) {
  33840. return offsetHash[font];
  33841. }
  33842. var textContent = text.getContent();
  33843. text.setContent("百度Fex");
  33844. var bbox = text.getBoundaryBox(), y = text.getY();
  33845. var topOffset = y - bbox.y + +text.node.getAttribute("dy"), bottomOffset = topOffset - bbox.height;
  33846. text.setContent(textContent);
  33847. return offsetHash[font] = {
  33848. top: topOffset,
  33849. bottom: bottomOffset,
  33850. middle: (topOffset + bottomOffset) / 2
  33851. };
  33852. }
  33853. return _p.r(11).createClass("Text", {
  33854. base: TextContent,
  33855. mixins: [ ShapeContainer ],
  33856. constructor: function(content) {
  33857. this.callBase("text");
  33858. if (content !== undefined) {
  33859. this.setContent(content);
  33860. }
  33861. this._buildFontHash();
  33862. },
  33863. _buildFontHash: function() {
  33864. var style = window.getComputedStyle(this.node);
  33865. this._cachedFontHash = [ style.fontFamily, style.fontSize, style.fontStretch, style.fontStyle, style.fontVariant, style.fontWeight ].join("-");
  33866. },
  33867. _fontChanged: function(font) {
  33868. var last = this._lastFont;
  33869. var current = utils.extend({}, last, font);
  33870. if (!last) {
  33871. this._lastFont = font;
  33872. return true;
  33873. }
  33874. var changed = last.family != current.family || last.size != current.size || last.style != current.style || last.weight != current.weight;
  33875. this._lastFont = current;
  33876. return changed;
  33877. },
  33878. setX: function(x) {
  33879. this.node.setAttribute("x", x);
  33880. return this;
  33881. },
  33882. setPosition: function(x, y) {
  33883. return this.setX(x).setY(y);
  33884. },
  33885. setY: function(y) {
  33886. this.node.setAttribute("y", y);
  33887. return this;
  33888. },
  33889. getX: function() {
  33890. return +this.node.getAttribute("x") || 0;
  33891. },
  33892. getY: function() {
  33893. return +this.node.getAttribute("y") || 0;
  33894. },
  33895. setFont: function(font) {
  33896. this.callBase(font);
  33897. if (this._fontChanged(font)) {
  33898. this._buildFontHash();
  33899. this.setVerticalAlign(this.getVerticalAlign());
  33900. }
  33901. return this;
  33902. },
  33903. setTextAnchor: function(anchor) {
  33904. this.node.setAttribute("text-anchor", anchor);
  33905. return this;
  33906. },
  33907. getTextAnchor: function() {
  33908. return this.node.getAttribute("text-anchor") || "start";
  33909. },
  33910. // top/bottom/middle/baseline
  33911. setVerticalAlign: function(align) {
  33912. this.whenPaperReady(function() {
  33913. var dy;
  33914. switch (align) {
  33915. case "top":
  33916. dy = getTextBoundOffset(this).top;
  33917. break;
  33918. case "bottom":
  33919. dy = getTextBoundOffset(this).bottom;
  33920. break;
  33921. case "middle":
  33922. dy = getTextBoundOffset(this).middle;
  33923. break;
  33924. default:
  33925. dy = 0;
  33926. }
  33927. this.node.setAttribute("dy", dy);
  33928. });
  33929. this.verticalAlign = align;
  33930. return this;
  33931. },
  33932. getVerticalAlign: function() {
  33933. return this.verticalAlign || "baseline";
  33934. },
  33935. setStartOffset: function(offset) {
  33936. // only for text path
  33937. if (this.shapeNode != this.node) {
  33938. this.shapeNode.setAttribute("startOffset", offset * 100 + "%");
  33939. }
  33940. },
  33941. addSpan: function(span) {
  33942. this.addShape(span);
  33943. return this;
  33944. },
  33945. setPath: function(path) {
  33946. var textpath = this.shapeNode;
  33947. if (this.shapeNode == this.node) {
  33948. // 当前还不是 textpath
  33949. textpath = this.shapeNode = svg.createNode("textPath");
  33950. while (this.node.firstChild) {
  33951. this.shapeNode.appendChild(this.node.firstChild);
  33952. }
  33953. this.node.appendChild(textpath);
  33954. }
  33955. textpath.setAttributeNS(svg.xlink, "xlink:href", "#" + path.node.id);
  33956. this.setTextAnchor(this.getTextAnchor());
  33957. return this;
  33958. }
  33959. });
  33960. }
  33961. };
  33962. //src/graphic/textcontent.js
  33963. _p[70] = {
  33964. value: function(require, exports, module) {
  33965. var Shape = _p.r(60);
  33966. return _p.r(11).createClass("TextContent", {
  33967. base: Shape,
  33968. constructor: function(nodeType) {
  33969. // call shape constructor
  33970. this.callBase(nodeType);
  33971. this.shapeNode = this.shapeNode || this.node;
  33972. this.shapeNode.setAttribute("text-rendering", "geometricPrecision");
  33973. },
  33974. clearContent: function() {
  33975. while (this.shapeNode.firstChild) {
  33976. this.shapeNode.removeChild(this.shapeNode.firstChild);
  33977. }
  33978. return this;
  33979. },
  33980. setContent: function(content) {
  33981. this.shapeNode.textContent = content;
  33982. return this;
  33983. },
  33984. getContent: function() {
  33985. return this.shapeNode.textContent;
  33986. },
  33987. appendContent: function(content) {
  33988. this.shapeNode.textContent += content;
  33989. return this;
  33990. },
  33991. setSize: function(value) {
  33992. return this.setFontSize(value);
  33993. },
  33994. setFontSize: function(value) {
  33995. return this.setFont({
  33996. size: value
  33997. });
  33998. },
  33999. setFontFamily: function(value) {
  34000. return this.setFont({
  34001. family: value
  34002. });
  34003. },
  34004. setFontBold: function(bold) {
  34005. return this.setFont({
  34006. weight: bold ? "bold" : "normal"
  34007. });
  34008. },
  34009. setFontItalic: function(italic) {
  34010. return this.setFont({
  34011. style: italic ? "italic" : "normal"
  34012. });
  34013. },
  34014. setFont: function(font) {
  34015. var node = this.node;
  34016. [ "family", "size", "weight", "style" ].forEach(function(section) {
  34017. if (font[section] === null) {
  34018. node.removeAttribute("font-" + section);
  34019. } else if (font[section]) {
  34020. node.setAttribute("font-" + section, font[section]);
  34021. }
  34022. });
  34023. return this;
  34024. },
  34025. getExtentOfChar: function(index) {
  34026. return this.node.getExtentOfChar(index);
  34027. },
  34028. getRotationOfChar: function(index) {
  34029. return this.node.getRotationOfChar(index);
  34030. },
  34031. getCharNumAtPosition: function(x, y) {
  34032. return this.node.getCharNumAtPosition(this.node.viewportElement.createSVGPoint(x, y));
  34033. }
  34034. });
  34035. }
  34036. };
  34037. //src/graphic/textspan.js
  34038. _p[71] = {
  34039. value: function(require, exports, module) {
  34040. var TextContent = _p.r(70);
  34041. var Styled = _p.r(66);
  34042. return _p.r(11).createClass("TextSpan", {
  34043. base: TextContent,
  34044. mixins: [ Styled ],
  34045. constructor: function(content) {
  34046. this.callBase("tspan");
  34047. this.setContent(content);
  34048. }
  34049. });
  34050. }
  34051. };
  34052. //src/graphic/use.js
  34053. /*
  34054. * USE 功能
  34055. */
  34056. _p[72] = {
  34057. value: function(require, exports, module) {
  34058. var Svg = _p.r(67);
  34059. var Class = _p.r(11);
  34060. var Use = Class.createClass("Use", {
  34061. base: _p.r(60),
  34062. constructor: function(shape) {
  34063. this.callBase("use");
  34064. this.ref(shape);
  34065. },
  34066. ref: function(shape) {
  34067. if (!shape) {
  34068. this.node.removeAttributeNS(Svg.xlink, "xlink:href");
  34069. return this;
  34070. }
  34071. var shapeId = shape.getId();
  34072. if (shapeId) {
  34073. this.node.setAttributeNS(Svg.xlink, "xlink:href", "#" + shapeId);
  34074. }
  34075. // by techird
  34076. // 作为 Use 的图形,如果没有 fill 和 stroke,移除默认的 'none' 值,用于 Use 覆盖
  34077. if (shape.node.getAttribute("fill") === "none") {
  34078. shape.node.removeAttribute("fill");
  34079. }
  34080. if (shape.node.getAttribute("stroke") === "none") {
  34081. shape.node.removeAttribute("stroke");
  34082. }
  34083. return this;
  34084. }
  34085. });
  34086. var Shape = _p.r(60);
  34087. Class.extendClass(Shape, {
  34088. // fast-use
  34089. use: function() {
  34090. return new Use(this);
  34091. }
  34092. });
  34093. return Use;
  34094. }
  34095. };
  34096. //src/graphic/vector.js
  34097. _p[73] = {
  34098. value: function(require, exports, module) {
  34099. var Point = _p.r(50);
  34100. var Matrix = _p.r(43);
  34101. var Vector = _p.r(11).createClass("Vector", {
  34102. base: Point,
  34103. constructor: function(x, y) {
  34104. this.callBase(x, y);
  34105. },
  34106. square: function() {
  34107. return this.x * this.x + this.y * this.y;
  34108. },
  34109. length: function() {
  34110. return Math.sqrt(this.square());
  34111. },
  34112. add: function(q) {
  34113. return new Vector(this.x + q.x, this.y + q.y);
  34114. },
  34115. minus: function(q) {
  34116. return new Vector(this.x - q.x, this.y - q.y);
  34117. },
  34118. dot: function(q) {
  34119. return this.x * q.x + this.y * q.y;
  34120. },
  34121. project: function(q) {
  34122. return q.multipy(this.dot(q) / q.square());
  34123. },
  34124. normalize: function(length) {
  34125. if (length === undefined) {
  34126. length = 1;
  34127. }
  34128. return this.multipy(length / this.length());
  34129. },
  34130. multipy: function(scale) {
  34131. return new Vector(this.x * scale, this.y * scale);
  34132. },
  34133. rotate: function(angle, unit) {
  34134. if (unit == "rad") {
  34135. angle = angle / Math.PI * 180;
  34136. }
  34137. var p = new Matrix().rotate(angle).transformPoint(this);
  34138. return new Vector(p.x, p.y);
  34139. },
  34140. vertical: function() {
  34141. return new Vector(this.y, -this.x);
  34142. },
  34143. reverse: function() {
  34144. return this.multipy(-1);
  34145. },
  34146. getAngle: function() {
  34147. var length = this.length();
  34148. if (length === 0) return 0;
  34149. var rad = Math.acos(this.x / length);
  34150. var sign = this.y > 0 ? 1 : -1;
  34151. return sign * 180 * rad / Math.PI;
  34152. }
  34153. });
  34154. Vector.fromPoints = function(p1, p2) {
  34155. return new Vector(p2.x - p1.x, p2.y - p1.y);
  34156. };
  34157. Vector.fromPolar = function() {
  34158. var p = Point.fromPolar.apply(Point, arguments);
  34159. return new Vector(p.x, p.y);
  34160. };
  34161. _p.r(11).extendClass(Point, {
  34162. asVector: function() {
  34163. return new Vector(this.x, this.y);
  34164. }
  34165. });
  34166. return Vector;
  34167. }
  34168. };
  34169. //src/graphic/view.js
  34170. _p[74] = {
  34171. value: function(require, exports, module) {
  34172. var ShapeContainer = _p.r(61);
  34173. var ViewBox = _p.r(75);
  34174. return _p.r(11).createClass("View", {
  34175. mixins: [ ShapeContainer, ViewBox ],
  34176. base: _p.r(74),
  34177. constructor: function() {
  34178. this.callBase("view");
  34179. }
  34180. });
  34181. }
  34182. };
  34183. //src/graphic/viewbox.js
  34184. _p[75] = {
  34185. value: function(require, exports, module) {
  34186. return _p.r(11).createClass("ViewBox", {
  34187. getViewBox: function() {
  34188. var attr = this.node.getAttribute("viewBox");
  34189. if (attr === null) {
  34190. // firefox:
  34191. // 1. viewBox 没有设置过的时候获得的是 null
  34192. // 2. svg 标签没有指定绝对大小的时候 clientWidth 和 clientHeigt 为 0,需要在父容器上查找
  34193. // TODO: 第 2 条取得的不准确(假如有 padding 之类的)
  34194. return {
  34195. x: 0,
  34196. y: 0,
  34197. width: this.node.clientWidth || this.node.parentNode.clientWidth,
  34198. height: this.node.clientHeight || this.node.parentNode.clientHeight
  34199. };
  34200. } else {
  34201. attr = attr.split(" ");
  34202. return {
  34203. x: +attr[0],
  34204. y: +attr[1],
  34205. width: +attr[2],
  34206. height: +attr[3]
  34207. };
  34208. }
  34209. },
  34210. setViewBox: function(x, y, width, height) {
  34211. this.node.setAttribute("viewBox", [ x, y, width, height ].join(" "));
  34212. return this;
  34213. }
  34214. });
  34215. }
  34216. };
  34217. //src/kity.js
  34218. /**
  34219. * @fileOverview kity 暴露的方法或对象
  34220. */
  34221. _p[76] = {
  34222. value: function(require, exports, module) {
  34223. var kity = {}, utils = _p.r(12);
  34224. kity.version = "2.0.0";
  34225. utils.extend(kity, {
  34226. // core
  34227. createClass: _p.r(11).createClass,
  34228. extendClass: _p.r(11).extendClass,
  34229. Utils: utils,
  34230. Browser: _p.r(10),
  34231. // shape
  34232. Box: _p.r(25),
  34233. Bezier: _p.r(23),
  34234. BezierPoint: _p.r(24),
  34235. Circle: _p.r(26),
  34236. Clip: _p.r(27),
  34237. Color: _p.r(28),
  34238. Container: _p.r(29),
  34239. Curve: _p.r(30),
  34240. Ellipse: _p.r(32),
  34241. Group: _p.r(36),
  34242. Gradient: _p.r(35),
  34243. HyperLink: _p.r(37),
  34244. Image: _p.r(38),
  34245. Line: _p.r(39),
  34246. LinearGradient: _p.r(40),
  34247. Mask: _p.r(42),
  34248. Matrix: _p.r(43),
  34249. Marker: _p.r(41),
  34250. Palette: _p.r(44),
  34251. Paper: _p.r(45),
  34252. Path: _p.r(46),
  34253. Pattern: _p.r(47),
  34254. Pen: _p.r(48),
  34255. Point: _p.r(50),
  34256. PointContainer: _p.r(51),
  34257. Polygon: _p.r(53),
  34258. Polyline: _p.r(54),
  34259. Pie: _p.r(49),
  34260. RadialGradient: _p.r(55),
  34261. Resource: _p.r(58),
  34262. Rect: _p.r(56),
  34263. RegularPolygon: _p.r(57),
  34264. Ring: _p.r(59),
  34265. Shape: _p.r(60),
  34266. ShapePoint: _p.r(63),
  34267. ShapeContainer: _p.r(61),
  34268. Sweep: _p.r(68),
  34269. Star: _p.r(65),
  34270. Text: _p.r(69),
  34271. TextSpan: _p.r(71),
  34272. Use: _p.r(72),
  34273. Vector: _p.r(73),
  34274. g: _p.r(34),
  34275. // animate
  34276. Animator: _p.r(0),
  34277. Easing: _p.r(1),
  34278. OpacityAnimator: _p.r(4),
  34279. RotateAnimator: _p.r(6),
  34280. ScaleAnimator: _p.r(7),
  34281. Timeline: _p.r(8),
  34282. TranslateAnimator: _p.r(9),
  34283. PathAnimator: _p.r(5),
  34284. MotionAnimator: _p.r(3),
  34285. requestFrame: _p.r(2).requestFrame,
  34286. releaseFrame: _p.r(2).releaseFrame,
  34287. // filter
  34288. Filter: _p.r(20),
  34289. GaussianblurFilter: _p.r(21),
  34290. ProjectionFilter: _p.r(22),
  34291. // effect
  34292. ColorMatrixEffect: _p.r(13),
  34293. CompositeEffect: _p.r(14),
  34294. ConvolveMatrixEffect: _p.r(15),
  34295. Effect: _p.r(16),
  34296. GaussianblurEffect: _p.r(17),
  34297. OffsetEffect: _p.r(18)
  34298. });
  34299. return window.kity = kity;
  34300. }
  34301. };
  34302. var moduleMapping = {
  34303. kity: 76
  34304. };
  34305. function use(name) {
  34306. _p.r([ moduleMapping[name] ]);
  34307. }
  34308. /* global use, inc: true */
  34309. /**
  34310. * 模块暴露
  34311. */
  34312. use('kity');
  34313. })();
  34314. var KityMinder = window.KM = window.KityMinder = function() {
  34315. var instanceMap = {},
  34316. instanceId = 0,
  34317. uuidMap = {};
  34318. return {
  34319. version: '1.3.5',
  34320. uuid: function(name) {
  34321. name = name || 'unknown';
  34322. uuidMap[name] = uuidMap[name] || 0;
  34323. ++uuidMap[name];
  34324. return name + '_' + uuidMap[name];
  34325. },
  34326. createMinder: function(renderTarget, options) {
  34327. options = options || {};
  34328. options.renderTo = Utils.isString(renderTarget) ? document.getElementById(renderTarget) : renderTarget;
  34329. var minder = new Minder(options);
  34330. this.addMinder(options.renderTo, minder);
  34331. return minder;
  34332. },
  34333. addMinder: function(target, minder) {
  34334. var id;
  34335. if (typeof(target) === 'string') {
  34336. id = target;
  34337. } else {
  34338. id = target.id || ("KM_INSTANCE_" + instanceId++);
  34339. }
  34340. instanceMap[id] = minder;
  34341. },
  34342. getMinder: function(target, options) {
  34343. var id;
  34344. if (typeof(target) === 'string') {
  34345. id = target;
  34346. } else {
  34347. id = target.id || ("KM_INSTANCE_" + instanceId++);
  34348. }
  34349. return instanceMap[id] || this.createMinder(target, options);
  34350. },
  34351. //挂接多语言
  34352. LANG: {}
  34353. };
  34354. }();
  34355. var utils = Utils = KityMinder.Utils = {
  34356. extend: kity.Utils.extend.bind(kity.Utils),
  34357. listen: function(element, type, handler) {
  34358. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  34359. k = types.length;
  34360. if (k)
  34361. while (k--) {
  34362. type = types[k];
  34363. if (element.addEventListener) {
  34364. element.addEventListener(type, handler, false);
  34365. } else {
  34366. if (!handler._d) {
  34367. handler._d = {
  34368. els: []
  34369. };
  34370. }
  34371. var key = type + handler.toString(),
  34372. index = utils.indexOf(handler._d.els, element);
  34373. if (!handler._d[key] || index == -1) {
  34374. if (index == -1) {
  34375. handler._d.els.push(element);
  34376. }
  34377. if (!handler._d[key]) {
  34378. handler._d[key] = function(evt) {
  34379. return handler.call(evt.srcElement, evt || window.event);
  34380. };
  34381. }
  34382. element.attachEvent('on' + type, handler._d[key]);
  34383. }
  34384. }
  34385. }
  34386. element = null;
  34387. },
  34388. trim: function(str) {
  34389. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
  34390. },
  34391. each: function(obj, iterator, context) {
  34392. if (obj == null) return;
  34393. if (obj.length === +obj.length) {
  34394. for (var i = 0, l = obj.length; i < l; i++) {
  34395. if (iterator.call(context, i, obj[i], obj) === false)
  34396. return false;
  34397. }
  34398. } else {
  34399. for (var key in obj) {
  34400. if (obj.hasOwnProperty(key)) {
  34401. if (iterator.call(context, key, obj[key], obj) === false)
  34402. return false;
  34403. }
  34404. }
  34405. }
  34406. },
  34407. addCssRule: function(key, style, doc) {
  34408. var head, node;
  34409. if (style === undefined || style && style.nodeType && style.nodeType == 9) {
  34410. //获取样式
  34411. doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document);
  34412. node = doc.getElementById(key);
  34413. return node ? node.innerHTML : undefined;
  34414. }
  34415. doc = doc || document;
  34416. node = doc.getElementById(key);
  34417. //清除样式
  34418. if (style === '') {
  34419. if (node) {
  34420. node.parentNode.removeChild(node);
  34421. return true
  34422. }
  34423. return false;
  34424. }
  34425. //添加样式
  34426. if (node) {
  34427. node.innerHTML = style;
  34428. } else {
  34429. node = doc.createElement('style');
  34430. node.id = key;
  34431. node.innerHTML = style;
  34432. doc.getElementsByTagName('head')[0].appendChild(node);
  34433. }
  34434. },
  34435. keys: function(plain) {
  34436. var keys = [];
  34437. for (var key in plain) {
  34438. if (plain.hasOwnProperty(key)) {
  34439. keys.push(key);
  34440. }
  34441. }
  34442. return keys;
  34443. },
  34444. proxy: function(fn, context) {
  34445. return function() {
  34446. return fn.apply(context, arguments);
  34447. };
  34448. },
  34449. indexOf: function(array, item, start) {
  34450. var index = -1;
  34451. start = this.isNumber(start) ? start : 0;
  34452. this.each(array, function(v, i) {
  34453. if (i >= start && v === item) {
  34454. index = i;
  34455. return false;
  34456. }
  34457. });
  34458. return index;
  34459. },
  34460. argsToArray: function(args, index) {
  34461. return Array.prototype.slice.call(args, index || 0);
  34462. },
  34463. clonePlainObject: function(source, target) {
  34464. var tmp;
  34465. target = target || {};
  34466. for (var i in source) {
  34467. if (source.hasOwnProperty(i)) {
  34468. tmp = source[i];
  34469. if (utils.isObject(tmp) || utils.isArray(tmp)) {
  34470. target[i] = utils.isArray(tmp) ? [] : {};
  34471. utils.clonePlainObject(source[i], target[i])
  34472. } else {
  34473. target[i] = tmp;
  34474. }
  34475. }
  34476. }
  34477. return target;
  34478. },
  34479. compareObject: function(source, target) {
  34480. var tmp;
  34481. if (this.isEmptyObject(source) !== this.isEmptyObject(target)) {
  34482. return false
  34483. }
  34484. if (this.getObjectLength(source) != this.getObjectLength(target)) {
  34485. return false;
  34486. }
  34487. for (var p in source) {
  34488. if (source.hasOwnProperty(p)) {
  34489. tmp = source[p];
  34490. if (target[p] === undefined) {
  34491. return false;
  34492. }
  34493. if (this.isObject(tmp) || this.isArray(tmp)) {
  34494. if (this.isObject(target[p]) !== this.isObject(tmp)) {
  34495. return false;
  34496. }
  34497. if (this.isArray(tmp) !== this.isArray(target[p])) {
  34498. return false;
  34499. }
  34500. if (this.compareObject(tmp, target[p]) === false) {
  34501. return false
  34502. }
  34503. } else {
  34504. if (tmp != target[p]) {
  34505. return false
  34506. }
  34507. }
  34508. }
  34509. }
  34510. return true;
  34511. },
  34512. getObjectLength: function(obj) {
  34513. if (this.isArray(obj) || this.isString(obj)) return obj.length;
  34514. var count = 0;
  34515. for (var key in obj)
  34516. if (obj.hasOwnProperty(key)) count++;
  34517. return count;
  34518. },
  34519. isEmptyObject: function(obj) {
  34520. if (obj == null) return true;
  34521. if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
  34522. for (var key in obj)
  34523. if (obj.hasOwnProperty(key)) return false;
  34524. return true;
  34525. },
  34526. loadFile: function() {
  34527. var tmpList = [];
  34528. function getItem(doc, obj) {
  34529. try {
  34530. for (var i = 0, ci; ci = tmpList[i++];) {
  34531. if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
  34532. return ci;
  34533. }
  34534. }
  34535. } catch (e) {
  34536. return null;
  34537. }
  34538. }
  34539. return function(doc, obj, fn) {
  34540. var item = getItem(doc, obj);
  34541. if (item) {
  34542. if (item.ready) {
  34543. fn && fn();
  34544. } else {
  34545. item.funs.push(fn)
  34546. }
  34547. return;
  34548. }
  34549. tmpList.push({
  34550. doc: doc,
  34551. url: obj.src || obj.href,
  34552. funs: [fn]
  34553. });
  34554. if (!doc.body) {
  34555. var html = [];
  34556. for (var p in obj) {
  34557. if (p == 'tag') continue;
  34558. html.push(p + '="' + obj[p] + '"')
  34559. }
  34560. doc.write('<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>');
  34561. return;
  34562. }
  34563. if (obj.id && doc.getElementById(obj.id)) {
  34564. return;
  34565. }
  34566. var element = doc.createElement(obj.tag);
  34567. delete obj.tag;
  34568. for (var p in obj) {
  34569. element.setAttribute(p, obj[p]);
  34570. }
  34571. element.onload = element.onreadystatechange = function() {
  34572. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  34573. item = getItem(doc, obj);
  34574. if (item.funs.length > 0) {
  34575. item.ready = 1;
  34576. for (var fi; fi = item.funs.pop();) {
  34577. fi();
  34578. }
  34579. }
  34580. element.onload = element.onreadystatechange = null;
  34581. }
  34582. };
  34583. // element.onerror = function () {
  34584. // throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file ')
  34585. // };
  34586. doc.getElementsByTagName("head")[0].appendChild(element);
  34587. }
  34588. }(),
  34589. clone: function(source, target) {
  34590. var tmp;
  34591. target = target || {};
  34592. for (var i in source) {
  34593. if (source.hasOwnProperty(i)) {
  34594. tmp = source[i];
  34595. if (typeof tmp == 'object') {
  34596. target[i] = utils.isArray(tmp) ? [] : {};
  34597. utils.clone(source[i], target[i])
  34598. } else {
  34599. target[i] = tmp;
  34600. }
  34601. }
  34602. }
  34603. return target;
  34604. },
  34605. unhtml: function(str, reg) {
  34606. return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g, function(a, b) {
  34607. if (b) {
  34608. return a;
  34609. } else {
  34610. return {
  34611. '<': '&lt;',
  34612. '&': '&amp;',
  34613. '"': '&quot;',
  34614. '>': '&gt;',
  34615. "'": '&#39;'
  34616. }[a]
  34617. }
  34618. }) : '';
  34619. },
  34620. cloneArr:function(arr){
  34621. return [].concat(arr);
  34622. },
  34623. clearWhitespace:function(str){
  34624. return str.replace(/[\u200b\t\r\n]/g, '');
  34625. },
  34626. getValueByIndex:function(data,index){
  34627. var initIndex = 0,result = 0;
  34628. utils.each(data,function(i,arr){
  34629. if(initIndex + arr.length >= index){
  34630. if(index - initIndex == arr.length){
  34631. if(arr.length == 1 && arr[0].width === 0){
  34632. initIndex++;
  34633. return;
  34634. }
  34635. result = {
  34636. x: arr[arr.length - 1].x + arr[arr.length - 1].width,
  34637. y: arr[arr.length - 1].y
  34638. };
  34639. }else{
  34640. result = arr[index - initIndex];
  34641. }
  34642. return false;
  34643. }else{
  34644. initIndex += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
  34645. }
  34646. });
  34647. return result;
  34648. },
  34649. getNodeIndex:function (node, ignoreTextNode) {
  34650. var preNode = node,
  34651. i = 0;
  34652. while (preNode = preNode.previousSibling) {
  34653. if (ignoreTextNode && preNode.nodeType == 3) {
  34654. if(preNode.nodeType != preNode.nextSibling.nodeType ){
  34655. i++;
  34656. }
  34657. continue;
  34658. }
  34659. i++;
  34660. }
  34661. return i;
  34662. }
  34663. };
  34664. Utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object'], function(i, v) {
  34665. KityMinder.Utils['is' + v] = function(obj) {
  34666. return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
  34667. }
  34668. });
  34669. /**
  34670. * 提供浏览器检测的模块
  34671. * @unfile
  34672. * @module KM.browser
  34673. */
  34674. var browser = KityMinder.browser = function(){
  34675. var agent = navigator.userAgent.toLowerCase(),
  34676. opera = window.opera,
  34677. browser = {
  34678. /**
  34679. * @property {boolean} ie 检测当前浏览器是否为IE
  34680. * @example
  34681. * ```javascript
  34682. * if ( UE.browser.ie ) {
  34683. * console.log( '当前浏览器是IE' );
  34684. * }
  34685. * ```
  34686. */
  34687. ie : /(msie\s|trident.*rv:)([\w.]+)/.test(agent),
  34688. /**
  34689. * @property {boolean} opera 检测当前浏览器是否为Opera
  34690. * @example
  34691. * ```javascript
  34692. * if ( UE.browser.opera ) {
  34693. * console.log( '当前浏览器是Opera' );
  34694. * }
  34695. * ```
  34696. */
  34697. opera : ( !!opera && opera.version ),
  34698. /**
  34699. * @property {boolean} webkit 检测当前浏览器是否是webkit内核的浏览器
  34700. * @example
  34701. * ```javascript
  34702. * if ( UE.browser.webkit ) {
  34703. * console.log( '当前浏览器是webkit内核浏览器' );
  34704. * }
  34705. * ```
  34706. */
  34707. webkit : ( agent.indexOf( ' applewebkit/' ) > -1 ),
  34708. /**
  34709. * @property {boolean} mac 检测当前浏览器是否是运行在mac平台下
  34710. * @example
  34711. * ```javascript
  34712. * if ( UE.browser.mac ) {
  34713. * console.log( '当前浏览器运行在mac平台下' );
  34714. * }
  34715. * ```
  34716. */
  34717. mac : ( agent.indexOf( 'macintosh' ) > -1 ),
  34718. /**
  34719. * @property {boolean} quirks 检测当前浏览器是否处于“怪异模式”下
  34720. * @example
  34721. * ```javascript
  34722. * if ( UE.browser.quirks ) {
  34723. * console.log( '当前浏览器运行处于“怪异模式”' );
  34724. * }
  34725. * ```
  34726. */
  34727. quirks : ( document.compatMode == 'BackCompat' ),
  34728. ipad : ( agent.indexOf( 'ipad' ) > -1 )
  34729. };
  34730. /**
  34731. * @property {boolean} gecko 检测当前浏览器内核是否是gecko内核
  34732. * @example
  34733. * ```javascript
  34734. * if ( UE.browser.gecko ) {
  34735. * console.log( '当前浏览器内核是gecko内核' );
  34736. * }
  34737. * ```
  34738. */
  34739. browser.gecko =( navigator.product == 'Gecko' && !browser.webkit && !browser.opera && !browser.ie);
  34740. var version = 0;
  34741. // Internet Explorer 6.0+
  34742. if ( browser.ie ){
  34743. var v1 = agent.match(/(?:msie\s([\w.]+))/);
  34744. var v2 = agent.match(/(?:trident.*rv:([\w.]+))/);
  34745. if(v1 && v2 && v1[1] && v2[1]){
  34746. version = Math.max(v1[1]*1,v2[1]*1);
  34747. }else if(v1 && v1[1]){
  34748. version = v1[1]*1;
  34749. }else if(v2 && v2[1]){
  34750. version = v2[1]*1;
  34751. }else{
  34752. version = 0;
  34753. }
  34754. browser.ie11Compat = document.documentMode == 11;
  34755. /**
  34756. * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式
  34757. * @warning 如果浏览器不是IE, 则该值为undefined
  34758. * @example
  34759. * ```javascript
  34760. * if ( UE.browser.ie9Compat ) {
  34761. * console.log( '当前浏览器运行在IE9兼容模式下' );
  34762. * }
  34763. * ```
  34764. */
  34765. browser.ie9Compat = document.documentMode == 9;
  34766. /**
  34767. * @property { boolean } ie8 检测浏览器是否是IE8浏览器
  34768. * @warning 如果浏览器不是IE, 则该值为undefined
  34769. * @example
  34770. * ```javascript
  34771. * if ( UE.browser.ie8 ) {
  34772. * console.log( '当前浏览器是IE8浏览器' );
  34773. * }
  34774. * ```
  34775. */
  34776. browser.ie8 = !!document.documentMode;
  34777. /**
  34778. * @property { boolean } ie8Compat 检测浏览器模式是否为 IE8 兼容模式
  34779. * @warning 如果浏览器不是IE, 则该值为undefined
  34780. * @example
  34781. * ```javascript
  34782. * if ( UE.browser.ie8Compat ) {
  34783. * console.log( '当前浏览器运行在IE8兼容模式下' );
  34784. * }
  34785. * ```
  34786. */
  34787. browser.ie8Compat = document.documentMode == 8;
  34788. /**
  34789. * @property { boolean } ie7Compat 检测浏览器模式是否为 IE7 兼容模式
  34790. * @warning 如果浏览器不是IE, 则该值为undefined
  34791. * @example
  34792. * ```javascript
  34793. * if ( UE.browser.ie7Compat ) {
  34794. * console.log( '当前浏览器运行在IE7兼容模式下' );
  34795. * }
  34796. * ```
  34797. */
  34798. browser.ie7Compat = ( ( version == 7 && !document.documentMode )
  34799. || document.documentMode == 7 );
  34800. /**
  34801. * @property { boolean } ie6Compat 检测浏览器模式是否为 IE6 模式 或者怪异模式
  34802. * @warning 如果浏览器不是IE, 则该值为undefined
  34803. * @example
  34804. * ```javascript
  34805. * if ( UE.browser.ie6Compat ) {
  34806. * console.log( '当前浏览器运行在IE6模式或者怪异模式下' );
  34807. * }
  34808. * ```
  34809. */
  34810. browser.ie6Compat = ( version < 7 || browser.quirks );
  34811. browser.ie9above = version > 8;
  34812. browser.ie9below = version < 9;
  34813. }
  34814. // Gecko.
  34815. if ( browser.gecko ){
  34816. var geckoRelease = agent.match( /rv:([\d\.]+)/ );
  34817. if ( geckoRelease )
  34818. {
  34819. geckoRelease = geckoRelease[1].split( '.' );
  34820. version = geckoRelease[0] * 10000 + ( geckoRelease[1] || 0 ) * 100 + ( geckoRelease[2] || 0 ) * 1;
  34821. }
  34822. }
  34823. /**
  34824. * @property { Number } chrome 检测当前浏览器是否为Chrome, 如果是,则返回Chrome的大版本号
  34825. * @warning 如果浏览器不是chrome, 则该值为undefined
  34826. * @example
  34827. * ```javascript
  34828. * if ( UE.browser.chrome ) {
  34829. * console.log( '当前浏览器是Chrome' );
  34830. * }
  34831. * ```
  34832. */
  34833. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  34834. browser.chrome = + RegExp['\x241'];
  34835. }
  34836. /**
  34837. * @property { Number } safari 检测当前浏览器是否为Safari, 如果是,则返回Safari的大版本号
  34838. * @warning 如果浏览器不是safari, 则该值为undefined
  34839. * @example
  34840. * ```javascript
  34841. * if ( UE.browser.safari ) {
  34842. * console.log( '当前浏览器是Safari' );
  34843. * }
  34844. * ```
  34845. */
  34846. if(/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)){
  34847. browser.safari = + (RegExp['\x241'] || RegExp['\x242']);
  34848. }
  34849. // Opera 9.50+
  34850. if ( browser.opera )
  34851. version = parseFloat( opera.version() );
  34852. // WebKit 522+ (Safari 3+)
  34853. if ( browser.webkit )
  34854. version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[1] );
  34855. /**
  34856. * @property { Number } version 检测当前浏览器版本号
  34857. * @remind
  34858. * <ul>
  34859. * <li>IE系列返回值为5,6,7,8,9,10等</li>
  34860. * <li>gecko系列会返回10900,158900等</li>
  34861. * <li>webkit系列会返回其build号 (如 522等)</li>
  34862. * </ul>
  34863. * @example
  34864. * ```javascript
  34865. * console.log( '当前浏览器版本号是: ' + UE.browser.version );
  34866. * ```
  34867. */
  34868. browser.version = version;
  34869. /**
  34870. * @property { boolean } isCompatible 检测当前浏览器是否能够与UEditor良好兼容
  34871. * @example
  34872. * ```javascript
  34873. * if ( UE.browser.isCompatible ) {
  34874. * console.log( '浏览器与UEditor能够良好兼容' );
  34875. * }
  34876. * ```
  34877. */
  34878. browser.isCompatible =
  34879. !browser.mobile && (
  34880. ( browser.ie && version >= 6 ) ||
  34881. ( browser.gecko && version >= 10801 ) ||
  34882. ( browser.opera && version >= 9.5 ) ||
  34883. ( browser.air && version >= 1 ) ||
  34884. ( browser.webkit && version >= 522 ) ||
  34885. false );
  34886. return browser;
  34887. }();
  34888. //快捷方式
  34889. var ie = browser.ie,
  34890. webkit = browser.webkit,
  34891. gecko = browser.gecko,
  34892. opera = browser.opera;
  34893. /* jshint -W079 */
  34894. var Minder = KityMinder.Minder = kity.createClass('KityMinder', {
  34895. constructor: function(options) {
  34896. this._options = Utils.extend(window.KITYMINDER_CONFIG || {}, options);
  34897. var initQueue = Minder._initFnQueue.slice();
  34898. // @see option.js
  34899. // @see event.js
  34900. // @see status.js
  34901. // @see paper.js
  34902. // @see select.js
  34903. // @see key.js
  34904. // @see contextmenu.js
  34905. // @see module.js
  34906. // @see data.js
  34907. // @see readonly.js
  34908. // @see layout.js
  34909. // @see theme.js
  34910. while (initQueue.length) initQueue.shift().call(this, options);
  34911. this.fire('ready');
  34912. }
  34913. });
  34914. /* jshint +W079 */
  34915. Minder._initFnQueue = [];
  34916. Minder.registerInit = function(fn) {
  34917. Minder._initFnQueue.push(fn);
  34918. };
  34919. var Command = kity.createClass( "Command", {
  34920. constructor: function () {
  34921. this._isContentChange = true;
  34922. this._isSelectionChange = false;
  34923. },
  34924. execute: function ( minder, args ) {
  34925. },
  34926. setContentChanged: function ( val ) {
  34927. this._isContentChange = !! val;
  34928. },
  34929. isContentChanged: function () {
  34930. return this._isContentChange;
  34931. },
  34932. setSelectionChanged: function ( val ) {
  34933. this._isSelectionChange = !! val;
  34934. },
  34935. isSelectionChanged: function () {
  34936. return this._isContentChange;
  34937. },
  34938. queryState: function ( km ) {
  34939. return 0;
  34940. },
  34941. queryValue: function ( km ) {
  34942. return 0;
  34943. },
  34944. isNeedUndo: function () {
  34945. return true;
  34946. }
  34947. } );
  34948. kity.extendClass(Minder, {
  34949. _getCommand: function (name) {
  34950. return this._commands[name.toLowerCase()];
  34951. },
  34952. _queryCommand: function (name, type, args) {
  34953. var cmd = this._getCommand(name);
  34954. if (cmd) {
  34955. var queryCmd = cmd['query' + type];
  34956. if (queryCmd)
  34957. return queryCmd.apply(cmd, [this].concat(args));
  34958. }
  34959. return 0;
  34960. },
  34961. queryCommandState: function (name) {
  34962. return this._queryCommand(name, "State", Utils.argsToArray(1));
  34963. },
  34964. queryCommandValue: function (name) {
  34965. return this._queryCommand(name, "Value", Utils.argsToArray(1));
  34966. },
  34967. execCommand: function (name) {
  34968. name = name.toLowerCase();
  34969. var cmdArgs = Utils.argsToArray(arguments, 1),
  34970. cmd, stoped, result, eventParams;
  34971. var me = this;
  34972. cmd = this._getCommand(name);
  34973. eventParams = {
  34974. command: cmd,
  34975. commandName: name.toLowerCase(),
  34976. commandArgs: cmdArgs
  34977. };
  34978. if (!cmd || !~this.queryCommandState(name)) {
  34979. return false;
  34980. }
  34981. if (!this._hasEnterExecCommand && cmd.isNeedUndo()) {
  34982. this._hasEnterExecCommand = true;
  34983. stoped = this._fire(new MinderEvent('beforeExecCommand', eventParams, true));
  34984. if (!stoped) {
  34985. //保存场景
  34986. this._fire(new MinderEvent('saveScene'));
  34987. this._fire(new MinderEvent("preExecCommand", eventParams, false));
  34988. result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
  34989. this._fire(new MinderEvent('execCommand', eventParams, false));
  34990. //保存场景
  34991. this._fire(new MinderEvent('saveScene'));
  34992. if (cmd.isContentChanged()) {
  34993. this._firePharse(new MinderEvent('contentchange'));
  34994. }
  34995. this._interactChange();
  34996. }
  34997. this._hasEnterExecCommand = false;
  34998. } else {
  34999. result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
  35000. if (!this._hasEnterExecCommand) {
  35001. this._interactChange();
  35002. }
  35003. }
  35004. return result === undefined ? null : result;
  35005. }
  35006. });
  35007. /* jshint -W079 */
  35008. var MinderNode = KityMinder.MinderNode = kity.createClass('MinderNode', {
  35009. /* jshint +W079 */
  35010. /**
  35011. * 创建一个节点
  35012. *
  35013. * @param {KityMinder} minder
  35014. * 节点绑定的脑图的实例
  35015. *
  35016. * @param {String|Object} unknown
  35017. * 节点的初始数据或文本
  35018. */
  35019. constructor: function(unknown) {
  35020. this.parent = null;
  35021. this.root = this;
  35022. this.children = [];
  35023. this.data = {};
  35024. this.tmpData = {};
  35025. this.initContainers();
  35026. if (Utils.isString(unknown)) {
  35027. this.setText(unknown);
  35028. } else {
  35029. this.setData(unknown);
  35030. }
  35031. },
  35032. initContainers: function() {
  35033. this.rc = new kity.Group().setId(KityMinder.uuid('minder_node'));
  35034. this.rc.minderNode = this;
  35035. },
  35036. /**
  35037. * 判断节点是否根节点
  35038. */
  35039. isRoot: function() {
  35040. return this.root === this;
  35041. },
  35042. /**
  35043. * 判断节点是否叶子
  35044. */
  35045. isLeaf: function() {
  35046. return this.children.length === 0;
  35047. },
  35048. /**
  35049. * 获取节点的根节点
  35050. */
  35051. getRoot: function() {
  35052. return this.root || this;
  35053. },
  35054. /**
  35055. * 获得节点的父节点
  35056. */
  35057. getParent: function() {
  35058. return this.parent;
  35059. },
  35060. /**
  35061. * 获得节点的深度
  35062. */
  35063. getLevel: function() {
  35064. var level = 0,
  35065. parent = this.parent;
  35066. while (parent) {
  35067. level++;
  35068. parent = parent.parent;
  35069. }
  35070. return level;
  35071. },
  35072. /**
  35073. * 获得节点的复杂度(即子树中节点的数量)
  35074. */
  35075. getComplex: function() {
  35076. var complex = 0;
  35077. this.traverse(function() {
  35078. complex++;
  35079. });
  35080. return complex;
  35081. },
  35082. /**
  35083. * 获得节点的类型(root|main|sub)
  35084. */
  35085. getType: function(type) {
  35086. this.type = ['root', 'main', 'sub'][Math.min(this.getLevel(), 2)];
  35087. return this.type;
  35088. },
  35089. /**
  35090. * 判断当前节点是否被测试节点的祖先
  35091. * @param {MinderNode} test 被测试的节点
  35092. */
  35093. isAncestorOf: function(test) {
  35094. var p = test.parent;
  35095. while (p) {
  35096. if (p == this) return true;
  35097. p = p.parent;
  35098. }
  35099. return false;
  35100. },
  35101. /**
  35102. * 设置节点的文本数据
  35103. * @param {String} text 文本数据
  35104. */
  35105. setText: function(text) {
  35106. if(utils.isArray(text)){
  35107. text = text.join('\n');
  35108. }
  35109. return this.setData('text', text);
  35110. },
  35111. /**
  35112. * 获取节点的文本数据
  35113. * @return {String}
  35114. */
  35115. getText: function(str2arr) {
  35116. var text = this.getData('text') || '';
  35117. if(str2arr){
  35118. text = text.split('\n');
  35119. }
  35120. return text;
  35121. },
  35122. /**
  35123. * 先序遍历当前节点树
  35124. * @param {Function} fn 遍历函数
  35125. */
  35126. preTraverse: function(fn, excludeThis) {
  35127. var children = this.getChildren();
  35128. if (!excludeThis) fn(this);
  35129. for (var i = 0; i < children.length; i++) {
  35130. children[i].preTraverse(fn);
  35131. }
  35132. },
  35133. /**
  35134. * 后序遍历当前节点树
  35135. * @param {Function} fn 遍历函数
  35136. */
  35137. postTraverse: function(fn, excludeThis) {
  35138. var children = this.getChildren();
  35139. for (var i = 0; i < children.length; i++) {
  35140. children[i].postTraverse(fn);
  35141. }
  35142. if (!excludeThis) fn(this);
  35143. },
  35144. traverse: function(fn, excludeThis) {
  35145. return this.postTraverse(fn, excludeThis);
  35146. },
  35147. getChildren: function() {
  35148. return this.children;
  35149. },
  35150. getIndex: function() {
  35151. return this.parent ? this.parent.children.indexOf(this) : -1;
  35152. },
  35153. insertChild: function(node, index) {
  35154. if (index === undefined) {
  35155. index = this.children.length;
  35156. }
  35157. if (node.parent) {
  35158. node.parent.removeChild(node);
  35159. }
  35160. node.parent = this;
  35161. node.root = this.root;
  35162. this.children.splice(index, 0, node);
  35163. },
  35164. appendChild: function(node) {
  35165. return this.insertChild(node);
  35166. },
  35167. prependChild: function(node) {
  35168. return this.insertChild(node, 0);
  35169. },
  35170. removeChild: function(elem) {
  35171. var index = elem,
  35172. removed;
  35173. if (elem instanceof MinderNode) {
  35174. index = this.children.indexOf(elem);
  35175. }
  35176. if (index >= 0) {
  35177. removed = this.children.splice(index, 1)[0];
  35178. removed.parent = null;
  35179. removed.root = removed;
  35180. }
  35181. },
  35182. getChild: function(index) {
  35183. return this.children[index];
  35184. },
  35185. getFirstChild: function() {
  35186. return this.children[0];
  35187. },
  35188. getLastChild: function() {
  35189. return this.children[this.children.length - 1];
  35190. },
  35191. getData: function(name) {
  35192. if (name === undefined) {
  35193. return this.data;
  35194. }
  35195. return this.data[name];
  35196. },
  35197. setData: function(name, value) {
  35198. if (name === undefined) {
  35199. this.data = {};
  35200. } else if (utils.isObject(name)) {
  35201. Utils.extend(this.data, name);
  35202. } else {
  35203. if (value === undefined) {
  35204. this.data[name] = null;
  35205. delete this.data[name];
  35206. } else {
  35207. this.data[name] = value;
  35208. }
  35209. }
  35210. return this;
  35211. },
  35212. getRenderContainer: function() {
  35213. return this.rc;
  35214. },
  35215. getCommonAncestor: function(node) {
  35216. return Utils.getNodeCommonAncestor(this, node);
  35217. },
  35218. contains: function(node) {
  35219. return this == node || this.isAncestorOf(node);
  35220. },
  35221. clone: function() {
  35222. function cloneNode(parent, isClonedNode) {
  35223. var cloned = new KM.MinderNode();
  35224. cloned.data = Utils.clonePlainObject(isClonedNode.getData());
  35225. cloned.tmpData = Utils.clonePlainObject(isClonedNode.getTmpData());
  35226. if (parent) {
  35227. parent.appendChild(cloned);
  35228. }
  35229. for (var i = 0, ci;
  35230. (ci = isClonedNode.children[i++]);) {
  35231. cloneNode(cloned, ci);
  35232. }
  35233. return cloned;
  35234. }
  35235. return cloneNode(null, this);
  35236. },
  35237. equals: function(node,ignoreSelected) {
  35238. var me = this;
  35239. function restoreSelected(){
  35240. if(isSelectedA){
  35241. me.setSelectedFlag();
  35242. }
  35243. if(isSelectedB){
  35244. node.setSelectedFlag();
  35245. }
  35246. }
  35247. if(ignoreSelected){
  35248. var isSelectedA = false;
  35249. var isSelectedB = false;
  35250. if(me.isSelected()){
  35251. isSelectedA = true;
  35252. me.clearSelectedFlag();
  35253. }
  35254. if(node.isSelected()){
  35255. isSelectedB = true;
  35256. node.clearSelectedFlag();
  35257. }
  35258. }
  35259. if (node.children.length != this.children.length) {
  35260. restoreSelected();
  35261. return false;
  35262. }
  35263. if (utils.compareObject(node.getData(), me.getData()) === false) {
  35264. restoreSelected();
  35265. return false;
  35266. }
  35267. if (utils.compareObject(node.getTmpData(), me.getTmpData()) === false) {
  35268. restoreSelected();
  35269. return false;
  35270. }
  35271. for (var i = 0, ci;
  35272. (ci = me.children[i]); i++) {
  35273. if (ci.equals(node.children[i],ignoreSelected) === false) {
  35274. restoreSelected();
  35275. return false;
  35276. }
  35277. }
  35278. restoreSelected();
  35279. return true;
  35280. },
  35281. clearChildren: function() {
  35282. this.children = [];
  35283. },
  35284. setTmpData: function(a, v) {
  35285. var me = this;
  35286. if (utils.isObject(a)) {
  35287. utils.each(a, function(key, val) {
  35288. me.setTmpData(key, val);
  35289. });
  35290. }
  35291. if (v === undefined || v === null || v === '') {
  35292. delete this.tmpData[a];
  35293. } else {
  35294. this.tmpData[a] = v;
  35295. }
  35296. },
  35297. getTmpData: function(a) {
  35298. if (a === undefined) {
  35299. return this.tmpData;
  35300. }
  35301. return this.tmpData[a];
  35302. },
  35303. setValue: function(node) {
  35304. this.data = {};
  35305. this.setData(utils.clonePlainObject(node.getData()));
  35306. this.tmpData = {};
  35307. this.setTmpData(utils.clonePlainObject(node.getTmpData()));
  35308. return this;
  35309. }
  35310. });
  35311. MinderNode.getCommonAncestor = function(nodeA, nodeB) {
  35312. if (nodeA instanceof Array) {
  35313. return MinderNode.getCommonAncestor.apply(this, nodeA);
  35314. }
  35315. switch (arguments.length) {
  35316. case 1:
  35317. return nodeA.parent || nodeA;
  35318. case 2:
  35319. if (nodeA.isAncestorOf(nodeB)) {
  35320. return nodeA;
  35321. }
  35322. if (nodeB.isAncestorOf(nodeA)) {
  35323. return nodeB;
  35324. }
  35325. var ancestor = nodeA.parent;
  35326. while (ancestor && !ancestor.isAncestorOf(nodeB)) {
  35327. ancestor = ancestor.parent;
  35328. }
  35329. return ancestor;
  35330. default:
  35331. return Array.prototype.reduce.call(arguments, function(prev, current) {
  35332. return MinderNode.getCommonAncestor(prev, current);
  35333. }, nodeA);
  35334. }
  35335. };
  35336. kity.extendClass(Minder, {
  35337. getRoot: function() {
  35338. return this._root;
  35339. },
  35340. setRoot: function(root) {
  35341. this._root = root;
  35342. root.minder = this;
  35343. },
  35344. createNode: function(unknown, parent, index) {
  35345. var node = new MinderNode(unknown);
  35346. this.fire('nodecreate', { node: node, parent: parent, index: index });
  35347. this.appendNode(node, parent, index);
  35348. return node;
  35349. },
  35350. appendNode: function(node, parent, index) {
  35351. if (parent) parent.insertChild(node, index);
  35352. this.attachNode(node);
  35353. return this;
  35354. },
  35355. removeNode: function(node) {
  35356. if (node.parent) {
  35357. node.parent.removeChild(node);
  35358. this.detachNode(node);
  35359. this.fire('noderemove', { node: node });
  35360. }
  35361. },
  35362. attachNode: function(node) {
  35363. var rc = this._rc;
  35364. node.traverse(function(current) {
  35365. current.attached = true;
  35366. rc.addShape(current.getRenderContainer());
  35367. });
  35368. rc.addShape(node.getRenderContainer());
  35369. this.fire('nodeattach', {
  35370. node: node
  35371. });
  35372. },
  35373. detachNode: function(node) {
  35374. var rc = this._rc;
  35375. node.traverse(function(current) {
  35376. current.attached = false;
  35377. rc.removeShape(current.getRenderContainer());
  35378. });
  35379. this.fire('nodedetach', {
  35380. node: node
  35381. });
  35382. },
  35383. getMinderTitle: function() {
  35384. return this.getRoot().getText();
  35385. }
  35386. });
  35387. kity.extendClass(MinderNode, {
  35388. getMinder: function() {
  35389. return this.getRoot().minder;
  35390. }
  35391. });
  35392. /**
  35393. * @fileOverview
  35394. *
  35395. * 提供脑图选项支持
  35396. *
  35397. * @author: techird
  35398. * @copyright: Baidu FEX, 2014
  35399. */
  35400. kity.extendClass(Minder, {
  35401. getOptions: function(key) {
  35402. var val;
  35403. if (key) {
  35404. val = this.getPreferences(key);
  35405. return val && val[key] || this._options[key];
  35406. } else {
  35407. val = this.getPreferences();
  35408. return utils.extend(val, this._options, true);
  35409. }
  35410. },
  35411. setDefaultOptions: function(key, val, cover) {
  35412. var obj = {};
  35413. if (Utils.isString(key)) {
  35414. obj[key] = val;
  35415. } else {
  35416. obj = key;
  35417. }
  35418. utils.extend(this._options, obj, !cover);
  35419. },
  35420. setOptions: function(key, val) {
  35421. this.setPreferences(key, val);
  35422. }
  35423. });
  35424. Minder.registerInit(function(option) {
  35425. this.setDefaultOptions(KM.defaultOptions);
  35426. });
  35427. var MinderEvent = kity.createClass('MindEvent', {
  35428. constructor: function(type, params, canstop) {
  35429. params = params || {};
  35430. if (params.getType && params.getType() == 'ShapeEvent') {
  35431. this.kityEvent = params;
  35432. this.originEvent = params.originEvent;
  35433. this.getPosition = params.getPosition.bind(params);
  35434. } else if (params.target && params.preventDefault) {
  35435. this.originEvent = params;
  35436. } else {
  35437. kity.Utils.extend(this, params);
  35438. }
  35439. this.type = type;
  35440. this._canstop = canstop || false;
  35441. },
  35442. getTargetNode: function() {
  35443. var findShape = this.kityEvent && this.kityEvent.targetShape;
  35444. if (!findShape) return null;
  35445. while (!findShape.minderNode && findShape.container) {
  35446. findShape = findShape.container;
  35447. }
  35448. var node = findShape.minderNode;
  35449. if (node && findShape.getOpacity() < 1) return null;
  35450. return node || null;
  35451. },
  35452. stopPropagation: function() {
  35453. this._stoped = true;
  35454. },
  35455. stopPropagationImmediately: function() {
  35456. this._immediatelyStoped = true;
  35457. this._stoped = true;
  35458. },
  35459. shouldStopPropagation: function() {
  35460. return this._canstop && this._stoped;
  35461. },
  35462. shouldStopPropagationImmediately: function() {
  35463. return this._canstop && this._immediatelyStoped;
  35464. },
  35465. preventDefault: function() {
  35466. this.originEvent.preventDefault();
  35467. },
  35468. isRightMB: function() {
  35469. var isRightMB = false;
  35470. if (!this.originEvent) {
  35471. return false;
  35472. }
  35473. if ("which" in this.originEvent)
  35474. isRightMB = this.originEvent.which == 3;
  35475. else if ("button" in this.originEvent)
  35476. isRightMB = this.originEvent.button == 2;
  35477. return isRightMB;
  35478. },
  35479. getKeyCode: function(){
  35480. var evt = this.originEvent;
  35481. return evt.keyCode || evt.which;
  35482. }
  35483. });
  35484. Minder.registerInit(function() {
  35485. this._initEvents();
  35486. });
  35487. // 事件机制
  35488. kity.extendClass(Minder, {
  35489. _initEvents: function() {
  35490. this._eventCallbacks = {};
  35491. },
  35492. _bindEvents: function() {
  35493. this._bindPaperEvents();
  35494. this._bindKeyboardEvents();
  35495. },
  35496. _resetEvents: function() {
  35497. this._initEvents();
  35498. this._bindEvents();
  35499. },
  35500. // TODO: mousemove lazy bind
  35501. _bindPaperEvents: function() {
  35502. this._paper.on('click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', this._firePharse.bind(this));
  35503. if (window) {
  35504. window.addEventListener('resize', this._firePharse.bind(this));
  35505. window.addEventListener('blur', this._firePharse.bind(this));
  35506. }
  35507. },
  35508. _bindKeyboardEvents: function() {
  35509. if ((navigator.userAgent.indexOf('iPhone') == -1) && (navigator.userAgent.indexOf('iPod') == -1) && (navigator.userAgent.indexOf('iPad') == -1)) {
  35510. //只能在这里做,要不无法触发
  35511. Utils.listen(document.body, 'keydown keyup keypress paste', this._firePharse.bind(this));
  35512. }
  35513. },
  35514. _firePharse: function(e) {
  35515. // //只读模式下强了所有的事件操作
  35516. // if(this.readOnly === true){
  35517. // return false;
  35518. // }
  35519. var beforeEvent, preEvent, executeEvent;
  35520. if (e.type == 'DOMMouseScroll') {
  35521. e.type = 'mousewheel';
  35522. e.wheelDelta = e.originEvent.wheelDelta = e.originEvent.detail * -10;
  35523. e.wheelDeltaX = e.originEvent.mozMovementX;
  35524. e.wheelDeltaY = e.originEvent.mozMovementY;
  35525. }
  35526. beforeEvent = new MinderEvent('before' + e.type, e, true);
  35527. if (this._fire(beforeEvent)) {
  35528. return;
  35529. }
  35530. preEvent = new MinderEvent('pre' + e.type, e, true);
  35531. executeEvent = new MinderEvent(e.type, e, true);
  35532. if (this._fire(preEvent) ||
  35533. this._fire(executeEvent))
  35534. this._fire(new MinderEvent('after' + e.type, e, false));
  35535. },
  35536. _interactChange: function(e) {
  35537. var me = this;
  35538. if (me._interactScheduled) return;
  35539. setTimeout(function() {
  35540. me._fire(new MinderEvent('interactchange'));
  35541. me._interactScheduled = false;
  35542. }, 100);
  35543. me._interactScheduled = true;
  35544. },
  35545. _listen: function(type, callback) {
  35546. var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []);
  35547. callbacks.push(callback);
  35548. },
  35549. _fire: function(e) {
  35550. var status = this.getStatus();
  35551. var callbacks = this._eventCallbacks[e.type.toLowerCase()] || [];
  35552. if (status) {
  35553. callbacks = callbacks.concat(this._eventCallbacks[status + '.' + e.type.toLowerCase()] || []);
  35554. }
  35555. if (callbacks.length === 0) {
  35556. return;
  35557. }
  35558. var lastStatus = this.getStatus();
  35559. for (var i = 0; i < callbacks.length; i++) {
  35560. callbacks[i].call(this, e);
  35561. /* this.getStatus() != lastStatus ||*/
  35562. if (e.shouldStopPropagationImmediately()) {
  35563. break;
  35564. }
  35565. }
  35566. return e.shouldStopPropagation();
  35567. },
  35568. on: function(name, callback) {
  35569. var km = this;
  35570. utils.each(name.split(/\s+/), function(i, n) {
  35571. km._listen(n.toLowerCase(), callback);
  35572. });
  35573. return this;
  35574. },
  35575. off: function(name, callback) {
  35576. var types = name.split(/\s+/);
  35577. var i, j, callbacks, removeIndex;
  35578. for (i = 0; i < types.length; i++) {
  35579. callbacks = this._eventCallbacks[types[i].toLowerCase()];
  35580. if (callbacks) {
  35581. removeIndex = null;
  35582. for (j = 0; j < callbacks.length; j++) {
  35583. if (callbacks[j] == callback) {
  35584. removeIndex = j;
  35585. }
  35586. }
  35587. if (removeIndex !== null) {
  35588. callbacks.splice(removeIndex, 1);
  35589. }
  35590. }
  35591. }
  35592. },
  35593. fire: function(type, params) {
  35594. var e = new MinderEvent(type, params);
  35595. this._fire(e);
  35596. return this;
  35597. }
  35598. });
  35599. /**
  35600. * @fileOverview
  35601. *
  35602. * 状态切换控制
  35603. *
  35604. * @author: techird
  35605. * @copyright: Baidu FEX, 2014
  35606. */
  35607. Minder.registerInit(function() {
  35608. this._initStatus();
  35609. });
  35610. kity.extendClass(Minder, {
  35611. _initStatus: function() {
  35612. this._status = 'normal';
  35613. this._rollbackStatus = 'normal';
  35614. },
  35615. setStatus: (function() {
  35616. var sf = ~window.location.href.indexOf('status');
  35617. var tf = ~window.location.href.indexOf('trace');
  35618. // 在 readonly 模式下,只有 force 为 true 才能切换回来
  35619. return function(status, force) {
  35620. if (this._status == 'readonly' && !force) return this;
  35621. if (status != this._status) {
  35622. this._rollbackStatus = this._status;
  35623. this._status = status;
  35624. this.fire('statuschange', {
  35625. lastStatus: this._rollbackStatus,
  35626. currentStatus: this._status
  35627. });
  35628. if (sf) {
  35629. console.log(window.event.type, this._rollbackStatus, '->', this._status);
  35630. if (tf) {
  35631. console.trace();
  35632. }
  35633. }
  35634. }
  35635. return this;
  35636. };
  35637. })(),
  35638. rollbackStatus: function() {
  35639. this.setStatus(this._rollbackStatus);
  35640. },
  35641. getRollbackStatus:function(){
  35642. return this._rollbackStatus;
  35643. },
  35644. getStatus: function() {
  35645. return this._status;
  35646. }
  35647. });
  35648. /**
  35649. * @fileOverview
  35650. *
  35651. * 初始化渲染容器
  35652. *
  35653. * @author: techird
  35654. * @copyright: Baidu FEX, 2014
  35655. */
  35656. Minder.registerInit(function() {
  35657. this._initPaper();
  35658. });
  35659. kity.extendClass(Minder, {
  35660. _initPaper: function() {
  35661. this._paper = new kity.Paper();
  35662. this._paper.getNode().setAttribute('contenteditable', true);
  35663. this._paper.getNode().ondragstart = function(e) {
  35664. e.preventDefault();
  35665. };
  35666. this._paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
  35667. this._addRenderContainer();
  35668. this.setRoot(this.createNode(this.getLang().maintopic));
  35669. if (this._options.renderTo) {
  35670. this.renderTo(this._options.renderTo);
  35671. }
  35672. },
  35673. _addRenderContainer: function() {
  35674. this._rc = new kity.Group().setId(KityMinder.uuid('minder'));
  35675. this._paper.addShape(this._rc);
  35676. },
  35677. renderTo: function(target) {
  35678. this._paper.renderTo(this._renderTarget = target);
  35679. this._bindEvents();
  35680. },
  35681. getRenderContainer: function() {
  35682. return this._rc;
  35683. },
  35684. getPaper: function() {
  35685. return this._paper;
  35686. },
  35687. getRenderTarget: function() {
  35688. return this._renderTarget;
  35689. },
  35690. });
  35691. Minder.registerInit(function() {
  35692. this._initSelection();
  35693. });
  35694. // 选区管理
  35695. kity.extendClass(Minder, {
  35696. _initSelection: function() {
  35697. this._selectedNodes = [];
  35698. },
  35699. renderChangedSelection: function(last) {
  35700. var current = this.getSelectedNodes();
  35701. var changed = [];
  35702. var i = 0;
  35703. current.forEach(function(node) {
  35704. if (last.indexOf(node) == -1) {
  35705. changed.push(node);
  35706. node.setTmpData('selected', true);
  35707. }
  35708. });
  35709. last.forEach(function(node) {
  35710. if (current.indexOf(node) == -1) {
  35711. changed.push(node);
  35712. node.setTmpData('selected', false);
  35713. }
  35714. });
  35715. if (changed.length) {
  35716. this._interactChange();
  35717. this.fire('selectionchange');
  35718. }
  35719. while (i < changed.length) changed[i++].render();
  35720. },
  35721. getSelectedNodes: function() {
  35722. //不能克隆返回,会对当前选区操作,从而影响querycommand
  35723. return this._selectedNodes;
  35724. },
  35725. getSelectedNode: function() {
  35726. return this.getSelectedNodes()[0] || null;
  35727. },
  35728. removeAllSelectedNodes: function() {
  35729. var me = this;
  35730. var last = this._selectedNodes.splice(0);
  35731. this._selectedNodes = [];
  35732. this.renderChangedSelection(last);
  35733. return this.fire('selectionclear');
  35734. },
  35735. removeSelectedNodes: function(nodes) {
  35736. var me = this;
  35737. var last = this._selectedNodes.slice(0);
  35738. nodes = Utils.isArray(nodes) ? nodes : [nodes];
  35739. Utils.each(nodes, function(i, n) {
  35740. var index;
  35741. if ((index = me._selectedNodes.indexOf(n)) === -1) return;
  35742. me._selectedNodes.splice(index, 1);
  35743. });
  35744. this.renderChangedSelection(last);
  35745. return this;
  35746. },
  35747. select: function(nodes, isSingleSelect) {
  35748. var lastSelect = this.getSelectedNodes().slice(0);
  35749. if (isSingleSelect) {
  35750. this._selectedNodes = [];
  35751. }
  35752. var me = this;
  35753. nodes = Utils.isArray(nodes) ? nodes : [nodes];
  35754. Utils.each(nodes, function(i, n) {
  35755. if (me._selectedNodes.indexOf(n) !== -1) return;
  35756. me._selectedNodes.push(n);
  35757. });
  35758. this.renderChangedSelection(lastSelect);
  35759. return this;
  35760. },
  35761. //当前选区中的节点在给定的节点范围内的保留选中状态,
  35762. //没在给定范围的取消选中,给定范围中的但没在当前选中范围的也做选中效果
  35763. toggleSelect: function(node) {
  35764. if (Utils.isArray(node)) {
  35765. node.forEach(this.toggleSelect.bind(this));
  35766. } else {
  35767. if (node.isSelected()) this.removeSelectedNodes(node);
  35768. else this.select(node);
  35769. }
  35770. return this;
  35771. },
  35772. isSingleSelect: function() {
  35773. return this._selectedNodes.length == 1;
  35774. },
  35775. getSelectedAncestors: function(includeRoot) {
  35776. var nodes = this.getSelectedNodes().slice(0),
  35777. ancestors = [],
  35778. judge;
  35779. // 根节点不参与计算
  35780. var rootIndex = nodes.indexOf(this.getRoot());
  35781. if (~rootIndex && !includeRoot) {
  35782. nodes.splice(rootIndex, 1);
  35783. }
  35784. // 判断 nodes 列表中是否存在 judge 的祖先
  35785. function hasAncestor(nodes, judge) {
  35786. for (var i = nodes.length - 1; i >= 0; --i) {
  35787. if (nodes[i].isAncestorOf(judge)) return true;
  35788. }
  35789. return false;
  35790. }
  35791. // 按照拓扑排序
  35792. nodes.sort(function(node1, node2) {
  35793. return node1.getLevel() - node2.getLevel();
  35794. });
  35795. // 因为是拓扑有序的,所以只需往上查找
  35796. while ((judge = nodes.pop())) {
  35797. if (!hasAncestor(nodes, judge)) {
  35798. ancestors.push(judge);
  35799. }
  35800. }
  35801. return ancestors;
  35802. }
  35803. });
  35804. kity.extendClass(MinderNode, {
  35805. isSelected: function() {
  35806. return this.getTmpData('selected');
  35807. },
  35808. clearSelectedFlag:function(){
  35809. this.setTmpData('selected');
  35810. },
  35811. setSelectedFlag:function(){
  35812. this.setTmpData('selected',true);
  35813. }
  35814. });
  35815. /**
  35816. * @fileOverview
  35817. *
  35818. * 添加快捷键支持
  35819. *
  35820. * @author: techird
  35821. * @copyright: Baidu FEX, 2014
  35822. */
  35823. /**
  35824. * 计算包含 meta 键的 keycode
  35825. *
  35826. * @param {String|KeyEvent} unknown
  35827. */
  35828. function getMetaKeyCode(unknown) {
  35829. var CTRL_MASK = 0x1000;
  35830. var ALT_MASK = 0x2000;
  35831. var SHIFT_MASK = 0x4000;
  35832. var metaKeyCode = 0;
  35833. if (typeof(unknown) == 'string') {
  35834. // unknown as string
  35835. unknown.toLowerCase().split(/\+\s*/).forEach(function(name) {
  35836. switch(name) {
  35837. case 'ctrl':
  35838. case 'cmd':
  35839. metaKeyCode |= CTRL_MASK;
  35840. break;
  35841. case 'alt':
  35842. metaKeyCode |= ALT_MASK;
  35843. break;
  35844. case 'shift':
  35845. metaKeyCode |= SHIFT_MASK;
  35846. break;
  35847. default:
  35848. metaKeyCode |= keymap[name];
  35849. }
  35850. });
  35851. } else {
  35852. // unknown as key event
  35853. if (unknown.ctrlKey || unknown.metaKey) {
  35854. metaKeyCode |= CTRL_MASK;
  35855. }
  35856. if (unknown.altKey) {
  35857. metaKeyCode |= ALT_MASK;
  35858. }
  35859. if (unknown.shiftKey) {
  35860. metaKeyCode |= SHIFT_MASK;
  35861. }
  35862. metaKeyCode |= unknown.keyCode;
  35863. }
  35864. return metaKeyCode;
  35865. }
  35866. kity.extendClass(MinderEvent, {
  35867. isShortcutKey: function(keyCombine) {
  35868. var keyEvent = this.originEvent;
  35869. if (!keyEvent) return false;
  35870. return getMetaKeyCode(keyCombine) == getMetaKeyCode(keyEvent);
  35871. }
  35872. });
  35873. Minder.registerInit(function() {
  35874. this._initShortcutKey();
  35875. });
  35876. kity.extendClass(Minder, {
  35877. _initShortcutKey: function() {
  35878. this._bindShortcutKeys();
  35879. },
  35880. _bindShortcutKeys: function() {
  35881. var map = this._shortcutKeys = {};
  35882. var has = 'hasOwnProperty';
  35883. this.on('keydown', function(e) {
  35884. for (var keys in map) {
  35885. if (!map[has](keys)) continue;
  35886. if (e.isShortcutKey(keys)) {
  35887. var fn = map[keys];
  35888. if (fn.__statusCondition && fn.__statusCondition != this.getStatus()) return;
  35889. fn();
  35890. e.preventDefault();
  35891. }
  35892. }
  35893. });
  35894. },
  35895. addShortcut: function(keys, fn) {
  35896. var binds = this._shortcutKeys;
  35897. keys.split(/\|\s*/).forEach(function(combine) {
  35898. var parts = combine.split('::');
  35899. var status;
  35900. if (parts.length > 1) {
  35901. combine = parts[1];
  35902. status = parts[0];
  35903. fn.__statusCondition = status;
  35904. }
  35905. binds[combine] = fn;
  35906. });
  35907. },
  35908. addCommandShortcutKeys: function(cmd, keys) {
  35909. var binds = this._commandShortcutKeys || (this._commandShortcutKeys = {});
  35910. var obj = {},
  35911. km = this;
  35912. if (keys) {
  35913. obj[cmd] = keys;
  35914. } else {
  35915. obj = cmd;
  35916. }
  35917. var minder = this;
  35918. utils.each(obj, function(command, keys) {
  35919. binds[command] = keys;
  35920. minder.addShortcut(keys, function execCommandByShortcut() {
  35921. if (minder.queryCommandState(command) === 0) {
  35922. minder.execCommand(command);
  35923. }
  35924. });
  35925. });
  35926. },
  35927. getCommandShortcutKey: function(cmd) {
  35928. var binds = this._commandShortcutKeys;
  35929. return binds && binds[cmd] || null;
  35930. }
  35931. });
  35932. /**
  35933. * @fileOverview
  35934. *
  35935. * 添加模块上下文菜单支持
  35936. *
  35937. * @author: techird
  35938. * @copyright: Baidu FEX, 2014
  35939. */
  35940. Minder.registerInit(function() {
  35941. this._initContextMenu();
  35942. });
  35943. kity.extendClass(Minder, {
  35944. _initContextMenu: function() {
  35945. this.contextmenus = [];
  35946. },
  35947. addContextMenu: function(item) {
  35948. if (utils.isArray(item)) {
  35949. this.contextmenus = this.contextmenus.concat(item);
  35950. } else {
  35951. this.contextmenus.push(item);
  35952. }
  35953. return this;
  35954. },
  35955. getContextMenu: function() {
  35956. return this.contextmenus;
  35957. }
  35958. });
  35959. //模块注册&暴露模块接口
  35960. ( function () {
  35961. var _modules;
  35962. KityMinder.registerModule = function ( name, module ) {
  35963. //初始化模块列表
  35964. if ( !_modules ) {
  35965. _modules = {};
  35966. }
  35967. _modules[ name ] = module;
  35968. };
  35969. KityMinder.getModules = function () {
  35970. return _modules;
  35971. };
  35972. } )();
  35973. Minder.registerInit(function() {
  35974. this._initModules();
  35975. });
  35976. // 模块声明周期维护
  35977. kity.extendClass(Minder, {
  35978. _initModules: function() {
  35979. var modulesPool = KityMinder.getModules();
  35980. var modulesToLoad = this._options.modules || Utils.keys(modulesPool);
  35981. this._commands = {};
  35982. this._query = {};
  35983. this._modules = {};
  35984. this._rendererClasses = {};
  35985. var i, name, type, module, moduleDeals,
  35986. dealCommands, dealEvents, dealRenderers;
  35987. var me = this;
  35988. for (i = 0; i < modulesToLoad.length; i++) {
  35989. name = modulesToLoad[i];
  35990. if (!modulesPool[name]) continue;
  35991. // 执行模块初始化,抛出后续处理对象
  35992. if (typeof(modulesPool[name]) == 'function') {
  35993. moduleDeals = modulesPool[name].call(me);
  35994. } else {
  35995. moduleDeals = modulesPool[name];
  35996. }
  35997. this._modules[name] = moduleDeals;
  35998. if (!moduleDeals) continue;
  35999. if (moduleDeals.init) {
  36000. moduleDeals.init.call(me, this._options);
  36001. }
  36002. // command加入命令池子
  36003. dealCommands = moduleDeals.commands;
  36004. for (name in dealCommands) {
  36005. this._commands[name.toLowerCase()] = new dealCommands[name]();
  36006. }
  36007. // 绑定事件
  36008. dealEvents = moduleDeals.events;
  36009. if (dealEvents) {
  36010. for (type in dealEvents) {
  36011. me.on(type, dealEvents[type]);
  36012. }
  36013. }
  36014. // 渲染器
  36015. dealRenderers = moduleDeals.renderers;
  36016. if (dealRenderers) {
  36017. for (type in dealRenderers) {
  36018. this._rendererClasses[type] = this._rendererClasses[type] || [];
  36019. if (Utils.isArray(dealRenderers[type])) {
  36020. this._rendererClasses[type] = this._rendererClasses[type].concat(dealRenderers[type]);
  36021. } else {
  36022. this._rendererClasses[type].push(dealRenderers[type]);
  36023. }
  36024. }
  36025. }
  36026. if (moduleDeals.defaultOptions) {
  36027. this.setDefaultOptions(moduleDeals.defaultOptions);
  36028. }
  36029. //添加模块的快捷键
  36030. if (moduleDeals.commandShortcutKeys) {
  36031. this.addCommandShortcutKeys(moduleDeals.commandShortcutKeys);
  36032. }
  36033. //添加邮件菜单
  36034. if (moduleDeals.contextmenu) {
  36035. this.addContextMenu(moduleDeals.contextmenu);
  36036. }
  36037. }
  36038. },
  36039. _garbage: function() {
  36040. this.clearSelect();
  36041. while (this._root.getChildren().length) {
  36042. this._root.removeChild(0);
  36043. }
  36044. },
  36045. destroy: function() {
  36046. var modules = this._modules;
  36047. this._resetEvents();
  36048. this._garbage();
  36049. for (var key in modules) {
  36050. if (!modules[key].destroy) continue;
  36051. modules[key].destroy.call(this);
  36052. }
  36053. },
  36054. reset: function() {
  36055. var modules = this._modules;
  36056. this._garbage();
  36057. for (var key in modules) {
  36058. if (!modules[key].reset) continue;
  36059. modules[key].reset.call(this);
  36060. }
  36061. }
  36062. });
  36063. Utils.extend(KityMinder, {
  36064. _protocols: {},
  36065. registerProtocol: function(name, protocolDeal) {
  36066. KityMinder._protocols[name] = protocolDeal;
  36067. }
  36068. });
  36069. var DEFAULT_TEXT = {
  36070. 'root': 'maintopic',
  36071. 'main': 'topic',
  36072. 'sub': 'topic'
  36073. };
  36074. Minder.registerInit(function() {
  36075. this._initProtocols();
  36076. });
  36077. // 导入导出
  36078. kity.extendClass(Minder, {
  36079. _initProtocols: function(options) {
  36080. var protocols = this._protocols = {};
  36081. var pool = KityMinder._protocols;
  36082. for (var name in pool) {
  36083. if (pool.hasOwnProperty(name))
  36084. protocols[name] = pool[name](this);
  36085. protocols[name].name = name;
  36086. }
  36087. },
  36088. getProtocol: function(name) {
  36089. return this._protocols[name] || null;
  36090. },
  36091. getSupportedProtocols: function() {
  36092. var protocols = this._protocols;
  36093. return Utils.keys(protocols).map(function(name) {
  36094. return protocols[name];
  36095. });
  36096. },
  36097. exportJson: function() {
  36098. /* 导出 node 上整棵树的数据为 JSON */
  36099. function exportNode(node) {
  36100. var exported = {};
  36101. exported.data = node.getData();
  36102. var childNodes = node.getChildren();
  36103. if (childNodes.length) {
  36104. exported.children = [];
  36105. for (var i = 0; i < childNodes.length; i++) {
  36106. exported.children.push(exportNode(childNodes[i]));
  36107. }
  36108. }
  36109. return exported;
  36110. }
  36111. var json = exportNode(this.getRoot());
  36112. json.template = this.getTemplate();
  36113. json.theme = this.getTheme();
  36114. json.version = KityMinder.version;
  36115. return json;
  36116. },
  36117. importJson: function(json, params) {
  36118. function importNode(node, json, km) {
  36119. var data = json.data;
  36120. node.data = {};
  36121. for (var field in data) {
  36122. node.setData(field, data[field]);
  36123. }
  36124. node.setData('text', data.text || km.getLang(DEFAULT_TEXT[node.getType()]));
  36125. var childrenTreeData = json.children || [];
  36126. for (var i = 0; i < childrenTreeData.length; i++) {
  36127. var childNode = km.createNode(null, node);
  36128. importNode(childNode, childrenTreeData[i], km);
  36129. }
  36130. return node;
  36131. }
  36132. if (!json) return;
  36133. this._fire(new MinderEvent('preimport', params, false));
  36134. // 删除当前所有节点
  36135. while (this._root.getChildren().length) {
  36136. this.removeNode(this._root.getChildren()[0]);
  36137. }
  36138. json = KityMinder.compatibility(json);
  36139. importNode(this._root, json, this);
  36140. this.setTemplate(json.template || 'default');
  36141. this.setTheme(json.theme || null);
  36142. this.refresh();
  36143. this.fire('import', params);
  36144. this._firePharse({
  36145. type: 'contentchange'
  36146. });
  36147. this._interactChange();
  36148. },
  36149. exportData: function(protocolName, options) {
  36150. var json, protocol;
  36151. json = this.exportJson();
  36152. // 指定了协议进行导出,需要检测协议是否支持
  36153. if (protocolName) {
  36154. protocol = this.getProtocol(protocolName);
  36155. if (!protocol || !protocol.encode) {
  36156. return Promise.reject(new Error('Not supported protocol:' + protocolName));
  36157. }
  36158. }
  36159. // 导出前抛个事件
  36160. this._fire(new MinderEvent('beforeexport', {
  36161. json: json,
  36162. protocolName: protocolName,
  36163. protocol: protocol
  36164. }));
  36165. if (protocol) {
  36166. return Promise.resolve(protocol.encode(json, this, options));
  36167. } else {
  36168. return Promise.resolve(json);
  36169. }
  36170. },
  36171. importData: function(local, protocolName) {
  36172. var json, protocol;
  36173. var minder = this;
  36174. // 指定了协议进行导入,需要检测协议是否支持
  36175. if (protocolName) {
  36176. protocol = this.getProtocol(protocolName);
  36177. if (!protocol || !protocol.decode) {
  36178. return Promise.reject(new Error('Not supported protocol:' + protocolName));
  36179. }
  36180. }
  36181. var params = {
  36182. local: local,
  36183. protocolName: protocolName,
  36184. protocol: protocol
  36185. };
  36186. // 导入前抛事件
  36187. this._fire(new MinderEvent('beforeimport', params));
  36188. return new Promise(function(resolve, reject) {
  36189. resolve(protocol ? protocol.decode(local) : local);
  36190. }).then(function(json) {
  36191. minder.importJson(json, params);
  36192. return json;
  36193. });
  36194. }
  36195. });
  36196. /**
  36197. * @fileOverview
  36198. *
  36199. *
  36200. *
  36201. * @author: techird
  36202. * @copyright: Baidu FEX, 2014
  36203. */
  36204. Minder.registerInit(function(options) {
  36205. if (options.readOnly) {
  36206. this.setDisabled();
  36207. }
  36208. });
  36209. kity.extendClass(Minder, {
  36210. disable: function() {
  36211. var me = this;
  36212. //禁用命令
  36213. me.bkqueryCommandState = me.queryCommandState;
  36214. me.bkqueryCommandValue = me.queryCommandValue;
  36215. me.queryCommandState = function(type) {
  36216. var cmd = this._getCommand(type);
  36217. if (cmd && cmd.enableReadOnly) {
  36218. return me.bkqueryCommandState.apply(me, arguments);
  36219. }
  36220. return -1;
  36221. };
  36222. me.queryCommandValue = function(type) {
  36223. var cmd = this._getCommand(type);
  36224. if (cmd && cmd.enableReadOnly) {
  36225. return me.bkqueryCommandValue.apply(me, arguments);
  36226. }
  36227. return null;
  36228. };
  36229. this.setStatus('readonly');
  36230. me._interactChange();
  36231. },
  36232. enable: function() {
  36233. var me = this;
  36234. if (me.bkqueryCommandState) {
  36235. me.queryCommandState = me.bkqueryCommandState;
  36236. delete me.bkqueryCommandState;
  36237. }
  36238. if (me.bkqueryCommandValue) {
  36239. me.queryCommandValue = me.bkqueryCommandValue;
  36240. delete me.bkqueryCommandValue;
  36241. }
  36242. this.setStatus('normal');
  36243. me._interactChange();
  36244. }
  36245. });
  36246. /**
  36247. * 布局支持池子管理
  36248. */
  36249. Utils.extend(KityMinder, {
  36250. _layout: {},
  36251. registerLayout: function(name, layout) {
  36252. KityMinder._layout[name] = layout;
  36253. if (!KityMinder._defaultLayout) {
  36254. KityMinder._defaultLayout = name;
  36255. }
  36256. },
  36257. getLayoutList: function() {
  36258. return this._layout;
  36259. },
  36260. getLayoutInstance: function(name) {
  36261. var LayoutClass = KityMinder._layout[name];
  36262. if (!LayoutClass) throw new Error('Missing Layout: ' + name);
  36263. var layout = new LayoutClass();
  36264. return layout;
  36265. }
  36266. });
  36267. /**
  36268. * MinderNode 上的布局支持
  36269. */
  36270. kity.extendClass(MinderNode, {
  36271. /**
  36272. * 获得当前节点的布局名称
  36273. *
  36274. * @return {String}
  36275. */
  36276. getLayout: function() {
  36277. var layout = this.getData('layout');
  36278. layout = layout || (this.isRoot() ? KityMinder._defaultLayout : this.parent.getLayout());
  36279. return layout;
  36280. },
  36281. setLayout: function(name) {
  36282. if (name) {
  36283. if (name == 'inherit') {
  36284. this.setData('layout');
  36285. } else {
  36286. this.setData('layout', name);
  36287. }
  36288. }
  36289. return this;
  36290. },
  36291. layout: function(name, duration) {
  36292. this.setLayout(name).getMinder().layout(duration);
  36293. return this;
  36294. },
  36295. getLayoutInstance: function() {
  36296. return KityMinder.getLayoutInstance(this.getLayout());
  36297. },
  36298. getOrderHint: function(refer) {
  36299. return this.parent.getLayoutInstance().getOrderHint(this);
  36300. },
  36301. getExpandPosition: function() {
  36302. return this.getLayoutInstance().getExpandPosition();
  36303. },
  36304. /**
  36305. * 获取当前节点相对于父节点的布局变换
  36306. */
  36307. getLayoutTransform: function() {
  36308. return this._layoutTransform || new kity.Matrix();
  36309. },
  36310. /**
  36311. * 第一轮布局计算后,获得的全局布局位置
  36312. *
  36313. * @return {[type]} [description]
  36314. */
  36315. getGlobalLayoutTransformPreview: function() {
  36316. var pMatrix = this.parent ? this.parent.getLayoutTransform() : new kity.Matrix();
  36317. var matrix = this.getLayoutTransform();
  36318. var offset = this.getLayoutOffset();
  36319. if (offset) {
  36320. matrix.translate(offset.x, offset.y);
  36321. }
  36322. return pMatrix.merge(matrix);
  36323. },
  36324. getLayoutPointPreview: function() {
  36325. return this.getGlobalLayoutTransformPreview().transformPoint(new kity.Point());
  36326. },
  36327. /**
  36328. * 获取节点相对于全局的布局变换
  36329. */
  36330. getGlobalLayoutTransform: function() {
  36331. if (this._globalLayoutTransform) {
  36332. return this._globalLayoutTransform;
  36333. } else if (this.parent) {
  36334. return this.parent.getGlobalLayoutTransform();
  36335. } else {
  36336. return new kity.Matrix();
  36337. }
  36338. },
  36339. /**
  36340. * 设置当前节点相对于父节点的布局变换
  36341. */
  36342. setLayoutTransform: function(matrix) {
  36343. this._layoutTransform = matrix;
  36344. return this;
  36345. },
  36346. /**
  36347. * 设置当前节点相对于全局的布局变换(冗余优化)
  36348. */
  36349. setGlobalLayoutTransform: function(matrix) {
  36350. this.getRenderContainer().setMatrix(this._globalLayoutTransform = matrix);
  36351. return this;
  36352. },
  36353. setVertexIn: function(p) {
  36354. this._vertexIn = p;
  36355. },
  36356. setVertexOut: function(p) {
  36357. this._vertexOut = p;
  36358. },
  36359. getVertexIn: function() {
  36360. return this._vertexIn || new kity.Point();
  36361. },
  36362. getVertexOut: function() {
  36363. return this._vertexOut || new kity.Point();
  36364. },
  36365. getLayoutVertexIn: function() {
  36366. return this.getGlobalLayoutTransform().transformPoint(this.getVertexIn());
  36367. },
  36368. getLayoutVertexOut: function() {
  36369. return this.getGlobalLayoutTransform().transformPoint(this.getVertexOut());
  36370. },
  36371. setLayoutVectorIn: function(v) {
  36372. this._layoutVectorIn = v;
  36373. return this;
  36374. },
  36375. setLayoutVectorOut: function(v) {
  36376. this._layoutVectorOut = v;
  36377. return this;
  36378. },
  36379. getLayoutVectorIn: function() {
  36380. return this._layoutVectorIn || new kity.Vector();
  36381. },
  36382. getLayoutVectorOut: function() {
  36383. return this._layoutVectorOut || new kity.Vector();
  36384. },
  36385. getLayoutBox: function() {
  36386. var matrix = this.getGlobalLayoutTransform();
  36387. return matrix.transformBox(this.getContentBox());
  36388. },
  36389. getLayoutPoint: function() {
  36390. var matrix = this.getGlobalLayoutTransform();
  36391. return matrix.transformPoint(new kity.Point());
  36392. },
  36393. getLayoutOffset: function() {
  36394. if (!this.parent) return new kity.Point();
  36395. // 影响当前节点位置的是父节点的布局
  36396. var data = this.getData('layout_' + this.parent.getLayout() + '_offset');
  36397. if (data) return new kity.Point(data.x, data.y);
  36398. return new kity.Point();
  36399. },
  36400. setLayoutOffset: function(p) {
  36401. if (!this.parent) return this;
  36402. if (p && !this.hasLayoutOffset()) {
  36403. var m = this.getLayoutTransform().m;
  36404. p = p.offset(m.e, m.f);
  36405. this.setLayoutTransform(null);
  36406. }
  36407. this.setData('layout_' + this.parent.getLayout() + '_offset', p ? {
  36408. x: p.x,
  36409. y: p.y
  36410. } : null);
  36411. return this;
  36412. },
  36413. hasLayoutOffset: function() {
  36414. return !!this.getData('layout_' + this.parent.getLayout() + '_offset');
  36415. },
  36416. resetLayoutOffset: function() {
  36417. return this.setLayoutOffset(null);
  36418. },
  36419. getLayoutRoot: function() {
  36420. if (this.isLayoutRoot()) {
  36421. return this;
  36422. }
  36423. return this.parent.getLayoutRoot();
  36424. },
  36425. isLayoutRoot: function() {
  36426. return this.getData('layout') || this.isRoot();
  36427. }
  36428. });
  36429. Minder.registerInit(function(options) {
  36430. this.refresh();
  36431. });
  36432. kity.extendClass(Minder, {
  36433. layout: function(duration) {
  36434. this.getRoot().traverse(function(node) {
  36435. // clear last results
  36436. node.setLayoutTransform(null);
  36437. });
  36438. function layoutNode(node, round) {
  36439. // layout all children first
  36440. // 剪枝:收起的节点无需计算
  36441. if (node.isExpanded() || true) {
  36442. node.children.forEach(function(child) {
  36443. layoutNode(child, round);
  36444. });
  36445. }
  36446. var layout = node.getLayoutInstance();
  36447. var childrenInFlow = node.getChildren().filter(function(child) {
  36448. return !child.hasLayoutOffset();
  36449. });
  36450. layout.doLayout(node, childrenInFlow, round);
  36451. }
  36452. // 第一轮布局
  36453. layoutNode(this.getRoot(), 1);
  36454. // 第二轮布局
  36455. layoutNode(this.getRoot(), 2);
  36456. duration = duration ? 300 : 0;
  36457. var minder = this;
  36458. this.applyLayoutResult(this.getRoot(), duration).then(function() {
  36459. minder.fire('layoutallfinish');
  36460. });
  36461. return this.fire('layout');
  36462. },
  36463. refresh: function(duration) {
  36464. this.getRoot().renderTree();
  36465. this.layout(duration).fire('contentchange')._interactChange();
  36466. return this;
  36467. },
  36468. applyLayoutResult: function(root, duration) {
  36469. root = root || this.getRoot();
  36470. var me = this;
  36471. var deffered = {};
  36472. var promise = new Promise(function(resolve, reject) {
  36473. deffered.resolve = resolve;
  36474. deffered.reject = reject;
  36475. });
  36476. var complex = root.getComplex();
  36477. function consume() {
  36478. if (!--complex) {
  36479. deffered.resolve();
  36480. }
  36481. }
  36482. // 节点复杂度大于 100,关闭动画
  36483. if (complex > 200) duration = 0;
  36484. function applyMatrix(node, matrix) {
  36485. node.setGlobalLayoutTransform(matrix);
  36486. me.fire('layoutapply', {
  36487. node: node,
  36488. matrix: matrix
  36489. });
  36490. }
  36491. function apply(node, pMatrix) {
  36492. var matrix = node.getLayoutTransform().merge(pMatrix);
  36493. var lastMatrix = node.getGlobalLayoutTransform() || new kity.Matrix();
  36494. var offset = node.getLayoutOffset();
  36495. matrix.translate(offset.x, offset.y);
  36496. matrix.m.e = Math.round(matrix.m.e);
  36497. matrix.m.f = Math.round(matrix.m.f);
  36498. // 如果当前有动画,停止动画
  36499. if (node._layoutTimeline) {
  36500. node._layoutTimeline.stop();
  36501. node._layoutTimeline = null;
  36502. }
  36503. // 如果要求以动画形式来更新,创建动画
  36504. if (duration) {
  36505. node._layoutTimeline = new kity.Animator(lastMatrix, matrix, applyMatrix)
  36506. .start(node, duration, 'ease')
  36507. .on('finish', function() {
  36508. //可能性能低的时候会丢帧,手动添加一帧
  36509. setTimeout(function() {
  36510. applyMatrix(node, matrix);
  36511. me.fire('layoutfinish', {
  36512. node: node,
  36513. matrix: matrix
  36514. });
  36515. consume();
  36516. }, 150);
  36517. });
  36518. }
  36519. // 否则直接更新
  36520. else {
  36521. applyMatrix(node, matrix);
  36522. me.fire('layoutfinish', {
  36523. node: node,
  36524. matrix: matrix
  36525. });
  36526. consume();
  36527. }
  36528. for (var i = 0; i < node.children.length; i++) {
  36529. apply(node.children[i], matrix);
  36530. }
  36531. }
  36532. apply(root, root.parent ? root.parent.getGlobalLayoutTransform() : new kity.Matrix());
  36533. return promise;
  36534. },
  36535. });
  36536. /**
  36537. * @class Layout 布局基类,具体布局需要从该类派生
  36538. */
  36539. var Layout = kity.createClass('Layout', {
  36540. /**
  36541. * @abstract
  36542. *
  36543. * 子类需要实现的布局算法,该算法输入一个节点,排布该节点的子节点(相对父节点的变换)
  36544. *
  36545. * @param {MinderNode} node 需要布局的节点
  36546. *
  36547. * @example
  36548. *
  36549. * doLayout: function(node) {
  36550. * var children = node.getChildren();
  36551. * // layout calculation
  36552. * children[i].setLayoutTransform(new kity.Matrix().translate(x, y));
  36553. * }
  36554. */
  36555. doLayout: function(node) {
  36556. throw new Error('Not Implement: Layout.doLayout()');
  36557. },
  36558. /**
  36559. * 对齐指定的节点
  36560. *
  36561. * @param {Array<MinderNode>} nodes 要对齐的节点
  36562. * @param {string} border 对齐边界,允许取值 left, right, top, bottom
  36563. *
  36564. */
  36565. align: function(nodes, border, offset) {
  36566. var me = this;
  36567. offset = offset || 0;
  36568. nodes.forEach(function(node) {
  36569. var tbox = me.getTreeBox([node]);
  36570. var matrix = node.getLayoutTransform();
  36571. switch (border) {
  36572. case 'left':
  36573. return matrix.translate(offset - tbox.left, 0);
  36574. case 'right':
  36575. return matrix.translate(offset - tbox.right, 0);
  36576. case 'top':
  36577. return matrix.translate(0, offset - tbox.top);
  36578. case 'bottom':
  36579. return matrix.translate(0, offset - tbox.bottom);
  36580. }
  36581. });
  36582. },
  36583. stack: function(nodes, axis, distance) {
  36584. var me = this;
  36585. var position = 0;
  36586. distance = distance || function(node, next, axis) {
  36587. return node.getStyle({
  36588. x: 'margin-right',
  36589. y: 'margin-bottom'
  36590. }[axis]) + next.getStyle({
  36591. x: 'margin-left',
  36592. y: 'margin-top'
  36593. }[axis]);
  36594. };
  36595. nodes.forEach(function(node, index, nodes) {
  36596. var tbox = me.getTreeBox([node]);
  36597. var size = {
  36598. x: tbox.width,
  36599. y: tbox.height
  36600. }[axis];
  36601. var offset = {
  36602. x: tbox.left,
  36603. y: tbox.top
  36604. }[axis];
  36605. var matrix = node.getLayoutTransform();
  36606. if (axis == 'x') {
  36607. matrix.translate(position - offset, 0);
  36608. } else {
  36609. matrix.translate(0, position - offset);
  36610. }
  36611. position += size;
  36612. if (nodes[index + 1])
  36613. position += distance(node, nodes[index + 1], axis);
  36614. });
  36615. return position;
  36616. },
  36617. move: function(nodes, dx, dy) {
  36618. nodes.forEach(function(node) {
  36619. node.getLayoutTransform().translate(dx, dy);
  36620. });
  36621. },
  36622. /**
  36623. * 工具方法:获取给点的节点所占的布局区域
  36624. *
  36625. * @param {MinderNode[]} nodes 需要计算的节点
  36626. *
  36627. * @return {Box} 计算结果
  36628. */
  36629. getBranchBox: function(nodes) {
  36630. var box = new kity.Box();
  36631. var i, node, matrix, contentBox;
  36632. for (i = 0; i < nodes.length; i++) {
  36633. node = nodes[i];
  36634. matrix = node.getLayoutTransform();
  36635. contentBox = node.getContentBox();
  36636. box = box.merge(matrix.transformBox(contentBox));
  36637. }
  36638. return box;
  36639. },
  36640. /**
  36641. * 工具方法:计算给定的节点的子树所占的布局区域
  36642. *
  36643. * @param {MinderNode} nodes 需要计算的节点
  36644. *
  36645. * @return {Box} 计算的结果
  36646. */
  36647. getTreeBox: function(nodes) {
  36648. var i, node, matrix, treeBox;
  36649. var g = KityMinder.Geometry;
  36650. var box = {
  36651. x: 0,
  36652. y: 0,
  36653. height: 0,
  36654. width: 0
  36655. };
  36656. if (!(nodes instanceof Array)) nodes = [nodes];
  36657. for (i = 0; i < nodes.length; i++) {
  36658. node = nodes[i];
  36659. matrix = node.getLayoutTransform();
  36660. treeBox = node.getContentBox();
  36661. if (node.isExpanded() && node.children.length) {
  36662. treeBox = g.mergeBox(treeBox, this.getTreeBox(node.children));
  36663. }
  36664. box = g.mergeBox(box, matrix.transformBox(treeBox));
  36665. }
  36666. return box;
  36667. },
  36668. getOrderHint: function(node) {
  36669. return [];
  36670. }
  36671. });
  36672. var LayoutCommand = kity.createClass('LayoutCommand', {
  36673. base: Command,
  36674. execute: function(minder, name) {
  36675. var nodes = minder.getSelectedNodes();
  36676. nodes.forEach(function(node) {
  36677. node.layout(name);
  36678. });
  36679. },
  36680. queryValue: function(minder) {
  36681. var node = minder.getSelectedNode();
  36682. if (node) {
  36683. return node.getData('layout');
  36684. }
  36685. },
  36686. queryState: function(minder) {
  36687. return minder.getSelectedNode() ? 0 : -1;
  36688. }
  36689. });
  36690. var ResetLayoutCommand = kity.createClass('ResetLayoutCommand', {
  36691. base: Command,
  36692. execute: function(minder, name) {
  36693. var nodes = minder.getSelectedNodes();
  36694. if (!nodes.length) nodes = [minder.getRoot()];
  36695. nodes.forEach(function(node) {
  36696. node.traverse(function(child) {
  36697. child.resetLayoutOffset();
  36698. if (!child.isRoot()) {
  36699. child.setData('layout', null);
  36700. }
  36701. });
  36702. });
  36703. minder.layout(300);
  36704. },
  36705. enableReadOnly: true
  36706. });
  36707. KityMinder.registerModule('LayoutModule', {
  36708. commands: {
  36709. 'layout': LayoutCommand,
  36710. 'resetlayout': ResetLayoutCommand
  36711. },
  36712. contextmenu: [{
  36713. command: 'resetlayout'
  36714. }, {
  36715. divider: true
  36716. }],
  36717. commandShortcutKeys: {
  36718. 'resetlayout': 'Ctrl+Shift+L'
  36719. }
  36720. });
  36721. var cssLikeValueMatcher = {
  36722. left: function(value) {
  36723. return 3 in value && value[3] ||
  36724. 1 in value && value[1] ||
  36725. value[0];
  36726. },
  36727. right: function(value) {
  36728. return 1 in value && value[1] || value[0];
  36729. },
  36730. top: function(value) {
  36731. return value[0];
  36732. },
  36733. bottom: function(value) {
  36734. return 2 in value && value[2] || value[0];
  36735. }
  36736. };
  36737. Utils.extend(KityMinder, {
  36738. _themes: {},
  36739. /**
  36740. * 注册一个主题
  36741. *
  36742. * @param {String} name 主题的名称
  36743. * @param {Plain} theme 主题的样式描述
  36744. *
  36745. * @example
  36746. * KityMinder.registerTheme('default', {
  36747. * 'root-color': 'red',
  36748. * 'root-stroke': 'none',
  36749. * 'root-padding': [10, 20]
  36750. * });
  36751. */
  36752. registerTheme: function(name, theme) {
  36753. KityMinder._themes[name] = theme;
  36754. },
  36755. getThemeList: function() {
  36756. return KityMinder._themes;
  36757. }
  36758. });
  36759. kity.extendClass(Minder, {
  36760. /**
  36761. * 切换脑图实例上的主题
  36762. * @param {String} name 要使用的主题的名称
  36763. */
  36764. useTheme: function(name) {
  36765. this.setTheme(name);
  36766. this.refresh(800);
  36767. return true;
  36768. },
  36769. setTheme: function(name) {
  36770. this._theme = name || null;
  36771. this.getRenderTarget().style.background = this.getStyle('background');
  36772. this.fire('themechange', {
  36773. theme: name
  36774. });
  36775. },
  36776. /**
  36777. * 获取脑图实例上的当前主题
  36778. * @return {[type]} [description]
  36779. */
  36780. getTheme: function(node) {
  36781. return this._theme || this.getOptions('defaultTheme');
  36782. },
  36783. getThemeItems: function(node) {
  36784. var theme = this.getTheme(node);
  36785. return KityMinder._themes[this.getTheme(node)];
  36786. },
  36787. /**
  36788. * 获得脑图实例上的样式
  36789. * @param {String} item 样式名称
  36790. */
  36791. getStyle: function(item, node) {
  36792. var items = this.getThemeItems(node);
  36793. var segment, dir, selector, value, matcher;
  36794. if (item in items) return items[item];
  36795. // 尝试匹配 CSS 数组形式的值
  36796. // 比如 item 为 'pading-left'
  36797. // theme 里有 {'padding': [10, 20]} 的定义,则可以返回 20
  36798. segment = item.split('-');
  36799. if (segment.length < 2) return null;
  36800. dir = segment.pop();
  36801. item = segment.join('-');
  36802. if (item in items) {
  36803. value = items[item];
  36804. if (Utils.isArray(value) && (matcher = cssLikeValueMatcher[dir])) {
  36805. return matcher(value);
  36806. }
  36807. if (!isNaN(value)) return value;
  36808. }
  36809. return null;
  36810. },
  36811. /**
  36812. * 获取指定节点的样式
  36813. * @param {String} name 样式名称,可以不加节点类型的前缀
  36814. */
  36815. getNodeStyle: function(node, name) {
  36816. var value = this.getStyle(node.getType() + '-' + name, node);
  36817. return value !== null ? value : this.getStyle(name, node);
  36818. }
  36819. });
  36820. kity.extendClass(MinderNode, {
  36821. getStyle: function(name) {
  36822. return this.getMinder().getNodeStyle(this, name);
  36823. }
  36824. });
  36825. KityMinder.registerModule('Theme', {
  36826. defaultOptions: {
  36827. defaultTheme: 'fresh-blue'
  36828. },
  36829. commands: {
  36830. 'theme': kity.createClass('ThemeCommand', {
  36831. base: Command,
  36832. execute: function(km, name) {
  36833. return km.useTheme(name);
  36834. },
  36835. queryValue: function(km) {
  36836. return km.getTheme() || 'default';
  36837. }
  36838. })
  36839. }
  36840. });
  36841. Minder.registerInit(function() {
  36842. this.setTheme();
  36843. });
  36844. Utils.extend(KityMinder, {
  36845. compatibility: function(json) {
  36846. var version = json.version || '1.1.3';
  36847. function traverse(node, fn) {
  36848. fn(node);
  36849. if (node.children) node.children.forEach(function(child) {
  36850. traverse(child, fn);
  36851. });
  36852. }
  36853. /* 脑图数据升级 */
  36854. function c_120_130(json) {
  36855. traverse(json, function(node) {
  36856. var data = node.data;
  36857. delete data.layout_bottom_offset;
  36858. delete data.layout_default_offset;
  36859. delete data.layout_filetree_offset;
  36860. });
  36861. }
  36862. /**
  36863. * 脑图数据升级
  36864. * v1.1.3 => v1.2.0
  36865. * */
  36866. function c_113_120(json) {
  36867. // 原本的布局风格
  36868. var ocs = json.data.currentstyle;
  36869. delete json.data.currentstyle;
  36870. // 为 1.2 选择模板,同时保留老版本文件的皮肤
  36871. if (ocs == 'bottom') {
  36872. json.template = 'structure';
  36873. json.theme = 'snow';
  36874. } else if (ocs == 'default') {
  36875. json.template = 'default';
  36876. json.theme = 'classic';
  36877. }
  36878. traverse(json, function(node) {
  36879. var data = node.data;
  36880. // 升级优先级、进度图标
  36881. if ('PriorityIcon' in data) {
  36882. data.priority = data.PriorityIcon;
  36883. delete data.PriorityIcon;
  36884. }
  36885. if ('ProgressIcon' in data) {
  36886. data.progress = 1 + ((data.ProgressIcon - 1) << 1);
  36887. delete data.ProgressIcon;
  36888. }
  36889. // 删除过时属性
  36890. delete data.point;
  36891. delete data.layout;
  36892. });
  36893. }
  36894. switch (version) {
  36895. case '1.1.3':
  36896. c_113_120(json);
  36897. case '1.2.0':
  36898. case '1.2.1':
  36899. c_120_130(json);
  36900. }
  36901. return json;
  36902. }
  36903. });
  36904. var Renderer = KityMinder.Renderer = kity.createClass('Renderer', {
  36905. constructor: function(node) {
  36906. this.node = node;
  36907. },
  36908. create: function(node) {
  36909. throw new Error('Not implement: Renderer.create()');
  36910. },
  36911. shouldRender: function(node) {
  36912. return true;
  36913. },
  36914. watchChange: function(data) {
  36915. var changed;
  36916. if (this.watchingData === undefined) {
  36917. changed = true;
  36918. } else if (this.watchingData != data) {
  36919. changed = true;
  36920. } else {
  36921. changed = false;
  36922. }
  36923. this.watchingData = data;
  36924. },
  36925. shouldDraw: function(node) {
  36926. return true;
  36927. },
  36928. update: function(shape, node, box) {
  36929. if (this.shouldDraw()) this.draw(shape, node);
  36930. return this.place(shape, node, box);
  36931. },
  36932. draw: function(shape, node) {
  36933. throw new Error('Not implement: Renderer.draw()');
  36934. },
  36935. place: function(shape, node, box) {
  36936. throw new Error('Not implement: Renderer.place()');
  36937. },
  36938. getRenderShape: function() {
  36939. return this._renderShape || null;
  36940. },
  36941. setRenderShape: function(shape) {
  36942. this._renderShape = shape;
  36943. }
  36944. });
  36945. kity.extendClass(Minder, (function() {
  36946. function createRendererForNode(node, registered) {
  36947. var renderers = [];
  36948. ['center', 'left', 'right', 'top', 'bottom', 'outline', 'outside'].forEach(function(section) {
  36949. var before = 'before' + section;
  36950. var after = 'after' + section;
  36951. if (registered[before]) {
  36952. renderers = renderers.concat(registered[before]);
  36953. }
  36954. if (registered[section]) {
  36955. renderers = renderers.concat(registered[section]);
  36956. }
  36957. if (registered[after]) {
  36958. renderers = renderers.concat(registered[after]);
  36959. }
  36960. });
  36961. node._renderers = renderers.map(function(Renderer) {
  36962. return new Renderer(node);
  36963. });
  36964. }
  36965. return {
  36966. renderNodeBatch: function(nodes) {
  36967. var rendererClasses = this._rendererClasses;
  36968. var lastBoxes = [];
  36969. var rendererCount = 0;
  36970. var i, j, renderer, node;
  36971. if (!nodes.length) return;
  36972. for (j = 0; j < nodes.length; j++) {
  36973. node = nodes[j];
  36974. if (!node._renderers) {
  36975. createRendererForNode(node, rendererClasses);
  36976. }
  36977. node._contentBox = new kity.Box();
  36978. this.fire('beforerender', {
  36979. node: node
  36980. });
  36981. }
  36982. // 所有节点渲染器数量是一致的
  36983. rendererCount = nodes[0]._renderers.length;
  36984. for (i = 0; i < rendererCount; i++) {
  36985. // 获取延迟盒子数据
  36986. for (j = 0; j < nodes.length; j++) {
  36987. if (typeof(lastBoxes[j]) == 'function') {
  36988. lastBoxes[j] = lastBoxes[j]();
  36989. }
  36990. if (!(lastBoxes[j] instanceof kity.Box)) {
  36991. lastBoxes[j] = new kity.Box(lastBoxes[j]);
  36992. }
  36993. }
  36994. for (j = 0; j < nodes.length; j++) {
  36995. node = nodes[j];
  36996. renderer = node._renderers[i];
  36997. // 合并盒子
  36998. if (lastBoxes[j]) {
  36999. node._contentBox = node._contentBox.merge(lastBoxes[j]);
  37000. }
  37001. // 判断当前上下文是否应该渲染
  37002. if (renderer.shouldRender(node)) {
  37003. // 应该渲染,但是渲染图形没创建过,需要创建
  37004. if (!renderer.getRenderShape()) {
  37005. renderer.setRenderShape(renderer.create(node));
  37006. if (renderer.bringToBack) {
  37007. node.getRenderContainer().prependShape(renderer.getRenderShape());
  37008. } else {
  37009. node.getRenderContainer().appendShape(renderer.getRenderShape());
  37010. }
  37011. }
  37012. // 强制让渲染图形显示
  37013. renderer.getRenderShape().setVisible(true);
  37014. // 更新渲染图形
  37015. lastBoxes[j] = renderer.update(renderer.getRenderShape(), node, node._contentBox);
  37016. }
  37017. // 如果不应该渲染,但是渲染图形创建过了,需要隐藏起来
  37018. else if (renderer.getRenderShape()) {
  37019. renderer.getRenderShape().setVisible(false);
  37020. lastBoxes[j] = null;
  37021. }
  37022. }
  37023. }
  37024. for (j = 0; j < nodes.length; j++) {
  37025. this.fire('noderender', {
  37026. node: nodes[j]
  37027. });
  37028. }
  37029. },
  37030. renderNode: function(node) {
  37031. var rendererClasses = this._rendererClasses;
  37032. var g = KityMinder.Geometry;
  37033. var i, latestBox, renderer;
  37034. if (!node._renderers) {
  37035. createRendererForNode(node, rendererClasses);
  37036. }
  37037. this.fire('beforerender', {
  37038. node: node
  37039. });
  37040. node._contentBox = new kity.Box();
  37041. node._renderers.forEach(function(renderer) {
  37042. // 判断当前上下文是否应该渲染
  37043. if (renderer.shouldRender(node)) {
  37044. // 应该渲染,但是渲染图形没创建过,需要创建
  37045. if (!renderer.getRenderShape()) {
  37046. renderer.setRenderShape(renderer.create(node));
  37047. if (renderer.bringToBack) {
  37048. node.getRenderContainer().prependShape(renderer.getRenderShape());
  37049. } else {
  37050. node.getRenderContainer().appendShape(renderer.getRenderShape());
  37051. }
  37052. }
  37053. // 强制让渲染图形显示
  37054. renderer.getRenderShape().setVisible(true);
  37055. // 更新渲染图形
  37056. latestBox = renderer.update(renderer.getRenderShape(), node, node._contentBox);
  37057. if (typeof(latestBox) == 'function') latestBox = latestBox();
  37058. // 合并渲染区域
  37059. if (latestBox) {
  37060. node._contentBox = node._contentBox.merge(latestBox);
  37061. }
  37062. }
  37063. // 如果不应该渲染,但是渲染图形创建过了,需要隐藏起来
  37064. else if (renderer.getRenderShape()) {
  37065. renderer.getRenderShape().setVisible(false);
  37066. }
  37067. });
  37068. this.fire('noderender', {
  37069. node: node
  37070. });
  37071. }
  37072. };
  37073. })());
  37074. kity.extendClass(MinderNode, {
  37075. render: function() {
  37076. if (!this.attached) return;
  37077. this.getMinder().renderNode(this);
  37078. return this;
  37079. },
  37080. renderTree: function() {
  37081. if (!this.attached) return;
  37082. var list = [];
  37083. this.traverse(function(node) {
  37084. list.push(node);
  37085. });
  37086. this.getMinder().renderNodeBatch(list);
  37087. return this;
  37088. },
  37089. getRenderer: function(type) {
  37090. var rs = this._renderers;
  37091. for (var i = 0; i < rs.length; i++) {
  37092. if (rs[i].getType() == type) return rs[i];
  37093. }
  37094. return null;
  37095. },
  37096. getContentBox: function() {
  37097. //if (!this._contentBox) this.render();
  37098. return this.parent && this.parent.isCollapsed() ? new kity.Box() : (this._contentBox || new kity.Box());
  37099. }
  37100. });
  37101. /* global Renderer: true */
  37102. utils.extend(KityMinder, {
  37103. _connectProviders: {},
  37104. _defaultConnectProvider: function(node, parent, connection) {
  37105. connection.setPathData([
  37106. 'M', parent.getLayoutVertexOut(),
  37107. 'L', node.getLayoutVertexIn()
  37108. ]);
  37109. },
  37110. registerConnectProvider: function(name, provider) {
  37111. KityMinder._connectProviders[name] = provider;
  37112. },
  37113. getConnectProvider: function(name) {
  37114. return KityMinder._connectProviders[name] || KityMinder._defaultConnectProvider;
  37115. }
  37116. });
  37117. kity.extendClass(MinderNode, {
  37118. getConnectProvider: function() {
  37119. return KityMinder.getConnectProvider(this.getConnect());
  37120. },
  37121. getConnect: function() {
  37122. return null;
  37123. },
  37124. getConnection: function() {
  37125. return this._connection || null;
  37126. }
  37127. });
  37128. kity.extendClass(Minder, {
  37129. getConnectContainer: function() {
  37130. return this._connectContainer;
  37131. },
  37132. createConnect: function(node) {
  37133. if (node.isRoot()) return;
  37134. var connection = new kity.Path();
  37135. node._connection = connection;
  37136. this._connectContainer.addShape(connection);
  37137. this.updateConnect(node);
  37138. },
  37139. removeConnect: function(node) {
  37140. var me = this;
  37141. node.traverse(function(node) {
  37142. me._connectContainer.removeShape(node._connection);
  37143. node._connection = null;
  37144. });
  37145. },
  37146. updateConnect: function(node) {
  37147. var connection = node._connection;
  37148. var parent = node.parent;
  37149. if (!parent || !connection) return;
  37150. if (parent.isCollapsed()) {
  37151. connection.setVisible(false);
  37152. return;
  37153. }
  37154. connection.setVisible(true);
  37155. var provider = node.getConnectProvider();
  37156. var strokeColor = node.getStyle('connect-color') || 'white',
  37157. strokeWidth = node.getStyle('connect-width') || 2;
  37158. connection.stroke(strokeColor, strokeWidth);
  37159. provider(node, parent, connection, strokeWidth, strokeColor);
  37160. if (strokeWidth % 2 === 0) {
  37161. connection.setTranslate(0.5, 0.5);
  37162. } else {
  37163. connection.setTranslate(0, 0);
  37164. }
  37165. }
  37166. });
  37167. KityMinder.registerModule('Connect', {
  37168. init: function() {
  37169. this._connectContainer = new kity.Group().setId(KityMinder.uuid('minder_connect_group'));
  37170. this.getRenderContainer().prependShape(this._connectContainer);
  37171. },
  37172. events: {
  37173. 'nodeattach': function(e) {
  37174. this.createConnect(e.node);
  37175. },
  37176. 'nodedetach': function(e) {
  37177. this.removeConnect(e.node);
  37178. },
  37179. 'layoutapply layoutfinish noderender': function(e) {
  37180. this.updateConnect(e.node);
  37181. }
  37182. }
  37183. });
  37184. utils.extend(KityMinder, {
  37185. _templates: {},
  37186. registerTemplate: function(name, supports) {
  37187. KityMinder._templates[name] = supports;
  37188. },
  37189. getTemplateList: function() {
  37190. return KityMinder._templates;
  37191. }
  37192. });
  37193. kity.extendClass(Minder, (function() {
  37194. var originGetTheme = Minder.prototype.getTheme;
  37195. return {
  37196. useTemplate: function(name, duration) {
  37197. this.setTemplate(name);
  37198. this.refresh(duration || 800);
  37199. },
  37200. getTemplate: function() {
  37201. return this._template || 'default';
  37202. },
  37203. setTemplate: function(name) {
  37204. this._template = name || null;
  37205. },
  37206. getTemplateSupport: function(method) {
  37207. var supports = KityMinder._templates[this.getTemplate()];
  37208. return supports && supports[method];
  37209. },
  37210. getTheme: function(node) {
  37211. var support = this.getTemplateSupport('getTheme') || originGetTheme;
  37212. return support.call(this, node);
  37213. }
  37214. };
  37215. })());
  37216. kity.extendClass(MinderNode, (function() {
  37217. var originGetLayout = MinderNode.prototype.getLayout;
  37218. var originGetConnect = MinderNode.prototype.getConnect;
  37219. return {
  37220. getLayout: function() {
  37221. var support = this.getMinder().getTemplateSupport('getLayout') || originGetLayout;
  37222. return support.call(this, this);
  37223. },
  37224. getConnect: function() {
  37225. var support = this.getMinder().getTemplateSupport('getConnect') || originGetConnect;
  37226. return support.call(this, this);
  37227. }
  37228. };
  37229. })());
  37230. KityMinder.registerModule('TemplateModule', {
  37231. commands: {
  37232. 'template': kity.createClass('TemplateCommand', {
  37233. base: Command,
  37234. execute: function(minder, name) {
  37235. minder.useTemplate(name);
  37236. minder.execCommand('camera');
  37237. },
  37238. queryValue: function(minder) {
  37239. return minder.getTemplate() || 'default';
  37240. }
  37241. })
  37242. }
  37243. });
  37244. //添加多语言模块
  37245. kity.extendClass( Minder, {
  37246. getLang: function ( path ) {
  37247. var lang = KM.LANG[ this.getOptions( 'lang' ) ];
  37248. if ( !lang ) {
  37249. throw Error( "not import language file" );
  37250. }
  37251. path = ( path || "" ).split( "." );
  37252. for ( var i = 0, ci; ci = path[ i++ ]; ) {
  37253. lang = lang[ ci ];
  37254. if ( !lang ) break;
  37255. }
  37256. if (typeof(lang) == 'string') {
  37257. var args = arguments;
  37258. return lang.replace(/\{(\d+)\}/ig, function(match, gindex) {
  37259. return args[+gindex + 1] != undefined && args[+gindex + 1].toString() || match;
  37260. });
  37261. }
  37262. return lang;
  37263. }
  37264. } );
  37265. //这里只放不是由模块产生的默认参数
  37266. KM.defaultOptions = {
  37267. zIndex : 1000,
  37268. lang:'zh-cn',
  37269. readyOnly:false
  37270. };
  37271. kity.extendClass( Minder, function(){
  37272. var ROOTKEY = 'kityminder_preference';
  37273. //创建存储机制
  37274. var LocalStorage = ( function () {
  37275. var storage = window.localStorage,
  37276. LOCAL_FILE = "localStorage";
  37277. return {
  37278. saveLocalData: function ( key, data ) {
  37279. if ( storage && data) {
  37280. storage.setItem( key, data );
  37281. return true;
  37282. }
  37283. return false;
  37284. },
  37285. getLocalData: function ( key ) {
  37286. if ( storage ) {
  37287. return storage.getItem( key );
  37288. }
  37289. return null;
  37290. },
  37291. removeItem: function ( key ) {
  37292. if (storage) storage.removeItem( key );
  37293. }
  37294. };
  37295. } )();
  37296. return {
  37297. setPreferences: function(key,value){
  37298. var obj = {};
  37299. if ( Utils.isString( key ) ) {
  37300. obj[ key ] = value;
  37301. } else {
  37302. obj = key;
  37303. }
  37304. var data = LocalStorage.getLocalData(ROOTKEY);
  37305. if(data){
  37306. data = JSON.parse(data);
  37307. utils.extend(data, obj);
  37308. }else{
  37309. data = obj;
  37310. }
  37311. LocalStorage.saveLocalData(ROOTKEY,JSON.stringify(data));
  37312. },
  37313. getPreferences: function(key){
  37314. var data = LocalStorage.getLocalData(ROOTKEY);
  37315. if(data){
  37316. data = JSON.parse(data);
  37317. return key ? data[key] : data;
  37318. }
  37319. return {};
  37320. },
  37321. resetPreferences: function(pres){
  37322. var str = pres ? JSON.stringify(pres) : '';
  37323. LocalStorage.saveLocalData(str);
  37324. }
  37325. };
  37326. }() );
  37327. var keymap = KityMinder.keymap = (function(origin) {
  37328. var ret = {};
  37329. for (var key in origin) {
  37330. if (origin.hasOwnProperty(key)) {
  37331. ret[key] = origin[key];
  37332. ret[key.toLowerCase()] = origin[key];
  37333. }
  37334. }
  37335. var aKeyCode = 65;
  37336. var aCharCode = 'a'.charCodeAt(0);
  37337. // letters
  37338. 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function(letter) {
  37339. ret[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
  37340. });
  37341. // numbers
  37342. var n = 9;
  37343. do {
  37344. ret[n.toString()] = n + 48;
  37345. } while(--n);
  37346. return ret;
  37347. })({
  37348. 'Backspace': 8,
  37349. 'Tab': 9,
  37350. 'Enter': 13,
  37351. 'Shift': 16,
  37352. 'Control': 17,
  37353. 'Alt': 18,
  37354. 'CapsLock': 20,
  37355. 'Esc': 27,
  37356. 'Spacebar': 32,
  37357. 'PageUp': 33,
  37358. 'PageDown': 34,
  37359. 'End': 35,
  37360. 'Home': 36,
  37361. 'Insert': 45,
  37362. 'Left': 37,
  37363. 'Up': 38,
  37364. 'Right': 39,
  37365. 'Down': 40,
  37366. 'direction': {
  37367. 37: 1,
  37368. 38: 1,
  37369. 39: 1,
  37370. 40: 1
  37371. },
  37372. 'Del': 46,
  37373. 'NumLock': 144,
  37374. 'Cmd': 91,
  37375. 'CmdFF': 224,
  37376. 'F1': 112,
  37377. 'F2': 113,
  37378. 'F3': 114,
  37379. 'F4': 115,
  37380. 'F5': 116,
  37381. 'F6': 117,
  37382. 'F7': 118,
  37383. 'F8': 119,
  37384. 'F9': 120,
  37385. 'F10': 121,
  37386. 'F11': 122,
  37387. 'F12': 123,
  37388. '`': 192,
  37389. '=': 187,
  37390. '-': 189,
  37391. '/': 191,
  37392. '.': 190,
  37393. controlKeys: {
  37394. 16: 1,
  37395. 17: 1,
  37396. 18: 1,
  37397. 20: 1,
  37398. 91: 1,
  37399. 224: 1
  37400. },
  37401. 'notContentChange': {
  37402. 13: 1,
  37403. 9: 1,
  37404. 33: 1,
  37405. 34: 1,
  37406. 35: 1,
  37407. 36: 1,
  37408. 16: 1,
  37409. 17: 1,
  37410. 18: 1,
  37411. 20: 1,
  37412. 91: 1,
  37413. //上下左右
  37414. 37: 1,
  37415. 38: 1,
  37416. 39: 1,
  37417. 40: 1,
  37418. 113: 1,
  37419. 114: 1,
  37420. 115: 1,
  37421. 144: 1,
  37422. 27: 1
  37423. },
  37424. 'isSelectedNodeKey': {
  37425. //上下左右
  37426. 37: 1,
  37427. 38: 1,
  37428. 39: 1,
  37429. 40: 1,
  37430. 13: 1,
  37431. 9: 1
  37432. }
  37433. });
  37434. /* global Layout:true */
  37435. KityMinder.registerLayout('mind', kity.createClass({
  37436. base: Layout,
  37437. doLayout: function(node, children) {
  37438. var layout = this;
  37439. var half = Math.ceil(node.children.length / 2);
  37440. var right = [];
  37441. var left = [];
  37442. children.forEach(function(child) {
  37443. if (child.getIndex() < half) right.push(child);
  37444. else left.push(child);
  37445. });
  37446. var leftLayout = KityMinder.getLayoutInstance('left');
  37447. var rightLayout = KityMinder.getLayoutInstance('right');
  37448. leftLayout.doLayout(node, left);
  37449. rightLayout.doLayout(node, right);
  37450. var box = node.getContentBox();
  37451. node.setVertexOut(new kity.Point(box.cx, box.cy));
  37452. node.setLayoutVectorOut(new kity.Vector(0, 0));
  37453. },
  37454. getOrderHint: function(node) {
  37455. var hint = [];
  37456. var box = node.getLayoutBox();
  37457. var offset = 5;
  37458. hint.push({
  37459. type: 'up',
  37460. node: node,
  37461. area: {
  37462. x: box.x,
  37463. y: box.top - node.getStyle('margin-top') - offset,
  37464. width: box.width,
  37465. height: node.getStyle('margin-top')
  37466. },
  37467. path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
  37468. });
  37469. hint.push({
  37470. type: 'down',
  37471. node: node,
  37472. area: {
  37473. x: box.x,
  37474. y: box.bottom + offset,
  37475. width: box.width,
  37476. height: node.getStyle('margin-bottom')
  37477. },
  37478. path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
  37479. });
  37480. return hint;
  37481. }
  37482. }));
  37483. /* global Layout:true */
  37484. [-1, 1].forEach(function (dir) {
  37485. var name = 'filetree-' + (dir > 0 ? 'down' : 'up');
  37486. KityMinder.registerLayout(name, kity.createClass({
  37487. base: Layout,
  37488. doLayout: function(parent, children, round) {
  37489. var pBox = parent.getContentBox();
  37490. var indent = 20;
  37491. parent.setVertexOut(new kity.Point(pBox.left + indent, dir > 0 ? pBox.bottom : pBox.top));
  37492. parent.setLayoutVectorOut(new kity.Vector(0, dir));
  37493. if (!children.length) return;
  37494. children.forEach(function(child) {
  37495. var cbox = child.getContentBox();
  37496. child.setLayoutTransform(new kity.Matrix());
  37497. child.setVertexIn(new kity.Point(cbox.left, cbox.cy));
  37498. child.setLayoutVectorIn(new kity.Vector(1, 0));
  37499. });
  37500. this.align(children, 'left');
  37501. this.stack(children, 'y');
  37502. var xAdjust = 0;
  37503. xAdjust += pBox.left;
  37504. xAdjust += indent;
  37505. xAdjust += children[0].getStyle('margin-left');
  37506. var yAdjust = 0;
  37507. if (dir > 0) {
  37508. yAdjust += pBox.bottom;
  37509. yAdjust += parent.getStyle('margin-bottom');
  37510. yAdjust += children[0].getStyle('margin-top');
  37511. } else {
  37512. yAdjust -= this.getTreeBox(children).bottom;
  37513. yAdjust += pBox.top;
  37514. yAdjust -= parent.getStyle('margin-top');
  37515. yAdjust -= children[0].getStyle('margin-bottom');
  37516. }
  37517. this.move(children, xAdjust, yAdjust);
  37518. },
  37519. getOrderHint: function(node) {
  37520. var hint = [];
  37521. var box = node.getLayoutBox();
  37522. var offset = node.getLevel() > 1 ? 3 : 5;
  37523. hint.push({
  37524. type: 'up',
  37525. node: node,
  37526. area: {
  37527. x: box.x,
  37528. y: box.top - node.getStyle('margin-top') - offset,
  37529. width: box.width,
  37530. height: node.getStyle('margin-top')
  37531. },
  37532. path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
  37533. });
  37534. hint.push({
  37535. type: 'down',
  37536. node: node,
  37537. area: {
  37538. x: box.x,
  37539. y: box.bottom + offset,
  37540. width: box.width,
  37541. height: node.getStyle('margin-bottom')
  37542. },
  37543. path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
  37544. });
  37545. return hint;
  37546. }
  37547. }));
  37548. });
  37549. /* global Layout:true */
  37550. var layouts = ['left', 'right', 'top', 'bottom'];
  37551. layouts.forEach(function(name) {
  37552. var axis = (name == 'left' || name == 'right') ? 'x' : 'y';
  37553. var dir = (name == 'left' || name == 'top') ? -1 : 1;
  37554. var oppsite = {
  37555. 'left': 'right',
  37556. 'right': 'left',
  37557. 'top': 'bottom',
  37558. 'bottom': 'top',
  37559. 'x': 'y',
  37560. 'y': 'x'
  37561. };
  37562. function getOrderHint(node) {
  37563. var hint = [];
  37564. var box = node.getLayoutBox();
  37565. var offset = 5;
  37566. if (axis == 'x') {
  37567. hint.push({
  37568. type: 'up',
  37569. node: node,
  37570. area: {
  37571. x: box.x,
  37572. y: box.top - node.getStyle('margin-top') - offset,
  37573. width: box.width,
  37574. height: node.getStyle('margin-top')
  37575. },
  37576. path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
  37577. });
  37578. hint.push({
  37579. type: 'down',
  37580. node: node,
  37581. area: {
  37582. x: box.x,
  37583. y: box.bottom + offset,
  37584. width: box.width,
  37585. height: node.getStyle('margin-bottom')
  37586. },
  37587. path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
  37588. });
  37589. } else {
  37590. hint.push({
  37591. type: 'up',
  37592. node: node,
  37593. area: {
  37594. x: box.left - node.getStyle('margin-left') - offset,
  37595. y: box.top,
  37596. width: node.getStyle('margin-left'),
  37597. height: box.height
  37598. },
  37599. path: ['M', box.left - offset, box.top, 'L', box.left - offset, box.bottom]
  37600. });
  37601. hint.push({
  37602. type: 'down',
  37603. node: node,
  37604. area: {
  37605. x: box.right + offset,
  37606. y: box.top,
  37607. width: node.getStyle('margin-right'),
  37608. height: box.height
  37609. },
  37610. path: ['M', box.right + offset, box.top, 'L', box.right + offset, box.bottom]
  37611. });
  37612. }
  37613. return hint;
  37614. }
  37615. KityMinder.registerLayout(name, kity.createClass({
  37616. base: Layout,
  37617. doLayout: function(parent, children) {
  37618. var pbox = parent.getContentBox();
  37619. if (axis == 'x') {
  37620. parent.setVertexOut(new kity.Point(pbox[name], pbox.cy));
  37621. parent.setLayoutVectorOut(new kity.Vector(dir, 0));
  37622. } else {
  37623. parent.setVertexOut(new kity.Point(pbox.cx, pbox[name]));
  37624. parent.setLayoutVectorOut(new kity.Vector(0, dir));
  37625. }
  37626. if (!children.length) {
  37627. return false;
  37628. }
  37629. children.forEach(function(child) {
  37630. var cbox = child.getContentBox();
  37631. child.setLayoutTransform(new kity.Matrix());
  37632. if (axis == 'x') {
  37633. child.setVertexIn(new kity.Point(cbox[oppsite[name]], cbox.cy));
  37634. child.setLayoutVectorIn(new kity.Vector(dir, 0));
  37635. } else {
  37636. child.setVertexIn(new kity.Point(cbox.cx, cbox[oppsite[name]]));
  37637. child.setLayoutVectorIn(new kity.Vector(0, dir));
  37638. }
  37639. });
  37640. this.align(children, oppsite[name]);
  37641. this.stack(children, oppsite[axis]);
  37642. var bbox = this.getBranchBox(children);
  37643. var xAdjust, yAdjust;
  37644. if (axis == 'x') {
  37645. xAdjust = pbox[name];
  37646. xAdjust += dir * parent.getStyle('margin-' + name);
  37647. xAdjust += dir * children[0].getStyle('margin-' + oppsite[name]);
  37648. yAdjust = pbox.bottom;
  37649. yAdjust -= pbox.height / 2;
  37650. yAdjust -= bbox.height / 2;
  37651. yAdjust -= bbox.y;
  37652. } else {
  37653. xAdjust = pbox.right;
  37654. xAdjust -= pbox.width / 2;
  37655. xAdjust -= bbox.width / 2;
  37656. xAdjust -= bbox.x;
  37657. yAdjust = pbox[name];
  37658. yAdjust += dir * parent.getStyle('margin-' + name);
  37659. yAdjust += dir * children[0].getStyle('margin-' + oppsite[name]);
  37660. }
  37661. this.move(children, xAdjust, yAdjust);
  37662. },
  37663. getOrderHint: getOrderHint
  37664. }));
  37665. });
  37666. /**
  37667. * @fileOverview
  37668. *
  37669. * 鱼骨图主骨架布局
  37670. *
  37671. * @author: techird
  37672. * @copyright: Baidu FEX, 2014
  37673. */
  37674. /* global Layout:true */
  37675. KityMinder.registerLayout('fish-bone-master', kity.createClass('FishBoneMasterLayout', {
  37676. base: Layout,
  37677. doLayout: function(parent, children, round) {
  37678. var upPart = [],
  37679. downPart = [];
  37680. var child = children[0];
  37681. var pBox = parent.getContentBox();
  37682. parent.setVertexOut(new kity.Point(pBox.right, pBox.cy));
  37683. parent.setLayoutVectorOut(new kity.Vector(1, 0));
  37684. if (!child) return;
  37685. var cBox = child.getContentBox();
  37686. var pMarginRight = parent.getStyle('margin-right');
  37687. var cMarginLeft = child.getStyle('margin-left');
  37688. var cMarginTop = child.getStyle('margin-top');
  37689. var cMarginBottom = child.getStyle('margin-bottom');
  37690. children.forEach(function(child, index) {
  37691. child.setLayoutTransform(new kity.Matrix());
  37692. var cBox = child.getContentBox();
  37693. if (index % 2) {
  37694. downPart.push(child);
  37695. child.setVertexIn(new kity.Point(cBox.left, cBox.top));
  37696. child.setLayoutVectorIn(new kity.Vector(1, 1));
  37697. }
  37698. else {
  37699. upPart.push(child);
  37700. child.setVertexIn(new kity.Point(cBox.left, cBox.bottom));
  37701. child.setLayoutVectorIn(new kity.Vector(1, -1));
  37702. }
  37703. });
  37704. this.stack(upPart, 'x');
  37705. this.stack(downPart, 'x');
  37706. this.align(upPart, 'bottom');
  37707. this.align(downPart, 'top');
  37708. var xAdjust = pBox.right + pMarginRight + cMarginLeft;
  37709. var yAdjustUp = pBox.cy - cMarginBottom - parent.getStyle('margin-top');
  37710. var yAdjustDown = pBox.cy + cMarginTop + parent.getStyle('margin-bottom');
  37711. this.move(upPart, xAdjust, yAdjustUp);
  37712. this.move(downPart, xAdjust + cMarginLeft, yAdjustDown);
  37713. // children.forEach(function(child, index) {
  37714. // var matrix = child.getLayoutTransform();
  37715. // var dx, dy;
  37716. // dx = matrix.getMatrix().e;
  37717. // dy = matrix.getMatrix().f;
  37718. // matrix.translate(-dx, -dy);
  37719. // matrix.rotate(index % 2 ? 45 : -45);
  37720. // matrix.translate(dx, dy);
  37721. // });
  37722. }
  37723. }));
  37724. /**
  37725. * @fileOverview
  37726. *
  37727. *
  37728. *
  37729. * @author: techird
  37730. * @copyright: Baidu FEX, 2014
  37731. */
  37732. /* global Layout: true */
  37733. KityMinder.registerLayout('fish-bone-slave', kity.createClass('FishBoneSlaveLayout', {
  37734. base: Layout,
  37735. doLayout: function (parent, children, round) {
  37736. var layout = this;
  37737. var abs = Math.abs;
  37738. var GOLD_CUT = 1 - 0.618;
  37739. var pBox = parent.getContentBox();
  37740. var vi = parent.getLayoutVectorIn();
  37741. parent.setLayoutVectorOut(vi);
  37742. var goldX = pBox.left + pBox.width * GOLD_CUT;
  37743. var pout = new kity.Point(goldX, vi.y > 0 ? pBox.bottom : pBox.top);
  37744. parent.setVertexOut(pout);
  37745. var child = children[0];
  37746. if (!child) return;
  37747. var cBox = child.getContentBox();
  37748. children.forEach(function(child, index) {
  37749. child.setLayoutTransform(new kity.Matrix());
  37750. child.setLayoutVectorIn(new kity.Vector(1, 0));
  37751. child.setVertexIn(new kity.Point(cBox.left, cBox.cy));
  37752. });
  37753. this.stack(children, 'y');
  37754. this.align(children, 'left');
  37755. var xAdjust = 0, yAdjust = 0;
  37756. xAdjust += pout.x;
  37757. if (parent.getLayoutVectorOut().y < 0) {
  37758. yAdjust -= this.getTreeBox(children).bottom;
  37759. yAdjust += parent.getContentBox().top;
  37760. yAdjust -= parent.getStyle('margin-top');
  37761. yAdjust -= child.getStyle('margin-bottom');
  37762. } else {
  37763. yAdjust += parent.getContentBox().bottom;
  37764. yAdjust += parent.getStyle('margin-bottom');
  37765. yAdjust += child.getStyle('margin-top');
  37766. }
  37767. this.move(children, xAdjust, yAdjust);
  37768. if (round == 2) {
  37769. children.forEach(function(child) {
  37770. var m = child.getLayoutTransform();
  37771. var cbox = child.getContentBox();
  37772. var pin = m.transformPoint(new kity.Point(cbox.left, 0));
  37773. layout.move([child], abs(pin.y - pout.y), 0);
  37774. });
  37775. }
  37776. }
  37777. }));
  37778. /**
  37779. * @fileOverview
  37780. *
  37781. * 天盘模板
  37782. *
  37783. * @author: along
  37784. * @copyright: bpd729@163.com, 2015
  37785. */
  37786. KityMinder.registerLayout('tianpan', kity.createClass({
  37787. base: Layout,
  37788. doLayout: function (parent, children) {
  37789. if (children.length == 0) return;
  37790. var layout = this;
  37791. var pbox = parent.getContentBox();
  37792. var x, y,box;
  37793. var _theta = 5;
  37794. var _r = Math.max(pbox.width, 50);
  37795. children.forEach(function (child, index) {
  37796. child.setLayoutTransform(new kity.Matrix());
  37797. box = layout.getTreeBox(child);
  37798. _r = Math.max(Math.max(box.width, box.height), _r);
  37799. })
  37800. _r = _r / 1.5 / Math.PI;
  37801. children.forEach(function (child, index) {
  37802. x = _r * (Math.cos(_theta) + Math.sin(_theta) * _theta);
  37803. y = _r * (Math.sin(_theta) - Math.cos(_theta) * _theta);
  37804. _theta += (0.9 - index * 0.02);
  37805. child.setLayoutVectorIn(new kity.Vector(1, 0));
  37806. child.setVertexIn(new kity.Point(pbox.cx, pbox.cy));
  37807. child.setLayoutTransform(new kity.Matrix());
  37808. layout.move([child], x, y);
  37809. });
  37810. },
  37811. getOrderHint: function (node) {
  37812. var hint = [];
  37813. var box = node.getLayoutBox();
  37814. var offset = 5;
  37815. hint.push({
  37816. type: 'up',
  37817. node: node,
  37818. area: {
  37819. x: box.x,
  37820. y: box.top - node.getStyle('margin-top') - offset,
  37821. width: box.width,
  37822. height: node.getStyle('margin-top')
  37823. },
  37824. path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
  37825. });
  37826. hint.push({
  37827. type: 'down',
  37828. node: node,
  37829. area: {
  37830. x: box.x,
  37831. y: box.bottom + offset,
  37832. width: box.width,
  37833. height: node.getStyle('margin-bottom')
  37834. },
  37835. path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
  37836. });
  37837. return hint;
  37838. }
  37839. }));
  37840. /**
  37841. * @fileOverview
  37842. *
  37843. * 提供折线相连的方法
  37844. *
  37845. * @author: techird
  37846. * @copyright: Baidu FEX, 2014
  37847. */
  37848. KityMinder.registerConnectProvider('bezier', function(node, parent, connection) {
  37849. // 连线起点和终点
  37850. var po = parent.getLayoutVertexOut(),
  37851. pi = node.getLayoutVertexIn();
  37852. // 连线矢量和方向
  37853. var v = parent.getLayoutVectorOut().normalize();
  37854. var r = Math.round;
  37855. var abs = Math.abs;
  37856. var pathData = [];
  37857. pathData.push('M', r(po.x), r(po.y));
  37858. if (abs(v.x) > abs(v.y)) {
  37859. // x - direction
  37860. var hx = (pi.x + po.x) / 2;
  37861. pathData.push('C', hx, po.y, hx, pi.y, pi.x, pi.y);
  37862. } else {
  37863. // y - direction
  37864. var hy = (pi.y + po.y) / 2;
  37865. pathData.push('C', po.x, hy, pi.x, hy, pi.x, pi.y);
  37866. }
  37867. connection.setMarker(null);
  37868. connection.setPathData(pathData);
  37869. });
  37870. /**
  37871. * @fileOverview
  37872. *
  37873. * 提供折线相连的方法
  37874. *
  37875. * @author: techird
  37876. * @copyright: Baidu FEX, 2014
  37877. */
  37878. KityMinder.registerConnectProvider('poly', function(node, parent, connection, width) {
  37879. // 连线起点和终点
  37880. var po = parent.getLayoutVertexOut(),
  37881. pi = node.getLayoutVertexIn();
  37882. // 连线矢量和方向
  37883. var v = parent.getLayoutVectorOut().normalize();
  37884. var r = Math.round;
  37885. var abs = Math.abs;
  37886. var pathData = [];
  37887. pathData.push('M', r(po.x), r(po.y));
  37888. switch (true) {
  37889. case abs(v.x) > abs(v.y) && v.x < 0:
  37890. // left
  37891. pathData.push('h', -parent.getStyle('margin-left'));
  37892. pathData.push('v', pi.y - po.y);
  37893. pathData.push('H', pi.x);
  37894. break;
  37895. case abs(v.x) > abs(v.y) && v.x >= 0:
  37896. // right
  37897. pathData.push('h', parent.getStyle('margin-right'));
  37898. pathData.push('v', pi.y - po.y);
  37899. pathData.push('H', pi.x);
  37900. break;
  37901. case abs(v.x) <= abs(v.y) && v.y < 0:
  37902. // top
  37903. pathData.push('v', -parent.getStyle('margin-top'));
  37904. pathData.push('h', pi.x - po.x);
  37905. pathData.push('V', pi.y);
  37906. break;
  37907. case abs(v.x) <= abs(v.y) && v.y >= 0:
  37908. // bottom
  37909. pathData.push('v', parent.getStyle('margin-bottom'));
  37910. pathData.push('h', pi.x - po.x);
  37911. pathData.push('V', pi.y);
  37912. break;
  37913. }
  37914. connection.setMarker(null);
  37915. connection.setPathData(pathData);
  37916. });
  37917. /**
  37918. * @fileOverview
  37919. *
  37920. * 圆弧连线
  37921. *
  37922. * @author: techird
  37923. * @copyright: Baidu FEX, 2014
  37924. */
  37925. var connectMarker = new kity.Marker().pipe(function() {
  37926. var r = 7;
  37927. var dot = new kity.Circle(r - 1);
  37928. this.addShape(dot);
  37929. this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r);
  37930. this.dot = dot;
  37931. this.node.setAttribute('markerUnits', 'userSpaceOnUse');
  37932. });
  37933. KityMinder.registerConnectProvider('arc', function(node, parent, connection, width, color) {
  37934. var box = node.getLayoutBox(),
  37935. pBox = parent.getLayoutBox();
  37936. var start, end, vector;
  37937. var abs = Math.abs;
  37938. var pathData = [];
  37939. var side = box.x > pBox.x ? 'right' : 'left';
  37940. node.getMinder().getPaper().addResource(connectMarker);
  37941. start = new kity.Point(pBox.cx, pBox.cy);
  37942. end = side == 'left' ?
  37943. new kity.Point(box.right + 2, box.cy) :
  37944. new kity.Point(box.left - 2, box.cy);
  37945. vector = kity.Vector.fromPoints(start, end);
  37946. pathData.push('M', start);
  37947. pathData.push('A', abs(vector.x), abs(vector.y), 0, 0, (vector.x * vector.y > 0 ? 0 : 1), end);
  37948. connection.setMarker(connectMarker);
  37949. connectMarker.dot.fill(color);
  37950. connection.setPathData(pathData);
  37951. });
  37952. /**
  37953. * @fileOverview
  37954. *
  37955. * 下划线连线
  37956. *
  37957. * @author: techird
  37958. * @copyright: Baidu FEX, 2014
  37959. */
  37960. KityMinder.registerConnectProvider('under', function(node, parent, connection, width, color) {
  37961. var box = node.getLayoutBox(),
  37962. pBox = parent.getLayoutBox();
  37963. var start, end, vector;
  37964. var abs = Math.abs;
  37965. var pathData = [];
  37966. var side = box.x > pBox.x ? 'right' : 'left';
  37967. var radius = node.getStyle('connect-radius');
  37968. var underY = box.bottom + 3;
  37969. var startY = parent.getType() == 'sub' ? pBox.bottom + 3 : pBox.cy;
  37970. var p1, p2, p3, mx;
  37971. if (side == 'right') {
  37972. p1 = new kity.Point(pBox.right, startY);
  37973. p2 = new kity.Point(box.left - 10, underY);
  37974. p3 = new kity.Point(box.right, underY);
  37975. } else {
  37976. p1 = new kity.Point(pBox.left, startY);
  37977. p2 = new kity.Point(box.right + 10, underY);
  37978. p3 = new kity.Point(box.left, underY);
  37979. }
  37980. mx = (p1.x + p2.x) / 2;
  37981. pathData.push('M', p1);
  37982. pathData.push('C', mx, p1.y, mx, p2.y, p2);
  37983. pathData.push('L', p3);
  37984. connection.setMarker(null);
  37985. connection.setPathData(pathData);
  37986. });
  37987. /**
  37988. * @fileOverview
  37989. *
  37990. * "L" 连线
  37991. *
  37992. * @author: techird
  37993. * @copyright: Baidu FEX, 2014
  37994. */
  37995. KityMinder.registerConnectProvider('l', function(node, parent, connection) {
  37996. var po = parent.getLayoutVertexOut();
  37997. var pi = node.getLayoutVertexIn();
  37998. var vo = parent.getLayoutVectorOut();
  37999. var pathData = [];
  38000. var r = Math.round,
  38001. abs = Math.abs;
  38002. pathData.push('M', po.round());
  38003. if (abs(vo.x) > abs(vo.y)) {
  38004. pathData.push('H', r(pi.x));
  38005. } else {
  38006. pathData.push('V', pi.y);
  38007. }
  38008. pathData.push('L', pi);
  38009. connection.setPathData(pathData);
  38010. });
  38011. /**
  38012. * @fileOverview
  38013. *
  38014. * 鱼骨头主干连线
  38015. *
  38016. * @author: techird
  38017. * @copyright: Baidu FEX, 2014
  38018. */
  38019. KityMinder.registerConnectProvider('fish-bone-master', function(node, parent, connection) {
  38020. var pout = parent.getLayoutVertexOut(),
  38021. pin = node.getLayoutVertexIn();
  38022. var abs = Math.abs;
  38023. var dy = abs(pout.y - pin.y),
  38024. dx = abs(pout.x - pin.x);
  38025. var pathData = [];
  38026. pathData.push('M', pout.x, pout.y);
  38027. pathData.push('h', dx - dy);
  38028. pathData.push('L', pin.x, pin.y);
  38029. connection.setMarker(null);
  38030. connection.setPathData(pathData);
  38031. });
  38032. /**
  38033. *
  38034. * 圆弧连线
  38035. *
  38036. * @author: along
  38037. * @copyright: bpd729@163.com , 2015
  38038. */
  38039. var connectMarker = new kity.Marker().pipe(function () {
  38040. var r = 7;
  38041. var dot = new kity.Circle(r - 1);
  38042. this.addShape(dot);
  38043. this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r);
  38044. this.dot = dot;
  38045. this.node.setAttribute('markerUnits', 'userSpaceOnUse');
  38046. });
  38047. KityMinder.registerConnectProvider('arc_tp', function (node, parent, connection, width, color) {
  38048. var end_box = node.getLayoutBox(),
  38049. start_box = parent.getLayoutBox();
  38050. if (node.getIndex() > 0) {
  38051. var index = node.getIndex();
  38052. start_box = parent.getChildren()[index - 1].getLayoutBox();
  38053. }
  38054. var start, end, vector;
  38055. var abs = Math.abs;
  38056. var pathData = [];
  38057. var side = end_box.x > start_box.x ? 'right' : 'left';
  38058. node.getMinder().getPaper().addResource(connectMarker);
  38059. start = new kity.Point(start_box.cx, start_box.cy);
  38060. end = new kity.Point(end_box.cx, end_box.cy);
  38061. var jl = Math.sqrt(Math.abs(start.x - end.x) * Math.abs(start.x - end.x) + Math.abs(start.y - end.y) * Math.abs(start.y - end.y)); //两圆中心点距离
  38062. jl = node.getIndex() == 0 ? jl * 0.4 : jl;
  38063. vector = kity.Vector.fromPoints(start, end);
  38064. pathData.push('M', start);
  38065. pathData.push('A', jl, jl, 0, 0, 1, end);
  38066. connection.setMarker(connectMarker);
  38067. connectMarker.dot.fill(color);
  38068. connection.setPathData(pathData);
  38069. });
  38070. ['classic', 'classic-compact'].forEach(function(name) {
  38071. var compact = name == 'classic-compact';
  38072. KityMinder.registerTheme(name, {
  38073. 'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat',
  38074. 'root-color': '#430',
  38075. 'root-background': '#e9df98',
  38076. 'root-stroke': '#e9df98',
  38077. 'root-font-size': 24,
  38078. 'root-padding': compact ? [10, 25] : [15, 25],
  38079. 'root-margin': compact ? [15, 25] : [30, 100],
  38080. 'root-radius': 30,
  38081. 'root-space': 10,
  38082. 'root-shadow': 'rgba(0, 0, 0, .25)',
  38083. 'main-color': '#333',
  38084. 'main-background': '#a4c5c0',
  38085. 'main-stroke': '#a4c5c0',
  38086. 'main-font-size': 16,
  38087. 'main-padding': compact ? [5, 15] : [6, 20],
  38088. 'main-margin': compact ? [5, 10] : 20,
  38089. 'main-radius': 10,
  38090. 'main-space': 5,
  38091. 'main-shadow': 'rgba(0, 0, 0, .25)',
  38092. 'sub-color': 'white',
  38093. 'sub-background': 'transparent',
  38094. 'sub-stroke': 'none',
  38095. 'sub-font-size': 12,
  38096. 'sub-padding': [5, 10],
  38097. 'sub-margin': compact ? [5, 10] : [15, 20],
  38098. 'sub-tree-margin': 30,
  38099. 'sub-radius': 5,
  38100. 'sub-space': 5,
  38101. 'connect-color': 'white',
  38102. 'connect-width': 2,
  38103. 'main-connect-width': 3,
  38104. 'connect-radius': 5,
  38105. 'selected-background': 'rgb(254, 219, 0)',
  38106. 'selected-stroke': 'rgb(254, 219, 0)',
  38107. 'selected-color': 'black',
  38108. 'marquee-background': 'rgba(255,255,255,.3)',
  38109. 'marquee-stroke': 'white',
  38110. 'drop-hint-color': 'yellow',
  38111. 'sub-drop-hint-width': 2,
  38112. 'main-drop-hint-width': 4,
  38113. 'root-drop-hint-width': 4,
  38114. 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
  38115. 'order-hint-path-color': '#0f0',
  38116. 'order-hint-path-width': 1,
  38117. 'text-selection-color': 'rgb(27,171,255)',
  38118. 'line-height':1.5
  38119. });
  38120. });
  38121. ['snow', 'snow-compact'].forEach(function(name) {
  38122. var compact = name == 'snow-compact';
  38123. KityMinder.registerTheme(name, {
  38124. 'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat',
  38125. 'root-color': '#430',
  38126. 'root-background': '#e9df98',
  38127. 'root-stroke': '#e9df98',
  38128. 'root-font-size': 24,
  38129. 'root-padding': compact ? [5, 10] : [15, 25],
  38130. 'root-margin': compact ? 15 : 30,
  38131. 'root-radius': 5,
  38132. 'root-space': 10,
  38133. 'root-shadow': 'rgba(0, 0, 0, .25)',
  38134. 'main-color': '#333',
  38135. 'main-background': '#a4c5c0',
  38136. 'main-stroke': '#a4c5c0',
  38137. 'main-font-size': 16,
  38138. 'main-padding': compact ? [4, 10] : [6, 20],
  38139. 'main-margin': compact ? [5, 10] : [20, 40],
  38140. 'main-radius': 5,
  38141. 'main-space': 5,
  38142. 'main-shadow': 'rgba(0, 0, 0, .25)',
  38143. 'sub-color': 'black',
  38144. 'sub-background': 'white',
  38145. 'sub-stroke': 'white',
  38146. 'sub-font-size': 12,
  38147. 'sub-padding': [5, 10],
  38148. 'sub-margin': compact ? [5, 10] : [10, 20],
  38149. 'sub-radius': 5,
  38150. 'sub-space': 5,
  38151. 'connect-color': 'white',
  38152. 'connect-width': 2,
  38153. 'main-connect-width': 3,
  38154. 'connect-radius': 5,
  38155. 'selected-background': 'rgb(254, 219, 0)',
  38156. 'selected-stroke': 'rgb(254, 219, 0)',
  38157. 'marquee-background': 'rgba(255,255,255,.3)',
  38158. 'marquee-stroke': 'white',
  38159. 'drop-hint-color': 'yellow',
  38160. 'drop-hint-width': 4,
  38161. 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
  38162. 'order-hint-path-color': '#0f0',
  38163. 'order-hint-path-width': 1,
  38164. 'text-selection-color': 'rgb(27,171,255)',
  38165. 'line-height':1.5
  38166. });
  38167. });
  38168. (function() {
  38169. function hsl(h, s, l) {
  38170. return kity.Color.createHSL(h, s, l);
  38171. }
  38172. function generate(h, compat) {
  38173. return {
  38174. 'background': '#fbfbfb',
  38175. 'root-color': 'white',
  38176. 'root-background': hsl(h, 37, 60),
  38177. 'root-stroke': hsl(h, 37, 60),
  38178. 'root-font-size': 16,
  38179. 'root-padding': compat ? [6, 12] : [12, 24],
  38180. 'root-margin': compat ? 10 : [30, 100],
  38181. 'root-radius': 5,
  38182. 'root-space': 10,
  38183. 'main-color': 'black',
  38184. 'main-background': hsl(h, 33, 95),
  38185. 'main-stroke': hsl(h, 37, 60),
  38186. 'main-stroke-width': 1,
  38187. 'main-font-size': 14,
  38188. 'main-padding': [6, 20],
  38189. 'main-margin': compat ? 8 : 20,
  38190. 'main-radius': 3,
  38191. 'main-space': 5,
  38192. 'sub-color': 'black',
  38193. 'sub-background': 'transparent',
  38194. 'sub-stroke': 'none',
  38195. 'sub-font-size': 12,
  38196. 'sub-padding': compat ? [3, 5] : [5, 10],
  38197. 'sub-margin': compat ? [4, 8] : [15, 20],
  38198. 'sub-radius': 5,
  38199. 'sub-space': 5,
  38200. 'connect-color': hsl(h, 37, 60),
  38201. 'connect-width': 1,
  38202. 'connect-radius': 5,
  38203. 'selected-stroke': hsl(h, 26, 30),
  38204. 'selected-stroke-width': '3',
  38205. 'marquee-background': hsl(h, 100, 80).set('a', 0.1),
  38206. 'marquee-stroke': hsl(h, 37, 60),
  38207. 'drop-hint-color': hsl(h, 26, 35),
  38208. 'drop-hint-width': 5,
  38209. 'order-hint-area-color': hsl(h, 100, 30).set('a', 0.5),
  38210. 'order-hint-path-color': hsl(h, 100, 25),
  38211. 'order-hint-path-width': 1,
  38212. 'text-selection-color': hsl(h, 100, 20),
  38213. 'line-height':1.5
  38214. };
  38215. }
  38216. var plans = {
  38217. red: 0,
  38218. soil: 25,
  38219. green: 122,
  38220. blue: 204,
  38221. purple: 246,
  38222. pink: 334
  38223. };
  38224. var name;
  38225. for (name in plans) {
  38226. KityMinder.registerTheme('fresh-' + name, generate(plans[name]));
  38227. KityMinder.registerTheme('fresh-' + name + '-compat', generate(plans[name], true));
  38228. }
  38229. })();
  38230. KityMinder.registerTheme('fish', {
  38231. 'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat',
  38232. 'root-color': '#430',
  38233. 'root-background': '#e9df98',
  38234. 'root-stroke': '#e9df98',
  38235. 'root-font-size': 24,
  38236. 'root-padding': [35, 35],
  38237. 'root-margin': 30,
  38238. 'root-radius': 100,
  38239. 'root-space': 10,
  38240. 'root-shadow': 'rgba(0, 0, 0, .25)',
  38241. 'main-color': '#333',
  38242. 'main-background': '#a4c5c0',
  38243. 'main-stroke': '#a4c5c0',
  38244. 'main-font-size': 16,
  38245. 'main-padding': [6, 20],
  38246. 'main-margin': [20, 20],
  38247. 'main-radius': 5,
  38248. 'main-space': 5,
  38249. 'main-shadow': 'rgba(0, 0, 0, .25)',
  38250. 'sub-color': 'black',
  38251. 'sub-background': 'white',
  38252. 'sub-stroke': 'white',
  38253. 'sub-font-size': 12,
  38254. 'sub-padding': [5, 10],
  38255. 'sub-margin': [10],
  38256. 'sub-radius': 5,
  38257. 'sub-space': 5,
  38258. 'connect-color': 'white',
  38259. 'connect-width': 3,
  38260. 'main-connect-width': 3,
  38261. 'connect-radius': 5,
  38262. 'selected-background': 'rgb(254, 219, 0)',
  38263. 'selected-stroke': 'rgb(254, 219, 0)',
  38264. 'marquee-background': 'rgba(255,255,255,.3)',
  38265. 'marquee-stroke': 'white',
  38266. 'drop-hint-color': 'yellow',
  38267. 'drop-hint-width': 4,
  38268. 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
  38269. 'order-hint-path-color': '#0f0',
  38270. 'order-hint-path-width': 1,
  38271. 'text-selection-color': 'rgb(27,171,255)',
  38272. 'line-height':1.5
  38273. });
  38274. KityMinder.registerTheme('wire', {
  38275. 'background': 'black',
  38276. 'color': '#999',
  38277. 'stroke': 'none',
  38278. 'padding': 10,
  38279. 'margin': 20,
  38280. 'font-size': 14,
  38281. 'connect-color': '#999',
  38282. 'connect-width': 1,
  38283. 'selected-background': '#999',
  38284. 'selected-color': 'black',
  38285. 'marquee-background': 'rgba(255,255,255,.3)',
  38286. 'marquee-stroke': 'white',
  38287. 'drop-hint-color': 'yellow',
  38288. 'sub-drop-hint-width': 2,
  38289. 'main-drop-hint-width': 4,
  38290. 'root-drop-hint-width': 4,
  38291. 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
  38292. 'order-hint-path-color': '#0f0',
  38293. 'order-hint-path-width': 1,
  38294. 'text-selection-color': 'rgb(27,171,255)',
  38295. 'line-height':1.5
  38296. });
  38297. ['tianpan', 'tianpan-compact'].forEach(function (name) {
  38298. var compact = name == 'tianpan-compact';
  38299. KityMinder.registerTheme(name, {
  38300. 'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat',
  38301. 'root-color': '#430',
  38302. 'root-background': '#e9df98',
  38303. 'root-stroke': '#e9df98',
  38304. 'root-font-size': 25,
  38305. 'root-padding': compact ? 15 : 20,
  38306. 'root-margin': compact ? [15, 25] : 100,
  38307. 'root-radius': 30,
  38308. 'root-space': 10,
  38309. 'root-shadow': 'rgba(0, 0, 0, .25)',
  38310. 'root-shape': 'circle',
  38311. 'main-color': '#333',
  38312. 'main-background': '#a4c5c0',
  38313. 'main-stroke': '#a4c5c0',
  38314. 'main-font-size': 15,
  38315. 'main-padding': compact ? 10 : 12,
  38316. 'main-margin': compact ? 10 : 12,
  38317. 'main-radius': 10,
  38318. 'main-space': 5,
  38319. 'main-shadow': 'rgba(0, 0, 0, .25)',
  38320. 'main-shape': 'circle',
  38321. 'sub-color': '#333',
  38322. 'sub-background': '#99ca6a',
  38323. 'sub-stroke': '#a4c5c0',
  38324. 'sub-font-size': 13,
  38325. 'sub-padding': 5,
  38326. 'sub-margin': compact ? 6 : 10,
  38327. 'sub-tree-margin': 30,
  38328. 'sub-radius': 5,
  38329. 'sub-space': 5,
  38330. 'sub-shadow': 'rgba(0, 0, 0, .25)',
  38331. 'sub-shape': 'circle',
  38332. 'connect-color': 'white',
  38333. 'connect-width': 2,
  38334. 'main-connect-width': 3,
  38335. 'connect-radius': 5,
  38336. 'selected-background': 'rgb(254, 219, 0)',
  38337. 'selected-stroke': 'rgb(254, 219, 0)',
  38338. 'selected-color': 'black',
  38339. 'marquee-background': 'rgba(255,255,255,.3)',
  38340. 'marquee-stroke': 'white',
  38341. 'drop-hint-color': 'yellow',
  38342. 'sub-drop-hint-width': 2,
  38343. 'main-drop-hint-width': 4,
  38344. 'root-drop-hint-width': 4,
  38345. 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
  38346. 'order-hint-path-color': '#0f0',
  38347. 'order-hint-path-width': 1,
  38348. 'text-selection-color': 'rgb(27,171,255)',
  38349. 'line-height': 1.4
  38350. });
  38351. });
  38352. /**
  38353. * @fileOverview
  38354. *
  38355. * 默认模板 - 脑图模板
  38356. *
  38357. * @author: techird
  38358. * @copyright: Baidu FEX, 2014
  38359. */
  38360. KityMinder.registerTemplate('default', {
  38361. getLayout: function(node) {
  38362. if (node.getData('layout')) return node.getData('layout');
  38363. var level = node.getLevel();
  38364. // 根节点
  38365. if (level === 0) {
  38366. return 'mind';
  38367. }
  38368. // 一级节点
  38369. if (level === 1) {
  38370. return node.getLayoutPointPreview().x > 0 ? 'right': 'left';
  38371. }
  38372. return node.parent.getLayout();
  38373. },
  38374. getConnect: function(node) {
  38375. if (node.getLevel() == 1) return 'arc';
  38376. return 'under';
  38377. }
  38378. });
  38379. /**
  38380. * @fileOverview
  38381. *
  38382. * 组织结构图模板
  38383. *
  38384. * @author: techird
  38385. * @copyright: Baidu FEX, 2014
  38386. */
  38387. KityMinder.registerTemplate('structure', {
  38388. getLayout: function(node) {
  38389. return node.getData('layout') || 'bottom';
  38390. },
  38391. getConnect: function(node) {
  38392. return 'poly';
  38393. }
  38394. });
  38395. /**
  38396. * @fileOverview
  38397. *
  38398. * 文件夹模板
  38399. *
  38400. * @author: techird
  38401. * @copyright: Baidu FEX, 2014
  38402. */
  38403. KityMinder.registerTemplate('filetree', {
  38404. getLayout: function(node) {
  38405. if (node.getData('layout')) return node.getData('layout');
  38406. if (node.isRoot()) return 'bottom';
  38407. return 'filetree-down';
  38408. },
  38409. getConnect: function(node) {
  38410. if (node.getLevel() == 1) {
  38411. return 'poly';
  38412. }
  38413. return 'l';
  38414. }
  38415. });
  38416. /**
  38417. * @fileOverview
  38418. *
  38419. * 往右布局结构模板
  38420. *
  38421. * @author: techird
  38422. * @copyright: Baidu FEX, 2014
  38423. */
  38424. KityMinder.registerTemplate('right', {
  38425. getLayout: function(node) {
  38426. return node.getData('layout') || 'right';
  38427. },
  38428. getConnect: function(node) {
  38429. if (node.getLevel() == 1) return 'arc';
  38430. return 'bezier';
  38431. }
  38432. });
  38433. /**
  38434. * @fileOverview
  38435. *
  38436. * 默认模板 - 鱼骨头模板
  38437. *
  38438. * @author: techird
  38439. * @copyright: Baidu FEX, 2014
  38440. */
  38441. KityMinder.registerTemplate('fish-bone', {
  38442. getLayout: function(node) {
  38443. if (node.getData('layout')) return node.getData('layout');
  38444. var level = node.getLevel();
  38445. // 根节点
  38446. if (level === 0) {
  38447. return 'fish-bone-master';
  38448. }
  38449. // 一级节点
  38450. if (level === 1) {
  38451. return 'fish-bone-slave';
  38452. }
  38453. return node.getLayoutPointPreview().y > 0 ? 'filetree-up': 'filetree-down';
  38454. },
  38455. getConnect: function(node) {
  38456. switch (node.getLevel()) {
  38457. case 1: return 'fish-bone-master';
  38458. case 2: return 'line';
  38459. default: return 'l';
  38460. }
  38461. }
  38462. });
  38463. /**
  38464. * @fileOverview
  38465. *
  38466. * 天盘模板
  38467. *
  38468. * @author: along
  38469. * @copyright: bpd729@163.com, 2015
  38470. */
  38471. KityMinder.registerTemplate('tianpan', {
  38472. getLayout: function (node) {
  38473. if (node.getData('layout')) return node.getData('layout');
  38474. var level = node.getLevel();
  38475. // 根节点
  38476. if (level === 0) {
  38477. return 'tianpan';
  38478. }
  38479. return node.parent.getLayout();
  38480. },
  38481. getConnect: function (node) {
  38482. return 'arc_tp';
  38483. }
  38484. });
  38485. var AppendChildCommand = kity.createClass('AppendChildCommand', {
  38486. base: Command,
  38487. execute: function(km, text) {
  38488. var parent = km.getSelectedNode();
  38489. if (!parent) {
  38490. return null;
  38491. }
  38492. text = text || km.getLang('topic');
  38493. parent.expand();
  38494. var node = km.createNode(text, parent);
  38495. km.select(node, true);
  38496. node.render();
  38497. km.layout(600);
  38498. },
  38499. queryState: function(km) {
  38500. var selectedNode = km.getSelectedNode();
  38501. return selectedNode ? 0 : -1;
  38502. }
  38503. });
  38504. var AppendSiblingCommand = kity.createClass('AppendSiblingCommand', {
  38505. base: Command,
  38506. execute: function(km, text) {
  38507. var sibling = km.getSelectedNode();
  38508. var parent = sibling.parent;
  38509. if (!parent) {
  38510. return km.execCommand('AppendChildNode', text);
  38511. }
  38512. text = text || km.getLang('topic');
  38513. var node = km.createNode(text, parent, sibling.getIndex() + 1);
  38514. km.select(node, true);
  38515. node.render();
  38516. km.layout(600);
  38517. },
  38518. queryState: function(km) {
  38519. var selectedNode = km.getSelectedNode();
  38520. return selectedNode ? 0 : -1;
  38521. }
  38522. });
  38523. var RemoveNodeCommand = kity.createClass('RemoverNodeCommand', {
  38524. base: Command,
  38525. execute: function(km, text) {
  38526. var nodes = km.getSelectedNodes();
  38527. var ancestor = MinderNode.getCommonAncestor.apply(null, nodes);
  38528. nodes.forEach(function(node) {
  38529. if (!node.isRoot()) km.removeNode(node);
  38530. });
  38531. km.select(ancestor || km.getRoot(), true);
  38532. km.layout(600);
  38533. },
  38534. queryState: function(km) {
  38535. var selectedNode = km.getSelectedNode();
  38536. return selectedNode ? 0 : -1;
  38537. }
  38538. });
  38539. var EditNodeCommand = kity.createClass('EditNodeCommand', {
  38540. base: Command,
  38541. execute: function(km) {
  38542. var selectedNode = km.getSelectedNode();
  38543. if (!selectedNode) {
  38544. return null;
  38545. }
  38546. km.select(selectedNode, true);
  38547. km.textEditNode(selectedNode);
  38548. },
  38549. queryState: function(km) {
  38550. var selectedNode = km.getSelectedNode();
  38551. if (!selectedNode) {
  38552. return -1;
  38553. }
  38554. else {
  38555. return 0;
  38556. }
  38557. },
  38558. isNeedUndo: function() {
  38559. return false;
  38560. }
  38561. });
  38562. var $importDialog;
  38563. var $exportDialog;
  38564. var ImportTextNode = kity.createClass('ImportTextNode', {
  38565. base: Command,
  38566. execute: function(km, text) {
  38567. if (!$importDialog) {
  38568. var plainProtocol = km.getProtocol('plain');
  38569. var height = 400;
  38570. $importDialog = new FUI.Dialog({
  38571. width: 600,
  38572. height: height,
  38573. prompt: true,
  38574. caption: km.getLang('ui.importtextnode')
  38575. }).appendTo(document.getElementById('content-wrapper'));
  38576. var $dialogBody = $($importDialog.getBodyElement());
  38577. $dialogBody.html([
  38578. '<textarea style="width: 100%; height: ' + (height - 130) + 'px"></textarea>'
  38579. ].join(''));
  38580. var $editor = $dialogBody.find('textarea');
  38581. var $ok = $importDialog.getButton(0);
  38582. var $errorMsg = $('<span class="validate-error"></span>');
  38583. var rootNode;
  38584. function check(value) {
  38585. var error;
  38586. if (!value) {
  38587. error = '内容不能为空';
  38588. }
  38589. else {
  38590. try {
  38591. rootNode = plainProtocol.decode(value, true);
  38592. }
  38593. catch (ex) {
  38594. error = '文本格式解析错误. ' + ex.message;
  38595. }
  38596. }
  38597. if (error) {
  38598. $editor.addClass('validate-error');
  38599. $errorMsg.text(error);
  38600. $ok.disable();
  38601. }
  38602. else {
  38603. $editor.removeClass('validate-error');
  38604. $errorMsg.text('');
  38605. $ok.enable();
  38606. }
  38607. }
  38608. $editor.after($errorMsg);
  38609. $editor.on('input', function() {
  38610. check($editor.val());
  38611. });
  38612. $editor.on('keydown keyup', function(e) {
  38613. if (e.keyCode === 9 && e.type === 'keydown') {
  38614. e.preventDefault();
  38615. var s = this.selectionStart;
  38616. this.value = this.value.substring(0, this.selectionStart) + '\t' +
  38617. this.value.substring(this.selectionEnd);
  38618. this.selectionEnd = s + 1;
  38619. }
  38620. if (e.keyCode === 13 && !e.shiftKey) {
  38621. return;
  38622. }
  38623. e.stopPropagation();
  38624. });
  38625. $importDialog.on('open', function() {
  38626. check($editor.val());
  38627. setTimeout(function() {
  38628. $editor[0].focus();
  38629. }, 10);
  38630. });
  38631. $importDialog.on('ok', function() {
  38632. var _selectedNodes = [];
  38633. function appendChild(parent, child, index) {
  38634. if (!parent || !child) {
  38635. return;
  38636. }
  38637. var kmNode = km.createNode(child.data.text, parent);
  38638. if (child.children) {
  38639. child.children.forEach(function(item) {
  38640. appendChild(kmNode, item);
  38641. });
  38642. }
  38643. kmNode.render();
  38644. return kmNode;
  38645. }
  38646. var selectedNode = km.getSelectedNode();
  38647. if (rootNode && rootNode.children && selectedNode) {
  38648. selectedNode.expand();
  38649. rootNode.children.forEach(function(child) {
  38650. _selectedNodes.push(appendChild(selectedNode, child));
  38651. });
  38652. }
  38653. km.select(_selectedNodes, true);
  38654. km.layout(300);
  38655. $editor.val('');
  38656. _selectedNodes = null;
  38657. rootNode = null;
  38658. });
  38659. }
  38660. $importDialog.open();
  38661. },
  38662. queryState: function(km) {
  38663. var selectedNode = km.getSelectedNode();
  38664. return selectedNode ? 0 : -1;
  38665. }
  38666. });
  38667. var ExportTextNode = kity.createClass('ExportTextNode', {
  38668. base: Command,
  38669. execute: function(km, text) {
  38670. if (!$exportDialog) {
  38671. var plainProtocol = km.getProtocol('plain');
  38672. var height = 400;
  38673. $exportDialog = new FUI.Dialog({
  38674. width: 600,
  38675. height: height,
  38676. prompt: true,
  38677. caption: km.getLang('ui.exporttextnode')
  38678. }).appendTo(document.getElementById('content-wrapper'));
  38679. var $dialogBody = $($exportDialog.getBodyElement());
  38680. $dialogBody.html([
  38681. '<textarea style="width: 100%; height: ' + (height - 130) + 'px"></textarea>'
  38682. ].join(''));
  38683. var $editor = $dialogBody.find('textarea');
  38684. $editor.on('keydown keyup', function(e) {
  38685. if (e.keyCode === 9 && e.type === 'keydown') {
  38686. e.preventDefault();
  38687. var s = this.selectionStart;
  38688. this.value = this.value.substring(0, this.selectionStart) + '\t' +
  38689. this.value.substring(this.selectionEnd);
  38690. this.selectionEnd = s + 1;
  38691. }
  38692. if (e.keyCode === 13 && !e.shiftKey) {
  38693. return;
  38694. }
  38695. e.stopPropagation();
  38696. });
  38697. $exportDialog.on('open', function() {
  38698. $editor.val(plainProtocol.encode(km.getSelectedNode()));
  38699. setTimeout(function() {
  38700. $editor[0].focus();
  38701. }, 10);
  38702. });
  38703. }
  38704. $exportDialog.open();
  38705. },
  38706. queryState: function(km) {
  38707. var selectedNode = km.getSelectedNode();
  38708. return selectedNode ? 0 : -1;
  38709. }
  38710. });
  38711. KityMinder.registerModule('NodeModule', function() {
  38712. return {
  38713. commands: {
  38714. 'AppendChildNode': AppendChildCommand,
  38715. 'AppendSiblingNode': AppendSiblingCommand,
  38716. 'ImportTextNode': ImportTextNode,
  38717. 'ExportTextNode': ExportTextNode,
  38718. 'RemoveNode': RemoveNodeCommand,
  38719. 'EditNode': EditNodeCommand
  38720. },
  38721. 'contextmenu': [{
  38722. command: 'appendsiblingnode'
  38723. }, {
  38724. command: 'appendchildnode'
  38725. }, {
  38726. command: 'editnode'
  38727. }, {
  38728. command: 'removenode'
  38729. }, {
  38730. command: 'importtextnode'
  38731. }, {
  38732. command: 'exporttextnode'
  38733. }, {
  38734. divider: 1
  38735. }],
  38736. 'commandShortcutKeys': {
  38737. 'appendsiblingnode': 'normal::Enter',
  38738. 'appendchildnode': 'normal::Insert|Tab',
  38739. 'editnode': 'normal::F2',
  38740. 'removenode': 'normal::Del|Backspace'
  38741. }
  38742. };
  38743. });
  38744. /* global Renderer: true */
  38745. var FONT_ADJUST = {
  38746. '微软雅黑,Microsoft YaHei': -0.15,
  38747. 'arial black,avant garde': -0.17,
  38748. 'default': -0.15
  38749. };
  38750. var TextRenderer = KityMinder.TextRenderer = kity.createClass('TextRenderer', {
  38751. base: Renderer,
  38752. create: function() {
  38753. return new kity.Group().setId(KityMinder.uuid('node_text'));
  38754. },
  38755. update: function(textGroup, node) {
  38756. function s(name) {
  38757. return node.getData(name) || node.getStyle(name);
  38758. }
  38759. var textArr = node.getText(true);
  38760. var lineHeight = node.getStyle('line-height');
  38761. var fontSize = s('font-size');
  38762. var fontFamily = s('font-family') || 'default';
  38763. var height = (lineHeight * fontSize) * textArr.length - (lineHeight - 1) * fontSize;
  38764. var yStart = -height / 2;
  38765. var adjust = FONT_ADJUST[fontFamily] || 0;
  38766. textGroup.setTranslate(0, adjust * fontSize);
  38767. var rBox = new kity.Box(),
  38768. r = Math.round;
  38769. this.setTextStyle(node, textGroup);
  38770. var textLength = textArr.length;
  38771. var textGroupLength = textGroup.getItems().length;
  38772. if(textLength < textGroupLength){
  38773. for( var i = textLength,ci;ci = textGroup.getItem(i);){
  38774. textGroup.removeItem(i);
  38775. }
  38776. }else if(textLength > textGroupLength){
  38777. var length = textLength - textGroupLength;
  38778. for(var i = 0;i < length;i++){
  38779. var textShape = new kity.Text()
  38780. .setAttr('text-rendering', 'inherit');
  38781. if (kity.Browser.ie) {
  38782. textShape.setVerticalAlign('top');
  38783. } else {
  38784. textShape.setAttr('dominant-baseline', 'text-before-edge');
  38785. }
  38786. textGroup.addItem(textShape);
  38787. }
  38788. }
  38789. for (var i = 0, text, textShape;
  38790. (text = textArr[i], textShape = textGroup.getItem(i)); i++) {
  38791. textShape.setContent(text);
  38792. }
  38793. this.setTextStyle(node, textGroup);
  38794. var textHash = node.getText() + [s('font-size'), s('font-name'), s('font-weight'), s('font-style')].join('/');
  38795. if (node._currentTextHash == textHash && node._currentTextGroupBox) return node._currentTextGroupBox;
  38796. node._currentTextHash = textHash;
  38797. return function() {
  38798. textGroup.eachItem(function(i, textShape) {
  38799. var y = yStart + i * fontSize * lineHeight;
  38800. textShape.setY(y);
  38801. rBox = rBox.merge(new kity.Box(0, y, textShape.getBoundaryBox().width || 1, fontSize));
  38802. });
  38803. //为了让文字在圆中垂直居中
  38804. var w = 0;
  38805. var shape = node.getStyle('shape');
  38806. if(shape && shape=='circle'){
  38807. w = Math.max(rBox.width,rBox.height)/2-rBox.height/2;
  38808. }
  38809. var nBox = new kity.Box(r(rBox.x), r(rBox.y-w), r(rBox.width), r(rBox.height));
  38810. node._currentTextGroupBox = nBox;
  38811. return nBox;
  38812. };
  38813. },
  38814. setTextStyle: function(node, text) {
  38815. var hooks = TextRenderer._styleHooks;
  38816. hooks.forEach(function(hook) {
  38817. hook(node, text);
  38818. });
  38819. }
  38820. });
  38821. utils.extend(TextRenderer, {
  38822. _styleHooks: [],
  38823. registerStyleHook: function(fn) {
  38824. TextRenderer._styleHooks.push(fn);
  38825. }
  38826. });
  38827. kity.extendClass(MinderNode, {
  38828. getTextGroup: function() {
  38829. return this.getRenderer('TextRenderer').getRenderShape();
  38830. }
  38831. });
  38832. KityMinder.registerModule('text', {
  38833. 'renderers': {
  38834. center: TextRenderer
  38835. }
  38836. });
  38837. /* global Renderer: true */
  38838. KityMinder.registerModule('Expand', function() {
  38839. var minder = this;
  38840. var EXPAND_STATE_DATA = 'expandState',
  38841. STATE_EXPAND = 'expand',
  38842. STATE_COLLAPSE = 'collapse';
  38843. // 将展开的操作和状态读取接口拓展到 MinderNode 上
  38844. kity.extendClass(MinderNode, {
  38845. /**
  38846. * 展开节点
  38847. * @param {Policy} policy 展开的策略,默认为 KEEP_STATE
  38848. */
  38849. expand: function() {
  38850. this.setData(EXPAND_STATE_DATA, STATE_EXPAND);
  38851. return this;
  38852. },
  38853. /**
  38854. * 收起节点
  38855. */
  38856. collapse: function() {
  38857. this.setData(EXPAND_STATE_DATA, STATE_COLLAPSE);
  38858. return this;
  38859. },
  38860. /**
  38861. * 判断节点当前的状态是否为展开
  38862. */
  38863. isExpanded: function() {
  38864. var expanded = this.getData(EXPAND_STATE_DATA) !== STATE_COLLAPSE;
  38865. return expanded && (this.isRoot() || this.parent.isExpanded());
  38866. },
  38867. /**
  38868. * 判断节点当前的状态是否为收起
  38869. */
  38870. isCollapsed: function() {
  38871. return !this.isExpanded();
  38872. }
  38873. });
  38874. var ExpandCommand = kity.createClass('ExpandCommand', {
  38875. base: Command,
  38876. execute: function(km, justParents) {
  38877. var node = km.getSelectedNode();
  38878. if (!node) return;
  38879. if (justParents) {
  38880. node = node.parent;
  38881. }
  38882. while(node.parent) {
  38883. node.expand();
  38884. node = node.parent;
  38885. }
  38886. node.renderTree();
  38887. km.layout(100);
  38888. },
  38889. queryState: function(km) {
  38890. return km.getSelectedNode() ? 0 : -1;
  38891. }
  38892. });
  38893. var ExpandToLevelCommand = kity.createClass('ExpandToLevelCommand', {
  38894. base: Command,
  38895. execute: function(km, level) {
  38896. km.getRoot().traverse(function(node) {
  38897. if (node.getLevel() < level) node.expand();
  38898. if (node.getLevel() == level) node.collapse();
  38899. });
  38900. km.refresh(100);
  38901. },
  38902. enableReadOnly: true
  38903. });
  38904. var Expander = kity.createClass('Expander', {
  38905. base: kity.Group,
  38906. constructor: function(node) {
  38907. this.callBase();
  38908. this.radius = 6;
  38909. this.outline = new kity.Circle(this.radius).stroke('gray').fill('white');
  38910. this.sign = new kity.Path().stroke('gray');
  38911. this.addShapes([this.outline, this.sign]);
  38912. this.initEvent(node);
  38913. this.setId(KityMinder.uuid('node_expander'));
  38914. this.setStyle('cursor', 'pointer');
  38915. },
  38916. initEvent: function(node) {
  38917. this.on('mousedown', function(e) {
  38918. if (node.isExpanded()) {
  38919. node.collapse();
  38920. } else {
  38921. node.expand();
  38922. }
  38923. node.renderTree().getMinder().layout(100);
  38924. node.getMinder().fire('contentchange');
  38925. e.stopPropagation();
  38926. e.preventDefault();
  38927. });
  38928. this.on('dblclick click mouseup', function(e) {
  38929. e.stopPropagation();
  38930. e.preventDefault();
  38931. });
  38932. },
  38933. setState: function(state) {
  38934. if (state == 'hide') {
  38935. this.setVisible(false);
  38936. return;
  38937. }
  38938. this.setVisible(true);
  38939. var pathData = ['M', 1.5 - this.radius, 0, 'L', this.radius - 1.5, 0];
  38940. if (state == STATE_COLLAPSE) {
  38941. pathData.push(['M', 0, 1.5 - this.radius, 'L', 0, this.radius - 1.5]);
  38942. }
  38943. this.sign.setPathData(pathData);
  38944. }
  38945. });
  38946. var ExpanderRenderer = kity.createClass('ExpanderRenderer', {
  38947. base: Renderer,
  38948. create: function(node) {
  38949. if (node.isRoot()) return;
  38950. this.expander = new Expander(node);
  38951. node.getRenderContainer().prependShape(this.expander);
  38952. node.expanderRenderer = this;
  38953. this.node = node;
  38954. return this.expander;
  38955. },
  38956. shouldRender: function(node) {
  38957. return !node.isRoot();
  38958. },
  38959. update: function(expander, node, box) {
  38960. if (!node.parent) return;
  38961. var visible = node.parent.isExpanded();
  38962. expander.setState(visible && node.children.length ? node.getData(EXPAND_STATE_DATA) : 'hide');
  38963. var vector = node.getLayoutVectorIn().normalize(expander.radius + node.getStyle('stroke-width'));
  38964. var position = node.getVertexIn().offset(vector.reverse());
  38965. this.expander.setTranslate(position);
  38966. }
  38967. });
  38968. return {
  38969. commands: {
  38970. 'expand': ExpandCommand,
  38971. 'expandtolevel': ExpandToLevelCommand
  38972. },
  38973. events: {
  38974. 'layoutapply': function(e) {
  38975. var r = e.node.getRenderer('ExpanderRenderer');
  38976. if (r.getRenderShape()) {
  38977. r.update(r.getRenderShape(), e.node);
  38978. }
  38979. },
  38980. 'beforerender': function(e) {
  38981. var node = e.node;
  38982. var visible = !node.parent || node.parent.isExpanded();
  38983. var minder = this;
  38984. node.getRenderContainer().setVisible(visible);
  38985. if (!visible) e.stopPropagation();
  38986. },
  38987. 'normal.keydown': function(e) {
  38988. if (this.getStatus() == 'textedit') return;
  38989. if (e.originEvent.keyCode == keymap['/']) {
  38990. var node = this.getSelectedNode();
  38991. if (!node || node == this.getRoot()) return;
  38992. var expanded = node.isExpanded();
  38993. this.getSelectedNodes().forEach(function(node) {
  38994. if (expanded) node.collapse();
  38995. else node.expand();
  38996. node.renderTree();
  38997. });
  38998. this.layout(100);
  38999. this.fire('contentchange');
  39000. e.preventDefault();
  39001. e.stopPropagationImmediately();
  39002. }
  39003. if (e.isShortcutKey('Alt+`')) {
  39004. this.execCommand('expandtolevel', 9999);
  39005. }
  39006. for (var i = 1; i < 6; i++) {
  39007. if (e.isShortcutKey('Alt+' + i)) {
  39008. this.execCommand('expandtolevel', i);
  39009. }
  39010. }
  39011. }
  39012. },
  39013. renderers: {
  39014. outside: ExpanderRenderer
  39015. },
  39016. contextmenu: [{
  39017. command: 'expandtoleaf',
  39018. query: function() {
  39019. return !minder.getSelectedNode();
  39020. },
  39021. fn: function(minder) {
  39022. minder.execCommand('expandtolevel', 9999);
  39023. }
  39024. }, {
  39025. command: 'expandtolevel1',
  39026. query: function() {
  39027. return !minder.getSelectedNode();
  39028. },
  39029. fn: function(minder) {
  39030. minder.execCommand('expandtolevel', 1);
  39031. }
  39032. }, {
  39033. command: 'expandtolevel2',
  39034. query: function() {
  39035. return !minder.getSelectedNode();
  39036. },
  39037. fn: function(minder) {
  39038. minder.execCommand('expandtolevel', 2);
  39039. }
  39040. },{
  39041. command: 'expandtolevel3',
  39042. query: function() {
  39043. return !minder.getSelectedNode();
  39044. },
  39045. fn: function(minder) {
  39046. minder.execCommand('expandtolevel', 3);
  39047. }
  39048. }, {
  39049. divider: true
  39050. }]
  39051. };
  39052. });
  39053. /* global Renderer: true */
  39054. var OutlineRenderer = kity.createClass('OutlineRenderer', {
  39055. base: Renderer,
  39056. create: function(node) {
  39057. var outline = new kity.Rect()
  39058. .setId(KityMinder.uuid('node_outline'));
  39059. this.bringToBack = true;
  39060. return outline;
  39061. },
  39062. update: function(outline, node, box) {
  39063. //增加圆形update、待更好解决方案
  39064. var shape = node.getStyle('shape');
  39065. if(shape){
  39066. if(shape=='circle'){
  39067. return updateCircle(outline, node, box);
  39068. }
  39069. }
  39070. var paddingLeft = node.getStyle('padding-left'),
  39071. paddingRight = node.getStyle('padding-right'),
  39072. paddingTop = node.getStyle('padding-top'),
  39073. paddingBottom = node.getStyle('padding-bottom');
  39074. var outlineBox = {
  39075. x: box.x - paddingLeft,
  39076. y: box.y - paddingTop,
  39077. width: box.width + paddingLeft + paddingRight,
  39078. height: box.height + paddingTop + paddingBottom
  39079. };
  39080. var prefix = node.isSelected() ? 'selected-' : '';
  39081. outline
  39082. .setPosition(outlineBox.x, outlineBox.y)
  39083. .setSize(outlineBox.width, outlineBox.height)
  39084. .setRadius(node.getStyle('radius'))
  39085. .fill(node.getData('background') || node.getStyle(prefix + 'background') || node.getStyle('background'))
  39086. .stroke(node.getStyle(prefix + 'stroke' || node.getStyle('stroke')),
  39087. node.getStyle(prefix + 'stroke-width'));
  39088. return new kity.Box(outlineBox);
  39089. }
  39090. });
  39091. //圆
  39092. function updateCircle(outline, node, box){
  39093. var paddingLeft = node.getStyle('padding-left'),
  39094. paddingRight = node.getStyle('padding-right'),
  39095. paddingTop = node.getStyle('padding-top'),
  39096. paddingBottom = node.getStyle('padding-bottom');
  39097. var width= Math.max(box.width,box.height);
  39098. var outlineBox = {
  39099. x: box.x - paddingLeft,
  39100. y: box.y - paddingTop,
  39101. width: width + paddingLeft + paddingRight,
  39102. height: width + paddingTop + paddingBottom
  39103. };
  39104. var prefix = node.isSelected() ? 'selected-' : '';
  39105. width= Math.max(outlineBox.width,outlineBox.height);
  39106. outline
  39107. .setPosition(outlineBox.x, outlineBox.y)
  39108. .setSize(width, width)
  39109. .setRadius(width/2)
  39110. .fill(node.getData('background') || node.getStyle(prefix + 'background') || node.getStyle('background'))
  39111. .stroke(node.getStyle(prefix + 'stroke' || node.getStyle('stroke')),
  39112. node.getStyle(prefix + 'stroke-width'));
  39113. return new kity.Box(outlineBox);
  39114. }
  39115. var ShadowRenderer = kity.createClass('ShadowRenderer', {
  39116. base: Renderer,
  39117. create: function(node) {
  39118. this.bringToBack = true;
  39119. return new kity.Rect();
  39120. },
  39121. shouldRender: function(node) {
  39122. return node.getStyle('shadow');
  39123. },
  39124. update: function(shadow, node, box) {
  39125. shadow.setPosition(box.x + 4, box.y + 5)
  39126. .fill(node.getStyle('shadow'));
  39127. var shape = node.getStyle('shape');
  39128. if(!shape){
  39129. shadow.setSize(box.width, box.height)
  39130. shadow.setRadius(node.getStyle('radius'));
  39131. }else if(shape=='circle'){
  39132. var width= Math.max(box.width,box.height);
  39133. shadow.setSize(width, width)
  39134. shadow.setRadius(width/2);
  39135. }
  39136. }
  39137. });
  39138. var marker = new kity.Marker();
  39139. marker.setWidth(10);
  39140. marker.setHeight(12);
  39141. marker.setRef(0, 0);
  39142. marker.setViewBox(-6, -4, 8, 10);
  39143. marker.addShape(new kity.Path().setPathData('M-5-3l5,3,-5,3').stroke('#33ffff'));
  39144. var wireframeOption = /wire/.test(window.location.href);
  39145. var WireframeRenderer = kity.createClass('WireframeRenderer', {
  39146. base: Renderer,
  39147. create: function() {
  39148. var wireframe = new kity.Group();
  39149. var oxy = this.oxy = new kity.Path()
  39150. .stroke('#f6f')
  39151. .setPathData('M0,-50L0,50M-50,0L50,0');
  39152. var box = this.wireframe = new kity.Rect()
  39153. .stroke('lightgreen');
  39154. var vectorIn = this.vectorIn = new kity.Path()
  39155. .stroke('#66ffff');
  39156. var vectorOut = this.vectorOut = new kity.Path()
  39157. .stroke('#66ffff');
  39158. vectorIn.setMarker(marker, 'end');
  39159. vectorOut.setMarker(marker, 'end');
  39160. return wireframe.addShapes([oxy, box, vectorIn, vectorOut]);
  39161. },
  39162. shouldRender: function() {
  39163. return wireframeOption;
  39164. },
  39165. update: function(created, node, box) {
  39166. this.wireframe
  39167. .setPosition(box.x, box.y)
  39168. .setSize(box.width, box.height);
  39169. var pin = node.getVertexIn();
  39170. var pout = node.getVertexOut();
  39171. var vin = node.getLayoutVectorIn().normalize(30);
  39172. var vout = node.getLayoutVectorOut().normalize(30);
  39173. this.vectorIn.setPathData(['M', pin.offset(vin.reverse()), 'L', pin]);
  39174. this.vectorOut.setPathData(['M', pout, 'l', vout]);
  39175. }
  39176. });
  39177. KityMinder.registerModule('OutlineModule', function() {
  39178. return {
  39179. events: (!wireframeOption ? null : {
  39180. 'ready': function() {
  39181. this.getPaper().addResource(marker);
  39182. },
  39183. 'layoutallfinish': function() {
  39184. this.getRoot().traverse(function(node) {
  39185. node.getRenderer('WireframeRenderer').update(null, node, node.getContentBox());
  39186. });
  39187. }
  39188. }),
  39189. renderers: {
  39190. outline: OutlineRenderer,
  39191. outside: [ShadowRenderer, WireframeRenderer]
  39192. }
  39193. };
  39194. });
  39195. KityMinder.Geometry = (function() {
  39196. var g = {};
  39197. var min = Math.min,
  39198. max = Math.max,
  39199. abs = Math.abs;
  39200. var own = Object.prototype.hasOwnProperty;
  39201. g.isNumberInRange = function(number, range) {
  39202. return number > range[0] && number < range[1];
  39203. };
  39204. g.getDistance = function(p1, p2) {
  39205. return kity.Vector.fromPoints(p1, p2).length();
  39206. };
  39207. function wrapBox(box) {
  39208. box.width = box.right - box.left;
  39209. box.height = box.bottom - box.top;
  39210. box.x = box.left;
  39211. box.y = box.top;
  39212. box.cx = box.x + box.width / 2;
  39213. box.cy = box.y + box.height / 2;
  39214. return box;
  39215. }
  39216. function uniformBox(box) {
  39217. // duck check
  39218. if ('x' in box) {
  39219. box.left = box.x;
  39220. box.right = box.x + box.width;
  39221. box.top = box.y;
  39222. box.bottom = box.y + box.height;
  39223. }
  39224. }
  39225. g.wrapBox = wrapBox;
  39226. g.getBox = function(p1, p2) {
  39227. return wrapBox({
  39228. left: min(p1.x, p2.x),
  39229. right: max(p1.x, p2.x),
  39230. top: min(p1.y, p2.y),
  39231. bottom: max(p1.y, p2.y)
  39232. });
  39233. };
  39234. g.mergeBox = function(b1, b2) {
  39235. uniformBox(b1);
  39236. uniformBox(b2);
  39237. return wrapBox({
  39238. left: min(b1.left, b2.left),
  39239. right: max(b1.right, b2.right),
  39240. top: min(b1.top, b2.top),
  39241. bottom: max(b1.bottom, b2.bottom)
  39242. });
  39243. };
  39244. g.getBoxRange = function(box) {
  39245. return {
  39246. x: [box.left, box.right],
  39247. y: [box.top, box.bottom]
  39248. };
  39249. };
  39250. g.getBoxVertex = function(box) {
  39251. return {
  39252. leftTop: {
  39253. x: box.left,
  39254. y: box.top
  39255. },
  39256. rightTop: {
  39257. x: box.right,
  39258. y: box.top
  39259. },
  39260. leftBottom: {
  39261. x: box.left,
  39262. y: box.bottom
  39263. },
  39264. rightBottom: {
  39265. x: box.right,
  39266. y: box.bottom
  39267. }
  39268. };
  39269. };
  39270. g.isPointInsideBox = function(p, b) {
  39271. uniformBox(b);
  39272. var ranges = g.getBoxRange(b);
  39273. return g.isNumberInRange(p.x, ranges.x) && g.isNumberInRange(p.y, ranges.y);
  39274. };
  39275. g.getIntersectBox = function(b1, b2) {
  39276. uniformBox(b1);
  39277. uniformBox(b2);
  39278. var minx = max(b1.left, b2.left),
  39279. miny = max(b1.top, b2.top),
  39280. maxx = min(b1.right, b2.right),
  39281. maxy = min(b1.bottom, b2.bottom);
  39282. return minx < maxx && miny < maxy ? wrapBox({
  39283. left: minx,
  39284. right: maxx,
  39285. top: miny,
  39286. bottom: maxy
  39287. }) : null;
  39288. };
  39289. g.snapToSharp = function(unknown) {
  39290. if (utils.isNumber(unknown)) {
  39291. return (unknown | 0) + 0.5;
  39292. }
  39293. if (utils.isArray(unknown)) {
  39294. return unknown.map(g.snapToSharp);
  39295. }
  39296. ['x', 'y', 'left', 'top', 'right', 'bottom'].forEach(function(n) {
  39297. if (own.call(unknown, n)) {
  39298. unknown[n] = g.snapToSharp(unknown[n]);
  39299. }
  39300. });
  39301. return unknown;
  39302. };
  39303. g.expandBox = function(box, sizeX, sizeY) {
  39304. if (sizeY === undefined) {
  39305. sizeY = sizeX;
  39306. }
  39307. return wrapBox({
  39308. left: box.left - sizeX,
  39309. top: box.top - sizeY,
  39310. right: box.right + sizeX,
  39311. bottom: box.bottom + sizeY
  39312. });
  39313. };
  39314. return g;
  39315. })();
  39316. KityMinder.registerModule("HistoryModule", function() {
  39317. var km = this;
  39318. var Scene = kity.createClass('Scene', {
  39319. constructor: function(root,inputStatus) {
  39320. this.data = root.clone();
  39321. this.inputStatus = inputStatus;
  39322. },
  39323. getData: function() {
  39324. return this.data;
  39325. },
  39326. cloneData: function() {
  39327. return this.getData().clone();
  39328. },
  39329. equals: function(scene) {
  39330. return this.getData().equals(scene.getData());
  39331. },
  39332. isInputStatus:function(){
  39333. return this.inputStatus;
  39334. },
  39335. setInputStatus:function(status){
  39336. this.inputStatus = status;
  39337. }
  39338. });
  39339. var HistoryManager = kity.createClass('HistoryManager', {
  39340. constructor: function(km) {
  39341. this.list = [];
  39342. this.index = 0;
  39343. this.hasUndo = false;
  39344. this.hasRedo = false;
  39345. this.km = km;
  39346. },
  39347. undo: function() {
  39348. if (this.hasUndo) {
  39349. var currentScene = this.list[this.index];
  39350. //如果是输入文字时的保存,直接回复当前场景
  39351. if(currentScene && currentScene.isInputStatus()){
  39352. this.saveScene();
  39353. this.restore(--this.index);
  39354. currentScene.setInputStatus(false);
  39355. return;
  39356. }
  39357. if(this.list.length == 1){
  39358. this.restore(0);
  39359. return;
  39360. }
  39361. if (!this.list[this.index - 1] && this.list.length == 1) {
  39362. this.reset();
  39363. return;
  39364. }
  39365. while (this.list[this.index].equals(this.list[this.index - 1])) {
  39366. this.index--;
  39367. if (this.index === 0) {
  39368. return this.restore(0);
  39369. }
  39370. }
  39371. this.restore(--this.index);
  39372. }
  39373. },
  39374. redo: function() {
  39375. if (this.hasRedo) {
  39376. while (this.list[this.index].equals(this.list[this.index + 1])) {
  39377. this.index++;
  39378. if (this.index == this.list.length - 1) {
  39379. return this.restore(this.index);
  39380. }
  39381. }
  39382. this.restore(++this.index);
  39383. }
  39384. },
  39385. partialRenewal: function(target) {
  39386. var selectedNodes = [];
  39387. function compareNode(source, target) {
  39388. if (source.getText() != target.getText()) {
  39389. return false;
  39390. }
  39391. if (utils.compareObject(source.getData(), target.getData()) === false) {
  39392. return false;
  39393. }
  39394. if (utils.compareObject(source.getTmpData(), target.getTmpData()) === false) {
  39395. return false;
  39396. }
  39397. return true;
  39398. }
  39399. function appendChildNode(parent, child) {
  39400. if (child.isSelected()) {
  39401. selectedNodes.push(child);
  39402. }
  39403. km.appendNode(child, parent);
  39404. child.render();
  39405. var children = utils.cloneArr(child.children);
  39406. for (var i = 0, ci; ci = children[i++];) {
  39407. appendChildNode(child, ci);
  39408. }
  39409. }
  39410. function traverseNode(srcNode, tagNode) {
  39411. if (compareNode(srcNode, tagNode) === false) {
  39412. srcNode.setValue(tagNode);
  39413. }
  39414. //todo,这里有性能问题,变成全部render了
  39415. srcNode.render();
  39416. if (srcNode.isSelected()) {
  39417. selectedNodes.push(srcNode);
  39418. }
  39419. for (var i = 0, j = 0, si, tj;
  39420. (si = srcNode.children[i], tj = tagNode.children[j], si || tj); i++, j++) {
  39421. if (si && !tj) {
  39422. i--;
  39423. km.removeNode(si);
  39424. } else if (!si && tj) {
  39425. j--;
  39426. appendChildNode(srcNode, tj);
  39427. } else {
  39428. traverseNode(si, tj);
  39429. }
  39430. }
  39431. }
  39432. traverseNode(km.getRoot(), target);
  39433. km.layout(200);
  39434. km.select(selectedNodes,true);
  39435. selectedNodes = [];
  39436. },
  39437. restore: function(index) {
  39438. index = index === undefined ? this.index : index;
  39439. var scene = this.list[index];
  39440. this.partialRenewal(scene.cloneData());
  39441. this.update();
  39442. this.km.fire('restoreScene');
  39443. this.km.fire('contentChange');
  39444. },
  39445. getScene: function(inputStatus) {
  39446. return new Scene(this.km.getRoot(),inputStatus);
  39447. },
  39448. saveScene: function(inputStatus) {
  39449. var currentScene = this.getScene(inputStatus);
  39450. var lastScene = this.list[this.index];
  39451. if (lastScene && lastScene.equals(currentScene)) {
  39452. if(inputStatus){
  39453. lastScene.setInputStatus(true);
  39454. this.update();
  39455. }
  39456. return;
  39457. }
  39458. this.list = this.list.slice(0, this.index + 1);
  39459. this.list.push(currentScene);
  39460. //如果大于最大数量了,就把最前的剔除
  39461. if (this.list.length > this.km.getOptions('maxUndoCount')) {
  39462. this.list.shift();
  39463. }
  39464. this.index = this.list.length - 1;
  39465. //跟新undo/redo状态
  39466. this.update();
  39467. },
  39468. update: function() {
  39469. this.hasRedo = !!this.list[this.index + 1];
  39470. this.hasUndo = !!this.list[this.index - 1];
  39471. var currentScene = this.list[this.index];
  39472. if(currentScene && currentScene.isInputStatus()){
  39473. this.hasUndo = true;
  39474. }
  39475. },
  39476. reset: function() {
  39477. this.list = [];
  39478. this.index = 0;
  39479. this.hasUndo = false;
  39480. this.hasRedo = false;
  39481. }
  39482. });
  39483. //为km实例添加history管理
  39484. this.historyManager = new HistoryManager(this);
  39485. return {
  39486. defaultOptions: {
  39487. maxUndoCount: 20,
  39488. maxInputCount: 20
  39489. },
  39490. "commands": {
  39491. "undo": kity.createClass("UndoCommand", {
  39492. base: Command,
  39493. execute: function(km) {
  39494. km.historyManager.undo();
  39495. },
  39496. queryState: function(km) {
  39497. return km.historyManager.hasUndo ? 0 : -1;
  39498. },
  39499. isNeedUndo: function() {
  39500. return false;
  39501. }
  39502. }),
  39503. "redo": kity.createClass("RedoCommand", {
  39504. base: Command,
  39505. execute: function(km) {
  39506. km.historyManager.redo();
  39507. },
  39508. queryState: function(km) {
  39509. return km.historyManager.hasRedo ? 0 : -1;
  39510. },
  39511. isNeedUndo: function() {
  39512. return false;
  39513. }
  39514. })
  39515. },
  39516. commandShortcutKeys: {
  39517. "undo": "ctrl+z", //undo
  39518. "redo": "ctrl+y" //redo
  39519. },
  39520. "events": {
  39521. "saveScene": function(e) {
  39522. this.historyManager.saveScene(e.inputStatus);
  39523. },
  39524. "import": function() {
  39525. this.historyManager.reset();
  39526. }
  39527. }
  39528. };
  39529. });
  39530. KityMinder.registerModule('ProgressModule', function() {
  39531. var minder = this;
  39532. var PROGRESS_DATA = 'progress';
  39533. // Designed by Akikonata
  39534. var BG_COLOR = '#FFED83';
  39535. var PIE_COLOR = '#43BC00';
  39536. var SHADOW_PATH = 'M10,3c4.418,0,8,3.582,8,8h1c0-5.523-3.477-10-9-10S1,5.477,1,11h1C2,6.582,5.582,3,10,3z';
  39537. var SHADOW_COLOR = '#8E8E8E';
  39538. var FRAME_PATH = 'M10,0C4.477,0,0,4.477,0,10c0,5.523,4.477,10,10,10s10-4.477,10-10C20,4.477,15.523,0,10,0zM10,18c-4.418,0-8-3.582-8-8s3.582-8,8-8s8,3.582,8,8S14.418,18,10,18z';
  39539. var FRAME_GRAD = new kity.LinearGradient().pipe(function(g) {
  39540. g.setStartPosition(0, 0);
  39541. g.setEndPosition(0, 1);
  39542. g.addStop(0, '#fff');
  39543. g.addStop(1, '#ccc');
  39544. });
  39545. var CHECK_PATH = 'M15.812,7.896l-6.75,6.75l-4.5-4.5L6.25,8.459l2.812,2.803l5.062-5.053L15.812,7.896z';
  39546. var CHECK_COLOR = '#EEE';
  39547. minder.getPaper().addResource(FRAME_GRAD);
  39548. // 进度图标的图形
  39549. var ProgressIcon = kity.createClass('ProgressIcon', {
  39550. base: kity.Group,
  39551. constructor: function(value) {
  39552. this.callBase();
  39553. this.setSize(20);
  39554. this.create();
  39555. this.setValue(value);
  39556. this.setId(KityMinder.uuid('node_progress'));
  39557. this.translate(0.5, 0.5);
  39558. },
  39559. setSize: function(size) {
  39560. this.width = this.height = size;
  39561. },
  39562. create: function() {
  39563. var bg, pie, shadow, frame, check;
  39564. bg = new kity.Circle(9)
  39565. .fill(BG_COLOR);
  39566. pie = new kity.Pie(9, 0)
  39567. .fill(PIE_COLOR);
  39568. shadow = new kity.Path()
  39569. .setPathData(SHADOW_PATH)
  39570. .setTranslate(-10, -10)
  39571. .fill(SHADOW_COLOR);
  39572. frame = new kity.Path()
  39573. .setTranslate(-10, -10)
  39574. .setPathData(FRAME_PATH)
  39575. .fill(FRAME_GRAD);
  39576. check = new kity.Path()
  39577. .setTranslate(-10, -10)
  39578. .setPathData(CHECK_PATH)
  39579. .fill(CHECK_COLOR);
  39580. this.addShapes([bg, pie, shadow, check, frame]);
  39581. this.pie = pie;
  39582. this.check = check;
  39583. },
  39584. setValue: function(value) {
  39585. this.pie.setAngle(-360 * (value - 1) / 8);
  39586. this.check.setVisible(value == 9);
  39587. }
  39588. });
  39589. var ProgressCommand = kity.createClass('ProgressCommand', {
  39590. base: Command,
  39591. execute: function(km, value) {
  39592. var nodes = km.getSelectedNodes();
  39593. for (var i = 0; i < nodes.length; i++) {
  39594. nodes[i].setData(PROGRESS_DATA, value || null).render();
  39595. }
  39596. km.layout();
  39597. },
  39598. queryValue: function(km) {
  39599. var nodes = km.getSelectedNodes();
  39600. var val;
  39601. for (var i = 0; i < nodes.length; i++) {
  39602. val = nodes[i].getData(PROGRESS_DATA);
  39603. if (val) break;
  39604. }
  39605. return val|| null;
  39606. },
  39607. queryState: function(km) {
  39608. return km.getSelectedNodes().length ? 0 : -1;
  39609. }
  39610. });
  39611. return {
  39612. 'commands': {
  39613. 'progress': ProgressCommand
  39614. },
  39615. 'renderers': {
  39616. left: kity.createClass('ProgressRenderer', {
  39617. base: KityMinder.Renderer,
  39618. create: function(node) {
  39619. return new ProgressIcon();
  39620. },
  39621. shouldRender: function(node) {
  39622. return node.getData(PROGRESS_DATA);
  39623. },
  39624. update: function(icon, node, box) {
  39625. var data = node.getData(PROGRESS_DATA);
  39626. var spaceLeft = node.getStyle('space-left');
  39627. var x, y;
  39628. icon.setValue(data);
  39629. x = box.left - icon.width - spaceLeft;
  39630. y = -icon.height / 2;
  39631. icon.setTranslate(x + icon.width / 2, y + icon.height / 2);
  39632. return new kity.Box(x, y, icon.width, icon.height);
  39633. }
  39634. })
  39635. }
  39636. };
  39637. });
  39638. KityMinder.registerModule('PriorityModule', function() {
  39639. var minder = this;
  39640. // Designed by Akikonata
  39641. // [MASK, BACK]
  39642. var PRIORITY_COLORS = [null,
  39643. ['#FF1200', '#840023'], // 1 - red
  39644. ['#0074FF', '#01467F'], // 2 - blue
  39645. ['#00AF00', '#006300'], // 3 - green
  39646. ['#FF962E', '#B25000'], // 4 - orange
  39647. ['#A464FF', '#4720C4'], // 5 - purple
  39648. ['#A3A3A3', '#515151'], // 6,7,8,9 - gray
  39649. ['#A3A3A3', '#515151'],
  39650. ['#A3A3A3', '#515151'],
  39651. ['#A3A3A3', '#515151'],
  39652. ]; // hue from 1 to 5
  39653. var BACK_PATH = 'M0,13c0,3.866,3.134,7,7,7h6c3.866,0,7-3.134,7-7V7H0V13z';
  39654. var MASK_PATH = 'M20,10c0,3.866-3.134,7-7,7H7c-3.866,0-7-3.134-7-7V7c0-3.866,3.134-7,7-7h6c3.866,0,7,3.134,7,7V10z';
  39655. var PRIORITY_DATA = 'priority';
  39656. // 进度图标的图形
  39657. var PriorityIcon = kity.createClass('PriorityIcon', {
  39658. base: kity.Group,
  39659. constructor: function() {
  39660. this.callBase();
  39661. this.setSize(20);
  39662. this.create();
  39663. this.setId(KityMinder.uuid('node_priority'));
  39664. },
  39665. setSize: function(size) {
  39666. this.width = this.height = size;
  39667. },
  39668. create: function() {
  39669. var white, back, mask, number; // 4 layer
  39670. white = new kity.Path().setPathData(MASK_PATH).fill('white');
  39671. back = new kity.Path().setPathData(BACK_PATH).setTranslate(0.5, 0.5);
  39672. mask = new kity.Path().setPathData(MASK_PATH).setOpacity(0.8).setTranslate(0.5, 0.5);
  39673. number = new kity.Text()
  39674. .setX(this.width / 2 - 0.5).setY(this.height / 2 - 1.5)
  39675. .setTextAnchor('middle')
  39676. .setVerticalAlign('middle')
  39677. .setFontItalic(true)
  39678. .setFontSize(14)
  39679. .fill('white');
  39680. this.addShapes([back, mask, number]);
  39681. this.mask = mask;
  39682. this.back = back;
  39683. this.number = number;
  39684. },
  39685. setValue: function(value) {
  39686. var back = this.back,
  39687. mask = this.mask,
  39688. number = this.number;
  39689. var color = PRIORITY_COLORS[value];
  39690. if (color) {
  39691. back.fill(color[1]);
  39692. mask.fill(color[0]);
  39693. }
  39694. number.setContent(value);
  39695. }
  39696. });
  39697. // 提供的命令
  39698. var PriorityCommand = kity.createClass('SetPriorityCommand', {
  39699. base: Command,
  39700. execute: function(km, value) {
  39701. var nodes = km.getSelectedNodes();
  39702. for (var i = 0; i < nodes.length; i++) {
  39703. nodes[i].setData(PRIORITY_DATA, value || null).render();
  39704. }
  39705. km.layout();
  39706. },
  39707. queryValue: function(km) {
  39708. var nodes = km.getSelectedNodes();
  39709. var val;
  39710. for (var i = 0; i < nodes.length; i++) {
  39711. val = nodes[i].getData(PRIORITY_DATA);
  39712. if (val) break;
  39713. }
  39714. return val || null;
  39715. },
  39716. queryState: function(km) {
  39717. return km.getSelectedNodes().length ? 0 : -1;
  39718. }
  39719. });
  39720. return {
  39721. 'commands': {
  39722. 'priority': PriorityCommand,
  39723. },
  39724. 'renderers': {
  39725. left: kity.createClass('PriorityRenderer', {
  39726. base: KityMinder.Renderer,
  39727. create: function(node) {
  39728. return new PriorityIcon();
  39729. },
  39730. shouldRender: function(node) {
  39731. return node.getData(PRIORITY_DATA);
  39732. },
  39733. update: function(icon, node, box) {
  39734. var data = node.getData(PRIORITY_DATA);
  39735. var spaceLeft = node.getStyle('space-left'),
  39736. x, y;
  39737. icon.setValue(data);
  39738. x = box.left - icon.width - spaceLeft;
  39739. y = -icon.height / 2;
  39740. icon.setTranslate(x, y);
  39741. return new kity.Box({
  39742. x: x,
  39743. y: y,
  39744. width: icon.width,
  39745. height: icon.height
  39746. });
  39747. }
  39748. })
  39749. }
  39750. };
  39751. });
  39752. KityMinder.registerModule('image', function() {
  39753. function loadImageSize(url, callback) {
  39754. var img = document.createElement('img');
  39755. img.onload = function() {
  39756. callback(img.width, img.height);
  39757. };
  39758. img.onerror = function() {
  39759. callback(null);
  39760. };
  39761. img.src = url;
  39762. }
  39763. function fitImageSize(width, height, maxWidth, maxHeight) {
  39764. var ratio = width / height,
  39765. fitRatio = maxWidth / maxHeight;
  39766. // 宽高比大于最大尺寸的宽高比,以宽度为标准适应
  39767. if (width > maxWidth && ratio > fitRatio) {
  39768. width = maxWidth;
  39769. height = width / ratio;
  39770. } else if (height > maxHeight) {
  39771. height = maxHeight;
  39772. width = height * ratio;
  39773. }
  39774. return {
  39775. width: width | 0,
  39776. height: height | 0
  39777. };
  39778. }
  39779. var ImageCommand = kity.createClass('ImageCommand', {
  39780. base: Command,
  39781. execute: function(km, url, title) {
  39782. var nodes = km.getSelectedNodes();
  39783. loadImageSize(url, function(width, height) {
  39784. if (!width) return;
  39785. utils.each(nodes, function(i, n) {
  39786. var size = fitImageSize(
  39787. width, height,
  39788. km.getOptions('maxImageWidth'),
  39789. km.getOptions('maxImageHeight'));
  39790. n.setData('image', url);
  39791. n.setData('imageTitle', title);
  39792. n.setData('imageSize', size);
  39793. n.render();
  39794. });
  39795. km.fire("saveScene");
  39796. km.layout(300);
  39797. });
  39798. },
  39799. queryState: function(km) {
  39800. var nodes = km.getSelectedNodes(),
  39801. result = 0;
  39802. if (nodes.length === 0) {
  39803. return -1;
  39804. }
  39805. utils.each(nodes, function(i, n) {
  39806. if (n && n.getData('image')) {
  39807. result = 0;
  39808. return false;
  39809. }
  39810. });
  39811. return result;
  39812. },
  39813. queryValue: function(km) {
  39814. var node = km.getSelectedNode();
  39815. return {
  39816. url: node.getData('image'),
  39817. title: node.getData('imageTitle')
  39818. };
  39819. }
  39820. });
  39821. var RemoveImageCommand = kity.createClass('RemoveImageCommand', {
  39822. base: Command,
  39823. execute: function(km) {
  39824. var nodes = km.getSelectedNodes();
  39825. utils.each(nodes, function(i, n) {
  39826. n.setData('image').render();
  39827. });
  39828. km.layout(300);
  39829. },
  39830. queryState: function(km) {
  39831. var nodes = km.getSelectedNodes();
  39832. if (nodes.length === 0) {
  39833. return -1;
  39834. }
  39835. var image = false;
  39836. utils.each(nodes, function(i, n) {
  39837. if (n.getData('image')) {
  39838. image = true;
  39839. return false;
  39840. }
  39841. });
  39842. if (image) {
  39843. return 0;
  39844. }
  39845. return -1;
  39846. }
  39847. });
  39848. var ImageRenderer = kity.createClass('ImageRenderer', {
  39849. base: KityMinder.Renderer,
  39850. create: function(node) {
  39851. return new kity.Image(node.getData('image'));
  39852. },
  39853. shouldRender: function(node) {
  39854. return node.getData('image');
  39855. },
  39856. update: function(image, node, box) {
  39857. var url = node.getData('image');
  39858. var title = node.getData('imageTitle');
  39859. var size = node.getData('imageSize');
  39860. var spaceTop = node.getStyle('space-top');
  39861. if (!size) return;
  39862. if (title) {
  39863. image.node.setAttributeNS('http://www.w3.org/1999/xlink', 'title', title);
  39864. }
  39865. var x = box.cx - size.width / 2;
  39866. var y = box.y - size.height - spaceTop;
  39867. image
  39868. .setUrl(url)
  39869. .setX(x | 0)
  39870. .setY(y | 0)
  39871. .setWidth(size.width | 0)
  39872. .setHeight(size.height | 0);
  39873. return new kity.Box(x | 0, y | 0, size.width | 0, size.height | 0);
  39874. }
  39875. });
  39876. return {
  39877. 'defaultOptions': {
  39878. 'maxImageWidth': 200,
  39879. 'maxImageHeight': 200
  39880. },
  39881. 'commands': {
  39882. 'image': ImageCommand,
  39883. 'removeimage': RemoveImageCommand
  39884. },
  39885. 'renderers': {
  39886. 'top': ImageRenderer
  39887. }
  39888. };
  39889. });
  39890. KityMinder.registerModule('Resource', function() {
  39891. // String Hash
  39892. // https://github.com/drostie/sha3-js/edit/master/blake32.min.js
  39893. var blake32=(function(){var k,g,r,l,m,o,p,q,t,w,x;x=4*(1<<30);k=[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19];m=[0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917];w=function(i){if(i<0){i+=x}return("00000000"+i.toString(16)).slice(-8)};o=[[16,50,84,118,152,186,220,254],[174,132,249,109,193,32,123,53],[139,12,37,223,234,99,23,73],[151,19,205,235,98,165,4,143],[9,117,66,250,30,203,134,211],[194,166,176,56,212,87,239,145],[92,241,222,164,112,54,41,184],[189,231,28,147,5,79,104,162],[246,158,59,128,44,125,65,90],[42,72,103,81,191,233,195,13]];p=function(a,b,n){var s=q[a]^q[b];q[a]=(s>>>n)|(s<<(32-n))};g=function(i,a,b,c,d){var u=l+o[r][i]%16,v=l+(o[r][i]>>4);a%=4;b=4+b%4;c=8+c%4;d=12+d%4;q[a]+=q[b]+(t[u]^m[v%16]);p(d,a,16);q[c]+=q[d];p(b,c,12);q[a]+=q[b]+(t[v]^m[u%16]);p(d,a,8);q[c]+=q[d];p(b,c,7)};return function(a,b){if(!(b instanceof Array&&b.length===4)){b=[0,0,0,0]}var c,d,e,L,f,h,j,i;d=k.slice(0);c=m.slice(0,8);for(r=0;r<4;r+=1){c[r]^=b[r]}e=a.length*16;f=(e%512>446||e%512===0)?0:e;if(e%512===432){a+="\u8001"}else{a+="\u8000";while(a.length%32!==27){a+="\u0000"}a+="\u0001"}t=[];for(i=0;i<a.length;i+=2){t.push(a.charCodeAt(i)*65536+a.charCodeAt(i+1))}t.push(0);t.push(e);h=t.length-16;j=0;for(l=0;l<t.length;l+=16){j+=512;L=(l===h)?f:Math.min(e,j);q=d.concat(c);q[12]^=L;q[13]^=L;for(r=0;r<10;r+=1){for(i=0;i<8;i+=1){if(i<4){g(i,i,i,i,i)}else{g(i,i,i+1,i+2,i+3)}}}for(i=0;i<8;i+=1){d[i]^=b[i%4]^q[i]^q[i+8]}}return d.map(w).join("")}}());
  39894. /**
  39895. * 自动使用的颜色序列
  39896. */
  39897. var RESOURCE_COLOR_SERIES = [51, 303, 75, 200, 157, 0, 26, 254].map(function(h) {
  39898. return kity.Color.createHSL(h, 100, 85);
  39899. });
  39900. /**
  39901. * 在 Minder 上拓展一些关于资源的支持接口
  39902. */
  39903. kity.extendClass(Minder, {
  39904. /**
  39905. * 获取字符串的哈希值
  39906. *
  39907. * @param {String} str
  39908. * @return {Number} hashCode
  39909. */
  39910. getHashCode: function(str) {
  39911. str = blake32(str);
  39912. var hash = 1315423911, i, ch;
  39913. for (i = str.length - 1; i >= 0; i--) {
  39914. ch = str.charCodeAt(i);
  39915. hash ^= ((hash << 5) + ch + (hash >> 2));
  39916. }
  39917. return (hash & 0x7FFFFFFF);
  39918. },
  39919. /**
  39920. * 获取脑图中某个资源对应的颜色
  39921. *
  39922. * 如果存在同名资源,则返回已经分配给该资源的颜色,否则分配给该资源一个颜色,并且返回
  39923. *
  39924. * 如果资源数超过颜色序列数量,返回哈希颜色
  39925. *
  39926. * @param {String} resource 资源名称
  39927. * @return {Color}
  39928. */
  39929. getResourceColor: function(resource) {
  39930. var colorMapping = this._getResourceColorIndexMapping();
  39931. var nextIndex;
  39932. if (!colorMapping.hasOwnProperty(resource)) {
  39933. // 找不到找下个可用索引
  39934. nextIndex = this._getNextResourceColorIndex();
  39935. colorMapping[resource] = nextIndex;
  39936. }
  39937. // 资源过多,找不到可用索引颜色,统一返回哈希函数得到的颜色
  39938. return RESOURCE_COLOR_SERIES[colorMapping[resource]] || kity.Color.createHSL(Math.floor(this.getHashCode(resource) / 0x7FFFFFFF * 359), 100, 85);
  39939. },
  39940. /**
  39941. * 获得已使用的资源的列表
  39942. *
  39943. * @return {Array}
  39944. */
  39945. getUsedResource: function() {
  39946. var mapping = this._getResourceColorIndexMapping();
  39947. var used = [],
  39948. resource;
  39949. for (resource in mapping) {
  39950. if (mapping.hasOwnProperty(resource)) {
  39951. used.push(resource);
  39952. }
  39953. }
  39954. return used;
  39955. },
  39956. /**
  39957. * 获取脑图下一个可用的资源颜色索引
  39958. *
  39959. * @return {int}
  39960. */
  39961. _getNextResourceColorIndex: function() {
  39962. // 获取现有颜色映射
  39963. // resource => color_index
  39964. var colorMapping = this._getResourceColorIndexMapping();
  39965. var resource, used, i;
  39966. used = [];
  39967. // 抽取已经使用的值到 used 数组
  39968. for (resource in colorMapping) {
  39969. if (colorMapping.hasOwnProperty(resource)) {
  39970. used.push(colorMapping[resource]);
  39971. }
  39972. }
  39973. // 枚举所有的可用值,如果还没被使用,返回
  39974. for (i = 0; i < RESOURCE_COLOR_SERIES.length; i++) {
  39975. if (!~used.indexOf(i)) return i;
  39976. }
  39977. // 没有可用的颜色了
  39978. return -1;
  39979. },
  39980. // 获取现有颜色映射
  39981. // resource => color_index
  39982. _getResourceColorIndexMapping: function() {
  39983. return this._resourceColorMapping || (this._resourceColorMapping = {});
  39984. }
  39985. });
  39986. /**
  39987. * @class 设置资源的命令
  39988. *
  39989. * @example
  39990. *
  39991. * // 设置选中节点资源为 "张三"
  39992. * minder.execCommand('resource', ['张三']);
  39993. *
  39994. * // 添加资源 "李四" 到选中节点
  39995. * var resource = minder.queryCommandValue();
  39996. * resource.push('李四');
  39997. * minder.execCommand('resource', resource);
  39998. *
  39999. * // 清除选中节点的资源
  40000. * minder.execCommand('resource', null);
  40001. */
  40002. var ResourceCommand = kity.createClass('ResourceCommand', {
  40003. base: Command,
  40004. execute: function(minder, resource) {
  40005. var nodes = minder.getSelectedNodes();
  40006. if (typeof(resource) == 'string') {
  40007. resource = [resource];
  40008. }
  40009. nodes.forEach(function(node) {
  40010. node.setData('resource', resource).render();
  40011. });
  40012. minder.layout(200);
  40013. },
  40014. queryValue: function(minder) {
  40015. var nodes = minder.getSelectedNodes();
  40016. var resource = [];
  40017. nodes.forEach(function(node) {
  40018. var nodeResource = node.getData('resource');
  40019. if (!nodeResource) return;
  40020. nodeResource.forEach(function(name) {
  40021. if (!~resource.indexOf(name)) {
  40022. resource.push(name);
  40023. }
  40024. });
  40025. });
  40026. return resource;
  40027. },
  40028. queryState: function(km) {
  40029. return km.getSelectedNode() ? 0 : -1;
  40030. }
  40031. });
  40032. /**
  40033. * @class 资源的覆盖图形
  40034. *
  40035. * 该类为一个资源以指定的颜色渲染一个动态的覆盖图形
  40036. */
  40037. var ResourceOverlay = kity.createClass('ResourceOverlay', {
  40038. base: kity.Group,
  40039. constructor: function() {
  40040. this.callBase();
  40041. var text, rect;
  40042. rect = this.rect = new kity.Rect().setRadius(4);
  40043. text = this.text = new kity.Text()
  40044. .setFontSize(12)
  40045. .setVerticalAlign('middle');
  40046. this.addShapes([rect, text]);
  40047. },
  40048. setValue: function(resourceName, color) {
  40049. var paddingX = 8,
  40050. paddingY = 4,
  40051. borderRadius = 4;
  40052. var text, box, rect;
  40053. text = this.text;
  40054. if (resourceName == this.lastResourceName) {
  40055. box = this.lastBox;
  40056. } else {
  40057. text.setContent(resourceName);
  40058. box = text.getBoundaryBox();
  40059. this.lastResourceName = resourceName;
  40060. this.lastBox = box;
  40061. }
  40062. text.setX(paddingX).fill(color.dec('l', 70));
  40063. rect = this.rect;
  40064. rect.setPosition(0, box.y - paddingY);
  40065. this.width = Math.round(box.width + paddingX * 2);
  40066. this.height = Math.round(box.height + paddingY * 2);
  40067. rect.setSize(this.width, this.height);
  40068. rect.fill(color);
  40069. }
  40070. });
  40071. /**
  40072. * @class 资源渲染器
  40073. */
  40074. var ResourceRenderer = kity.createClass('ResourceRenderer', {
  40075. base: KityMinder.Renderer,
  40076. create: function(node) {
  40077. this.overlays = [];
  40078. return new kity.Group();
  40079. },
  40080. shouldRender: function(node) {
  40081. return node.getData('resource') && node.getData('resource').length;
  40082. },
  40083. update: function(container, node, box) {
  40084. var spaceRight = node.getStyle('space-right');
  40085. var overlays = this.overlays;
  40086. var resource = node.getData('resource');
  40087. var minder = node.getMinder();
  40088. var i, overlay, x;
  40089. x = 0;
  40090. for (i = 0; i < resource.length; i++) {
  40091. x += spaceRight;
  40092. overlay = overlays[i];
  40093. if (!overlay) {
  40094. overlay = new ResourceOverlay();
  40095. overlays.push(overlay);
  40096. container.addShape(overlay);
  40097. }
  40098. overlay.setVisible(true);
  40099. overlay.setValue(resource[i], minder.getResourceColor(resource[i]));
  40100. overlay.setTranslate(x, -1);
  40101. x += overlay.width;
  40102. }
  40103. while ((overlay = overlays[i++])) overlay.setVisible(false);
  40104. container.setTranslate(box.right, 0);
  40105. return new kity.Box({
  40106. x: box.right,
  40107. y: Math.round(-overlays[0].height / 2),
  40108. width: x,
  40109. height: overlays[0].height
  40110. });
  40111. }
  40112. });
  40113. return {
  40114. commands: {
  40115. 'resource': ResourceCommand
  40116. },
  40117. renderers: {
  40118. right: ResourceRenderer
  40119. }
  40120. };
  40121. });
  40122. /**
  40123. * @fileOverview
  40124. *
  40125. * 支持节点详细信息(HTML)格式
  40126. *
  40127. * @author: techird
  40128. * @copyright: Baidu FEX, 2014
  40129. */
  40130. KityMinder.registerModule('NoteModule', function() {
  40131. var NOTE_PATH = 'M9,9H3V8h6L9,9L9,9z M9,7H3V6h6V7z M9,5H3V4h6V5z M8.5,11H2V2h8v7.5 M9,12l2-2V1H1v11';
  40132. var NoteCommand = kity.createClass('NoteCommand', {
  40133. base: Command,
  40134. execute: function(minder, note) {
  40135. var node = minder.getSelectedNode();
  40136. node.setData('note', note);
  40137. node.render();
  40138. node.getMinder().layout(300);
  40139. },
  40140. queryState: function(minder) {
  40141. return minder.getSelectedNodes().length === 1 ? 0 : -1;
  40142. },
  40143. queryValue: function(minder) {
  40144. var node = minder.getSelectedNode();
  40145. return node && node.getData('note');
  40146. }
  40147. });
  40148. var NoteIcon = kity.createClass('NoteIcon', {
  40149. base: kity.Group,
  40150. constructor: function() {
  40151. this.callBase();
  40152. this.width = 16;
  40153. this.height = 17;
  40154. this.rect = new kity.Rect(16, 17, 0.5, -8.5, 2).fill('transparent');
  40155. this.path = new kity.Path().setPathData(NOTE_PATH).setTranslate(2.5, -6.5);
  40156. this.addShapes([this.rect, this.path]);
  40157. this.on('mouseover', function() {
  40158. this.rect.fill('rgba(255, 255, 200, .8)');
  40159. }).on('mouseout', function() {
  40160. this.rect.fill('transparent');
  40161. });
  40162. this.setStyle('cursor', 'pointer');
  40163. }
  40164. });
  40165. var NoteIconRenderer = kity.createClass('NoteIconRenderer', {
  40166. base: KityMinder.Renderer,
  40167. create: function(node) {
  40168. var icon = new NoteIcon();
  40169. icon.on('mousedown', function(e) {
  40170. e.preventDefault();
  40171. node.getMinder().fire('editnoterequest');
  40172. });
  40173. icon.on('mouseover', function() {
  40174. node.getMinder().fire('shownoterequest', {node: node, icon: icon});
  40175. });
  40176. icon.on('mouseout', function() {
  40177. node.getMinder().fire('hidenoterequest', {node: node, icon: icon});
  40178. });
  40179. return icon;
  40180. },
  40181. shouldRender: function(node) {
  40182. return node.getData('note');
  40183. },
  40184. update: function(icon, node, box) {
  40185. var x = box.right + node.getStyle('space-left');
  40186. var y = box.cy;
  40187. icon.path.fill(node.getStyle('color'));
  40188. icon.setTranslate(x, y);
  40189. return new kity.Box(x, Math.round(y - icon.height / 2), icon.width, icon.height);
  40190. }
  40191. });
  40192. return {
  40193. renderers: {
  40194. right: NoteIconRenderer
  40195. },
  40196. commands: {
  40197. 'note': NoteCommand
  40198. }
  40199. };
  40200. });
  40201. var ViewDragger = kity.createClass("ViewDragger", {
  40202. constructor: function(minder) {
  40203. this._minder = minder;
  40204. this._enabled = false;
  40205. this._bind();
  40206. var me = this;
  40207. this._minder.getViewDragger = function() {
  40208. return me;
  40209. };
  40210. },
  40211. isEnabled: function() {
  40212. return this._enabled;
  40213. },
  40214. setEnabled: function(value) {
  40215. var paper = this._minder.getPaper();
  40216. paper.setStyle('cursor', value ? 'pointer' : 'default');
  40217. paper.setStyle('cursor', value ? '-webkit-grab' : 'default');
  40218. this._enabled = value;
  40219. },
  40220. move: function(offset, duration) {
  40221. var minder = this._minder;
  40222. var targetPosition = this.getMovement().offset(offset);
  40223. this.moveTo(targetPosition, duration);
  40224. },
  40225. moveTo: function(position, duration) {
  40226. if (duration) {
  40227. var dragger = this;
  40228. if (this._moveTimeline) this._moveTimeline.stop();
  40229. this._moveTimeline = this._minder.getRenderContainer().animate(new kity.Animator(
  40230. this.getMovement(),
  40231. position,
  40232. function(target, value) {
  40233. dragger.moveTo(value);
  40234. }
  40235. ), duration, 'easeOutCubic');
  40236. this._moveTimeline.on('finish', function() {
  40237. dragger._moveTimeline = null;
  40238. });
  40239. return this;
  40240. }
  40241. this._minder.getRenderContainer().setTranslate(position.round());
  40242. this._minder.fire('viewchange');
  40243. },
  40244. getMovement: function() {
  40245. var translate = this._minder.getRenderContainer().transform.translate;
  40246. return translate ? translate[0] : new kity.Point();
  40247. },
  40248. getView: function() {
  40249. var minder = this._minder;
  40250. var c = {
  40251. width: minder.getRenderTarget().clientWidth,
  40252. height: minder.getRenderTarget().clientHeight
  40253. };
  40254. var m = this.getMovement();
  40255. var box = new kity.Box(0, 0, c.width, c.height);
  40256. var viewMatrix = minder.getPaper().getViewPortMatrix();
  40257. return viewMatrix.inverse().translate(-m.x, -m.y).transformBox(box);
  40258. },
  40259. _bind: function() {
  40260. var dragger = this,
  40261. isTempDrag = false,
  40262. lastPosition = null,
  40263. currentPosition = null;
  40264. function dragEnd(e) {
  40265. if (!lastPosition) return;
  40266. lastPosition = null;
  40267. e.stopPropagation();
  40268. // 临时拖动需要还原状态
  40269. if (isTempDrag) {
  40270. dragger.setEnabled(false);
  40271. isTempDrag = false;
  40272. if (dragger._minder.getStatus() == 'hand')
  40273. dragger._minder.rollbackStatus();
  40274. }
  40275. var paper = dragger._minder.getPaper();
  40276. paper.setStyle('cursor', dragger._minder.getStatus() == 'hand' ? '-webkit-grab' : 'default');
  40277. }
  40278. this._minder.on('normal.mousedown normal.touchstart ' +
  40279. 'inputready.mousedown inputready.touchstart ' +
  40280. 'readonly.mousedown readonly.touchstart', function(e) {
  40281. if (e.originEvent.button == 2) {
  40282. e.originEvent.preventDefault(); // 阻止中键拉动
  40283. }
  40284. // 点击未选中的根节点临时开启
  40285. if (e.getTargetNode() == this.getRoot() || e.originEvent.button == 2 || e.originEvent.altKey) {
  40286. lastPosition = e.getPosition();
  40287. isTempDrag = true;
  40288. }
  40289. })
  40290. .on('normal.mousemove normal.touchmove ' +
  40291. 'readonly.mousemove readonly.touchmove ' +
  40292. 'inputready.mousemove inputready.touchmove', function(e) {
  40293. if (e.type == 'touchmove') {
  40294. e.preventDefault(); // 阻止浏览器的后退事件
  40295. }
  40296. if (!isTempDrag) return;
  40297. var offset = kity.Vector.fromPoints(lastPosition, e.getPosition());
  40298. if (offset.length() > 10) {
  40299. this.setStatus('hand', true);
  40300. var paper = dragger._minder.getPaper();
  40301. paper.setStyle('cursor', '-webkit-grabbing');
  40302. }
  40303. })
  40304. .on('hand.beforemousedown hand.beforetouchstart', function(e) {
  40305. // 已经被用户打开拖放模式
  40306. if (dragger.isEnabled()) {
  40307. lastPosition = e.getPosition();
  40308. e.stopPropagation();
  40309. var paper = dragger._minder.getPaper();
  40310. paper.setStyle('cursor', '-webkit-grabbing');
  40311. }
  40312. })
  40313. .on('hand.beforemousemove hand.beforetouchmove', function(e) {
  40314. if (lastPosition) {
  40315. currentPosition = e.getPosition();
  40316. // 当前偏移加上历史偏移
  40317. var offset = kity.Vector.fromPoints(lastPosition, currentPosition);
  40318. dragger.move(offset);
  40319. e.stopPropagation();
  40320. e.preventDefault();
  40321. e.originEvent.preventDefault();
  40322. lastPosition = currentPosition;
  40323. }
  40324. })
  40325. .on('mouseup touchend', dragEnd);
  40326. window.addEventListener('mouseup', dragEnd);
  40327. this._minder.on('contextmenu', function(e) {
  40328. e.preventDefault();
  40329. });
  40330. }
  40331. });
  40332. KityMinder.registerModule('View', function() {
  40333. var km = this;
  40334. var ToggleHandCommand = kity.createClass('ToggleHandCommand', {
  40335. base: Command,
  40336. execute: function(minder) {
  40337. if (minder.getStatus() != 'hand') {
  40338. minder.setStatus('hand', true);
  40339. } else {
  40340. minder.rollbackStatus();
  40341. }
  40342. this.setContentChanged(false);
  40343. },
  40344. queryState: function(minder) {
  40345. return minder.getStatus() == 'hand' ? 1 : 0;
  40346. },
  40347. enableReadOnly: true
  40348. });
  40349. var CameraCommand = kity.createClass('CameraCommand', {
  40350. base: Command,
  40351. execute: function(km, focusNode, duration) {
  40352. focusNode = focusNode || km.getRoot();
  40353. var viewport = km.getPaper().getViewPort();
  40354. var offset = focusNode.getRenderContainer().getRenderBox('view');
  40355. var dx = viewport.center.x - offset.x - offset.width / 2,
  40356. dy = viewport.center.y - offset.y;
  40357. var dragger = km._viewDragger;
  40358. dragger.move(new kity.Point(dx, dy), duration);
  40359. this.setContentChanged(false);
  40360. },
  40361. enableReadOnly: true
  40362. });
  40363. var MoveCommand = kity.createClass('MoveCommand', {
  40364. base: Command,
  40365. execute: function(km, dir, duration) {
  40366. var dragger = km._viewDragger;
  40367. var size = km._lastClientSize;
  40368. switch (dir) {
  40369. case 'up':
  40370. dragger.move(new kity.Point(0, size.height / 2), duration);
  40371. break;
  40372. case 'down':
  40373. dragger.move(new kity.Point(0, -size.height / 2), duration);
  40374. break;
  40375. case 'left':
  40376. dragger.move(new kity.Point(size.width / 2, 0), duration);
  40377. break;
  40378. case 'right':
  40379. dragger.move(new kity.Point(-size.width / 2, 0), duration);
  40380. break;
  40381. }
  40382. },
  40383. enableReadOnly: true
  40384. });
  40385. return {
  40386. init: function() {
  40387. this._viewDragger = new ViewDragger(this);
  40388. },
  40389. commands: {
  40390. 'hand': ToggleHandCommand,
  40391. 'camera': CameraCommand,
  40392. 'move': MoveCommand
  40393. },
  40394. events: {
  40395. keydown: function(e) {
  40396. var minder = this;
  40397. ['up', 'down', 'left', 'right'].forEach(function(name) {
  40398. if (e.isShortcutKey('ctrl+' + name) && minder.getStatus() != 'textedit') {
  40399. minder.removeAllSelectedNodes();
  40400. minder.execCommand('move', name, 100);
  40401. e.preventDefault();
  40402. }
  40403. });
  40404. if (e.isShortcutKey('ctrl+enter')) {
  40405. minder.execCommand('camera', minder.getRoot(), 100);
  40406. }
  40407. },
  40408. statuschange: function(e) {
  40409. this._viewDragger.setEnabled(e.currentStatus == 'hand');
  40410. },
  40411. mousewheel: function(e) {
  40412. var dx, dy;
  40413. e = e.originEvent;
  40414. if (e.ctrlKey || e.shiftKey) return;
  40415. if ('wheelDeltaX' in e) {
  40416. dx = e.wheelDeltaX || 0;
  40417. dy = e.wheelDeltaY || 0;
  40418. } else {
  40419. dx = 0;
  40420. dy = e.wheelDelta;
  40421. }
  40422. this._viewDragger.move({
  40423. x: dx / 2.5,
  40424. y: dy / 2.5
  40425. });
  40426. e.preventDefault();
  40427. },
  40428. 'normal.dblclick readonly.dblclick': function(e) {
  40429. if (e.kityEvent.targetShape instanceof kity.Paper) {
  40430. this.execCommand('camera', this.getRoot(), 800);
  40431. }
  40432. },
  40433. ready: function() {
  40434. this.execCommand('camera', null, 0);
  40435. this._lastClientSize = {
  40436. width: this.getRenderTarget().clientWidth,
  40437. height: this.getRenderTarget().clientHeight
  40438. };
  40439. },
  40440. resize: function(e) {
  40441. var a = {
  40442. width: this.getRenderTarget().clientWidth,
  40443. height: this.getRenderTarget().clientHeight
  40444. },
  40445. b = this._lastClientSize;
  40446. this._viewDragger.move(
  40447. new kity.Point((a.width - b.width) / 2 | 0, (a.height - b.height) / 2 | 0));
  40448. this._lastClientSize = a;
  40449. },
  40450. 'selectionchange layoutallfinish': function(e) {
  40451. var selected = this.getSelectedNode();
  40452. if (!selected) return;
  40453. var dragger = this._viewDragger;
  40454. var view = dragger.getView();
  40455. var focus = selected.getLayoutBox();
  40456. var space = 50;
  40457. var dx = 0, dy = 0;
  40458. if (focus.right > view.right) {
  40459. dx += view.right - focus.right - space;
  40460. }
  40461. else if (focus.left < view.left) {
  40462. dx += view.left - focus.left + space;
  40463. }
  40464. if (focus.bottom > view.bottom) {
  40465. dy += view.bottom - focus.bottom - space;
  40466. }
  40467. if (focus.top < view.top) {
  40468. dy += view.top - focus.top + space;
  40469. }
  40470. if (dx || dy) dragger.move(new kity.Point(dx, dy), 100);
  40471. }
  40472. }
  40473. };
  40474. });
  40475. var GM = KityMinder.Geometry;
  40476. // 矩形的变形动画定义
  40477. var MoveToParentCommand = kity.createClass('MoveToParentCommand', {
  40478. base: Command,
  40479. execute: function(minder, nodes, parent) {
  40480. var node;
  40481. for (var i = nodes.length - 1; i >= 0; i--) {
  40482. node = nodes[i];
  40483. if (node.parent) {
  40484. node.parent.removeChild(node);
  40485. parent.appendChild(node);
  40486. node.render();
  40487. }
  40488. }
  40489. parent.expand();
  40490. minder.select(nodes, true);
  40491. }
  40492. });
  40493. var DropHinter = kity.createClass('DropHinter', {
  40494. base: kity.Group,
  40495. constructor: function() {
  40496. this.callBase();
  40497. this.rect = new kity.Rect();
  40498. this.addShape(this.rect);
  40499. },
  40500. render: function(target) {
  40501. this.setVisible(!!target);
  40502. if (target) {
  40503. this.rect
  40504. .setBox(target.getLayoutBox())
  40505. .setRadius(target.getStyle('radius') || 0)
  40506. .stroke(
  40507. target.getStyle('drop-hint-color') || 'yellow',
  40508. target.getStyle('drop-hint-width') || 2
  40509. );
  40510. this.bringTop();
  40511. }
  40512. }
  40513. });
  40514. var OrderHinter = kity.createClass('OrderHinter', {
  40515. base: kity.Group,
  40516. constructor: function() {
  40517. this.callBase();
  40518. this.area = new kity.Rect();
  40519. this.path = new kity.Path();
  40520. this.addShapes([this.area, this.path]);
  40521. },
  40522. render: function(hint) {
  40523. this.setVisible(!!hint);
  40524. if (hint) {
  40525. this.area.setBox(hint.area);
  40526. this.area.fill(hint.node.getStyle('order-hint-area-color') || 'rgba(0, 255, 0, .5)');
  40527. this.path.setPathData(hint.path);
  40528. this.path.stroke(
  40529. hint.node.getStyle('order-hint-path-color') || '#0f0',
  40530. hint.node.getStyle('order-hint-path-width') || 1);
  40531. }
  40532. }
  40533. });
  40534. // 对拖动对象的一个替代盒子,控制整个拖放的逻辑,包括:
  40535. // 1. 从节点列表计算出拖动部分
  40536. // 2. 计算可以 drop 的节点,产生 drop 交互提示
  40537. var TreeDragger = kity.createClass('TreeDragger', {
  40538. constructor: function(minder) {
  40539. this._minder = minder;
  40540. this._dropHinter = new DropHinter();
  40541. this._orderHinter = new OrderHinter();
  40542. minder.getRenderContainer().addShapes([this._dropHinter, this._orderHinter]);
  40543. },
  40544. dragStart: function(position) {
  40545. // 只记录开始位置,不马上开启拖放模式
  40546. // 这个位置同时是拖放范围收缩时的焦点位置(中心)
  40547. this._startPosition = position;
  40548. },
  40549. dragMove: function(position) {
  40550. // 启动拖放模式需要最小的移动距离
  40551. var DRAG_MOVE_THRESHOLD = 10;
  40552. if (!this._startPosition) return;
  40553. var movement = kity.Vector.fromPoints(this._dragPosition || this._startPosition, position);
  40554. var minder = this._minder;
  40555. this._dragPosition = position;
  40556. if (!this._dragMode) {
  40557. // 判断拖放模式是否该启动
  40558. if (GM.getDistance(this._dragPosition, this._startPosition) < DRAG_MOVE_THRESHOLD) {
  40559. return;
  40560. }
  40561. if (!this._enterDragMode()) {
  40562. return;
  40563. }
  40564. }
  40565. for (var i = 0; i < this._dragSources.length; i++) {
  40566. this._dragSources[i].setLayoutOffset(this._dragSources[i].getLayoutOffset().offset(movement));
  40567. minder.applyLayoutResult(this._dragSources[i]);
  40568. }
  40569. if (!this._dropTest()) {
  40570. this._orderTest();
  40571. } else {
  40572. this._renderOrderHint(this._orderSucceedHint = null);
  40573. }
  40574. },
  40575. dragEnd: function() {
  40576. this._startPosition = null;
  40577. this._dragPosition = null;
  40578. if (!this._dragMode) {
  40579. return;
  40580. }
  40581. this._fadeDragSources(1);
  40582. if (this._dropSucceedTarget) {
  40583. this._dragSources.forEach(function(source) {
  40584. source.setLayoutOffset(null);
  40585. });
  40586. this._minder.layout(-1);
  40587. this._minder.execCommand('movetoparent', this._dragSources, this._dropSucceedTarget);
  40588. } else if (this._orderSucceedHint) {
  40589. var hint = this._orderSucceedHint;
  40590. var index = hint.node.getIndex();
  40591. var sourceIndexes = this._dragSources.map(function(source) {
  40592. // 顺便干掉布局偏移
  40593. source.setLayoutOffset(null);
  40594. return source.getIndex();
  40595. });
  40596. var maxIndex = Math.max.apply(Math, sourceIndexes);
  40597. var minIndex = Math.min.apply(Math, sourceIndexes);
  40598. if (index < minIndex && hint.type == 'down') index++;
  40599. if (index > maxIndex && hint.type == 'up') index--;
  40600. hint.node.setLayoutOffset(null);
  40601. this._minder.execCommand('arrange', this._dragSources, index);
  40602. this._renderOrderHint(null);
  40603. } else {
  40604. this._minder.fire('savescene');
  40605. }
  40606. this._minder.layout(300);
  40607. this._leaveDragMode();
  40608. this._minder.fire('contentchange');
  40609. },
  40610. // 进入拖放模式:
  40611. // 1. 计算拖放源和允许的拖放目标
  40612. // 2. 标记已启动
  40613. _enterDragMode: function() {
  40614. this._calcDragSources();
  40615. if (!this._dragSources.length) {
  40616. this._startPosition = null;
  40617. return false;
  40618. }
  40619. this._fadeDragSources(0.5);
  40620. this._calcDropTargets();
  40621. this._calcOrderHints();
  40622. this._dragMode = true;
  40623. this._minder.setStatus('dragtree');
  40624. return true;
  40625. },
  40626. // 从选中的节点计算拖放源
  40627. // 并不是所有选中的节点都作为拖放源,如果选中节点中存在 A 和 B,
  40628. // 并且 A 是 B 的祖先,则 B 不作为拖放源
  40629. //
  40630. // 计算过程:
  40631. // 1. 将节点按照树高排序,排序后只可能是前面节点是后面节点的祖先
  40632. // 2. 从后往前枚举排序的结果,如果发现枚举目标之前存在其祖先,
  40633. // 则排除枚举目标作为拖放源,否则加入拖放源
  40634. _calcDragSources: function() {
  40635. this._dragSources = this._minder.getSelectedAncestors();
  40636. },
  40637. _fadeDragSources: function(opacity) {
  40638. var minder = this._minder;
  40639. this._dragSources.forEach(function(source) {
  40640. source.getRenderContainer().setOpacity(opacity, 200);
  40641. source.traverse(function(node) {
  40642. if (opacity < 1) {
  40643. minder.detachNode(node);
  40644. } else {
  40645. minder.attachNode(node);
  40646. }
  40647. }, true);
  40648. });
  40649. },
  40650. // 计算拖放目标可以释放的节点列表(释放意味着成为其子树),存在这条限制规则:
  40651. // - 不能拖放到拖放目标的子树上(允许拖放到自身,因为多选的情况下可以把其它节点加入)
  40652. //
  40653. // 1. 加入当前节点(初始为根节点)到允许列表
  40654. // 2. 对于当前节点的每一个子节点:
  40655. // (1) 如果是拖放目标的其中一个节点,忽略(整棵子树被剪枝)
  40656. // (2) 如果不是拖放目标之一,以当前子节点为当前节点,回到 1 计算
  40657. // 3. 返回允许列表
  40658. //
  40659. _calcDropTargets: function() {
  40660. function findAvailableParents(nodes, root) {
  40661. var availables = [],
  40662. i;
  40663. availables.push(root);
  40664. root.getChildren().forEach(function(test) {
  40665. for (i = 0; i < nodes.length; i++) {
  40666. if (nodes[i] == test) return;
  40667. }
  40668. availables = availables.concat(findAvailableParents(nodes, test));
  40669. });
  40670. return availables;
  40671. }
  40672. this._dropTargets = findAvailableParents(this._dragSources, this._minder.getRoot());
  40673. this._dropTargetBoxes = this._dropTargets.map(function(source) {
  40674. return source.getLayoutBox();
  40675. });
  40676. },
  40677. _calcOrderHints: function() {
  40678. var sources = this._dragSources;
  40679. var ancestor = MinderNode.getCommonAncestor(sources);
  40680. // 只有一个元素选中,公共祖先是其父
  40681. if (ancestor == sources[0]) ancestor = sources[0].parent;
  40682. if (sources.length === 0 || ancestor != sources[0].parent) {
  40683. this._orderHints = [];
  40684. return;
  40685. }
  40686. var siblings = ancestor.children;
  40687. this._orderHints = siblings.reduce(function(hint, sibling) {
  40688. if (sources.indexOf(sibling) == -1) {
  40689. hint = hint.concat(sibling.getOrderHint());
  40690. }
  40691. return hint;
  40692. }, []);
  40693. },
  40694. _leaveDragMode: function() {
  40695. this._dragMode = false;
  40696. this._dropSucceedTarget = null;
  40697. this._orderSucceedHint = null;
  40698. this._renderDropHint(null);
  40699. this._renderOrderHint(null);
  40700. this._minder.rollbackStatus();
  40701. },
  40702. _drawForDragMode: function() {
  40703. this._text.setContent(this._dragSources.length + ' items');
  40704. this._text.setPosition(this._startPosition.x, this._startPosition.y + 5);
  40705. this._minder.getRenderContainer().addShape(this);
  40706. },
  40707. _boxTest: function(targets, targetBoxMapper, judge) {
  40708. var sourceBoxes = this._dragSources.map(function(source) {
  40709. return source.getLayoutBox();
  40710. });
  40711. var i, j, target, sourceBox, targetBox;
  40712. judge = judge || function(intersectBox, sourceBox, targetBox) {
  40713. return intersectBox;
  40714. };
  40715. for (i = 0; i < targets.length; i++) {
  40716. target = targets[i];
  40717. targetBox = targetBoxMapper.call(this, target, i);
  40718. for (j = 0; j < sourceBoxes.length; j++) {
  40719. sourceBox = sourceBoxes[j];
  40720. var intersectBox = GM.getIntersectBox(sourceBox, targetBox);
  40721. if (judge(intersectBox, sourceBox, targetBox)) {
  40722. return target;
  40723. }
  40724. }
  40725. }
  40726. return null;
  40727. },
  40728. _dropTest: function() {
  40729. this._dropSucceedTarget = this._boxTest(this._dropTargets, function(target, i) {
  40730. return this._dropTargetBoxes[i];
  40731. }, function(intersectBox, sourceBox, targetBox) {
  40732. function area(box) {
  40733. return box.width * box.height;
  40734. }
  40735. if (!intersectBox) return false;
  40736. // 面积判断
  40737. if (area(intersectBox) > 0.5 * Math.min(area(sourceBox), area(targetBox))) return true;
  40738. if (intersectBox.width + 1 >= Math.min(sourceBox.width, targetBox.width)) return true;
  40739. if (intersectBox.height + 1 >= Math.min(sourceBox.height, targetBox.height)) return true;
  40740. return false;
  40741. });
  40742. this._renderDropHint(this._dropSucceedTarget);
  40743. return !!this._dropSucceedTarget;
  40744. },
  40745. _orderTest: function() {
  40746. this._orderSucceedHint = this._boxTest(this._orderHints, function(hint) {
  40747. return hint.area;
  40748. });
  40749. this._renderOrderHint(this._orderSucceedHint);
  40750. return !!this._orderSucceedHint;
  40751. },
  40752. _renderDropHint: function(target) {
  40753. this._dropHinter.render(target);
  40754. },
  40755. _renderOrderHint: function(hint) {
  40756. this._orderHinter.render(hint);
  40757. },
  40758. preventDragMove: function() {
  40759. this._startPosition = null;
  40760. }
  40761. });
  40762. KityMinder.registerModule('DragTree', function() {
  40763. var dragger;
  40764. return {
  40765. init: function() {
  40766. dragger = new TreeDragger(this);
  40767. window.addEventListener('mouseup', function() {
  40768. dragger.dragEnd();
  40769. });
  40770. },
  40771. events: {
  40772. 'normal.mousedown inputready.mousedown': function(e) {
  40773. // 单选中根节点也不触发拖拽
  40774. if (e.originEvent.button) return;
  40775. if (e.getTargetNode() && e.getTargetNode() != this.getRoot()) {
  40776. dragger.dragStart(e.getPosition(this.getRenderContainer()));
  40777. }
  40778. },
  40779. 'normal.mousemove dragtree.mousemove': function(e) {
  40780. dragger.dragMove(e.getPosition(this.getRenderContainer()));
  40781. },
  40782. 'normal.mouseup dragtree.beforemouseup': function(e) {
  40783. dragger.dragEnd();
  40784. //e.stopPropagation();
  40785. e.preventDefault();
  40786. },
  40787. 'statuschange': function(e) {
  40788. if (e.lastStatus == 'textedit' && e.currentStatus == 'normal') {
  40789. dragger.preventDragMove();
  40790. }
  40791. }
  40792. },
  40793. commands: {
  40794. 'movetoparent': MoveToParentCommand
  40795. }
  40796. };
  40797. });
  40798. KityMinder.registerModule('KeyboardModule', function() {
  40799. var min = Math.min,
  40800. max = Math.max,
  40801. abs = Math.abs,
  40802. sqrt = Math.sqrt,
  40803. exp = Math.exp;
  40804. function buildPositionNetwork(root) {
  40805. var pointIndexes = [],
  40806. p;
  40807. root.traverse(function(node) {
  40808. p = node.getLayoutBox();
  40809. // bugfix: 不应导航到收起的节点(判断其尺寸是否存在)
  40810. if (p.width && p.height) {
  40811. pointIndexes.push({
  40812. left: p.x,
  40813. top: p.y,
  40814. right: p.x + p.width,
  40815. bottom: p.y + p.height,
  40816. width: p.width,
  40817. height: p.height,
  40818. node: node,
  40819. text: node.getText()
  40820. });
  40821. }
  40822. });
  40823. for (var i = 0; i < pointIndexes.length; i++) {
  40824. findClosestPointsFor(pointIndexes, i);
  40825. }
  40826. }
  40827. // 这是金泉的点子,赞!
  40828. // 求两个不相交矩形的最近距离
  40829. function getCoefedDistance(box1, box2) {
  40830. var xMin, xMax, yMin, yMax, xDist, yDist, dist, cx, cy;
  40831. xMin = min(box1.left, box2.left);
  40832. xMax = max(box1.right, box2.right);
  40833. yMin = min(box1.top, box2.top);
  40834. yMax = max(box1.bottom, box2.bottom);
  40835. xDist = xMax - xMin - box1.width - box2.width;
  40836. yDist = yMax - yMin - box1.height - box2.height;
  40837. if (xDist < 0) dist = yDist;
  40838. else if (yDist < 0) dist = xDist;
  40839. else dist = sqrt(xDist * xDist + yDist * yDist);
  40840. return {
  40841. cx: dist,
  40842. cy: dist
  40843. };
  40844. }
  40845. function findClosestPointsFor(pointIndexes, iFind) {
  40846. var find = pointIndexes[iFind];
  40847. var most = {},
  40848. quad;
  40849. var current, dist;
  40850. for (var i = 0; i < pointIndexes.length; i++) {
  40851. if (i == iFind) continue;
  40852. current = pointIndexes[i];
  40853. dist = getCoefedDistance(current, find);
  40854. // left check
  40855. if (current.right < find.left) {
  40856. if (!most.left || dist.cx < most.left.dist) {
  40857. most.left = {
  40858. dist: dist.cx,
  40859. node: current.node
  40860. };
  40861. }
  40862. }
  40863. // right check
  40864. if (current.left > find.right) {
  40865. if (!most.right || dist.cx < most.right.dist) {
  40866. most.right = {
  40867. dist: dist.cx,
  40868. node: current.node
  40869. };
  40870. }
  40871. }
  40872. // top check
  40873. if (current.bottom < find.top) {
  40874. if (!most.top || dist.cy < most.top.dist) {
  40875. most.top = {
  40876. dist: dist.cy,
  40877. node: current.node
  40878. };
  40879. }
  40880. }
  40881. // bottom check
  40882. if (current.top > find.bottom) {
  40883. if (!most.down || dist.cy < most.down.dist) {
  40884. most.down = {
  40885. dist: dist.cy,
  40886. node: current.node
  40887. };
  40888. }
  40889. }
  40890. }
  40891. find.node._nearestNodes = {
  40892. right: most.right && most.right.node || null,
  40893. top: most.top && most.top.node || null,
  40894. left: most.left && most.left.node || null,
  40895. down: most.down && most.down.node || null
  40896. };
  40897. }
  40898. function navigateTo(km, direction) {
  40899. var referNode = km.getSelectedNode();
  40900. if (!referNode) {
  40901. km.select(km.getRoot());
  40902. buildPositionNetwork(km.getRoot());
  40903. return;
  40904. }
  40905. if (!referNode._nearestNodes) {
  40906. buildPositionNetwork(km.getRoot());
  40907. }
  40908. var nextNode = referNode._nearestNodes[direction];
  40909. if (nextNode) {
  40910. km.select(nextNode, true);
  40911. }
  40912. }
  40913. var NavigateToParentCommand = kity.createClass({
  40914. base: Command,
  40915. execute: function(km) {
  40916. var node = km.getSelectedNode();
  40917. if (node && node.parent) {
  40918. km.select(node.parent, true);
  40919. }
  40920. this.setContentChanged(false);
  40921. },
  40922. queryState: function(km) {
  40923. return km.getSelectedNode() ? 0 : -1;
  40924. },
  40925. enableReadOnly: true
  40926. });
  40927. // 稀释用
  40928. var lastFrame;
  40929. return {
  40930. 'commands': {
  40931. 'navparent': NavigateToParentCommand
  40932. },
  40933. 'commandShortcutKeys': {
  40934. 'navparent': 'shift+tab'
  40935. },
  40936. 'events': {
  40937. 'layoutallfinish': function() {
  40938. var root = this.getRoot();
  40939. buildPositionNetwork(root);
  40940. },
  40941. 'normal.keydown readonly.keydown': function(e) {
  40942. var minder = this;
  40943. ['left', 'right', 'up', 'down'].forEach(function(key) {
  40944. if (e.isShortcutKey(key)) {
  40945. navigateTo(minder, key == 'up' ? 'top' : key);
  40946. }
  40947. });
  40948. },
  40949. 'normal.keyup': function(e) {
  40950. if (browser.ipad) {
  40951. var keys = KityMinder.keymap;
  40952. var node = e.getTargetNode();
  40953. var lang = this.getLang();
  40954. if (this.receiver) this.receiver.keydownNode = node;
  40955. var keyEvent = e.originEvent;
  40956. if (keyEvent.altKey || keyEvent.ctrlKey || keyEvent.metaKey || keyEvent.shiftKey) return;
  40957. switch (keyEvent.keyCode) {
  40958. case keys.Enter:
  40959. this.execCommand('AppendSiblingNode', lang.topic);
  40960. e.preventDefault();
  40961. break;
  40962. case keys.Backspace:
  40963. case keys.Del:
  40964. e.preventDefault();
  40965. this.execCommand('RemoveNode');
  40966. break;
  40967. }
  40968. }
  40969. }
  40970. }
  40971. };
  40972. });
  40973. KityMinder.registerModule('Select', function() {
  40974. var minder = this;
  40975. var rc = minder.getRenderContainer();
  40976. var g = KityMinder.Geometry;
  40977. // 在实例上渲染框选矩形、计算框选范围的对象
  40978. var marqueeActivator = (function() {
  40979. // 记录选区的开始位置(mousedown的位置)
  40980. var startPosition = null;
  40981. // 选区的图形
  40982. var marqueeShape = new kity.Path();
  40983. // 标记是否已经启动框选状态
  40984. // 并不是 mousedown 发生之后就启动框选状态,而是检测到移动了一定的距离(MARQUEE_MODE_THRESHOLD)之后
  40985. var marqueeMode = false;
  40986. var MARQUEE_MODE_THRESHOLD = 10;
  40987. return {
  40988. selectStart: function(e) {
  40989. // 只接受左键
  40990. if (e.originEvent.button || e.originEvent.altKey) return;
  40991. // 清理不正确状态
  40992. if (startPosition) {
  40993. return this.selectEnd();
  40994. }
  40995. startPosition = g.snapToSharp(e.getPosition(rc));
  40996. },
  40997. selectMove: function(e) {
  40998. if (minder.getStatus() == 'textedit') {
  40999. return;
  41000. }
  41001. if (!startPosition) return;
  41002. var p1 = startPosition,
  41003. p2 = e.getPosition(rc);
  41004. // 检测是否要进入选区模式
  41005. if (!marqueeMode) {
  41006. // 距离没达到阈值,退出
  41007. if (g.getDistance(p1, p2) < MARQUEE_MODE_THRESHOLD) {
  41008. return;
  41009. }
  41010. // 已经达到阈值,记录下来并且重置选区形状
  41011. marqueeMode = true;
  41012. rc.addShape(marqueeShape);
  41013. marqueeShape
  41014. .fill(minder.getStyle('marquee-background'))
  41015. .stroke(minder.getStyle('marquee-stroke')).setOpacity(0.8).getDrawer().clear();
  41016. }
  41017. var marquee = g.getBox(p1, p2),
  41018. selectedNodes = [];
  41019. // 使其犀利
  41020. marquee.left = Math.round(marquee.left);
  41021. marquee.top = Math.round(marquee.top);
  41022. marquee.right = Math.round(marquee.right);
  41023. marquee.bottom = Math.round(marquee.bottom);
  41024. // 选区形状更新
  41025. marqueeShape.getDrawer().pipe(function() {
  41026. this.clear();
  41027. this.moveTo(marquee.left, marquee.top);
  41028. this.lineTo(marquee.right, marquee.top);
  41029. this.lineTo(marquee.right, marquee.bottom);
  41030. this.lineTo(marquee.left, marquee.bottom);
  41031. this.close();
  41032. });
  41033. // 计算选中范围
  41034. minder.getRoot().traverse(function(node) {
  41035. var renderBox = node.getLayoutBox();
  41036. if (g.getIntersectBox(renderBox, marquee)) {
  41037. selectedNodes.push(node);
  41038. }
  41039. });
  41040. // 应用选中范围
  41041. minder.select(selectedNodes, true);
  41042. // 清除多余的东西
  41043. window.getSelection().removeAllRanges();
  41044. },
  41045. selectEnd: function(e) {
  41046. if (startPosition) {
  41047. startPosition = null;
  41048. }
  41049. if (marqueeMode) {
  41050. marqueeShape.fadeOut(200, 'ease', 0, function() {
  41051. if (marqueeShape.remove) marqueeShape.remove();
  41052. });
  41053. marqueeMode = false;
  41054. }
  41055. }
  41056. };
  41057. })();
  41058. var lastDownNode = null, lastDownPosition = null;
  41059. return {
  41060. 'init': function() {
  41061. window.addEventListener('mouseup', function() {
  41062. marqueeActivator.selectEnd();
  41063. });
  41064. },
  41065. 'events': {
  41066. 'mousedown': function(e) {
  41067. var downNode = e.getTargetNode();
  41068. // 没有点中节点:
  41069. // 清除选中状态,并且标记选区开始位置
  41070. if (!downNode) {
  41071. this.removeAllSelectedNodes();
  41072. marqueeActivator.selectStart(e);
  41073. this.setStatus('normal');
  41074. }
  41075. // 点中了节点,并且按了 shift 键:
  41076. // 被点中的节点切换选中状态
  41077. else if (e.originEvent.shiftKey) {
  41078. this.toggleSelect(downNode);
  41079. }
  41080. // 点中的节点没有被选择:
  41081. // 单选点中的节点
  41082. else if (!downNode.isSelected()) {
  41083. this.select(downNode, true);
  41084. }
  41085. // 点中的节点被选中了,并且不是单选:
  41086. // 完成整个点击之后需要使其变为单选。
  41087. // 不能马上变为单选,因为可能是需要拖动选中的多个节点
  41088. else if (!this.isSingleSelect()) {
  41089. lastDownNode = downNode;
  41090. lastDownPosition = e.getPosition(this.getRenderContainer());
  41091. }
  41092. },
  41093. 'mousemove': marqueeActivator.selectMove,
  41094. 'mouseup': function(e) {
  41095. var upNode = e.getTargetNode();
  41096. // 如果 mouseup 发生在 lastDownNode 外,是无需理会的
  41097. if (upNode && upNode == lastDownNode) {
  41098. var upPosition = e.getPosition(this.getRenderContainer());
  41099. var movement = kity.Vector.fromPoints(lastDownPosition, upPosition);
  41100. if (movement.length() < 1) this.select(lastDownNode, true);
  41101. lastDownNode = null;
  41102. }
  41103. // 清理一下选择状态
  41104. marqueeActivator.selectEnd(e);
  41105. },
  41106. //全选操作
  41107. 'normal.keydown inputready.keydown':function(e){
  41108. if ( e.isShortcutKey('ctrl+a') ){
  41109. var selectedNodes = [];
  41110. this.getRoot().traverse(function(node){
  41111. selectedNodes.push(node);
  41112. });
  41113. this.select(selectedNodes,true);
  41114. e.preventDefault();
  41115. }
  41116. }
  41117. }
  41118. };
  41119. });
  41120. /* global Renderer: true */
  41121. KityMinder.registerModule('TextEditModule', function() {
  41122. var km = this;
  41123. var sel = new Minder.Selection();
  41124. var range = new Minder.Range();
  41125. var receiver = new Minder.Receiver(this,sel,range);
  41126. var keyboarder = new Minder.keyboarder(receiver);
  41127. this.receiver = receiver;
  41128. //鼠标被点击,并未太抬起时为真
  41129. var mouseDownStatus = false;
  41130. var dblclickEvent = false;
  41131. //当前是否有选区存在
  41132. var selectionReadyShow = false;
  41133. var mousedownNode,mouseupTimer,mousedownTimer;
  41134. var lastMinderNode;
  41135. function inputStatusReady(node){
  41136. if (node && km.isSingleSelect() && node.isSelected()) {
  41137. node.getTextGroup().setStyle('cursor','default');
  41138. var color = node.getStyle('text-selection-color');
  41139. //准备输入状态
  41140. receiver.updateByMinderNode(node);
  41141. sel.setHide()
  41142. .setStartOffset(0)
  41143. .setEndOffset(receiver.getTxtOfContainer().length)
  41144. .setColor(color);
  41145. receiver.updateContainerRangeBySel();
  41146. if(browser.ie ){
  41147. var timer = setInterval(function(){
  41148. var nativeRange = range.nativeSel.getRangeAt(0);
  41149. if(!nativeRange || nativeRange.collapsed){
  41150. range.select();
  41151. }else {
  41152. clearInterval(timer);
  41153. }
  41154. });
  41155. }
  41156. km.setStatus('inputready');
  41157. }
  41158. }
  41159. km.textEditNode = function(node){
  41160. inputStatusReady(node);
  41161. km.setStatus('textedit');
  41162. receiver.updateSelection();
  41163. };
  41164. return {
  41165. 'events': {
  41166. 'ready': function() {
  41167. document.body.appendChild(receiver.container);
  41168. },
  41169. 'normal.beforemousedown textedit.beforemousedown inputready.beforemousedown': function(e) {
  41170. //右键直接退出
  41171. if (e.isRightMB()) {
  41172. if (!e.getTargetNode()) this.setStatus('normal');
  41173. return;
  41174. }
  41175. mouseDownStatus = true;
  41176. selectionReadyShow = sel.isShow();
  41177. sel.setHide();
  41178. var node = e.getTargetNode();
  41179. //点击在之前的选区上
  41180. if (!node) {
  41181. var selectionShape = e.kityEvent.targetShape;
  41182. if (selectionShape && selectionShape.getType() == 'Selection') {
  41183. node = receiver.getMinderNode();
  41184. e.stopPropagationImmediately();
  41185. }
  41186. }
  41187. if(node){
  41188. if (this.isSingleSelect() && node.isSelected()) {
  41189. lastMinderNode = node;
  41190. mousedownNode = node;
  41191. var textGroup = node.getTextGroup();
  41192. sel.collapse(true);
  41193. sel.setColor(node.getStyle('text-selection-color'));
  41194. receiver
  41195. .updateByMinderNode(node)
  41196. .updateIndexByMouse(e.getPosition(node.getRenderContainer()))
  41197. .setRange(range)
  41198. .setReady();
  41199. if(selectionReadyShow){
  41200. sel.setShowStatus();
  41201. clearTimeout(mousedownTimer);
  41202. mousedownTimer = setTimeout(function() {
  41203. if(dblclickEvent){
  41204. dblclickEvent = false;
  41205. return;
  41206. }
  41207. sel.collapse(true)
  41208. .updatePosition(receiver.getOffsetByIndex())
  41209. .setShow();
  41210. textGroup.setStyle('cursor','text');
  41211. },200);
  41212. km.setStatus('textedit');
  41213. }
  41214. return;
  41215. }
  41216. }
  41217. //模拟光标没有准备好
  41218. receiver.clearReady();
  41219. //当点击空白处时,光标需要消失
  41220. receiver.clear();
  41221. if(lastMinderNode){
  41222. lastMinderNode.getTextGroup().setStyle('cursor','default');
  41223. }
  41224. },
  41225. 'inputready.keyup':function(){
  41226. if(sel.isHide()){
  41227. inputStatusReady(this.getSelectedNode());
  41228. }
  41229. },
  41230. //当节点选区通过键盘发生变化时,输入状态要准备好
  41231. 'normal.keyup': function(e) {
  41232. var node = this.getSelectedNode();
  41233. var keyCode = e.getKeyCode();
  41234. if (node) {
  41235. if (this.isSingleSelect() && node.isSelected() && !sel.isShow() ) {
  41236. var orgEvt = e.originEvent;
  41237. if (keymap.isSelectedNodeKey[keyCode] &&
  41238. !orgEvt.ctrlKey &&
  41239. !orgEvt.metaKey &&
  41240. !orgEvt.shiftKey &&
  41241. !orgEvt.altKey) {
  41242. inputStatusReady(node);
  41243. }
  41244. }
  41245. }
  41246. },
  41247. 'normal.mouseup textedit.mouseup inputready.mouseup': function(e) {
  41248. mouseDownStatus = false;
  41249. var node = e.getTargetNode();
  41250. mousedownNode = null;
  41251. if (node && !selectionReadyShow && receiver.isReady()) {
  41252. sel.collapse(true);
  41253. sel.setColor(node.getStyle('text-selection-color'));
  41254. //必须再次focus,要不不能呼出键盘
  41255. if(browser.ipad){
  41256. receiver.focus();
  41257. }
  41258. clearTimeout(mouseupTimer);
  41259. mouseupTimer = setTimeout(function() {
  41260. if(dblclickEvent){
  41261. dblclickEvent = false;
  41262. return;
  41263. }
  41264. sel.collapse(true)
  41265. .updatePosition(receiver.getOffsetByIndex())
  41266. .setShow();
  41267. node.getTextGroup().setStyle('cursor','text');
  41268. }, 200);
  41269. km.setStatus('textedit');
  41270. return;
  41271. }
  41272. //当选中节点后,输入状态准备
  41273. if(sel.isHide()){
  41274. inputStatusReady(e.getTargetNode());
  41275. }else {
  41276. //当有光标时,要同步选区
  41277. if(!sel.collapsed){
  41278. receiver.updateContainerRangeBySel();
  41279. }
  41280. }
  41281. },
  41282. 'textedit.beforemousemove inputready.beforemousemove': function(e) {
  41283. if(browser.ipad){
  41284. return;
  41285. }
  41286. //ipad下不做框选
  41287. if (mouseDownStatus && receiver.isReady() && selectionReadyShow) {
  41288. e.stopPropagationImmediately();
  41289. if(mousedownNode){
  41290. var offset = e.getPosition( mousedownNode.getRenderContainer());
  41291. receiver
  41292. .updateSelectionByMousePosition(offset)
  41293. .updateSelection(offset);
  41294. setTimeout(function(){
  41295. receiver.updateContainerRangeBySel();
  41296. });
  41297. }
  41298. }else if(mouseDownStatus && !selectionReadyShow){
  41299. //第一次点中,第二次再次点中进行拖拽
  41300. km.setStatus('normal');
  41301. receiver.clearReady();
  41302. }
  41303. },
  41304. 'normal.dblclick textedit.dblclick inputready.dblclick': function(e) {
  41305. var node = e.getTargetNode();
  41306. dblclickEvent = true;
  41307. if(node){
  41308. //跟mouseup的timeout有冲突,这里做标记处理
  41309. inputStatusReady(node);
  41310. km.setStatus('textedit');
  41311. receiver.updateSelection();
  41312. }
  41313. },
  41314. 'restoreScene': function() {
  41315. receiver.clear();
  41316. inputStatusReady(this.getSelectedNode());
  41317. },
  41318. 'stopTextEdit': function() {
  41319. receiver.clear();
  41320. km.setStatus('normal');
  41321. },
  41322. 'resize': function(e) {
  41323. sel.setHide();
  41324. },
  41325. 'execCommand': function(e) {
  41326. var cmds = {
  41327. 'appendchildnode': 1,
  41328. 'appendsiblingnode': 1,
  41329. 'editnode': 1
  41330. };
  41331. if (cmds[e.commandName]) {
  41332. inputStatusReady(km.getSelectedNode());
  41333. receiver.updateSelection();
  41334. return;
  41335. }
  41336. if(sel.isShow()){
  41337. receiver.updateTextOffsetData().updateSelection();
  41338. }
  41339. },
  41340. 'layoutfinish':function(e){
  41341. if (e.node === receiver.minderNode && (this.getStatus() == 'textedit' || this.getStatus() == 'inputready') ) {//&& selectionReadyShow
  41342. receiver.setContainerStyle();
  41343. }
  41344. },
  41345. 'selectionclear': function() {
  41346. var node = km.getSelectedNode();
  41347. if(node){
  41348. inputStatusReady(node);
  41349. }else{
  41350. km.setStatus('normal');
  41351. receiver.clear();
  41352. }
  41353. },
  41354. 'blur': function() {
  41355. !/\?debug#?/.test(location.href) && receiver.clear();
  41356. },
  41357. 'textedit.import': function() {
  41358. km.setStatus('normal');
  41359. receiver.clear();
  41360. },
  41361. 'inputready.mousewheel textedit.mousewheel': function() {
  41362. receiver.setContainerStyle();
  41363. },
  41364. 'statuschange':function(e){
  41365. if(e.lastStatus == 'textedit'){
  41366. this.fire('contentchange');
  41367. }
  41368. }
  41369. }
  41370. };
  41371. });
  41372. //接收者
  41373. Minder.keyboarder = kity.createClass('keyboarder', function(){
  41374. return {
  41375. constructor: function(re) {
  41376. this.re = re;
  41377. this.container = re.container;
  41378. this.selection = re.selection;
  41379. this.range = re.range;
  41380. this.km = re.km;
  41381. this.lastMinderNode = null;
  41382. this.isTypeText = false;
  41383. this._initEvent();
  41384. this.isShortcutCopyKey = false;
  41385. },
  41386. //给接受容器绑定事件
  41387. _initEvent: function(){
  41388. var me = this;
  41389. if(browser.ipad) {
  41390. utils.listen(this.container, 'keydown keypress keyup input', function(e) {
  41391. me._handleEvents.call(me, new MinderEvent(e.type == 'keyup' ? 'beforekeyup' : e.type, e));
  41392. if(e.type == 'keyup'){
  41393. if(me.km.getStatus() == 'normal'){
  41394. me.km.fire( 'keyup', e);
  41395. }
  41396. }
  41397. });
  41398. }
  41399. this.km.on('inputready.beforekeyup ' +
  41400. 'inputready.beforekeydown ' +
  41401. 'textedit.beforekeyup ' +
  41402. 'normal.keydown ' +
  41403. 'normal.keyup ' +
  41404. 'textedit.beforekeydown ' +
  41405. 'textedit.keypress ' +
  41406. 'textedit.paste',
  41407. utils.proxy(this._handleEvents, this));
  41408. },
  41409. _handleEvents:function(e){
  41410. switch (e.type) {
  41411. case 'input':
  41412. this._input(e);
  41413. break;
  41414. case 'beforekeydown':
  41415. this._beforeKeydown(e);
  41416. break;
  41417. case 'beforekeyup':
  41418. this._beforeKeyup(e);
  41419. break;
  41420. case 'keyup':
  41421. this._keyup(e);
  41422. }
  41423. },
  41424. _setTextToContainer : function(keyCode,iskeyUp){
  41425. var me = this;
  41426. //同步节点
  41427. me.minderNode = me.re.minderNode;
  41428. clearTimeout(me.timer);
  41429. if (!me.range.hasNativeRange()) {
  41430. return;
  41431. }
  41432. if(keymap.controlKeys[keyCode] && !iskeyUp ){
  41433. return;
  41434. }
  41435. //当第一次输入内容时进行保存
  41436. if(me.lastMinderNode !== me.minderNode && !keymap.notContentChange[keyCode]){
  41437. me.km.fire('saveScene',{
  41438. inputStatus:true
  41439. });
  41440. me.lastMinderNode = me.minderNode;
  41441. }
  41442. var text = me.re.getTxtOfContainer();
  41443. // //#46 修复在ff下定位到文字后方空格光标不移动问题
  41444. // if (browser.gecko && /\s$/.test(text)) {
  41445. // text += '\u200b';
  41446. // }
  41447. //重新渲染节点
  41448. me.minderNode.setText(text);
  41449. me.re.setContainerStyle();
  41450. me.minderNode.getRenderContainer().bringTop();
  41451. me.minderNode.render();
  41452. //移动光标不做layout
  41453. if(!keymap.notContentChange[keyCode]){
  41454. clearTimeout(me.inputTextTimer);
  41455. me.inputTextTimer = setTimeout(function(){
  41456. me.km.layout(300);
  41457. },300);
  41458. }
  41459. me.re.updateTextOffsetData()
  41460. .updateRange()
  41461. .updateSelectionByRange();
  41462. me.selection
  41463. .updateOffsetByTextData(me.re.textData)
  41464. .updatePosition();
  41465. //当然inputready状态时,如果输入文字,节点内文本会被先选中然后再消失,体验不好
  41466. if(me.km.getStatus() != 'inputready'){
  41467. me.selection.setHoldShow();
  41468. }
  41469. me.timer = setTimeout(function() {
  41470. if(me.selection.isShow()){
  41471. me.selection.setShow();
  41472. }
  41473. }, 200);
  41474. me.km.setStatus('textedit');
  41475. },
  41476. _input:function(){
  41477. var me = this;
  41478. if (browser.ipad) {
  41479. setTimeout(function() {
  41480. me._setTextToContainer();
  41481. });
  41482. }
  41483. },
  41484. _beforeKeydown:function(e){
  41485. var me = this;
  41486. var orgEvt = e.originEvent;
  41487. var keyCode = orgEvt.keyCode;
  41488. this.isTypeText = keyCode == 229 || keyCode === 0;
  41489. switch (keyCode) {
  41490. case keymap.Enter:
  41491. if(e.originEvent.shiftKey && me.selection.isShow()){
  41492. me._handlerEnterkey();
  41493. e.preventDefault();
  41494. return false;
  41495. };
  41496. case keymap.Tab:
  41497. case keymap.Insert:
  41498. if(this.selection.isShow()){
  41499. this.re.clear();
  41500. this.km.setStatus('inputready');
  41501. clearTimeout(me.inputTextTimer);
  41502. e.preventDefault();
  41503. }else{
  41504. this.km.setStatus('normal');
  41505. this.km.fire('contentchange');
  41506. }
  41507. return;
  41508. case keymap.left:
  41509. case keymap.right:
  41510. case keymap.up:
  41511. case keymap.down:
  41512. case keymap.Backspace:
  41513. case keymap.Del:
  41514. case keymap['/']:
  41515. case keymap.F2:
  41516. case keymap.Insert:
  41517. if(this.selection.isHide()){
  41518. this.km.setStatus('normal');
  41519. return;
  41520. }
  41521. break;
  41522. case keymap.Control:
  41523. case keymap.Alt:
  41524. case keymap.Cmd:
  41525. if(this.selection.isHide() && this.km.getStatus() != 'textedit' && this.km.getStatus() !='inputready'){
  41526. this.km.setStatus('normal');
  41527. return;
  41528. }
  41529. }
  41530. if (e.originEvent.ctrlKey || e.originEvent.metaKey) {
  41531. //选中节点时的复制粘贴,要变成normal
  41532. if(this.selection.isHide() && {
  41533. 86:1,
  41534. 88:1,
  41535. 67:1
  41536. }[keyCode]){
  41537. //修正在cvs方式下_keyup会把节点文字选中
  41538. this.isShortcutCopyKey = true;
  41539. this.km.setStatus('normal');
  41540. return;
  41541. }
  41542. //粘贴
  41543. if (keyCode == keymap.v) {
  41544. setTimeout(function () {
  41545. me.range.updateNativeRange().insertNode($('<span>$$_kityminder_bookmark_$$</span>')[0]);
  41546. var brArr = [];
  41547. utils.each(me.container.getElementsByTagName('br'),function(i,br){
  41548. brArr.push(br);
  41549. });
  41550. utils.each(brArr,function(i,br){
  41551. var textNode = document.createTextNode('\n');
  41552. br.parentNode.insertBefore(textNode,br);
  41553. br.parentNode.removeChild(br);
  41554. });
  41555. var textContent = me.container.textContent.replace(/[\u200b\t\r]/g,'');
  41556. var index = textContent.indexOf('$$_kityminder_bookmark_$$');
  41557. me.re.setContainerTxt(textContent.replace('$$_kityminder_bookmark_$$',''));
  41558. me.range.setStartOffset(index).collapse(true).select();
  41559. me._setTextToContainer(keyCode);
  41560. },50);
  41561. return;
  41562. }
  41563. //剪切
  41564. if (keyCode == keymap.x) {
  41565. setTimeout(function () {
  41566. me._setTextToContainer(keyCode);
  41567. },50);
  41568. return;
  41569. }
  41570. }
  41571. this.isShortcutCopyKey = false;
  41572. //针对不能连续删除做处理
  41573. //if(keymap.Del == keyCode || keymap.Backspace == keyCode)
  41574. // me._setTextToContainer(keyCode);
  41575. me._setTextToContainer(keyCode);
  41576. },
  41577. _beforeKeyup:function(e){
  41578. var me = this;
  41579. var orgEvt = e.originEvent;
  41580. var keyCode = orgEvt.keyCode;
  41581. switch (keyCode) {
  41582. case keymap.Enter:
  41583. case keymap.Tab:
  41584. case keymap.Insert:
  41585. case keymap.F2:
  41586. if(browser.ipad){
  41587. if(this.selection.isShow()){
  41588. this.re.clear();
  41589. this.km.setStatus('inputready');
  41590. clearTimeout(me.inputTextTimer);
  41591. e.preventDefault();
  41592. }else{
  41593. this.km.setStatus('normal');
  41594. this.km.fire('contentchange');
  41595. }
  41596. return;
  41597. }
  41598. if (keymap.Enter == keyCode && (this.isTypeText || browser.mac && browser.gecko)) {
  41599. me._setTextToContainer(keyCode,true);
  41600. }
  41601. if (this.re.keydownNode === this.re.minderNode) {
  41602. this.km.rollbackStatus();
  41603. this.re.clear();
  41604. }
  41605. e.preventDefault();
  41606. return;
  41607. case keymap.Del:
  41608. case keymap.Backspace:
  41609. case keymap.Spacebar:
  41610. if(browser.ipad){
  41611. if(this.selection.isHide()){
  41612. this.km.setStatus('normal');
  41613. return;
  41614. }
  41615. }
  41616. me._setTextToContainer(keyCode,true);
  41617. return;
  41618. }
  41619. if (this.isTypeText) {
  41620. me._setTextToContainer(keyCode,true);
  41621. return;
  41622. }
  41623. if (browser.mac && browser.gecko){
  41624. me._setTextToContainer(keyCode,true);
  41625. return;
  41626. }
  41627. me._setTextToContainer(keyCode,true);
  41628. return true;
  41629. },
  41630. _keyup:function(e){
  41631. var me = this;
  41632. var timer;
  41633. var node = this.km.getSelectedNode();
  41634. if(this.km.getStatus() == 'normal' && node && this.selection.isHide()){
  41635. if(this.isShortcutCopyKey){
  41636. return;
  41637. }
  41638. if (node && this.km.isSingleSelect() && node.isSelected()) {
  41639. this.re.updateByMinderNode(node);
  41640. this.selection.setHide()
  41641. .setStartOffset(0)
  41642. .setEndOffset(this.re.getTxtOfContainer().length)
  41643. .setColor( node.getStyle('text-selection-color'));
  41644. setTimeout(function(){
  41645. me.re.updateContainerRangeBySel();
  41646. });
  41647. if(browser.ie ){
  41648. timer = setInterval(function(){
  41649. var nativeRange = me.range.nativeSel.getRangeAt(0);
  41650. if(!nativeRange || nativeRange.collapsed){
  41651. me.range.select();
  41652. }else {
  41653. clearInterval(timer);
  41654. }
  41655. });
  41656. }
  41657. this.km.setStatus('inputready');
  41658. }
  41659. }
  41660. },
  41661. //处理软回车操作
  41662. _handlerEnterkey:function(){
  41663. function removeTmpTextNode(node){
  41664. if(node && node.nodeType == 3 && node.nodeValue.length === 0){
  41665. node.parentNode.removeChild(node);
  41666. }
  41667. }
  41668. var rng = this.range;
  41669. var br = document.createElement('br');
  41670. var me = this;
  41671. if(!rng.collapsed){
  41672. rng.deleteContents();
  41673. }
  41674. rng.insertNode(br);
  41675. removeTmpTextNode(br.previousSibling);
  41676. removeTmpTextNode(br.nextSibling);
  41677. rng.setStartAfter(br);
  41678. rng.collapse(true);
  41679. var start = rng.startContainer.childNodes[rng.startOffset];
  41680. if(!start){
  41681. br = br.cloneNode(false);
  41682. rng.startContainer.appendChild(br);
  41683. rng.setStartBefore(br);
  41684. rng.collapse(true);
  41685. }
  41686. rng.select();
  41687. me._setTextToContainer(keymap.Enter);
  41688. }
  41689. };
  41690. }());
  41691. Minder.Range = kity.createClass('Range',function(){
  41692. function getOffset(rng,dir){
  41693. var node = rng[dir + 'Container'],
  41694. offset = rng[dir + 'Offset'],
  41695. rOffset = 0;
  41696. if(node.nodeType == 1){
  41697. //默认不会出现得不到子节点的情况
  41698. node = node.childNodes[offset];
  41699. if(!node && rng.startContainer && rng.startContainer.nodeName == 'DIV' ) {
  41700. rng.startContainer.innerHTML = '<p></p>';
  41701. offset = 0;
  41702. }else if(node.nodeType == 3){
  41703. offset = 0;
  41704. }
  41705. }
  41706. utils.each(rng.container.childNodes,function(index,n){
  41707. if(n === node){
  41708. if(n.nodeType == 1){
  41709. return false;
  41710. }else{
  41711. rOffset += offset;
  41712. return false;
  41713. }
  41714. }
  41715. rOffset += (n.nodeType == 1 ? 1 : utils.clearWhitespace(n.nodeValue).length);
  41716. });
  41717. return rOffset;
  41718. }
  41719. function setBoundary(rng,offset,dir){
  41720. var rOffset = 0,cont = rng.container;
  41721. utils.each(cont.childNodes,function(index,node){
  41722. if(node.nodeType == 1){
  41723. if(rOffset == offset){
  41724. rng['set' + dir](cont,index);
  41725. return false;
  41726. }
  41727. rOffset++;
  41728. return;
  41729. }
  41730. var currentLength = utils.clearWhitespace(node.nodeValue).length;
  41731. if(rOffset + currentLength >= offset){
  41732. rng['set' + dir](node,offset - rOffset);
  41733. return false;
  41734. }
  41735. rOffset += currentLength;
  41736. });
  41737. }
  41738. return {
  41739. constructor : function(container){
  41740. this.nativeRange = document.createRange();
  41741. this.nativeSel = window.getSelection();
  41742. this.startContainer =
  41743. this.endContainer =
  41744. this.startOffset =
  41745. this.endOffset = null;
  41746. this.collapsed = false;
  41747. this.container = container || null;
  41748. },
  41749. hasNativeRange : function(){
  41750. return this.nativeSel.rangeCount !== 0 ;
  41751. },
  41752. deleteContents : function(){
  41753. this.nativeRange.deleteContents();
  41754. return this._updateBoundary();
  41755. },
  41756. select:function(){
  41757. var start = this.nativeRange.startContainer;
  41758. if(start.nodeType == 1 && start.childNodes.length === 0){
  41759. var char = document.createTextNode('\u200b');
  41760. start.appendChild(char);
  41761. this.nativeRange.setStart(char,1);
  41762. this.nativeRange.collapse(true);
  41763. }else if(this.collapsed && start.nodeType == 1){
  41764. start = start.childNodes[this.startOffset];
  41765. if(start && start.nodeType == 3 && start.nodeValue.length === 0){
  41766. this.nativeRange.setStart(start,1);
  41767. this.nativeRange.collapse(true);
  41768. }
  41769. }
  41770. try{
  41771. this.nativeSel.removeAllRanges();
  41772. }catch(e){
  41773. }
  41774. this.nativeSel.addRange(this.nativeRange);
  41775. return this;
  41776. },
  41777. _updateBoundary : function(){
  41778. var nRange = this.nativeRange;
  41779. this.startContainer = nRange.startContainer;
  41780. this.startContainer = nRange.startContainer;
  41781. this.endContainer = nRange.endContainer;
  41782. this.startOffset = nRange.startOffset;
  41783. this.endOffset = nRange.endOffset;
  41784. this.collapsed = nRange.collapsed;
  41785. return this;
  41786. },
  41787. setStartOffset:function(offset){
  41788. setBoundary(this,offset,'Start');
  41789. return this;
  41790. },
  41791. setEndOffset:function(offset){
  41792. setBoundary(this,offset,'End');
  41793. return this;
  41794. },
  41795. setStart:function(node,offset){
  41796. this.nativeRange.setStart(node,offset);
  41797. this._updateBoundary();
  41798. return this;
  41799. },
  41800. setStartAfter:function(node){
  41801. return this.setStart(node.parentNode,utils.getNodeIndex(node) + 1);
  41802. },
  41803. setStartBefore:function(node){
  41804. return this.setStart(node.parentNode,utils.getNodeIndex(node));
  41805. },
  41806. setEnd:function(node,offset){
  41807. this.nativeRange.setEnd(node,offset);
  41808. this._updateBoundary();
  41809. return this;
  41810. },
  41811. update:function(){
  41812. this.updateNativeRange()
  41813. ._updateBoundary();
  41814. return this;
  41815. },
  41816. getStart:function(){
  41817. this.update();
  41818. return {
  41819. startContainer:this.startContainer,
  41820. startOffset:this.startOffset
  41821. };
  41822. },
  41823. getStartOffset:function(){
  41824. return getOffset(this,'start');
  41825. },
  41826. getEndOffset:function(){
  41827. return getOffset(this,'end');
  41828. },
  41829. collapse:function(toStart){
  41830. this.nativeRange.collapse(toStart === true);
  41831. this._updateBoundary();
  41832. return this;
  41833. },
  41834. isCollapsed:function(){
  41835. this._updateBoundary();
  41836. return this.collapsed;
  41837. },
  41838. insertNode:function(node){
  41839. this.nativeRange.insertNode(node);
  41840. return this._updateBoundary();
  41841. },
  41842. updateNativeRange:function(){
  41843. this.nativeRange = this.nativeSel.getRangeAt(0);
  41844. return this;
  41845. },
  41846. clear : function(){
  41847. this.nativeSel.removeAllRanges();
  41848. return this;
  41849. }
  41850. };
  41851. }());
  41852. //接收者
  41853. Minder.Receiver = kity.createClass('Receiver', {
  41854. clear: function() {
  41855. this.container.innerHTML = '';
  41856. if (this.selection) {
  41857. this.selection.setHide();
  41858. }
  41859. if (this.range) {
  41860. this.range.clear();
  41861. }
  41862. this.index = 0;
  41863. return this;
  41864. },
  41865. constructor: function(km,sel,range) {
  41866. //初始化接收者
  41867. this.setKityMinder(km);
  41868. //创建接收者容器
  41869. var _div = document.createElement('div');
  41870. _div.setAttribute('contenteditable', true);
  41871. _div.className = 'km_receiver';
  41872. this.container = _div;
  41873. utils.addCssRule('km_receiver_css',
  41874. ' .km_receiver{white-space:nowrap;position:absolute;padding:0;margin:0;word-wrap:break-word;'
  41875. + (/\?debug#?/.test(location.href)?'':'clip:rect(1em 1em 1em 1em);'));
  41876. this.index = 0;
  41877. this.selection = sel;
  41878. this.range = range;
  41879. this.range.container = _div;
  41880. },
  41881. setRange: function(range, index) {
  41882. this.index = index || this.index;
  41883. this.range = range;
  41884. range.setStartOffset(this.index);
  41885. range.collapse(true);
  41886. var me = this;
  41887. setTimeout(function() {
  41888. me.container.focus();
  41889. range.select();
  41890. });
  41891. return this;
  41892. },
  41893. setTextGroup: function(textGroup) {
  41894. this.textGroup = textGroup;
  41895. return this;
  41896. },
  41897. setKityMinder: function(km) {
  41898. this.km = km;
  41899. return this;
  41900. },
  41901. updateByMinderNode:function(node){
  41902. this.setMinderNode(node);
  41903. //追加selection到节点
  41904. this._addSelection();
  41905. //更新minderNode下的textGroup
  41906. this.setTextGroup(node.getTextGroup());
  41907. //更新接受容器的样式
  41908. this.setContainerStyle();
  41909. //更新textOffsetData数据
  41910. this.updateTextOffsetData();
  41911. //更新选取高度
  41912. this.setSelectionHeight();
  41913. //更新接收容器内容
  41914. this.setContainerTxt();
  41915. return this;
  41916. },
  41917. setMinderNode: function(node) {
  41918. this.minderNode = node;
  41919. this.selection.setMinderNode(node);
  41920. return this;
  41921. },
  41922. _addSelection:function(){
  41923. if (this.selection.container){
  41924. this.selection.remove();
  41925. }
  41926. this.minderNode.getRenderContainer().addShape(this.selection);
  41927. return this;
  41928. },
  41929. getMinderNode:function(){
  41930. return this.minderNode;
  41931. },
  41932. updateIndex: function() {
  41933. this.index = this.range.getStartOffset();
  41934. return this;
  41935. },
  41936. setSelection: function(selection) {
  41937. this.selection = selection;
  41938. return this;
  41939. },
  41940. updateSelection: function(offset) {
  41941. this.selection.update(this.textData,offset);
  41942. return this;
  41943. },
  41944. getOffsetByIndex:function(index){
  41945. return utils.getValueByIndex(this.textData, index !== undefined ? index : this.index);
  41946. },
  41947. getBaseOffset: function() {
  41948. var offset = this.textGroup.getRenderBox('screen');
  41949. return offset;
  41950. },
  41951. setContainerStyle: function() {
  41952. var textGroupBox = this.getBaseOffset();
  41953. this.container.style.cssText = ';left:' + (browser.ipad ? '-' : '') +
  41954. textGroupBox.x + 'px;top:' + (textGroupBox.y + (/\?debug#?/.test(location.href)?this.textGroup.getItems().length * this.getlineHeight():0)) +
  41955. 'px;width:' + textGroupBox.width + 'px;height:' + textGroupBox.height + 'px;';
  41956. return this;
  41957. },
  41958. updateTextOffsetData: function() {
  41959. var me = this;
  41960. var fontHeight = this.minderNode.getData('font-size') || this.minderNode.getStyle('font-size');
  41961. var lineHeight = this.minderNode.getStyle('line-height') * fontHeight;
  41962. var offsetHeight = (me.textGroup.getShapes().length * lineHeight - (lineHeight - fontHeight)) / 2;
  41963. var box;
  41964. this.textData = [];
  41965. me.textGroup.eachItem(function(index,textShape){
  41966. me.textData[index] = [];
  41967. var currentLineTop = index * lineHeight + 1;
  41968. var text = textShape.getContent();
  41969. for (var i = 0, l = text.length; i < l; i++) {
  41970. try {
  41971. box = textShape.getExtentOfChar(i);
  41972. } catch (e) {
  41973. console.log(e);
  41974. }
  41975. me.textData[index].push({
  41976. x: box.x ,
  41977. y: currentLineTop - offsetHeight,
  41978. width: box.width,
  41979. height: box.height
  41980. });
  41981. }
  41982. if(text.length === 0){
  41983. me.textData[index].push({
  41984. x: 0,
  41985. y: currentLineTop - offsetHeight,
  41986. width: 0,
  41987. height:lineHeight
  41988. });
  41989. }
  41990. });
  41991. return this;
  41992. },
  41993. getlineHeight:function(){
  41994. return this.minderNode.getStyle('line-height') * (this.minderNode.getData('font-size') || this.minderNode.getStyle('font-size'));
  41995. },
  41996. updateIndexByMouse : function(offset) {
  41997. var me = this;
  41998. //更新文本字符坐标
  41999. me.updateTextOffsetData();
  42000. this.index = 0;
  42001. var lineHeight = this.getlineHeight();
  42002. utils.each(this.textData,function(l,arr){
  42003. var first = arr[0];
  42004. //确定行号
  42005. if(first.y <= offset.y && first.y + lineHeight >= offset.y){
  42006. utils.each(arr,function(i,v){
  42007. //点击开始之前
  42008. if (i === 0 && offset.x <= v.x) {
  42009. return false;
  42010. }
  42011. if (offset.x >= v.x && offset.x <= v.x + v.width) {
  42012. if (offset.x - v.x > v.width / 2) {
  42013. me.index += i + 1;
  42014. } else {
  42015. me.index += i;
  42016. }
  42017. return false;
  42018. }
  42019. if (i == arr.length - 1 && offset.x >= v.x) {
  42020. me.index += (arr.length == 1 && arr[0].width === 0 ? 0 : arr.length);
  42021. return false;
  42022. }
  42023. });
  42024. return false;
  42025. }else{
  42026. me.index += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
  42027. return;
  42028. }
  42029. });
  42030. this.selection.setStartOffset(this.index).collapse(true);
  42031. return this;
  42032. },
  42033. setSelectionHeight: function() {
  42034. this.selection.setHeight((this.minderNode.getData('font-size') || this.minderNode.getStyle('font-size')) * 1);
  42035. return this;
  42036. },
  42037. updateSelectionByMousePosition: function(offset) {
  42038. var me = this;
  42039. var result = 0;
  42040. var lineHeight = this.getlineHeight();
  42041. utils.each(this.textData,function(l,arr){
  42042. var first = arr[0];
  42043. //确定行号
  42044. if(first.y <= offset.y && first.y + lineHeight >= offset.y){
  42045. utils.each(arr,function(i,v){
  42046. //点击开始之前
  42047. if (i === 0 && offset.x <= v.x) {
  42048. return false;
  42049. }
  42050. if (offset.x >= v.x && offset.x <= v.x + v.width) {
  42051. result += i;
  42052. if (offset.x - v.x > v.width / 2) {
  42053. result += 1;
  42054. }
  42055. return false;
  42056. }
  42057. if (i == arr.length - 1 && offset.x >= v.x) {
  42058. result += (arr.length == 1 && arr[0].width === 0 ? 0 : arr.length);
  42059. return false;
  42060. }
  42061. });
  42062. return false;
  42063. }else{
  42064. if(first.y > offset.y && l === 0){
  42065. result = 0;
  42066. return false;
  42067. }else if(l == me.textData.length - 1 && first.y + lineHeight < offset.y){
  42068. result += arr.length + 1;
  42069. return false;
  42070. }
  42071. result += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
  42072. return;
  42073. }
  42074. });
  42075. if(result < me.index){
  42076. this.selection.setStartOffset(result);
  42077. this.selection.setEndOffset(me.index);
  42078. }else if(result == me.index){
  42079. this.selection.setStartOffset(result).collapse(true);
  42080. }else{
  42081. this.selection.setStartOffset(me.index);
  42082. this.selection.setEndOffset(result);
  42083. }
  42084. return this;
  42085. },
  42086. updateRange: function() {
  42087. this.range.update();
  42088. return this;
  42089. },
  42090. updateContainerRangeBySel:function(){
  42091. var me = this;
  42092. this.range.setStartOffset(this.selection.startOffset);
  42093. this.range.setEndOffset(this.selection.endOffset);
  42094. if(browser.gecko){
  42095. this.container.focus();
  42096. setTimeout(function(){
  42097. me.range.select();
  42098. });
  42099. }else{
  42100. this.range.select();
  42101. }
  42102. return this;
  42103. },
  42104. updateSelectionByRange:function(){
  42105. this.selection.setStartOffset(this.range.getStartOffset());
  42106. this.selection.setEndOffset(this.range.getEndOffset());
  42107. return this;
  42108. },
  42109. setIndex: function(index) {
  42110. this.index = index;
  42111. return this;
  42112. },
  42113. setContainerTxt: function(txt) {
  42114. function encodeHtml(text) {
  42115. return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
  42116. }
  42117. if(txt){
  42118. txt = encodeHtml(txt);
  42119. txt = txt.replace(/[\n]/g,'<br\/>');
  42120. }else{
  42121. txt = '';
  42122. this.textGroup.eachItem(function(i,item){
  42123. txt += encodeHtml(item.getContent()) + '<br/>';
  42124. });
  42125. }
  42126. this.container.innerHTML = txt;
  42127. return this;
  42128. },
  42129. setReady:function(){
  42130. this._ready = true;
  42131. },
  42132. clearReady:function(){
  42133. this._ready = false;
  42134. },
  42135. isReady:function(){
  42136. return this._ready;
  42137. },
  42138. focus:function(){
  42139. this.container.focus();
  42140. },
  42141. getTxtOfContainer:function(){
  42142. var result = '',cont = this.container;
  42143. utils.each(cont.childNodes,function(i,n){
  42144. if(n.nodeType == 3){
  42145. result += n.nodeValue.replace(/[\u200b]/g, '');
  42146. }else{
  42147. if(n !== cont.lastChild)
  42148. result += '\n';
  42149. }
  42150. });
  42151. return result;
  42152. }
  42153. });
  42154. //模拟光标
  42155. Minder.Selection = kity.createClass( 'Selection', {
  42156. base: kity.Path,
  42157. constructor: function ( height, color, width ) {
  42158. this.callBase();
  42159. this.height = height || 20;
  42160. this.setAttr('id','_kity_selection');
  42161. this.width = 2;
  42162. this.fill('rgb(27,171,255)');
  42163. this.setHide();
  42164. this.timer = null;
  42165. this.collapsed = true;
  42166. this.startOffset = this.endOffset = 0;
  42167. this.setOpacity(0.5);
  42168. this.setStyle('cursor','text');
  42169. this._show = false;
  42170. this.offset = [];
  42171. this.setTranslate(-0.5, -1.5);
  42172. },
  42173. setMinderNode : function(node){
  42174. this.minderNode = node;
  42175. },
  42176. setColor:function(color){
  42177. this.fill(color);
  42178. },
  42179. updateOffsetByTextData:function(data,offset){
  42180. if(this.collapsed){
  42181. this.offset = utils.getValueByIndex(data,this.startOffset);
  42182. return this;
  42183. }else{
  42184. var arrOffset = [],tmpOffset = {},
  42185. startOffset = this.startOffset,
  42186. endOffset = this.endOffset,
  42187. cIndex = 0;
  42188. utils.each(data,function(l,arr){
  42189. tmpOffset = {
  42190. width:0,
  42191. x:0,
  42192. y:0
  42193. };
  42194. utils.each(arr,function(i,o){
  42195. if(cIndex >= startOffset && cIndex <= endOffset){
  42196. if(i === 0 || cIndex === startOffset){
  42197. tmpOffset.x = o.x;
  42198. tmpOffset.y = o.y;
  42199. tmpOffset.width = o.width;
  42200. //i === 0 && offset && offset.x <= o.x && cIndex != startOffset ? 0 :
  42201. }else if(cIndex < endOffset){
  42202. tmpOffset.width += o.width;
  42203. }else if(cIndex === endOffset){
  42204. return false;
  42205. }
  42206. }
  42207. cIndex++;
  42208. });
  42209. if(tmpOffset.x !== undefined) {
  42210. arrOffset.push(tmpOffset);
  42211. }
  42212. if(cIndex === endOffset) {
  42213. return false;
  42214. }
  42215. if(arr.length == 1 && arr[0].width === 0)
  42216. return;
  42217. cIndex++;
  42218. });
  42219. this.offset = arrOffset;
  42220. return this;
  42221. }
  42222. this._show = true;
  42223. },
  42224. updatePosition: function(offset){
  42225. var me = this;
  42226. var r = Math.round;
  42227. var rect = function (x, y, w, h) {
  42228. return ['M', r(x), r(y),
  42229. 'h', r(w),
  42230. 'v', r(h),
  42231. 'h', -r(w),
  42232. 'v', -r(h),
  42233. 'z'];
  42234. };
  42235. offset = offset !== undefined ? offset : this.offset;
  42236. if(this.collapsed){
  42237. if (isNaN(offset.x) || isNaN(offset.y)) {
  42238. if (console) console.warn('editor.selection.js 不正确的偏移位置');
  42239. return this;
  42240. }
  42241. this.setPathData(rect(offset.x, offset.y, this.width, this.height));
  42242. } else {
  42243. this.setPathData(offset.reduce(function (prev, current) {
  42244. return prev.concat(rect(current.x, current.y, current.width, me.height));
  42245. }, []));
  42246. }
  42247. this._show = true;
  42248. return this;
  42249. },
  42250. collapse : function(toStart){
  42251. this.setOpacity(1);
  42252. this.collapsed = true;
  42253. if(toStart){
  42254. this.endOffset = this.startOffset;
  42255. }else{
  42256. this.startOffset = this.endOffset;
  42257. }
  42258. return this;
  42259. },
  42260. setStartOffset:function(offset){
  42261. this.startOffset = offset;
  42262. if(this.startOffset >= this.endOffset){
  42263. this.collapse(true);
  42264. return this;
  42265. }
  42266. this.collapsed = false;
  42267. this.setOpacity(0.5);
  42268. return this;
  42269. },
  42270. setEndOffset:function(offset){
  42271. this.endOffset = offset;
  42272. if(this.endOffset <= this.startOffset){
  42273. this.startOffset = offset;
  42274. this.collapse(true);
  42275. return this;
  42276. }
  42277. this.collapsed = false;
  42278. this.setOpacity(0.5);
  42279. return this;
  42280. },
  42281. update : function(data,offset){
  42282. if(data){
  42283. this.updateOffsetByTextData(data,offset);
  42284. }
  42285. this.updatePosition();
  42286. this.setShow();
  42287. return this;
  42288. },
  42289. setHeight: function ( height ) {
  42290. this.height = Math.round(height) + 2;
  42291. return this;
  42292. },
  42293. setHide: function () {
  42294. clearInterval( this.timer );
  42295. this.setStyle( 'display', 'none' );
  42296. this._show = false;
  42297. return this;
  42298. },
  42299. setHoldShow:function(){
  42300. this.setStyle('display','');
  42301. clearInterval(this.timer);
  42302. return this;
  42303. },
  42304. setShow: function () {
  42305. this.bringTop();
  42306. clearInterval( this.timer );
  42307. var me = this,
  42308. state = '';
  42309. me.setStyle( 'display', '' );
  42310. me._show = true;
  42311. if(this.collapsed){
  42312. me.setOpacity(1);
  42313. this.timer = setInterval( function () {
  42314. me.setStyle( 'display', state );
  42315. state = state ? '' : 'none';
  42316. }, 400 );
  42317. }
  42318. return this;
  42319. },
  42320. setShowStatus:function(){
  42321. this._show = true;
  42322. return this;
  42323. },
  42324. isShow:function(){
  42325. return this._show;
  42326. },
  42327. isHide:function(){
  42328. return !this._show;
  42329. }
  42330. } );
  42331. KityMinder.registerModule('basestylemodule', function() {
  42332. var km = this;
  42333. function getNodeDataOrStyle(node, name) {
  42334. return node.getData(name) || node.getStyle(name);
  42335. }
  42336. KityMinder.TextRenderer.registerStyleHook(function(node, textGroup) {
  42337. var fontWeight = getNodeDataOrStyle(node,'font-weight');
  42338. var fontStyle = getNodeDataOrStyle(node, 'font-style');
  42339. var styleHash = [fontWeight, fontStyle].join('/');
  42340. textGroup.eachItem(function(index,item){
  42341. item.setFont({
  42342. 'weight': fontWeight,
  42343. 'style': fontStyle
  42344. });
  42345. });
  42346. });
  42347. return {
  42348. 'commands': {
  42349. 'bold': kity.createClass('boldCommand', {
  42350. base: Command,
  42351. execute: function(km) {
  42352. var nodes = km.getSelectedNodes();
  42353. if (this.queryState('bold') == 1) {
  42354. utils.each(nodes, function(i, n) {
  42355. n.setData('font-weight').render();
  42356. });
  42357. } else {
  42358. utils.each(nodes, function(i, n) {
  42359. n.setData('font-weight', 'bold').render();
  42360. });
  42361. }
  42362. km.layout();
  42363. },
  42364. queryState: function() {
  42365. var nodes = km.getSelectedNodes(),
  42366. result = 0;
  42367. if (nodes.length === 0) {
  42368. return -1;
  42369. }
  42370. utils.each(nodes, function(i, n) {
  42371. if (n && n.getData('font-weight')) {
  42372. result = 1;
  42373. return false;
  42374. }
  42375. });
  42376. return result;
  42377. }
  42378. }),
  42379. 'italic': kity.createClass('italicCommand', {
  42380. base: Command,
  42381. execute: function(km) {
  42382. var nodes = km.getSelectedNodes();
  42383. if (this.queryState('italic') == 1) {
  42384. utils.each(nodes, function(i, n) {
  42385. n.setData('font-style').render();
  42386. });
  42387. } else {
  42388. utils.each(nodes, function(i, n) {
  42389. n.setData('font-style', 'italic').render();
  42390. });
  42391. }
  42392. km.layout();
  42393. },
  42394. queryState: function() {
  42395. var nodes = km.getSelectedNodes(),
  42396. result = 0;
  42397. if (nodes.length === 0) {
  42398. return -1;
  42399. }
  42400. utils.each(nodes, function(i, n) {
  42401. if (n && n.getData('font-style')) {
  42402. result = 1;
  42403. return false;
  42404. }
  42405. });
  42406. return result;
  42407. }
  42408. })
  42409. },
  42410. commandShortcutKeys: {
  42411. 'bold': 'ctrl+b', //bold
  42412. 'italic': 'ctrl+i' //italic
  42413. }
  42414. };
  42415. });
  42416. KityMinder.registerModule("fontmodule", function() {
  42417. function getNodeDataOrStyle(node, name) {
  42418. return node.getData(name) || node.getStyle(name);
  42419. }
  42420. KityMinder.TextRenderer.registerStyleHook(function(node, textGroup) {
  42421. var dataColor = node.getData('color');
  42422. var selectedColor = node.getStyle('selected-color');
  42423. var styleColor = node.getStyle('color');
  42424. var foreColor = dataColor || (node.isSelected() && selectedColor ? selectedColor : styleColor);
  42425. var fontFamily = getNodeDataOrStyle(node, 'font-family');
  42426. var fontSize = getNodeDataOrStyle(node, 'font-size');
  42427. var fontHash = [fontFamily, fontSize].join('/');
  42428. textGroup.fill(foreColor);
  42429. node.setTmpData('fore-color', foreColor.toString());
  42430. textGroup.eachItem(function(index,item){
  42431. item.setFont({
  42432. 'family': fontFamily,
  42433. 'size': fontSize
  42434. });
  42435. });
  42436. node.setTmpData('font-hash', fontHash);
  42437. });
  42438. return {
  42439. defaultOptions: {
  42440. 'fontfamily': [{
  42441. name: '宋体',
  42442. val: '宋体,SimSun'
  42443. }, {
  42444. name: '微软雅黑',
  42445. val: '微软雅黑,Microsoft YaHei'
  42446. }, {
  42447. name: '楷体',
  42448. val: '楷体,楷体_GB2312,SimKai'
  42449. }, {
  42450. name: '黑体',
  42451. val: '黑体, SimHei'
  42452. }, {
  42453. name: '隶书',
  42454. val: '隶书, SimLi'
  42455. }, {
  42456. name: 'Andale Mono',
  42457. val: 'andale mono'
  42458. }, {
  42459. name: 'Arial',
  42460. val: 'arial,helvetica,sans-serif'
  42461. }, {
  42462. name: 'arialBlack',
  42463. val: 'arial black,avant garde'
  42464. }, {
  42465. name: 'Comic Sans Ms',
  42466. val: 'comic sans ms'
  42467. }, {
  42468. name: 'Impact',
  42469. val: 'impact,chicago'
  42470. }, {
  42471. name: 'Times New Roman',
  42472. val: 'times new roman'
  42473. }, {
  42474. name: 'Sans-Serif',
  42475. val: 'sans-serif'
  42476. }],
  42477. 'fontsize': [10, 12, 16, 18, 24, 32, 48]
  42478. },
  42479. "commands": {
  42480. "forecolor": kity.createClass("fontcolorCommand", {
  42481. base: Command,
  42482. execute: function(km, color) {
  42483. var nodes = km.getSelectedNodes();
  42484. utils.each(nodes, function(i, n) {
  42485. n.setData('color', color);
  42486. n.render();
  42487. });
  42488. },
  42489. queryState: function(km) {
  42490. return km.getSelectedNodes().length == 0 ? -1 : 0
  42491. },
  42492. queryValue: function(km) {
  42493. if (km.getSelectedNodes().length == 1) {
  42494. return km.getSelectedNodes()[0].getData('color');
  42495. }
  42496. return 'mixed';
  42497. }
  42498. }),
  42499. "background": kity.createClass("backgroudCommand", {
  42500. base: Command,
  42501. execute: function(km, color) {
  42502. var nodes = km.getSelectedNodes();
  42503. utils.each(nodes, function(i, n) {
  42504. n.setData('background', color);
  42505. n.render();
  42506. });
  42507. },
  42508. queryState: function(km) {
  42509. return km.getSelectedNodes().length == 0 ? -1 : 0
  42510. },
  42511. queryValue: function(km) {
  42512. if (km.getSelectedNodes().length == 1) {
  42513. return km.getSelectedNodes()[0].getData('background');
  42514. }
  42515. return 'mixed';
  42516. }
  42517. }),
  42518. "fontfamily": kity.createClass("fontfamilyCommand", {
  42519. base: Command,
  42520. execute: function(km, family) {
  42521. var nodes = km.getSelectedNodes();
  42522. utils.each(nodes, function(i, n) {
  42523. n.setData('font-family', family);
  42524. n.render();
  42525. km.layout();
  42526. });
  42527. },
  42528. queryState: function(km) {
  42529. return km.getSelectedNodes().length === 0 ? -1 : 0
  42530. },
  42531. queryValue: function(km) {
  42532. var node = km.getSelectedNode();
  42533. if (node) return node.getData('font-family');
  42534. return null;
  42535. }
  42536. }),
  42537. "fontsize": kity.createClass("fontsizeCommand", {
  42538. base: Command,
  42539. execute: function(km, size) {
  42540. var nodes = km.getSelectedNodes();
  42541. utils.each(nodes, function(i, n) {
  42542. n.setData('font-size', size);
  42543. n.render();
  42544. km.layout(300);
  42545. });
  42546. },
  42547. queryState: function(km) {
  42548. return km.getSelectedNodes().length == 0 ? -1 : 0
  42549. },
  42550. queryValue: function(km) {
  42551. var node = km.getSelectedNode();
  42552. if (node) return node.getData('font-size');
  42553. return null;
  42554. }
  42555. })
  42556. }
  42557. };
  42558. });
  42559. KityMinder.registerModule('Zoom', function() {
  42560. var me = this;
  42561. var timeline;
  42562. me.setDefaultOptions('zoom', [10, 20, 30, 50, 80, 100, 120, 150, 200]);
  42563. function setTextRendering() {
  42564. var value = me._zoomValue >= 100 ? 'optimize-speed' : 'geometricPrecision';
  42565. me.getRenderContainer().setAttr('text-rendering', value);
  42566. }
  42567. function fixPaperCTM(paper) {
  42568. var node = paper.shapeNode;
  42569. var ctm = node.getCTM();
  42570. var matrix = new kity.Matrix(ctm.a, ctm.b, ctm.c, ctm.d, (ctm.e | 0) + 0.5, (ctm.f | 0) + 0.5);
  42571. node.setAttribute('transform', 'matrix(' + matrix.toString() + ')');
  42572. }
  42573. kity.extendClass(Minder, {
  42574. zoom: function(value) {
  42575. var paper = this.getPaper();
  42576. var viewport = paper.getViewPort();
  42577. viewport.zoom = value / 100;
  42578. viewport.center = {
  42579. x: viewport.center.x,
  42580. y: viewport.center.y
  42581. };
  42582. paper.setViewPort(viewport);
  42583. if (value == 100) fixPaperCTM(paper);
  42584. },
  42585. getZoomValue: function() {
  42586. return this._zoomValue;
  42587. }
  42588. });
  42589. function zoomMinder(minder, value) {
  42590. var paper = minder.getPaper();
  42591. var viewport = paper.getViewPort();
  42592. if (!value) return;
  42593. setTextRendering();
  42594. if (minder.getRoot().getComplex() > 200) {
  42595. minder._zoomValue = value;
  42596. minder.zoom(value);
  42597. minder.fire('viewchange');
  42598. } else {
  42599. var animator = new kity.Animator({
  42600. beginValue: minder._zoomValue,
  42601. finishValue: value,
  42602. setter: function(target, value) {
  42603. target.zoom(value);
  42604. }
  42605. });
  42606. minder._zoomValue = value;
  42607. if (timeline) {
  42608. timeline.pause();
  42609. }
  42610. timeline = animator.start(minder, 300, 'easeInOutSine');
  42611. timeline.on('finish', function() {
  42612. minder.fire('viewchange');
  42613. });
  42614. }
  42615. minder.fire('zoom', { zoom: value });
  42616. }
  42617. var ZoomCommand = kity.createClass('Zoom', {
  42618. base: Command,
  42619. execute: zoomMinder,
  42620. queryValue: function(minder) {
  42621. return minder._zoomValue;
  42622. }
  42623. });
  42624. var ZoomInCommand = kity.createClass('ZoomInCommand', {
  42625. base: Command,
  42626. execute: function(minder) {
  42627. zoomMinder(minder, this.nextValue(minder));
  42628. },
  42629. queryState: function(minder) {
  42630. return +!this.nextValue(minder);
  42631. },
  42632. nextValue: function(minder) {
  42633. var stack = minder.getOptions('zoom'),
  42634. i;
  42635. for (i = 0; i < stack.length; i++) {
  42636. if (stack[i] > minder._zoomValue) return stack[i];
  42637. }
  42638. return 0;
  42639. },
  42640. enableReadOnly: true
  42641. });
  42642. var ZoomOutCommand = kity.createClass('ZoomOutCommand', {
  42643. base: Command,
  42644. execute: function(minder) {
  42645. zoomMinder(minder, this.nextValue(minder));
  42646. },
  42647. queryState: function(minder) {
  42648. return +!this.nextValue(minder);
  42649. },
  42650. nextValue: function(minder) {
  42651. var stack = minder.getOptions('zoom'),
  42652. i;
  42653. for (i = stack.length - 1; i >= 0; i--) {
  42654. if (stack[i] < minder._zoomValue) return stack[i];
  42655. }
  42656. return 0;
  42657. },
  42658. enableReadOnly: true
  42659. });
  42660. return {
  42661. init: function() {
  42662. this._zoomValue = 100;
  42663. setTextRendering();
  42664. },
  42665. commands: {
  42666. 'zoom-in': ZoomInCommand,
  42667. 'zoom-out': ZoomOutCommand,
  42668. 'zoom': ZoomCommand
  42669. },
  42670. events: {
  42671. 'normal.mousewheel readonly.mousewheel': function(e) {
  42672. if (!e.originEvent.ctrlKey && !e.originEvent.metaKey) return;
  42673. var delta = e.originEvent.wheelDelta;
  42674. var me = this;
  42675. if (!kity.Browser.mac) {
  42676. delta = -delta;
  42677. }
  42678. // 稀释
  42679. if (Math.abs(delta) > 100) {
  42680. clearTimeout(this._wheelZoomTimeout);
  42681. } else {
  42682. return;
  42683. }
  42684. this._wheelZoomTimeout = setTimeout(function() {
  42685. var value;
  42686. var lastValue = me.getPaper()._zoom || 1;
  42687. if (delta < 0) {
  42688. me.execCommand('zoom-in');
  42689. } else if (delta > 0) {
  42690. me.execCommand('zoom-out');
  42691. }
  42692. }, 100);
  42693. e.originEvent.preventDefault();
  42694. }
  42695. },
  42696. commandShortcutKeys: {
  42697. 'zoom-in': 'ctrl+=',
  42698. 'zoom-out': 'ctrl+-'
  42699. }
  42700. };
  42701. });
  42702. KityMinder.registerModule("hyperlink", function() {
  42703. var linkShapePath = "M16.614,10.224h-1.278c-1.668,0-3.07-1.07-3.599-2.556h4.877c0.707,0,1.278-0.571,1.278-1.278V3.834 c0-0.707-0.571-1.278-1.278-1.278h-4.877C12.266,1.071,13.668,0,15.336,0h1.278c2.116,0,3.834,1.716,3.834,3.834V6.39 C20.448,8.508,18.73,10.224,16.614,10.224z M5.112,5.112c0-0.707,0.573-1.278,1.278-1.278h7.668c0.707,0,1.278,0.571,1.278,1.278 S14.765,6.39,14.058,6.39H6.39C5.685,6.39,5.112,5.819,5.112,5.112z M2.556,3.834V6.39c0,0.707,0.573,1.278,1.278,1.278h4.877 c-0.528,1.486-1.932,2.556-3.599,2.556H3.834C1.716,10.224,0,8.508,0,6.39V3.834C0,1.716,1.716,0,3.834,0h1.278 c1.667,0,3.071,1.071,3.599,2.556H3.834C3.129,2.556,2.556,3.127,2.556,3.834z";
  42704. return {
  42705. "commands": {
  42706. "hyperlink": kity.createClass("hyperlink", {
  42707. base: Command,
  42708. execute: function(km, url, title) {
  42709. var nodes = km.getSelectedNodes();
  42710. utils.each(nodes, function(i, n) {
  42711. n.setData('hyperlink', url);
  42712. n.setData('hyperlinkTitle', title);
  42713. n.render();
  42714. });
  42715. km.layout();
  42716. },
  42717. queryState: function(km) {
  42718. var nodes = km.getSelectedNodes(),
  42719. result = 0;
  42720. if (nodes.length === 0) {
  42721. return -1;
  42722. }
  42723. utils.each(nodes, function(i, n) {
  42724. if (n && n.getData('hyperlink')) {
  42725. result = 0;
  42726. return false;
  42727. }
  42728. });
  42729. return result;
  42730. },
  42731. queryValue: function(km) {
  42732. var node = km.getSelectedNode();
  42733. return {
  42734. url: node.getData('hyperlink'),
  42735. title: node.getData('hyperlinkTitle')
  42736. };
  42737. }
  42738. }),
  42739. "unhyperlink": kity.createClass("hyperlink", {
  42740. base: Command,
  42741. execute: function(km) {
  42742. var nodes = km.getSelectedNodes();
  42743. utils.each(nodes, function(i, n) {
  42744. n.setData('hyperlink');
  42745. n.render();
  42746. });
  42747. km.layout();
  42748. },
  42749. queryState: function(km) {
  42750. var nodes = km.getSelectedNodes();
  42751. if (nodes.length === 0) {
  42752. return -1;
  42753. }
  42754. var link = false;
  42755. utils.each(nodes, function(i, n) {
  42756. if (n.getData('hyperlink')) {
  42757. link = true;
  42758. return false;
  42759. }
  42760. });
  42761. if (link) {
  42762. return 0;
  42763. }
  42764. return -1;
  42765. }
  42766. })
  42767. },
  42768. 'renderers': {
  42769. right: kity.createClass('hyperlinkrender', {
  42770. base: KityMinder.Renderer,
  42771. create: function() {
  42772. var link = new kity.HyperLink();
  42773. var linkshape = new kity.Path();
  42774. var outline = new kity.Rect(24, 22, -2, -6, 4).fill('rgba(255, 255, 255, 0)');
  42775. linkshape.setPathData(linkShapePath).fill('#666');
  42776. link.addShape(outline);
  42777. link.addShape(linkshape);
  42778. link.setTarget('_blank');
  42779. link.setStyle('cursor', 'pointer');
  42780. link.on('mouseover', function() {
  42781. outline.fill('rgba(255, 255, 200, .8)');
  42782. }).on('mouseout', function() {
  42783. outline.fill('rgba(255, 255, 255, 0)');
  42784. });
  42785. return link;
  42786. },
  42787. shouldRender: function(node) {
  42788. return node.getData('hyperlink');
  42789. },
  42790. update: function(link, node, box) {
  42791. var href = node.getData('hyperlink');
  42792. link.setHref(href);
  42793. var title = node.getData('hyperlinkTitle');
  42794. if (title) {
  42795. title = [title, '(', href, ')'].join('');
  42796. } else {
  42797. title = href;
  42798. }
  42799. link.node.setAttributeNS('http://www.w3.org/1999/xlink', 'title', title);
  42800. var spaceRight = node.getStyle('space-right');
  42801. link.setTranslate(box.right + spaceRight + 2, -5);
  42802. return new kity.Box({
  42803. x: box.right + spaceRight,
  42804. y: -11,
  42805. width: 24,
  42806. height: 22
  42807. });
  42808. }
  42809. })
  42810. }
  42811. };
  42812. });
  42813. kity.extendClass(MinderNode, {
  42814. arrange: function(index) {
  42815. var parent = this.parent;
  42816. if (!parent) return;
  42817. var sibling = parent.children;
  42818. if (index < 0 || index >= sibling.length) return;
  42819. sibling.splice(this.getIndex(), 1);
  42820. sibling.splice(index, 0, this);
  42821. return this;
  42822. }
  42823. });
  42824. function asc(nodeA, nodeB) {
  42825. return nodeA.getIndex() - nodeB.getIndex();
  42826. }
  42827. function desc(nodeA, nodeB) {
  42828. return -asc(nodeA, nodeB);
  42829. }
  42830. function canArrange(km) {
  42831. var selected = km.getSelectedNode();
  42832. return selected && selected.parent && selected.parent.children.length > 1;
  42833. }
  42834. var ArrangeUpCommand = kity.createClass('ArrangeUpCommand', {
  42835. base: Command,
  42836. execute: function(km) {
  42837. var nodes = km.getSelectedNodes();
  42838. nodes.sort(asc);
  42839. var lastIndexes = nodes.map(function(node) {
  42840. return node.getIndex();
  42841. });
  42842. nodes.forEach(function(node, index) {
  42843. node.arrange(lastIndexes[index] - 1);
  42844. });
  42845. km.layout(300);
  42846. },
  42847. queryState: function(km) {
  42848. var selected = km.getSelectedNode();
  42849. return selected ? 0 : -1;
  42850. }
  42851. });
  42852. var ArrangeDownCommand = kity.createClass('ArrangeUpCommand', {
  42853. base: Command,
  42854. execute: function(km) {
  42855. var nodes = km.getSelectedNodes();
  42856. nodes.sort(desc);
  42857. var lastIndexes = nodes.map(function(node) {
  42858. return node.getIndex();
  42859. });
  42860. nodes.forEach(function(node, index) {
  42861. node.arrange(lastIndexes[index] + 1);
  42862. });
  42863. km.layout(300);
  42864. },
  42865. queryState: function(km) {
  42866. var selected = km.getSelectedNode();
  42867. return selected ? 0 : -1;
  42868. }
  42869. });
  42870. var ArrangeCommand = kity.createClass('ArrangeCommand', {
  42871. base: Command,
  42872. execute: function(km, nodes, index) {
  42873. nodes = nodes && nodes.slice() || km.getSelectedNodes().slice();
  42874. if (!nodes.length) return;
  42875. var ancestor = MinderNode.getCommonAncestor(nodes);
  42876. if (ancestor != nodes[0].parent) return;
  42877. var indexed = nodes.map(function(node) {
  42878. return {
  42879. index: node.getIndex(),
  42880. node: node
  42881. };
  42882. });
  42883. var asc = Math.min.apply(Math, indexed.map(function(one) { return one.index; })) >= index;
  42884. indexed.sort(function(a, b) {
  42885. return asc ? (b.index - a.index) : (a.index - b.index);
  42886. });
  42887. indexed.forEach(function(one) {
  42888. one.node.arrange(index);
  42889. });
  42890. km.layout(300);
  42891. },
  42892. queryState: function(km) {
  42893. var selected = km.getSelectedNode();
  42894. return selected ? 0 : -1;
  42895. }
  42896. });
  42897. KityMinder.registerModule('ArrangeModule', {
  42898. commands: {
  42899. 'arrangeup': ArrangeUpCommand,
  42900. 'arrangedown': ArrangeDownCommand,
  42901. 'arrange': ArrangeCommand
  42902. },
  42903. contextmenu: [{
  42904. command: 'arrangeup'
  42905. }, {
  42906. command: 'arrangedown'
  42907. }, {
  42908. divider: true
  42909. }],
  42910. commandShortcutKeys: {
  42911. 'arrangeup': 'normal::alt+Up',
  42912. 'arrangedown': 'normal::alt+Down'
  42913. }
  42914. });
  42915. KityMinder.registerModule( "ClipboardModule", function () {
  42916. var km = this,
  42917. _clipboardNodes = [],
  42918. _selectedNodes = [];
  42919. function appendChildNode(parent, child) {
  42920. _selectedNodes.push(child);
  42921. km.appendNode(child, parent);
  42922. child.render();
  42923. child.setLayoutOffset(null);
  42924. var children = utils.cloneArr(child.children);
  42925. for (var i = 0, ci; (ci = children[i]); i++) {
  42926. appendChildNode(child, ci);
  42927. }
  42928. }
  42929. function sendToClipboard(nodes) {
  42930. if (!nodes.length) return;
  42931. nodes.sort(function(a, b) {
  42932. return a.getIndex() - b.getIndex();
  42933. });
  42934. _clipboardNodes = nodes.map(function(node) {
  42935. return node.clone();
  42936. });
  42937. }
  42938. var CopyCommand = kity.createClass('CopyCommand', {
  42939. base: Command,
  42940. execute: function(km) {
  42941. sendToClipboard(km.getSelectedAncestors(true));
  42942. this.setContentChanged(false);
  42943. }
  42944. });
  42945. var CutCommand = kity.createClass('CutCommand', {
  42946. base: Command,
  42947. execute: function(km) {
  42948. var ancestors = km.getSelectedAncestors();
  42949. if (ancestors.length === 0) return;
  42950. sendToClipboard(ancestors);
  42951. km.select(MinderNode.getCommonAncestor(ancestors), true);
  42952. ancestors.slice().forEach(function(node) {
  42953. km.removeNode(node);
  42954. });
  42955. km.layout(300);
  42956. }
  42957. });
  42958. var PasteCommand = kity.createClass('PasteCommand', {
  42959. base: Command,
  42960. execute: function(km) {
  42961. if (_clipboardNodes.length) {
  42962. var node = km.getSelectedNode();
  42963. if (!node) return;
  42964. for (var i = 0, ni; (ni = _clipboardNodes[i]); i++) {
  42965. appendChildNode(node, ni.clone());
  42966. }
  42967. km.select(_selectedNodes, true);
  42968. _selectedNodes = [];
  42969. km.layout(300);
  42970. }
  42971. },
  42972. queryState: function(km) {
  42973. return km.getSelectedNode() ? 0 : -1;
  42974. }
  42975. });
  42976. return {
  42977. 'commands': {
  42978. 'copy': CopyCommand,
  42979. 'cut': CutCommand,
  42980. 'paste': PasteCommand
  42981. },
  42982. 'commandShortcutKeys': {
  42983. 'copy': 'normal::ctrl+c|',
  42984. 'cut': 'normal::ctrl+x',
  42985. 'paste': 'normal::ctrl+v'
  42986. }
  42987. };
  42988. } );
  42989. KityMinder.registerModule('StyleModule', function() {
  42990. var styleNames = ['font-size', 'font-family', 'font-weight', 'font-style', 'background', 'color'];
  42991. var styleClipBoard = null;
  42992. function hasStyle(node) {
  42993. var data = node.getData();
  42994. for(var i = 0; i < styleNames.length; i++) {
  42995. if (styleNames[i] in data) return true;
  42996. }
  42997. }
  42998. return {
  42999. "commands": {
  43000. "copystyle": kity.createClass("CopyStyleCommand", {
  43001. base: Command,
  43002. execute: function(minder) {
  43003. var node = minder.getSelectedNode();
  43004. var nodeData = node.getData();
  43005. styleClipBoard = {};
  43006. styleNames.forEach(function(name) {
  43007. if (name in nodeData) styleClipBoard[name] = nodeData[name];
  43008. else {
  43009. styleClipBoard[name] = null;
  43010. delete styleClipBoard[name];
  43011. }
  43012. });
  43013. return styleClipBoard;
  43014. },
  43015. queryState: function(minder) {
  43016. var nodes = minder.getSelectedNodes();
  43017. if (nodes.length !== 1) return -1;
  43018. return hasStyle(nodes[0]) ? 0 : -1;
  43019. }
  43020. }),
  43021. "pastestyle": kity.createClass("PastStyleCommand", {
  43022. base: Command,
  43023. execute: function(minder) {
  43024. minder.getSelectedNodes().forEach(function(node) {
  43025. for (var name in styleClipBoard) {
  43026. if (styleClipBoard.hasOwnProperty(name))
  43027. node.setData(name, styleClipBoard[name]);
  43028. }
  43029. });
  43030. minder.renderNodeBatch(minder.getSelectedNodes());
  43031. minder.layout(300);
  43032. return styleClipBoard;
  43033. },
  43034. queryState: function(minder) {
  43035. return (styleClipBoard && minder.getSelectedNodes().length) ? 0 : -1;
  43036. }
  43037. }),
  43038. "clearstyle": kity.createClass("ClearStyleCommand", {
  43039. base: Command,
  43040. execute: function(minder) {
  43041. minder.getSelectedNodes().forEach(function(node) {
  43042. styleNames.forEach(function(name) {
  43043. node.setData(name);
  43044. });
  43045. });
  43046. minder.renderNodeBatch(minder.getSelectedNodes());
  43047. minder.layout(300);
  43048. return styleClipBoard;
  43049. },
  43050. queryState: function(minder) {
  43051. var nodes = minder.getSelectedNodes();
  43052. if (!nodes.length) return -1;
  43053. for(var i = 0; i < nodes.length; i++) {
  43054. if (hasStyle(nodes[i])) return 0;
  43055. }
  43056. return -1;
  43057. }
  43058. })
  43059. }
  43060. };
  43061. });
  43062. /* global zip:true */
  43063. /*
  43064. http://www.xmind.net/developer/
  43065. Parsing XMind file
  43066. XMind files are generated in XMind Workbook (.xmind) format, an open format
  43067. that is based on the principles of OpenDocument. It consists of a ZIP
  43068. compressed archive containing separate XML documents for content and styles,
  43069. a .jpg image file for thumbnails, and directories for related attachments.
  43070. */
  43071. KityMinder.registerProtocol('xmind', function(minder) {
  43072. // 标签 map
  43073. var markerMap = {
  43074. 'priority-1': ['priority', 1],
  43075. 'priority-2': ['priority', 2],
  43076. 'priority-3': ['priority', 3],
  43077. 'priority-4': ['priority', 4],
  43078. 'priority-5': ['priority', 5],
  43079. 'priority-6': ['priority', 6],
  43080. 'priority-7': ['priority', 7],
  43081. 'priority-8': ['priority', 8],
  43082. 'task-start': ['progress', 1],
  43083. 'task-oct': ['progress', 2],
  43084. 'task-quarter': ['progress', 3],
  43085. 'task-3oct': ['progress', 4],
  43086. 'task-half': ['progress', 5],
  43087. 'task-5oct': ['progress', 6],
  43088. 'task-3quar': ['progress', 7],
  43089. 'task-7oct': ['progress', 8],
  43090. 'task-done': ['progress', 9]
  43091. };
  43092. return {
  43093. fileDescription: 'XMind 格式',
  43094. fileExtension: '.xmind',
  43095. dataType: 'blob',
  43096. mineType: 'application/octet-stream',
  43097. decode: function(local) {
  43098. function processTopic(topic, obj) {
  43099. //处理文本
  43100. obj.data = {
  43101. text: topic.title
  43102. };
  43103. // 处理标签
  43104. if (topic.marker_refs && topic.marker_refs.marker_ref) {
  43105. var markers = topic.marker_refs.marker_ref;
  43106. var type;
  43107. if (markers.length && markers.length > 0) {
  43108. for (var i in markers) {
  43109. type = markerMap[markers[i].marker_id];
  43110. if (type) obj.data[type[0]] = type[1];
  43111. }
  43112. } else {
  43113. type = markerMap[markers.marker_id];
  43114. if (type) obj.data[type[0]] = type[1];
  43115. }
  43116. }
  43117. // 处理超链接
  43118. if (topic['xlink:href']) {
  43119. obj.data.hyperlink = topic['xlink:href'];
  43120. }
  43121. //处理子节点
  43122. var topics = topic.children && topic.children.topics;
  43123. var subTopics = topics && (topics.topic || topics[0] && topics[0].topic);
  43124. if (subTopics) {
  43125. var tmp = subTopics;
  43126. if (tmp.length && tmp.length > 0) { //多个子节点
  43127. obj.children = [];
  43128. for (var i in tmp) {
  43129. obj.children.push({});
  43130. processTopic(tmp[i], obj.children[i]);
  43131. }
  43132. } else { //一个子节点
  43133. obj.children = [{}];
  43134. processTopic(tmp, obj.children[0]);
  43135. }
  43136. }
  43137. }
  43138. function xml2km(xml) {
  43139. var json = $.xml2json(xml);
  43140. var result = {};
  43141. var sheet = json.sheet;
  43142. var topic = utils.isArray(sheet) ? sheet[0].topic : sheet.topic;
  43143. processTopic(topic, result);
  43144. return result;
  43145. }
  43146. function getEntries(file, onend) {
  43147. return new Promise(function(resolve, reject) {
  43148. zip.createReader(new zip.BlobReader(file), function(zipReader) {
  43149. zipReader.getEntries(resolve);
  43150. }, reject);
  43151. });
  43152. }
  43153. function readDocument(entries) {
  43154. return new Promise(function(resolve, reject) {
  43155. var entry, json;
  43156. // 查找文档入口
  43157. while ((entry = entries.pop())) {
  43158. if (entry.filename.split('/').pop() == 'content.xml') break;
  43159. entry = null;
  43160. }
  43161. // 找到了读取数据
  43162. if (entry) {
  43163. entry.getData(new zip.TextWriter(), function(text) {
  43164. try {
  43165. json = xml2km($.parseXML(text));
  43166. resolve(json);
  43167. } catch (e) {
  43168. reject(e);
  43169. }
  43170. });
  43171. }
  43172. // 找不到返回失败
  43173. else {
  43174. reject(new Error('Content document missing'));
  43175. }
  43176. });
  43177. }
  43178. return getEntries(local).then(readDocument);
  43179. },
  43180. encode: function(json, km, options) {
  43181. var url = 'native-support/export.php';
  43182. var data = JSON.stringify(json);
  43183. function fetch() {
  43184. return new Promise(function(resolve, reject) {
  43185. var xhr = new XMLHttpRequest();
  43186. xhr.open('POST', url);
  43187. xhr.responseType = 'blob';
  43188. xhr.onload = resolve;
  43189. xhr.onerror = reject;
  43190. var form = new FormData();
  43191. form.append('type', 'xmind');
  43192. form.append('data', data);
  43193. xhr.send(form);
  43194. }).then(function(e) {
  43195. return e.target.response;
  43196. });
  43197. }
  43198. function download() {
  43199. var filename = options.filename || 'xmind.xmind';
  43200. var form = document.createElement('form');
  43201. form.setAttribute('action', url);
  43202. form.setAttribute('method', 'POST');
  43203. form.appendChild(field('filename', filename));
  43204. form.appendChild(field('type', 'xmind'));
  43205. form.appendChild(field('data', data));
  43206. form.appendChild(field('download', '1'));
  43207. document.body.appendChild(form);
  43208. form.submit();
  43209. document.body.removeChild(form);
  43210. function field(name, content) {
  43211. var input = document.createElement('input');
  43212. input.type = 'hidden';
  43213. input.name = name;
  43214. input.value = content;
  43215. return input;
  43216. }
  43217. }
  43218. if (options && options.download) {
  43219. return download();
  43220. } else {
  43221. return fetch();
  43222. }
  43223. },
  43224. // recognize: recognize,
  43225. recognizePriority: -1
  43226. };
  43227. });
  43228. /**
  43229. * @fileOverview FreeMind 文件格式支持
  43230. *
  43231. * Freemind 文件后缀为 .mm,实际上是一个 XML 文件
  43232. * @see http://freemind.sourceforge.net/
  43233. */
  43234. KityMinder.registerProtocol('freemind', function(minder) {
  43235. // 标签 map
  43236. var markerMap = {
  43237. 'full-1': ['priority', 1],
  43238. 'full-2': ['priority', 2],
  43239. 'full-3': ['priority', 3],
  43240. 'full-4': ['priority', 4],
  43241. 'full-5': ['priority', 5],
  43242. 'full-6': ['priority', 6],
  43243. 'full-7': ['priority', 7],
  43244. 'full-8': ['priority', 8]
  43245. };
  43246. function processTopic(topic, obj) {
  43247. //处理文本
  43248. obj.data = {
  43249. text: topic.TEXT
  43250. };
  43251. var i;
  43252. // 处理标签
  43253. if (topic.icon) {
  43254. var icons = topic.icon;
  43255. var type;
  43256. if (icons.length && icons.length > 0) {
  43257. for (i in icons) {
  43258. type = markerMap[icons[i].BUILTIN];
  43259. if (type) obj.data[type[0]] = type[1];
  43260. }
  43261. } else {
  43262. type = markerMap[icons.BUILTIN];
  43263. if (type) obj.data[type[0]] = type[1];
  43264. }
  43265. }
  43266. // 处理超链接
  43267. if (topic.LINK) {
  43268. obj.data.hyperlink = topic.LINK;
  43269. }
  43270. //处理子节点
  43271. if (topic.node) {
  43272. var tmp = topic.node;
  43273. if (tmp.length && tmp.length > 0) { //多个子节点
  43274. obj.children = [];
  43275. for (i in tmp) {
  43276. obj.children.push({});
  43277. processTopic(tmp[i], obj.children[i]);
  43278. }
  43279. } else { //一个子节点
  43280. obj.children = [{}];
  43281. processTopic(tmp, obj.children[0]);
  43282. }
  43283. }
  43284. }
  43285. function xml2km(xml) {
  43286. var json = $.xml2json(xml);
  43287. var result = {};
  43288. processTopic(json.node, result);
  43289. return result;
  43290. }
  43291. return {
  43292. fileDescription: 'Freemind 格式',
  43293. fileExtension: '.mm',
  43294. dataType: 'text',
  43295. decode: function(local) {
  43296. return new Promise(function(resolve, reject) {
  43297. try {
  43298. resolve(xml2km(local));
  43299. } catch (e) {
  43300. reject(new Error('XML 文件损坏!'));
  43301. }
  43302. });
  43303. },
  43304. encode: function(json, km, options) {
  43305. var url = 'native-support/export.php';
  43306. var data = JSON.stringify(json);
  43307. function fetch() {
  43308. return new Promise(function(resolve, reject) {
  43309. var xhr = new XMLHttpRequest();
  43310. xhr.open('POST', url);
  43311. xhr.responseType = 'blob';
  43312. xhr.onload = resolve;
  43313. xhr.onerror = reject;
  43314. var form = new FormData();
  43315. form.append('type', 'freemind');
  43316. form.append('data', data);
  43317. xhr.send(form);
  43318. }).then(function(e) {
  43319. return e.target.response;
  43320. });
  43321. }
  43322. function download() {
  43323. var filename = options.filename || 'freemind.mm';
  43324. var form = document.createElement('form');
  43325. form.setAttribute('action', url);
  43326. form.setAttribute('method', 'POST');
  43327. form.appendChild(field('filename', filename));
  43328. form.appendChild(field('type', 'freemind'));
  43329. form.appendChild(field('data', data));
  43330. form.appendChild(field('download', '1'));
  43331. document.body.appendChild(form);
  43332. form.submit();
  43333. document.body.removeChild(form);
  43334. function field(name, content) {
  43335. var input = document.createElement('input');
  43336. input.type = 'hidden';
  43337. input.name = name;
  43338. input.value = content;
  43339. return input;
  43340. }
  43341. }
  43342. if (options && options.download) {
  43343. return download();
  43344. } else {
  43345. return fetch();
  43346. }
  43347. }
  43348. };
  43349. });
  43350. /* global zip:true */
  43351. /*
  43352. http://www.mindjet.com/mindmanager/
  43353. mindmanager的后缀为.mmap,实际文件格式是zip,解压之后核心文件是Document.xml
  43354. */
  43355. KityMinder.registerProtocol('mindmanager', function(minder) {
  43356. // 标签 map
  43357. var markerMap = {
  43358. 'urn:mindjet:Prio1': ['PriorityIcon', 1],
  43359. 'urn:mindjet:Prio2': ['PriorityIcon', 2],
  43360. 'urn:mindjet:Prio3': ['PriorityIcon', 3],
  43361. 'urn:mindjet:Prio4': ['PriorityIcon', 4],
  43362. 'urn:mindjet:Prio5': ['PriorityIcon', 5],
  43363. '0': ['ProgressIcon', 1],
  43364. '25': ['ProgressIcon', 2],
  43365. '50': ['ProgressIcon', 3],
  43366. '75': ['ProgressIcon', 4],
  43367. '100': ['ProgressIcon', 5]
  43368. };
  43369. function processTopic(topic, obj) {
  43370. //处理文本
  43371. obj.data = {
  43372. text: topic.Text && topic.Text.PlainText || ''
  43373. }; // 节点默认的文本,没有Text属性
  43374. // 处理标签
  43375. if (topic.Task) {
  43376. var type;
  43377. if (topic.Task.TaskPriority) {
  43378. type = markerMap[topic.Task.TaskPriority];
  43379. if (type) obj.data[type[0]] = type[1];
  43380. }
  43381. if (topic.Task.TaskPercentage) {
  43382. type = markerMap[topic.Task.TaskPercentage];
  43383. if (type) obj.data[type[0]] = type[1];
  43384. }
  43385. }
  43386. // 处理超链接
  43387. if (topic.Hyperlink) {
  43388. obj.data.hyperlink = topic.Hyperlink.Url;
  43389. }
  43390. //处理子节点
  43391. if (topic.SubTopics && topic.SubTopics.Topic) {
  43392. var tmp = topic.SubTopics.Topic;
  43393. if (tmp.length && tmp.length > 0) { //多个子节点
  43394. obj.children = [];
  43395. for (var i in tmp) {
  43396. obj.children.push({});
  43397. processTopic(tmp[i], obj.children[i]);
  43398. }
  43399. } else { //一个子节点
  43400. obj.children = [{}];
  43401. processTopic(tmp, obj.children[0]);
  43402. }
  43403. }
  43404. }
  43405. function xml2km(xml) {
  43406. var json = $.xml2json(xml);
  43407. var result = {};
  43408. processTopic(json.OneTopic.Topic, result);
  43409. return result;
  43410. }
  43411. function getEntries(file) {
  43412. return new Promise(function(resolve, reject) {
  43413. zip.createReader(new zip.BlobReader(file), function(zipReader) {
  43414. zipReader.getEntries(resolve);
  43415. }, reject);
  43416. });
  43417. }
  43418. function readMainDocument(entries) {
  43419. return new Promise(function(resolve, reject) {
  43420. var entry, json;
  43421. // 查找文档入口
  43422. while ((entry = entries.pop())) {
  43423. if (entry.filename.split('/').pop() == 'Document.xml') break;
  43424. entry = null;
  43425. }
  43426. // 找到了读取数据
  43427. if (entry) {
  43428. entry.getData(new zip.TextWriter(), function(text) {
  43429. json = xml2km($.parseXML(text));
  43430. resolve(json);
  43431. });
  43432. }
  43433. // 找不到返回失败
  43434. else {
  43435. reject(new Error('Main document missing'));
  43436. }
  43437. });
  43438. }
  43439. return {
  43440. fileDescription: 'MindManager 格式',
  43441. fileExtension: '.mmap',
  43442. dataType: 'blob',
  43443. decode: function(local) {
  43444. return getEntries(local).then(readMainDocument);
  43445. },
  43446. // 暂时不支持编码
  43447. encode: null,
  43448. recognizePriority: -1
  43449. };
  43450. });
  43451. KityMinder.registerProtocol('plain', function(minder) {
  43452. var LINE_ENDING = '\r',
  43453. LINE_ENDING_SPLITER = /\r\n|\r|\n/,
  43454. TAB_CHAR = '\t';
  43455. function repeat(s, n) {
  43456. var result = '';
  43457. while (n--) result += s;
  43458. return result;
  43459. }
  43460. function encode(json, level) {
  43461. var local = '';
  43462. level = level || 0;
  43463. local += repeat(TAB_CHAR, level);
  43464. local += json.data.text + LINE_ENDING;
  43465. if (json.children) {
  43466. json.children.forEach(function(child) {
  43467. local += encode(child, level + 1);
  43468. });
  43469. }
  43470. return local;
  43471. }
  43472. function isEmpty(line) {
  43473. return !/\S/.test(line);
  43474. }
  43475. function getLevel(line) {
  43476. var level = 0;
  43477. while (line.charAt(level) === TAB_CHAR) level++;
  43478. return level;
  43479. }
  43480. function getNode(line) {
  43481. return {
  43482. data: {
  43483. text: line.replace(new RegExp('^' + TAB_CHAR + '*'), '')
  43484. }
  43485. };
  43486. }
  43487. /**
  43488. * 文本解码
  43489. *
  43490. * @param {string} local 文本内容
  43491. * @param {=boolean} root 自动根节点
  43492. * @return {Object} 返回解析后节点
  43493. */
  43494. function decode(local, root) {
  43495. var json,
  43496. offset,
  43497. parentMap = {},
  43498. lines = local.split(LINE_ENDING_SPLITER),
  43499. line, level, node;
  43500. function addChild(parent, child) {
  43501. var children = parent.children || (parent.children = []);
  43502. children.push(child);
  43503. }
  43504. if (root) {
  43505. parentMap[0] = json = getNode('root');
  43506. offset = 1;
  43507. } else {
  43508. offset = 0;
  43509. }
  43510. for (var i = 0; i < lines.length; i++) {
  43511. line = lines[i];
  43512. if (isEmpty(line)) continue;
  43513. level = getLevel(line) + offset;
  43514. node = getNode(line);
  43515. if (level === 0) {
  43516. if (json) {
  43517. throw new Error('Invalid local format');
  43518. }
  43519. json = node;
  43520. } else {
  43521. if (!parentMap[level - 1]) {
  43522. throw new Error('Invalid local format');
  43523. }
  43524. addChild(parentMap[level - 1], node);
  43525. }
  43526. parentMap[level] = node;
  43527. }
  43528. return json;
  43529. }
  43530. return {
  43531. fileDescription: '大纲文本',
  43532. fileExtension: '.txt',
  43533. mineType: 'text/plain',
  43534. dataType: 'text',
  43535. encode: function(json) {
  43536. return encode(json, 0);
  43537. },
  43538. decode: function(local, root) {
  43539. return decode(local, root);
  43540. },
  43541. recognizePriority: -1
  43542. };
  43543. });
  43544. /**
  43545. * @fileOverview
  43546. *
  43547. * Markdown 格式导入导出支持
  43548. *
  43549. * @author: techird
  43550. * @copyright: Baidu FEX, 2014
  43551. */
  43552. KityMinder.registerProtocol('markdown', function() {
  43553. var LINE_ENDING_SPLITER = /\r\n|\r|\n/;
  43554. var EMPTY_LINE = '';
  43555. var NOTE_MARK_START = '<!--Note-->';
  43556. var NOTE_MARK_CLOSE = '<!--/Note-->';
  43557. function encode(json) {
  43558. return _build(json, 1).join('\n');
  43559. }
  43560. function _build(node, level) {
  43561. var lines = [];
  43562. level = level || 1;
  43563. var sharps = _generateHeaderSharp(level);
  43564. lines.push(sharps + ' ' + node.data.text);
  43565. lines.push(EMPTY_LINE);
  43566. var note = node.data.note;
  43567. if (note) {
  43568. var hasSharp = /^#/.test(note);
  43569. if (hasSharp) {
  43570. lines.push(NOTE_MARK_START);
  43571. note = note.replace(/^#+/gm, function($0) {
  43572. return sharps + $0;
  43573. });
  43574. }
  43575. lines.push(note);
  43576. if (hasSharp) {
  43577. lines.push(NOTE_MARK_CLOSE);
  43578. }
  43579. lines.push(EMPTY_LINE);
  43580. }
  43581. if (node.children) node.children.forEach(function(child) {
  43582. lines = lines.concat(_build(child, level + 1));
  43583. });
  43584. return lines;
  43585. }
  43586. function _generateHeaderSharp(level) {
  43587. var sharps = '';
  43588. while(level--) sharps += '#';
  43589. return sharps;
  43590. }
  43591. function decode(markdown) {
  43592. var json,
  43593. parentMap = {},
  43594. lines, line, lineInfo, level, node, parent, noteProgress, codeBlock;
  43595. // 一级标题转换 `{title}\n===` => `# {title}`
  43596. markdown = markdown.replace(/^(.+)\n={3,}/, function($0, $1) {
  43597. return '# ' + $1;
  43598. });
  43599. lines = markdown.split(LINE_ENDING_SPLITER);
  43600. // 按行分析
  43601. for (var i = 0; i < lines.length; i++) {
  43602. line = lines[i];
  43603. lineInfo = _resolveLine(line);
  43604. // 备注标记处理
  43605. if (lineInfo.noteClose) {
  43606. noteProgress = false;
  43607. continue;
  43608. } else if (lineInfo.noteStart) {
  43609. noteProgress = true;
  43610. continue;
  43611. }
  43612. // 代码块处理
  43613. codeBlock = lineInfo.codeBlock ? !codeBlock : codeBlock;
  43614. // 备注条件:备注标签中,非标题定义,或标题越位
  43615. if (noteProgress || codeBlock || !lineInfo.level || lineInfo.level > level + 1) {
  43616. if (node) _pushNote(node, line);
  43617. continue;
  43618. }
  43619. // 标题处理
  43620. level = lineInfo.level;
  43621. node = _initNode(lineInfo.content, parentMap[level - 1]);
  43622. parentMap[level] = node;
  43623. }
  43624. _cleanUp(parentMap[1]);
  43625. return parentMap[1];
  43626. }
  43627. function _initNode(text, parent) {
  43628. var node = {
  43629. data: {
  43630. text: text,
  43631. note: ''
  43632. }
  43633. };
  43634. if (parent) {
  43635. if (parent.children) parent.children.push(node);
  43636. else parent.children = [node];
  43637. }
  43638. return node;
  43639. }
  43640. function _pushNote(node, line) {
  43641. node.data.note += line + '\n';
  43642. }
  43643. function _isEmpty(line) {
  43644. return !/\S/.test(line);
  43645. }
  43646. function _resolveLine(line) {
  43647. var match = /^(#+)?\s*(.*)$/.exec(line);
  43648. return {
  43649. level: match[1] && match[1].length || null,
  43650. content: match[2],
  43651. noteStart: line == NOTE_MARK_START,
  43652. noteClose: line == NOTE_MARK_CLOSE,
  43653. codeBlock: /^\s*```/.test(line)
  43654. };
  43655. }
  43656. function _cleanUp(node) {
  43657. if (!/\S/.test(node.data.note)) {
  43658. node.data.note = null;
  43659. delete node.data.note;
  43660. } else {
  43661. var notes = node.data.note.split('\n');
  43662. while(notes.length && !/\S/.test(notes[0])) notes.shift();
  43663. while(notes.length && !/\S/.test(notes[notes.length - 1])) notes.pop();
  43664. node.data.note = notes.join('\n');
  43665. }
  43666. if (node.children) node.children.forEach(_cleanUp);
  43667. }
  43668. return {
  43669. fileDescription: 'Markdown/GFM 格式',
  43670. fileExtension: '.md',
  43671. mineType: 'text/markdown',
  43672. dataType: 'text',
  43673. encode: function(json) {
  43674. return encode(json);
  43675. },
  43676. decode: function(markdown) {
  43677. return decode(markdown);
  43678. },
  43679. recognizePriority: -1
  43680. };
  43681. });
  43682. KityMinder.registerProtocol('json', function(minder) {
  43683. return {
  43684. fileDescription: 'KityMinder 格式',
  43685. fileExtension: '.km',
  43686. dataType: 'text',
  43687. mineType: 'application/json',
  43688. encode: function(json) {
  43689. return JSON.stringify(json);
  43690. },
  43691. decode: function(local) {
  43692. return JSON.parse(local);
  43693. }
  43694. };
  43695. });
  43696. if (!kity.Browser.ie) {
  43697. KityMinder.registerProtocol('png', function(minder) {
  43698. var DomURL = window.URL || window.webkitURL || window;
  43699. function loadImage(url, callback) {
  43700. return new Promise(function(resolve, reject) {
  43701. var image = document.createElement('img');
  43702. image.onload = function() {
  43703. resolve(this);
  43704. };
  43705. image.onerror = function(err) {
  43706. reject(err);
  43707. };
  43708. image.crossOrigin = '';
  43709. image.src = url;
  43710. });
  43711. }
  43712. function getSVGInfo() {
  43713. var paper = minder.getPaper(),
  43714. paperTransform,
  43715. domContainer = paper.container,
  43716. svgXml,
  43717. $svg,
  43718. renderContainer = minder.getRenderContainer(),
  43719. renderBox = renderContainer.getRenderBox(),
  43720. width = renderBox.width + 1,
  43721. height = renderBox.height + 1,
  43722. blob, svgUrl, img;
  43723. // 保存原始变换,并且移动到合适的位置
  43724. paperTransform = paper.shapeNode.getAttribute('transform');
  43725. paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
  43726. renderContainer.translate(-renderBox.x, -renderBox.y);
  43727. // 获取当前的 XML 代码
  43728. svgXml = paper.container.innerHTML;
  43729. // 回复原始变换及位置
  43730. renderContainer.translate(renderBox.x, renderBox.y);
  43731. paper.shapeNode.setAttribute('transform', paperTransform);
  43732. // 过滤内容
  43733. $svg = $(svgXml).filter('svg');
  43734. $svg.attr({
  43735. width: renderBox.width + 1,
  43736. height: renderBox.height + 1,
  43737. style: 'font-family: Arial, "Microsoft Yahei","Heiti SC";'
  43738. });
  43739. svgXml = $('<div></div>').append($svg).html();
  43740. // Dummy IE
  43741. svgXml = svgXml.replace(' xmlns="http://www.w3.org/2000/svg" xmlns:NS1="" NS1:ns1:xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:NS2="" NS2:xmlns:ns1=""', '');
  43742. // svg 含有 &nbsp; 符号导出报错 Entity 'nbsp' not defined
  43743. svgXml = svgXml.replace(/&nbsp;/g, '&#xa0;');
  43744. blob = new Blob([svgXml], {
  43745. type: 'image/svg+xml'
  43746. });
  43747. svgUrl = DomURL.createObjectURL(blob);
  43748. //svgUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgXml);
  43749. return {
  43750. width: width,
  43751. height: height,
  43752. dataUrl: svgUrl,
  43753. xml: svgXml
  43754. };
  43755. }
  43756. function encode(json) {
  43757. /* 绘制 PNG 的画布及上下文 */
  43758. var canvas = document.createElement('canvas');
  43759. var ctx = canvas.getContext('2d');
  43760. /* 尝试获取背景图片 URL 或背景颜色 */
  43761. var bgDeclare = minder.getStyle('background').toString();
  43762. var bgUrl = /url\((.+)\)/.exec(bgDeclare);
  43763. var bgColor = kity.Color.parse(bgDeclare);
  43764. /* 获取 SVG 文件内容 */
  43765. var svgInfo = getSVGInfo();
  43766. var width = svgInfo.width;
  43767. var height = svgInfo.height;
  43768. var svgDataUrl = svgInfo.dataUrl;
  43769. /* 画布的填充大小 */
  43770. var padding = 20;
  43771. canvas.width = width + padding * 2;
  43772. canvas.height = height + padding * 2;
  43773. function fillBackground(ctx, style) {
  43774. ctx.save();
  43775. ctx.fillStyle = style;
  43776. ctx.fillRect(0, 0, canvas.width, canvas.height);
  43777. ctx.restore();
  43778. }
  43779. function drawImage(ctx, image, x, y) {
  43780. ctx.drawImage(image, x, y);
  43781. }
  43782. function generateDataUrl(canvas) {
  43783. try {
  43784. var url = canvas.toDataURL('png');
  43785. return url;
  43786. } catch (e) {
  43787. throw new Error('当前浏览器版本不支持导出 PNG 功能,请尝试升级到最新版本!');
  43788. }
  43789. }
  43790. function drawSVG() {
  43791. if (typeof(window.canvg) != 'undefined') {
  43792. return new Promise(function(resolve) {
  43793. window.canvg(canvas, svgInfo.xml, {
  43794. ignoreMouse: true,
  43795. ignoreAnimation: true,
  43796. ignoreDimensions: true,
  43797. ignoreClear: true,
  43798. offsetX: padding,
  43799. offsetY: padding,
  43800. renderCallback: function() {
  43801. resolve(generateDataUrl(canvas));
  43802. }
  43803. });
  43804. });
  43805. } else {
  43806. return loadImage(svgDataUrl).then(function(svgImage) {
  43807. drawImage(ctx, svgImage, padding, padding);
  43808. DomURL.revokeObjectURL(svgDataUrl);
  43809. return generateDataUrl(canvas);
  43810. });
  43811. }
  43812. }
  43813. if (bgUrl) {
  43814. return loadImage(bgUrl[1]).then(function(image) {
  43815. fillBackground(ctx, ctx.createPattern(image, 'repeat'));
  43816. return drawSVG();
  43817. });
  43818. } else {
  43819. fillBackground(ctx, bgColor.toString());
  43820. return drawSVG();
  43821. }
  43822. }
  43823. return {
  43824. fileDescription: 'PNG 图片',
  43825. fileExtension: '.png',
  43826. mineType: 'image/png',
  43827. dataType: 'base64',
  43828. encode: encode,
  43829. recognizePriority: -1
  43830. };
  43831. });
  43832. }
  43833. if (!kity.Browser.ie) {
  43834. KityMinder.registerProtocol('svg', function(minder) {
  43835. return {
  43836. fileDescription: 'SVG 矢量图',
  43837. fileExtension: '.svg',
  43838. mineType: 'image/svg+xml',
  43839. dataType: 'text',
  43840. encode: function(json) {
  43841. var paper = minder.getPaper(),
  43842. paperTransform = paper.shapeNode.getAttribute('transform'),
  43843. svgXml,
  43844. $svg,
  43845. renderContainer = minder.getRenderContainer(),
  43846. renderBox = renderContainer.getRenderBox(),
  43847. transform = renderContainer.getTransform(),
  43848. width = renderBox.width,
  43849. height = renderBox.height,
  43850. padding = 20;
  43851. paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
  43852. svgXml = paper.container.innerHTML;
  43853. paper.shapeNode.setAttribute('transform', paperTransform);
  43854. $svg = $(svgXml).filter('svg');
  43855. $svg.attr({
  43856. width: width + padding * 2 | 0,
  43857. height: height + padding * 2 | 0,
  43858. style: 'font-family: Arial, "Microsoft Yahei", "Heiti SC"; background: ' + minder.getStyle('background')
  43859. });
  43860. $svg[0].setAttribute('viewBox', [renderBox.x - padding | 0,
  43861. renderBox.y - padding | 0,
  43862. width + padding * 2 | 0,
  43863. height + padding * 2 | 0
  43864. ].join(' '));
  43865. // need a xml with width and height
  43866. svgXml = $('<div></div>').append($svg).html();
  43867. svgXml = $('<div></div>').append($svg).html();
  43868. // svg 含有 &nbsp; 符号导出报错 Entity 'nbsp' not defined
  43869. svgXml = svgXml.replace(/&nbsp;/g, '&#xa0;');
  43870. // svg 含有 &nbsp; 符号导出报错 Entity 'nbsp' not defined
  43871. return svgXml;
  43872. },
  43873. recognizePriority: -1
  43874. };
  43875. });
  43876. }
  43877. /**
  43878. * @fileOverview
  43879. *
  43880. * KityMinder UI 注册及加载机制
  43881. *
  43882. * @author: techird
  43883. * @copyright: Baidu FEX, 2014
  43884. */
  43885. (function() {
  43886. var uiQueue = [];
  43887. /* 注册一个新的 UI 交互 */
  43888. KityMinder.registerUI = function(id, deps, ui) {
  43889. if (typeof(deps) == 'function') {
  43890. ui = deps;
  43891. deps = null;
  43892. }
  43893. uiQueue.push({
  43894. id: id,
  43895. ui: ui,
  43896. deps: deps
  43897. });
  43898. };
  43899. kity.extendClass(Minder, {
  43900. /* 为实例注册 UI 交互 */
  43901. initUI: function() {
  43902. var ui = this._ui = {};
  43903. var minder = this;
  43904. uiQueue.forEach(function(uiDeal) {
  43905. var deps = uiDeal.deps;
  43906. if (deps) deps = deps.map(function(dep) {
  43907. return minder.getUI(dep);
  43908. });
  43909. ui[uiDeal.id] = uiDeal.ui.apply(null, [minder].concat(deps || []));
  43910. });
  43911. // 阻止非脑图事件冒泡
  43912. $('#content-wrapper').delegate('#panel, #tab-container, .fui-dialog, #main-menu', 'keydown keyup', function(e) {
  43913. e.stopPropagation();
  43914. });
  43915. // 阻止非脑图事件冒泡
  43916. $('#content-wrapper').delegate('input', 'mousedown mousemove mouseup contextmenu', function(e) {
  43917. e.stopPropagation();
  43918. });
  43919. minder.getPaper().addClass('loading-target');
  43920. this.fire('interactchange');
  43921. this.fire('uiready');
  43922. },
  43923. /* 获得实例的 UI 实例 */
  43924. getUI: function(id) {
  43925. return this._ui[id];
  43926. }
  43927. });
  43928. $.ajaxSetup({ cache: false });
  43929. $.extend($, {
  43930. pajax: function() {
  43931. var jqXHR = $.ajax.apply($, arguments);
  43932. return new Promise(function(resolve, reject) {
  43933. jqXHR.done(resolve);
  43934. jqXHR.fail(function(jqXHR, textStatus, errorThrown) {
  43935. var e = new Error(textStatus);
  43936. e.getDetail = function() {
  43937. try {
  43938. return 'jQuery XHR Error: \n' + JSON.stringify(errorThrown);
  43939. } catch (e) {
  43940. return errorThrown;
  43941. }
  43942. };
  43943. reject(e);
  43944. });
  43945. });
  43946. }
  43947. });
  43948. // preload css images
  43949. $(function() {
  43950. var list = ["kmcat_warn.png", "kmcat_sad.png", "icons.png", "template_large.png", "history.png", "feedback.png", "iconpriority.png", "iconprogress.png", "template.png", "layout.png", "next-level.png", "prev-level.png"];
  43951. list.forEach(function(item) {
  43952. (new Image()).src = 'ui/theme/default/images/' + item;
  43953. });
  43954. });
  43955. })();
  43956. /**
  43957. * @fileOverview
  43958. *
  43959. * 简版事件解耦功能
  43960. *
  43961. * @author: techird
  43962. * @copyright: Baidu FEX, 2014
  43963. */
  43964. KityMinder.registerUI('eve', function(minder) {
  43965. return {
  43966. setup: function(obj) {
  43967. var callbacks = {};
  43968. obj.on = function on(name, callback) {
  43969. var list = callbacks[name] || (callbacks[name] = []);
  43970. list.push(callback);
  43971. return this;
  43972. };
  43973. obj.off = function off(name, callback) {
  43974. var list = callbacks[name];
  43975. if (list) {
  43976. var index = list.indexOf(callback);
  43977. if (~index) {
  43978. list.splice(index, 1);
  43979. } else {
  43980. callback[name] = null;
  43981. }
  43982. }
  43983. return this;
  43984. };
  43985. obj.once = function once(name, callback) {
  43986. return this.on(name, function wrapped() {
  43987. callback.apply(obj, arguments);
  43988. obj.off(name, wrapped);
  43989. });
  43990. };
  43991. obj.fire = function fire(name) {
  43992. var list = callbacks[name];
  43993. var args = [].slice.call(arguments, 1);
  43994. if (list) list.forEach(function(callback) {
  43995. callback.apply(obj, args);
  43996. });
  43997. return this;
  43998. };
  43999. return obj;
  44000. }
  44001. };
  44002. });
  44003. /**
  44004. * @fileOverview
  44005. *
  44006. * UI 状态记忆
  44007. *
  44008. * @author: techird
  44009. * @copyright: Baidu FEX, 2014
  44010. */
  44011. KityMinder.registerUI('memory', function () {
  44012. var ls = window.localStorage;
  44013. var memory = ls.uiMemory ? JSON.parse(ls.uiMemory) : {};
  44014. return {
  44015. get: function(item) {
  44016. return memory[item] || null;
  44017. },
  44018. set: function(item, value) {
  44019. memory[item] = value;
  44020. ls.uiMemory = JSON.stringify(memory);
  44021. }
  44022. };
  44023. });
  44024. /**
  44025. * @fileOverview
  44026. *
  44027. * 拓展 FUI 组件的功能
  44028. *
  44029. * @author: techird
  44030. * @copyright: Baidu FEX, 2014
  44031. */
  44032. kity.extendClass(FUI.Widget, {
  44033. setEnable: function(value) {
  44034. if (value === false) this.disable();
  44035. else this.enable();
  44036. },
  44037. setActive: function(value) {
  44038. if (value === false) this.removeClass('active');
  44039. else this.addClass('active');
  44040. },
  44041. bindExecution: function(event, fn) {
  44042. var widget = this;
  44043. widget.on(event, function() {
  44044. if (widget.interactFlag) return;
  44045. fn.apply(widget, arguments);
  44046. });
  44047. },
  44048. bindCommandState: function(minder, command, valueHandle) {
  44049. var widget = this;
  44050. minder.on('interactchange', function() {
  44051. widget.interactFlag = true;
  44052. if (valueHandle) {
  44053. var value = this.queryCommandValue(command);
  44054. if (value != widget.lastHandleCommandValue) {
  44055. valueHandle.call(widget, value);
  44056. widget.lastHandleCommandValue = value;
  44057. }
  44058. }
  44059. widget.setEnable(this.queryCommandState(command) !== -1);
  44060. widget.setActive(this.queryCommandState(command) === 1);
  44061. widget.interactFlag = false;
  44062. });
  44063. }
  44064. });
  44065. /**
  44066. * @fileOverview
  44067. *
  44068. * XSS Protection
  44069. *
  44070. * @author: techird
  44071. * @copyright: Baidu FEX, 2014
  44072. */
  44073. KityMinder.registerUI('axss', function() {
  44074. function axss(value) {
  44075. var div = document.createElement('div');
  44076. div.innerHTML = value;
  44077. $(div).find('script, iframe, link').remove();
  44078. for (var name in div) {
  44079. if (name.indexOf('on') === 0) {
  44080. div.removeAttribute(name);
  44081. }
  44082. }
  44083. return div.innerHTML;
  44084. }
  44085. return axss;
  44086. });
  44087. /**
  44088. * @fileOverview
  44089. *
  44090. * 拓展 fio 的能力
  44091. *
  44092. * @author: techird
  44093. * @copyright: Baidu FEX, 2014
  44094. */
  44095. KityMinder.registerUI('fiox', function(minder) {
  44096. var eve = minder.getUI('eve');
  44097. eve.setup(fio.user);
  44098. /* 初始化网盘使用的 APP 身份 */
  44099. fio.user.init({
  44100. apiKey: 'wiE55BGOG8BkGnpPs6UNtPbb'
  44101. });
  44102. });
  44103. /**
  44104. * @fileOverview
  44105. *
  44106. * 生成绑定到某个命令的按钮
  44107. *
  44108. * @author: techird
  44109. * @copyright: Baidu FEX, 2014
  44110. */
  44111. KityMinder.registerUI('widget/commandbutton', function(minder) {
  44112. return {
  44113. generate: function(command, onclick) {
  44114. var $button = new FUI.Button({
  44115. label: minder.getLang('ui.command.' + command) || minder.getLang('ui.' + command),
  44116. text: minder.getLang('ui.command.' + command) || minder.getLang('ui.' + command),
  44117. className: ['command-widget', 'command-button', command]
  44118. });
  44119. $button.bindExecution('click', onclick || function() {
  44120. minder.execCommand(command);
  44121. });
  44122. $button.bindCommandState(minder, command);
  44123. return $button;
  44124. }
  44125. };
  44126. });
  44127. /**
  44128. * @fileOverview
  44129. *
  44130. * commandbuttonset.js 生成与指定命令绑定的按钮
  44131. *
  44132. * @author: techird
  44133. * @copyright: Baidu FEX, 2014
  44134. */
  44135. KityMinder.registerUI('widget/commandbuttonset', function(minder) {
  44136. function mapValueItem(command, valueList) {
  44137. return valueList.map(function(value) {
  44138. var text = minder.getLang([command, value].join('.')) || value;
  44139. return {
  44140. label: text,
  44141. text: text,
  44142. value: value,
  44143. className: [command, value].join(' ')
  44144. };
  44145. });
  44146. }
  44147. function generate(command, valueList) {
  44148. var $buttonset = new FUI.Buttonset({
  44149. id: 'template-set',
  44150. buttons: typeof(valueList[0]) == 'object' ? valueList : mapValueItem(command, valueList),
  44151. className: ['command-widget', 'command-buttonset', command].join(' ')
  44152. });
  44153. $buttonset.bindExecution('change', function() {
  44154. minder.execCommand(command, $buttonset.getValue());
  44155. });
  44156. $buttonset.bindCommandState(minder, command, function(value) {
  44157. this.selectByValue(value);
  44158. });
  44159. return $buttonset;
  44160. }
  44161. return {
  44162. generate: generate
  44163. };
  44164. });
  44165. /**
  44166. * @fileOverview
  44167. *
  44168. * 绑定到某个命令的下拉选框
  44169. *
  44170. */
  44171. KityMinder.registerUI('widget/commandinputmenu', function(minder) {
  44172. function generate(command, menuList) {
  44173. var $menu = new FUI.InputMenu({
  44174. menu: {
  44175. items: menuList
  44176. },
  44177. input: {
  44178. placeholder: minder.getLang('ui.' + command),
  44179. },
  44180. className: ['command-widget', 'command-inputmenu', command]
  44181. });
  44182. $menu.bindCommandState(minder, command, function(value) {
  44183. if (!$menu.selectByValue(value)) {
  44184. $menu.clearSelect();
  44185. }
  44186. });
  44187. var lastIndex = -1;
  44188. $menu.bindExecution('select', function(e, info) {
  44189. if (~info.index) {
  44190. minder.execCommand(command, info.value);
  44191. } else {
  44192. $menu.select(lastIndex);
  44193. }
  44194. lastIndex = info.index;
  44195. });
  44196. return $menu;
  44197. }
  44198. return {
  44199. generate: generate
  44200. };
  44201. });
  44202. /**
  44203. * @fileOverview
  44204. *
  44205. * 生成与指定命令绑定的下拉选框
  44206. *
  44207. * @author: techird
  44208. * @copyright: Baidu FEX, 2014
  44209. */
  44210. KityMinder.registerUI('widget/commandselectmenu', function(minder) {
  44211. function mapValueWidget(command, valueList) {
  44212. return valueList.map(function(value) {
  44213. var text = minder.getLang([command, value].join('.')) || value;
  44214. return {
  44215. clazz: 'Button',
  44216. label: text,
  44217. text: text,
  44218. value: value,
  44219. className: [command, value].join(' ')
  44220. };
  44221. });
  44222. }
  44223. function generate(command, valueList, column) {
  44224. var $selectMenu = new FUI.SelectMenu({
  44225. widgets: typeof(valueList[0]) == 'object' ? valueList : mapValueWidget(command, valueList),
  44226. className: ['command-widget', 'command-selectmenu', command].join(' '),
  44227. column: column || 3
  44228. });
  44229. $selectMenu.bindExecution('change', function() {
  44230. minder.execCommand(command, $selectMenu.getValue());
  44231. });
  44232. $selectMenu.bindCommandState(minder, command, function(value) {
  44233. if (value !== undefined) this.selectByValue(value);
  44234. });
  44235. return $selectMenu;
  44236. }
  44237. return {
  44238. generate: generate
  44239. };
  44240. });
  44241. /**
  44242. * @fileOverview
  44243. *
  44244. * 通知小组件
  44245. *
  44246. * @author: techird
  44247. * @copyright: Baidu FEX, 2014
  44248. */
  44249. KityMinder.registerUI('widget/notice', function(minder) {
  44250. var errorMessage = minder.getLang('error_message');
  44251. var memory = minder.getUI('memory');
  44252. var $notice = $('<div>')
  44253. .addClass('notice-widget')
  44254. .appendTo('#content-wrapper');
  44255. var $mask = $('<div>')
  44256. .addClass('error-mask');
  44257. var $error = new FUI.Dialog({
  44258. width: 500,
  44259. height: 'auto',
  44260. prompt: true,
  44261. caption: errorMessage.title,
  44262. className: 'error-dialog'
  44263. }).appendTo(document.getElementById('content-wrapper'));
  44264. $error.on('ok cancel', function(e) {
  44265. if (error.resolve) error.resolve(e);
  44266. });
  44267. var $error_body = $($error.getBodyElement());
  44268. var isBuilded = (function() {
  44269. var scripts = [].slice.apply(document.getElementsByTagName('script'));
  44270. var s, m;
  44271. while ((s = scripts.pop())) {
  44272. if ((m = /kityminder.*\.min\.js/.exec(s.src))) return m[0];
  44273. }
  44274. return false;
  44275. })();
  44276. // concatMap: sperate files -> join file
  44277. // minMap: join file -> min file
  44278. var concatMap, minMap;
  44279. function fixSourceSymbol($ta, $mask) {
  44280. function fix() {
  44281. var text = $ta.text();
  44282. var pattern = new RegExp('at.+' + isBuilded + '.+\\:(\\d+)\\:(\\d+)\\)?', 'g');
  44283. var match;
  44284. $ta.text(text.replace(pattern, function(match, $1, $2) {
  44285. var lookup = {
  44286. line: +$1,
  44287. column: +$2
  44288. };
  44289. var info = minMap.originalPositionFor(lookup);
  44290. var name = info.name;
  44291. lookup = {
  44292. line: info.line,
  44293. column: info.column
  44294. };
  44295. info = concatMap.originalPositionFor(lookup);
  44296. name = name || '<Anonymous>';
  44297. var replaced = 'at ' + name + ' (' +
  44298. info.source.replace('../', '') + ':' + info.line + ':' + info.column + ')';
  44299. if (replaced.indexOf('promise') != -1) {
  44300. replaced = 'at <async> Promise.' + name;
  44301. }
  44302. return replaced;
  44303. }));
  44304. }
  44305. if (isBuilded) {
  44306. if (concatMap) return fix();
  44307. $mask.addClass('loading');
  44308. setTimeout(function() {
  44309. $mask.removeClass('loading');
  44310. }, 5000);
  44311. var script = document.createElement('script');
  44312. script.onload = function() {
  44313. Promise.all([
  44314. $.pajax({
  44315. url: isBuilded.replace('min.js', 'js.map'),
  44316. dataType: 'json'
  44317. }),
  44318. $.pajax({
  44319. url: isBuilded.replace('.js', '.map'),
  44320. dataType: 'json'
  44321. })
  44322. ]).then(function(files) {
  44323. concatMap = new window.sourceMap.SourceMapConsumer(files[0]);
  44324. minMap = new window.sourceMap.SourceMapConsumer(files[1]);
  44325. fix();
  44326. $mask.removeClass('loading');
  44327. });
  44328. };
  44329. script.src = 'lib/source-map.min.js';
  44330. document.head.appendChild(script);
  44331. }
  44332. }
  44333. $error_body.delegate('.error-detail a.expander', 'click', function(e) {
  44334. var $detail = $(e.target).closest('.error-detail').toggleClass('expanded');
  44335. var showDetail = $detail.hasClass('expanded');
  44336. memory.set('show-error-detail', showDetail);
  44337. });
  44338. function info(msg, warn, time) {
  44339. if (!$notice.hasClass('show')) $notice.empty();
  44340. clearTimeout(info.ttl2);
  44341. if (warn) $notice.addClass('warn');
  44342. else $notice.removeClass('warn');
  44343. var $menu = minder.getUI('menu/menu');
  44344. $notice.css({
  44345. top: $menu && $menu.isVisible() ?
  44346. $('#main-menu .main-menu-level1').offset().top :
  44347. $('#kityminder').offset().top + 20
  44348. });
  44349. $notice.append($('<p>').text(msg));
  44350. $notice.addClass('show');
  44351. clearTimeout(info.ttl);
  44352. time = time || (warn ? 5000 : 3000);
  44353. info.ttl = setTimeout(function() {
  44354. $notice.removeClass('show');
  44355. info.ttl2 = setTimeout(function() {
  44356. $notice.empty();
  44357. }, 1000);
  44358. }, time);
  44359. }
  44360. function warn(msg) {
  44361. info(msg, warn);
  44362. }
  44363. function descriptReason(e) {
  44364. e = e || new Error();
  44365. if (typeof(e) == 'string') {
  44366. e = new Error(e);
  44367. }
  44368. if (e.getDetail) return e;
  44369. // 文件访问错误
  44370. if (typeof(fio) != 'undefined' && (e instanceof fio.FileRequestError)) {
  44371. if (!e.status) {
  44372. e.description = errorMessage.err_network;
  44373. } else {
  44374. e.description = errorMessage.pcs_code[e.detail.error_code];
  44375. }
  44376. e.getDetail = function() {
  44377. return JSON.stringify(e, null, 4);
  44378. };
  44379. }
  44380. // jqXhr
  44381. else if ('readyState' in e) {
  44382. } else {
  44383. e.getDetail = function() {
  44384. return e.stack || new Error().stack;
  44385. };
  44386. }
  44387. return e;
  44388. }
  44389. function error(name, e) {
  44390. if (arguments.length == 1) {
  44391. e = name;
  44392. name = 'unknown';
  44393. }
  44394. $error_body.empty();
  44395. e = descriptReason(e);
  44396. var $content = $('<div>')
  44397. .addClass('error-content')
  44398. .appendTo($error_body);
  44399. var $msg = $('<h3>')
  44400. .text(errorMessage[name] || errorMessage.err_unknown)
  44401. .appendTo($content);
  44402. var $reason = $('<p>')
  44403. .text(e.message || e.description || errorMessage.unknownreason)
  44404. .appendTo($content);
  44405. if (e.getDetail) {
  44406. var $detail = $('<div>')
  44407. .addClass('error-detail')
  44408. .append($('<a class="expander"></a>').text(minder.getLang('ui.error_detail')))
  44409. .appendTo($error_body);
  44410. var $detailContent = $('<div>')
  44411. .addClass('error-detail-wrapper')
  44412. .appendTo($detail);
  44413. var $textarea = $('<textarea>')
  44414. .attr('id', 'error-detail-content')
  44415. .text(e.getDetail() + '\n\n浏览器信息:' + navigator.userAgent)
  44416. .appendTo($detailContent);
  44417. fixSourceSymbol($textarea, $detailContent);
  44418. var $copy = $('<button>')
  44419. .addClass('copy-and-feedback')
  44420. .text(minder.getLang('ui.copy_and_feedback'))
  44421. .appendTo($detailContent);
  44422. $copy.attr('data-clipboard-target', 'error-detail-content');
  44423. zeroCopy($copy);
  44424. if (memory.get('show-error-detail')) $detail.addClass('expanded');
  44425. }
  44426. $error.show();
  44427. $error.getElement().style.top = '180px';
  44428. return new Promise(function(resolve) {
  44429. error.resolve = resolve;
  44430. });
  44431. }
  44432. function zeroCopy($target) {
  44433. /* global ZeroClipboard:true */
  44434. if (window.ZeroClipboard) {
  44435. ZeroClipboard.config({
  44436. swfPath: 'lib/ZeroClipboard.swf',
  44437. hoverClass: 'hover',
  44438. activeClass: 'active'
  44439. });
  44440. var clip = new window.ZeroClipboard($target);
  44441. clip.on('ready', function() {
  44442. clip.on('aftercopy', function() {
  44443. $error.hide();
  44444. minder.getUI('topbar/feedback').click();
  44445. });
  44446. });
  44447. } else {
  44448. $target.remove();
  44449. }
  44450. }
  44451. return {
  44452. info: info,
  44453. error: error,
  44454. warn: warn
  44455. };
  44456. });
  44457. /**
  44458. * @fileOverview
  44459. *
  44460. * 渲染当前时间离指定时间的时长
  44461. *
  44462. * @author: techird
  44463. * @copyright: Baidu FEX, 2014
  44464. */
  44465. KityMinder.registerUI('widget/friendlytimespan', function(minder) {
  44466. $.extend($.fn, {
  44467. displayFriendlyTime: function(time) {
  44468. return this.each(function() {
  44469. display($(this)
  44470. .addClass('friendly-time')
  44471. .data('time', time));
  44472. });
  44473. }
  44474. });
  44475. function getTimeText(timeInMs) {
  44476. var ms = Math.abs(timeInMs - new Date()),
  44477. s = ms / 1000,
  44478. m = s / 60,
  44479. h = m / 60,
  44480. d = h / 24;
  44481. if (s < 60) return minder.getLang('ui.justnow', s | 0);
  44482. if (m < 60) return minder.getLang('ui.minutesago', m | 0);
  44483. if (h < 24) return minder.getLang('ui.hoursago', h | 0);
  44484. if (d < 2) return minder.getLang('ui.yesterday');
  44485. if (d <= 30) return minder.getLang('ui.daysago', d | 0);
  44486. return minder.getLang("ui.longago");
  44487. }
  44488. function display($element) {
  44489. $element.text(getTimeText($element.data('time')));
  44490. }
  44491. function update() {
  44492. $('.friendly-time').each(function() {
  44493. display($(this));
  44494. });
  44495. }
  44496. setInterval(update, 60000);
  44497. });
  44498. /**
  44499. * @fileOverview
  44500. *
  44501. * 提供存储在 LocalStorage 中的列表
  44502. *
  44503. * @author: techird
  44504. * @copyright: Baidu FEX, 2014
  44505. */
  44506. KityMinder.registerUI('widget/locallist', function() {
  44507. function LocalList(name, maxCount) {
  44508. var list;
  44509. maxCount = maxCount || 10;
  44510. function load() {
  44511. list = localStorage.getItem(name);
  44512. if (list) {
  44513. list = JSON.parse(list);
  44514. } else {
  44515. list = [];
  44516. }
  44517. this.length = list.length;
  44518. }
  44519. function save() {
  44520. while (list.length > maxCount) list.pop();
  44521. localStorage.setItem(name, JSON.stringify(list));
  44522. this.length = list.length;
  44523. }
  44524. function get(index) {
  44525. return list[index];
  44526. }
  44527. function remove(index) {
  44528. list.splice(index, 1);
  44529. save();
  44530. }
  44531. function clear() {
  44532. list = [];
  44533. save();
  44534. }
  44535. function unshift(item) {
  44536. list.unshift(item);
  44537. save();
  44538. }
  44539. function createKeyMatcher(key) {
  44540. return function(item, value) {
  44541. return item[key] == value;
  44542. };
  44543. }
  44544. function findIndex(matcher, value) {
  44545. if (typeof(matcher) == 'string') {
  44546. matcher = createKeyMatcher(matcher);
  44547. }
  44548. for (var i = 0; i < list.length; i++) {
  44549. if (matcher(list[i], value)) return i;
  44550. }
  44551. return -1;
  44552. }
  44553. function find(matcher, value) {
  44554. return get(findIndex(matcher, value));
  44555. }
  44556. function forEach(callback) {
  44557. list.forEach(callback);
  44558. save();
  44559. }
  44560. load.call(this);
  44561. this.get = get;
  44562. this.remove = remove;
  44563. this.findIndex = findIndex;
  44564. this.find = find;
  44565. this.forEach = forEach;
  44566. this.unshift = unshift;
  44567. this.clear = clear;
  44568. }
  44569. return {
  44570. use: function(name) {
  44571. return new LocalList(name);
  44572. }
  44573. };
  44574. });
  44575. /**
  44576. * @fileOverview
  44577. *
  44578. * 网盘的目录访问组件
  44579. *
  44580. * @author: techird
  44581. * @copyright: Baidu FEX, 2014
  44582. */
  44583. KityMinder.registerUI('widget/netdiskfinder', function(minder) {
  44584. var eve = minder.getUI('eve');
  44585. var notice = minder.getUI('widget/notice');
  44586. var recycleReady = null;
  44587. var base = '/apps/kityminder';
  44588. var recyclePath = base + '/.recycle';
  44589. var moveConfirm = true;
  44590. var instances = [];
  44591. var Finder = eve.setup({});
  44592. Finder.BASE_PATH = base + '/';
  44593. Finder.RECYCLE_PATH = recyclePath + '/';
  44594. Finder.on('mv', function(from, to, source) {
  44595. instances.forEach(function(instance) {
  44596. if (source != instance) instance.refresh();
  44597. });
  44598. });
  44599. /**
  44600. * 生成一个网盘的目录访问组件
  44601. *
  44602. * @param {JQueryObject} $container 容器
  44603. * @param {function} listFilter 一个函数,检查一个文件是否应该被列出
  44604. */
  44605. function generate($container, listFilter) {
  44606. var finder = eve.setup({});
  44607. instances.push(finder);
  44608. var currentPath = base;
  44609. var $finder = $('<div class="netdisk-finder"></div>').appendTo($container);
  44610. /* 顶部工具栏 */
  44611. var $headbar = $('<div class="head"></div>').appendTo($finder);
  44612. /* 控制按钮 */
  44613. var $control = $('<div class="control"></div>').appendTo($headbar);
  44614. var $mkdir = $('<a></a>')
  44615. .text(minder.getLang('ui.mkdir'))
  44616. .attr('title', minder.getLang('ui.mkdir'))
  44617. .addClass('button mkdir')
  44618. .appendTo($control)
  44619. .click(mkdir);
  44620. var $recycle = $('<a></a>')
  44621. .text(minder.getLang('ui.recycle'))
  44622. .attr('title', minder.getLang('ui.recycle'))
  44623. .addClass('button recycle dir')
  44624. .data('file', {
  44625. path: recyclePath,
  44626. filename: minder.getLang('ui.recycle')
  44627. })
  44628. .appendTo($control)
  44629. .click(recycle);
  44630. var $recycleClear = $('<a></a>')
  44631. .text(minder.getLang('ui.recycle_clear'))
  44632. .attr('title', minder.getLang('ui.recycle_clear'))
  44633. .addClass('button recycle-clear')
  44634. .appendTo($control)
  44635. .click(clearRecycle);
  44636. /* 路径导航 */
  44637. var $nav = $('<div class="nav"></div>').appendTo($headbar);
  44638. /* 显示当前目录文件列表 */
  44639. var $list = $('<ul class="file-list"></ul>')
  44640. .appendTo($finder);
  44641. var selected = null;
  44642. minder.on('uiready', function() {
  44643. var $user = minder.getUI('topbar/user');
  44644. $user.requireLogin($container);
  44645. fio.user.on('login', function() {
  44646. list();
  44647. });
  44648. });
  44649. handleClick();
  44650. handleDrag();
  44651. handleNav();
  44652. handleRename();
  44653. function handleRename() {
  44654. $list.delegate('.file-list-item a.rename-button', 'click', function(e) {
  44655. var $li = $(e.target).closest('li');
  44656. $li.find('span.filename').remove();
  44657. rename($li);
  44658. $li.addClass('renaming');
  44659. e.stopPropagation();
  44660. });
  44661. function rename($li) {
  44662. rename.onprogress = true;
  44663. var file = $li.data('file');
  44664. var $input = $('<input>')
  44665. .attr('type', 'text')
  44666. .addClass('new-dir-name fui-widget fui-selectable')
  44667. .val(file.filename)
  44668. .appendTo($li);
  44669. $li.removeAttr('draggable');
  44670. $input.on('keydown', function (e) {
  44671. if (e.keyCode == 13) return confirm();
  44672. if (e.keyCode == 27) {
  44673. e.stopPropagation();
  44674. return cancel();
  44675. }
  44676. }).on('blur', cancel);
  44677. $input.on('dragstart mousedown mouseup click dblclick', function(e) {
  44678. e.stopPropagation();
  44679. });
  44680. setTimeout(function() {
  44681. $input[0].select();
  44682. });
  44683. function reset(filename) {
  44684. $input.remove();
  44685. $li.find('.icon').after('<span class="filename">' + filename + '</span>');
  44686. $li.removeClass('renaming');
  44687. $li.attr('draggable', true);
  44688. }
  44689. function cancel() {
  44690. reset(file.filename);
  44691. }
  44692. function confirm() {
  44693. var newFilename = $input.val();
  44694. var newPath = file.parentPath + newFilename;
  44695. if (file.filename == newFilename) return cancel();
  44696. if (fio.file.anlysisPath(newFilename).extension != file.extension) {
  44697. $input.addClass('invalid-name');
  44698. setTimeout(function () {
  44699. $input.removeClass('invalid-name');
  44700. }, 500);
  44701. return $input.select();
  44702. }
  44703. $container.addClass('loading');
  44704. mv(file.path, newPath).then(function () {
  44705. var oldPath = file.path;
  44706. file.filename = newFilename;
  44707. file.path = newPath;
  44708. reset(newFilename);
  44709. Finder.fire('mv', oldPath, newPath, finder);
  44710. notice.info(minder.getLang('ui.rename_success', newFilename));
  44711. })['catch'](function(e) {
  44712. notice.error('err_rename', e);
  44713. cancel();
  44714. }).then(function() {
  44715. $container.removeClass('loading');
  44716. });
  44717. }
  44718. }
  44719. }
  44720. function handleClick() {
  44721. /* 点击目录中的项目时打开项目 */
  44722. $list.delegate('.file-list-item', 'dblclick', function(e) {
  44723. if (currentPath == recyclePath + '/') return;
  44724. if (mkdir.onprogress) return mkdir.onprogress.select();
  44725. var $file = $(e.target).closest('li'),
  44726. file = $file.data('file');
  44727. if (file) open(file);
  44728. });
  44729. $list.delegate('.file-list-item', 'mousedown', function(e) {
  44730. if (mkdir.onprogress) return mkdir.onprogress.select();
  44731. var $file = $(e.target).closest('li'),
  44732. file = $file.data('file');
  44733. if (!file) return;
  44734. select(file && file.path);
  44735. });
  44736. }
  44737. function handleNav() {
  44738. /* 点击导航处,切换路径 */
  44739. $nav.delegate('a', 'click', function(e) {
  44740. if (mkdir.onprogress) return mkdir.onprogress.select();
  44741. if ($(e.target).hasClass('dir-back')) {
  44742. var parts = currentPath.split('/');
  44743. parts.pop(); // 有一个无效部分
  44744. parts.pop();
  44745. return list(parts.join('/'));
  44746. }
  44747. list($(e.target).data('path'));
  44748. });
  44749. }
  44750. function handleDrag() {
  44751. var fileItemSelector = '.file-list-item';
  44752. var dirSelector = '.dir';
  44753. var $dragging = null;
  44754. $list.delegate(fileItemSelector, 'dragstart', itemDragStart)
  44755. .delegate(fileItemSelector, 'dragend', itemDragEnd)
  44756. .delegate(dirSelector, 'dragover', dragOver)
  44757. .delegate(dirSelector, 'dragenter', dirDragEnter)
  44758. .delegate(dirSelector, 'dragleave', dirDragLeave)
  44759. .delegate(dirSelector, 'drop', dirDrop);
  44760. $headbar.delegate(dirSelector, 'dragover', dragOver)
  44761. .delegate(dirSelector, 'dragenter', dirDragEnter)
  44762. .delegate(dirSelector, 'dragleave', dirDragLeave)
  44763. .delegate(dirSelector, 'drop', dirDrop);
  44764. $list.delegate(fileItemSelector + ' input', 'dragstart', function(e) {
  44765. e.stopPropagation();
  44766. e.preventDefault();
  44767. });
  44768. function itemDragStart(e) {
  44769. var $target = $(e.target);
  44770. if (!$target.hasClass('file-list-item')) {
  44771. return;
  44772. }
  44773. // e.originalEvent.dataTransfer.effectAllowed = "move";
  44774. // e.originalEvent.dataTransfer.dropEffect = 'move';
  44775. try {
  44776. var dataType = kity.Browser.ie && kity.Browser.version == 10 ? 'text' : 'text/plain';
  44777. e.originalEvent.dataTransfer.setData(dataType, 'FEX');
  44778. e.originalEvent.dataTransfer.setDragImage($target.find('.icon').get(0), 12, 12);
  44779. } catch (ignore) {}
  44780. $dragging = $target.addClass('dragging');
  44781. $finder.addClass('drop-mode');
  44782. }
  44783. function itemDragEnd(e) {
  44784. $(e.target).removeClass('dragging');
  44785. e.originalEvent.dataTransfer.dropEffect = 'move';
  44786. e.preventDefault();
  44787. $finder.removeClass('drop-mode');
  44788. }
  44789. function dragOver(e) {
  44790. if ($(e.target).hasClass('filename')) e.preventDefault();
  44791. }
  44792. function dirDragEnter(e) {
  44793. var $target = $(e.target).closest('.dir');
  44794. $target.addClass('drag-enter');
  44795. if (e.target != $target[0]) $target.addClass('enter-child');
  44796. }
  44797. function dirDragLeave(e) {
  44798. if ($(e.target).hasClass('dir')) {
  44799. if ($(e.target).hasClass('enter-child')) {
  44800. return $(e.target).removeClass('enter-child');
  44801. }
  44802. $(e.target).removeClass('drag-enter');
  44803. }
  44804. }
  44805. function dirDrop(e) {
  44806. e.preventDefault();
  44807. var $target = $(e.target).closest('.dir').removeClass('drag-enter');
  44808. if (!$target.hasClass('dir')) return;
  44809. var source = $dragging.data('file');
  44810. var destination = $target.data('file');
  44811. var destinationPath = destination.path + '/' + source.filename;
  44812. var sourcePath = source.path;
  44813. if (destinationPath.indexOf(sourcePath) === 0) return;
  44814. if (!moveConfirm || window.confirm(minder.getLang('ui.move_file_confirm', source.filename, destination.filename))) {
  44815. $container.addClass('loading');
  44816. recycleReady.then(doMove);
  44817. moveConfirm = false;
  44818. }
  44819. function doMove() {
  44820. mv(sourcePath, destinationPath).then(function() {
  44821. $dragging.remove();
  44822. Finder.fire('mv', sourcePath, destinationPath, finder);
  44823. notice.info(minder.getLang('ui.move_success', source.filename, destination.filename));
  44824. })['catch'](function(e) {
  44825. notice.error('err_move_file', e);
  44826. }).then(function() {
  44827. $container.removeClass('loading');
  44828. });
  44829. }
  44830. }
  44831. }
  44832. function recycle() {
  44833. list(recyclePath);
  44834. }
  44835. function createRecycleBin() {
  44836. return fio.file.mkdir({
  44837. path: recyclePath
  44838. });
  44839. }
  44840. function clearRecycle() {
  44841. if (!window.confirm(minder.getLang('ui.recycle_clear_confirm'))) return;
  44842. $container.addClass('loading');
  44843. fio.file['delete']({
  44844. path: recyclePath
  44845. }).then(function() {
  44846. return recycleReady = createRecycleBin();
  44847. }).then(function() {
  44848. renderList([]);
  44849. $container.removeClass('loading');
  44850. });
  44851. }
  44852. function mv(source, destination) {
  44853. return fio.file.move({
  44854. path: source,
  44855. newPath: destination,
  44856. ondup: destination.indexOf(recyclePath) === 0 ? fio.file.DUP_RENAME : fio.file.DUP_FAIL
  44857. });
  44858. }
  44859. function mkdir() {
  44860. if (mkdir.onprogress) {
  44861. return mkdir.onprogress.select();
  44862. }
  44863. var $li = $('<li>').addClass('file-list-item dir').prependTo($list);
  44864. $li.append('<span class="icon"></span>');
  44865. var $input = $('<input>')
  44866. .attr('type', 'text')
  44867. .addClass('new-dir-name fui-widget fui-selectable')
  44868. .val(minder.getLang('ui.newdir'))
  44869. .appendTo($li);
  44870. mkdir.onprogress = $input[0];
  44871. $input[0].select();
  44872. $input.on('keydown', function(e) {
  44873. if (e.keyCode == 13) confirm();
  44874. if (e.keyCode == 27) {
  44875. cancel();
  44876. e.stopPropagation();
  44877. }
  44878. }).on('blur', confirm);
  44879. function cancel() {
  44880. $li.remove();
  44881. mkdir.onprogress = false;
  44882. }
  44883. function confirm() {
  44884. var name = $input.val();
  44885. if (name) {
  44886. $container.addClass('loading');
  44887. fio.file.mkdir({
  44888. path: currentPath + name
  44889. }).then(function() {
  44890. return new Promise(function(resolve) {
  44891. setTimeout(function() {
  44892. resolve(refresh());
  44893. }, 200);
  44894. });
  44895. }, function(e) {
  44896. if (e.detail && e.detail.error_code == 31061) {
  44897. e.message = '已存在同名目录';
  44898. }
  44899. var notice = minder.getUI('widget/notice');
  44900. notice.error('err_mkdir', e);
  44901. $li.remove();
  44902. }).then(function() {
  44903. $container.removeClass('loading');
  44904. mkdir.onprogress = false;
  44905. });
  44906. }
  44907. }
  44908. }
  44909. /**
  44910. * 返回数值的符号:
  44911. * 正数 => 1
  44912. * 0 => 0
  44913. * 负数 => -1
  44914. */
  44915. function sign(num) {
  44916. return num > 0 ? 1 : (num < 0 ? -1 : 0);
  44917. }
  44918. /**
  44919. * 打开选中的文件或目录
  44920. *
  44921. * @param {fio.file.File} file
  44922. */
  44923. function open(file) {
  44924. if (file.isDir) return list(file.path);
  44925. finder.fire('fileclick', file);
  44926. }
  44927. function fadeOutList(x) {
  44928. return new Promise(function(resolve, reject) {
  44929. $list.transit({
  44930. x: x,
  44931. opacity: 0
  44932. }, 100, resolve);
  44933. });
  44934. }
  44935. function fadeInList() {
  44936. return new Promise(function(resolve) {
  44937. $list.css({
  44938. x: -parseInt($list.css('x'))
  44939. }).stop().transit({
  44940. x: 0,
  44941. opacity: 1
  44942. }, 100, resolve);
  44943. });
  44944. }
  44945. function refresh() {
  44946. return list(currentPath, true);
  44947. }
  44948. /**
  44949. * 列出指定目录的文件
  44950. */
  44951. function list(path, noAnimate) {
  44952. path = path || base;
  44953. var listPromise = fio.file.list({
  44954. path: path
  44955. });
  44956. var transitPromise = noAnimate ? Promise.resolve() : fadeOutList(-100 * sign(path.length - currentPath.length));
  44957. currentPath = path.charAt(path.length - 1) == '/' ? path : path + '/';
  44958. updateNav();
  44959. function checkRecycleBin(files) {
  44960. if (!recycleReady && path == base) {
  44961. for (var i = 0; i < files.length; i++) {
  44962. if (files[i].path == recyclePath) {
  44963. recycleReady = Promise.resolve(true);
  44964. }
  44965. break;
  44966. }
  44967. recycleReady = recycleReady || createRecycleBin();
  44968. }
  44969. }
  44970. return Promise.all([listPromise, transitPromise]).then(function(values) {
  44971. var files = values[0];
  44972. checkRecycleBin(files);
  44973. return renderList(files);
  44974. }, function(error) {
  44975. var notice = minder.getUI('widget/notice');
  44976. notice.error('err_ls', error);
  44977. });
  44978. }
  44979. function renderFileList(files) {
  44980. $list.empty();
  44981. if (!files.length) {
  44982. $list.append('<li class="empty" disabled="disabled">' + minder.getLang('ui.emptydir') + '</li>');
  44983. } else {
  44984. files.forEach(function(file) {
  44985. if (!file.isDir && (!listFilter || !listFilter(file))) return;
  44986. if (file.path == recyclePath) return;
  44987. $('<li></li>')
  44988. .append('<span class="icon"></span>')
  44989. .append('<span class="filename">' + file.filename + '</span>')
  44990. .append('<a class="rename-button" title="' + minder.getLang('ui.rename') + '">"' + minder.getLang('ui.rename') + '"</a>')
  44991. .addClass('file-list-item')
  44992. .addClass(file.isDir ? 'dir' : 'file')
  44993. .data('file', file)
  44994. .attr('draggable', true)
  44995. .appendTo($list);
  44996. });
  44997. }
  44998. }
  44999. finder._renderFileList = renderFileList;
  45000. function renderList(files) {
  45001. files.sort(function(a, b) {
  45002. if (a.isDir > b.isDir) {
  45003. return -1;
  45004. } else if (a.isDir == b.isDir) {
  45005. return a.createTime > b.createTime ? -1 : 1;
  45006. } else return 1;
  45007. });
  45008. renderFileList(files);
  45009. // 通知其他 finder 更新
  45010. instances.forEach(function(instance) {
  45011. if (instance == finder) return;
  45012. if (instance.pwd() == currentPath)
  45013. instance._renderFileList(files);
  45014. });
  45015. fadeInList();
  45016. checkSelect();
  45017. finder.fire('cd', currentPath);
  45018. }
  45019. function updateNav() {
  45020. $nav.empty();
  45021. if (currentPath != base && currentPath != base + '/') {
  45022. $nav.append('<a class="dir-back">Back</a>');
  45023. } else {
  45024. $nav.append('<span class="my-document"></span>');
  45025. }
  45026. var path = currentPath.substr(base.length);
  45027. var parts = path.split('/');
  45028. var processPath = '';
  45029. function pathButton(part) {
  45030. processPath += part + '/';
  45031. var $a = $('<a></a>').addClass('dir');
  45032. if (part == base) {
  45033. $a.text(minder.getLang('ui.mydocument'));
  45034. } else if (part == '.recycle') {
  45035. $a.text(minder.getLang('ui.recycle'));
  45036. $finder.addClass('recycle-bin');
  45037. } else {
  45038. $a.text(part);
  45039. }
  45040. return $a.data('path', processPath).data('file', {
  45041. path: processPath.substr(0, processPath.length - 1),
  45042. filename: part == base ? minder.getLang('ui.mydocument') : part
  45043. });
  45044. }
  45045. $finder.removeClass('recycle-bin');
  45046. $nav.append(pathButton(base));
  45047. parts.forEach(function(part) {
  45048. if (!part) return;
  45049. $nav.append('<span class="spliter"></span>');
  45050. $nav.append(pathButton(part));
  45051. });
  45052. }
  45053. function select(path) {
  45054. selected = path;
  45055. return checkSelect();
  45056. }
  45057. function checkSelect() {
  45058. var hasSelect = false;
  45059. $list.find('.file-list-item').removeClass('selected').each(function() {
  45060. var file = $(this).data('file');
  45061. if (file && file.path == selected) {
  45062. $(this).addClass('selected');
  45063. hasSelect = true;
  45064. $list[0].focus();
  45065. finder.fire('select', file, this);
  45066. }
  45067. });
  45068. if (!hasSelect) selected = false;
  45069. return hasSelect;
  45070. }
  45071. function pwd() {
  45072. return currentPath;
  45073. }
  45074. finder.list = list;
  45075. finder.select = select;
  45076. finder.pwd = pwd;
  45077. finder.refresh = refresh;
  45078. return finder;
  45079. }
  45080. Finder.generate = generate;
  45081. return Finder;
  45082. });
  45083. /**
  45084. * @fileOverview
  45085. *
  45086. * 用 FUI.Tabs 实现的多级的创建
  45087. *
  45088. * @author: techird
  45089. * @copyright: Baidu FEX, 2014
  45090. */
  45091. KM.registerUI('widget/menutab', function(minder) {
  45092. function generate(parent, name, asDefault) {
  45093. var index = parent.getButtons().length;
  45094. var tab = parent.appendTab({
  45095. buttons: [{
  45096. label: minder.getLang('ui.menu.' + name + 'tab'),
  45097. className: 'tab-' + name
  45098. }]
  45099. });
  45100. if (asDefault) {
  45101. parent.select(index);
  45102. }
  45103. return tab[0].panel.getContentElement();
  45104. }
  45105. return {
  45106. generate: generate
  45107. };
  45108. });
  45109. /**
  45110. * @fileOverview
  45111. *
  45112. * 当前文档管理
  45113. *
  45114. * @author: techird
  45115. * @copyright: Baidu FEX, 2014
  45116. */
  45117. KityMinder.registerUI('doc', function(minder) {
  45118. var ret = minder.getUI('eve').setup({});
  45119. var current = { saved: true };
  45120. var loading = false;
  45121. var notice = minder.getUI('widget/notice');
  45122. var finder = minder.getUI('widget/netdiskfinder');
  45123. if (finder) finder.on('mv', trackFileMove);
  45124. function trackFileMove(from, to) {
  45125. if (current.source != 'netdisk') return;
  45126. var fromPath = from.split('/');
  45127. var toPath = to.split('/');
  45128. function preCommonLength(a, b) {
  45129. var i = 0;
  45130. while ((i in a) && (i in b) && a[i] == b[i]) i++;
  45131. return (i in b) ? 0 : i;
  45132. }
  45133. var originPath = current.path.split('/');
  45134. var clen = preCommonLength(originPath, fromPath);
  45135. if (clen) {
  45136. var movedPath = toPath.concat(originPath.slice(clen));
  45137. current.path = movedPath.join('/');
  45138. current.title = movedPath.pop();
  45139. ret.fire('docchange', current);
  45140. }
  45141. }
  45142. var locked = false;
  45143. ret.lock = function() { locked = true; };
  45144. ret.unlock = function() { locked = false; };
  45145. /**
  45146. * 加载文档
  45147. *
  45148. * @param {Object} doc 文档的属性,可包括:
  45149. * doc.content {string} [Required] 文档内容
  45150. * doc.protocol {string} [Required] 内容所使用的编码协议
  45151. * doc.title {string} 文档的标题
  45152. * doc.source {string} 文档的来源
  45153. * doc.path {string} 文档的路径
  45154. * doc.saved {bool} 文档的保存状态
  45155. *
  45156. * @event docload(doc)
  45157. * doc - 文档解析之后的文档对象
  45158. *
  45159. * @return {Promise<doc>} 返回解析完之后的文档对象,解析的结果为 doc.data
  45160. */
  45161. function load(doc) {
  45162. if (locked) return Promise.reject(new Error('doc was locked'));
  45163. var restore = doc;
  45164. current = doc;
  45165. loading = true;
  45166. return minder.importData(doc.content, doc.protocol).then(function(data) {
  45167. doc.title = doc.title || minder.getMinderTitle();
  45168. minder.execCommand('camera', minder.getRoot(), 300);
  45169. doc.data = data;
  45170. doc.json = JSON.stringify(data);
  45171. ret.fire('docload', doc);
  45172. ret.fire('docchange', doc);
  45173. return doc;
  45174. })['catch'](function(e) {
  45175. current = restore;
  45176. notice.error('err_doc_resolve', e);
  45177. }).then(function(doc) {
  45178. loading = false;
  45179. if (doc)
  45180. notice.info(minder.getLang('ui.load_success', doc.title));
  45181. return doc;
  45182. });
  45183. }
  45184. function save(doc) {
  45185. current = doc;
  45186. doc.data = minder.exportJson();
  45187. doc.json = JSON.stringify(doc.data);
  45188. doc.saved = true;
  45189. ret.fire('docsave', doc);
  45190. ret.fire('docchange', doc);
  45191. }
  45192. function getCurrent() {
  45193. return current;
  45194. }
  45195. function checkSaved(noConfirm) {
  45196. if (!fio.user.current()) return true;
  45197. if (locked) return false;
  45198. if (noConfirm) return current.saved;
  45199. return current.saved || window.confirm(minder.getLang('ui.unsavedcontent', '* ' + current.title));
  45200. }
  45201. /* 绕开初始化时候的乱事件 */
  45202. setTimeout(function() {
  45203. minder.on('contentchange', function() {
  45204. if (loading) return;
  45205. if (current.source != 'netdisk') {
  45206. current.title = minder.getMinderTitle();
  45207. current.saved = false;
  45208. } else {
  45209. current.saved = current.json == JSON.stringify(minder.exportJson());
  45210. }
  45211. ret.fire('docchange', current);
  45212. });
  45213. }, 1000);
  45214. ret.load = load;
  45215. ret.save = save;
  45216. ret.current = getCurrent;
  45217. ret.checkSaved = checkSaved;
  45218. return ret;
  45219. });
  45220. /**
  45221. * @fileOverview
  45222. *
  45223. *
  45224. *
  45225. * @author: techird
  45226. * @copyright: Baidu FEX, 2014
  45227. */
  45228. KityMinder.registerUI('contextmenu', function(minder) {
  45229. var mac = kity.Browser.mac;
  45230. function camel(word) {
  45231. return word.charAt(0).toUpperCase() + word.substr(1).toLowerCase();
  45232. }
  45233. var $menu = $('<ul>')
  45234. .addClass('km-context-menu fui-popup-menu')
  45235. .appendTo('#content-wrapper');
  45236. var downPosition;
  45237. function distance(p1, p2) {
  45238. var dx = p1[0] - p2[0];
  45239. var dy = p1[1] - p2[1];
  45240. var ds = Math.sqrt(dx * dx + dy * dy);
  45241. return ds;
  45242. }
  45243. $menu.delegate('li', 'mousedown', function(e, info) {
  45244. var item = $(e.target).closest('li').data('menu');
  45245. if (item.fn) {
  45246. return item.fn.call(minder, minder);
  45247. }
  45248. if (item.command) {
  45249. return minder.execCommand(item.command);
  45250. }
  45251. });
  45252. $('#content-wrapper').on('contextmenu', function(e) {
  45253. e.preventDefault();
  45254. });
  45255. $('#content-wrapper').on('mousedown', function(e) {
  45256. $menu.hide();
  45257. if (e.button == 2) {
  45258. downPosition = [e.pageX, e.pageY];
  45259. } else {
  45260. downPosition = null;
  45261. }
  45262. });
  45263. minder.on('mouseup', function(e) {
  45264. //e.preventDefault();
  45265. if (!e.isRightMB()) return;
  45266. e = e.originEvent;
  45267. var d = distance(downPosition, [e.pageX, e.pageY]);
  45268. if (isNaN(d) || d > 5) return;
  45269. $menu.empty();
  45270. var ctxmenu = minder.getContextMenu();
  45271. var lastDivider = true;
  45272. ctxmenu.forEach(function(item) {
  45273. var query = item.query || function() {
  45274. return item.command && minder.queryCommandState(item.command) === 0;
  45275. };
  45276. if (query()) {
  45277. var label = minder.getLang('ui.command.' + item.command);
  45278. var $li = $('<li>')
  45279. .addClass('fui-item')
  45280. .data('menu', item)
  45281. .appendTo($menu);
  45282. var shortcuts = minder.getCommandShortcutKey(item.command);
  45283. if (shortcuts) {
  45284. shortcuts.split('|').forEach(function(shortcut) {
  45285. var $shortcut = $('<span>').addClass('shortcut').appendTo($li);
  45286. shortcut.split('+').forEach(function(key) {
  45287. var parts = key.split('::');
  45288. key = parts.length > 1 ? parts[1] : parts[0];
  45289. $('<span>').addClass('shortcut-key ' + key.toLowerCase())
  45290. .text(camel(key))
  45291. .appendTo($shortcut);
  45292. });
  45293. if (mac) $shortcut.addClass('mac');
  45294. });
  45295. }
  45296. $li.append($('<div>').text(label).addClass('menu-label'));
  45297. lastDivider = false;
  45298. }
  45299. if (item.divider && !lastDivider) {
  45300. $('<li>').addClass('divider').appendTo($menu);
  45301. lastDivider = true;
  45302. }
  45303. });
  45304. if (ctxmenu.length) {
  45305. $menu.show();
  45306. var x = e.pageX,
  45307. y = e.pageY,
  45308. width = $menu.outerWidth(),
  45309. height = $menu.outerHeight(),
  45310. clientWidth = document.body.clientWidth,
  45311. clientHeight = document.body.clientHeight;
  45312. if (x + width > clientWidth) x -= width;
  45313. if (y + height > clientHeight) y -= height;
  45314. $menu.offset({
  45315. left: x,
  45316. top: y
  45317. });
  45318. }
  45319. });
  45320. });
  45321. /**
  45322. * @fileOverview
  45323. *
  45324. * 脑图缩略图导航功能
  45325. *
  45326. * @author: techird
  45327. * @copyright: Baidu FEX, 2014
  45328. */
  45329. KityMinder.registerUI('nav', function(minder) {
  45330. var memory = minder.getUI('memory');
  45331. var $navBar = $('<div>').addClass('nav-bar').appendTo('#content-wrapper');
  45332. var $commandbutton = minder.getUI('widget/commandbutton');
  45333. var $zoomIn = $commandbutton.generate('zoom-in').appendTo($navBar[0]);
  45334. var $zoomPan = createZoomPan($navBar);
  45335. var $zoomOut = $commandbutton.generate('zoom-out').appendTo($navBar[0]);
  45336. var $previewNavigator = createViewNavigator();
  45337. var $hand = $commandbutton.generate('hand').appendTo($navBar[0]);
  45338. var $root = $commandbutton.generate('camera', function() {
  45339. minder.execCommand('camera', minder.getRoot(), 600);
  45340. }).appendTo($navBar[0]);
  45341. var $previewTrigger = createPreviewTrigger($previewNavigator).appendTo($navBar);
  45342. function createZoomPan($parent) {
  45343. var $pan = $('<div>').addClass('zoom-pan').appendTo($parent);
  45344. var zoomStack = minder.getOptions('zoom');
  45345. var minValue = zoomStack[0];
  45346. var maxValue = zoomStack[zoomStack.length - 1];
  45347. var valueRange = maxValue - minValue;
  45348. var totalHeight = $pan.height();
  45349. function getHeight(value) {
  45350. return (1 - (value - minValue) / valueRange) * totalHeight;
  45351. }
  45352. var $origin = $('<div>')
  45353. .addClass('origin')
  45354. .appendTo($pan)
  45355. .css('y', getHeight(100));
  45356. var $indicator = $('<div>')
  45357. .addClass('indicator')
  45358. .appendTo($pan)
  45359. .css('y', getHeight(100));
  45360. function indicate(value) {
  45361. $indicator.animate({
  45362. 'y': getHeight(value)
  45363. }, 200);
  45364. }
  45365. minder.on('zoom', function(e) {
  45366. indicate(e.zoom);
  45367. });
  45368. $origin.click(function() {
  45369. minder.execCommand('zoom', 100);
  45370. });
  45371. return $pan;
  45372. }
  45373. /**
  45374. * 创建导航器的 DOM 元素以及交互的逻辑代码
  45375. */
  45376. function createViewNavigator() {
  45377. var $previewNavigator = $('<div>')
  45378. .addClass('preview-navigator')
  45379. .appendTo('#content-wrapper');
  45380. // 画布,渲染缩略图
  45381. var paper = new kity.Paper($previewNavigator[0]);
  45382. // 用两个路径来挥之节点和连线的缩略图
  45383. var nodeThumb = paper.put(new kity.Path());
  45384. var connectionThumb = paper.put(new kity.Path());
  45385. // 表示可视区域的矩形
  45386. var visibleRect = paper.put(new kity.Rect(100, 100).stroke('red', '1%'));
  45387. var contentView = new kity.Box(), visibleView = new kity.Box();
  45388. navigate();
  45389. $previewNavigator.show = function() {
  45390. $.fn.show.call(this);
  45391. bind();
  45392. updateContentView();
  45393. updateVisibleView();
  45394. };
  45395. $previewNavigator.hide = function() {
  45396. $.fn.hide.call(this);
  45397. unbind();
  45398. };
  45399. function bind() {
  45400. minder.on('layout layoutallfinish', updateContentView);
  45401. minder.on('viewchange', updateVisibleView);
  45402. }
  45403. function unbind() {
  45404. minder.off('layout layoutallfinish', updateContentView);
  45405. minder.off('viewchange', updateVisibleView);
  45406. }
  45407. window.u = updateContentView;
  45408. function navigate() {
  45409. function moveView(center, duration) {
  45410. var box = visibleView;
  45411. center.x = -center.x;
  45412. center.y = -center.y;
  45413. var viewMatrix = minder.getPaper().getViewPortMatrix();
  45414. box = viewMatrix.transformBox(box);
  45415. var targetPosition = center.offset(box.width / 2, box.height / 2);
  45416. minder.getViewDragger().moveTo(targetPosition, duration);
  45417. }
  45418. var dragging = false;
  45419. paper.on('mousedown', function(e) {
  45420. dragging = true;
  45421. moveView(e.getPosition('top'), 200);
  45422. $previewNavigator.addClass('grab');
  45423. });
  45424. paper.on('mousemove', function(e) {
  45425. if (dragging) {
  45426. moveView(e.getPosition('top'));
  45427. }
  45428. });
  45429. $(window).on('mouseup', function() {
  45430. dragging = false;
  45431. $previewNavigator.removeClass('grab');
  45432. });
  45433. }
  45434. function updateContentView() {
  45435. var view = minder.getRenderContainer().getBoundaryBox();
  45436. contentView = view;
  45437. var padding = 30;
  45438. paper.setViewBox(
  45439. view.x - padding - 0.5,
  45440. view.y - padding - 0.5,
  45441. view.width + padding * 2 + 1,
  45442. view.height + padding * 2 + 1);
  45443. var nodePathData = [];
  45444. var connectionThumbData = [];
  45445. minder.getRoot().traverse(function(node) {
  45446. var box = node.getLayoutBox();
  45447. nodePathData.push('M', box.x, box.y,
  45448. 'h', box.width, 'v', box.height,
  45449. 'h', -box.width, 'z');
  45450. if (node.getConnection() && node.parent && node.parent.isExpanded()) {
  45451. connectionThumbData.push(node.getConnection().getPathData());
  45452. }
  45453. });
  45454. paper.setStyle('background', minder.getStyle('background'));
  45455. if (nodePathData.length) {
  45456. nodeThumb
  45457. .fill(minder.getStyle('root-background'))
  45458. .setPathData(nodePathData);
  45459. } else {
  45460. nodeThumb.setPathData(null);
  45461. }
  45462. if (connectionThumbData.length) {
  45463. connectionThumb
  45464. .stroke(minder.getStyle('connect-color'), '0.5%')
  45465. .setPathData(connectionThumbData);
  45466. } else {
  45467. connectionThumb.setPathData(null);
  45468. }
  45469. updateVisibleView();
  45470. }
  45471. function updateVisibleView() {
  45472. visibleView = minder.getViewDragger().getView();
  45473. visibleRect.setBox(visibleView.intersect(contentView));
  45474. }
  45475. return $previewNavigator;
  45476. }
  45477. function createPreviewTrigger($previewNavigator) {
  45478. var $trigger = $('<div>').addClass('command-button nav-trigger');
  45479. $trigger.append('<div class="fui-icon">');
  45480. $trigger.click(toggle);
  45481. $trigger.attr('title', minder.getLang('ui.navigator'));
  45482. function toggle() {
  45483. if ($trigger.toggleClass('active').hasClass('active')) {
  45484. $previewNavigator.show();
  45485. memory.set('navigator-hidden', false);
  45486. } else {
  45487. $previewNavigator.hide();
  45488. memory.set('navigator-hidden', true);
  45489. }
  45490. }
  45491. if (memory.get('navigator-hidden')) toggle();
  45492. toggle();
  45493. return $trigger;
  45494. }
  45495. });
  45496. /**
  45497. * @fileOverview
  45498. *
  45499. * 搜索节点功能
  45500. *
  45501. * @author: yangxiaohu
  45502. * @copyright: Baidu FEX, 2014
  45503. */
  45504. KityMinder.registerUI('topbar/moreservice', function(minder) {
  45505. var $service;
  45506. var $link = $('<link>').attr('href', "http://baiduoffice.duapp.com/public/assets/style/moreService.css").attr('rel', "stylesheet");
  45507. $('head').append($link);
  45508. $.getScript('http://baiduoffice.duapp.com/public/widget/moreService.js', startService);
  45509. $service = $('<div id="moreservice"></div>');
  45510. function startService(){
  45511. $service.prependTo('#panel').moreService({button: {float: 'left', width: '40px', height: '40px', 'border-right': '1px solid rgba(255, 255, 255, .5)'}});
  45512. };
  45513. return $service;
  45514. });
  45515. /**
  45516. * @fileOverview
  45517. *
  45518. * 主菜单控制
  45519. *
  45520. * @author: techird
  45521. * @copyright: Baidu FEX, 2014
  45522. */
  45523. KityMinder.registerUI('menu/menu', function(minder) {
  45524. var ret = minder.getUI('eve').setup({});
  45525. var $menutab = minder.getUI('widget/menutab');
  45526. // 主菜单容器
  45527. var $panel = $('<div>')
  45528. .attr('id', 'main-menu')
  45529. .css('display', 'none')
  45530. .appendTo('#content-wrapper');
  45531. // 主菜单按钮
  45532. var $button = new FUI.Button({
  45533. id: 'main-menu-btn',
  45534. label: minder.getLang('ui.menu.mainmenutext')
  45535. }).appendTo(document.getElementById('panel'));
  45536. // 一级菜单选项卡
  45537. var $tabs = new FUI.Tabs({
  45538. className: 'main-menu-level1'
  45539. }).appendTo($panel[0]);
  45540. var timer;
  45541. function show() {
  45542. $panel.css('display', 'block');
  45543. clearTimeout(timer);
  45544. timer = setTimeout(function() {
  45545. $panel.addClass('show');
  45546. ret.fire('show');
  45547. });
  45548. }
  45549. function hide() {
  45550. ret.fire('hide');
  45551. $panel.removeClass('show');
  45552. minder.getRenderTarget().focus();
  45553. timer = setTimeout(function() {
  45554. $panel.css('display', 'none');
  45555. });
  45556. }
  45557. function isVisible() {
  45558. return $panel.hasClass('show');
  45559. }
  45560. function toggle() {
  45561. if ($('#content-wrapper').hasClass('fullscreen')) return;
  45562. (isVisible() ? hide : show)();
  45563. }
  45564. function createSub(name, asDefault) {
  45565. var $sub = $menutab.generate($tabs, name, asDefault);
  45566. var $h2 = $('<h2></h2>')
  45567. .text(minder.getLang('ui.menu.' + name + 'header'))
  45568. .appendTo($sub);
  45569. return $sub;
  45570. }
  45571. function createSubMenu(name, asDefault) {
  45572. var $sub = createSub(name, asDefault);
  45573. var $subtabs = new FUI.Tabs().appendTo($sub);
  45574. return {
  45575. $tabs: $subtabs,
  45576. createSub: function(subname, asDefault) {
  45577. return $menutab.generate($subtabs, subname, asDefault);
  45578. }
  45579. };
  45580. }
  45581. $button.on('click', toggle);
  45582. minder.addShortcut('esc', toggle);
  45583. // expose
  45584. ret.show = show;
  45585. ret.hide = hide;
  45586. ret.toggle = toggle;
  45587. ret.isVisible = isVisible;
  45588. ret.createSub = createSub;
  45589. ret.createSubMenu = createSubMenu;
  45590. ret.$panel = $panel;
  45591. ret.$button = $button;
  45592. ret.$tabs = $tabs;
  45593. return ret;
  45594. });
  45595. /**
  45596. * @fileOverview
  45597. *
  45598. * 菜单头部
  45599. *
  45600. * @author: techird
  45601. * @copyright: Baidu FEX, 2014
  45602. */
  45603. KityMinder.registerUI('menu/header', function(minder) {
  45604. var $menu = minder.getUI('menu/menu');
  45605. var $header = $('<div class="main-menu-header"></div>')
  45606. .prependTo($menu.$panel);
  45607. var $backPanel = $('<div class="main-menu-back-panel"></div>')
  45608. .appendTo($header);
  45609. var $titlePanel = $('<div class="main-menu-title">众核脑图</div>')
  45610. .appendTo($header);
  45611. var $backButton = new FUI.Button({
  45612. className: 'main-menu-back-button',
  45613. label: minder.getLang('ui.back')
  45614. }).appendTo($backPanel[0]).on('click', $menu.hide);
  45615. $menu.on('show', function() {
  45616. var $title = minder.getUI('topbar/title');
  45617. $titlePanel.text($title.getTitle());
  45618. });
  45619. return $header;
  45620. });
  45621. /**
  45622. * @fileOverview
  45623. *
  45624. * 菜单默认选择项目
  45625. *
  45626. * @author: techird
  45627. * @copyright: Baidu FEX, 2014
  45628. */
  45629. KityMinder.registerUI('menu/default', function(minder) {
  45630. minder.on('uiready', function() {
  45631. var $menu = minder.getUI('menu/menu');
  45632. var $open = minder.getUI('menu/open/open');
  45633. var $recent = minder.getUI('menu/open/recent');
  45634. var $save = minder.getUI('menu/save/save');
  45635. var $share = minder.getUI('menu/share/share');
  45636. var $draft = minder.getUI('menu/open/draft');
  45637. setMenuDefaults();
  45638. // $menu.show();
  45639. // $menu.$tabs.select(1);
  45640. // $open.$tabs.select(1);
  45641. // return;
  45642. loadLandingFile();
  45643. function setMenuDefaults() {
  45644. // 主菜单默认选中「打开」
  45645. $menu.$tabs.select(1);
  45646. // 打开菜单默认选中「本地文件」
  45647. $open.$tabs.select(2);
  45648. // 保存菜单默认选中「导出到本地」
  45649. $save.$tabs.select(1);
  45650. // 如果用户登陆了,选中「百度云存储」
  45651. fio.user.check().then(function(user) {
  45652. if (user) {
  45653. $save.$tabs.select(0);
  45654. }
  45655. });
  45656. $share.$menu.$tabs.select(0); // 当前脑图
  45657. }
  45658. function loadLandingFile() {
  45659. var pattern = /(?:shareId|share_id)=(\w+)([&#]|$)/;
  45660. var match = pattern.exec(window.location) || pattern.exec(document.referrer);
  45661. if (match) {
  45662. return $share.loadShareFile();
  45663. }
  45664. // 检查登录状态
  45665. fio.user.check().then(function(user) {
  45666. var draft = $draft.last();
  45667. var recent = $recent.last();
  45668. // 登录
  45669. if (user) {
  45670. if (recent) {
  45671. if (draft) {
  45672. if (recent.time > draft.time) openRecent();
  45673. else openDraft();
  45674. } else {
  45675. openRecent();
  45676. }
  45677. } else {
  45678. if (draft) openDraft();
  45679. else $open.$tabs.select(1); // locale netdisk
  45680. }
  45681. } else {
  45682. if (draft) openDraft();
  45683. else $open.$tabs.select(2); // locale local
  45684. }
  45685. function openDraft() {
  45686. $open.$tabs.select(3);
  45687. $draft.openLast();
  45688. }
  45689. function openRecent() {
  45690. $open.$tabs.select(0);
  45691. $recent.loadLast();
  45692. }
  45693. });
  45694. }
  45695. });
  45696. });
  45697. /**
  45698. * @fileOverview
  45699. *
  45700. * 新建文件菜单
  45701. *
  45702. * @author: techird
  45703. * @copyright: Baidu FEX, 2014
  45704. */
  45705. KityMinder.registerUI('menu/new/new', function(minder) {
  45706. var $menu = minder.getUI('menu/menu');
  45707. var $doc = minder.getUI('doc');
  45708. var ret = minder.getUI('eve').setup({});
  45709. var $panel = $menu.createSub('new');
  45710. // 模板列表容器
  45711. var $ul = $('<ul></ul>')
  45712. .addClass('new-file-template-select')
  45713. .appendTo($panel);
  45714. // 模板容器
  45715. var $li;
  45716. var templates = KityMinder.getTemplateList();
  45717. for (var name in templates) {
  45718. $li = $('<li></li>')
  45719. .addClass('template-item')
  45720. .addClass(name)
  45721. .data('template', name)
  45722. .append('<a>' + minder.getLang('template')[name] + '</a>')
  45723. .appendTo($ul);
  45724. }
  45725. $ul.delegate('.template-item', 'click', function(e) {
  45726. if (!$doc.checkSaved()) return;
  45727. var template = $(e.target).data('template');
  45728. $doc.load({
  45729. content: {
  45730. template: template,
  45731. version: KityMinder.version,
  45732. data: {
  45733. text: minder.getLang('template')[template]
  45734. }
  45735. },
  45736. protocol: null,
  45737. saved: true
  45738. });
  45739. $menu.hide();
  45740. });
  45741. return ret;
  45742. });
  45743. /**
  45744. * @fileOverview
  45745. *
  45746. * 打开菜单(二级菜单)
  45747. *
  45748. * @author: techird
  45749. * @copyright: Baidu FEX, 2014
  45750. */
  45751. KityMinder.registerUI('menu/open/open', function(minder) {
  45752. return minder.getUI('menu/menu').createSubMenu('open', true);
  45753. });
  45754. /**
  45755. * @fileOverview
  45756. *
  45757. * 最近文件功能
  45758. *
  45759. * @author: techird
  45760. * @copyright: Baidu FEX, 2014
  45761. */
  45762. KityMinder.registerUI('menu/open/recent', function(minder) {
  45763. var $menu = minder.getUI('menu/menu');
  45764. var $open = minder.getUI('menu/open/open');
  45765. var $loader = minder.getUI('widget/fileloader');
  45766. var frdTime = minder.getUI('widget/friendlytimespan');
  45767. var doc = minder.getUI('doc');
  45768. var recentList = minder.getUI('widget/locallist').use('recent');
  45769. var finder = minder.getUI('widget/netdiskfinder');
  45770. /* 网盘面板 */
  45771. var $panel = $($open.createSub('recent')).addClass('recent-file-panel');
  45772. minder.on('uiready', function() {
  45773. minder.getUI('topbar/user').requireLogin($panel);
  45774. });
  45775. /* 标题 */
  45776. var $title = $('<h2></h2>')
  45777. .text(minder.getLang('ui.recent'))
  45778. .appendTo($panel);
  45779. var $clear = $('<button></button>')
  45780. .addClass('clear-recent-list')
  45781. .text(minder.getLang('ui.clearrecent'))
  45782. .appendTo($panel);
  45783. /* 最近文件列表容器 */
  45784. var $ul = $('<ul></ul>')
  45785. .addClass('recent-file-list')
  45786. .appendTo($panel);
  45787. $ul.delegate('.recent-file-item', 'click', function(e) {
  45788. if (!doc.checkSaved()) return;
  45789. var netdisk = minder.getUI('menu/open/netdisk');
  45790. var path = $(e.target)
  45791. .closest('.recent-file-item')
  45792. .data('path');
  45793. netdisk.open(path);
  45794. });
  45795. $clear.on('click', function() {
  45796. if (!window.confirm(minder.getLang('ui.clearrecentconfirm'))) return;
  45797. recentList.clear();
  45798. renderList();
  45799. });
  45800. doc.on('docload', addToList);
  45801. doc.on('docsave', addToList);
  45802. finder.on('mv', trackFileMove);
  45803. renderList();
  45804. function trackFileMove(from, to) {
  45805. var fromPath = from.split('/');
  45806. var toPath = to.split('/');
  45807. function preCommonLength(a, b) {
  45808. var i = 0;
  45809. while((i in a) && (i in b) && a[i] == b[i]) i++;
  45810. return (i in b) ? 0 : i;
  45811. }
  45812. recentList.forEach(function(item) {
  45813. var originPath = item.path.split('/');
  45814. var clen = preCommonLength(originPath, fromPath);
  45815. if (clen) {
  45816. var movedPath = toPath.concat(originPath.slice(clen));
  45817. item.path = movedPath.join('/');
  45818. item.filename = toPath.pop();
  45819. }
  45820. });
  45821. renderList();
  45822. }
  45823. function addToList(doc) {
  45824. if (doc.source != 'netdisk') return;
  45825. var exist = recentList.findIndex('path', doc.path);
  45826. if (~exist) {
  45827. recentList.remove(exist);
  45828. }
  45829. recentList.unshift({
  45830. path: doc.path,
  45831. filename: fio.file.anlysisPath(doc.path).filename,
  45832. title: minder.getMinderTitle(),
  45833. time: +new Date()
  45834. });
  45835. renderList();
  45836. }
  45837. function renderList() {
  45838. $ul.empty();
  45839. recentList.forEach(function(item) {
  45840. var $li = $('<li></li>')
  45841. .addClass('recent-file-item')
  45842. .data('path', item.path)
  45843. .appendTo($ul);
  45844. $('<h4></h4>')
  45845. .addClass('file-name')
  45846. .text(item.filename)
  45847. .appendTo($li);
  45848. $('<p></p>')
  45849. .addClass('file-title')
  45850. .text(item.title)
  45851. .appendTo($li);
  45852. $('<span></span>')
  45853. .addClass('file-time')
  45854. .displayFriendlyTime(item.time)
  45855. .appendTo($li);
  45856. });
  45857. }
  45858. return {
  45859. hasRecent: function() {
  45860. return recentList.length;
  45861. },
  45862. loadLast: function() {
  45863. $ul.find('.recent-file-item').eq(0).click();
  45864. },
  45865. last: function() {
  45866. return recentList.get(0) || null;
  45867. }
  45868. };
  45869. });
  45870. /**
  45871. * @fileOverview
  45872. *
  45873. * 支持从百度网盘打开文件
  45874. *
  45875. * @author: techird
  45876. * @copyright: Baidu FEX, 2014
  45877. */
  45878. KityMinder.registerUI('menu/open/netdisk', function(minder) {
  45879. var $menu = minder.getUI('menu/menu');
  45880. var $open = minder.getUI('menu/open/open');
  45881. var $netdiskfinder = minder.getUI('widget/netdiskfinder');
  45882. var $eve = minder.getUI('eve');
  45883. var $doc = minder.getUI('doc');
  45884. var ret = $eve.setup({});
  45885. var notice = minder.getUI('widget/notice');
  45886. /* 网盘面板 */
  45887. var $panel = $($open.createSub('netdisk')).addClass('netdisk-open-panel');
  45888. /* extension => protocol */
  45889. var supports = {};
  45890. minder.getSupportedProtocols().forEach(function(protocol) {
  45891. if (protocol.decode) {
  45892. supports[protocol.fileExtension] = protocol;
  45893. }
  45894. });
  45895. /* Finder */
  45896. var $finder = $netdiskfinder.generate($panel, function(file) {
  45897. return supports[file.extension];
  45898. });
  45899. $finder.on('fileclick', function(file) {
  45900. if (!$doc.checkSaved()) return;
  45901. return open(file.path);
  45902. });
  45903. function open(path, errorHandler) {
  45904. $menu.hide();
  45905. $(minder.getRenderTarget()).addClass('loading');
  45906. var info = fio.file.anlysisPath(path);
  45907. var protocol = supports[info.extension];
  45908. function read() {
  45909. return fio.file.read({
  45910. path: path,
  45911. dataType: protocol.dataType
  45912. });
  45913. }
  45914. function load(file) {
  45915. var doc = {
  45916. protocol: supports[file.extension].name,
  45917. content: file.data.content,
  45918. title: file.filename,
  45919. source: 'netdisk',
  45920. path: file.path,
  45921. saved: true
  45922. };
  45923. return $doc.load(doc);
  45924. }
  45925. function error(e) {
  45926. return errorHandler && errorHandler(e) || notice.error('err_load', e);
  45927. }
  45928. return read().then(load)['catch'](error).then(function() {
  45929. $(minder.getRenderTarget()).removeClass('loading');
  45930. });
  45931. }
  45932. ret.open = open;
  45933. return ret;
  45934. });
  45935. /**
  45936. * @fileOverview
  45937. *
  45938. * 支持从本地打开文件
  45939. *
  45940. * @author: techird
  45941. * @copyright: Baidu FEX, 2014
  45942. */
  45943. KityMinder.registerUI('menu/open/local', function(minder) {
  45944. var $menu = minder.getUI('menu/menu');
  45945. var $open = minder.getUI('menu/open/open');
  45946. var $doc = minder.getUI('doc');
  45947. var notice = minder.getUI('widget/notice');
  45948. /* extension => protocol */
  45949. var supports = {};
  45950. var accepts = [];
  45951. minder.getSupportedProtocols().forEach(function(protocol) {
  45952. if (protocol.decode) {
  45953. supports[protocol.fileExtension] = protocol;
  45954. accepts.push(protocol.fileExtension);
  45955. }
  45956. });
  45957. /* 网盘面板 */
  45958. var $panel = $($open.createSub('local')).addClass('local-file-open-panel');
  45959. /* 标题 */
  45960. $('<h2>本地文件</h2>')
  45961. .appendTo($panel);
  45962. /* 选择文件 */
  45963. var $pick = $('<div class="pick-file"></div>')
  45964. .appendTo($panel);
  45965. var $pickButton = $('<a></a>')
  45966. .text(minder.getLang('ui.pickfile'))
  45967. .appendTo($pick);
  45968. $('<span></span>')
  45969. .text(minder.getLang('ui.acceptfile', accepts.map(function(ext) {
  45970. var protocol = supports[ext];
  45971. return protocol.fileDescription + '(' + ext + ')';
  45972. }).join(', '))).appendTo($pick);
  45973. /* 拖放提示 */
  45974. var $drop = $('<div class="drop-file"></div>')
  45975. .append($('<span></span>').html(minder.getLang('ui.dropfile')))
  45976. .appendTo($panel);
  45977. /* 交互事件 */
  45978. $pickButton.click(function() {
  45979. if (!$doc.checkSaved()) return;
  45980. $('<input type="file" />')
  45981. .attr('accept', accepts.join())
  45982. .on('change', function(e) {
  45983. read(this.files[0]);
  45984. $menu.hide();
  45985. }).click();
  45986. });
  45987. var cwrapper = $('#content-wrapper')[0];
  45988. cwrapper.addEventListener('dragover', function(e) {
  45989. e.preventDefault();
  45990. e.stopPropagation();
  45991. }, false);
  45992. cwrapper.addEventListener('drop', function(e) {
  45993. if (e.dataTransfer.files.length) {
  45994. e.preventDefault();
  45995. if (!$doc.checkSaved()) return;
  45996. read(e.dataTransfer.files[0]);
  45997. $menu.hide();
  45998. }
  45999. }, false);
  46000. function read(domfile) {
  46001. if (!domfile) return;
  46002. var info = new fio.file.anlysisPath(domfile.name);
  46003. var protocol = supports[info.extension];
  46004. if (!protocol || !protocol.decode) {
  46005. notice.warn(minder.getLang('ui.unsupportedfile'));
  46006. return Promise.reject();
  46007. }
  46008. function loadFile(file, protocol) {
  46009. return new Promise(function(resolve, reject) {
  46010. var reader;
  46011. if (protocol.dataType == 'blob') {
  46012. resolve(new fio.file.Data(domfile));
  46013. } else {
  46014. reader = new FileReader();
  46015. reader.onload = function() {
  46016. resolve(new fio.file.Data(this.result));
  46017. };
  46018. reader.onerror = reject;
  46019. reader.readAsText(domfile, 'utf-8');
  46020. }
  46021. });
  46022. }
  46023. function loadFileError() {
  46024. var notice = minder.getUI('widget/notice');
  46025. notice.error('err_localfile_read');
  46026. }
  46027. function loadDoc(data) {
  46028. var doc = {
  46029. content: data.content,
  46030. protocol: protocol.name,
  46031. title: info.filename,
  46032. source: 'local'
  46033. };
  46034. return $doc.load(doc);
  46035. }
  46036. $(minder.getRenderTarget()).addClass('loading');
  46037. return loadFile(domfile, protocol).then(loadDoc, loadFileError).then(function() {
  46038. $(minder.getRenderTarget()).removeClass('loading');
  46039. });
  46040. }
  46041. return {
  46042. read: read
  46043. };
  46044. });
  46045. /**
  46046. * @fileOverview
  46047. *
  46048. * 草稿箱功能
  46049. *
  46050. * @author: techird
  46051. * @copyright: Baidu FEX, 2014
  46052. */
  46053. KityMinder.registerUI('menu/open/draft', function(minder) {
  46054. var $menu = minder.getUI('menu/menu');
  46055. var $open = minder.getUI('menu/open/open');
  46056. var $loader = minder.getUI('widget/fileloader');
  46057. var frdTime = minder.getUI('widget/friendlytimespan');
  46058. var $doc = minder.getUI('doc');
  46059. // 旧数据迁移
  46060. if (localStorage.drafts) {
  46061. var oldDrafts = JSON.parse(localStorage.drafts);
  46062. var list = oldDrafts.map(function(draft) {
  46063. var ret = {};
  46064. ret.json = draft.data;
  46065. ret.time = +new Date(draft.update);
  46066. ret.title = JSON.parse(draft.data).data.text;
  46067. return ret;
  46068. });
  46069. delete localStorage.drafts;
  46070. localStorage.draft = JSON.stringify(list);
  46071. }
  46072. var draftList = minder.getUI('widget/locallist').use('draft');
  46073. /* 网盘面板 */
  46074. var $panel = $($open.createSub('draft')).addClass('draft-panel');
  46075. /* 标题 */
  46076. var $title = $('<h2></h2>')
  46077. .text(minder.getLang('ui.menu.draftheader'))
  46078. .appendTo($panel);
  46079. var $clear = $('<button></button>')
  46080. .addClass('clear-draft')
  46081. .text(minder.getLang('ui.cleardraft'))
  46082. .appendTo($panel);
  46083. /* 最近文件列表容器 */
  46084. var $ul = $('<ul></ul>')
  46085. .addClass('draft-list')
  46086. .appendTo($panel);
  46087. var current = null,
  46088. lastDoc = null;
  46089. $ul.delegate('.draft-list-item', 'click', function(e) {
  46090. if (!$doc.checkSaved()) return;
  46091. var item = $(e.target).closest('.draft-list-item').data('item');
  46092. var index = draftList.findIndex(function(finding) {
  46093. return finding == item;
  46094. });
  46095. if (index > -1) {
  46096. current = item;
  46097. draftList.remove(index);
  46098. draftList.unshift(current);
  46099. lastDoc = {
  46100. title: current.title,
  46101. protocol: 'json',
  46102. content: current.json,
  46103. path: current.path,
  46104. source: current.source,
  46105. saved: false
  46106. };
  46107. $doc.load(lastDoc);
  46108. }
  46109. $menu.hide();
  46110. });
  46111. $clear.on('click', function() {
  46112. if (!window.confirm(minder.getLang('ui.cleardraftconfirm'))) return;
  46113. draftList.clear();
  46114. current = null;
  46115. renderList();
  46116. });
  46117. $doc.on('docsave', popDraft);
  46118. $doc.on('docchange', pushDraft);
  46119. renderList();
  46120. function pushDraft(doc) {
  46121. if (doc.saved) return;
  46122. if (doc == lastDoc) {
  46123. if (current) {
  46124. draftList.remove(0);
  46125. }
  46126. } else {
  46127. current = null;
  46128. }
  46129. lastDoc = doc;
  46130. current = current || {};
  46131. current.json = JSON.stringify(minder.exportJson());
  46132. current.title = doc.title;
  46133. current.time = +new Date();
  46134. current.path = doc.path;
  46135. current.source = doc.source;
  46136. draftList.unshift(current);
  46137. renderList();
  46138. }
  46139. function popDraft() {
  46140. if (current) {
  46141. draftList.remove(0);
  46142. current = null;
  46143. }
  46144. renderList();
  46145. }
  46146. function renderList() {
  46147. $ul.empty();
  46148. draftList.forEach(function(item) {
  46149. var $li = $('<li></li>')
  46150. .addClass('draft-list-item')
  46151. .data('item', item)
  46152. .appendTo($ul);
  46153. $('<h4></h4>')
  46154. .addClass('draft-title')
  46155. .text(item.title)
  46156. .appendTo($li);
  46157. $('<span></span>')
  46158. .addClass('file-time')
  46159. .displayFriendlyTime(item.time)
  46160. .appendTo($li);
  46161. });
  46162. }
  46163. return {
  46164. hasDraft: function() {
  46165. return draftList.length;
  46166. },
  46167. openLast: function() {
  46168. $ul.find('.draft-list-item').eq(0).click();
  46169. },
  46170. last: function() {
  46171. return draftList.get(0) || null;
  46172. }
  46173. };
  46174. });
  46175. /**
  46176. * @fileOverview
  46177. *
  46178. * 保存菜单(二级菜单)
  46179. *
  46180. * @author: techird
  46181. * @copyright: Baidu FEX, 2014
  46182. */
  46183. KityMinder.registerUI('menu/save/save', function(minder) {
  46184. return minder.getUI('menu/menu').createSubMenu('save');
  46185. });
  46186. /**
  46187. * @fileOverview
  46188. *
  46189. * 保存文件到网盘的功能
  46190. *
  46191. * @author: techird
  46192. * @copyright: Baidu FEX, 2014
  46193. */
  46194. KityMinder.registerUI('menu/save/netdisk', function(minder) {
  46195. var $menu = minder.getUI('menu/menu');
  46196. var $save = minder.getUI('menu/save/save');
  46197. var $netdiskfinder = minder.getUI('widget/netdiskfinder');
  46198. var $eve = minder.getUI('eve');
  46199. var $doc = minder.getUI('doc');
  46200. var ret = $eve.setup({});
  46201. var notice = minder.getUI('widget/notice');
  46202. /* extension => protocol */
  46203. var supports = {};
  46204. minder.getSupportedProtocols().forEach(function(protocol) {
  46205. if (protocol.encode && protocol.decode) {
  46206. supports[protocol.fileExtension] = protocol;
  46207. }
  46208. });
  46209. // 删除不稳定两种格式
  46210. delete supports['.mm'];
  46211. delete supports['.xmind'];
  46212. /* 网盘面板 */
  46213. var $panel = $($save.createSub('netdisk', true)).addClass('netdisk-save-panel');
  46214. var $finder = $netdiskfinder.generate($panel, function(file) {
  46215. return supports[file.extension];
  46216. });
  46217. var $selects = $('<div class="netdisk-save-select"></div>')
  46218. .appendTo($panel);
  46219. $('<label>')
  46220. .text(minder.getLang('ui.saveas'))
  46221. .appendTo($selects);
  46222. /* 文件名 */
  46223. var $filename = $('<input>')
  46224. .addClass('fui-widget fui-selectable')
  46225. .attr('type', 'text')
  46226. .attr('placeholder', minder.getLang('ui.filename'))
  46227. .attr('title', minder.getLang('ui.filename'))
  46228. .on('keydown', function(e) {
  46229. if (e.keyCode == 27) $menu.toggle();
  46230. if (e.keyCode == 13) save();
  46231. })
  46232. .appendTo($selects);
  46233. /* 文件格式 */
  46234. var $format = $('<select>')
  46235. .attr('title', minder.getLang('ui.fileformat'))
  46236. .appendTo($selects);
  46237. for (var ext in supports) {
  46238. var protocol = supports[ext];
  46239. if (!protocol.encode) return;
  46240. $('<option>')
  46241. .text(protocol.fileDescription + '(' + protocol.fileExtension + ')')
  46242. .val(ext)
  46243. .appendTo($format);
  46244. }
  46245. $format.val('.km');
  46246. $format.on('change', normalizeFilename);
  46247. /* 保存按钮 */
  46248. var $saveBtn = $('<button></button>')
  46249. .addClass('save-button')
  46250. .text(minder.getLang('ui.save'))
  46251. .click(save)
  46252. .appendTo($selects);
  46253. $menu.on('show', setFilename);
  46254. $finder.on('fileclick', function(file) {
  46255. $finder.select(file.path);
  46256. $filename.val(file.filename);
  46257. });
  46258. ret.quickSave = quickSave;
  46259. window.onbeforeunload = function() {
  46260. var noask = ret.mute || window.location.href.indexOf('noask') > 0;
  46261. if (!$doc.checkSaved(true) && !noask)
  46262. return minder.getLang('ui.unsavedcontent', '* ' + $doc.current().title);
  46263. };
  46264. var autoSaveDuration = minder.getOptions('autoSave');
  46265. if (autoSaveDuration !== false) {
  46266. autoSaveDuration = isNaN(autoSaveDuration) ? 3000 : (autoSaveDuration * 1000);
  46267. autoSave();
  46268. }
  46269. var autoSaveTimer = 0;
  46270. function autoSave() {
  46271. function lazySave(doc) {
  46272. if (doc.saved) return;
  46273. clearTimeout(autoSaveTimer);
  46274. autoSaveTimer = setTimeout(saveCurrent, autoSaveDuration);
  46275. }
  46276. $doc.on('docchange', lazySave);
  46277. }
  46278. // 快速保存
  46279. function quickSave() {
  46280. var doc = $doc.current();
  46281. if (doc.source != 'netdisk' && !$menu.isVisible()) {
  46282. $menu.$tabs.select(2);
  46283. $save.$tabs.select(0);
  46284. return $menu.show();
  46285. } else {
  46286. saveCurrent();
  46287. }
  46288. }
  46289. function saveCurrent() {
  46290. var doc = $doc.current();
  46291. if (doc.source != 'netdisk') return Promise.resolve();
  46292. var $title = minder.getUI('topbar/title').$title;
  46293. $filename.val(doc.title);
  46294. return doSave(doc.path, doc.protocol, doc, $title, 'leaveTheMenu');
  46295. }
  46296. function normalizeFilename() {
  46297. var filename = $filename.val();
  46298. var info = fio.file.anlysisPath(filename);
  46299. var ext = info.extension;
  46300. if (ext != $format.val()) {
  46301. if (ext in supports) {
  46302. $filename.val(info.name + $format.val());
  46303. } else {
  46304. $filename.val(filename + $format.val());
  46305. }
  46306. $filename[0].select();
  46307. }
  46308. return $filename.val();
  46309. }
  46310. function getSaveContext() {
  46311. var filename = normalizeFilename();
  46312. var path = $finder.pwd() + filename;
  46313. var doc = $doc.current();
  46314. var protocol = supports[$format.val()];
  46315. var exist = $finder.select(path); // 目标路径存在
  46316. var match = doc.path == path; // 目标路径正是当前文档
  46317. var duplicated = exist && !match;
  46318. return {
  46319. filename: filename,
  46320. path: path,
  46321. doc: doc,
  46322. protocol: protocol,
  46323. exist: exist,
  46324. match: match,
  46325. duplicated: duplicated
  46326. };
  46327. }
  46328. function save() {
  46329. var ctx = getSaveContext();
  46330. if (ctx.match || !ctx.exist ||
  46331. ctx.duplicated && window.confirm(minder.getLang('ui.overrideconfirm', ctx.filename))) {
  46332. doSave(ctx.path, ctx.protocol.name, ctx.doc, $panel);
  46333. }
  46334. }
  46335. var saving = 0;
  46336. function doSave(path, protocol, doc, $mask, leaveTheMenu, msg) {
  46337. if (saving) return;
  46338. saving = true;
  46339. $doc.lock();
  46340. if ($mask) $mask.addClass('loading');
  46341. function upload(data) {
  46342. return fio.file.write({
  46343. path: path,
  46344. content: data,
  46345. ondup: fio.file.DUP_OVERWRITE
  46346. });
  46347. }
  46348. function finish(file) {
  46349. if (!file.modifyTime) throw new Error('File Save Error');
  46350. if (!leaveTheMenu) {
  46351. $menu.hide();
  46352. }
  46353. doc.path = file.path;
  46354. doc.title = file.filename;
  46355. doc.source = 'netdisk';
  46356. doc.protocol = protocol;
  46357. $doc.save(doc);
  46358. $doc.unlock();
  46359. //notice.info(msg || minder.getLang('ui.save_success', doc.title, file.modifyTime.toLocaleTimeString()));
  46360. setTimeout(function() {
  46361. $finder.list($finder.pwd(), true);
  46362. }, 1499);
  46363. }
  46364. function error(e) {
  46365. notice.error('err_save', e);
  46366. }
  46367. return minder.exportData(protocol).then(upload).then(finish, error).then(function() {
  46368. if ($mask) $mask.removeClass('loading');
  46369. saving = false;
  46370. });
  46371. }
  46372. function setFilename() {
  46373. var doc = $doc.current();
  46374. switch (doc.source) {
  46375. case 'netdisk':
  46376. setFilenameForNetDiskSource(doc);
  46377. break;
  46378. default:
  46379. setFilenameForOtherSource(doc);
  46380. break;
  46381. }
  46382. $filename[0].select();
  46383. }
  46384. function setFilenameInputValue(filename) {
  46385. $filename.val(filename);
  46386. normalizeFilename(filename);
  46387. }
  46388. function setFilenameForNetDiskSource(doc) {
  46389. if (!fio.user.current()) return;
  46390. var path = doc.path;
  46391. var pathInfo = fio.file.anlysisPath(path);
  46392. // 选中当前文件
  46393. if ($finder.pwd() != pathInfo.parentPath) {
  46394. $finder.list(pathInfo.parentPath).then(function() {
  46395. $finder.select(path);
  46396. });
  46397. } else {
  46398. $finder.select(path);
  46399. }
  46400. setFilenameInputValue(pathInfo.filename);
  46401. }
  46402. function setFilenameForOtherSource(doc) {
  46403. setFilenameInputValue(doc.title);
  46404. $finder.select(null);
  46405. }
  46406. return ret;
  46407. });
  46408. /**
  46409. * @fileOverview
  46410. *
  46411. * 导出数据到本地
  46412. *
  46413. * @author: techird
  46414. * @copyright: Baidu FEX, 2014
  46415. */
  46416. KityMinder.registerUI('menu/save/download', function(minder) {
  46417. var $menu = minder.getUI('menu/menu');
  46418. var $save = minder.getUI('menu/save/save');
  46419. /* 导出面板 */
  46420. var $panel = $($save.createSub('download')).addClass('download-panel');
  46421. /* 标题 */
  46422. var $title = $('<h2></h2>')
  46423. .text(minder.getLang('ui.menu.downloadheader'))
  46424. .appendTo($panel);
  46425. var $list = $('<ul>')
  46426. .addClass('download-list')
  46427. .appendTo($panel);
  46428. var supports = [];
  46429. minder.getSupportedProtocols().forEach(function(protocol) {
  46430. if (protocol.encode) {
  46431. supports.push(protocol);
  46432. }
  46433. });
  46434. supports.forEach(function(protocol) {
  46435. $('<li>')
  46436. .addClass(protocol.name)
  46437. .text(protocol.fileDescription + ' (' + protocol.fileExtension + ')')
  46438. .data('protocol', protocol)
  46439. .appendTo($list);
  46440. });
  46441. $list.delegate('li', 'click', function(e) {
  46442. var protocol = $(e.target).data('protocol');
  46443. if (!$panel.hasClass('loading')) doExport(protocol);
  46444. });
  46445. function doExport(protocol) {
  46446. var filename = minder.getMinderTitle() + protocol.fileExtension;
  46447. var mineType = protocol.mineType || 'text/plain';
  46448. $panel.addClass('loading');
  46449. var options = {
  46450. download: true,
  46451. filename: filename
  46452. };
  46453. minder.exportData(protocol.name, options).then(function(data) {
  46454. if (protocol.name == 'freemind') return;
  46455. switch (protocol.dataType) {
  46456. case 'text':
  46457. return doDownload(buildDataUrl(mineType, data), filename, 'text');
  46458. case 'base64':
  46459. return doDownload(data, filename, 'base64');
  46460. case 'blob':
  46461. return null;
  46462. }
  46463. return null;
  46464. })['catch'](function exportError(e) {
  46465. var notice = minder.getUI('widget/notice');
  46466. return notice.error('err_download', e);
  46467. })
  46468. .then(function done(tick) {
  46469. $panel.removeClass('loading');
  46470. });
  46471. }
  46472. function doDownload(url, filename, type) {
  46473. var stamp = +new Date() * 1e5 + Math.floor(Math.random() * (1e5 - 1));
  46474. stamp = stamp.toString(36);
  46475. var ret = new Promise(function(resolve, reject) {
  46476. var ticker = 0;
  46477. var MAX_TICK = 30;
  46478. var interval = 1000;
  46479. function check() {
  46480. if (document.cookie.indexOf(stamp + '=1') != -1) return resolve([stamp, ticker]);
  46481. if (++ticker > MAX_TICK) {
  46482. resolve([stamp, ticker]);
  46483. }
  46484. setTimeout(check, interval);
  46485. }
  46486. setTimeout(check, interval);
  46487. });
  46488. var content = url.split(',')[1];
  46489. var $form = $('<form></form>').attr({
  46490. 'action': 'download.php',
  46491. 'method': 'POST',
  46492. 'accept-charset': 'utf-8'
  46493. });
  46494. var $content = $('<input />').attr({
  46495. name: 'content',
  46496. type: 'hidden',
  46497. value: decodeURIComponent(content)
  46498. }).appendTo($form);
  46499. var $type = $('<input />').attr({
  46500. name: 'type',
  46501. type: 'hidden',
  46502. value: type
  46503. }).appendTo($form);
  46504. var $filename = $('<input />').attr({
  46505. name: 'filename',
  46506. type: 'hidden',
  46507. value: filename
  46508. }).appendTo($form);
  46509. if (kity.Browser.ie) {
  46510. $('<input name="iehack" value="1" />').appendTo($form);
  46511. }
  46512. $('<input name="stamp" />').val(stamp).appendTo($form);
  46513. var netdisk = minder.getUI('menu/save/netdisk');
  46514. if (netdisk) {
  46515. netdisk.mute = true;
  46516. setTimeout(function() {
  46517. netdisk.mute = false;
  46518. }, 1000);
  46519. }
  46520. $form.appendTo('body').submit().remove();
  46521. return ret;
  46522. }
  46523. function buildDataUrl(mineType, data) {
  46524. return 'data:' + mineType + '; utf-8,' + encodeURIComponent(data);
  46525. }
  46526. });
  46527. /**
  46528. * @fileOverview
  46529. *
  46530. * 分享功能交互
  46531. *
  46532. * @author: techird
  46533. * @copyright: Baidu FEX, 2014
  46534. */
  46535. KityMinder.registerUI('menu/share/share', function(minder) {
  46536. var $share_menu = minder.getUI('menu/menu').createSubMenu('share');
  46537. var $create_menu = $($share_menu.createSub('createshare'));
  46538. var $manage_menu = $($share_menu.createSub('manageshare'));
  46539. var $share_list = $('<ul>')
  46540. .attr('id', 'manage-share-list')
  46541. .appendTo($manage_menu);
  46542. var $doc = minder.getUI('doc');
  46543. var notice = minder.getUI('widget/notice');
  46544. var finder = minder.getUI('widget/netdiskfinder');
  46545. var BACKEND_URL = 'http://naotu.baidu.com/share.php';
  46546. if (window.location.host == 'local.host') {
  46547. //BACKEND_URL = '/naotu/share.php'; // 测试环境
  46548. }
  46549. var currentShare = null;
  46550. var shareList = [];
  46551. renderCreatePanel().then(bindCreatePanelEvent);
  46552. renderManagePanel();
  46553. var shareListLoaded = loadShareList();
  46554. shareListLoaded.then(renderShareList);
  46555. shareListLoaded.then(bindManageActions);
  46556. minder.on('uiready', function() {
  46557. minder.getUI('topbar/user').requireLogin($manage_menu);
  46558. });
  46559. $doc.on('docload', function(doc) {
  46560. if (doc.source != 'netdisk') {
  46561. currentShare = null;
  46562. setShareType('none');
  46563. }
  46564. shareListLoaded.then(function() {
  46565. var shared = getShareByPath(doc.path);
  46566. setCurrentShare(shared);
  46567. });
  46568. });
  46569. $doc.on('docsave', function(doc) {
  46570. if (doc.source != 'netdisk') return;
  46571. var shared = getShareByPath(doc.path);
  46572. if (shared) {
  46573. fio.user.check().then(function(user) {
  46574. $.pajax({
  46575. url: BACKEND_URL,
  46576. type: 'POST',
  46577. data: {
  46578. action: 'update',
  46579. ak: user.access_token,
  46580. id: shared.id || shared.shareMinder.id,
  46581. record: doc.json
  46582. }
  46583. }).then(function() {
  46584. //notice.info(minder.getLang('ui.share_sync_success', doc.title));
  46585. })['catch'](function(e) {
  46586. notice.error('err_share_sync_fail', e);
  46587. });
  46588. });
  46589. }
  46590. });
  46591. finder.on('mv', trackFileMove);
  46592. function trackFileMove(from, to) {
  46593. var fromPath = from.split('/');
  46594. var toPath = to.split('/');
  46595. function preCommonLength(a, b) {
  46596. var i = 0;
  46597. while ((i in a) && (i in b) && a[i] == b[i]) i++;
  46598. return (i in b) ? 0 : i;
  46599. }
  46600. shareListLoaded.then(function(list) {
  46601. var userChecked = fio.user.check();
  46602. list.forEach(function(item) {
  46603. var originPath = item.path.split('/');
  46604. var clen = preCommonLength(originPath, fromPath);
  46605. if (clen) {
  46606. var movedPath = toPath.concat(originPath.slice(clen));
  46607. userChecked.then(function(user) {
  46608. $.pajax({
  46609. url: BACKEND_URL,
  46610. type: 'POST',
  46611. data: {
  46612. action: 'move',
  46613. ak: user.access_token,
  46614. id: item.id || item.shareMinder.id,
  46615. path: movedPath.join('/')
  46616. }
  46617. }).then(function() {
  46618. notice.info(minder.getLang('ui.share_sync_success', item.title));
  46619. })['catch'](function(e) {
  46620. notice.error('err_share_sync_failed', e);
  46621. });
  46622. });
  46623. item.path = movedPath.join('/');
  46624. }
  46625. });
  46626. renderShareList(list);
  46627. });
  46628. }
  46629. function loadShareFile() {
  46630. var pattern = /(?:shareId|share_id)=(\w+)([&#]|$)/;
  46631. var match = pattern.exec(window.location) || pattern.exec(document.referrer);
  46632. if (!match) return Promise.resolve(null);
  46633. var shareId = match[1];
  46634. $(minder.getRenderTarget()).addClass('loading');
  46635. shareListLoaded.then(function(list) {
  46636. for (var i = 0; i < list.length; i++) {
  46637. var id = list[i].id || (list[i].shareMinder && list[i].shareMinder.id);
  46638. if (id == shareId && list[i].path) {
  46639. return loadOriginFile(list[i]);
  46640. }
  46641. }
  46642. return loadShare(shareId);
  46643. });
  46644. }
  46645. function loadOriginFile(share) {
  46646. var $netdisk = minder.getUI('menu/open/netdisk');
  46647. notice.info(minder.getLang('ui.load_share_for_edit', share.title));
  46648. return $netdisk.open(share.path, function() {
  46649. // 网盘加载失败
  46650. return loadShare(share);
  46651. });
  46652. }
  46653. function loadShare(shareId) {
  46654. function renderShareData(data) {
  46655. if (data.error) {
  46656. notice.error('err_share_data', data.error);
  46657. return;
  46658. }
  46659. var content = data.shareMinder.data;
  46660. return $doc.load({
  46661. source: 'share',
  46662. content: content,
  46663. protocol: 'json',
  46664. saved: true,
  46665. ownerId: data.uid,
  46666. ownerName: data.uname
  46667. });
  46668. }
  46669. var $container = $(minder.getRenderTarget()).addClass('loading');
  46670. return $.pajax({
  46671. url: 'http://naotu.baidu.com/share.php',
  46672. data: {
  46673. action: 'find',
  46674. id: shareId
  46675. },
  46676. dataType: 'json'
  46677. }).then(renderShareData)['catch'](function(e) {
  46678. notice.error('err_share_data', e);
  46679. }).then(function() {
  46680. $container.removeClass('loading');
  46681. });
  46682. }
  46683. function getShareByPath(path) {
  46684. if (!path || !shareList) return null;
  46685. var i = shareList.length;
  46686. while (i--) {
  46687. if (shareList[i].path == path) return shareList[i];
  46688. }
  46689. return null;
  46690. }
  46691. function setCurrentShare(share) {
  46692. currentShare = share;
  46693. if (share)
  46694. renderPublicShare(share);
  46695. else
  46696. setShareType('none');
  46697. }
  46698. function renderCreatePanel() {
  46699. // render template
  46700. return $.pajax({ url: 'static/pages/createshare.html' }).then(function(html) {
  46701. /* global jhtmls: true */
  46702. var render = jhtmls.render(html);
  46703. $create_menu.html(render({
  46704. lang: minder.getLang('ui'),
  46705. minder: minder
  46706. }));
  46707. setTimeout(zeroCopy, 10);
  46708. return $create_menu;
  46709. });
  46710. }
  46711. function renderManagePanel() {
  46712. $manage_menu.append($('<h2>')
  46713. .text(minder.getLang('ui.manage_share'))
  46714. .attr('id', 'manage-share-header'));
  46715. }
  46716. function bindCreatePanelEvent($panel) {
  46717. $panel.delegate('input[name=sharetype]', 'click', function(e) {
  46718. var actions = {
  46719. 'none': removeCurrentShare,
  46720. 'public': createPublicShare
  46721. };
  46722. actions[e.target.value]();
  46723. });
  46724. $panel.delegate('input#share-url', 'dblclick', function() {
  46725. this.select();
  46726. });
  46727. $panel.delegate('#copy-share-url', 'click', function() {
  46728. if (kity.Browser.safari && kity.Browser.safari < 8) {
  46729. var input = $('#share-url');
  46730. input.focus();
  46731. input.select();
  46732. window.alert(minder.getLang('ui.clipboardunsupported'));
  46733. }
  46734. });
  46735. }
  46736. function bindManageActions() {
  46737. $manage_menu.delegate('.share-item a', 'click', function(e) {
  46738. var $target = $(e.target);
  46739. var $li = $target.closest('.share-item');
  46740. var share = $li.data('share');
  46741. switch (true) {
  46742. case $target.hasClass('view-action'):
  46743. window.open(buildShareUrl(share.id || share.shareMinder.id), '_blank');
  46744. return;
  46745. case $target.hasClass('remove-action'):
  46746. $li.addClass('loading');
  46747. removeShare(share).then(function(result) {
  46748. if (result && result.deleted) {
  46749. shareList.splice(shareList.indexOf(share), 1);
  46750. $li.slideUp(function() {
  46751. $li.remove();
  46752. });
  46753. if (share == currentShare) {
  46754. removeCurrentShareSelect();
  46755. }
  46756. }
  46757. }).then(function() {
  46758. $li.removeClass('loading');
  46759. });
  46760. return;
  46761. case $target.hasClass('edit-action'):
  46762. loadOriginFile(share);
  46763. return;
  46764. }
  46765. });
  46766. }
  46767. function removeShare(share) {
  46768. return fio.user.check().then(function(user) {
  46769. return $.pajax(BACKEND_URL, {
  46770. type: 'POST',
  46771. data: {
  46772. action: 'remove',
  46773. ak: user && user.access_token,
  46774. id: share.id || share.shareMinder.id
  46775. },
  46776. dataType: 'json'
  46777. })['catch'](function(e) {
  46778. var notice = minder.getUI('widget/notice');
  46779. notice.error('err_remove_share', e);
  46780. });
  46781. });
  46782. }
  46783. function removeCurrentShare() {
  46784. if (!currentShare) return;
  46785. $create_menu.addClass('loading');
  46786. return removeShare(currentShare).then(function(result) {
  46787. if (result && result.deleted) {
  46788. removeCurrentShareSelect();
  46789. }
  46790. $create_menu.removeClass('loading');
  46791. });
  46792. }
  46793. function removeCurrentShareSelect() {
  46794. if (currentShare.$listItem) {
  46795. currentShare.$listItem.remove();
  46796. }
  46797. currentShare = null;
  46798. setShareType('none');
  46799. }
  46800. function uuid() {
  46801. // 最多使用 1e7,否则 IE toString() 会出来指数表示法
  46802. var timeLead = 1e6;
  46803. return ((+new Date() * timeLead) + (Math.random() * --timeLead)).toString(36);
  46804. }
  46805. function createPublicShare(user) {
  46806. if (currentShare) return;
  46807. $create_menu.addClass('loading');
  46808. return fio.user.check().then(function(user) {
  46809. var record = {
  46810. shareMinder: {
  46811. id: uuid(),
  46812. data: JSON.stringify(minder.exportJson())
  46813. }
  46814. };
  46815. var currentDoc = $doc.current();
  46816. if (currentDoc.source == 'netdisk') {
  46817. record.path = currentDoc.path;
  46818. }
  46819. return $.pajax(BACKEND_URL, {
  46820. type: 'POST',
  46821. data: {
  46822. action: 'insert',
  46823. record: JSON.stringify(record),
  46824. ak: user && user.access_token
  46825. },
  46826. dataType: 'json'
  46827. }).then(function(result) {
  46828. if (result.error) {
  46829. throw new Error(result.error);
  46830. }
  46831. return result;
  46832. })['catch'](function(e) {
  46833. var notice = minder.getUI('widget/notice');
  46834. notice.error('err_create_share', e);
  46835. });
  46836. })
  46837. .then(function(shared) {
  46838. if (shared) {
  46839. setCurrentShare(shared);
  46840. shareListLoaded.then(function() {
  46841. shareList.unshift(shared);
  46842. $('#manage-share-list').prepend(currentShare.$listItem = buildShareItem(shared));
  46843. });
  46844. }
  46845. $create_menu.removeClass('loading');
  46846. });
  46847. }
  46848. function buildShareUrl(id) {
  46849. var baseUrl = /^(.*?)(\?|\#|$)/.exec(window.location.href)[1];
  46850. baseUrl = baseUrl.split('edit.html')[0];
  46851. return baseUrl + 'viewshare.html?shareId=' + id;
  46852. }
  46853. function setShareType(value) {
  46854. var $sbody = $('#public-share .share-body', $create_menu);
  46855. if (value == 'public') {
  46856. $sbody.show();
  46857. } else {
  46858. $sbody.hide();
  46859. }
  46860. $('#share-select input[name=sharetype][value=' + value + ']', $create_menu)
  46861. .prop('checked', true);
  46862. }
  46863. function renderPublicShare(shared) {
  46864. var $sbody = $('#public-share .share-body', $create_menu);
  46865. var shareUrl = buildShareUrl(shared.id || shared.shareMinder.id);
  46866. $('#share-url', $sbody).val(shareUrl)[0].select();
  46867. // qr code
  46868. var $qrcontainer = $sbody.find('.share-qr-code').empty();
  46869. new window.QRCode($qrcontainer[0], {
  46870. text: shareUrl,
  46871. width: 128,
  46872. height: 128,
  46873. correctLevel : window.QRCode.CorrectLevel.M
  46874. });
  46875. var shareConfig = window._bd_share_config && window._bd_share_config.common,
  46876. resetShare = window._bd_share_main && window._bd_share_main.init;
  46877. if (shareConfig && resetShare) {
  46878. shareConfig.bdTitle = shareConfig.bdText = minder.getMinderTitle();
  46879. shareConfig.bdDesc = shareConfig.bdText = minder.getLang('ui.sns_share_text',
  46880. minder.getMinderTitle(), shareUrl);
  46881. shareConfig.bdUrl = shareUrl;
  46882. resetShare();
  46883. }
  46884. setShareType('public');
  46885. }
  46886. function loadShareList() {
  46887. return fio.user.check().then(function(user) {
  46888. if (!user) return;
  46889. return $.pajax(BACKEND_URL, {
  46890. type: 'GET',
  46891. data: {
  46892. action: 'list',
  46893. ak: user && user.access_token
  46894. },
  46895. dataType: 'json'
  46896. }).then(function(result) {
  46897. return (shareList = result.list || []);
  46898. });
  46899. });
  46900. }
  46901. function renderShareList(list) {
  46902. var frdTime = minder.getUI('widget/friendlytimespan');
  46903. if (!list) return;
  46904. $share_list.empty();
  46905. list.forEach(function(share) {
  46906. $share_list.append(share.$listItem = buildShareItem(share));
  46907. });
  46908. }
  46909. function buildShareItem(share) {
  46910. var id = share.id || (share.shareMinder && share.shareMinder.id);
  46911. if (!id) return;
  46912. var $li = $('<li>')
  46913. .addClass('share-item')
  46914. .data('share', share);
  46915. $('<span>')
  46916. .addClass('title')
  46917. .text(share.title)
  46918. .appendTo($li);
  46919. $('<span>')
  46920. .addClass('url')
  46921. .text(share.path ?
  46922. share.path.replace('/apps/kityminder', minder.getLang('ui.mydocument')) :
  46923. buildShareUrl(id))
  46924. .appendTo($li);
  46925. if (share.ctime) {
  46926. $('<span>')
  46927. .addClass('ctime')
  46928. .displayFriendlyTime(+share.ctime)
  46929. .appendTo($li);
  46930. }
  46931. $('<a>')
  46932. .addClass('remove-action')
  46933. .text(minder.getLang('ui.share_remove_action'))
  46934. .attr('title', minder.getLang('ui.share_remove_action'))
  46935. .appendTo($li);
  46936. $('<a>')
  46937. .addClass('view-action')
  46938. .text(minder.getLang('ui.share_view_action'))
  46939. .attr('title', minder.getLang('ui.share_view_action'))
  46940. .appendTo($li);
  46941. if (share.path)
  46942. $('<a>')
  46943. .addClass('edit-action')
  46944. .text(minder.getLang('ui.share_edit_action'))
  46945. .attr('title', minder.getLang('ui.share_edit_action'))
  46946. .appendTo($li);
  46947. return $li;
  46948. }
  46949. function clearShareList() {
  46950. shareList = [];
  46951. }
  46952. function shareRedirect() {
  46953. var pattern = /(?:shareId|share_id)=(\w+)([&#]|$)/;
  46954. var match = pattern.exec(window.location) || pattern.exec(document.referrer);
  46955. if (match) {
  46956. window.location.href = 'viewshare.html?shareId=' + match[1];
  46957. }
  46958. }
  46959. function zeroCopy() {
  46960. /* global ZeroClipboard:true */
  46961. var $copy_url_btn = $('#copy-share-url', $create_menu);
  46962. if (window.ZeroClipboard) {
  46963. ZeroClipboard.config({
  46964. swfPath: 'lib/ZeroClipboard.swf',
  46965. hoverClass: 'hover',
  46966. activeClass: 'active'
  46967. });
  46968. var clip = new window.ZeroClipboard($copy_url_btn);
  46969. clip.on('ready', function() {
  46970. clip.on('aftercopy', function() {
  46971. $copy_url_btn.text(minder.getLang('ui.copied')).attr('disabled', 'disabled');
  46972. setTimeout(function() {
  46973. $copy_url_btn
  46974. .text(minder.getLang('ui.copy'))
  46975. .removeAttr('disabled');
  46976. }, 3000);
  46977. });
  46978. });
  46979. }
  46980. }
  46981. return {
  46982. $menu: $share_menu,
  46983. loadShareFile: loadShareFile
  46984. };
  46985. });
  46986. /**
  46987. * @fileOverview
  46988. *
  46989. * 帮助面板
  46990. *
  46991. * @author: techird
  46992. * @copyright: Baidu FEX, 2014
  46993. */
  46994. KityMinder.registerUI('menu/help/help', function (minder) {
  46995. var $menu = minder.getUI('menu/menu');
  46996. var $panel = $($menu.createSub('help'));
  46997. var $help = $('<div id="help-panel">')
  46998. .appendTo($panel)
  46999. .addClass('loading');
  47000. Promise.all([$.pajax({
  47001. url: 'static/pages/helpcontent.html',
  47002. dataType: 'text'
  47003. }), $.pajax({
  47004. url: 'static/pages/operation.' + minder.getOptions('lang') + '.txt',
  47005. dataType: 'text'
  47006. })])
  47007. .then(function(values) {
  47008. var template = values[0];
  47009. var operation = values[1];
  47010. render(template, operation);
  47011. });
  47012. function render(template, operation) {
  47013. /* global jhtmls: true */
  47014. var renderer = jhtmls.render(template);
  47015. $help.html(renderer({
  47016. lang: minder.getLang('ui'),
  47017. minder: minder
  47018. }));
  47019. $help.find('.shortcut-content').html(convert(operation));
  47020. if (kity.Browser.mac) {
  47021. $help.addClass('mac');
  47022. }
  47023. $help.removeClass('loading');
  47024. $help.find('.km-version').text(KityMinder.version);
  47025. // 彩蛋:点很多次按钮的蛋疼
  47026. /*9szjzrzdznztz6z1z28z1wzhzbz9z4z2mz23z27zcz1xz27z9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z23zfz20z8z26z27z9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z1uz1uztztz1uz29z2nz3zsz5ztz2mzfz2nz2nzez7z1wzczhz2iz28zjzrzdznztz6z1z20z2lz2kz9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z2azhzjz1zmz19z14zqz2mz2lz2pzczjz6zsziz1ez17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2nz2eziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2nz2nz1yz9zvzmz1yz2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z1uz1uztztz1uz29z2nz3zsz5ztz2mzfz0zez7z1wzczhz2iz28zjzrzdznztz6z1z20z2lz2kz9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z2dz2nz27zbz9zjz1ez19zbz1z11z1iz2mzozpziz1ez17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2nz2eziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2nz3ez17z0z0z0z0z0z0z0z0z0z0z0z2gznzjz2cz25zezsz2jztztzgz22z23z2z2zazrz17z17z0z0z0z0z0z0z0z0z0z0z0z2gznzjz2cz1vz1vztztz3iz6z2wz1ez17z0z0z0z0z0z0z0z0z0z0z0z2gznzjz2cz23z23ztztzgzbz1ez17z0z0z0z0z0z0z0z0z0z0z0z1vz26z2oz5z6zrz1tz23z1nz1fz1hz3kz3lz3lz25zezsz2aziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2hzvz1z5z9z27z23z1nz37z0z1vz1hz3kz1zsz0ztz2fzrzaz1z3zfz7zbz1z27z9z1vz26z2oz5z6zrz1tz23z1nz1fz1hz3kz3lz3lz8z26z1xzvzvz1vz1mz1fz1xzsz33z3kzqzqz1uz1nz1fz1xzsz33z3bz0ziz1ez17z0z0z0z0z0z0z0z0z0z0z0z1wzcz1ztzsz3z9z25z1vz3z8z29z23z22ziz1ez17z0z0z0z0z0z0z0z0z0z0z0z1wzcz1ztzsz3z9z25z1vz3z8z29z24z25ziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z1xz1xzvzvz3az14z6zrz7z9z23z22zkztz2z1bz18z9zjz1ez19zbz1z25z29zhz0zszlz2bz20zrzpz0z1tzcz1vz25z9zqzqz1vz26z1wzczhz2iz28zjzrzdznztz6z1z20z26z27z9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z1xz24z2kzrz1pz14z6zrz7z9z29zrz6zsziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2nz2ez7z1xz5z6z7z20zfz2nz2nzeziz1ez17z0z0z0z0z0z0z0z2n*/
  47027. function decrypt(a) {
  47028. a = a.split('z').map(function(s) {
  47029. return parseInt(s, 35);
  47030. });
  47031. var key = 0x131;
  47032. var b = [];
  47033. var i = 0;
  47034. b.push(a[i] ^ key);
  47035. while(a[++i] !== undefined) b.push(a[i] ^ b[i-1]);
  47036. return String.fromCharCode.apply(null, b);
  47037. }
  47038. var counter = 0;
  47039. var archives = {
  47040. '1': 'gctz8m5z8cpz61kz5vvz3uuz1a3az1hwtzbqdz124y',
  47041. '10': 'gctz8m5z8cpz9tdz1dz2p1zcn3zalez6d3z2f7zbqdz124y',
  47042. '100': 'hctz77uzd0az123kzr6u',
  47043. '1000': 'gctzbs8z3kpz8nzclpz8nrzw8z8wwz3syz5oyzoiuz0zi7yzbqz7nbz77uzd0az123kzuu5z2f9z8ny',
  47044. '1000000': '96z1zjzoz27z2kz2oz23z22zbz2izrzoz2az5z27zpz2az3z24z3zbznzvzfzdzczez25z2cznzhzvz25z2dz2cz1z25z25z4z1vz29z1vz25z2ez2cz2nzgz1vz2lzizbzpzazjziz2nzdz1vz22z2z24z23z23zezez22z2ezsz25z22z3zbzbz25z2hzsz3z3z23z23z1vz1vzuzuziziz22z2ozmz22z5z27zpzpz22'
  47045. };
  47046. $help.delegate('.shortcut-key', 'click', function() {
  47047. var msg = archives[++counter];
  47048. if (msg) {
  47049. window.alert(decrypt(msg));
  47050. if (counter > 1000000) console.log(msg);
  47051. }
  47052. });
  47053. }
  47054. function convert(markdown) {
  47055. var html = '';
  47056. var titleReg = /##\s(.+)$/;
  47057. var declareReg = /(.+?)\:\s(.+)$/;
  47058. var section = false;
  47059. markdown.split('\n').forEach(convertLine);
  47060. if (section) {
  47061. html += '</section>';
  47062. }
  47063. function convertLine(line) {
  47064. var match = titleReg.exec(line);
  47065. if (match) {
  47066. if (section) html += '</section>';
  47067. html += '<section><h3>' + match[1] + '</h3>';
  47068. section = true;
  47069. return;
  47070. }
  47071. match = declareReg.exec(line);
  47072. if (match) {
  47073. var declare = match[1];
  47074. var description = match[2];
  47075. html += '<div class="shortcut-group"><span class="shortcut">';
  47076. html += declare.replace(/\`(.+?)\`/g, function(match, key) {
  47077. return '<span class="shortcut-key ' + key.toLowerCase() + '" title="' + key + '">' + key + '</span>';
  47078. });
  47079. html += '</span>';
  47080. html += '<span class="description">' + description + '</span>';
  47081. html += '</div>';
  47082. return;
  47083. }
  47084. }
  47085. return html;
  47086. }
  47087. });
  47088. /**
  47089. * @fileOverview
  47090. *
  47091. * 帮助面板
  47092. *
  47093. * @author: techird
  47094. * @copyright: Baidu FEX, 2014
  47095. */
  47096. KityMinder.registerUI('menu/help/feedback', function (minder) {
  47097. var $menu = minder.getUI('menu/menu');
  47098. var $panel = $($menu.createSub('feedback'));
  47099. var $feedback = $('<div id="feedback-panel">')
  47100. .appendTo($panel)
  47101. .addClass('loading');
  47102. $.pajax({
  47103. url: 'static/pages/feedback.html',
  47104. dataType: 'text'
  47105. }).then(render);
  47106. function render(template) {
  47107. /* global jhtmls: true */
  47108. var renderer = jhtmls.render(template);
  47109. $feedback.html(renderer({
  47110. lang: minder.getLang('ui'),
  47111. minder: minder
  47112. }));
  47113. $feedback.on('click contextmenu keydown', function(e) {
  47114. e.stopPropagation();
  47115. });
  47116. $feedback.removeClass('loading');
  47117. $feedback.find('.km-version').text(KityMinder.version);
  47118. }
  47119. });
  47120. /**
  47121. * @fileOverview
  47122. *
  47123. * 快速访问区域
  47124. *
  47125. * @author: techird
  47126. * @copyright: Baidu FEX, 2014
  47127. */
  47128. KityMinder.registerUI('topbar/quickvisit', function (minder) {
  47129. var rightDocks = [];
  47130. function btn(name, dockRight) {
  47131. var $btn = $('<a class="quick-visit-button"></a>')
  47132. .text(minder.getLang('ui.quickvisit.' + name))
  47133. .attr('title', minder.getLang('ui.quickvisit.' + name))
  47134. .addClass(name);
  47135. if (dockRight) rightDocks.push($btn);
  47136. else $btn.appendTo('#panel');
  47137. return $btn;
  47138. }
  47139. var $new = btn('new'),
  47140. $save = btn('save'),
  47141. $share = btn('share');
  47142. var ret = {
  47143. $new: $new,
  47144. $save: $save,
  47145. $share: $share
  47146. };
  47147. minder.on('uiready', function quickVisit() {
  47148. while (rightDocks.length) $('#panel #search').after(rightDocks.shift());
  47149. function quickNew() {
  47150. var $doc = minder.getUI('doc');
  47151. if (!$doc.checkSaved()) return;
  47152. $doc.load({
  47153. content: {
  47154. template: 'default',
  47155. version: KityMinder.version,
  47156. data: {
  47157. text: minder.getLang('maintopic')
  47158. }
  47159. },
  47160. saved: true
  47161. });
  47162. }
  47163. function quickSave() {
  47164. minder.getUI('menu/save/netdisk').quickSave();
  47165. }
  47166. function quickShare() {
  47167. var $menu = minder.getUI('menu/menu');
  47168. $menu.$tabs.select(3);
  47169. $menu.show();
  47170. }
  47171. $new.click(quickNew);
  47172. $save.click(quickSave);
  47173. $share.click(quickShare);
  47174. minder.addShortcut('ctrl+alt+n', quickNew);
  47175. minder.addShortcut('ctrl+s', quickSave);
  47176. minder.addShortcut('ctrl+alt+s', quickShare);
  47177. minder.addShortcut('ctrl+shift+s', function() {
  47178. var $menu = minder.getUI('menu/menu');
  47179. $menu.$tabs.select(2);
  47180. $menu.show();
  47181. });
  47182. ret.ready = true;
  47183. ret.quickNew = quickNew;
  47184. ret.quickSave = quickSave;
  47185. ret.quickShare = quickShare;
  47186. });
  47187. ret.add = btn;
  47188. return ret;
  47189. });
  47190. /**
  47191. * @fileOverview
  47192. *
  47193. * 历史控制按钮
  47194. *
  47195. * @author: techird
  47196. * @copyright: Baidu FEX, 2014
  47197. */
  47198. KityMinder.registerUI('topbar/history', function(minder) {
  47199. var ret = {};
  47200. var commandbutton = minder.getUI('widget/commandbutton');
  47201. ['undo', 'redo'].forEach(function(command) {
  47202. ret[command] = commandbutton.generate(command).appendTo(document.getElementById('panel'));
  47203. });
  47204. return ret;
  47205. });
  47206. /**
  47207. * @fileOverview
  47208. *
  47209. * 用户登录控制
  47210. *
  47211. * @author: techird
  47212. * @copyright: Baidu FEX, 2014
  47213. */
  47214. KityMinder.registerUI('topbar/user', function(minder) {
  47215. var eve = minder.getUI('eve');
  47216. var currentUser;
  47217. var $userPanel = $('<div class="user-panel"></div>').appendTo('#panel');
  47218. var $tip = $('<span class="loading-tip"></span>')
  47219. .text(minder.getLang('ui.checklogin'))
  47220. .appendTo($userPanel);
  47221. /* 登录按钮 */
  47222. var $loginButton = new FUI.Button({
  47223. label: minder.getLang('ui.login'),
  47224. text: minder.getLang('ui.login'),
  47225. className: 'login-button'
  47226. }).appendTo($userPanel[0]).hide();
  47227. /* 用户按钮 */
  47228. var $userButton = new FUI.Button({
  47229. icon: {
  47230. // 1px 透明图
  47231. img: 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='
  47232. },
  47233. className: 'user-button'
  47234. }).appendTo($userPanel[0]).hide();
  47235. /* 用户菜单 */
  47236. var $userMenu = new FUI.PopupMenu({
  47237. id: 'user-menu'
  47238. }).appendTo(document.getElementById('content-wrapper')).positionTo($userButton);
  47239. var menu = $userMenu.getMenuWidget().show();
  47240. ['userinfo', 'gotonetdisk', 'fui-spliter', 'switchuser', 'logout'].forEach(function(name) {
  47241. menu.appendItem(new FUI.Item({
  47242. label: minder.getLang('ui.' + name),
  47243. className: name,
  47244. value: name
  47245. }));
  47246. });
  47247. $userButton.on('click', function() {
  47248. $userMenu.open();
  47249. var $dom = $($userMenu.getElement());
  47250. var $button = $($userButton.getElement());
  47251. $dom.offset({
  47252. left: $button.offset().left - $dom.outerWidth() + $button.outerWidth() - 10,
  47253. top: $button.offset().top + $button.outerHeight()
  47254. });
  47255. });
  47256. menu.on('select', function(e, info) {
  47257. switch (info.value) {
  47258. case 'userinfo':
  47259. window.open('http://i.baidu.com');
  47260. break;
  47261. case 'gotonetdisk':
  47262. window.open('http://pan.baidu.com/disk/home#path=/apps/kityminder');
  47263. break;
  47264. case 'switchuser':
  47265. switchUser();
  47266. break;
  47267. case 'logout':
  47268. logout();
  47269. break;
  47270. }
  47271. menu.clearSelect();
  47272. $userMenu.hide();
  47273. });
  47274. minder.on('uiready', function() {
  47275. //alert("skip login");
  47276. /*
  47277. fio.user.check().then(check)['catch'](function(error) {
  47278. $loginButton.show();
  47279. $userButton.hide();
  47280. $tip.hide();
  47281. });
  47282. */
  47283. });
  47284. $loginButton.on('click', login);
  47285. $('#content-wrapper').delegate('.login-button', 'click', login);
  47286. function check(user) {
  47287. if (user) {
  47288. $userButton.setLabel(user.username);
  47289. $userButton.getIconWidget().setImage(user.smallImage);
  47290. $userButton.show();
  47291. $loginButton.hide();
  47292. fio.user.fire('login', user);
  47293. } else {
  47294. if (window.location.href.indexOf('nocheck') == -1) {
  47295. return login();
  47296. } else {
  47297. $loginButton.show();
  47298. }
  47299. }
  47300. $tip.hide();
  47301. currentUser = user;
  47302. }
  47303. function logout() {
  47304. fio.user.logout();
  47305. $loginButton.show();
  47306. $userButton.hide();
  47307. fio.user.fire('logout');
  47308. window.location.href = window.location.href.split('edit.html')[0] + 'index.html'; // refresh
  47309. }
  47310. function login() {
  47311. $loginButton.setLabel(minder.getLang('ui.loggingin'));
  47312. fio.user.login({
  47313. remember: 7 * 24 * 60 * 60 // remember 7 days
  47314. });
  47315. }
  47316. function switchUser() {
  47317. fio.user.login({
  47318. remember: 7 * 24 * 60 * 60, // remember 7 days
  47319. force: true
  47320. });
  47321. }
  47322. function requireLogin($element) {
  47323. var $login_tip = $('<p class="login-tip"></p>')
  47324. .html(minder.getLang('ui.requirelogin'));
  47325. $element.append($login_tip);
  47326. fio.user.on('login', function() {
  47327. $element.removeClass('login-required');
  47328. });
  47329. fio.user.on('logout', function() {
  47330. $element.addClass('login-required');
  47331. });
  47332. }
  47333. return {
  47334. getCurrent: function() {
  47335. return currentUser;
  47336. },
  47337. loginLink: function() {
  47338. return $('<a></a>').click(login);
  47339. },
  47340. requireLogin: requireLogin
  47341. };
  47342. });
  47343. /**
  47344. * @fileOverview
  47345. *
  47346. * 快速反馈按钮
  47347. *
  47348. * @author: techird
  47349. * @copyright: Baidu FEX, 2014
  47350. */
  47351. KityMinder.registerUI('topbar/feedback', function(minder) {
  47352. var $quickvisit = minder.getUI('topbar/quickvisit');
  47353. var $feedback = $quickvisit.add('feedback', 'right');
  47354. function quickFeedback() {
  47355. var $menu = minder.getUI('menu/menu');
  47356. $menu.$tabs.select(5);
  47357. $menu.show();
  47358. }
  47359. $feedback.click(quickFeedback);
  47360. minder.addShortcut('f1', quickFeedback);
  47361. return $feedback;
  47362. });
  47363. /**
  47364. * @fileOverview
  47365. *
  47366. * 搜索节点功能
  47367. *
  47368. * @author: techird
  47369. * @copyright: Baidu FEX, 2014
  47370. */
  47371. KityMinder.registerUI('topbar/search', function(minder) {
  47372. var $search = $('<div id="search"><input type="search" /></div>').appendTo('#panel');
  47373. var $input = $search.find('input');
  47374. minder.addShortcut('ctrl+f', function() {
  47375. $input[0].focus();
  47376. $input[0].select();
  47377. });
  47378. $input.on('keydown', function(e) {
  47379. if (e.keyCode == 13) {
  47380. doSearch($input.val());
  47381. }
  47382. if (e.keyCode == 27) {
  47383. $input[0].blur();
  47384. }
  47385. });
  47386. var nodeSequence;
  47387. minder.on('contentchange', makeNodeSequence);
  47388. function makeNodeSequence() {
  47389. nodeSequence = [];
  47390. minder.getRoot().traverse(function(node) {
  47391. nodeSequence.push(node);
  47392. });
  47393. }
  47394. function doSearch(keyword) {
  47395. if (!/\S/.exec(keyword)) {
  47396. $input[0].focus();
  47397. $input[0].select();
  47398. return;
  47399. }
  47400. keyword = keyword.toLowerCase();
  47401. var newSearch = doSearch.lastKeyword != keyword;
  47402. doSearch.lastKeyword = keyword;
  47403. var startIndex = newSearch ? 0 : doSearch.lastIndex + 1 || 0;
  47404. var endIndex = startIndex + nodeSequence.length - 1;
  47405. for (var i = startIndex; i <= endIndex; i++) {
  47406. var node = nodeSequence[i % nodeSequence.length];
  47407. var text = node.getText().toLowerCase();
  47408. if (text.indexOf(keyword) != -1) {
  47409. setSearchResult(node);
  47410. doSearch.lastIndex = i;
  47411. break;
  47412. }
  47413. var note = node.getData('note');
  47414. if (note && note.indexOf(keyword) != -1) {
  47415. setSearchResult(node, keyword);
  47416. doSearch.lastIndex = i;
  47417. break;
  47418. }
  47419. }
  47420. function setSearchResult(node, previewKeyword) {
  47421. var $notepreview = minder.getUI('ribbon/idea/notepreview');
  47422. if ($notepreview) {
  47423. $notepreview.hide();
  47424. }
  47425. minder.execCommand('camera', node, 50);
  47426. setTimeout(function() {
  47427. minder.select(node, true);
  47428. if (!node.isExpanded()) minder.execCommand('expand', true);
  47429. if (previewKeyword) {
  47430. if ($notepreview) {
  47431. $notepreview.preview(node, previewKeyword);
  47432. }
  47433. }
  47434. }, 60);
  47435. }
  47436. }
  47437. return $search;
  47438. });
  47439. /**
  47440. * @fileOverview
  47441. *
  47442. * 显示并更新脑图文件的标题
  47443. *
  47444. * @author: techird
  47445. * @copyright: Baidu FEX, 2014
  47446. */
  47447. KityMinder.registerUI('topbar/title', function(minder) {
  47448. var $title = $('<h1>').appendTo('#panel');
  47449. var $doc = minder.getUI('doc');
  47450. var finder = minder.getUI('widget/netdiskfinder');
  47451. var notice = minder.getUI('widget/notice');
  47452. var renameEnabled = false;
  47453. var renameMode = false;
  47454. $doc.on('docchange', update);
  47455. $title.on('click', rename);
  47456. function rename() {
  47457. if (!renameEnabled || renameMode) return;
  47458. var doc = $doc.current();
  47459. var $input = $('<input>').width($title.find('.title-content').width());
  47460. var oldFilename = doc.title;
  47461. var oldPath = doc.path;
  47462. $input.val(oldFilename);
  47463. setTimeout(function() {
  47464. $input[0].select();
  47465. });
  47466. $title.addClass('rename-mode');
  47467. $title.empty();
  47468. $title.append($input);
  47469. renameMode = true;
  47470. $input.on('keydown', function(e) {
  47471. if (e.keyCode == 13) confirm();
  47472. else if (e.keyCode == 27) {
  47473. cancel();
  47474. e.stopPropagation();
  47475. }
  47476. }).on('blur', cancel);
  47477. function exit() {
  47478. setTimeout(function() {
  47479. renameMode = false;
  47480. });
  47481. }
  47482. function cancel() {
  47483. update();
  47484. exit();
  47485. }
  47486. function confirm() {
  47487. var newFilename = $input.val();
  47488. var oldFilenameInfo = fio.file.anlysisPath(oldFilename);
  47489. var newFilenameInfo = fio.file.anlysisPath(newFilename);
  47490. if (!newFilenameInfo.name.length) return cancel();
  47491. newFilename = newFilenameInfo.name + oldFilenameInfo.extension;
  47492. var newPath = fio.file.anlysisPath(oldPath).parentPath + newFilename;
  47493. if (newPath == oldPath) return cancel();
  47494. $title.addClass('loading');
  47495. fio.file.move({
  47496. path: oldPath,
  47497. newPath: newPath
  47498. }).then(function() {
  47499. doc.path = newPath;
  47500. doc.title = newFilename;
  47501. finder.fire('mv', oldPath, newPath);
  47502. notice.info(minder.getLang('ui.rename_success', newFilename));
  47503. })['catch'](function(e) {
  47504. notice.error('err_rename', e);
  47505. }).then(function() {
  47506. $title.removeClass('loading');
  47507. update();
  47508. exit();
  47509. });
  47510. }
  47511. }
  47512. function enableRename(enabled) {
  47513. renameEnabled = enabled;
  47514. if (enabled) $title.addClass('rename-enabled');
  47515. else $title.removeClass('rename-enabled');
  47516. }
  47517. function update() {
  47518. var doc = $doc.current();
  47519. function setTitle(title) {
  47520. if (setTitle.lastValue == title) return;
  47521. title = title || minder.getLang('ui.untitleddoc');
  47522. $title.empty().append($('<span class="title-content"></span>').text(title));
  47523. document.title = title ? title + ' - 众核脑图' : '众核脑图';
  47524. setTitle.lastValue = title;
  47525. }
  47526. if (doc.saved) {
  47527. setTitle(doc.title);
  47528. } else {
  47529. setTitle('* ' + doc.title);
  47530. }
  47531. enableRename(doc.source == 'netdisk' && doc.saved);
  47532. }
  47533. update();
  47534. return {
  47535. $title: $title,
  47536. getTitle: function() {
  47537. return $doc.current().title;
  47538. }
  47539. };
  47540. });
  47541. /**
  47542. * @fileOverview
  47543. *
  47544. * Ribbon 选项卡
  47545. *
  47546. * @author: techird
  47547. * @copyright: Baidu FEX, 2014
  47548. */
  47549. KityMinder.registerUI('ribbon/tabs', function(minder) {
  47550. var memory = minder.getUI('memory');
  47551. var $tab = new FUI.Tabs({
  47552. buttons: ['idea', 'appearence', 'view'].map(function(key) {
  47553. return minder.getLang('ui.tabs.' + key);
  47554. })
  47555. });
  47556. var $title = minder.getUI('topbar/title').$title;
  47557. var $header = $('<div id="tab-select"></div>');
  47558. var $container = $('<div id="tab-container"></div>');
  47559. $title.before($header);
  47560. $('#panel').after($container);
  47561. $tab.appendButtonTo($header[0]);
  47562. $tab.appendPanelTo($container[0]);
  47563. // 隐藏效果
  47564. var lastIndex = 0;
  47565. var muteRemember = false;
  47566. $tab.on('tabsselect', function(e, info) {
  47567. if (info.index == lastIndex) {
  47568. $container.toggleClass('collapsed');
  47569. $header.toggleClass('collapsed');
  47570. } else {
  47571. $container.removeClass('collapsed');
  47572. $header.removeClass('collapsed');
  47573. }
  47574. if (!muteRemember) {
  47575. memory.set('ribbon-tab-collapsed', $container.hasClass('collapsed'));
  47576. memory.set('ribbon-tab-index', info.index);
  47577. }
  47578. lastIndex = info.index;
  47579. });
  47580. $tab.idea = $tab.getPanel(0);
  47581. $tab.appearence = $tab.getPanel(1);
  47582. $tab.view = $tab.getPanel(2);
  47583. var rememberIndex = memory.get('ribbon-tab-index');
  47584. var rememberCollapse = memory.get('ribbon-tab-collapsed');
  47585. muteRemember = true;
  47586. $tab.select(rememberIndex || 0);
  47587. muteRemember = false;
  47588. if (rememberCollapse) {
  47589. $container.addClass('collapsed');
  47590. $header.addClass('collapsed');
  47591. } else {
  47592. $container.removeClass('collapsed');
  47593. $header.removeClass('collapsed');
  47594. }
  47595. return $tab;
  47596. });
  47597. /**
  47598. * @fileOverview
  47599. *
  47600. * 插入节点
  47601. *
  47602. * @author: techird
  47603. * @copyright: Baidu FEX, 2014
  47604. */
  47605. KityMinder.registerUI('ribbon/idea/insert', function(minder) {
  47606. var $commandbutton = minder.getUI('widget/commandbutton');
  47607. var $tabs = minder.getUI('ribbon/tabs');
  47608. var $insertNodePanel = new FUI.LabelPanel({
  47609. label: minder.getLang('panels.insert'),
  47610. column: true
  47611. });
  47612. $commandbutton.generate('appendchildnode').appendTo($insertNodePanel);
  47613. $commandbutton.generate('appendsiblingnode').appendTo($insertNodePanel);
  47614. $tabs.idea.appendWidget($insertNodePanel);
  47615. return $insertNodePanel;
  47616. });
  47617. /**
  47618. * @fileOverview
  47619. *
  47620. * 排列节点的两个命令按钮
  47621. *
  47622. * @author: techird
  47623. * @copyright: Baidu FEX, 2014
  47624. */
  47625. KityMinder.registerUI('ribbon/idea/arrange', function(minder) {
  47626. var $tabs = minder.getUI('ribbon/tabs');
  47627. var $commandbutton = minder.getUI('widget/commandbutton');
  47628. var $arrangePanel = new FUI.LabelPanel({
  47629. label: minder.getLang('panels.arrange'),
  47630. column: true
  47631. });
  47632. $commandbutton.generate('arrangeup').appendTo($arrangePanel);
  47633. $commandbutton.generate('arrangedown').appendTo($arrangePanel);
  47634. $tabs.idea.appendWidget($arrangePanel);
  47635. return $arrangePanel;
  47636. });
  47637. /**
  47638. * @fileOverview
  47639. *
  47640. * 节点操作(编辑和删除)
  47641. *
  47642. * @author: techird
  47643. * @copyright: Baidu FEX, 2014
  47644. */
  47645. KityMinder.registerUI('ribbon/idea/operation', function(minder) {
  47646. var $commandbutton = minder.getUI('widget/commandbutton');
  47647. var $tabs = minder.getUI('ribbon/tabs');
  47648. var $opPanel = new FUI.LabelPanel({
  47649. label: minder.getLang('panels.nodeop'),
  47650. column: true
  47651. }).appendTo($tabs.idea);
  47652. ['editnode', 'removenode'].forEach(function(cmd) {
  47653. $commandbutton.generate(cmd).appendTo($opPanel);
  47654. });
  47655. });
  47656. /**
  47657. * @fileOverview
  47658. *
  47659. * 附件面板
  47660. *
  47661. * @author: techird
  47662. * @copyright: Baidu FEX, 2014
  47663. */
  47664. KityMinder.registerUI('ribbon/idea/attachment', function(minder) {
  47665. var $tabs = minder.getUI('ribbon/tabs');
  47666. var $attachmentPanel = new FUI.LabelPanel({
  47667. label: minder.getLang('panels.attachment'),
  47668. coloum: true
  47669. }).appendTo($tabs.idea);
  47670. return $attachmentPanel;
  47671. });
  47672. /**
  47673. * @fileOverview
  47674. *
  47675. * 插入和管理超链接
  47676. *
  47677. * @author: techird
  47678. * @copyright: Baidu FEX, 2014
  47679. */
  47680. KityMinder.registerUI('ribbon/idea/link', function(minder) {
  47681. var R_URL = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?/;
  47682. var $attachment = minder.getUI('ribbon/idea/attachment');
  47683. var $linkButtonMenu = new FUI.ButtonMenu({
  47684. id: 'link-button-menu',
  47685. text: minder.getLang('ui.link'),
  47686. layout: 'bottom',
  47687. buttons: [{}, {
  47688. label: minder.getLang('ui.link')
  47689. }],
  47690. menu: {
  47691. items: [minder.getLang('ui.removelink')]
  47692. }
  47693. }).appendTo($attachment);
  47694. $linkButtonMenu.bindCommandState(minder, 'hyperlink');
  47695. var $linkDialog = new FUI.Dialog({
  47696. width: 600,
  47697. height: 200,
  47698. prompt: true,
  47699. caption: minder.getLang('ui.link')
  47700. }).appendTo(document.getElementById('content-wrapper'));
  47701. var $dialogBody = $($linkDialog.getBodyElement());
  47702. $dialogBody.html([
  47703. '<p><label>连接地址:</label><input type="url" class="link-href fui-widget fui-selectable" /></p>',
  47704. '<p><label>提示文本:</label><input type="text" class="link-title fui-widget fui-selectable" /></p>'
  47705. ].join(''));
  47706. var $href = $dialogBody.find('.link-href');
  47707. var $title = $dialogBody.find('.link-title');
  47708. var $ok = $linkDialog.getButton(0);
  47709. var $errorMsg = $('<span class="validate-error"></span>');
  47710. function error(value) {
  47711. if (value) {
  47712. $href.addClass('validate-error');
  47713. $errorMsg.text('地址格式错误');
  47714. $ok.disable();
  47715. } else {
  47716. $href.removeClass('validate-error');
  47717. $errorMsg.text('');
  47718. $ok.enable();
  47719. }
  47720. }
  47721. $href.after($errorMsg);
  47722. $href.on('input', function() {
  47723. var url = $href.val();
  47724. error(!R_URL.test(url));
  47725. });
  47726. $linkButtonMenu.on('buttonclick', function() {
  47727. $linkDialog.open();
  47728. $href[0].focus();
  47729. });
  47730. $linkButtonMenu.on('select', function() {
  47731. minder.execCommand('unhyperlink');
  47732. });
  47733. $linkDialog.on('ok', function() {
  47734. minder.execCommand('hyperlink', $href.val(), $title.val() || '');
  47735. });
  47736. $linkDialog.on('open', function() {
  47737. var value = minder.queryCommandValue('hyperlink');
  47738. $href.val(value.url);
  47739. $title.val(value.title);
  47740. error(false);
  47741. });
  47742. $(minder.getPaper().getNode()).delegate('a', 'click', function(e) {
  47743. var $a = $(e.target).closest('a');
  47744. var href = $a.prop('href').baseVal;
  47745. if (window.confirm(minder.getLang('ui.redirect', href))) {
  47746. window.open(href, '_blank');
  47747. }
  47748. e.preventDefault();
  47749. });
  47750. return $linkButtonMenu;
  47751. });
  47752. /**
  47753. * @fileOverview
  47754. *
  47755. * 插入和管理图片
  47756. *
  47757. * @author: techird
  47758. * @copyright: Baidu FEX, 2014
  47759. */
  47760. KityMinder.registerUI('ribbon/idea/image', function(minder) {
  47761. var $attachment = minder.getUI('ribbon/idea/attachment');
  47762. var $imageButtonMenu = new FUI.ButtonMenu({
  47763. id: 'image-button-menu',
  47764. text: minder.getLang('ui.image'),
  47765. layout: 'bottom',
  47766. buttons: [{}, {
  47767. label: minder.getLang('ui.image')
  47768. }],
  47769. menu: {
  47770. items: [minder.getLang('ui.removeimage')]
  47771. }
  47772. }).appendTo($attachment);
  47773. $imageButtonMenu.bindCommandState(minder, 'image');
  47774. var $imageDialog = new FUI.Dialog({
  47775. width: 600,
  47776. height: 600,
  47777. prompt: true,
  47778. className: 'image-dialog',
  47779. caption: minder.getLang('ui.image')
  47780. }).appendTo(document.getElementById('content-wrapper'));
  47781. var $dialogBody = $($imageDialog.getBodyElement());
  47782. // writed by yangxiaohu 2014-10-20
  47783. var tabs = new FUI.Tabs( {
  47784. buttons: [ "图片搜索", "插入图片" ]
  47785. } );
  47786. $dialogBody.html([
  47787. '<div id="img_buttons"></div>',
  47788. '<div id="img_panels"></div>'
  47789. ].join(''));
  47790. tabs.appendButtonTo( document.getElementById( 'img_buttons') );
  47791. tabs.appendPanelTo( document.getElementById( 'img_panels'));
  47792. tabs.getPanel(0).getContentElement().innerHTML = ['<div class="searchBar"><label>关键字:</label><input id="img_searchTxt" type="text" placeholder="请输入搜索关键词">',
  47793. '<button id="img_searchBtn">百度一下</button></div>',
  47794. '<div id="img_searchList"><ul id="img_searchListUl"></ul></div>'
  47795. ].join('');
  47796. tabs.getPanel(1).getContentElement().innerHTML = ['<p><label>图片地址:</label><input type="url" class="image-url fui-widget fui-selectable" /></p>',
  47797. '<p><label>提示文本:</label><input type="text" class="image-title fui-widget fui-selectable" /></p>',
  47798. '<img class="image-preview" src="" style="max-height: 200px;" />'].join('');
  47799. //the content below is from xujinquan's ueditor
  47800. /*搜索图片 */
  47801. $G = function ( id ) {
  47802. return document.getElementById( id )
  47803. };
  47804. function SearchImage() {
  47805. this.init();
  47806. }
  47807. SearchImage.prototype = {
  47808. lang: {
  47809. searchRemind : '请输入搜索关键词',
  47810. searchLoading : '图片加载中,请稍后……',
  47811. searchRetry : '抱歉,没有找到图片!请重试一次!',
  47812. },
  47813. data: {
  47814. imgUrl: '',
  47815. imgTitle: '',
  47816. },
  47817. init: function () {
  47818. this.initEvents();
  47819. },
  47820. initEvents: function(){
  47821. var _this = this;
  47822. /* 点击搜索按钮 */
  47823. $('#img_searchBtn').on('click', function(){
  47824. var key = $G('img_searchTxt').value;
  47825. if(key && key != _this.lang.searchRemind) {
  47826. _this.getImageData();
  47827. }
  47828. });
  47829. /* 搜索框聚焦 */
  47830. $('#img_searchTxt').on('focus', function(){
  47831. var key = $G('img_searchTxt').value;
  47832. if(key && key == _this.lang.searchRemind) {
  47833. $G('img_searchTxt').value = '';
  47834. }
  47835. });
  47836. /* 搜索框回车键搜索 */
  47837. $('#img_searchTxt').on('keydown', function(e){
  47838. var keyCode = e.keyCode || e.which;
  47839. if (keyCode == 13) {
  47840. $G('img_searchBtn').click();
  47841. return false;
  47842. }
  47843. });
  47844. /* 选中图片 */
  47845. $('#img_searchList').on('click', function(e){
  47846. var target = e.target || e.srcElement,
  47847. $li = $(target).closest('li');
  47848. _this.data.imgUrl = $li.find('img').attr('src');
  47849. _this.data.imgTitle = $li.find('span').attr('title');
  47850. $li.siblings('.selected').removeClass('selected');
  47851. $li.addClass('selected');
  47852. });
  47853. },
  47854. /* 改变图片大小 */
  47855. scale: function (img, w, h) {
  47856. var ow = img.width,
  47857. oh = img.height;
  47858. if (ow >= oh) {
  47859. img.width = w * ow / oh;
  47860. img.height = h;
  47861. img.style.marginLeft = '-' + parseInt((img.width - w) / 2) + 'px';
  47862. } else {
  47863. img.width = w;
  47864. img.height = h * oh / ow;
  47865. img.style.marginTop = '-' + parseInt((img.height - h) / 2) + 'px';
  47866. }
  47867. },
  47868. getImageData: function(){
  47869. var _this = this,
  47870. key = $G('img_searchTxt').value,
  47871. keepOriginName = '1';
  47872. url = "http://image.baidu.com/i?ct=201326592&cl=2&lm=-1&st=-1&tn=baiduimagejson&istype=2&rn=3200&fm=index&pv=&word=" + key + "&ie=utf-8&oe=utf-8&keeporiginname=" + keepOriginName + "&" + +new Date;
  47873. $G('img_searchListUl').innerHTML = _this.lang.searchLoading;
  47874. $.ajax({url : url,
  47875. dataType: 'jsonp',
  47876. scriptCharset: 'GB18030',
  47877. success:function(json){
  47878. var list = [];
  47879. if(json && json.data) {
  47880. for(var i = 0; i < json.data.length; i++) {
  47881. if(json.data[i].objURL) {
  47882. list.push({
  47883. title: json.data[i].fromPageTitleEnc,
  47884. src: json.data[i].objURL,
  47885. url: json.data[i].fromURL
  47886. });
  47887. }
  47888. }
  47889. }
  47890. _this.setList(list);
  47891. },
  47892. error:function(){
  47893. $G('img_searchListUl').innerHTML = _this.lang.searchRetry;
  47894. }
  47895. });
  47896. },
  47897. /* 添加图片到列表界面上 */
  47898. setList: function (list) {
  47899. var i, item, p, img, title, _this = this,
  47900. listUl = $G('img_searchListUl');
  47901. listUl.innerHTML = '';
  47902. if(list.length) {
  47903. for (i = 0; i < list.length; i++) {
  47904. item = document.createElement('li');
  47905. img = document.createElement('img');
  47906. title = document.createElement('span');
  47907. img.setAttribute('src', list[i].src);
  47908. title.innerHTML = list[i].title;
  47909. item.appendChild(img);
  47910. item.appendChild(title);
  47911. listUl.appendChild(item);
  47912. img.onerror = function() {
  47913. $(this).closest('li').remove();
  47914. };
  47915. }
  47916. } else {
  47917. listUl.innerHTML = _this.lang.searchRetry;
  47918. }
  47919. },
  47920. getInsertList: function () {
  47921. var child,
  47922. src,
  47923. align = getAlign(),
  47924. list = [],
  47925. items = $G('img_searchListUl').children;
  47926. for(var i = 0; i < items.length; i++) {
  47927. child = items[i].firstChild && items[i].firstChild.firstChild;
  47928. if(child.tagName && child.tagName.toLowerCase() == 'img' && $(items[i]).hasClass('selected')) {
  47929. src = child.src;
  47930. list.push({
  47931. src: src,
  47932. _src: src,
  47933. alt: src.substr(src.lastIndexOf('/') + 1),
  47934. floatStyle: align
  47935. });
  47936. }
  47937. }
  47938. return list;
  47939. }
  47940. };
  47941. var searchImage = new SearchImage();
  47942. // the end content writed by yangxiaohu
  47943. var $url = $dialogBody.find('.image-url');
  47944. var $title = $dialogBody.find('.image-title');
  47945. var $preview = $dialogBody.find('.image-preview');
  47946. var $errorMsg = $('<span class="validate-error"></span>');
  47947. $imageDialog.on('ok', function() {
  47948. var index = tabs.getSelectedIndex();
  47949. switch(index) {
  47950. case 1:
  47951. minder.execCommand('image', $url.val(), $title.val());
  47952. break;
  47953. case 0:
  47954. minder.execCommand('image', searchImage.data.imgUrl, searchImage.data.imgTitle);
  47955. break;
  47956. }
  47957. });
  47958. $imageDialog.on('open', function() {
  47959. var image = minder.queryCommandValue('image');
  47960. $url.val(image.url);
  47961. $title.val(image.title);
  47962. $preview.attr('src', image.url || '');
  47963. error(false);
  47964. });
  47965. function error(value) {
  47966. if (value) {
  47967. $url.addClass('validate-error');
  47968. $errorMsg.text('图片无法加载');
  47969. // $ok.disable();
  47970. } else {
  47971. $url.removeClass('validate-error');
  47972. $errorMsg.text('');
  47973. // $imageDialog.enable();
  47974. }
  47975. return value;
  47976. }
  47977. $url.after($errorMsg);
  47978. $url.on('input', function() {
  47979. var url = $url.val();
  47980. if (/^https?\:\/\/(\w+\.)+\w+/.test(url)) {
  47981. $preview.attr('src', url);
  47982. error(false);
  47983. // $imageDialog.disable();
  47984. $preview.addClass('loading');
  47985. } else {
  47986. error(true);
  47987. }
  47988. });
  47989. $preview.on('load', function() {
  47990. error(false);
  47991. $preview.removeClass('loading');
  47992. }).on('error', function() {
  47993. if ($preview.attr('src')) error(true);
  47994. $preview.removeClass('loading');
  47995. });
  47996. $imageButtonMenu.on('buttonclick', function() {
  47997. $imageDialog.open();
  47998. $url[0].focus();
  47999. });
  48000. $imageButtonMenu.on('select', function() {
  48001. minder.execCommand('removeimage');
  48002. });
  48003. return $imageButtonMenu;
  48004. });
  48005. /**
  48006. * @fileOverview
  48007. *
  48008. * 节点笔记支持
  48009. *
  48010. * @author: techird
  48011. * @copyright: Baidu FEX, 2014
  48012. */
  48013. /* global marked: true */
  48014. KityMinder.registerUI('ribbon/idea/note', function(minder) {
  48015. var axss = minder.getUI('axss');
  48016. marked.setOptions({
  48017. gfm: true,
  48018. breaks: true
  48019. });
  48020. var $attachment = minder.getUI('ribbon/idea/attachment');
  48021. var $noteButtonMenu = new FUI.ButtonMenu({
  48022. id: 'note-button-menu',
  48023. text: minder.getLang('ui.note'),
  48024. layout: 'bottom',
  48025. buttons: [{}, {
  48026. label: minder.getLang('ui.note')
  48027. }],
  48028. menu: {
  48029. items: [minder.getLang('ui.removenote')]
  48030. }
  48031. }).appendTo($attachment);
  48032. $noteButtonMenu.on('select', function() {
  48033. minder.execCommand('note', null);
  48034. });
  48035. var $notePanel = $('<div id="note-panel"></div>');
  48036. var $title = $('<h2>节点备注</h2>').appendTo($notePanel);
  48037. var $close = $('<a class="close"></a>').appendTo($notePanel).click(hide);
  48038. var $tab = $('<div class="tab">' +
  48039. '<a class="edit-tab">编辑</a>' +
  48040. '<a class="preview-tab">预览</a>' +
  48041. '<a class="help" href="https://www.zybuluo.com/techird/note/46064" target="_blank">支持 GFM 语法书写</a>' +
  48042. '</div>').appendTo($notePanel);
  48043. var $editTab = $tab.find('.edit-tab');
  48044. var $previewTab = $tab.find('.preview-tab');
  48045. var $editor = $('<div class="note-editor"></div>').appendTo($notePanel);
  48046. var $preview = $('<div class="note-preview"></div>').appendTo($notePanel);
  48047. var noteVisible = false;
  48048. $notePanel.on('keydown keyup keypress mouedown mouseup click contextmenu', function(e) {
  48049. e.stopPropagation();
  48050. });
  48051. var editor = new window.CodeMirror($editor[0], {
  48052. mode: 'gfm',
  48053. lineWrapping: true,
  48054. dragDrop: false
  48055. });
  48056. minder.on('uiready', function() {
  48057. editor.setSize('100%', '100%');
  48058. });
  48059. var visible = false;
  48060. var selectedNode = null;
  48061. function updateEditorView() {
  48062. if (noteVisible && selectedNode != minder.getSelectedNode()) {
  48063. selectedNode = minder.getSelectedNode();
  48064. var note = minder.queryCommandValue('note') || '';
  48065. editor.setValue(note);
  48066. if (selectedNode) {
  48067. $notePanel.removeAttr('disabled');
  48068. $title.text('备注 - ' + selectedNode.getText());
  48069. } else {
  48070. $notePanel.attr('disabled', 'disabled');
  48071. $title.text('选择节点添加备注');
  48072. }
  48073. if ($previewTab.hasClass(activeTabClass)) {
  48074. $preview.html(axss(marked(note)));
  48075. $preview.find('a').attr('target', '_blank');
  48076. }
  48077. }
  48078. }
  48079. function updateNodeData() {
  48080. if (selectedNode && minder.queryCommandState('note') != -1) {
  48081. minder.execCommand('note', editor.getValue());
  48082. }
  48083. }
  48084. minder.on('interactchange', updateEditorView);
  48085. editor.on('change', updateNodeData);
  48086. $noteButtonMenu.bindCommandState(minder, 'note');
  48087. $noteButtonMenu.on('buttonclick', show);
  48088. minder.on('editnoterequest', show);
  48089. $('#kityminder').after($notePanel);
  48090. hide();
  48091. var activeTabClass = 'active-tab';
  48092. function editMode() {
  48093. if ($editTab.hasClass(activeTabClass)) return;
  48094. $preview.hide();
  48095. $previewTab.removeClass(activeTabClass);
  48096. $editor.show().addClass(activeTabClass);
  48097. $editTab.addClass(activeTabClass);
  48098. var note = minder.queryCommandValue('note') || '';
  48099. editor.setValue(note);
  48100. }
  48101. function previewMode() {
  48102. if ($previewTab.hasClass(activeTabClass)) return;
  48103. $editor.hide();
  48104. $editTab.removeClass(activeTabClass);
  48105. $preview.html(axss(marked(editor.getValue()))).show();
  48106. $preview.find('a').attr('target', '_blank');
  48107. $previewTab.addClass(activeTabClass);
  48108. }
  48109. $editTab.click(editMode);
  48110. $previewTab.click(previewMode);
  48111. function show() {
  48112. noteVisible = true;
  48113. $notePanel.show();
  48114. editMode();
  48115. updateEditorView();
  48116. $('#content-wrapper').addClass('note-panel-visible');
  48117. }
  48118. function hide() {
  48119. noteVisible = false;
  48120. $notePanel.hide();
  48121. $('#content-wrapper').removeClass('note-panel-visible');
  48122. }
  48123. });
  48124. /**
  48125. * @fileOverview
  48126. *
  48127. * 节点笔记支持
  48128. *
  48129. * @author: techird
  48130. * @copyright: Baidu FEX, 2014
  48131. */
  48132. /* global marked: true */
  48133. KityMinder.registerUI('ribbon/idea/notepreview', function(minder) {
  48134. var axss = minder.getUI('axss');
  48135. marked.setOptions({
  48136. gfm: true,
  48137. breaks: true
  48138. });
  48139. var $previewer = $('<div id="note-previewer"></div>').appendTo('#content-wrapper');
  48140. var visible = false;
  48141. var selectedNode = null;
  48142. var previewTimer;
  48143. minder.on('shownoterequest', function(e) {
  48144. previewTimer = setTimeout(function() {
  48145. preview(e.node);
  48146. }, 300);
  48147. });
  48148. minder.on('hidenoterequest', function() {
  48149. clearTimeout(previewTimer);
  48150. });
  48151. var previewLive = false;
  48152. $('#kityminder').on('mousedown mousewheel DOMMouseScroll', function() {
  48153. if (!previewLive) return;
  48154. $previewer.fadeOut();
  48155. previewLive = false;
  48156. });
  48157. $previewer.hide();
  48158. function preview(node, keyword) {
  48159. var icon = node.getRenderer('NoteIconRenderer').getRenderShape();
  48160. var b = icon.getRenderBox('screen');
  48161. var note = node.getData('note');
  48162. $previewer[0].scrollTop = 0;
  48163. var html = marked(note);
  48164. if (keyword) {
  48165. html = html.replace(new RegExp('(' + keyword + ')', 'ig'), '<span class="highlight">$1</span>');
  48166. }
  48167. $previewer.html(axss(html));
  48168. var cw = $('#content-wrapper').width();
  48169. var ch = $('#content-wrapper').height();
  48170. var pw = $previewer.outerWidth();
  48171. var ph = $previewer.outerHeight();
  48172. var x = b.cx - pw / 2;
  48173. var y = b.bottom + 10;
  48174. if (x < 0) x = 10;
  48175. if (x + pw > cw) x = cw - pw - 10;
  48176. if (y + ph > ch) y = b.top - ph - 10;
  48177. $previewer.css({
  48178. left: Math.round(x),
  48179. top: Math.round(y)
  48180. });
  48181. $previewer.show();
  48182. var view = $previewer[0].querySelector('.highlight');
  48183. if (view) {
  48184. view.scrollIntoView();
  48185. }
  48186. previewLive = true;
  48187. }
  48188. $previewer.delegate('a', 'click', function(e) {
  48189. var $a = $(e.target).closest('a');
  48190. var href = $a.prop('href');
  48191. if (window.confirm(minder.getLang('ui.redirect', href))) {
  48192. window.open(href, '_blank');
  48193. }
  48194. e.preventDefault();
  48195. });
  48196. return {
  48197. preview: preview,
  48198. hide: function() {
  48199. $previewer.hide();
  48200. }
  48201. };
  48202. });
  48203. /**
  48204. * @fileOverview
  48205. *
  48206. * 添加和修改优先级标签
  48207. *
  48208. * @author: techird
  48209. * @copyright: Baidu FEX, 2014
  48210. */
  48211. KityMinder.registerUI('ribbon/idea/priority', function(minder) {
  48212. var $commandbuttonset = minder.getUI('widget/commandbuttonset');
  48213. var $tabs = minder.getUI('ribbon/tabs');
  48214. var $priorityPanel = new FUI.LabelPanel({
  48215. label: minder.getLang('panels.priority')
  48216. }).appendTo($tabs.idea);
  48217. $commandbuttonset.generate('priority', [1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map(function(p) {
  48218. return {
  48219. label: p,
  48220. text: minder.getLang('ui.priority') + p,
  48221. value: p,
  48222. className: ['priority', p].join('-')
  48223. };
  48224. })).appendTo($priorityPanel);
  48225. return $priorityPanel;
  48226. });
  48227. /**
  48228. * @fileOverview
  48229. *
  48230. * 添加和修改进度标签
  48231. *
  48232. * @author: techird
  48233. * @copyright: Baidu FEX, 2014
  48234. */
  48235. KityMinder.registerUI('ribbon/idea/progress', function(minder) {
  48236. var $commandbuttonset = minder.getUI('widget/commandbuttonset');
  48237. var $tabs = minder.getUI('ribbon/tabs');
  48238. var $progressPanel = new FUI.LabelPanel({
  48239. label: minder.getLang('panels.progress')
  48240. }).appendTo($tabs.idea);
  48241. $commandbuttonset.generate('progress', [1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map(function(p) {
  48242. return {
  48243. label: p,
  48244. text: minder.getLang('ui.progress.p' + p),
  48245. value: p,
  48246. className: ['progress', p].join('-')
  48247. };
  48248. })).appendTo($progressPanel);
  48249. return $progressPanel;
  48250. });
  48251. /**
  48252. * @fileOverview
  48253. *
  48254. * 添加和管理资源标签
  48255. *
  48256. * @author: techird
  48257. * @copyright: Baidu FEX, 2014
  48258. */
  48259. KityMinder.registerUI('ribbon/idea/resource', function(minder) {
  48260. var $commandbuttonset = minder.getUI('widget/commandbuttonset');
  48261. var $tabs = minder.getUI('ribbon/tabs');
  48262. var $resourcePanel = new FUI.LabelPanel({
  48263. label: minder.getLang('panels.resource'),
  48264. id: 'resource-panel'
  48265. }).appendTo($tabs.idea);
  48266. var $addInput = new FUI.Input().appendTo($resourcePanel);
  48267. $addInput.getElement().type = 'text';
  48268. var $addButton = new FUI.Button({
  48269. label: '添加'
  48270. }).appendTo($resourcePanel);
  48271. var $resourceDrop = new FUI.DropPanel().appendTo($resourcePanel);
  48272. var $dropContainer = $($resourceDrop.getPanelElement());
  48273. var $ul = $('<ul></ul>').addClass('resource-list').appendTo($dropContainer);
  48274. var $list = [];
  48275. function addResource() {
  48276. var resource = $addInput.getValue();
  48277. var origin = minder.queryCommandValue('resource');
  48278. if (/\S/.test(resource)) {
  48279. if (!~origin.indexOf(resource)) origin.push(resource);
  48280. origin.sort();
  48281. minder.execCommand('resource', origin);
  48282. }
  48283. $addInput.setValue(null);
  48284. update();
  48285. $addInput.focus();
  48286. }
  48287. $addInput.on('inputcomplete', function(e) {
  48288. addResource();
  48289. });
  48290. $addButton.on('click', addResource);
  48291. $dropContainer.delegate('input[type=checkbox]', 'change', function() {
  48292. minder.execCommand('resource', $dropContainer.find('input[type=checkbox]:checked').map(function(index, chk) {
  48293. return $(chk).data('resource');
  48294. }).toArray());
  48295. update();
  48296. });
  48297. function hash(resource, used) {
  48298. return [resource.join(','), used.join(',')].join(';');
  48299. }
  48300. function changed(resource, used) {
  48301. var currentHash = hash(resource, used);
  48302. if (currentHash == changed.lastHash) return false;
  48303. changed.lastHash = currentHash;
  48304. return true;
  48305. }
  48306. function update() {
  48307. var resource = minder.queryCommandValue('resource');
  48308. var used = minder.getUsedResource();
  48309. used.sort();
  48310. switch (minder.queryCommandState('resource')) {
  48311. case 0:
  48312. $addInput.enable();
  48313. $addButton.enable();
  48314. $resourceDrop.enable();
  48315. $ul.find('input[type=checkbox]').removeAttr('disabled');
  48316. break;
  48317. case -1:
  48318. $addInput.disable();
  48319. $addButton.disable();
  48320. $resourceDrop.disable();
  48321. $ul.find('input[type=checkbox]').attr('disabled', true);
  48322. break;
  48323. }
  48324. if (!changed(resource, used)) return;
  48325. var delta = used.length - $ul.children().length;
  48326. while (delta--) $ul.append('<li><label><input type="checkbox" /><span></span></label></li>');
  48327. while (++delta) $ul.children().first().remove();
  48328. used.forEach(function(name, index) {
  48329. var $li = $ul.children().eq(index);
  48330. var $label = $li.find('label');
  48331. var $chk = $label.find('input');
  48332. var $span = $label.find('span');
  48333. $chk.data('resource', name);
  48334. $chk.prop('checked', ~resource.indexOf(name));
  48335. $span.text(name);
  48336. var color = minder.getResourceColor(name);
  48337. $li.css({
  48338. color: color.dec('l', 60).toString(),
  48339. backgroundColor: ~resource.indexOf(name) ? color : color.dec('a', 0.85).toRGBA()
  48340. });
  48341. });
  48342. }
  48343. minder.on('interactchange', update);
  48344. return $resourcePanel;
  48345. });
  48346. /**
  48347. * @fileOverview
  48348. *
  48349. * 模板选择
  48350. *
  48351. * @author: techird
  48352. * @copyright: Baidu FEX, 2014
  48353. */
  48354. KityMinder.registerUI('ribbon/appearence/template', function(minder) {
  48355. var $commandselectmenu = minder.getUI('widget/commandselectmenu');
  48356. var $tabs = minder.getUI('ribbon/tabs');
  48357. var $templatePanel = new FUI.LabelPanel({
  48358. id: 'template-panel',
  48359. label: minder.getLang('panels.template')
  48360. });
  48361. var templateList = KityMinder.Utils.keys(KityMinder.getTemplateList());
  48362. var $templateSelect = $commandselectmenu.generate('template', templateList, 2);
  48363. $tabs.appearence.appendWidget($templatePanel);
  48364. $templatePanel.appendWidget($templateSelect);
  48365. return $templatePanel;
  48366. });
  48367. /**
  48368. * @fileOverview
  48369. *
  48370. * 皮肤选择
  48371. *
  48372. * @author: techird
  48373. * @copyright: Baidu FEX, 2014
  48374. */
  48375. KityMinder.registerUI('ribbon/appearence/theme', function(minder) {
  48376. var $commandselectmenu = minder.getUI('widget/commandselectmenu');
  48377. var $tabs = minder.getUI('ribbon/tabs');
  48378. var $themePanel = new FUI.LabelPanel({
  48379. id: 'theme-panel',
  48380. label: minder.getLang('panels.theme')
  48381. });
  48382. var themeList = KityMinder.Utils.keys(KityMinder.getThemeList());
  48383. var $themeSelect = $commandselectmenu.generate('theme', themeList.map(function(theme) {
  48384. var style = KityMinder._themes[theme];
  48385. return {
  48386. clazz: 'Button',
  48387. label: {
  48388. text: minder.getLang('theme.' + theme),
  48389. style: {
  48390. background: style['root-background'],
  48391. color: style['root-color'],
  48392. borderRadius: style['root-radius'] / 2
  48393. }
  48394. },
  48395. text: minder.getLang('theme.' + theme),
  48396. value: theme,
  48397. className: ['theme', theme].join(' ')
  48398. };
  48399. }));
  48400. $tabs.appearence.appendWidget($themePanel);
  48401. $themePanel.appendWidget($themeSelect);
  48402. minder.on('themechange', function(e) {
  48403. $('#content-wrapper').css('background', minder.getStyle('background'));
  48404. });
  48405. return $themePanel;
  48406. });
  48407. /**
  48408. * @fileOverview
  48409. *
  48410. * 布局面板
  48411. *
  48412. * @author: techird
  48413. * @copyright: Baidu FEX, 2014
  48414. */
  48415. KityMinder.registerUI('ribbon/appearence/layout', function(minder) {
  48416. var $tabs = minder.getUI('ribbon/tabs');
  48417. // var $commandbuttonset = minder.getUI('widget/commandbuttonset');
  48418. var $commandbutton = minder.getUI('widget/commandbutton');
  48419. var $layoutPanel = new FUI.LabelPanel({
  48420. id: 'layout-panel',
  48421. label: minder.getLang('panels.layout')
  48422. }).appendTo($tabs.appearence);
  48423. // var $layoutSelect = new FUI.DropPanel({
  48424. // id: 'layout-select'
  48425. // }).appendTo($layoutPanel);
  48426. // var layoutList = KityMinder.Utils.keys(KityMinder.getLayoutList());
  48427. // $layoutSelect.appendWidget($commandbuttonset.generate('layout', layoutList));
  48428. $commandbutton.generate('resetlayout').appendTo($layoutPanel).addClass('large');
  48429. return $layoutPanel;
  48430. });
  48431. /**
  48432. * @fileOverview
  48433. *
  48434. * 样式控制
  48435. *
  48436. * @author: techird
  48437. * @copyright: Baidu FEX, 2014
  48438. */
  48439. KityMinder.registerUI('ribbon/appearence/style', function(minder) {
  48440. var $tabs = minder.getUI('ribbon/tabs');
  48441. var $commandbutton = minder.getUI('widget/commandbutton');
  48442. var $stylePanel = new FUI.LabelPanel({
  48443. label: minder.getLang('panels.style')
  48444. }).appendTo($tabs.appearence);
  48445. $commandbutton.generate('clearstyle').addClass('large').appendTo($stylePanel);
  48446. var $styleClipPanel = new FUI.Panel({
  48447. column: true
  48448. }).appendTo($stylePanel);
  48449. $commandbutton.generate('copystyle').appendTo($styleClipPanel);
  48450. $commandbutton.generate('pastestyle').appendTo($styleClipPanel);
  48451. return $stylePanel;
  48452. });
  48453. /**
  48454. * @fileOverview
  48455. *
  48456. * 字体设置(字体字号加粗斜体)
  48457. *
  48458. * @author: techird
  48459. * @copyright: Baidu FEX, 2014
  48460. */
  48461. KityMinder.registerUI('ribbon/appearence/font', function(minder) {
  48462. var $tabs = minder.getUI('ribbon/tabs');
  48463. var commandinputmenu = minder.getUI('widget/commandinputmenu');
  48464. var commandbutton = minder.getUI('widget/commandbutton');
  48465. var $fontPanel = new FUI.LabelPanel({
  48466. label: minder.getLang('panels.font'),
  48467. id: 'font-panel'
  48468. });
  48469. var $leftPanel = new FUI.Panel({
  48470. column: true
  48471. });
  48472. var $rightPanel = new FUI.Panel({
  48473. column: true
  48474. });
  48475. var $fontFamilyMenu = commandinputmenu.generate('fontfamily', minder.getOptions('fontfamily').map(function(ff) {
  48476. return {
  48477. label: {
  48478. text: ff.name,
  48479. style: {
  48480. fontFamily: ff.val
  48481. }
  48482. },
  48483. text: ff.name,
  48484. value: ff.val
  48485. };
  48486. }));
  48487. var $fontSizeMenu = commandinputmenu.generate('fontsize', minder.getOptions('fontsize').map(function(fs) {
  48488. return {
  48489. label: {
  48490. text: fs,
  48491. style: {
  48492. fontSize: fs
  48493. }
  48494. },
  48495. text: fs,
  48496. value: fs
  48497. };
  48498. }));
  48499. $leftPanel.appendWidgets([$fontFamilyMenu, $fontSizeMenu]);
  48500. var $boldButton = commandbutton.generate('bold');
  48501. var $italicButton = commandbutton.generate('italic');
  48502. $rightPanel.appendWidgets([$boldButton, $italicButton]);
  48503. $fontPanel.appendWidgets([$leftPanel, $rightPanel]);
  48504. $tabs.appearence.appendWidget($fontPanel);
  48505. });
  48506. /**
  48507. * @fileOverview
  48508. *
  48509. * 节点颜色设置(包括和背景)
  48510. *
  48511. * @author: techird
  48512. * @copyright: Baidu FEX, 2014
  48513. */
  48514. KityMinder.registerUI('ribbon/appearence/color', function(minder) {
  48515. function generateSerisColor() {
  48516. return ['#e75d66', '#fac75b', '#99ca6a', '#00c5ad', '#3bbce0', '#c9ced1', '#425b71', 'white'];
  48517. }
  48518. var $commandbuttonset = minder.getUI('widget/commandbuttonset');
  48519. var $tabs = minder.getUI('ribbon/tabs');
  48520. var $colorPanel = new FUI.LabelPanel({
  48521. label: minder.getLang('panels.color')
  48522. }).appendTo($tabs.appearence);
  48523. var $backgroundPanel = new FUI.LabelPanel({
  48524. label: minder.getLang('panels.background')
  48525. }).appendTo($tabs.appearence);
  48526. var foreColorList = generateSerisColor();
  48527. $colorPanel.appendWidget($commandbuttonset.generate('forecolor', foreColorList.map(function(color) {
  48528. return {
  48529. icon: {
  48530. style: {
  48531. background: color
  48532. }
  48533. },
  48534. label: color,
  48535. text: color,
  48536. value: color
  48537. };
  48538. })).addClass('color-picker'));
  48539. $backgroundPanel.appendWidget($commandbuttonset.generate('background', foreColorList.map(function(color) {
  48540. return {
  48541. icon: {
  48542. style: {
  48543. background: color
  48544. }
  48545. },
  48546. label: color,
  48547. text: color,
  48548. value: color
  48549. };
  48550. })).addClass('color-picker'));
  48551. return {
  48552. color: $colorPanel,
  48553. background: $backgroundPanel
  48554. };
  48555. });
  48556. /**
  48557. * @fileOverview
  48558. *
  48559. * 全屏无打扰模式
  48560. *
  48561. * @author: techird
  48562. * @copyright: Baidu FEX, 2014
  48563. */
  48564. KityMinder.registerUI('ribbon/view/fullscreen', function(minder) {
  48565. var $commandbutton = minder.getUI('widget/commandbutton');
  48566. var $tabs = minder.getUI('ribbon/tabs');
  48567. var notice = minder.getUI('widget/notice');
  48568. var $fullscreenPanel = new FUI.LabelPanel({
  48569. label: minder.getLang('panels.level'),
  48570. column: true
  48571. }).appendTo($tabs.view);
  48572. var $fullscreenButton = $commandbutton
  48573. .generate('fullscreen', fullscreen)
  48574. .addClass('large')
  48575. .appendTo($fullscreenPanel);
  48576. function fullscreen() {
  48577. if ($('#content-wrapper').toggleClass('fullscreen').hasClass('fullscreen')) {
  48578. notice.info(minder.getLang('ui.fullscreen_exit_hint'), false, 4000);
  48579. }
  48580. }
  48581. minder.addShortcut('F11', fullscreen);
  48582. minder.addShortcut('Esc', function () {
  48583. if ($('#content-wrapper').hasClass('fullscreen')) {
  48584. $('#content-wrapper').removeClass('fullscreen');
  48585. }
  48586. });
  48587. return $fullscreenButton;
  48588. });
  48589. /**
  48590. * @fileOverview
  48591. *
  48592. * 切换展开层次
  48593. *
  48594. * @author: techird
  48595. * @copyright: Baidu FEX, 2014
  48596. */
  48597. KityMinder.registerUI('ribbon/view/level', function(minder) {
  48598. var $commandbutton = minder.getUI('widget/commandbutton');
  48599. var $tabs = minder.getUI('ribbon/tabs');
  48600. var $levelPanel = new FUI.LabelPanel({
  48601. label: minder.getLang('panels.level'),
  48602. column: true
  48603. }).appendTo($tabs.view);
  48604. var $levelButtonMenu = new FUI.ButtonMenu({
  48605. id: 'level-button-menu',
  48606. text: minder.getLang('ui.level'),
  48607. layout: 'bottom',
  48608. buttons: [{}, {
  48609. label: minder.getLang('ui.expandtoleaf')
  48610. }],
  48611. menu: {
  48612. items: [1, 2, 3, 4, 5, 6].map(function(level) {
  48613. return {
  48614. label: minder.getLang('ui.command.expandtolevel' + level),
  48615. value: level
  48616. };
  48617. })
  48618. }
  48619. }).appendTo($levelPanel);
  48620. $levelButtonMenu.on('buttonclick', function() {
  48621. minder.execCommand('expandtolevel', 9999);
  48622. });
  48623. $levelButtonMenu.on('select', function(e, info) {
  48624. minder.execCommand('expandtolevel', info.value);
  48625. });
  48626. });
  48627. /**
  48628. * @fileOverview
  48629. *
  48630. * 节点选择功能
  48631. *
  48632. * @author: techird
  48633. * @copyright: Baidu FEX, 2014
  48634. */
  48635. KityMinder.registerUI('ribbon/view/select', function(minder) {
  48636. var $tabs = minder.getUI('ribbon/tabs');
  48637. var $selectPanel = new FUI.LabelPanel({
  48638. label: minder.getLang('panels.level'),
  48639. column: true
  48640. }).appendTo($tabs.view);
  48641. var $selectButtonMenu = new FUI.ButtonMenu({
  48642. id: 'select-button-menu',
  48643. text: minder.getLang('ui.select'),
  48644. layout: 'bottom',
  48645. buttons: [{}, {
  48646. label: minder.getLang('ui.selectall')
  48647. }],
  48648. menu: {
  48649. items: ['revert', 'siblings', 'level', 'path', 'tree'].map(function(mode) {
  48650. return {
  48651. label: minder.getLang('ui.select' + mode),
  48652. value: mode
  48653. };
  48654. })
  48655. }
  48656. }).appendTo($selectPanel);
  48657. var select = {
  48658. all: function() {
  48659. var selection = [];
  48660. minder.getRoot().traverse(function(node) {
  48661. selection.push(node);
  48662. });
  48663. minder.select(selection, true);
  48664. },
  48665. revert: function() {
  48666. var selected = minder.getSelectedNodes();
  48667. var selection = [];
  48668. minder.getRoot().traverse(function(node) {
  48669. if (selected.indexOf(node) == -1) {
  48670. selection.push(node);
  48671. }
  48672. });
  48673. minder.select(selection, true);
  48674. },
  48675. siblings: function() {
  48676. var selected = minder.getSelectedNodes();
  48677. var selection = [];
  48678. selected.forEach(function(node) {
  48679. if (!node.parent) return;
  48680. node.parent.children.forEach(function(sibling) {
  48681. if (selection.indexOf(sibling) == -1) selection.push(sibling);
  48682. });
  48683. });
  48684. minder.select(selection, true);
  48685. },
  48686. level: function() {
  48687. var selectedLevel = minder.getSelectedNodes().map(function(node) {
  48688. return node.getLevel();
  48689. });
  48690. var selection = [];
  48691. minder.getRoot().traverse(function(node) {
  48692. if (selectedLevel.indexOf(node.getLevel()) != -1) {
  48693. selection.push(node);
  48694. }
  48695. });
  48696. minder.select(selection, true);
  48697. },
  48698. path: function() {
  48699. var selected = minder.getSelectedNodes();
  48700. var selection = [];
  48701. selected.forEach(function(node) {
  48702. while(node && selection.indexOf(node) == -1) {
  48703. selection.push(node);
  48704. node = node.parent;
  48705. }
  48706. });
  48707. minder.select(selection, true);
  48708. },
  48709. tree: function() {
  48710. var selected = minder.getSelectedNodes();
  48711. var selection = [];
  48712. selected.forEach(function(parent) {
  48713. parent.traverse(function(node) {
  48714. if (selection.indexOf(node) == -1) selection.push(node);
  48715. });
  48716. });
  48717. minder.select(selection, true);
  48718. }
  48719. };
  48720. $selectButtonMenu.on('buttonclick', select.all);
  48721. $selectButtonMenu.on('select', function(e, info) {
  48722. select[info.value]();
  48723. });
  48724. });
  48725. })(window)
  48726. //# sourceMappingURL=kityminder.edit.js.map