e2e.entry.js 1.3 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393
  1. /*!
  2. * (The MIT License)
  3. *
  4. * Copyright (c) 2012-2014 Marcin Warpechowski
  5. * Copyright (c) 2015 Handsoncode sp. z o.o. <hello@handsoncode.net>
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining
  8. * a copy of this software and associated documentation files (the
  9. * 'Software'), to deal in the Software without restriction, including
  10. * without limitation the rights to use, copy, modify, merge, publish,
  11. * distribute, sublicense, and/or sell copies of the Software, and to
  12. * permit persons to whom the Software is furnished to do so, subject to
  13. * the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be
  16. * included in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
  19. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  21. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  22. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. * Version: 0.32.0-beta2
  27. * Date: Tue May 30 2017 12:10:57 GMT+0200 (CEST)
  28. */
  29. /******/ (function(modules) { // webpackBootstrap
  30. /******/ // The module cache
  31. /******/ var installedModules = {};
  32. /******/
  33. /******/ // The require function
  34. /******/ function __webpack_require__(moduleId) {
  35. /******/
  36. /******/ // Check if module is in cache
  37. /******/ if(installedModules[moduleId]) {
  38. /******/ return installedModules[moduleId].exports;
  39. /******/ }
  40. /******/ // Create a new module (and put it into the cache)
  41. /******/ var module = installedModules[moduleId] = {
  42. /******/ i: moduleId,
  43. /******/ l: false,
  44. /******/ exports: {}
  45. /******/ };
  46. /******/
  47. /******/ // Execute the module function
  48. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  49. /******/
  50. /******/ // Flag the module as loaded
  51. /******/ module.l = true;
  52. /******/
  53. /******/ // Return the exports of the module
  54. /******/ return module.exports;
  55. /******/ }
  56. /******/
  57. /******/
  58. /******/ // expose the modules object (__webpack_modules__)
  59. /******/ __webpack_require__.m = modules;
  60. /******/
  61. /******/ // expose the module cache
  62. /******/ __webpack_require__.c = installedModules;
  63. /******/
  64. /******/ // identity function for calling harmony imports with the correct context
  65. /******/ __webpack_require__.i = function(value) { return value; };
  66. /******/
  67. /******/ // define getter function for harmony exports
  68. /******/ __webpack_require__.d = function(exports, name, getter) {
  69. /******/ if(!__webpack_require__.o(exports, name)) {
  70. /******/ Object.defineProperty(exports, name, {
  71. /******/ configurable: false,
  72. /******/ enumerable: true,
  73. /******/ get: getter
  74. /******/ });
  75. /******/ }
  76. /******/ };
  77. /******/
  78. /******/ // getDefaultExport function for compatibility with non-harmony modules
  79. /******/ __webpack_require__.n = function(module) {
  80. /******/ var getter = module && module.__esModule ?
  81. /******/ function getDefault() { return module['default']; } :
  82. /******/ function getModuleExports() { return module; };
  83. /******/ __webpack_require__.d(getter, 'a', getter);
  84. /******/ return getter;
  85. /******/ };
  86. /******/
  87. /******/ // Object.prototype.hasOwnProperty.call
  88. /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  89. /******/
  90. /******/ // __webpack_public_path__
  91. /******/ __webpack_require__.p = "";
  92. /******/
  93. /******/ // Load entry module and return exports
  94. /******/ return __webpack_require__(__webpack_require__.s = 216);
  95. /******/ })
  96. /************************************************************************/
  97. /******/ ([
  98. /* 0 */
  99. /***/ (function(module, exports, __webpack_require__) {
  100. var global = __webpack_require__(2)
  101. , core = __webpack_require__(20)
  102. , hide = __webpack_require__(13)
  103. , redefine = __webpack_require__(14)
  104. , ctx = __webpack_require__(10)
  105. , PROTOTYPE = 'prototype';
  106. var $export = function(type, name, source){
  107. var IS_FORCED = type & $export.F
  108. , IS_GLOBAL = type & $export.G
  109. , IS_STATIC = type & $export.S
  110. , IS_PROTO = type & $export.P
  111. , IS_BIND = type & $export.B
  112. , target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {})[PROTOTYPE]
  113. , exports = IS_GLOBAL ? core : core[name] || (core[name] = {})
  114. , expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {})
  115. , key, own, out, exp;
  116. if(IS_GLOBAL)source = name;
  117. for(key in source){
  118. // contains in native
  119. own = !IS_FORCED && target && target[key] !== undefined;
  120. // export native or passed
  121. out = (own ? target : source)[key];
  122. // bind timers to global for call from export context
  123. exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
  124. // extend global
  125. if(target)redefine(target, key, out, type & $export.U);
  126. // export
  127. if(exports[key] != out)hide(exports, key, exp);
  128. if(IS_PROTO && expProto[key] != out)expProto[key] = out;
  129. }
  130. };
  131. global.core = core;
  132. // type bitmap
  133. $export.F = 1; // forced
  134. $export.G = 2; // global
  135. $export.S = 4; // static
  136. $export.P = 8; // proto
  137. $export.B = 16; // bind
  138. $export.W = 32; // wrap
  139. $export.U = 64; // safe
  140. $export.R = 128; // real proto method for `library`
  141. module.exports = $export;
  142. /***/ }),
  143. /* 1 */
  144. /***/ (function(module, exports, __webpack_require__) {
  145. var store = __webpack_require__(47)('wks')
  146. , uid = __webpack_require__(25)
  147. , Symbol = __webpack_require__(2).Symbol
  148. , USE_SYMBOL = typeof Symbol == 'function';
  149. var $exports = module.exports = function(name){
  150. return store[name] || (store[name] =
  151. USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));
  152. };
  153. $exports.store = store;
  154. /***/ }),
  155. /* 2 */
  156. /***/ (function(module, exports) {
  157. // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
  158. var global = module.exports = typeof window != 'undefined' && window.Math == Math
  159. ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();
  160. if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef
  161. /***/ }),
  162. /* 3 */
  163. /***/ (function(module, exports) {
  164. module.exports = function(it){
  165. return typeof it === 'object' ? it !== null : typeof it === 'function';
  166. };
  167. /***/ }),
  168. /* 4 */
  169. /***/ (function(module, exports, __webpack_require__) {
  170. var isObject = __webpack_require__(3);
  171. module.exports = function(it){
  172. if(!isObject(it))throw TypeError(it + ' is not an object!');
  173. return it;
  174. };
  175. /***/ }),
  176. /* 5 */
  177. /***/ (function(module, exports, __webpack_require__) {
  178. var anObject = __webpack_require__(4)
  179. , IE8_DOM_DEFINE = __webpack_require__(57)
  180. , toPrimitive = __webpack_require__(50)
  181. , dP = Object.defineProperty;
  182. exports.f = __webpack_require__(6) ? Object.defineProperty : function defineProperty(O, P, Attributes){
  183. anObject(O);
  184. P = toPrimitive(P, true);
  185. anObject(Attributes);
  186. if(IE8_DOM_DEFINE)try {
  187. return dP(O, P, Attributes);
  188. } catch(e){ /* empty */ }
  189. if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!');
  190. if('value' in Attributes)O[P] = Attributes.value;
  191. return O;
  192. };
  193. /***/ }),
  194. /* 6 */
  195. /***/ (function(module, exports, __webpack_require__) {
  196. // Thank's IE8 for his funny defineProperty
  197. module.exports = !__webpack_require__(12)(function(){
  198. return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7;
  199. });
  200. /***/ }),
  201. /* 7 */
  202. /***/ (function(module, exports) {
  203. var hasOwnProperty = {}.hasOwnProperty;
  204. module.exports = function(it, key){
  205. return hasOwnProperty.call(it, key);
  206. };
  207. /***/ }),
  208. /* 8 */
  209. /***/ (function(module, exports, __webpack_require__) {
  210. // to indexed object, toObject with fallback for non-array-like ES3 strings
  211. var IObject = __webpack_require__(41)
  212. , defined = __webpack_require__(11);
  213. module.exports = function(it){
  214. return IObject(defined(it));
  215. };
  216. /***/ }),
  217. /* 9 */
  218. /***/ (function(module, exports, __webpack_require__) {
  219. // 7.1.15 ToLength
  220. var toInteger = __webpack_require__(35)
  221. , min = Math.min;
  222. module.exports = function(it){
  223. return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
  224. };
  225. /***/ }),
  226. /* 10 */
  227. /***/ (function(module, exports, __webpack_require__) {
  228. // optional / simple context binding
  229. var aFunction = __webpack_require__(36);
  230. module.exports = function(fn, that, length){
  231. aFunction(fn);
  232. if(that === undefined)return fn;
  233. switch(length){
  234. case 1: return function(a){
  235. return fn.call(that, a);
  236. };
  237. case 2: return function(a, b){
  238. return fn.call(that, a, b);
  239. };
  240. case 3: return function(a, b, c){
  241. return fn.call(that, a, b, c);
  242. };
  243. }
  244. return function(/* ...args */){
  245. return fn.apply(that, arguments);
  246. };
  247. };
  248. /***/ }),
  249. /* 11 */
  250. /***/ (function(module, exports) {
  251. // 7.2.1 RequireObjectCoercible(argument)
  252. module.exports = function(it){
  253. if(it == undefined)throw TypeError("Can't call method on " + it);
  254. return it;
  255. };
  256. /***/ }),
  257. /* 12 */
  258. /***/ (function(module, exports) {
  259. module.exports = function(exec){
  260. try {
  261. return !!exec();
  262. } catch(e){
  263. return true;
  264. }
  265. };
  266. /***/ }),
  267. /* 13 */
  268. /***/ (function(module, exports, __webpack_require__) {
  269. var dP = __webpack_require__(5)
  270. , createDesc = __webpack_require__(18);
  271. module.exports = __webpack_require__(6) ? function(object, key, value){
  272. return dP.f(object, key, createDesc(1, value));
  273. } : function(object, key, value){
  274. object[key] = value;
  275. return object;
  276. };
  277. /***/ }),
  278. /* 14 */
  279. /***/ (function(module, exports, __webpack_require__) {
  280. var global = __webpack_require__(2)
  281. , hide = __webpack_require__(13)
  282. , has = __webpack_require__(7)
  283. , SRC = __webpack_require__(25)('src')
  284. , TO_STRING = 'toString'
  285. , $toString = Function[TO_STRING]
  286. , TPL = ('' + $toString).split(TO_STRING);
  287. __webpack_require__(20).inspectSource = function(it){
  288. return $toString.call(it);
  289. };
  290. (module.exports = function(O, key, val, safe){
  291. var isFunction = typeof val == 'function';
  292. if(isFunction)has(val, 'name') || hide(val, 'name', key);
  293. if(O[key] === val)return;
  294. if(isFunction)has(val, SRC) || hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key)));
  295. if(O === global){
  296. O[key] = val;
  297. } else {
  298. if(!safe){
  299. delete O[key];
  300. hide(O, key, val);
  301. } else {
  302. if(O[key])O[key] = val;
  303. else hide(O, key, val);
  304. }
  305. }
  306. // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
  307. })(Function.prototype, TO_STRING, function toString(){
  308. return typeof this == 'function' && this[SRC] || $toString.call(this);
  309. });
  310. /***/ }),
  311. /* 15 */
  312. /***/ (function(module, exports, __webpack_require__) {
  313. // 22.1.3.31 Array.prototype[@@unscopables]
  314. var UNSCOPABLES = __webpack_require__(1)('unscopables')
  315. , ArrayProto = Array.prototype;
  316. if(ArrayProto[UNSCOPABLES] == undefined)__webpack_require__(13)(ArrayProto, UNSCOPABLES, {});
  317. module.exports = function(key){
  318. ArrayProto[UNSCOPABLES][key] = true;
  319. };
  320. /***/ }),
  321. /* 16 */
  322. /***/ (function(module, exports) {
  323. var toString = {}.toString;
  324. module.exports = function(it){
  325. return toString.call(it).slice(8, -1);
  326. };
  327. /***/ }),
  328. /* 17 */
  329. /***/ (function(module, exports, __webpack_require__) {
  330. // 19.1.2.14 / 15.2.3.14 Object.keys(O)
  331. var $keys = __webpack_require__(66)
  332. , enumBugKeys = __webpack_require__(39);
  333. module.exports = Object.keys || function keys(O){
  334. return $keys(O, enumBugKeys);
  335. };
  336. /***/ }),
  337. /* 18 */
  338. /***/ (function(module, exports) {
  339. module.exports = function(bitmap, value){
  340. return {
  341. enumerable : !(bitmap & 1),
  342. configurable: !(bitmap & 2),
  343. writable : !(bitmap & 4),
  344. value : value
  345. };
  346. };
  347. /***/ }),
  348. /* 19 */
  349. /***/ (function(module, exports, __webpack_require__) {
  350. // 7.1.13 ToObject(argument)
  351. var defined = __webpack_require__(11);
  352. module.exports = function(it){
  353. return Object(defined(it));
  354. };
  355. /***/ }),
  356. /* 20 */
  357. /***/ (function(module, exports) {
  358. var core = module.exports = {version: '2.4.0'};
  359. if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef
  360. /***/ }),
  361. /* 21 */
  362. /***/ (function(module, exports) {
  363. module.exports = {};
  364. /***/ }),
  365. /* 22 */
  366. /***/ (function(module, exports, __webpack_require__) {
  367. var META = __webpack_require__(25)('meta')
  368. , isObject = __webpack_require__(3)
  369. , has = __webpack_require__(7)
  370. , setDesc = __webpack_require__(5).f
  371. , id = 0;
  372. var isExtensible = Object.isExtensible || function(){
  373. return true;
  374. };
  375. var FREEZE = !__webpack_require__(12)(function(){
  376. return isExtensible(Object.preventExtensions({}));
  377. });
  378. var setMeta = function(it){
  379. setDesc(it, META, {value: {
  380. i: 'O' + ++id, // object ID
  381. w: {} // weak collections IDs
  382. }});
  383. };
  384. var fastKey = function(it, create){
  385. // return primitive with prefix
  386. if(!isObject(it))return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
  387. if(!has(it, META)){
  388. // can't set metadata to uncaught frozen object
  389. if(!isExtensible(it))return 'F';
  390. // not necessary to add metadata
  391. if(!create)return 'E';
  392. // add missing metadata
  393. setMeta(it);
  394. // return object ID
  395. } return it[META].i;
  396. };
  397. var getWeak = function(it, create){
  398. if(!has(it, META)){
  399. // can't set metadata to uncaught frozen object
  400. if(!isExtensible(it))return true;
  401. // not necessary to add metadata
  402. if(!create)return false;
  403. // add missing metadata
  404. setMeta(it);
  405. // return hash weak collections IDs
  406. } return it[META].w;
  407. };
  408. // add metadata on freeze-family methods calling
  409. var onFreeze = function(it){
  410. if(FREEZE && meta.NEED && isExtensible(it) && !has(it, META))setMeta(it);
  411. return it;
  412. };
  413. var meta = module.exports = {
  414. KEY: META,
  415. NEED: false,
  416. fastKey: fastKey,
  417. getWeak: getWeak,
  418. onFreeze: onFreeze
  419. };
  420. /***/ }),
  421. /* 23 */
  422. /***/ (function(module, exports) {
  423. exports.f = {}.propertyIsEnumerable;
  424. /***/ }),
  425. /* 24 */
  426. /***/ (function(module, exports, __webpack_require__) {
  427. var def = __webpack_require__(5).f
  428. , has = __webpack_require__(7)
  429. , TAG = __webpack_require__(1)('toStringTag');
  430. module.exports = function(it, tag, stat){
  431. if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag});
  432. };
  433. /***/ }),
  434. /* 25 */
  435. /***/ (function(module, exports) {
  436. var id = 0
  437. , px = Math.random();
  438. module.exports = function(key){
  439. return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
  440. };
  441. /***/ }),
  442. /* 26 */
  443. /***/ (function(module, exports) {
  444. module.exports = function(it, Constructor, name, forbiddenField){
  445. if(!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)){
  446. throw TypeError(name + ': incorrect invocation!');
  447. } return it;
  448. };
  449. /***/ }),
  450. /* 27 */
  451. /***/ (function(module, exports, __webpack_require__) {
  452. // 0 -> Array#forEach
  453. // 1 -> Array#map
  454. // 2 -> Array#filter
  455. // 3 -> Array#some
  456. // 4 -> Array#every
  457. // 5 -> Array#find
  458. // 6 -> Array#findIndex
  459. var ctx = __webpack_require__(10)
  460. , IObject = __webpack_require__(41)
  461. , toObject = __webpack_require__(19)
  462. , toLength = __webpack_require__(9)
  463. , asc = __webpack_require__(250);
  464. module.exports = function(TYPE, $create){
  465. var IS_MAP = TYPE == 1
  466. , IS_FILTER = TYPE == 2
  467. , IS_SOME = TYPE == 3
  468. , IS_EVERY = TYPE == 4
  469. , IS_FIND_INDEX = TYPE == 6
  470. , NO_HOLES = TYPE == 5 || IS_FIND_INDEX
  471. , create = $create || asc;
  472. return function($this, callbackfn, that){
  473. var O = toObject($this)
  474. , self = IObject(O)
  475. , f = ctx(callbackfn, that, 3)
  476. , length = toLength(self.length)
  477. , index = 0
  478. , result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined
  479. , val, res;
  480. for(;length > index; index++)if(NO_HOLES || index in self){
  481. val = self[index];
  482. res = f(val, index, O);
  483. if(TYPE){
  484. if(IS_MAP)result[index] = res; // map
  485. else if(res)switch(TYPE){
  486. case 3: return true; // some
  487. case 5: return val; // find
  488. case 6: return index; // findIndex
  489. case 2: result.push(val); // filter
  490. } else if(IS_EVERY)return false; // every
  491. }
  492. }
  493. return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result;
  494. };
  495. };
  496. /***/ }),
  497. /* 28 */
  498. /***/ (function(module, exports, __webpack_require__) {
  499. "use strict";
  500. var global = __webpack_require__(2)
  501. , $export = __webpack_require__(0)
  502. , redefine = __webpack_require__(14)
  503. , redefineAll = __webpack_require__(33)
  504. , meta = __webpack_require__(22)
  505. , forOf = __webpack_require__(30)
  506. , anInstance = __webpack_require__(26)
  507. , isObject = __webpack_require__(3)
  508. , fails = __webpack_require__(12)
  509. , $iterDetect = __webpack_require__(42)
  510. , setToStringTag = __webpack_require__(24)
  511. , inheritIfRequired = __webpack_require__(253);
  512. module.exports = function(NAME, wrapper, methods, common, IS_MAP, IS_WEAK){
  513. var Base = global[NAME]
  514. , C = Base
  515. , ADDER = IS_MAP ? 'set' : 'add'
  516. , proto = C && C.prototype
  517. , O = {};
  518. var fixMethod = function(KEY){
  519. var fn = proto[KEY];
  520. redefine(proto, KEY,
  521. KEY == 'delete' ? function(a){
  522. return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a);
  523. } : KEY == 'has' ? function has(a){
  524. return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a);
  525. } : KEY == 'get' ? function get(a){
  526. return IS_WEAK && !isObject(a) ? undefined : fn.call(this, a === 0 ? 0 : a);
  527. } : KEY == 'add' ? function add(a){ fn.call(this, a === 0 ? 0 : a); return this; }
  528. : function set(a, b){ fn.call(this, a === 0 ? 0 : a, b); return this; }
  529. );
  530. };
  531. if(typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function(){
  532. new C().entries().next();
  533. }))){
  534. // create collection constructor
  535. C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER);
  536. redefineAll(C.prototype, methods);
  537. meta.NEED = true;
  538. } else {
  539. var instance = new C
  540. // early implementations not supports chaining
  541. , HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance
  542. // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
  543. , THROWS_ON_PRIMITIVES = fails(function(){ instance.has(1); })
  544. // most early implementations doesn't supports iterables, most modern - not close it correctly
  545. , ACCEPT_ITERABLES = $iterDetect(function(iter){ new C(iter); }) // eslint-disable-line no-new
  546. // for early implementations -0 and +0 not the same
  547. , BUGGY_ZERO = !IS_WEAK && fails(function(){
  548. // V8 ~ Chromium 42- fails only with 5+ elements
  549. var $instance = new C()
  550. , index = 5;
  551. while(index--)$instance[ADDER](index, index);
  552. return !$instance.has(-0);
  553. });
  554. if(!ACCEPT_ITERABLES){
  555. C = wrapper(function(target, iterable){
  556. anInstance(target, C, NAME);
  557. var that = inheritIfRequired(new Base, target, C);
  558. if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that);
  559. return that;
  560. });
  561. C.prototype = proto;
  562. proto.constructor = C;
  563. }
  564. if(THROWS_ON_PRIMITIVES || BUGGY_ZERO){
  565. fixMethod('delete');
  566. fixMethod('has');
  567. IS_MAP && fixMethod('get');
  568. }
  569. if(BUGGY_ZERO || HASNT_CHAINING)fixMethod(ADDER);
  570. // weak collections should not contains .clear method
  571. if(IS_WEAK && proto.clear)delete proto.clear;
  572. }
  573. setToStringTag(C, NAME);
  574. O[NAME] = C;
  575. $export($export.G + $export.W + $export.F * (C != Base), O);
  576. if(!IS_WEAK)common.setStrong(C, NAME, IS_MAP);
  577. return C;
  578. };
  579. /***/ }),
  580. /* 29 */
  581. /***/ (function(module, exports, __webpack_require__) {
  582. "use strict";
  583. var hide = __webpack_require__(13)
  584. , redefine = __webpack_require__(14)
  585. , fails = __webpack_require__(12)
  586. , defined = __webpack_require__(11)
  587. , wks = __webpack_require__(1);
  588. module.exports = function(KEY, length, exec){
  589. var SYMBOL = wks(KEY)
  590. , fns = exec(defined, SYMBOL, ''[KEY])
  591. , strfn = fns[0]
  592. , rxfn = fns[1];
  593. if(fails(function(){
  594. var O = {};
  595. O[SYMBOL] = function(){ return 7; };
  596. return ''[KEY](O) != 7;
  597. })){
  598. redefine(String.prototype, KEY, strfn);
  599. hide(RegExp.prototype, SYMBOL, length == 2
  600. // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
  601. // 21.2.5.11 RegExp.prototype[@@split](string, limit)
  602. ? function(string, arg){ return rxfn.call(string, this, arg); }
  603. // 21.2.5.6 RegExp.prototype[@@match](string)
  604. // 21.2.5.9 RegExp.prototype[@@search](string)
  605. : function(string){ return rxfn.call(string, this); }
  606. );
  607. }
  608. };
  609. /***/ }),
  610. /* 30 */
  611. /***/ (function(module, exports, __webpack_require__) {
  612. var ctx = __webpack_require__(10)
  613. , call = __webpack_require__(62)
  614. , isArrayIter = __webpack_require__(58)
  615. , anObject = __webpack_require__(4)
  616. , toLength = __webpack_require__(9)
  617. , getIterFn = __webpack_require__(73)
  618. , BREAK = {}
  619. , RETURN = {};
  620. var exports = module.exports = function(iterable, entries, fn, that, ITERATOR){
  621. var iterFn = ITERATOR ? function(){ return iterable; } : getIterFn(iterable)
  622. , f = ctx(fn, that, entries ? 2 : 1)
  623. , index = 0
  624. , length, step, iterator, result;
  625. if(typeof iterFn != 'function')throw TypeError(iterable + ' is not iterable!');
  626. // fast case for arrays with default iterator
  627. if(isArrayIter(iterFn))for(length = toLength(iterable.length); length > index; index++){
  628. result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);
  629. if(result === BREAK || result === RETURN)return result;
  630. } else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){
  631. result = call(iterator, f, step.value, entries);
  632. if(result === BREAK || result === RETURN)return result;
  633. }
  634. };
  635. exports.BREAK = BREAK;
  636. exports.RETURN = RETURN;
  637. /***/ }),
  638. /* 31 */
  639. /***/ (function(module, exports) {
  640. module.exports = false;
  641. /***/ }),
  642. /* 32 */
  643. /***/ (function(module, exports) {
  644. exports.f = Object.getOwnPropertySymbols;
  645. /***/ }),
  646. /* 33 */
  647. /***/ (function(module, exports, __webpack_require__) {
  648. var redefine = __webpack_require__(14);
  649. module.exports = function(target, src, safe){
  650. for(var key in src)redefine(target, key, src[key], safe);
  651. return target;
  652. };
  653. /***/ }),
  654. /* 34 */
  655. /***/ (function(module, exports, __webpack_require__) {
  656. var toInteger = __webpack_require__(35)
  657. , max = Math.max
  658. , min = Math.min;
  659. module.exports = function(index, length){
  660. index = toInteger(index);
  661. return index < 0 ? max(index + length, 0) : min(index, length);
  662. };
  663. /***/ }),
  664. /* 35 */
  665. /***/ (function(module, exports) {
  666. // 7.1.4 ToInteger
  667. var ceil = Math.ceil
  668. , floor = Math.floor;
  669. module.exports = function(it){
  670. return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
  671. };
  672. /***/ }),
  673. /* 36 */
  674. /***/ (function(module, exports) {
  675. module.exports = function(it){
  676. if(typeof it != 'function')throw TypeError(it + ' is not a function!');
  677. return it;
  678. };
  679. /***/ }),
  680. /* 37 */
  681. /***/ (function(module, exports, __webpack_require__) {
  682. "use strict";
  683. var $defineProperty = __webpack_require__(5)
  684. , createDesc = __webpack_require__(18);
  685. module.exports = function(object, index, value){
  686. if(index in object)$defineProperty.f(object, index, createDesc(0, value));
  687. else object[index] = value;
  688. };
  689. /***/ }),
  690. /* 38 */
  691. /***/ (function(module, exports, __webpack_require__) {
  692. var isObject = __webpack_require__(3)
  693. , document = __webpack_require__(2).document
  694. // in old IE typeof document.createElement is 'object'
  695. , is = isObject(document) && isObject(document.createElement);
  696. module.exports = function(it){
  697. return is ? document.createElement(it) : {};
  698. };
  699. /***/ }),
  700. /* 39 */
  701. /***/ (function(module, exports) {
  702. // IE 8- don't enum bug keys
  703. module.exports = (
  704. 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'
  705. ).split(',');
  706. /***/ }),
  707. /* 40 */
  708. /***/ (function(module, exports, __webpack_require__) {
  709. var MATCH = __webpack_require__(1)('match');
  710. module.exports = function(KEY){
  711. var re = /./;
  712. try {
  713. '/./'[KEY](re);
  714. } catch(e){
  715. try {
  716. re[MATCH] = false;
  717. return !'/./'[KEY](re);
  718. } catch(f){ /* empty */ }
  719. } return true;
  720. };
  721. /***/ }),
  722. /* 41 */
  723. /***/ (function(module, exports, __webpack_require__) {
  724. // fallback for non-array-like ES3 and non-enumerable old V8 strings
  725. var cof = __webpack_require__(16);
  726. module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){
  727. return cof(it) == 'String' ? it.split('') : Object(it);
  728. };
  729. /***/ }),
  730. /* 42 */
  731. /***/ (function(module, exports, __webpack_require__) {
  732. var ITERATOR = __webpack_require__(1)('iterator')
  733. , SAFE_CLOSING = false;
  734. try {
  735. var riter = [7][ITERATOR]();
  736. riter['return'] = function(){ SAFE_CLOSING = true; };
  737. Array.from(riter, function(){ throw 2; });
  738. } catch(e){ /* empty */ }
  739. module.exports = function(exec, skipClosing){
  740. if(!skipClosing && !SAFE_CLOSING)return false;
  741. var safe = false;
  742. try {
  743. var arr = [7]
  744. , iter = arr[ITERATOR]();
  745. iter.next = function(){ return {done: safe = true}; };
  746. arr[ITERATOR] = function(){ return iter; };
  747. exec(arr);
  748. } catch(e){ /* empty */ }
  749. return safe;
  750. };
  751. /***/ }),
  752. /* 43 */
  753. /***/ (function(module, exports, __webpack_require__) {
  754. // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
  755. var anObject = __webpack_require__(4)
  756. , dPs = __webpack_require__(258)
  757. , enumBugKeys = __webpack_require__(39)
  758. , IE_PROTO = __webpack_require__(46)('IE_PROTO')
  759. , Empty = function(){ /* empty */ }
  760. , PROTOTYPE = 'prototype';
  761. // Create object with fake `null` prototype: use iframe Object with cleared prototype
  762. var createDict = function(){
  763. // Thrash, waste and sodomy: IE GC bug
  764. var iframe = __webpack_require__(38)('iframe')
  765. , i = enumBugKeys.length
  766. , lt = '<'
  767. , gt = '>'
  768. , iframeDocument;
  769. iframe.style.display = 'none';
  770. __webpack_require__(56).appendChild(iframe);
  771. iframe.src = 'javascript:'; // eslint-disable-line no-script-url
  772. // createDict = iframe.contentWindow.Object;
  773. // html.removeChild(iframe);
  774. iframeDocument = iframe.contentWindow.document;
  775. iframeDocument.open();
  776. iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);
  777. iframeDocument.close();
  778. createDict = iframeDocument.F;
  779. while(i--)delete createDict[PROTOTYPE][enumBugKeys[i]];
  780. return createDict();
  781. };
  782. module.exports = Object.create || function create(O, Properties){
  783. var result;
  784. if(O !== null){
  785. Empty[PROTOTYPE] = anObject(O);
  786. result = new Empty;
  787. Empty[PROTOTYPE] = null;
  788. // add "__proto__" for Object.getPrototypeOf polyfill
  789. result[IE_PROTO] = O;
  790. } else result = createDict();
  791. return Properties === undefined ? result : dPs(result, Properties);
  792. };
  793. /***/ }),
  794. /* 44 */
  795. /***/ (function(module, exports, __webpack_require__) {
  796. var pIE = __webpack_require__(23)
  797. , createDesc = __webpack_require__(18)
  798. , toIObject = __webpack_require__(8)
  799. , toPrimitive = __webpack_require__(50)
  800. , has = __webpack_require__(7)
  801. , IE8_DOM_DEFINE = __webpack_require__(57)
  802. , gOPD = Object.getOwnPropertyDescriptor;
  803. exports.f = __webpack_require__(6) ? gOPD : function getOwnPropertyDescriptor(O, P){
  804. O = toIObject(O);
  805. P = toPrimitive(P, true);
  806. if(IE8_DOM_DEFINE)try {
  807. return gOPD(O, P);
  808. } catch(e){ /* empty */ }
  809. if(has(O, P))return createDesc(!pIE.f.call(O, P), O[P]);
  810. };
  811. /***/ }),
  812. /* 45 */
  813. /***/ (function(module, exports, __webpack_require__) {
  814. // 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O)
  815. var $keys = __webpack_require__(66)
  816. , hiddenKeys = __webpack_require__(39).concat('length', 'prototype');
  817. exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O){
  818. return $keys(O, hiddenKeys);
  819. };
  820. /***/ }),
  821. /* 46 */
  822. /***/ (function(module, exports, __webpack_require__) {
  823. var shared = __webpack_require__(47)('keys')
  824. , uid = __webpack_require__(25);
  825. module.exports = function(key){
  826. return shared[key] || (shared[key] = uid(key));
  827. };
  828. /***/ }),
  829. /* 47 */
  830. /***/ (function(module, exports, __webpack_require__) {
  831. var global = __webpack_require__(2)
  832. , SHARED = '__core-js_shared__'
  833. , store = global[SHARED] || (global[SHARED] = {});
  834. module.exports = function(key){
  835. return store[key] || (store[key] = {});
  836. };
  837. /***/ }),
  838. /* 48 */
  839. /***/ (function(module, exports, __webpack_require__) {
  840. // helper for String#{startsWith, endsWith, includes}
  841. var isRegExp = __webpack_require__(61)
  842. , defined = __webpack_require__(11);
  843. module.exports = function(that, searchString, NAME){
  844. if(isRegExp(searchString))throw TypeError('String#' + NAME + " doesn't accept regex!");
  845. return String(defined(that));
  846. };
  847. /***/ }),
  848. /* 49 */
  849. /***/ (function(module, exports, __webpack_require__) {
  850. var ctx = __webpack_require__(10)
  851. , invoke = __webpack_require__(254)
  852. , html = __webpack_require__(56)
  853. , cel = __webpack_require__(38)
  854. , global = __webpack_require__(2)
  855. , process = global.process
  856. , setTask = global.setImmediate
  857. , clearTask = global.clearImmediate
  858. , MessageChannel = global.MessageChannel
  859. , counter = 0
  860. , queue = {}
  861. , ONREADYSTATECHANGE = 'onreadystatechange'
  862. , defer, channel, port;
  863. var run = function(){
  864. var id = +this;
  865. if(queue.hasOwnProperty(id)){
  866. var fn = queue[id];
  867. delete queue[id];
  868. fn();
  869. }
  870. };
  871. var listener = function(event){
  872. run.call(event.data);
  873. };
  874. // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
  875. if(!setTask || !clearTask){
  876. setTask = function setImmediate(fn){
  877. var args = [], i = 1;
  878. while(arguments.length > i)args.push(arguments[i++]);
  879. queue[++counter] = function(){
  880. invoke(typeof fn == 'function' ? fn : Function(fn), args);
  881. };
  882. defer(counter);
  883. return counter;
  884. };
  885. clearTask = function clearImmediate(id){
  886. delete queue[id];
  887. };
  888. // Node.js 0.8-
  889. if(__webpack_require__(16)(process) == 'process'){
  890. defer = function(id){
  891. process.nextTick(ctx(run, id, 1));
  892. };
  893. // Browsers with MessageChannel, includes WebWorkers
  894. } else if(MessageChannel){
  895. channel = new MessageChannel;
  896. port = channel.port2;
  897. channel.port1.onmessage = listener;
  898. defer = ctx(port.postMessage, port, 1);
  899. // Browsers with postMessage, skip WebWorkers
  900. // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
  901. } else if(global.addEventListener && typeof postMessage == 'function' && !global.importScripts){
  902. defer = function(id){
  903. global.postMessage(id + '', '*');
  904. };
  905. global.addEventListener('message', listener, false);
  906. // IE8-
  907. } else if(ONREADYSTATECHANGE in cel('script')){
  908. defer = function(id){
  909. html.appendChild(cel('script'))[ONREADYSTATECHANGE] = function(){
  910. html.removeChild(this);
  911. run.call(id);
  912. };
  913. };
  914. // Rest old browsers
  915. } else {
  916. defer = function(id){
  917. setTimeout(ctx(run, id, 1), 0);
  918. };
  919. }
  920. }
  921. module.exports = {
  922. set: setTask,
  923. clear: clearTask
  924. };
  925. /***/ }),
  926. /* 50 */
  927. /***/ (function(module, exports, __webpack_require__) {
  928. // 7.1.1 ToPrimitive(input [, PreferredType])
  929. var isObject = __webpack_require__(3);
  930. // instead of the ES6 spec version, we didn't implement @@toPrimitive case
  931. // and the second argument - flag - preferred type is a string
  932. module.exports = function(it, S){
  933. if(!isObject(it))return it;
  934. var fn, val;
  935. if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
  936. if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val;
  937. if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
  938. throw TypeError("Can't convert object to primitive value");
  939. };
  940. /***/ }),
  941. /* 51 */
  942. /***/ (function(module, exports, __webpack_require__) {
  943. "use strict";
  944. var addToUnscopables = __webpack_require__(15)
  945. , step = __webpack_require__(64)
  946. , Iterators = __webpack_require__(21)
  947. , toIObject = __webpack_require__(8);
  948. // 22.1.3.4 Array.prototype.entries()
  949. // 22.1.3.13 Array.prototype.keys()
  950. // 22.1.3.29 Array.prototype.values()
  951. // 22.1.3.30 Array.prototype[@@iterator]()
  952. module.exports = __webpack_require__(63)(Array, 'Array', function(iterated, kind){
  953. this._t = toIObject(iterated); // target
  954. this._i = 0; // next index
  955. this._k = kind; // kind
  956. // 22.1.5.2.1 %ArrayIteratorPrototype%.next()
  957. }, function(){
  958. var O = this._t
  959. , kind = this._k
  960. , index = this._i++;
  961. if(!O || index >= O.length){
  962. this._t = undefined;
  963. return step(1);
  964. }
  965. if(kind == 'keys' )return step(0, index);
  966. if(kind == 'values')return step(0, O[index]);
  967. return step(0, [index, O[index]]);
  968. }, 'values');
  969. // argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)
  970. Iterators.Arguments = Iterators.Array;
  971. addToUnscopables('keys');
  972. addToUnscopables('values');
  973. addToUnscopables('entries');
  974. /***/ }),
  975. /* 52 */
  976. /***/ (function(module, exports, __webpack_require__) {
  977. // false -> Array#indexOf
  978. // true -> Array#includes
  979. var toIObject = __webpack_require__(8)
  980. , toLength = __webpack_require__(9)
  981. , toIndex = __webpack_require__(34);
  982. module.exports = function(IS_INCLUDES){
  983. return function($this, el, fromIndex){
  984. var O = toIObject($this)
  985. , length = toLength(O.length)
  986. , index = toIndex(fromIndex, length)
  987. , value;
  988. // Array#includes uses SameValueZero equality algorithm
  989. if(IS_INCLUDES && el != el)while(length > index){
  990. value = O[index++];
  991. if(value != value)return true;
  992. // Array#toIndex ignores holes, Array#includes - not
  993. } else for(;length > index; index++)if(IS_INCLUDES || index in O){
  994. if(O[index] === el)return IS_INCLUDES || index || 0;
  995. } return !IS_INCLUDES && -1;
  996. };
  997. };
  998. /***/ }),
  999. /* 53 */
  1000. /***/ (function(module, exports, __webpack_require__) {
  1001. // getting tag from 19.1.3.6 Object.prototype.toString()
  1002. var cof = __webpack_require__(16)
  1003. , TAG = __webpack_require__(1)('toStringTag')
  1004. // ES3 wrong here
  1005. , ARG = cof(function(){ return arguments; }()) == 'Arguments';
  1006. // fallback for IE11 Script Access Denied error
  1007. var tryGet = function(it, key){
  1008. try {
  1009. return it[key];
  1010. } catch(e){ /* empty */ }
  1011. };
  1012. module.exports = function(it){
  1013. var O, T, B;
  1014. return it === undefined ? 'Undefined' : it === null ? 'Null'
  1015. // @@toStringTag case
  1016. : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T
  1017. // builtinTag case
  1018. : ARG ? cof(O)
  1019. // ES3 arguments fallback
  1020. : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;
  1021. };
  1022. /***/ }),
  1023. /* 54 */
  1024. /***/ (function(module, exports, __webpack_require__) {
  1025. "use strict";
  1026. var dP = __webpack_require__(5).f
  1027. , create = __webpack_require__(43)
  1028. , redefineAll = __webpack_require__(33)
  1029. , ctx = __webpack_require__(10)
  1030. , anInstance = __webpack_require__(26)
  1031. , defined = __webpack_require__(11)
  1032. , forOf = __webpack_require__(30)
  1033. , $iterDefine = __webpack_require__(63)
  1034. , step = __webpack_require__(64)
  1035. , setSpecies = __webpack_require__(69)
  1036. , DESCRIPTORS = __webpack_require__(6)
  1037. , fastKey = __webpack_require__(22).fastKey
  1038. , SIZE = DESCRIPTORS ? '_s' : 'size';
  1039. var getEntry = function(that, key){
  1040. // fast case
  1041. var index = fastKey(key), entry;
  1042. if(index !== 'F')return that._i[index];
  1043. // frozen object case
  1044. for(entry = that._f; entry; entry = entry.n){
  1045. if(entry.k == key)return entry;
  1046. }
  1047. };
  1048. module.exports = {
  1049. getConstructor: function(wrapper, NAME, IS_MAP, ADDER){
  1050. var C = wrapper(function(that, iterable){
  1051. anInstance(that, C, NAME, '_i');
  1052. that._i = create(null); // index
  1053. that._f = undefined; // first entry
  1054. that._l = undefined; // last entry
  1055. that[SIZE] = 0; // size
  1056. if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that);
  1057. });
  1058. redefineAll(C.prototype, {
  1059. // 23.1.3.1 Map.prototype.clear()
  1060. // 23.2.3.2 Set.prototype.clear()
  1061. clear: function clear(){
  1062. for(var that = this, data = that._i, entry = that._f; entry; entry = entry.n){
  1063. entry.r = true;
  1064. if(entry.p)entry.p = entry.p.n = undefined;
  1065. delete data[entry.i];
  1066. }
  1067. that._f = that._l = undefined;
  1068. that[SIZE] = 0;
  1069. },
  1070. // 23.1.3.3 Map.prototype.delete(key)
  1071. // 23.2.3.4 Set.prototype.delete(value)
  1072. 'delete': function(key){
  1073. var that = this
  1074. , entry = getEntry(that, key);
  1075. if(entry){
  1076. var next = entry.n
  1077. , prev = entry.p;
  1078. delete that._i[entry.i];
  1079. entry.r = true;
  1080. if(prev)prev.n = next;
  1081. if(next)next.p = prev;
  1082. if(that._f == entry)that._f = next;
  1083. if(that._l == entry)that._l = prev;
  1084. that[SIZE]--;
  1085. } return !!entry;
  1086. },
  1087. // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
  1088. // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
  1089. forEach: function forEach(callbackfn /*, that = undefined */){
  1090. anInstance(this, C, 'forEach');
  1091. var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3)
  1092. , entry;
  1093. while(entry = entry ? entry.n : this._f){
  1094. f(entry.v, entry.k, this);
  1095. // revert to the last existing entry
  1096. while(entry && entry.r)entry = entry.p;
  1097. }
  1098. },
  1099. // 23.1.3.7 Map.prototype.has(key)
  1100. // 23.2.3.7 Set.prototype.has(value)
  1101. has: function has(key){
  1102. return !!getEntry(this, key);
  1103. }
  1104. });
  1105. if(DESCRIPTORS)dP(C.prototype, 'size', {
  1106. get: function(){
  1107. return defined(this[SIZE]);
  1108. }
  1109. });
  1110. return C;
  1111. },
  1112. def: function(that, key, value){
  1113. var entry = getEntry(that, key)
  1114. , prev, index;
  1115. // change existing entry
  1116. if(entry){
  1117. entry.v = value;
  1118. // create new entry
  1119. } else {
  1120. that._l = entry = {
  1121. i: index = fastKey(key, true), // <- index
  1122. k: key, // <- key
  1123. v: value, // <- value
  1124. p: prev = that._l, // <- previous entry
  1125. n: undefined, // <- next entry
  1126. r: false // <- removed
  1127. };
  1128. if(!that._f)that._f = entry;
  1129. if(prev)prev.n = entry;
  1130. that[SIZE]++;
  1131. // add to index
  1132. if(index !== 'F')that._i[index] = entry;
  1133. } return that;
  1134. },
  1135. getEntry: getEntry,
  1136. setStrong: function(C, NAME, IS_MAP){
  1137. // add .keys, .values, .entries, [@@iterator]
  1138. // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11
  1139. $iterDefine(C, NAME, function(iterated, kind){
  1140. this._t = iterated; // target
  1141. this._k = kind; // kind
  1142. this._l = undefined; // previous
  1143. }, function(){
  1144. var that = this
  1145. , kind = that._k
  1146. , entry = that._l;
  1147. // revert to the last existing entry
  1148. while(entry && entry.r)entry = entry.p;
  1149. // get next entry
  1150. if(!that._t || !(that._l = entry = entry ? entry.n : that._t._f)){
  1151. // or finish the iteration
  1152. that._t = undefined;
  1153. return step(1);
  1154. }
  1155. // return step by kind
  1156. if(kind == 'keys' )return step(0, entry.k);
  1157. if(kind == 'values')return step(0, entry.v);
  1158. return step(0, [entry.k, entry.v]);
  1159. }, IS_MAP ? 'entries' : 'values' , !IS_MAP, true);
  1160. // add [@@species], 23.1.2.2, 23.2.2.2
  1161. setSpecies(NAME);
  1162. }
  1163. };
  1164. /***/ }),
  1165. /* 55 */
  1166. /***/ (function(module, exports, __webpack_require__) {
  1167. "use strict";
  1168. var redefineAll = __webpack_require__(33)
  1169. , getWeak = __webpack_require__(22).getWeak
  1170. , anObject = __webpack_require__(4)
  1171. , isObject = __webpack_require__(3)
  1172. , anInstance = __webpack_require__(26)
  1173. , forOf = __webpack_require__(30)
  1174. , createArrayMethod = __webpack_require__(27)
  1175. , $has = __webpack_require__(7)
  1176. , arrayFind = createArrayMethod(5)
  1177. , arrayFindIndex = createArrayMethod(6)
  1178. , id = 0;
  1179. // fallback for uncaught frozen keys
  1180. var uncaughtFrozenStore = function(that){
  1181. return that._l || (that._l = new UncaughtFrozenStore);
  1182. };
  1183. var UncaughtFrozenStore = function(){
  1184. this.a = [];
  1185. };
  1186. var findUncaughtFrozen = function(store, key){
  1187. return arrayFind(store.a, function(it){
  1188. return it[0] === key;
  1189. });
  1190. };
  1191. UncaughtFrozenStore.prototype = {
  1192. get: function(key){
  1193. var entry = findUncaughtFrozen(this, key);
  1194. if(entry)return entry[1];
  1195. },
  1196. has: function(key){
  1197. return !!findUncaughtFrozen(this, key);
  1198. },
  1199. set: function(key, value){
  1200. var entry = findUncaughtFrozen(this, key);
  1201. if(entry)entry[1] = value;
  1202. else this.a.push([key, value]);
  1203. },
  1204. 'delete': function(key){
  1205. var index = arrayFindIndex(this.a, function(it){
  1206. return it[0] === key;
  1207. });
  1208. if(~index)this.a.splice(index, 1);
  1209. return !!~index;
  1210. }
  1211. };
  1212. module.exports = {
  1213. getConstructor: function(wrapper, NAME, IS_MAP, ADDER){
  1214. var C = wrapper(function(that, iterable){
  1215. anInstance(that, C, NAME, '_i');
  1216. that._i = id++; // collection id
  1217. that._l = undefined; // leak store for uncaught frozen objects
  1218. if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that);
  1219. });
  1220. redefineAll(C.prototype, {
  1221. // 23.3.3.2 WeakMap.prototype.delete(key)
  1222. // 23.4.3.3 WeakSet.prototype.delete(value)
  1223. 'delete': function(key){
  1224. if(!isObject(key))return false;
  1225. var data = getWeak(key);
  1226. if(data === true)return uncaughtFrozenStore(this)['delete'](key);
  1227. return data && $has(data, this._i) && delete data[this._i];
  1228. },
  1229. // 23.3.3.4 WeakMap.prototype.has(key)
  1230. // 23.4.3.4 WeakSet.prototype.has(value)
  1231. has: function has(key){
  1232. if(!isObject(key))return false;
  1233. var data = getWeak(key);
  1234. if(data === true)return uncaughtFrozenStore(this).has(key);
  1235. return data && $has(data, this._i);
  1236. }
  1237. });
  1238. return C;
  1239. },
  1240. def: function(that, key, value){
  1241. var data = getWeak(anObject(key), true);
  1242. if(data === true)uncaughtFrozenStore(that).set(key, value);
  1243. else data[that._i] = value;
  1244. return that;
  1245. },
  1246. ufstore: uncaughtFrozenStore
  1247. };
  1248. /***/ }),
  1249. /* 56 */
  1250. /***/ (function(module, exports, __webpack_require__) {
  1251. module.exports = __webpack_require__(2).document && document.documentElement;
  1252. /***/ }),
  1253. /* 57 */
  1254. /***/ (function(module, exports, __webpack_require__) {
  1255. module.exports = !__webpack_require__(6) && !__webpack_require__(12)(function(){
  1256. return Object.defineProperty(__webpack_require__(38)('div'), 'a', {get: function(){ return 7; }}).a != 7;
  1257. });
  1258. /***/ }),
  1259. /* 58 */
  1260. /***/ (function(module, exports, __webpack_require__) {
  1261. // check on default Array iterator
  1262. var Iterators = __webpack_require__(21)
  1263. , ITERATOR = __webpack_require__(1)('iterator')
  1264. , ArrayProto = Array.prototype;
  1265. module.exports = function(it){
  1266. return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);
  1267. };
  1268. /***/ }),
  1269. /* 59 */
  1270. /***/ (function(module, exports, __webpack_require__) {
  1271. // 7.2.2 IsArray(argument)
  1272. var cof = __webpack_require__(16);
  1273. module.exports = Array.isArray || function isArray(arg){
  1274. return cof(arg) == 'Array';
  1275. };
  1276. /***/ }),
  1277. /* 60 */
  1278. /***/ (function(module, exports, __webpack_require__) {
  1279. // 20.1.2.3 Number.isInteger(number)
  1280. var isObject = __webpack_require__(3)
  1281. , floor = Math.floor;
  1282. module.exports = function isInteger(it){
  1283. return !isObject(it) && isFinite(it) && floor(it) === it;
  1284. };
  1285. /***/ }),
  1286. /* 61 */
  1287. /***/ (function(module, exports, __webpack_require__) {
  1288. // 7.2.8 IsRegExp(argument)
  1289. var isObject = __webpack_require__(3)
  1290. , cof = __webpack_require__(16)
  1291. , MATCH = __webpack_require__(1)('match');
  1292. module.exports = function(it){
  1293. var isRegExp;
  1294. return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : cof(it) == 'RegExp');
  1295. };
  1296. /***/ }),
  1297. /* 62 */
  1298. /***/ (function(module, exports, __webpack_require__) {
  1299. // call something on iterator step with safe closing on error
  1300. var anObject = __webpack_require__(4);
  1301. module.exports = function(iterator, fn, value, entries){
  1302. try {
  1303. return entries ? fn(anObject(value)[0], value[1]) : fn(value);
  1304. // 7.4.6 IteratorClose(iterator, completion)
  1305. } catch(e){
  1306. var ret = iterator['return'];
  1307. if(ret !== undefined)anObject(ret.call(iterator));
  1308. throw e;
  1309. }
  1310. };
  1311. /***/ }),
  1312. /* 63 */
  1313. /***/ (function(module, exports, __webpack_require__) {
  1314. "use strict";
  1315. var LIBRARY = __webpack_require__(31)
  1316. , $export = __webpack_require__(0)
  1317. , redefine = __webpack_require__(14)
  1318. , hide = __webpack_require__(13)
  1319. , has = __webpack_require__(7)
  1320. , Iterators = __webpack_require__(21)
  1321. , $iterCreate = __webpack_require__(255)
  1322. , setToStringTag = __webpack_require__(24)
  1323. , getPrototypeOf = __webpack_require__(260)
  1324. , ITERATOR = __webpack_require__(1)('iterator')
  1325. , BUGGY = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next`
  1326. , FF_ITERATOR = '@@iterator'
  1327. , KEYS = 'keys'
  1328. , VALUES = 'values';
  1329. var returnThis = function(){ return this; };
  1330. module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){
  1331. $iterCreate(Constructor, NAME, next);
  1332. var getMethod = function(kind){
  1333. if(!BUGGY && kind in proto)return proto[kind];
  1334. switch(kind){
  1335. case KEYS: return function keys(){ return new Constructor(this, kind); };
  1336. case VALUES: return function values(){ return new Constructor(this, kind); };
  1337. } return function entries(){ return new Constructor(this, kind); };
  1338. };
  1339. var TAG = NAME + ' Iterator'
  1340. , DEF_VALUES = DEFAULT == VALUES
  1341. , VALUES_BUG = false
  1342. , proto = Base.prototype
  1343. , $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]
  1344. , $default = $native || getMethod(DEFAULT)
  1345. , $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined
  1346. , $anyNative = NAME == 'Array' ? proto.entries || $native : $native
  1347. , methods, key, IteratorPrototype;
  1348. // Fix native
  1349. if($anyNative){
  1350. IteratorPrototype = getPrototypeOf($anyNative.call(new Base));
  1351. if(IteratorPrototype !== Object.prototype){
  1352. // Set @@toStringTag to native iterators
  1353. setToStringTag(IteratorPrototype, TAG, true);
  1354. // fix for some old engines
  1355. if(!LIBRARY && !has(IteratorPrototype, ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis);
  1356. }
  1357. }
  1358. // fix Array#{values, @@iterator}.name in V8 / FF
  1359. if(DEF_VALUES && $native && $native.name !== VALUES){
  1360. VALUES_BUG = true;
  1361. $default = function values(){ return $native.call(this); };
  1362. }
  1363. // Define iterator
  1364. if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){
  1365. hide(proto, ITERATOR, $default);
  1366. }
  1367. // Plug for library
  1368. Iterators[NAME] = $default;
  1369. Iterators[TAG] = returnThis;
  1370. if(DEFAULT){
  1371. methods = {
  1372. values: DEF_VALUES ? $default : getMethod(VALUES),
  1373. keys: IS_SET ? $default : getMethod(KEYS),
  1374. entries: $entries
  1375. };
  1376. if(FORCED)for(key in methods){
  1377. if(!(key in proto))redefine(proto, key, methods[key]);
  1378. } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);
  1379. }
  1380. return methods;
  1381. };
  1382. /***/ }),
  1383. /* 64 */
  1384. /***/ (function(module, exports) {
  1385. module.exports = function(done, value){
  1386. return {value: value, done: !!done};
  1387. };
  1388. /***/ }),
  1389. /* 65 */
  1390. /***/ (function(module, exports, __webpack_require__) {
  1391. "use strict";
  1392. // 19.1.2.1 Object.assign(target, source, ...)
  1393. var getKeys = __webpack_require__(17)
  1394. , gOPS = __webpack_require__(32)
  1395. , pIE = __webpack_require__(23)
  1396. , toObject = __webpack_require__(19)
  1397. , IObject = __webpack_require__(41)
  1398. , $assign = Object.assign;
  1399. // should work with symbols and should have deterministic property order (V8 bug)
  1400. module.exports = !$assign || __webpack_require__(12)(function(){
  1401. var A = {}
  1402. , B = {}
  1403. , S = Symbol()
  1404. , K = 'abcdefghijklmnopqrst';
  1405. A[S] = 7;
  1406. K.split('').forEach(function(k){ B[k] = k; });
  1407. return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;
  1408. }) ? function assign(target, source){ // eslint-disable-line no-unused-vars
  1409. var T = toObject(target)
  1410. , aLen = arguments.length
  1411. , index = 1
  1412. , getSymbols = gOPS.f
  1413. , isEnum = pIE.f;
  1414. while(aLen > index){
  1415. var S = IObject(arguments[index++])
  1416. , keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S)
  1417. , length = keys.length
  1418. , j = 0
  1419. , key;
  1420. while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key];
  1421. } return T;
  1422. } : $assign;
  1423. /***/ }),
  1424. /* 66 */
  1425. /***/ (function(module, exports, __webpack_require__) {
  1426. var has = __webpack_require__(7)
  1427. , toIObject = __webpack_require__(8)
  1428. , arrayIndexOf = __webpack_require__(52)(false)
  1429. , IE_PROTO = __webpack_require__(46)('IE_PROTO');
  1430. module.exports = function(object, names){
  1431. var O = toIObject(object)
  1432. , i = 0
  1433. , result = []
  1434. , key;
  1435. for(key in O)if(key != IE_PROTO)has(O, key) && result.push(key);
  1436. // Don't enum bug & hidden keys
  1437. while(names.length > i)if(has(O, key = names[i++])){
  1438. ~arrayIndexOf(result, key) || result.push(key);
  1439. }
  1440. return result;
  1441. };
  1442. /***/ }),
  1443. /* 67 */
  1444. /***/ (function(module, exports, __webpack_require__) {
  1445. var getKeys = __webpack_require__(17)
  1446. , toIObject = __webpack_require__(8)
  1447. , isEnum = __webpack_require__(23).f;
  1448. module.exports = function(isEntries){
  1449. return function(it){
  1450. var O = toIObject(it)
  1451. , keys = getKeys(O)
  1452. , length = keys.length
  1453. , i = 0
  1454. , result = []
  1455. , key;
  1456. while(length > i)if(isEnum.call(O, key = keys[i++])){
  1457. result.push(isEntries ? [key, O[key]] : O[key]);
  1458. } return result;
  1459. };
  1460. };
  1461. /***/ }),
  1462. /* 68 */
  1463. /***/ (function(module, exports, __webpack_require__) {
  1464. // Works with __proto__ only. Old v8 can't work with null proto objects.
  1465. /* eslint-disable no-proto */
  1466. var isObject = __webpack_require__(3)
  1467. , anObject = __webpack_require__(4);
  1468. var check = function(O, proto){
  1469. anObject(O);
  1470. if(!isObject(proto) && proto !== null)throw TypeError(proto + ": can't set as prototype!");
  1471. };
  1472. module.exports = {
  1473. set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line
  1474. function(test, buggy, set){
  1475. try {
  1476. set = __webpack_require__(10)(Function.call, __webpack_require__(44).f(Object.prototype, '__proto__').set, 2);
  1477. set(test, []);
  1478. buggy = !(test instanceof Array);
  1479. } catch(e){ buggy = true; }
  1480. return function setPrototypeOf(O, proto){
  1481. check(O, proto);
  1482. if(buggy)O.__proto__ = proto;
  1483. else set(O, proto);
  1484. return O;
  1485. };
  1486. }({}, false) : undefined),
  1487. check: check
  1488. };
  1489. /***/ }),
  1490. /* 69 */
  1491. /***/ (function(module, exports, __webpack_require__) {
  1492. "use strict";
  1493. var global = __webpack_require__(2)
  1494. , dP = __webpack_require__(5)
  1495. , DESCRIPTORS = __webpack_require__(6)
  1496. , SPECIES = __webpack_require__(1)('species');
  1497. module.exports = function(KEY){
  1498. var C = global[KEY];
  1499. if(DESCRIPTORS && C && !C[SPECIES])dP.f(C, SPECIES, {
  1500. configurable: true,
  1501. get: function(){ return this; }
  1502. });
  1503. };
  1504. /***/ }),
  1505. /* 70 */
  1506. /***/ (function(module, exports, __webpack_require__) {
  1507. // https://github.com/tc39/proposal-string-pad-start-end
  1508. var toLength = __webpack_require__(9)
  1509. , repeat = __webpack_require__(71)
  1510. , defined = __webpack_require__(11);
  1511. module.exports = function(that, maxLength, fillString, left){
  1512. var S = String(defined(that))
  1513. , stringLength = S.length
  1514. , fillStr = fillString === undefined ? ' ' : String(fillString)
  1515. , intMaxLength = toLength(maxLength);
  1516. if(intMaxLength <= stringLength || fillStr == '')return S;
  1517. var fillLen = intMaxLength - stringLength
  1518. , stringFiller = repeat.call(fillStr, Math.ceil(fillLen / fillStr.length));
  1519. if(stringFiller.length > fillLen)stringFiller = stringFiller.slice(0, fillLen);
  1520. return left ? stringFiller + S : S + stringFiller;
  1521. };
  1522. /***/ }),
  1523. /* 71 */
  1524. /***/ (function(module, exports, __webpack_require__) {
  1525. "use strict";
  1526. var toInteger = __webpack_require__(35)
  1527. , defined = __webpack_require__(11);
  1528. module.exports = function repeat(count){
  1529. var str = String(defined(this))
  1530. , res = ''
  1531. , n = toInteger(count);
  1532. if(n < 0 || n == Infinity)throw RangeError("Count can't be negative");
  1533. for(;n > 0; (n >>>= 1) && (str += str))if(n & 1)res += str;
  1534. return res;
  1535. };
  1536. /***/ }),
  1537. /* 72 */
  1538. /***/ (function(module, exports, __webpack_require__) {
  1539. exports.f = __webpack_require__(1);
  1540. /***/ }),
  1541. /* 73 */
  1542. /***/ (function(module, exports, __webpack_require__) {
  1543. var classof = __webpack_require__(53)
  1544. , ITERATOR = __webpack_require__(1)('iterator')
  1545. , Iterators = __webpack_require__(21);
  1546. module.exports = __webpack_require__(20).getIteratorMethod = function(it){
  1547. if(it != undefined)return it[ITERATOR]
  1548. || it['@@iterator']
  1549. || Iterators[classof(it)];
  1550. };
  1551. /***/ }),
  1552. /* 74 */
  1553. /***/ (function(module, exports) {
  1554. var g;
  1555. // This works in non-strict mode
  1556. g = (function() {
  1557. return this;
  1558. })();
  1559. try {
  1560. // This works if eval is allowed (see CSP)
  1561. g = g || Function("return this")() || (1,eval)("this");
  1562. } catch(e) {
  1563. // This works if the window reference is available
  1564. if(typeof window === "object")
  1565. g = window;
  1566. }
  1567. // g can still be undefined, but nothing to do about it...
  1568. // We return undefined, instead of nothing here, so it's
  1569. // easier to handle this case. if(!global) { ...}
  1570. module.exports = g;
  1571. /***/ }),
  1572. /* 75 */
  1573. /***/ (function(module, exports, __webpack_require__) {
  1574. "use strict";
  1575. // this file is called MemoryLeakTest.js (not MemoryLeak.spec.js) to make sure it is manually executed as the last suite
  1576. describe('MemoryLeakTest', function () {
  1577. it('after all Handsontable instances are destroy()\'d, there should be no more active listeners', function () {
  1578. expect(Handsontable._getListenersCounter()).toBe(0);
  1579. });
  1580. });
  1581. /***/ }),
  1582. /* 76 */,
  1583. /* 77 */,
  1584. /* 78 */
  1585. /***/ (function(module, exports, __webpack_require__) {
  1586. // 22.1.3.3 Array.prototype.copyWithin(target, start, end = this.length)
  1587. var $export = __webpack_require__(0);
  1588. $export($export.P, 'Array', {copyWithin: __webpack_require__(247)});
  1589. __webpack_require__(15)('copyWithin');
  1590. /***/ }),
  1591. /* 79 */
  1592. /***/ (function(module, exports, __webpack_require__) {
  1593. // 22.1.3.6 Array.prototype.fill(value, start = 0, end = this.length)
  1594. var $export = __webpack_require__(0);
  1595. $export($export.P, 'Array', {fill: __webpack_require__(248)});
  1596. __webpack_require__(15)('fill');
  1597. /***/ }),
  1598. /* 80 */
  1599. /***/ (function(module, exports, __webpack_require__) {
  1600. "use strict";
  1601. // 22.1.3.9 Array.prototype.findIndex(predicate, thisArg = undefined)
  1602. var $export = __webpack_require__(0)
  1603. , $find = __webpack_require__(27)(6)
  1604. , KEY = 'findIndex'
  1605. , forced = true;
  1606. // Shouldn't skip holes
  1607. if(KEY in [])Array(1)[KEY](function(){ forced = false; });
  1608. $export($export.P + $export.F * forced, 'Array', {
  1609. findIndex: function findIndex(callbackfn/*, that = undefined */){
  1610. return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
  1611. }
  1612. });
  1613. __webpack_require__(15)(KEY);
  1614. /***/ }),
  1615. /* 81 */
  1616. /***/ (function(module, exports, __webpack_require__) {
  1617. "use strict";
  1618. // 22.1.3.8 Array.prototype.find(predicate, thisArg = undefined)
  1619. var $export = __webpack_require__(0)
  1620. , $find = __webpack_require__(27)(5)
  1621. , KEY = 'find'
  1622. , forced = true;
  1623. // Shouldn't skip holes
  1624. if(KEY in [])Array(1)[KEY](function(){ forced = false; });
  1625. $export($export.P + $export.F * forced, 'Array', {
  1626. find: function find(callbackfn/*, that = undefined */){
  1627. return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
  1628. }
  1629. });
  1630. __webpack_require__(15)(KEY);
  1631. /***/ }),
  1632. /* 82 */
  1633. /***/ (function(module, exports, __webpack_require__) {
  1634. "use strict";
  1635. var ctx = __webpack_require__(10)
  1636. , $export = __webpack_require__(0)
  1637. , toObject = __webpack_require__(19)
  1638. , call = __webpack_require__(62)
  1639. , isArrayIter = __webpack_require__(58)
  1640. , toLength = __webpack_require__(9)
  1641. , createProperty = __webpack_require__(37)
  1642. , getIterFn = __webpack_require__(73);
  1643. $export($export.S + $export.F * !__webpack_require__(42)(function(iter){ Array.from(iter); }), 'Array', {
  1644. // 22.1.2.1 Array.from(arrayLike, mapfn = undefined, thisArg = undefined)
  1645. from: function from(arrayLike/*, mapfn = undefined, thisArg = undefined*/){
  1646. var O = toObject(arrayLike)
  1647. , C = typeof this == 'function' ? this : Array
  1648. , aLen = arguments.length
  1649. , mapfn = aLen > 1 ? arguments[1] : undefined
  1650. , mapping = mapfn !== undefined
  1651. , index = 0
  1652. , iterFn = getIterFn(O)
  1653. , length, result, step, iterator;
  1654. if(mapping)mapfn = ctx(mapfn, aLen > 2 ? arguments[2] : undefined, 2);
  1655. // if object isn't iterable or it's array with default iterator - use simple case
  1656. if(iterFn != undefined && !(C == Array && isArrayIter(iterFn))){
  1657. for(iterator = iterFn.call(O), result = new C; !(step = iterator.next()).done; index++){
  1658. createProperty(result, index, mapping ? call(iterator, mapfn, [step.value, index], true) : step.value);
  1659. }
  1660. } else {
  1661. length = toLength(O.length);
  1662. for(result = new C(length); length > index; index++){
  1663. createProperty(result, index, mapping ? mapfn(O[index], index) : O[index]);
  1664. }
  1665. }
  1666. result.length = index;
  1667. return result;
  1668. }
  1669. });
  1670. /***/ }),
  1671. /* 83 */
  1672. /***/ (function(module, exports, __webpack_require__) {
  1673. "use strict";
  1674. var $export = __webpack_require__(0)
  1675. , createProperty = __webpack_require__(37);
  1676. // WebKit Array.of isn't generic
  1677. $export($export.S + $export.F * __webpack_require__(12)(function(){
  1678. function F(){}
  1679. return !(Array.of.call(F) instanceof F);
  1680. }), 'Array', {
  1681. // 22.1.2.3 Array.of( ...items)
  1682. of: function of(/* ...args */){
  1683. var index = 0
  1684. , aLen = arguments.length
  1685. , result = new (typeof this == 'function' ? this : Array)(aLen);
  1686. while(aLen > index)createProperty(result, index, arguments[index++]);
  1687. result.length = aLen;
  1688. return result;
  1689. }
  1690. });
  1691. /***/ }),
  1692. /* 84 */
  1693. /***/ (function(module, exports, __webpack_require__) {
  1694. var dP = __webpack_require__(5).f
  1695. , createDesc = __webpack_require__(18)
  1696. , has = __webpack_require__(7)
  1697. , FProto = Function.prototype
  1698. , nameRE = /^\s*function ([^ (]*)/
  1699. , NAME = 'name';
  1700. var isExtensible = Object.isExtensible || function(){
  1701. return true;
  1702. };
  1703. // 19.2.4.2 name
  1704. NAME in FProto || __webpack_require__(6) && dP(FProto, NAME, {
  1705. configurable: true,
  1706. get: function(){
  1707. try {
  1708. var that = this
  1709. , name = ('' + that).match(nameRE)[1];
  1710. has(that, NAME) || !isExtensible(that) || dP(that, NAME, createDesc(5, name));
  1711. return name;
  1712. } catch(e){
  1713. return '';
  1714. }
  1715. }
  1716. });
  1717. /***/ }),
  1718. /* 85 */
  1719. /***/ (function(module, exports, __webpack_require__) {
  1720. "use strict";
  1721. var strong = __webpack_require__(54);
  1722. // 23.1 Map Objects
  1723. module.exports = __webpack_require__(28)('Map', function(get){
  1724. return function Map(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); };
  1725. }, {
  1726. // 23.1.3.6 Map.prototype.get(key)
  1727. get: function get(key){
  1728. var entry = strong.getEntry(this, key);
  1729. return entry && entry.v;
  1730. },
  1731. // 23.1.3.9 Map.prototype.set(key, value)
  1732. set: function set(key, value){
  1733. return strong.def(this, key === 0 ? 0 : key, value);
  1734. }
  1735. }, strong, true);
  1736. /***/ }),
  1737. /* 86 */
  1738. /***/ (function(module, exports, __webpack_require__) {
  1739. // 20.1.2.1 Number.EPSILON
  1740. var $export = __webpack_require__(0);
  1741. $export($export.S, 'Number', {EPSILON: Math.pow(2, -52)});
  1742. /***/ }),
  1743. /* 87 */
  1744. /***/ (function(module, exports, __webpack_require__) {
  1745. // 20.1.2.2 Number.isFinite(number)
  1746. var $export = __webpack_require__(0)
  1747. , _isFinite = __webpack_require__(2).isFinite;
  1748. $export($export.S, 'Number', {
  1749. isFinite: function isFinite(it){
  1750. return typeof it == 'number' && _isFinite(it);
  1751. }
  1752. });
  1753. /***/ }),
  1754. /* 88 */
  1755. /***/ (function(module, exports, __webpack_require__) {
  1756. // 20.1.2.3 Number.isInteger(number)
  1757. var $export = __webpack_require__(0);
  1758. $export($export.S, 'Number', {isInteger: __webpack_require__(60)});
  1759. /***/ }),
  1760. /* 89 */
  1761. /***/ (function(module, exports, __webpack_require__) {
  1762. // 20.1.2.4 Number.isNaN(number)
  1763. var $export = __webpack_require__(0);
  1764. $export($export.S, 'Number', {
  1765. isNaN: function isNaN(number){
  1766. return number != number;
  1767. }
  1768. });
  1769. /***/ }),
  1770. /* 90 */
  1771. /***/ (function(module, exports, __webpack_require__) {
  1772. // 20.1.2.5 Number.isSafeInteger(number)
  1773. var $export = __webpack_require__(0)
  1774. , isInteger = __webpack_require__(60)
  1775. , abs = Math.abs;
  1776. $export($export.S, 'Number', {
  1777. isSafeInteger: function isSafeInteger(number){
  1778. return isInteger(number) && abs(number) <= 0x1fffffffffffff;
  1779. }
  1780. });
  1781. /***/ }),
  1782. /* 91 */
  1783. /***/ (function(module, exports, __webpack_require__) {
  1784. // 20.1.2.6 Number.MAX_SAFE_INTEGER
  1785. var $export = __webpack_require__(0);
  1786. $export($export.S, 'Number', {MAX_SAFE_INTEGER: 0x1fffffffffffff});
  1787. /***/ }),
  1788. /* 92 */
  1789. /***/ (function(module, exports, __webpack_require__) {
  1790. // 20.1.2.10 Number.MIN_SAFE_INTEGER
  1791. var $export = __webpack_require__(0);
  1792. $export($export.S, 'Number', {MIN_SAFE_INTEGER: -0x1fffffffffffff});
  1793. /***/ }),
  1794. /* 93 */
  1795. /***/ (function(module, exports, __webpack_require__) {
  1796. // 19.1.3.1 Object.assign(target, source)
  1797. var $export = __webpack_require__(0);
  1798. $export($export.S + $export.F, 'Object', {assign: __webpack_require__(65)});
  1799. /***/ }),
  1800. /* 94 */
  1801. /***/ (function(module, exports, __webpack_require__) {
  1802. // 19.1.3.10 Object.is(value1, value2)
  1803. var $export = __webpack_require__(0);
  1804. $export($export.S, 'Object', {is: __webpack_require__(262)});
  1805. /***/ }),
  1806. /* 95 */
  1807. /***/ (function(module, exports, __webpack_require__) {
  1808. // 19.1.3.19 Object.setPrototypeOf(O, proto)
  1809. var $export = __webpack_require__(0);
  1810. $export($export.S, 'Object', {setPrototypeOf: __webpack_require__(68).set});
  1811. /***/ }),
  1812. /* 96 */
  1813. /***/ (function(module, exports, __webpack_require__) {
  1814. "use strict";
  1815. var LIBRARY = __webpack_require__(31)
  1816. , global = __webpack_require__(2)
  1817. , ctx = __webpack_require__(10)
  1818. , classof = __webpack_require__(53)
  1819. , $export = __webpack_require__(0)
  1820. , isObject = __webpack_require__(3)
  1821. , aFunction = __webpack_require__(36)
  1822. , anInstance = __webpack_require__(26)
  1823. , forOf = __webpack_require__(30)
  1824. , speciesConstructor = __webpack_require__(263)
  1825. , task = __webpack_require__(49).set
  1826. , microtask = __webpack_require__(257)()
  1827. , PROMISE = 'Promise'
  1828. , TypeError = global.TypeError
  1829. , process = global.process
  1830. , $Promise = global[PROMISE]
  1831. , process = global.process
  1832. , isNode = classof(process) == 'process'
  1833. , empty = function(){ /* empty */ }
  1834. , Internal, GenericPromiseCapability, Wrapper;
  1835. var USE_NATIVE = !!function(){
  1836. try {
  1837. // correct subclassing with @@species support
  1838. var promise = $Promise.resolve(1)
  1839. , FakePromise = (promise.constructor = {})[__webpack_require__(1)('species')] = function(exec){ exec(empty, empty); };
  1840. // unhandled rejections tracking support, NodeJS Promise without it fails @@species test
  1841. return (isNode || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise;
  1842. } catch(e){ /* empty */ }
  1843. }();
  1844. // helpers
  1845. var sameConstructor = function(a, b){
  1846. // with library wrapper special case
  1847. return a === b || a === $Promise && b === Wrapper;
  1848. };
  1849. var isThenable = function(it){
  1850. var then;
  1851. return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
  1852. };
  1853. var newPromiseCapability = function(C){
  1854. return sameConstructor($Promise, C)
  1855. ? new PromiseCapability(C)
  1856. : new GenericPromiseCapability(C);
  1857. };
  1858. var PromiseCapability = GenericPromiseCapability = function(C){
  1859. var resolve, reject;
  1860. this.promise = new C(function($$resolve, $$reject){
  1861. if(resolve !== undefined || reject !== undefined)throw TypeError('Bad Promise constructor');
  1862. resolve = $$resolve;
  1863. reject = $$reject;
  1864. });
  1865. this.resolve = aFunction(resolve);
  1866. this.reject = aFunction(reject);
  1867. };
  1868. var perform = function(exec){
  1869. try {
  1870. exec();
  1871. } catch(e){
  1872. return {error: e};
  1873. }
  1874. };
  1875. var notify = function(promise, isReject){
  1876. if(promise._n)return;
  1877. promise._n = true;
  1878. var chain = promise._c;
  1879. microtask(function(){
  1880. var value = promise._v
  1881. , ok = promise._s == 1
  1882. , i = 0;
  1883. var run = function(reaction){
  1884. var handler = ok ? reaction.ok : reaction.fail
  1885. , resolve = reaction.resolve
  1886. , reject = reaction.reject
  1887. , domain = reaction.domain
  1888. , result, then;
  1889. try {
  1890. if(handler){
  1891. if(!ok){
  1892. if(promise._h == 2)onHandleUnhandled(promise);
  1893. promise._h = 1;
  1894. }
  1895. if(handler === true)result = value;
  1896. else {
  1897. if(domain)domain.enter();
  1898. result = handler(value);
  1899. if(domain)domain.exit();
  1900. }
  1901. if(result === reaction.promise){
  1902. reject(TypeError('Promise-chain cycle'));
  1903. } else if(then = isThenable(result)){
  1904. then.call(result, resolve, reject);
  1905. } else resolve(result);
  1906. } else reject(value);
  1907. } catch(e){
  1908. reject(e);
  1909. }
  1910. };
  1911. while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
  1912. promise._c = [];
  1913. promise._n = false;
  1914. if(isReject && !promise._h)onUnhandled(promise);
  1915. });
  1916. };
  1917. var onUnhandled = function(promise){
  1918. task.call(global, function(){
  1919. var value = promise._v
  1920. , abrupt, handler, console;
  1921. if(isUnhandled(promise)){
  1922. abrupt = perform(function(){
  1923. if(isNode){
  1924. process.emit('unhandledRejection', value, promise);
  1925. } else if(handler = global.onunhandledrejection){
  1926. handler({promise: promise, reason: value});
  1927. } else if((console = global.console) && console.error){
  1928. console.error('Unhandled promise rejection', value);
  1929. }
  1930. });
  1931. // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
  1932. promise._h = isNode || isUnhandled(promise) ? 2 : 1;
  1933. } promise._a = undefined;
  1934. if(abrupt)throw abrupt.error;
  1935. });
  1936. };
  1937. var isUnhandled = function(promise){
  1938. if(promise._h == 1)return false;
  1939. var chain = promise._a || promise._c
  1940. , i = 0
  1941. , reaction;
  1942. while(chain.length > i){
  1943. reaction = chain[i++];
  1944. if(reaction.fail || !isUnhandled(reaction.promise))return false;
  1945. } return true;
  1946. };
  1947. var onHandleUnhandled = function(promise){
  1948. task.call(global, function(){
  1949. var handler;
  1950. if(isNode){
  1951. process.emit('rejectionHandled', promise);
  1952. } else if(handler = global.onrejectionhandled){
  1953. handler({promise: promise, reason: promise._v});
  1954. }
  1955. });
  1956. };
  1957. var $reject = function(value){
  1958. var promise = this;
  1959. if(promise._d)return;
  1960. promise._d = true;
  1961. promise = promise._w || promise; // unwrap
  1962. promise._v = value;
  1963. promise._s = 2;
  1964. if(!promise._a)promise._a = promise._c.slice();
  1965. notify(promise, true);
  1966. };
  1967. var $resolve = function(value){
  1968. var promise = this
  1969. , then;
  1970. if(promise._d)return;
  1971. promise._d = true;
  1972. promise = promise._w || promise; // unwrap
  1973. try {
  1974. if(promise === value)throw TypeError("Promise can't be resolved itself");
  1975. if(then = isThenable(value)){
  1976. microtask(function(){
  1977. var wrapper = {_w: promise, _d: false}; // wrap
  1978. try {
  1979. then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
  1980. } catch(e){
  1981. $reject.call(wrapper, e);
  1982. }
  1983. });
  1984. } else {
  1985. promise._v = value;
  1986. promise._s = 1;
  1987. notify(promise, false);
  1988. }
  1989. } catch(e){
  1990. $reject.call({_w: promise, _d: false}, e); // wrap
  1991. }
  1992. };
  1993. // constructor polyfill
  1994. if(!USE_NATIVE){
  1995. // 25.4.3.1 Promise(executor)
  1996. $Promise = function Promise(executor){
  1997. anInstance(this, $Promise, PROMISE, '_h');
  1998. aFunction(executor);
  1999. Internal.call(this);
  2000. try {
  2001. executor(ctx($resolve, this, 1), ctx($reject, this, 1));
  2002. } catch(err){
  2003. $reject.call(this, err);
  2004. }
  2005. };
  2006. Internal = function Promise(executor){
  2007. this._c = []; // <- awaiting reactions
  2008. this._a = undefined; // <- checked in isUnhandled reactions
  2009. this._s = 0; // <- state
  2010. this._d = false; // <- done
  2011. this._v = undefined; // <- value
  2012. this._h = 0; // <- rejection state, 0 - default, 1 - handled, 2 - unhandled
  2013. this._n = false; // <- notify
  2014. };
  2015. Internal.prototype = __webpack_require__(33)($Promise.prototype, {
  2016. // 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
  2017. then: function then(onFulfilled, onRejected){
  2018. var reaction = newPromiseCapability(speciesConstructor(this, $Promise));
  2019. reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
  2020. reaction.fail = typeof onRejected == 'function' && onRejected;
  2021. reaction.domain = isNode ? process.domain : undefined;
  2022. this._c.push(reaction);
  2023. if(this._a)this._a.push(reaction);
  2024. if(this._s)notify(this, false);
  2025. return reaction.promise;
  2026. },
  2027. // 25.4.5.1 Promise.prototype.catch(onRejected)
  2028. 'catch': function(onRejected){
  2029. return this.then(undefined, onRejected);
  2030. }
  2031. });
  2032. PromiseCapability = function(){
  2033. var promise = new Internal;
  2034. this.promise = promise;
  2035. this.resolve = ctx($resolve, promise, 1);
  2036. this.reject = ctx($reject, promise, 1);
  2037. };
  2038. }
  2039. $export($export.G + $export.W + $export.F * !USE_NATIVE, {Promise: $Promise});
  2040. __webpack_require__(24)($Promise, PROMISE);
  2041. __webpack_require__(69)(PROMISE);
  2042. Wrapper = __webpack_require__(20)[PROMISE];
  2043. // statics
  2044. $export($export.S + $export.F * !USE_NATIVE, PROMISE, {
  2045. // 25.4.4.5 Promise.reject(r)
  2046. reject: function reject(r){
  2047. var capability = newPromiseCapability(this)
  2048. , $$reject = capability.reject;
  2049. $$reject(r);
  2050. return capability.promise;
  2051. }
  2052. });
  2053. $export($export.S + $export.F * (LIBRARY || !USE_NATIVE), PROMISE, {
  2054. // 25.4.4.6 Promise.resolve(x)
  2055. resolve: function resolve(x){
  2056. // instanceof instead of internal slot check because we should fix it without replacement native Promise core
  2057. if(x instanceof $Promise && sameConstructor(x.constructor, this))return x;
  2058. var capability = newPromiseCapability(this)
  2059. , $$resolve = capability.resolve;
  2060. $$resolve(x);
  2061. return capability.promise;
  2062. }
  2063. });
  2064. $export($export.S + $export.F * !(USE_NATIVE && __webpack_require__(42)(function(iter){
  2065. $Promise.all(iter)['catch'](empty);
  2066. })), PROMISE, {
  2067. // 25.4.4.1 Promise.all(iterable)
  2068. all: function all(iterable){
  2069. var C = this
  2070. , capability = newPromiseCapability(C)
  2071. , resolve = capability.resolve
  2072. , reject = capability.reject;
  2073. var abrupt = perform(function(){
  2074. var values = []
  2075. , index = 0
  2076. , remaining = 1;
  2077. forOf(iterable, false, function(promise){
  2078. var $index = index++
  2079. , alreadyCalled = false;
  2080. values.push(undefined);
  2081. remaining++;
  2082. C.resolve(promise).then(function(value){
  2083. if(alreadyCalled)return;
  2084. alreadyCalled = true;
  2085. values[$index] = value;
  2086. --remaining || resolve(values);
  2087. }, reject);
  2088. });
  2089. --remaining || resolve(values);
  2090. });
  2091. if(abrupt)reject(abrupt.error);
  2092. return capability.promise;
  2093. },
  2094. // 25.4.4.4 Promise.race(iterable)
  2095. race: function race(iterable){
  2096. var C = this
  2097. , capability = newPromiseCapability(C)
  2098. , reject = capability.reject;
  2099. var abrupt = perform(function(){
  2100. forOf(iterable, false, function(promise){
  2101. C.resolve(promise).then(capability.resolve, reject);
  2102. });
  2103. });
  2104. if(abrupt)reject(abrupt.error);
  2105. return capability.promise;
  2106. }
  2107. });
  2108. /***/ }),
  2109. /* 97 */
  2110. /***/ (function(module, exports, __webpack_require__) {
  2111. // 21.2.5.3 get RegExp.prototype.flags()
  2112. if(__webpack_require__(6) && /./g.flags != 'g')__webpack_require__(5).f(RegExp.prototype, 'flags', {
  2113. configurable: true,
  2114. get: __webpack_require__(252)
  2115. });
  2116. /***/ }),
  2117. /* 98 */
  2118. /***/ (function(module, exports, __webpack_require__) {
  2119. // @@match logic
  2120. __webpack_require__(29)('match', 1, function(defined, MATCH, $match){
  2121. // 21.1.3.11 String.prototype.match(regexp)
  2122. return [function match(regexp){
  2123. 'use strict';
  2124. var O = defined(this)
  2125. , fn = regexp == undefined ? undefined : regexp[MATCH];
  2126. return fn !== undefined ? fn.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
  2127. }, $match];
  2128. });
  2129. /***/ }),
  2130. /* 99 */
  2131. /***/ (function(module, exports, __webpack_require__) {
  2132. // @@replace logic
  2133. __webpack_require__(29)('replace', 2, function(defined, REPLACE, $replace){
  2134. // 21.1.3.14 String.prototype.replace(searchValue, replaceValue)
  2135. return [function replace(searchValue, replaceValue){
  2136. 'use strict';
  2137. var O = defined(this)
  2138. , fn = searchValue == undefined ? undefined : searchValue[REPLACE];
  2139. return fn !== undefined
  2140. ? fn.call(searchValue, O, replaceValue)
  2141. : $replace.call(String(O), searchValue, replaceValue);
  2142. }, $replace];
  2143. });
  2144. /***/ }),
  2145. /* 100 */
  2146. /***/ (function(module, exports, __webpack_require__) {
  2147. // @@search logic
  2148. __webpack_require__(29)('search', 1, function(defined, SEARCH, $search){
  2149. // 21.1.3.15 String.prototype.search(regexp)
  2150. return [function search(regexp){
  2151. 'use strict';
  2152. var O = defined(this)
  2153. , fn = regexp == undefined ? undefined : regexp[SEARCH];
  2154. return fn !== undefined ? fn.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
  2155. }, $search];
  2156. });
  2157. /***/ }),
  2158. /* 101 */
  2159. /***/ (function(module, exports, __webpack_require__) {
  2160. // @@split logic
  2161. __webpack_require__(29)('split', 2, function(defined, SPLIT, $split){
  2162. 'use strict';
  2163. var isRegExp = __webpack_require__(61)
  2164. , _split = $split
  2165. , $push = [].push
  2166. , $SPLIT = 'split'
  2167. , LENGTH = 'length'
  2168. , LAST_INDEX = 'lastIndex';
  2169. if(
  2170. 'abbc'[$SPLIT](/(b)*/)[1] == 'c' ||
  2171. 'test'[$SPLIT](/(?:)/, -1)[LENGTH] != 4 ||
  2172. 'ab'[$SPLIT](/(?:ab)*/)[LENGTH] != 2 ||
  2173. '.'[$SPLIT](/(.?)(.?)/)[LENGTH] != 4 ||
  2174. '.'[$SPLIT](/()()/)[LENGTH] > 1 ||
  2175. ''[$SPLIT](/.?/)[LENGTH]
  2176. ){
  2177. var NPCG = /()??/.exec('')[1] === undefined; // nonparticipating capturing group
  2178. // based on es5-shim implementation, need to rework it
  2179. $split = function(separator, limit){
  2180. var string = String(this);
  2181. if(separator === undefined && limit === 0)return [];
  2182. // If `separator` is not a regex, use native split
  2183. if(!isRegExp(separator))return _split.call(string, separator, limit);
  2184. var output = [];
  2185. var flags = (separator.ignoreCase ? 'i' : '') +
  2186. (separator.multiline ? 'm' : '') +
  2187. (separator.unicode ? 'u' : '') +
  2188. (separator.sticky ? 'y' : '');
  2189. var lastLastIndex = 0;
  2190. var splitLimit = limit === undefined ? 4294967295 : limit >>> 0;
  2191. // Make `global` and avoid `lastIndex` issues by working with a copy
  2192. var separatorCopy = new RegExp(separator.source, flags + 'g');
  2193. var separator2, match, lastIndex, lastLength, i;
  2194. // Doesn't need flags gy, but they don't hurt
  2195. if(!NPCG)separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags);
  2196. while(match = separatorCopy.exec(string)){
  2197. // `separatorCopy.lastIndex` is not reliable cross-browser
  2198. lastIndex = match.index + match[0][LENGTH];
  2199. if(lastIndex > lastLastIndex){
  2200. output.push(string.slice(lastLastIndex, match.index));
  2201. // Fix browsers whose `exec` methods don't consistently return `undefined` for NPCG
  2202. if(!NPCG && match[LENGTH] > 1)match[0].replace(separator2, function(){
  2203. for(i = 1; i < arguments[LENGTH] - 2; i++)if(arguments[i] === undefined)match[i] = undefined;
  2204. });
  2205. if(match[LENGTH] > 1 && match.index < string[LENGTH])$push.apply(output, match.slice(1));
  2206. lastLength = match[0][LENGTH];
  2207. lastLastIndex = lastIndex;
  2208. if(output[LENGTH] >= splitLimit)break;
  2209. }
  2210. if(separatorCopy[LAST_INDEX] === match.index)separatorCopy[LAST_INDEX]++; // Avoid an infinite loop
  2211. }
  2212. if(lastLastIndex === string[LENGTH]){
  2213. if(lastLength || !separatorCopy.test(''))output.push('');
  2214. } else output.push(string.slice(lastLastIndex));
  2215. return output[LENGTH] > splitLimit ? output.slice(0, splitLimit) : output;
  2216. };
  2217. // Chakra, V8
  2218. } else if('0'[$SPLIT](undefined, 0)[LENGTH]){
  2219. $split = function(separator, limit){
  2220. return separator === undefined && limit === 0 ? [] : _split.call(this, separator, limit);
  2221. };
  2222. }
  2223. // 21.1.3.17 String.prototype.split(separator, limit)
  2224. return [function split(separator, limit){
  2225. var O = defined(this)
  2226. , fn = separator == undefined ? undefined : separator[SPLIT];
  2227. return fn !== undefined ? fn.call(separator, O, limit) : $split.call(String(O), separator, limit);
  2228. }, $split];
  2229. });
  2230. /***/ }),
  2231. /* 102 */
  2232. /***/ (function(module, exports, __webpack_require__) {
  2233. "use strict";
  2234. var strong = __webpack_require__(54);
  2235. // 23.2 Set Objects
  2236. module.exports = __webpack_require__(28)('Set', function(get){
  2237. return function Set(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); };
  2238. }, {
  2239. // 23.2.3.1 Set.prototype.add(value)
  2240. add: function add(value){
  2241. return strong.def(this, value = value === 0 ? 0 : value, value);
  2242. }
  2243. }, strong);
  2244. /***/ }),
  2245. /* 103 */
  2246. /***/ (function(module, exports, __webpack_require__) {
  2247. "use strict";
  2248. var $export = __webpack_require__(0)
  2249. , $at = __webpack_require__(264)(false);
  2250. $export($export.P, 'String', {
  2251. // 21.1.3.3 String.prototype.codePointAt(pos)
  2252. codePointAt: function codePointAt(pos){
  2253. return $at(this, pos);
  2254. }
  2255. });
  2256. /***/ }),
  2257. /* 104 */
  2258. /***/ (function(module, exports, __webpack_require__) {
  2259. "use strict";
  2260. // 21.1.3.6 String.prototype.endsWith(searchString [, endPosition])
  2261. var $export = __webpack_require__(0)
  2262. , toLength = __webpack_require__(9)
  2263. , context = __webpack_require__(48)
  2264. , ENDS_WITH = 'endsWith'
  2265. , $endsWith = ''[ENDS_WITH];
  2266. $export($export.P + $export.F * __webpack_require__(40)(ENDS_WITH), 'String', {
  2267. endsWith: function endsWith(searchString /*, endPosition = @length */){
  2268. var that = context(this, searchString, ENDS_WITH)
  2269. , endPosition = arguments.length > 1 ? arguments[1] : undefined
  2270. , len = toLength(that.length)
  2271. , end = endPosition === undefined ? len : Math.min(toLength(endPosition), len)
  2272. , search = String(searchString);
  2273. return $endsWith
  2274. ? $endsWith.call(that, search, end)
  2275. : that.slice(end - search.length, end) === search;
  2276. }
  2277. });
  2278. /***/ }),
  2279. /* 105 */
  2280. /***/ (function(module, exports, __webpack_require__) {
  2281. var $export = __webpack_require__(0)
  2282. , toIndex = __webpack_require__(34)
  2283. , fromCharCode = String.fromCharCode
  2284. , $fromCodePoint = String.fromCodePoint;
  2285. // length should be 1, old FF problem
  2286. $export($export.S + $export.F * (!!$fromCodePoint && $fromCodePoint.length != 1), 'String', {
  2287. // 21.1.2.2 String.fromCodePoint(...codePoints)
  2288. fromCodePoint: function fromCodePoint(x){ // eslint-disable-line no-unused-vars
  2289. var res = []
  2290. , aLen = arguments.length
  2291. , i = 0
  2292. , code;
  2293. while(aLen > i){
  2294. code = +arguments[i++];
  2295. if(toIndex(code, 0x10ffff) !== code)throw RangeError(code + ' is not a valid code point');
  2296. res.push(code < 0x10000
  2297. ? fromCharCode(code)
  2298. : fromCharCode(((code -= 0x10000) >> 10) + 0xd800, code % 0x400 + 0xdc00)
  2299. );
  2300. } return res.join('');
  2301. }
  2302. });
  2303. /***/ }),
  2304. /* 106 */
  2305. /***/ (function(module, exports, __webpack_require__) {
  2306. "use strict";
  2307. // 21.1.3.7 String.prototype.includes(searchString, position = 0)
  2308. var $export = __webpack_require__(0)
  2309. , context = __webpack_require__(48)
  2310. , INCLUDES = 'includes';
  2311. $export($export.P + $export.F * __webpack_require__(40)(INCLUDES), 'String', {
  2312. includes: function includes(searchString /*, position = 0 */){
  2313. return !!~context(this, searchString, INCLUDES)
  2314. .indexOf(searchString, arguments.length > 1 ? arguments[1] : undefined);
  2315. }
  2316. });
  2317. /***/ }),
  2318. /* 107 */
  2319. /***/ (function(module, exports, __webpack_require__) {
  2320. var $export = __webpack_require__(0)
  2321. , toIObject = __webpack_require__(8)
  2322. , toLength = __webpack_require__(9);
  2323. $export($export.S, 'String', {
  2324. // 21.1.2.4 String.raw(callSite, ...substitutions)
  2325. raw: function raw(callSite){
  2326. var tpl = toIObject(callSite.raw)
  2327. , len = toLength(tpl.length)
  2328. , aLen = arguments.length
  2329. , res = []
  2330. , i = 0;
  2331. while(len > i){
  2332. res.push(String(tpl[i++]));
  2333. if(i < aLen)res.push(String(arguments[i]));
  2334. } return res.join('');
  2335. }
  2336. });
  2337. /***/ }),
  2338. /* 108 */
  2339. /***/ (function(module, exports, __webpack_require__) {
  2340. var $export = __webpack_require__(0);
  2341. $export($export.P, 'String', {
  2342. // 21.1.3.13 String.prototype.repeat(count)
  2343. repeat: __webpack_require__(71)
  2344. });
  2345. /***/ }),
  2346. /* 109 */
  2347. /***/ (function(module, exports, __webpack_require__) {
  2348. "use strict";
  2349. // 21.1.3.18 String.prototype.startsWith(searchString [, position ])
  2350. var $export = __webpack_require__(0)
  2351. , toLength = __webpack_require__(9)
  2352. , context = __webpack_require__(48)
  2353. , STARTS_WITH = 'startsWith'
  2354. , $startsWith = ''[STARTS_WITH];
  2355. $export($export.P + $export.F * __webpack_require__(40)(STARTS_WITH), 'String', {
  2356. startsWith: function startsWith(searchString /*, position = 0 */){
  2357. var that = context(this, searchString, STARTS_WITH)
  2358. , index = toLength(Math.min(arguments.length > 1 ? arguments[1] : undefined, that.length))
  2359. , search = String(searchString);
  2360. return $startsWith
  2361. ? $startsWith.call(that, search, index)
  2362. : that.slice(index, index + search.length) === search;
  2363. }
  2364. });
  2365. /***/ }),
  2366. /* 110 */
  2367. /***/ (function(module, exports, __webpack_require__) {
  2368. "use strict";
  2369. // ECMAScript 6 symbols shim
  2370. var global = __webpack_require__(2)
  2371. , has = __webpack_require__(7)
  2372. , DESCRIPTORS = __webpack_require__(6)
  2373. , $export = __webpack_require__(0)
  2374. , redefine = __webpack_require__(14)
  2375. , META = __webpack_require__(22).KEY
  2376. , $fails = __webpack_require__(12)
  2377. , shared = __webpack_require__(47)
  2378. , setToStringTag = __webpack_require__(24)
  2379. , uid = __webpack_require__(25)
  2380. , wks = __webpack_require__(1)
  2381. , wksExt = __webpack_require__(72)
  2382. , wksDefine = __webpack_require__(265)
  2383. , keyOf = __webpack_require__(256)
  2384. , enumKeys = __webpack_require__(251)
  2385. , isArray = __webpack_require__(59)
  2386. , anObject = __webpack_require__(4)
  2387. , toIObject = __webpack_require__(8)
  2388. , toPrimitive = __webpack_require__(50)
  2389. , createDesc = __webpack_require__(18)
  2390. , _create = __webpack_require__(43)
  2391. , gOPNExt = __webpack_require__(259)
  2392. , $GOPD = __webpack_require__(44)
  2393. , $DP = __webpack_require__(5)
  2394. , $keys = __webpack_require__(17)
  2395. , gOPD = $GOPD.f
  2396. , dP = $DP.f
  2397. , gOPN = gOPNExt.f
  2398. , $Symbol = global.Symbol
  2399. , $JSON = global.JSON
  2400. , _stringify = $JSON && $JSON.stringify
  2401. , PROTOTYPE = 'prototype'
  2402. , HIDDEN = wks('_hidden')
  2403. , TO_PRIMITIVE = wks('toPrimitive')
  2404. , isEnum = {}.propertyIsEnumerable
  2405. , SymbolRegistry = shared('symbol-registry')
  2406. , AllSymbols = shared('symbols')
  2407. , OPSymbols = shared('op-symbols')
  2408. , ObjectProto = Object[PROTOTYPE]
  2409. , USE_NATIVE = typeof $Symbol == 'function'
  2410. , QObject = global.QObject;
  2411. // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
  2412. var setter = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild;
  2413. // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
  2414. var setSymbolDesc = DESCRIPTORS && $fails(function(){
  2415. return _create(dP({}, 'a', {
  2416. get: function(){ return dP(this, 'a', {value: 7}).a; }
  2417. })).a != 7;
  2418. }) ? function(it, key, D){
  2419. var protoDesc = gOPD(ObjectProto, key);
  2420. if(protoDesc)delete ObjectProto[key];
  2421. dP(it, key, D);
  2422. if(protoDesc && it !== ObjectProto)dP(ObjectProto, key, protoDesc);
  2423. } : dP;
  2424. var wrap = function(tag){
  2425. var sym = AllSymbols[tag] = _create($Symbol[PROTOTYPE]);
  2426. sym._k = tag;
  2427. return sym;
  2428. };
  2429. var isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function(it){
  2430. return typeof it == 'symbol';
  2431. } : function(it){
  2432. return it instanceof $Symbol;
  2433. };
  2434. var $defineProperty = function defineProperty(it, key, D){
  2435. if(it === ObjectProto)$defineProperty(OPSymbols, key, D);
  2436. anObject(it);
  2437. key = toPrimitive(key, true);
  2438. anObject(D);
  2439. if(has(AllSymbols, key)){
  2440. if(!D.enumerable){
  2441. if(!has(it, HIDDEN))dP(it, HIDDEN, createDesc(1, {}));
  2442. it[HIDDEN][key] = true;
  2443. } else {
  2444. if(has(it, HIDDEN) && it[HIDDEN][key])it[HIDDEN][key] = false;
  2445. D = _create(D, {enumerable: createDesc(0, false)});
  2446. } return setSymbolDesc(it, key, D);
  2447. } return dP(it, key, D);
  2448. };
  2449. var $defineProperties = function defineProperties(it, P){
  2450. anObject(it);
  2451. var keys = enumKeys(P = toIObject(P))
  2452. , i = 0
  2453. , l = keys.length
  2454. , key;
  2455. while(l > i)$defineProperty(it, key = keys[i++], P[key]);
  2456. return it;
  2457. };
  2458. var $create = function create(it, P){
  2459. return P === undefined ? _create(it) : $defineProperties(_create(it), P);
  2460. };
  2461. var $propertyIsEnumerable = function propertyIsEnumerable(key){
  2462. var E = isEnum.call(this, key = toPrimitive(key, true));
  2463. if(this === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return false;
  2464. return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] ? E : true;
  2465. };
  2466. var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key){
  2467. it = toIObject(it);
  2468. key = toPrimitive(key, true);
  2469. if(it === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return;
  2470. var D = gOPD(it, key);
  2471. if(D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key]))D.enumerable = true;
  2472. return D;
  2473. };
  2474. var $getOwnPropertyNames = function getOwnPropertyNames(it){
  2475. var names = gOPN(toIObject(it))
  2476. , result = []
  2477. , i = 0
  2478. , key;
  2479. while(names.length > i){
  2480. if(!has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META)result.push(key);
  2481. } return result;
  2482. };
  2483. var $getOwnPropertySymbols = function getOwnPropertySymbols(it){
  2484. var IS_OP = it === ObjectProto
  2485. , names = gOPN(IS_OP ? OPSymbols : toIObject(it))
  2486. , result = []
  2487. , i = 0
  2488. , key;
  2489. while(names.length > i){
  2490. if(has(AllSymbols, key = names[i++]) && (IS_OP ? has(ObjectProto, key) : true))result.push(AllSymbols[key]);
  2491. } return result;
  2492. };
  2493. // 19.4.1.1 Symbol([description])
  2494. if(!USE_NATIVE){
  2495. $Symbol = function Symbol(){
  2496. if(this instanceof $Symbol)throw TypeError('Symbol is not a constructor!');
  2497. var tag = uid(arguments.length > 0 ? arguments[0] : undefined);
  2498. var $set = function(value){
  2499. if(this === ObjectProto)$set.call(OPSymbols, value);
  2500. if(has(this, HIDDEN) && has(this[HIDDEN], tag))this[HIDDEN][tag] = false;
  2501. setSymbolDesc(this, tag, createDesc(1, value));
  2502. };
  2503. if(DESCRIPTORS && setter)setSymbolDesc(ObjectProto, tag, {configurable: true, set: $set});
  2504. return wrap(tag);
  2505. };
  2506. redefine($Symbol[PROTOTYPE], 'toString', function toString(){
  2507. return this._k;
  2508. });
  2509. $GOPD.f = $getOwnPropertyDescriptor;
  2510. $DP.f = $defineProperty;
  2511. __webpack_require__(45).f = gOPNExt.f = $getOwnPropertyNames;
  2512. __webpack_require__(23).f = $propertyIsEnumerable;
  2513. __webpack_require__(32).f = $getOwnPropertySymbols;
  2514. if(DESCRIPTORS && !__webpack_require__(31)){
  2515. redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true);
  2516. }
  2517. wksExt.f = function(name){
  2518. return wrap(wks(name));
  2519. }
  2520. }
  2521. $export($export.G + $export.W + $export.F * !USE_NATIVE, {Symbol: $Symbol});
  2522. for(var symbols = (
  2523. // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14
  2524. 'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables'
  2525. ).split(','), i = 0; symbols.length > i; )wks(symbols[i++]);
  2526. for(var symbols = $keys(wks.store), i = 0; symbols.length > i; )wksDefine(symbols[i++]);
  2527. $export($export.S + $export.F * !USE_NATIVE, 'Symbol', {
  2528. // 19.4.2.1 Symbol.for(key)
  2529. 'for': function(key){
  2530. return has(SymbolRegistry, key += '')
  2531. ? SymbolRegistry[key]
  2532. : SymbolRegistry[key] = $Symbol(key);
  2533. },
  2534. // 19.4.2.5 Symbol.keyFor(sym)
  2535. keyFor: function keyFor(key){
  2536. if(isSymbol(key))return keyOf(SymbolRegistry, key);
  2537. throw TypeError(key + ' is not a symbol!');
  2538. },
  2539. useSetter: function(){ setter = true; },
  2540. useSimple: function(){ setter = false; }
  2541. });
  2542. $export($export.S + $export.F * !USE_NATIVE, 'Object', {
  2543. // 19.1.2.2 Object.create(O [, Properties])
  2544. create: $create,
  2545. // 19.1.2.4 Object.defineProperty(O, P, Attributes)
  2546. defineProperty: $defineProperty,
  2547. // 19.1.2.3 Object.defineProperties(O, Properties)
  2548. defineProperties: $defineProperties,
  2549. // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)
  2550. getOwnPropertyDescriptor: $getOwnPropertyDescriptor,
  2551. // 19.1.2.7 Object.getOwnPropertyNames(O)
  2552. getOwnPropertyNames: $getOwnPropertyNames,
  2553. // 19.1.2.8 Object.getOwnPropertySymbols(O)
  2554. getOwnPropertySymbols: $getOwnPropertySymbols
  2555. });
  2556. // 24.3.2 JSON.stringify(value [, replacer [, space]])
  2557. $JSON && $export($export.S + $export.F * (!USE_NATIVE || $fails(function(){
  2558. var S = $Symbol();
  2559. // MS Edge converts symbol values to JSON as {}
  2560. // WebKit converts symbol values to JSON as null
  2561. // V8 throws on boxed symbols
  2562. return _stringify([S]) != '[null]' || _stringify({a: S}) != '{}' || _stringify(Object(S)) != '{}';
  2563. })), 'JSON', {
  2564. stringify: function stringify(it){
  2565. if(it === undefined || isSymbol(it))return; // IE8 returns string on undefined
  2566. var args = [it]
  2567. , i = 1
  2568. , replacer, $replacer;
  2569. while(arguments.length > i)args.push(arguments[i++]);
  2570. replacer = args[1];
  2571. if(typeof replacer == 'function')$replacer = replacer;
  2572. if($replacer || !isArray(replacer))replacer = function(key, value){
  2573. if($replacer)value = $replacer.call(this, key, value);
  2574. if(!isSymbol(value))return value;
  2575. };
  2576. args[1] = replacer;
  2577. return _stringify.apply($JSON, args);
  2578. }
  2579. });
  2580. // 19.4.3.4 Symbol.prototype[@@toPrimitive](hint)
  2581. $Symbol[PROTOTYPE][TO_PRIMITIVE] || __webpack_require__(13)($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf);
  2582. // 19.4.3.5 Symbol.prototype[@@toStringTag]
  2583. setToStringTag($Symbol, 'Symbol');
  2584. // 20.2.1.9 Math[@@toStringTag]
  2585. setToStringTag(Math, 'Math', true);
  2586. // 24.3.3 JSON[@@toStringTag]
  2587. setToStringTag(global.JSON, 'JSON', true);
  2588. /***/ }),
  2589. /* 111 */
  2590. /***/ (function(module, exports, __webpack_require__) {
  2591. "use strict";
  2592. var each = __webpack_require__(27)(0)
  2593. , redefine = __webpack_require__(14)
  2594. , meta = __webpack_require__(22)
  2595. , assign = __webpack_require__(65)
  2596. , weak = __webpack_require__(55)
  2597. , isObject = __webpack_require__(3)
  2598. , getWeak = meta.getWeak
  2599. , isExtensible = Object.isExtensible
  2600. , uncaughtFrozenStore = weak.ufstore
  2601. , tmp = {}
  2602. , InternalMap;
  2603. var wrapper = function(get){
  2604. return function WeakMap(){
  2605. return get(this, arguments.length > 0 ? arguments[0] : undefined);
  2606. };
  2607. };
  2608. var methods = {
  2609. // 23.3.3.3 WeakMap.prototype.get(key)
  2610. get: function get(key){
  2611. if(isObject(key)){
  2612. var data = getWeak(key);
  2613. if(data === true)return uncaughtFrozenStore(this).get(key);
  2614. return data ? data[this._i] : undefined;
  2615. }
  2616. },
  2617. // 23.3.3.5 WeakMap.prototype.set(key, value)
  2618. set: function set(key, value){
  2619. return weak.def(this, key, value);
  2620. }
  2621. };
  2622. // 23.3 WeakMap Objects
  2623. var $WeakMap = module.exports = __webpack_require__(28)('WeakMap', wrapper, methods, weak, true, true);
  2624. // IE11 WeakMap frozen keys fix
  2625. if(new $WeakMap().set((Object.freeze || Object)(tmp), 7).get(tmp) != 7){
  2626. InternalMap = weak.getConstructor(wrapper);
  2627. assign(InternalMap.prototype, methods);
  2628. meta.NEED = true;
  2629. each(['delete', 'has', 'get', 'set'], function(key){
  2630. var proto = $WeakMap.prototype
  2631. , method = proto[key];
  2632. redefine(proto, key, function(a, b){
  2633. // store frozen objects on internal weakmap shim
  2634. if(isObject(a) && !isExtensible(a)){
  2635. if(!this._f)this._f = new InternalMap;
  2636. var result = this._f[key](a, b);
  2637. return key == 'set' ? this : result;
  2638. // store all the rest on native weakmap
  2639. } return method.call(this, a, b);
  2640. });
  2641. });
  2642. }
  2643. /***/ }),
  2644. /* 112 */
  2645. /***/ (function(module, exports, __webpack_require__) {
  2646. "use strict";
  2647. var weak = __webpack_require__(55);
  2648. // 23.4 WeakSet Objects
  2649. __webpack_require__(28)('WeakSet', function(get){
  2650. return function WeakSet(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); };
  2651. }, {
  2652. // 23.4.3.1 WeakSet.prototype.add(value)
  2653. add: function add(value){
  2654. return weak.def(this, value, true);
  2655. }
  2656. }, weak, false, true);
  2657. /***/ }),
  2658. /* 113 */
  2659. /***/ (function(module, exports, __webpack_require__) {
  2660. "use strict";
  2661. // https://github.com/tc39/Array.prototype.includes
  2662. var $export = __webpack_require__(0)
  2663. , $includes = __webpack_require__(52)(true);
  2664. $export($export.P, 'Array', {
  2665. includes: function includes(el /*, fromIndex = 0 */){
  2666. return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
  2667. }
  2668. });
  2669. __webpack_require__(15)('includes');
  2670. /***/ }),
  2671. /* 114 */
  2672. /***/ (function(module, exports, __webpack_require__) {
  2673. // https://github.com/tc39/proposal-object-values-entries
  2674. var $export = __webpack_require__(0)
  2675. , $entries = __webpack_require__(67)(true);
  2676. $export($export.S, 'Object', {
  2677. entries: function entries(it){
  2678. return $entries(it);
  2679. }
  2680. });
  2681. /***/ }),
  2682. /* 115 */
  2683. /***/ (function(module, exports, __webpack_require__) {
  2684. // https://github.com/tc39/proposal-object-getownpropertydescriptors
  2685. var $export = __webpack_require__(0)
  2686. , ownKeys = __webpack_require__(261)
  2687. , toIObject = __webpack_require__(8)
  2688. , gOPD = __webpack_require__(44)
  2689. , createProperty = __webpack_require__(37);
  2690. $export($export.S, 'Object', {
  2691. getOwnPropertyDescriptors: function getOwnPropertyDescriptors(object){
  2692. var O = toIObject(object)
  2693. , getDesc = gOPD.f
  2694. , keys = ownKeys(O)
  2695. , result = {}
  2696. , i = 0
  2697. , key;
  2698. while(keys.length > i)createProperty(result, key = keys[i++], getDesc(O, key));
  2699. return result;
  2700. }
  2701. });
  2702. /***/ }),
  2703. /* 116 */
  2704. /***/ (function(module, exports, __webpack_require__) {
  2705. // https://github.com/tc39/proposal-object-values-entries
  2706. var $export = __webpack_require__(0)
  2707. , $values = __webpack_require__(67)(false);
  2708. $export($export.S, 'Object', {
  2709. values: function values(it){
  2710. return $values(it);
  2711. }
  2712. });
  2713. /***/ }),
  2714. /* 117 */
  2715. /***/ (function(module, exports, __webpack_require__) {
  2716. "use strict";
  2717. // https://github.com/tc39/proposal-string-pad-start-end
  2718. var $export = __webpack_require__(0)
  2719. , $pad = __webpack_require__(70);
  2720. $export($export.P, 'String', {
  2721. padEnd: function padEnd(maxLength /*, fillString = ' ' */){
  2722. return $pad(this, maxLength, arguments.length > 1 ? arguments[1] : undefined, false);
  2723. }
  2724. });
  2725. /***/ }),
  2726. /* 118 */
  2727. /***/ (function(module, exports, __webpack_require__) {
  2728. "use strict";
  2729. // https://github.com/tc39/proposal-string-pad-start-end
  2730. var $export = __webpack_require__(0)
  2731. , $pad = __webpack_require__(70);
  2732. $export($export.P, 'String', {
  2733. padStart: function padStart(maxLength /*, fillString = ' ' */){
  2734. return $pad(this, maxLength, arguments.length > 1 ? arguments[1] : undefined, true);
  2735. }
  2736. });
  2737. /***/ }),
  2738. /* 119 */
  2739. /***/ (function(module, exports, __webpack_require__) {
  2740. var $iterators = __webpack_require__(51)
  2741. , redefine = __webpack_require__(14)
  2742. , global = __webpack_require__(2)
  2743. , hide = __webpack_require__(13)
  2744. , Iterators = __webpack_require__(21)
  2745. , wks = __webpack_require__(1)
  2746. , ITERATOR = wks('iterator')
  2747. , TO_STRING_TAG = wks('toStringTag')
  2748. , ArrayValues = Iterators.Array;
  2749. for(var collections = ['NodeList', 'DOMTokenList', 'MediaList', 'StyleSheetList', 'CSSRuleList'], i = 0; i < 5; i++){
  2750. var NAME = collections[i]
  2751. , Collection = global[NAME]
  2752. , proto = Collection && Collection.prototype
  2753. , key;
  2754. if(proto){
  2755. if(!proto[ITERATOR])hide(proto, ITERATOR, ArrayValues);
  2756. if(!proto[TO_STRING_TAG])hide(proto, TO_STRING_TAG, NAME);
  2757. Iterators[NAME] = ArrayValues;
  2758. for(key in $iterators)if(!proto[key])redefine(proto, key, $iterators[key], true);
  2759. }
  2760. }
  2761. /***/ }),
  2762. /* 120 */
  2763. /***/ (function(module, exports, __webpack_require__) {
  2764. var $export = __webpack_require__(0)
  2765. , $task = __webpack_require__(49);
  2766. $export($export.G + $export.B, {
  2767. setImmediate: $task.set,
  2768. clearImmediate: $task.clear
  2769. });
  2770. /***/ }),
  2771. /* 121 */
  2772. /***/ (function(module, exports, __webpack_require__) {
  2773. /* WEBPACK VAR INJECTION */(function(global) {var co = __webpack_require__(246),
  2774. isGeneratorFn = __webpack_require__(266).fn;
  2775. var DEFAULT_METHODS = [
  2776. 'afterAll',
  2777. 'afterEach',
  2778. 'beforeAll',
  2779. 'beforeEach',
  2780. 'it', 'fit', //'xit',
  2781. ];
  2782. var EXPECTS_NAME = ['it', 'fit', 'xit'];
  2783. var originalMethods = {},
  2784. overrideMethods, installed;
  2785. module.exports = function jasmineCo(userFn) {
  2786. return wrapFn(userFn);
  2787. };
  2788. module.exports.install = function install() {
  2789. (overrideMethods || DEFAULT_METHODS).forEach(function(fname) {
  2790. coifyJasmineFn(fname);
  2791. });
  2792. installed = true;
  2793. };
  2794. module.exports.uninstall = function uninstall() {
  2795. Object.keys(originalMethods).forEach(function(key) {
  2796. global[key] = originalMethods[key];
  2797. });
  2798. originalMethods = {};
  2799. installed = false;
  2800. };
  2801. module.exports.isInstalled = function isInstalled() {
  2802. return installed;
  2803. };
  2804. module.exports.setOverrideMethods = function setOverrideMethods(methods) {
  2805. overrideMethods = Array.isArray(methods) ? methods : DEFAULT_METHODS;
  2806. };
  2807. function coifyJasmineFn(fname) {
  2808. // don't process methods that don't exist globally or have already been overridden
  2809. if (!global[fname] || originalMethods[fname]) { return; }
  2810. var origFn = originalMethods[fname] = global[fname];
  2811. global[fname] = wrapFn(origFn, EXPECTS_NAME.indexOf(fname) !== -1);
  2812. }
  2813. function wrapFn(origFn, expectsName) {
  2814. return function() {
  2815. var userFn = expectsName ? arguments[1] : arguments[0];
  2816. var restParams = [].slice.call(arguments, expectsName ? 2 : 1);
  2817. var args;
  2818. if (isGeneratorFn(userFn)) {
  2819. // if the user method is a generator:
  2820. // 1. call it with the correct `this` context object
  2821. // 2. wrap it in a co function which fails the spec if an exception is
  2822. // encountered and notifies jasmine that the spec is done when the co
  2823. // promise settles
  2824. args = [function(done) {
  2825. return co(userFn.bind(this)).then(done, done.fail);
  2826. }];
  2827. if (expectsName) { args.unshift(arguments[0]); }
  2828. if (restParams.length) { args.push.apply(args, restParams); }
  2829. return origFn.apply(null, args);
  2830. } else if (userFn && !userFn.length) {
  2831. // if the user method is a standard function that doesn't expect to be asynchronous
  2832. // (i.e. it doesn't take `done` as a parameter), wrap it with a function that *is*
  2833. // asynchronous and retrofit it to support returning a promise from the function
  2834. args = [function(done) {
  2835. var result = userFn.call(this);
  2836. if (!(result && typeof result.then === 'function')) {
  2837. done();
  2838. return result;
  2839. } else {
  2840. result.then(done, done.fail);
  2841. }
  2842. }];
  2843. if (expectsName) { args.unshift(arguments[0]); }
  2844. if (restParams.length) { args.push.apply(args, restParams); }
  2845. return origFn.apply(null, args);
  2846. } else {
  2847. // if the user method is already asynchronous, just call the standard jasmine method
  2848. // and let the user method take care of itself
  2849. return origFn.apply(null, arguments);
  2850. }
  2851. };
  2852. }
  2853. /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(74)))
  2854. /***/ }),
  2855. /* 122 */
  2856. /***/ (function(module, exports, __webpack_require__) {
  2857. /* WEBPACK VAR INJECTION */(function(global) {/**
  2858. * Copyright (c) 2014, Facebook, Inc.
  2859. * All rights reserved.
  2860. *
  2861. * This source code is licensed under the BSD-style license found in the
  2862. * https://raw.github.com/facebook/regenerator/master/LICENSE file. An
  2863. * additional grant of patent rights can be found in the PATENTS file in
  2864. * the same directory.
  2865. */
  2866. !(function(global) {
  2867. "use strict";
  2868. var Op = Object.prototype;
  2869. var hasOwn = Op.hasOwnProperty;
  2870. var undefined; // More compressible than void 0.
  2871. var $Symbol = typeof Symbol === "function" ? Symbol : {};
  2872. var iteratorSymbol = $Symbol.iterator || "@@iterator";
  2873. var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
  2874. var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
  2875. var inModule = typeof module === "object";
  2876. var runtime = global.regeneratorRuntime;
  2877. if (runtime) {
  2878. if (inModule) {
  2879. // If regeneratorRuntime is defined globally and we're in a module,
  2880. // make the exports object identical to regeneratorRuntime.
  2881. module.exports = runtime;
  2882. }
  2883. // Don't bother evaluating the rest of this file if the runtime was
  2884. // already defined globally.
  2885. return;
  2886. }
  2887. // Define the runtime globally (as expected by generated code) as either
  2888. // module.exports (if we're in a module) or a new, empty object.
  2889. runtime = global.regeneratorRuntime = inModule ? module.exports : {};
  2890. function wrap(innerFn, outerFn, self, tryLocsList) {
  2891. // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
  2892. var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
  2893. var generator = Object.create(protoGenerator.prototype);
  2894. var context = new Context(tryLocsList || []);
  2895. // The ._invoke method unifies the implementations of the .next,
  2896. // .throw, and .return methods.
  2897. generator._invoke = makeInvokeMethod(innerFn, self, context);
  2898. return generator;
  2899. }
  2900. runtime.wrap = wrap;
  2901. // Try/catch helper to minimize deoptimizations. Returns a completion
  2902. // record like context.tryEntries[i].completion. This interface could
  2903. // have been (and was previously) designed to take a closure to be
  2904. // invoked without arguments, but in all the cases we care about we
  2905. // already have an existing method we want to call, so there's no need
  2906. // to create a new function object. We can even get away with assuming
  2907. // the method takes exactly one argument, since that happens to be true
  2908. // in every case, so we don't have to touch the arguments object. The
  2909. // only additional allocation required is the completion record, which
  2910. // has a stable shape and so hopefully should be cheap to allocate.
  2911. function tryCatch(fn, obj, arg) {
  2912. try {
  2913. return { type: "normal", arg: fn.call(obj, arg) };
  2914. } catch (err) {
  2915. return { type: "throw", arg: err };
  2916. }
  2917. }
  2918. var GenStateSuspendedStart = "suspendedStart";
  2919. var GenStateSuspendedYield = "suspendedYield";
  2920. var GenStateExecuting = "executing";
  2921. var GenStateCompleted = "completed";
  2922. // Returning this object from the innerFn has the same effect as
  2923. // breaking out of the dispatch switch statement.
  2924. var ContinueSentinel = {};
  2925. // Dummy constructor functions that we use as the .constructor and
  2926. // .constructor.prototype properties for functions that return Generator
  2927. // objects. For full spec compliance, you may wish to configure your
  2928. // minifier not to mangle the names of these two functions.
  2929. function Generator() {}
  2930. function GeneratorFunction() {}
  2931. function GeneratorFunctionPrototype() {}
  2932. // This is a polyfill for %IteratorPrototype% for environments that
  2933. // don't natively support it.
  2934. var IteratorPrototype = {};
  2935. IteratorPrototype[iteratorSymbol] = function () {
  2936. return this;
  2937. };
  2938. var getProto = Object.getPrototypeOf;
  2939. var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
  2940. if (NativeIteratorPrototype &&
  2941. NativeIteratorPrototype !== Op &&
  2942. hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
  2943. // This environment has a native %IteratorPrototype%; use it instead
  2944. // of the polyfill.
  2945. IteratorPrototype = NativeIteratorPrototype;
  2946. }
  2947. var Gp = GeneratorFunctionPrototype.prototype =
  2948. Generator.prototype = Object.create(IteratorPrototype);
  2949. GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
  2950. GeneratorFunctionPrototype.constructor = GeneratorFunction;
  2951. GeneratorFunctionPrototype[toStringTagSymbol] =
  2952. GeneratorFunction.displayName = "GeneratorFunction";
  2953. // Helper for defining the .next, .throw, and .return methods of the
  2954. // Iterator interface in terms of a single ._invoke method.
  2955. function defineIteratorMethods(prototype) {
  2956. ["next", "throw", "return"].forEach(function(method) {
  2957. prototype[method] = function(arg) {
  2958. return this._invoke(method, arg);
  2959. };
  2960. });
  2961. }
  2962. runtime.isGeneratorFunction = function(genFun) {
  2963. var ctor = typeof genFun === "function" && genFun.constructor;
  2964. return ctor
  2965. ? ctor === GeneratorFunction ||
  2966. // For the native GeneratorFunction constructor, the best we can
  2967. // do is to check its .name property.
  2968. (ctor.displayName || ctor.name) === "GeneratorFunction"
  2969. : false;
  2970. };
  2971. runtime.mark = function(genFun) {
  2972. if (Object.setPrototypeOf) {
  2973. Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
  2974. } else {
  2975. genFun.__proto__ = GeneratorFunctionPrototype;
  2976. if (!(toStringTagSymbol in genFun)) {
  2977. genFun[toStringTagSymbol] = "GeneratorFunction";
  2978. }
  2979. }
  2980. genFun.prototype = Object.create(Gp);
  2981. return genFun;
  2982. };
  2983. // Within the body of any async function, `await x` is transformed to
  2984. // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
  2985. // `hasOwn.call(value, "__await")` to determine if the yielded value is
  2986. // meant to be awaited.
  2987. runtime.awrap = function(arg) {
  2988. return { __await: arg };
  2989. };
  2990. function AsyncIterator(generator) {
  2991. function invoke(method, arg, resolve, reject) {
  2992. var record = tryCatch(generator[method], generator, arg);
  2993. if (record.type === "throw") {
  2994. reject(record.arg);
  2995. } else {
  2996. var result = record.arg;
  2997. var value = result.value;
  2998. if (value &&
  2999. typeof value === "object" &&
  3000. hasOwn.call(value, "__await")) {
  3001. return Promise.resolve(value.__await).then(function(value) {
  3002. invoke("next", value, resolve, reject);
  3003. }, function(err) {
  3004. invoke("throw", err, resolve, reject);
  3005. });
  3006. }
  3007. return Promise.resolve(value).then(function(unwrapped) {
  3008. // When a yielded Promise is resolved, its final value becomes
  3009. // the .value of the Promise<{value,done}> result for the
  3010. // current iteration. If the Promise is rejected, however, the
  3011. // result for this iteration will be rejected with the same
  3012. // reason. Note that rejections of yielded Promises are not
  3013. // thrown back into the generator function, as is the case
  3014. // when an awaited Promise is rejected. This difference in
  3015. // behavior between yield and await is important, because it
  3016. // allows the consumer to decide what to do with the yielded
  3017. // rejection (swallow it and continue, manually .throw it back
  3018. // into the generator, abandon iteration, whatever). With
  3019. // await, by contrast, there is no opportunity to examine the
  3020. // rejection reason outside the generator function, so the
  3021. // only option is to throw it from the await expression, and
  3022. // let the generator function handle the exception.
  3023. result.value = unwrapped;
  3024. resolve(result);
  3025. }, reject);
  3026. }
  3027. }
  3028. if (typeof global.process === "object" && global.process.domain) {
  3029. invoke = global.process.domain.bind(invoke);
  3030. }
  3031. var previousPromise;
  3032. function enqueue(method, arg) {
  3033. function callInvokeWithMethodAndArg() {
  3034. return new Promise(function(resolve, reject) {
  3035. invoke(method, arg, resolve, reject);
  3036. });
  3037. }
  3038. return previousPromise =
  3039. // If enqueue has been called before, then we want to wait until
  3040. // all previous Promises have been resolved before calling invoke,
  3041. // so that results are always delivered in the correct order. If
  3042. // enqueue has not been called before, then it is important to
  3043. // call invoke immediately, without waiting on a callback to fire,
  3044. // so that the async generator function has the opportunity to do
  3045. // any necessary setup in a predictable way. This predictability
  3046. // is why the Promise constructor synchronously invokes its
  3047. // executor callback, and why async functions synchronously
  3048. // execute code before the first await. Since we implement simple
  3049. // async functions in terms of async generators, it is especially
  3050. // important to get this right, even though it requires care.
  3051. previousPromise ? previousPromise.then(
  3052. callInvokeWithMethodAndArg,
  3053. // Avoid propagating failures to Promises returned by later
  3054. // invocations of the iterator.
  3055. callInvokeWithMethodAndArg
  3056. ) : callInvokeWithMethodAndArg();
  3057. }
  3058. // Define the unified helper method that is used to implement .next,
  3059. // .throw, and .return (see defineIteratorMethods).
  3060. this._invoke = enqueue;
  3061. }
  3062. defineIteratorMethods(AsyncIterator.prototype);
  3063. AsyncIterator.prototype[asyncIteratorSymbol] = function () {
  3064. return this;
  3065. };
  3066. runtime.AsyncIterator = AsyncIterator;
  3067. // Note that simple async functions are implemented on top of
  3068. // AsyncIterator objects; they just return a Promise for the value of
  3069. // the final result produced by the iterator.
  3070. runtime.async = function(innerFn, outerFn, self, tryLocsList) {
  3071. var iter = new AsyncIterator(
  3072. wrap(innerFn, outerFn, self, tryLocsList)
  3073. );
  3074. return runtime.isGeneratorFunction(outerFn)
  3075. ? iter // If outerFn is a generator, return the full iterator.
  3076. : iter.next().then(function(result) {
  3077. return result.done ? result.value : iter.next();
  3078. });
  3079. };
  3080. function makeInvokeMethod(innerFn, self, context) {
  3081. var state = GenStateSuspendedStart;
  3082. return function invoke(method, arg) {
  3083. if (state === GenStateExecuting) {
  3084. throw new Error("Generator is already running");
  3085. }
  3086. if (state === GenStateCompleted) {
  3087. if (method === "throw") {
  3088. throw arg;
  3089. }
  3090. // Be forgiving, per 25.3.3.3.3 of the spec:
  3091. // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
  3092. return doneResult();
  3093. }
  3094. context.method = method;
  3095. context.arg = arg;
  3096. while (true) {
  3097. var delegate = context.delegate;
  3098. if (delegate) {
  3099. var delegateResult = maybeInvokeDelegate(delegate, context);
  3100. if (delegateResult) {
  3101. if (delegateResult === ContinueSentinel) continue;
  3102. return delegateResult;
  3103. }
  3104. }
  3105. if (context.method === "next") {
  3106. // Setting context._sent for legacy support of Babel's
  3107. // function.sent implementation.
  3108. context.sent = context._sent = context.arg;
  3109. } else if (context.method === "throw") {
  3110. if (state === GenStateSuspendedStart) {
  3111. state = GenStateCompleted;
  3112. throw context.arg;
  3113. }
  3114. context.dispatchException(context.arg);
  3115. } else if (context.method === "return") {
  3116. context.abrupt("return", context.arg);
  3117. }
  3118. state = GenStateExecuting;
  3119. var record = tryCatch(innerFn, self, context);
  3120. if (record.type === "normal") {
  3121. // If an exception is thrown from innerFn, we leave state ===
  3122. // GenStateExecuting and loop back for another invocation.
  3123. state = context.done
  3124. ? GenStateCompleted
  3125. : GenStateSuspendedYield;
  3126. if (record.arg === ContinueSentinel) {
  3127. continue;
  3128. }
  3129. return {
  3130. value: record.arg,
  3131. done: context.done
  3132. };
  3133. } else if (record.type === "throw") {
  3134. state = GenStateCompleted;
  3135. // Dispatch the exception by looping back around to the
  3136. // context.dispatchException(context.arg) call above.
  3137. context.method = "throw";
  3138. context.arg = record.arg;
  3139. }
  3140. }
  3141. };
  3142. }
  3143. // Call delegate.iterator[context.method](context.arg) and handle the
  3144. // result, either by returning a { value, done } result from the
  3145. // delegate iterator, or by modifying context.method and context.arg,
  3146. // setting context.delegate to null, and returning the ContinueSentinel.
  3147. function maybeInvokeDelegate(delegate, context) {
  3148. var method = delegate.iterator[context.method];
  3149. if (method === undefined) {
  3150. // A .throw or .return when the delegate iterator has no .throw
  3151. // method always terminates the yield* loop.
  3152. context.delegate = null;
  3153. if (context.method === "throw") {
  3154. if (delegate.iterator.return) {
  3155. // If the delegate iterator has a return method, give it a
  3156. // chance to clean up.
  3157. context.method = "return";
  3158. context.arg = undefined;
  3159. maybeInvokeDelegate(delegate, context);
  3160. if (context.method === "throw") {
  3161. // If maybeInvokeDelegate(context) changed context.method from
  3162. // "return" to "throw", let that override the TypeError below.
  3163. return ContinueSentinel;
  3164. }
  3165. }
  3166. context.method = "throw";
  3167. context.arg = new TypeError(
  3168. "The iterator does not provide a 'throw' method");
  3169. }
  3170. return ContinueSentinel;
  3171. }
  3172. var record = tryCatch(method, delegate.iterator, context.arg);
  3173. if (record.type === "throw") {
  3174. context.method = "throw";
  3175. context.arg = record.arg;
  3176. context.delegate = null;
  3177. return ContinueSentinel;
  3178. }
  3179. var info = record.arg;
  3180. if (! info) {
  3181. context.method = "throw";
  3182. context.arg = new TypeError("iterator result is not an object");
  3183. context.delegate = null;
  3184. return ContinueSentinel;
  3185. }
  3186. if (info.done) {
  3187. // Assign the result of the finished delegate to the temporary
  3188. // variable specified by delegate.resultName (see delegateYield).
  3189. context[delegate.resultName] = info.value;
  3190. // Resume execution at the desired location (see delegateYield).
  3191. context.next = delegate.nextLoc;
  3192. // If context.method was "throw" but the delegate handled the
  3193. // exception, let the outer generator proceed normally. If
  3194. // context.method was "next", forget context.arg since it has been
  3195. // "consumed" by the delegate iterator. If context.method was
  3196. // "return", allow the original .return call to continue in the
  3197. // outer generator.
  3198. if (context.method !== "return") {
  3199. context.method = "next";
  3200. context.arg = undefined;
  3201. }
  3202. } else {
  3203. // Re-yield the result returned by the delegate method.
  3204. return info;
  3205. }
  3206. // The delegate iterator is finished, so forget it and continue with
  3207. // the outer generator.
  3208. context.delegate = null;
  3209. return ContinueSentinel;
  3210. }
  3211. // Define Generator.prototype.{next,throw,return} in terms of the
  3212. // unified ._invoke helper method.
  3213. defineIteratorMethods(Gp);
  3214. Gp[toStringTagSymbol] = "Generator";
  3215. // A Generator should always return itself as the iterator object when the
  3216. // @@iterator function is called on it. Some browsers' implementations of the
  3217. // iterator prototype chain incorrectly implement this, causing the Generator
  3218. // object to not be returned from this call. This ensures that doesn't happen.
  3219. // See https://github.com/facebook/regenerator/issues/274 for more details.
  3220. Gp[iteratorSymbol] = function() {
  3221. return this;
  3222. };
  3223. Gp.toString = function() {
  3224. return "[object Generator]";
  3225. };
  3226. function pushTryEntry(locs) {
  3227. var entry = { tryLoc: locs[0] };
  3228. if (1 in locs) {
  3229. entry.catchLoc = locs[1];
  3230. }
  3231. if (2 in locs) {
  3232. entry.finallyLoc = locs[2];
  3233. entry.afterLoc = locs[3];
  3234. }
  3235. this.tryEntries.push(entry);
  3236. }
  3237. function resetTryEntry(entry) {
  3238. var record = entry.completion || {};
  3239. record.type = "normal";
  3240. delete record.arg;
  3241. entry.completion = record;
  3242. }
  3243. function Context(tryLocsList) {
  3244. // The root entry object (effectively a try statement without a catch
  3245. // or a finally block) gives us a place to store values thrown from
  3246. // locations where there is no enclosing try statement.
  3247. this.tryEntries = [{ tryLoc: "root" }];
  3248. tryLocsList.forEach(pushTryEntry, this);
  3249. this.reset(true);
  3250. }
  3251. runtime.keys = function(object) {
  3252. var keys = [];
  3253. for (var key in object) {
  3254. keys.push(key);
  3255. }
  3256. keys.reverse();
  3257. // Rather than returning an object with a next method, we keep
  3258. // things simple and return the next function itself.
  3259. return function next() {
  3260. while (keys.length) {
  3261. var key = keys.pop();
  3262. if (key in object) {
  3263. next.value = key;
  3264. next.done = false;
  3265. return next;
  3266. }
  3267. }
  3268. // To avoid creating an additional object, we just hang the .value
  3269. // and .done properties off the next function object itself. This
  3270. // also ensures that the minifier will not anonymize the function.
  3271. next.done = true;
  3272. return next;
  3273. };
  3274. };
  3275. function values(iterable) {
  3276. if (iterable) {
  3277. var iteratorMethod = iterable[iteratorSymbol];
  3278. if (iteratorMethod) {
  3279. return iteratorMethod.call(iterable);
  3280. }
  3281. if (typeof iterable.next === "function") {
  3282. return iterable;
  3283. }
  3284. if (!isNaN(iterable.length)) {
  3285. var i = -1, next = function next() {
  3286. while (++i < iterable.length) {
  3287. if (hasOwn.call(iterable, i)) {
  3288. next.value = iterable[i];
  3289. next.done = false;
  3290. return next;
  3291. }
  3292. }
  3293. next.value = undefined;
  3294. next.done = true;
  3295. return next;
  3296. };
  3297. return next.next = next;
  3298. }
  3299. }
  3300. // Return an iterator with no values.
  3301. return { next: doneResult };
  3302. }
  3303. runtime.values = values;
  3304. function doneResult() {
  3305. return { value: undefined, done: true };
  3306. }
  3307. Context.prototype = {
  3308. constructor: Context,
  3309. reset: function(skipTempReset) {
  3310. this.prev = 0;
  3311. this.next = 0;
  3312. // Resetting context._sent for legacy support of Babel's
  3313. // function.sent implementation.
  3314. this.sent = this._sent = undefined;
  3315. this.done = false;
  3316. this.delegate = null;
  3317. this.method = "next";
  3318. this.arg = undefined;
  3319. this.tryEntries.forEach(resetTryEntry);
  3320. if (!skipTempReset) {
  3321. for (var name in this) {
  3322. // Not sure about the optimal order of these conditions:
  3323. if (name.charAt(0) === "t" &&
  3324. hasOwn.call(this, name) &&
  3325. !isNaN(+name.slice(1))) {
  3326. this[name] = undefined;
  3327. }
  3328. }
  3329. }
  3330. },
  3331. stop: function() {
  3332. this.done = true;
  3333. var rootEntry = this.tryEntries[0];
  3334. var rootRecord = rootEntry.completion;
  3335. if (rootRecord.type === "throw") {
  3336. throw rootRecord.arg;
  3337. }
  3338. return this.rval;
  3339. },
  3340. dispatchException: function(exception) {
  3341. if (this.done) {
  3342. throw exception;
  3343. }
  3344. var context = this;
  3345. function handle(loc, caught) {
  3346. record.type = "throw";
  3347. record.arg = exception;
  3348. context.next = loc;
  3349. if (caught) {
  3350. // If the dispatched exception was caught by a catch block,
  3351. // then let that catch block handle the exception normally.
  3352. context.method = "next";
  3353. context.arg = undefined;
  3354. }
  3355. return !! caught;
  3356. }
  3357. for (var i = this.tryEntries.length - 1; i >= 0; --i) {
  3358. var entry = this.tryEntries[i];
  3359. var record = entry.completion;
  3360. if (entry.tryLoc === "root") {
  3361. // Exception thrown outside of any try block that could handle
  3362. // it, so set the completion value of the entire function to
  3363. // throw the exception.
  3364. return handle("end");
  3365. }
  3366. if (entry.tryLoc <= this.prev) {
  3367. var hasCatch = hasOwn.call(entry, "catchLoc");
  3368. var hasFinally = hasOwn.call(entry, "finallyLoc");
  3369. if (hasCatch && hasFinally) {
  3370. if (this.prev < entry.catchLoc) {
  3371. return handle(entry.catchLoc, true);
  3372. } else if (this.prev < entry.finallyLoc) {
  3373. return handle(entry.finallyLoc);
  3374. }
  3375. } else if (hasCatch) {
  3376. if (this.prev < entry.catchLoc) {
  3377. return handle(entry.catchLoc, true);
  3378. }
  3379. } else if (hasFinally) {
  3380. if (this.prev < entry.finallyLoc) {
  3381. return handle(entry.finallyLoc);
  3382. }
  3383. } else {
  3384. throw new Error("try statement without catch or finally");
  3385. }
  3386. }
  3387. }
  3388. },
  3389. abrupt: function(type, arg) {
  3390. for (var i = this.tryEntries.length - 1; i >= 0; --i) {
  3391. var entry = this.tryEntries[i];
  3392. if (entry.tryLoc <= this.prev &&
  3393. hasOwn.call(entry, "finallyLoc") &&
  3394. this.prev < entry.finallyLoc) {
  3395. var finallyEntry = entry;
  3396. break;
  3397. }
  3398. }
  3399. if (finallyEntry &&
  3400. (type === "break" ||
  3401. type === "continue") &&
  3402. finallyEntry.tryLoc <= arg &&
  3403. arg <= finallyEntry.finallyLoc) {
  3404. // Ignore the finally entry if control is not jumping to a
  3405. // location outside the try/catch block.
  3406. finallyEntry = null;
  3407. }
  3408. var record = finallyEntry ? finallyEntry.completion : {};
  3409. record.type = type;
  3410. record.arg = arg;
  3411. if (finallyEntry) {
  3412. this.method = "next";
  3413. this.next = finallyEntry.finallyLoc;
  3414. return ContinueSentinel;
  3415. }
  3416. return this.complete(record);
  3417. },
  3418. complete: function(record, afterLoc) {
  3419. if (record.type === "throw") {
  3420. throw record.arg;
  3421. }
  3422. if (record.type === "break" ||
  3423. record.type === "continue") {
  3424. this.next = record.arg;
  3425. } else if (record.type === "return") {
  3426. this.rval = this.arg = record.arg;
  3427. this.method = "return";
  3428. this.next = "end";
  3429. } else if (record.type === "normal" && afterLoc) {
  3430. this.next = afterLoc;
  3431. }
  3432. return ContinueSentinel;
  3433. },
  3434. finish: function(finallyLoc) {
  3435. for (var i = this.tryEntries.length - 1; i >= 0; --i) {
  3436. var entry = this.tryEntries[i];
  3437. if (entry.finallyLoc === finallyLoc) {
  3438. this.complete(entry.completion, entry.afterLoc);
  3439. resetTryEntry(entry);
  3440. return ContinueSentinel;
  3441. }
  3442. }
  3443. },
  3444. "catch": function(tryLoc) {
  3445. for (var i = this.tryEntries.length - 1; i >= 0; --i) {
  3446. var entry = this.tryEntries[i];
  3447. if (entry.tryLoc === tryLoc) {
  3448. var record = entry.completion;
  3449. if (record.type === "throw") {
  3450. var thrown = record.arg;
  3451. resetTryEntry(entry);
  3452. }
  3453. return thrown;
  3454. }
  3455. }
  3456. // The context.catch method must only be called with a location
  3457. // argument that corresponds to a known catch block.
  3458. throw new Error("illegal catch attempt");
  3459. },
  3460. delegateYield: function(iterable, resultName, nextLoc) {
  3461. this.delegate = {
  3462. iterator: values(iterable),
  3463. resultName: resultName,
  3464. nextLoc: nextLoc
  3465. };
  3466. if (this.method === "next") {
  3467. // Deliberately forget the last sent value so that we don't
  3468. // accidentally pass it on to the delegate.
  3469. this.arg = undefined;
  3470. }
  3471. return ContinueSentinel;
  3472. }
  3473. };
  3474. })(
  3475. // Among the various tricks for obtaining a reference to the global
  3476. // object, this seems to be the most reliable technique that does not
  3477. // use indirect eval (which violates Content Security Policy).
  3478. typeof global === "object" ? global :
  3479. typeof window === "object" ? window :
  3480. typeof self === "object" ? self : this
  3481. );
  3482. /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(74)))
  3483. /***/ }),
  3484. /* 123 */
  3485. /***/ (function(module, exports, __webpack_require__) {
  3486. var map = {
  3487. "./autoColumnSize/test/autoColumnSize.e2e.js": 126,
  3488. "./autoRowSize/test/autoRowSize.e2e.js": 127,
  3489. "./columnSorting/test/columnSorting.e2e.js": 128,
  3490. "./comments/test/comments.e2e.js": 129,
  3491. "./contextMenu/test/alignment.e2e.js": 130,
  3492. "./contextMenu/test/contextMenu.e2e.js": 131,
  3493. "./contextMenu/test/predefinedItems/readOnly.e2e.js": 132,
  3494. "./contextMenuCopyPaste/test/contextMenuCopyPaste.e2e.js": 133,
  3495. "./copyPaste/test/copyPaste.e2e.js": 134,
  3496. "./customBorders/test/customBorders.e2e.js": 135,
  3497. "./dragToScroll/test/dragToScroll.e2e.js": 136,
  3498. "./manualColumnFreeze/test/manualColumnFreeze.e2e.js": 137,
  3499. "./manualColumnMove/test/manualColumnMove.e2e.js": 138,
  3500. "./manualColumnMove/test/manualColumnMoveUI.e2e.js": 139,
  3501. "./manualColumnResize/test/manualColumnResize.e2e.js": 140,
  3502. "./manualRowMove/test/manualRowMove.e2e.js": 141,
  3503. "./manualRowMove/test/manualRowMoveUI.e2e.js": 142,
  3504. "./manualRowResize/test/manualRowResize.e2e.js": 143,
  3505. "./mergeCells/test/canMergeRange.e2e.js": 144,
  3506. "./observeChanges/test/observeChanges.e2e.js": 145,
  3507. "./persistentState/test/persistentState.e2e.js": 146,
  3508. "./search/test/search.e2e.js": 147,
  3509. "./undoRedo/test/UndoRedo.e2e.js": 148
  3510. };
  3511. function webpackContext(req) {
  3512. return __webpack_require__(webpackContextResolve(req));
  3513. };
  3514. function webpackContextResolve(req) {
  3515. var id = map[req];
  3516. if(!(id + 1)) // check for number or string
  3517. throw new Error("Cannot find module '" + req + "'.");
  3518. return id;
  3519. };
  3520. webpackContext.keys = function webpackContextKeys() {
  3521. return Object.keys(map);
  3522. };
  3523. webpackContext.resolve = webpackContextResolve;
  3524. module.exports = webpackContext;
  3525. webpackContext.id = 123;
  3526. /***/ }),
  3527. /* 124 */
  3528. /***/ (function(module, exports, __webpack_require__) {
  3529. var map = {
  3530. "./ColHeader.spec.js": 149,
  3531. "./Core_alter.spec.js": 150,
  3532. "./Core_beforeKeyDown.spec.js": 151,
  3533. "./Core_beforechange.spec.js": 152,
  3534. "./Core_copy.spec.js": 153,
  3535. "./Core_count.spec.js": 154,
  3536. "./Core_dataSchema.spec.js": 155,
  3537. "./Core_datachange.spec.js": 156,
  3538. "./Core_destroy.spec.js": 157,
  3539. "./Core_destroyEditor.spec.js": 158,
  3540. "./Core_getCellMeta.spec.js": 159,
  3541. "./Core_getColHeader.spec.js": 160,
  3542. "./Core_getDataAt.spec.js": 161,
  3543. "./Core_getDataType.spec.js": 162,
  3544. "./Core_getRowHeader.spec.js": 163,
  3545. "./Core_init.spec.js": 164,
  3546. "./Core_isEmpty.spec.js": 165,
  3547. "./Core_keepEmptyRows.spec.js": 166,
  3548. "./Core_listen.spec.js": 167,
  3549. "./Core_loadData.spec.js": 168,
  3550. "./Core_navigation.spec.js": 169,
  3551. "./Core_onKeyDown.spec.js": 170,
  3552. "./Core_paste.spec.js": 171,
  3553. "./Core_populateFromArray.spec.js": 172,
  3554. "./Core_reCreate.spec.js": 173,
  3555. "./Core_removeCellMeta.spec.js": 174,
  3556. "./Core_render.spec.js": 175,
  3557. "./Core_selection.spec.js": 176,
  3558. "./Core_setDataAtCell.spec.js": 177,
  3559. "./Core_splice.spec.js": 178,
  3560. "./Core_update.spec.js": 179,
  3561. "./Core_validate.spec.js": 180,
  3562. "./Core_view.spec.js": 181,
  3563. "./Dom.spec.js": 182,
  3564. "./FillHandle.spec.js": 183,
  3565. "./Performance.spec.js": 184,
  3566. "./PluginHooks.spec.js": 185,
  3567. "./RowHeader.spec.js": 186,
  3568. "./cellTypes/index.spec.js": 187,
  3569. "./core/colToProp.spec.js": 188,
  3570. "./core/countSourceCols.spec.js": 189,
  3571. "./core/getCellMetaAtRow.spec.js": 190,
  3572. "./core/getCellsMeta.spec.js": 191,
  3573. "./core/getCopyableData.spec.js": 192,
  3574. "./core/getCopyableText.spec.js": 193,
  3575. "./core/getSourceDataArray.spec.js": 194,
  3576. "./core/getSourceDataAtCell.spec.js": 195,
  3577. "./core/propToCol.spec.js": 196,
  3578. "./core/setCellMeta.spec.js": 197,
  3579. "./core/spliceCellsMeta.spec.js": 198,
  3580. "./core/spliceCol.spec.js": 199,
  3581. "./core/spliceRow.spec.js": 200,
  3582. "./core/toPhysicalColumn.spec.js": 201,
  3583. "./core/toPhysicalRow.spec.js": 202,
  3584. "./core/toVisualColumn.spec.js": 203,
  3585. "./core/toVisualRow.spec.js": 204,
  3586. "./editors/autocompleteEditor.spec.js": 205,
  3587. "./editors/baseEditor.spec.js": 206,
  3588. "./editors/dateEditor.spec.js": 207,
  3589. "./editors/dropdownEditor.spec.js": 208,
  3590. "./editors/handsontableEditor.spec.js": 209,
  3591. "./editors/index.spec.js": 210,
  3592. "./editors/noEditor.spec.js": 211,
  3593. "./editors/numericEditor.spec.js": 212,
  3594. "./editors/passwordEditor.spec.js": 213,
  3595. "./editors/selectEditor.spec.js": 214,
  3596. "./editors/textEditor.spec.js": 215,
  3597. "./publicAPI.spec.js": 217,
  3598. "./renderers/autocompleteRenderer.spec.js": 218,
  3599. "./renderers/cellDecorator.spec.js": 219,
  3600. "./renderers/checkboxRenderer.spec.js": 220,
  3601. "./renderers/htmlRenderer.spec.js": 221,
  3602. "./renderers/index.spec.js": 222,
  3603. "./renderers/numericRenderer.spec.js": 223,
  3604. "./renderers/passwordRenderer.spec.js": 224,
  3605. "./renderers/textRenderer.spec.js": 225,
  3606. "./settings/colWidths.spec.js": 226,
  3607. "./settings/columns.spec.js": 227,
  3608. "./settings/copyable.spec.js": 228,
  3609. "./settings/currentHeaderClassName.spec.js": 229,
  3610. "./settings/currentRowClassName.spec.js": 230,
  3611. "./settings/editor.spec.js": 231,
  3612. "./settings/fixedColumnsLeft.spec.js": 232,
  3613. "./settings/fixedRowsTop.spec.js": 233,
  3614. "./settings/fragmentSelection.spec.js": 234,
  3615. "./settings/maxCols.spec.js": 235,
  3616. "./settings/maxRows.spec.js": 236,
  3617. "./settings/renderer.spec.js": 237,
  3618. "./settings/tableClassName.spec.js": 238,
  3619. "./utils/ghostTable.spec.js": 239,
  3620. "./validators/autocompleteValidator.spec.js": 240,
  3621. "./validators/dateValidator.spec.js": 241,
  3622. "./validators/index.spec.js": 242,
  3623. "./validators/numericValidator.spec.js": 243,
  3624. "./validators/timeValidator.spec.js": 244
  3625. };
  3626. function webpackContext(req) {
  3627. return __webpack_require__(webpackContextResolve(req));
  3628. };
  3629. function webpackContextResolve(req) {
  3630. var id = map[req];
  3631. if(!(id + 1)) // check for number or string
  3632. throw new Error("Cannot find module '" + req + "'.");
  3633. return id;
  3634. };
  3635. webpackContext.keys = function webpackContextKeys() {
  3636. return Object.keys(map);
  3637. };
  3638. webpackContext.resolve = webpackContextResolve;
  3639. module.exports = webpackContext;
  3640. webpackContext.id = 124;
  3641. /***/ }),
  3642. /* 125 */,
  3643. /* 126 */
  3644. /***/ (function(module, exports, __webpack_require__) {
  3645. "use strict";
  3646. function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
  3647. describe('AutoColumnSize', function () {
  3648. var id = 'testContainer';
  3649. beforeEach(function () {
  3650. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  3651. });
  3652. afterEach(function () {
  3653. if (this.$container) {
  3654. destroy();
  3655. this.$container.remove();
  3656. }
  3657. });
  3658. var arrayOfObjects = function arrayOfObjects() {
  3659. return [{ id: 'Short', name: 'Somewhat long', lastName: 'The very very very longest one', nestedData: [{ id: 1000 }] }];
  3660. };
  3661. it('should apply auto size by default', function () {
  3662. handsontable({
  3663. data: arrayOfObjects()
  3664. });
  3665. var width0 = colWidth(this.$container, 0);
  3666. var width1 = colWidth(this.$container, 1);
  3667. var width2 = colWidth(this.$container, 2);
  3668. expect(width0).toBeLessThan(width1);
  3669. expect(width1).toBeLessThan(width2);
  3670. });
  3671. it('should update column width after update value in cell (array of objects)', function () {
  3672. handsontable({
  3673. data: arrayOfObjects(),
  3674. autoColumnSize: true,
  3675. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }]
  3676. });
  3677. expect(colWidth(this.$container, 0)).toBeAroundValue(50, 3);
  3678. expect([117, 120, 121, 129, 135]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 1)]));
  3679. expect([216, 229, 247, 260]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 2)]));
  3680. setDataAtRowProp(0, 'id', 'foo bar foo bar foo bar');
  3681. setDataAtRowProp(0, 'name', 'foo');
  3682. expect([165, 168, 169, 189, 191]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3683. expect(colWidth(this.$container, 1)).toBeAroundValue(50, 3);
  3684. expect([216, 229, 247, 260]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 2)]));
  3685. });
  3686. it('should correctly detect column widths with colHeaders', function () {
  3687. handsontable({
  3688. data: arrayOfObjects(),
  3689. autoColumnSize: true,
  3690. colHeaders: ['Identifier Longer text'],
  3691. columns: [{ data: 'id' }, { data: 'name' }]
  3692. });
  3693. expect([149, 155, 174, 178]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3694. });
  3695. it('should correctly detect column widths after update colHeaders when headers were passed as an array', function () {
  3696. handsontable({
  3697. data: arrayOfObjects(),
  3698. autoColumnSize: true,
  3699. colHeaders: true,
  3700. columns: [{ data: 'id' }, { data: 'name' }]
  3701. });
  3702. expect([50, 51, 53]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3703. updateSettings({ colHeaders: ['Identifier Longer text', 'Identifier Longer and longer text'] });
  3704. expect([149, 155, 174, 178]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3705. expect([226, 235, 263, 270]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 1)]));
  3706. });
  3707. it('should correctly detect column widths after update colHeaders when headers were passed as a string', function () {
  3708. handsontable({
  3709. data: arrayOfObjects(),
  3710. autoColumnSize: true,
  3711. colHeaders: true,
  3712. columns: [{ data: 'id' }, { data: 'name' }]
  3713. });
  3714. expect([50, 51, 53]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3715. updateSettings({ colHeaders: 'Identifier Longer text' });
  3716. expect([149, 155, 174, 178]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3717. expect([149, 155, 174, 178]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 1)]));
  3718. });
  3719. it('should correctly detect column widths after update colHeaders when headers were passed as a function', function () {
  3720. handsontable({
  3721. data: arrayOfObjects(),
  3722. autoColumnSize: true,
  3723. colHeaders: true,
  3724. columns: [{ data: 'id' }, { data: 'name' }]
  3725. });
  3726. expect([50, 51, 53]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3727. updateSettings({
  3728. colHeaders: function colHeaders(index) {
  3729. return index === 0 ? 'Identifier Longer text' : 'Identifier Longer and longer text';
  3730. }
  3731. });
  3732. expect([149, 155, 174, 178]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3733. expect([226, 235, 263, 270]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 1)]));
  3734. });
  3735. it('should correctly detect column width with colHeaders and the useHeaders option set to false (not taking the header widths into calculation)', function () {
  3736. handsontable({
  3737. data: [{ id: 'ab' }],
  3738. autoColumnSize: {
  3739. useHeaders: false
  3740. },
  3741. colHeaders: ['Identifier'],
  3742. columns: [{ data: 'id' }]
  3743. });
  3744. expect(colWidth(this.$container, 0)).toBe(50);
  3745. });
  3746. it('should correctly detect column width with columns.title', function () {
  3747. handsontable({
  3748. data: arrayOfObjects(),
  3749. autoColumnSize: true,
  3750. columns: [{ data: 'id', title: 'Identifier' }]
  3751. });
  3752. expect([68, 70, 71, 80, 82]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3753. });
  3754. it('should correctly detect column widths after update columns.title', function () {
  3755. handsontable({
  3756. data: arrayOfObjects(),
  3757. autoColumnSize: true,
  3758. columns: [{ data: 'id', title: 'Identifier' }]
  3759. });
  3760. updateSettings({
  3761. columns: [{ data: 'id', title: 'Identifier with longer text' }]
  3762. });
  3763. expect([174, 182, 183, 208, 213]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3764. });
  3765. // https://github.com/handsontable/handsontable/issues/2684
  3766. it('should correctly detect column width when table is hidden on init (display: none)', _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
  3767. var hot;
  3768. return regeneratorRuntime.wrap(function _callee$(_context) {
  3769. while (1) {
  3770. switch (_context.prev = _context.next) {
  3771. case 0:
  3772. spec().$container.css('display', 'none');
  3773. hot = handsontable({
  3774. data: arrayOfObjects(),
  3775. autoColumnSize: true,
  3776. colHeaders: ['Identifier', 'First Name']
  3777. });
  3778. _context.next = 4;
  3779. return sleep(200);
  3780. case 4:
  3781. spec().$container.css('display', 'block');
  3782. hot.render();
  3783. expect([68, 70, 71, 80, 82]).toEqual(jasmine.arrayContaining([colWidth(spec().$container, 0)]));
  3784. case 7:
  3785. case 'end':
  3786. return _context.stop();
  3787. }
  3788. }
  3789. }, _callee, undefined);
  3790. })));
  3791. it('should keep last columns width unchanged if all rows was removed', function () {
  3792. var hot = handsontable({
  3793. data: arrayOfObjects(),
  3794. autoColumnSize: true,
  3795. columns: [{ data: 'id', title: 'Identifier' }, { data: 'name', title: 'Name' }, { data: 'lastName', title: 'Last Name' }]
  3796. });
  3797. expect([68, 70, 71, 80, 82]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3798. expect([117, 120, 121, 129, 135]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 1)]));
  3799. expect([216, 229, 247, 260]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 2)]));
  3800. hot.alter('remove_row', 0);
  3801. expect([68, 70, 71, 80, 82]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 0)]));
  3802. expect([117, 120, 121, 129, 135]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 1)]));
  3803. expect([216, 229, 247, 260]).toEqual(jasmine.arrayContaining([colWidth(this.$container, 2)]));
  3804. });
  3805. it('should be possible to disable plugin using updateSettings', function () {
  3806. handsontable({
  3807. data: arrayOfObjects()
  3808. });
  3809. var width0 = colWidth(this.$container, 0);
  3810. var width1 = colWidth(this.$container, 1);
  3811. var width2 = colWidth(this.$container, 2);
  3812. expect(width0).toBeLessThan(width1);
  3813. expect(width1).toBeLessThan(width2);
  3814. updateSettings({
  3815. autoColumnSize: false
  3816. });
  3817. width0 = colWidth(this.$container, 0);
  3818. width1 = colWidth(this.$container, 1);
  3819. width2 = colWidth(this.$container, 2);
  3820. expect(width0).toEqual(width1);
  3821. expect(width0).toEqual(width2);
  3822. expect(width1).toEqual(width2);
  3823. });
  3824. it('should apply disabling/enabling plugin using updateSettings, only to a particular HOT instance', function () {
  3825. this.$container2 = $('<div id="' + id + '-2"></div>').appendTo('body');
  3826. handsontable({
  3827. data: arrayOfObjects()
  3828. });
  3829. this.$container2.handsontable({
  3830. data: arrayOfObjects()
  3831. });
  3832. var widths = {
  3833. 1: [],
  3834. 2: []
  3835. };
  3836. widths[1][0] = colWidth(this.$container, 0);
  3837. widths[1][1] = colWidth(this.$container, 1);
  3838. widths[1][2] = colWidth(this.$container, 2);
  3839. widths[2][0] = colWidth(this.$container2, 0);
  3840. widths[2][1] = colWidth(this.$container2, 1);
  3841. widths[2][2] = colWidth(this.$container2, 2);
  3842. expect(widths[1][0]).toBeLessThan(widths[1][1]);
  3843. expect(widths[1][1]).toBeLessThan(widths[1][2]);
  3844. expect(widths[2][0]).toBeLessThan(widths[2][1]);
  3845. expect(widths[2][1]).toBeLessThan(widths[2][2]);
  3846. updateSettings({
  3847. autoColumnSize: false
  3848. });
  3849. widths[1][0] = colWidth(this.$container, 0);
  3850. widths[1][1] = colWidth(this.$container, 1);
  3851. widths[1][2] = colWidth(this.$container, 2);
  3852. widths[2][0] = colWidth(this.$container2, 0);
  3853. widths[2][1] = colWidth(this.$container2, 1);
  3854. widths[2][2] = colWidth(this.$container2, 2);
  3855. expect(widths[1][0]).toEqual(widths[1][1]);
  3856. expect(widths[1][0]).toEqual(widths[1][2]);
  3857. expect(widths[1][1]).toEqual(widths[1][2]);
  3858. expect(widths[2][0]).toBeLessThan(widths[2][1]);
  3859. expect(widths[2][1]).toBeLessThan(widths[2][2]);
  3860. this.$container2.handsontable('destroy');
  3861. this.$container2.remove();
  3862. });
  3863. it('should be possible to enable plugin using updateSettings', function () {
  3864. handsontable({
  3865. data: arrayOfObjects(),
  3866. autoColumnSize: false
  3867. });
  3868. var width0 = colWidth(this.$container, 0);
  3869. var width1 = colWidth(this.$container, 1);
  3870. var width2 = colWidth(this.$container, 2);
  3871. expect(width0).toEqual(width1);
  3872. expect(width0).toEqual(width2);
  3873. expect(width1).toEqual(width2);
  3874. updateSettings({
  3875. autoColumnSize: true
  3876. });
  3877. width0 = colWidth(this.$container, 0);
  3878. width1 = colWidth(this.$container, 1);
  3879. width2 = colWidth(this.$container, 2);
  3880. expect(width0).toBeLessThan(width1);
  3881. expect(width1).toBeLessThan(width2);
  3882. });
  3883. it('should consider CSS style of each instance separately', function () {
  3884. var $style = $('<style>.big .htCore td {font-size: 40px; line-height: 1.1;}</style>').appendTo('head');
  3885. var $container1 = $('<div id="hot1"></div>').appendTo('body').handsontable({
  3886. data: arrayOfObjects()
  3887. });
  3888. var $container2 = $('<div id="hot2"></div>').appendTo('body').handsontable({
  3889. data: arrayOfObjects()
  3890. });
  3891. var hot1 = $container1.handsontable('getInstance');
  3892. var hot2 = $container2.handsontable('getInstance');
  3893. expect(colWidth($container1, 0)).toEqual(colWidth($container2, 0));
  3894. $container1.addClass('big');
  3895. hot1.render();
  3896. hot2.render();
  3897. expect(colWidth($container1, 0)).toBeGreaterThan(colWidth($container2, 0));
  3898. $container1.removeClass('big').handsontable('render');
  3899. $container2.addClass('big').handsontable('render');
  3900. expect(colWidth($container1, 0)).toBeLessThan(colWidth($container2, 0));
  3901. $style.remove();
  3902. $container1.handsontable('destroy');
  3903. $container1.remove();
  3904. $container2.handsontable('destroy');
  3905. $container2.remove();
  3906. });
  3907. it('should consider CSS class of the <table> element (e.g. when used with Bootstrap)', function () {
  3908. var $style = $('<style>.htCore.big-table td {font-size: 32px}</style>').appendTo('head');
  3909. handsontable({
  3910. data: arrayOfObjects(),
  3911. autoColumnSize: true
  3912. });
  3913. var width = colWidth(this.$container, 0);
  3914. this.$container.find('table').addClass('big-table');
  3915. render();
  3916. expect(colWidth(this.$container, 0)).toBeGreaterThan(width);
  3917. $style.remove();
  3918. });
  3919. it('should destroy temporary element', function () {
  3920. handsontable({
  3921. autoColumnSize: true
  3922. });
  3923. expect(document.querySelector('.htAutoSize')).toBe(null);
  3924. });
  3925. it('should not trigger autoColumnSize when column width is defined (through colWidths)', function () {
  3926. handsontable({
  3927. data: arrayOfObjects(),
  3928. autoColumnSize: true,
  3929. colWidths: [70, 70, 70],
  3930. width: 500,
  3931. height: 100,
  3932. rowHeaders: true
  3933. });
  3934. setDataAtCell(0, 0, 'LongLongLongLong');
  3935. expect(colWidth(this.$container, 0)).toBe(70);
  3936. });
  3937. it('should not trigger autoColumnSize when column width is defined (through columns.width)', function () {
  3938. handsontable({
  3939. data: arrayOfObjects(),
  3940. autoColumnSize: true,
  3941. colWidth: 77,
  3942. columns: [{ width: 70 }, { width: 70 }, { width: 70 }],
  3943. width: 500,
  3944. height: 100,
  3945. rowHeaders: true
  3946. });
  3947. setDataAtCell(0, 0, 'LongLongLongLong');
  3948. expect(colWidth(this.$container, 0)).toBe(70);
  3949. });
  3950. it('should consider renderer that uses conditional formatting for specific row & column index', function () {
  3951. var data = arrayOfObjects();
  3952. data.push({ id: '2', name: 'Rocket Man', lastName: 'In a tin can' });
  3953. handsontable({
  3954. data: data,
  3955. columns: [{ data: 'id' }, { data: 'name' }],
  3956. autoColumnSize: true,
  3957. renderer: function renderer(instance, td, row, col, prop, value, cellProperties) {
  3958. // taken from demo/renderers.html
  3959. Handsontable.renderers.TextRenderer.apply(this, arguments);
  3960. if (row === 1 && col === 0) {
  3961. td.style.padding = '100px';
  3962. }
  3963. }
  3964. });
  3965. expect(colWidth(this.$container, 0)).toBeGreaterThan(colWidth(this.$container, 1));
  3966. });
  3967. it('should\'t serialize value if it is array (nested data sources)', function () {
  3968. var spy = jasmine.createSpy('renderer');
  3969. handsontable({
  3970. data: arrayOfObjects(),
  3971. autoColumnSize: true,
  3972. columns: [{ data: 'nestedData' }],
  3973. renderer: spy
  3974. });
  3975. expect(spy.calls.mostRecent().args[5]).toEqual([{ id: 1000 }]);
  3976. });
  3977. });
  3978. /***/ }),
  3979. /* 127 */
  3980. /***/ (function(module, exports, __webpack_require__) {
  3981. "use strict";
  3982. describe('AutoRowSize', function () {
  3983. var id = 'testContainer';
  3984. beforeEach(function () {
  3985. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  3986. });
  3987. afterEach(function () {
  3988. if (this.$container) {
  3989. destroy();
  3990. this.$container.remove();
  3991. }
  3992. });
  3993. function arrayOfObjects() {
  3994. return [{ id: 'Short' }, { id: 'Somewhat\nlong' }, { id: 'The\nvery\nvery\nvery\nlongest one' }];
  3995. }
  3996. function arrayOfObjects2() {
  3997. return [{ id: 'Short', name: 'Somewhat long' }, { id: 'Somewhat long', name: 'The very very longest one' }, { id: 'The very very very longest one', name: 'Short' }];
  3998. }
  3999. it('should apply auto size by default', function () {
  4000. handsontable({
  4001. data: arrayOfObjects()
  4002. });
  4003. var height0 = rowHeight(this.$container, 0);
  4004. var height1 = rowHeight(this.$container, 1);
  4005. var height2 = rowHeight(this.$container, 2);
  4006. expect(height0).toBeLessThan(height1);
  4007. expect(height1).toBeLessThan(height2);
  4008. });
  4009. it('should draw scrollbar correctly (proper height) after calculation when autoRowSize option is set (long text in row) #4000', function (done) {
  4010. var row = ['This is very long text which will break this cell text into two lines'];
  4011. var data = [];
  4012. var nrOfRows = 200;
  4013. var columnWidth = 100;
  4014. for (var i = 0; i < nrOfRows; i += 1) {
  4015. data.push(row);
  4016. }
  4017. handsontable({
  4018. data: data,
  4019. colWidths: function colWidths() {
  4020. return columnWidth;
  4021. },
  4022. autoRowSize: true
  4023. });
  4024. var oldHeight = spec().$container[0].scrollHeight;
  4025. setTimeout(function () {
  4026. var newHeight = spec().$container[0].scrollHeight;
  4027. expect(oldHeight).toBeLessThan(newHeight);
  4028. done();
  4029. }, 200);
  4030. });
  4031. describe('should draw scrollbar correctly (proper height) after calculation when autoRowSize option is set (`table td` element height set by CSS) #4000', function () {
  4032. var cellHeightInPx = 100;
  4033. var nrOfRows = null;
  4034. var nrOfColumns = 200,
  4035. style;
  4036. var SYNC_CALCULATION_LIMIT = Handsontable.plugins.AutoRowSize.SYNC_CALCULATION_LIMIT;
  4037. var CALCULATION_STEP = Handsontable.plugins.AutoRowSize.CALCULATION_STEP;
  4038. beforeEach(function () {
  4039. if (!this.$container) {
  4040. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  4041. }
  4042. var css = '.handsontable table td { height: ' + cellHeightInPx + 'px !important }',
  4043. head = document.head;
  4044. style = document.createElement('style');
  4045. style.type = 'text/css';
  4046. if (style.styleSheet) {
  4047. style.styleSheet.cssText = css;
  4048. } else {
  4049. style.appendChild(document.createTextNode(css));
  4050. }
  4051. $(head).append(style);
  4052. });
  4053. afterEach(function () {
  4054. if (this.$container) {
  4055. destroy();
  4056. this.$container.remove();
  4057. }
  4058. if (style) {
  4059. $(style).remove();
  4060. }
  4061. });
  4062. it('(SYNC_CALCULATION_LIMIT - 1 rows)', function (done) {
  4063. nrOfRows = SYNC_CALCULATION_LIMIT - 1;
  4064. handsontable({
  4065. data: Handsontable.helper.createSpreadsheetData(nrOfRows, nrOfColumns),
  4066. autoRowSize: true
  4067. });
  4068. setTimeout(function () {
  4069. var newHeight = spec().$container[0].scrollHeight;
  4070. expect(newHeight).toEqual((cellHeightInPx + 1) * nrOfRows + 1);
  4071. done();
  4072. }, 200);
  4073. });
  4074. it('(SYNC_CALCULATION_LIMIT + 1 rows)', function (done) {
  4075. nrOfRows = SYNC_CALCULATION_LIMIT + 1;
  4076. handsontable({
  4077. data: Handsontable.helper.createSpreadsheetData(nrOfRows, nrOfColumns),
  4078. autoRowSize: true
  4079. });
  4080. setTimeout(function () {
  4081. var newHeight = spec().$container[0].scrollHeight;
  4082. expect(newHeight).toEqual((cellHeightInPx + 1) * nrOfRows + 1);
  4083. done();
  4084. }, 200);
  4085. });
  4086. it('(SYNC_CALCULATION_LIMIT + CALCULATION_STEP - 1 rows)', function (done) {
  4087. nrOfRows = SYNC_CALCULATION_LIMIT + CALCULATION_STEP - 1;
  4088. handsontable({
  4089. data: Handsontable.helper.createSpreadsheetData(nrOfRows, nrOfColumns),
  4090. autoRowSize: true
  4091. });
  4092. setTimeout(function () {
  4093. var newHeight = spec().$container[0].scrollHeight;
  4094. expect(newHeight).toEqual((cellHeightInPx + 1) * nrOfRows + 1);
  4095. done();
  4096. }, 200);
  4097. });
  4098. it('(SYNC_CALCULATION_LIMIT + CALCULATION_STEP + 1 rows)', function (done) {
  4099. nrOfRows = SYNC_CALCULATION_LIMIT + CALCULATION_STEP + 1;
  4100. handsontable({
  4101. data: Handsontable.helper.createSpreadsheetData(nrOfRows, nrOfColumns),
  4102. autoRowSize: true
  4103. });
  4104. setTimeout(function () {
  4105. var newHeight = spec().$container[0].scrollHeight;
  4106. expect(newHeight).toEqual((cellHeightInPx + 1) * nrOfRows + 1);
  4107. done();
  4108. }, 200);
  4109. });
  4110. });
  4111. it('should correctly detect row height when table is hidden on init (display: none)', function (done) {
  4112. this.$container.css('display', 'none');
  4113. var hot = handsontable({
  4114. data: arrayOfObjects(),
  4115. rowHeaders: true,
  4116. autoRowSize: true
  4117. });
  4118. setTimeout(function () {
  4119. spec().$container.css('display', 'block');
  4120. hot.render();
  4121. expect(rowHeight(spec().$container, 0)).toBe(24);
  4122. expect(rowHeight(spec().$container, 1)).toBe(43);
  4123. expect([106, 127]).toEqual(jasmine.arrayContaining([rowHeight(spec().$container, 2)]));
  4124. done();
  4125. }, 200);
  4126. });
  4127. it('should be possible to disable plugin using updateSettings', function () {
  4128. var hot = handsontable({
  4129. data: arrayOfObjects()
  4130. });
  4131. var height0 = rowHeight(this.$container, 0);
  4132. var height1 = rowHeight(this.$container, 1);
  4133. var height2 = rowHeight(this.$container, 2);
  4134. expect(height0).toBeLessThan(height1);
  4135. expect(height1).toBeLessThan(height2);
  4136. updateSettings({
  4137. autoRowSize: false
  4138. });
  4139. hot.setDataAtCell(0, 0, 'A\nB\nC');
  4140. var height4 = rowHeight(this.$container, 0);
  4141. expect(height4).toBeGreaterThan(height0);
  4142. });
  4143. it('should be possible to enable plugin using updateSettings', function () {
  4144. handsontable({
  4145. data: arrayOfObjects(),
  4146. autoRowSize: false
  4147. });
  4148. var height0 = parseInt(getCell(0, 0).style.height, 10);
  4149. var height1 = parseInt(getCell(1, 0).style.height, 10);
  4150. var height2 = parseInt(getCell(2, 0).style.height, 10);
  4151. expect(height0).toEqual(height1);
  4152. expect(height0).toEqual(height2);
  4153. expect(height1).toEqual(height2);
  4154. updateSettings({
  4155. autoRowSize: true
  4156. });
  4157. height0 = parseInt(getCell(0, 0).style.height, 10);
  4158. height1 = parseInt(getCell(1, 0).style.height, 10);
  4159. height2 = parseInt(getCell(2, 0).style.height, 10);
  4160. expect(height0).toBeLessThan(height1);
  4161. expect(height1).toBeLessThan(height2);
  4162. });
  4163. it('should consider CSS style of each instance separately', function () {
  4164. var $style = $('<style>.big .htCore td {font-size: 40px;line-height: 1.1}</style>').appendTo('head');
  4165. var $container1 = $('<div id="hot1"></div>').appendTo('body').handsontable({
  4166. data: arrayOfObjects(),
  4167. autoRowSize: true
  4168. });
  4169. var $container2 = $('<div id="hot2"></div>').appendTo('body').handsontable({
  4170. data: arrayOfObjects(),
  4171. autoRowSize: true
  4172. });
  4173. var hot1 = $container1.handsontable('getInstance');
  4174. var hot2 = $container2.handsontable('getInstance');
  4175. expect(parseInt(hot1.getCell(0, 0).style.height, 10)).toEqual(parseInt(hot2.getCell(0, 0).style.height, 10));
  4176. $container1.addClass('big');
  4177. hot1.render();
  4178. hot2.render();
  4179. expect(parseInt(hot1.getCell(2, 0).style.height, 10)).toBeGreaterThan(parseInt(hot2.getCell(2, 0).style.height, 10));
  4180. $container1.removeClass('big');
  4181. hot1.render();
  4182. $container2.addClass('big');
  4183. hot2.render();
  4184. expect(parseInt(hot1.getCell(2, 0).style.height, 10)).toBeLessThan(parseInt(hot2.getCell(2, 0).style.height, 10));
  4185. $style.remove();
  4186. $container1.handsontable('destroy');
  4187. $container1.remove();
  4188. $container2.handsontable('destroy');
  4189. $container2.remove();
  4190. });
  4191. it('should consider CSS class of the <table> element (e.g. when used with Bootstrap)', function () {
  4192. var $style = $('<style>.htCore.big-table td {font-size: 32px;line-height: 1.1}</style>').appendTo('head');
  4193. var hot = handsontable({
  4194. data: arrayOfObjects(),
  4195. autoRowSize: true
  4196. });
  4197. var height = parseInt(hot.getCell(2, 0).style.height, 10);
  4198. this.$container.find('table').addClass('big-table');
  4199. hot.getPlugin('autoRowSize').clearCache();
  4200. render();
  4201. expect(parseInt(hot.getCell(2, 0).style.height, 10)).toBeGreaterThan(height);
  4202. $style.remove();
  4203. });
  4204. it('should not trigger autoColumnSize when column width is defined (through colWidths)', function () {
  4205. var hot = handsontable({
  4206. data: arrayOfObjects(),
  4207. autoRowSize: true,
  4208. rowHeights: [70, 70, 70],
  4209. width: 500,
  4210. height: 100,
  4211. rowHeaders: true
  4212. });
  4213. setDataAtCell(0, 0, 'LongLongLongLong');
  4214. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(69); // -1px of cell border
  4215. });
  4216. // Currently columns.height is not supported
  4217. xit('should not trigger autoRowSize when column height is defined (through columns.height)', function () {
  4218. var hot = handsontable({
  4219. data: arrayOfObjects(),
  4220. autoRowSize: true,
  4221. rowHeights: 77,
  4222. columns: [{ height: 70 }, { height: 70 }, { height: 70 }],
  4223. width: 500,
  4224. height: 100,
  4225. rowHeaders: true
  4226. });
  4227. setDataAtCell(0, 0, 'LongLongLongLong');
  4228. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(69); // -1px of cell border
  4229. });
  4230. it('should consider renderer that uses conditional formatting for specific row & column index', function () {
  4231. var data = arrayOfObjects();
  4232. data.push({ id: '2', name: 'Rocket Man', lastName: 'In a tin can' });
  4233. var hot = handsontable({
  4234. data: data,
  4235. columns: [{ data: 'id' }, { data: 'name' }],
  4236. autoRowSize: true,
  4237. renderer: function renderer(instance, td, row, col, prop, value, cellProperties) {
  4238. // taken from demo/renderers.html
  4239. Handsontable.renderers.TextRenderer.apply(this, arguments);
  4240. if (row === 1 && col === 0) {
  4241. td.style.padding = '100px';
  4242. }
  4243. }
  4244. });
  4245. expect(parseInt(hot.getCell(1, 0).style.height || 0, 10)).toBe(242);
  4246. });
  4247. it('should destroy temporary element', function () {
  4248. handsontable({
  4249. autoRowSize: true
  4250. });
  4251. expect(document.querySelector('.htAutoSize')).toBe(null);
  4252. });
  4253. it('should recalculate heights after column resize', function () {
  4254. var hot = handsontable({
  4255. data: arrayOfObjects2(),
  4256. colWidths: 250,
  4257. manualColumnResize: true,
  4258. autoRowSize: true,
  4259. rowHeaders: true,
  4260. colHeaders: true
  4261. });
  4262. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22); // -1px of cell border
  4263. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(22); // -1px of cell border
  4264. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBeInArray([22, 42]); // -1px of cell border
  4265. resizeColumn.call(this, 1, 100);
  4266. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22);
  4267. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(42);
  4268. expect([63, 84]).toEqual(jasmine.arrayContaining([parseInt(hot.getCell(2, -1).style.height, 10)]));
  4269. resizeColumn.call(this, 1, 50);
  4270. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22);
  4271. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(42);
  4272. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBe(126);
  4273. resizeColumn.call(this, 1, 200);
  4274. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22);
  4275. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(22);
  4276. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBe(42);
  4277. });
  4278. it('should recalculate heights after column moved', function () {
  4279. var hot = handsontable({
  4280. data: arrayOfObjects2(),
  4281. colWidths: [250, 50],
  4282. manualColumnMove: true,
  4283. autoRowSize: true,
  4284. rowHeaders: true,
  4285. colHeaders: true
  4286. });
  4287. var plugin = hot.getPlugin('manualColumnMove');
  4288. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(42); // -1px of cell border
  4289. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(105); // -1px of cell border
  4290. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBeInArray([22, 42]); // -1px of cell border
  4291. plugin.moveColumn(0, 2);
  4292. hot.render();
  4293. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22);
  4294. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(42);
  4295. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBe(126);
  4296. });
  4297. it('should recalculate heights with manualRowResize when changing text to multiline', function () {
  4298. var hot = handsontable({
  4299. data: arrayOfObjects2(),
  4300. colWidths: 250,
  4301. manualRowResize: [23, 50],
  4302. autoRowSize: true,
  4303. rowHeaders: true,
  4304. colHeaders: true
  4305. });
  4306. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22); // -1px of cell border
  4307. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(49); // -1px of cell border
  4308. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBeInArray([22, 42]); // -1px of cell border
  4309. hot.setDataAtCell(1, 0, 'A\nB\nC\nD\nE');
  4310. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22);
  4311. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(105);
  4312. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBeInArray([22, 42]);
  4313. });
  4314. it('should recalculate heights after moved row', function () {
  4315. var hot = handsontable({
  4316. data: arrayOfObjects2(),
  4317. colWidths: 250,
  4318. manualRowResize: [23, 50],
  4319. manualRowMove: true,
  4320. autoRowSize: true,
  4321. rowHeaders: true,
  4322. colHeaders: true
  4323. });
  4324. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(22); // -1px of cell border
  4325. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(49); // -1px of cell border
  4326. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBeInArray([22, 42]); // -1px of cell border
  4327. var plugin = hot.getPlugin('manualRowMove');
  4328. plugin.moveRow(1, 0);
  4329. hot.render();
  4330. expect(parseInt(hot.getCell(0, -1).style.height, 10)).toBe(49);
  4331. expect(parseInt(hot.getCell(1, -1).style.height, 10)).toBe(22);
  4332. expect(parseInt(hot.getCell(2, -1).style.height, 10)).toBeInArray([22, 42]); // -1px of cell border
  4333. });
  4334. it('should resize the column headers properly, according the their content sizes', function () {
  4335. var hot = handsontable({
  4336. data: Handsontable.helper.createSpreadsheetData(30, 30),
  4337. colHeaders: function colHeaders(index) {
  4338. if (index === 22) {
  4339. return 'a<br>much<br>longer<br>label';
  4340. }
  4341. return 'test';
  4342. },
  4343. autoRowSize: true,
  4344. rowHeaders: true,
  4345. width: 300,
  4346. height: 300
  4347. });
  4348. expect(rowHeight(spec().$container, -1)).toBe(89);
  4349. });
  4350. });
  4351. /***/ }),
  4352. /* 128 */
  4353. /***/ (function(module, exports, __webpack_require__) {
  4354. "use strict";
  4355. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  4356. describe('ColumnSorting', function () {
  4357. var id = 'testContainer';
  4358. beforeEach(function () {
  4359. this.$container = $('<div id="' + id + '" style="overflow: auto; width: 300px; height: 200px;"></div>').appendTo('body');
  4360. this.sortByColumn = function (columnIndex) {
  4361. var element = this.$container.find('th span.columnSorting:eq(' + columnIndex + ')');
  4362. element.simulate('mousedown');
  4363. element.simulate('mouseup');
  4364. };
  4365. });
  4366. afterEach(function () {
  4367. if (this.$container) {
  4368. destroy();
  4369. this.$container.remove();
  4370. }
  4371. });
  4372. var arrayOfObjects = function arrayOfObjects() {
  4373. return [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }, { id: 6, name: 'Chuck', lastName: 'Jackson' }, { id: 7, name: 'Meg', lastName: 'Jansen' }, { id: 8, name: 'Rob', lastName: 'Norris' }, { id: 9, name: 'Sean', lastName: 'O\'Hara' }, { id: 10, name: 'Eve', lastName: 'Branson' }];
  4374. };
  4375. it('should sort table by first visible column', function () {
  4376. var hot = handsontable({
  4377. data: [[1, 9, 3, 4, 5, 6, 7, 8, 9], [9, 8, 7, 6, 5, 4, 3, 2, 1], [8, 7, 6, 5, 4, 3, 3, 1, 9], [0, 3, 0, 5, 6, 7, 8, 9, 1]],
  4378. colHeaders: true,
  4379. columnSorting: true
  4380. });
  4381. var htCore = getHtCore();
  4382. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  4383. expect(htCore.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('9');
  4384. expect(htCore.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('3');
  4385. expect(htCore.find('tbody tr:eq(0) td:eq(3)').text()).toEqual('4');
  4386. this.sortByColumn(0);
  4387. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4388. expect(htCore.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('3');
  4389. expect(htCore.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('0');
  4390. expect(htCore.find('tbody tr:eq(0) td:eq(3)').text()).toEqual('5');
  4391. });
  4392. it('should apply stable sort function #3606', function () {
  4393. var hot = handsontable({
  4394. data: [['mercedes1', 'Mercedes', 'A 160', '01/14/2007'], ['citroen1', 'Citroen', 'C4 Coupe', '12/01/2007'], ['opel1', 'Opel', 'Astra', '02/02/2006'], ['bmw1', 'BMW', '320i Coupe', '07/24/2009'], ['citroen2', 'Citroen', 'C4 Coupe', '12/01/2012'], ['opel2', 'Opel', 'Astra', '02/02/2004'], ['mercedes2', 'Mercedes', 'A 160', '01/14/2008'], ['citroen3', 'Citroen', 'C4 Coupe', '12/01/2007'], ['mercedes3', 'Mercedes', 'A 160', '01/14/2009'], ['opel3', 'Opel', 'Astra', '02/02/2006'], ['bmw2', 'BMW', '320i Coupe', '07/24/2013'], ['bmw3', 'BMW', '320i Coupe', '07/24/2012']],
  4395. columns: [{}, {}, {
  4396. type: 'date',
  4397. dateFormat: 'mm/dd/yy'
  4398. }, {
  4399. type: 'numeric'
  4400. }],
  4401. columnSorting: true
  4402. });
  4403. hot.sort(1, true); // ASC
  4404. expect(hot.getDataAtCol(0)).toEqual(['bmw1', 'bmw2', 'bmw3', 'citroen1', 'citroen2', 'citroen3', 'mercedes1', 'mercedes2', 'mercedes3', 'opel1', 'opel2', 'opel3']);
  4405. hot.sort(1, false); // DESC
  4406. expect(hot.getDataAtCol(0)).toEqual(['opel1', 'opel2', 'opel3', 'mercedes1', 'mercedes2', 'mercedes3', 'citroen1', 'citroen2', 'citroen3', 'bmw1', 'bmw2', 'bmw3']);
  4407. });
  4408. it('should not throw error when trying run handsontable with columnSorting and autoRowSize in the same time.', function () {
  4409. var errors = 0;
  4410. try {
  4411. handsontable({
  4412. data: arrayOfObjects(),
  4413. autoRowSize: true,
  4414. columnSorting: true
  4415. });
  4416. } catch (e) {
  4417. errors++;
  4418. }
  4419. expect(errors).toBe(0);
  4420. });
  4421. it('should sort numbers descending after 2 clicks on table header', function () {
  4422. handsontable({
  4423. data: arrayOfObjects(),
  4424. colHeaders: true,
  4425. columnSorting: true
  4426. });
  4427. this.sortByColumn(0);
  4428. this.sortByColumn(0);
  4429. expect(this.$container.find('tr td').first().html()).toEqual('10');
  4430. });
  4431. it('should remove specified row from sorted table and NOT sort the table again', function () {
  4432. var hot = handsontable({
  4433. data: [[1, 'B'], [3, 'D'], [2, 'A'], [0, 'C']],
  4434. colHeaders: true,
  4435. columnSorting: true
  4436. });
  4437. this.sortByColumn(0);
  4438. var htCore = getHtCore();
  4439. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4440. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  4441. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  4442. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  4443. expect(htCore.find('tbody tr').length).toEqual(4);
  4444. // Now if sort is launched, sorting ordered will be reversed
  4445. hot.sortOrder = false;
  4446. hot.alter('remove_row', 0);
  4447. expect(htCore.find('tbody tr').length).toEqual(3);
  4448. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  4449. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  4450. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  4451. });
  4452. it('should add an empty row to sorted table', function () {
  4453. var hot = handsontable({
  4454. data: [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']],
  4455. colHeaders: true,
  4456. columnSorting: true
  4457. });
  4458. this.sortByColumn(0);
  4459. var htCore = getHtCore();
  4460. expect(htCore.find('tbody tr').length).toEqual(4);
  4461. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4462. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  4463. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  4464. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  4465. hot.alter('insert_row', 1, 2);
  4466. expect(htCore.find('tbody tr').length).toEqual(6);
  4467. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4468. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('');
  4469. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  4470. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('1');
  4471. expect(htCore.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('2');
  4472. expect(htCore.find('tbody tr:eq(5) td:eq(0)').text()).toEqual('3');
  4473. });
  4474. it('should add an empty row to sorted table at a given index', function () {
  4475. var hot = handsontable({
  4476. data: [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']],
  4477. colHeaders: true,
  4478. columnSorting: true
  4479. });
  4480. var htCore = getHtCore();
  4481. this.sortByColumn(0);
  4482. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  4483. expect(htCore.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('');
  4484. hot.alter('insert_row', 2);
  4485. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4486. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  4487. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  4488. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  4489. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  4490. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  4491. });
  4492. it('should NOT sort the table after value update in sorted column', function () {
  4493. var hot = handsontable({
  4494. data: [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']],
  4495. colHeaders: true,
  4496. columnSorting: true
  4497. });
  4498. var htCore = getHtCore();
  4499. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  4500. this.sortByColumn(0);
  4501. this.sortByColumn(0);
  4502. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  4503. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  4504. hot.setDataAtCell(1, 0, 20);
  4505. render();
  4506. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  4507. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('20');
  4508. });
  4509. it('defaultSort comparing function shouldn\'t change order when comparing empty string, null and undefined', function () {
  4510. var hot = handsontable({});
  4511. var defaultSort = hot.getPlugin('columnSorting').defaultSort;
  4512. expect(defaultSort(false, {})(['key1', null], ['key2', null])).toEqual(0);
  4513. expect(defaultSort(false, {})(['key1', ''], ['key2', ''])).toEqual(0);
  4514. expect(defaultSort(false, {})(['key1', undefined], ['key2', undefined])).toEqual(0);
  4515. expect(defaultSort(false, {})(['key1', ''], ['key2', null])).toEqual(0);
  4516. expect(defaultSort(false, {})(['key1', null], ['key2', ''])).toEqual(0);
  4517. expect(defaultSort(false, {})(['key1', ''], ['key2', undefined])).toEqual(0);
  4518. expect(defaultSort(false, {})(['key1', undefined], ['key2', ''])).toEqual(0);
  4519. expect(defaultSort(false, {})(['key1', null], ['key2', undefined])).toEqual(0);
  4520. expect(defaultSort(false, {})(['key1', undefined], ['key2', null])).toEqual(0);
  4521. });
  4522. it('should place empty strings, null and undefined values at proper position (stability of default comparing function)', function () {
  4523. var hot = handsontable({
  4524. data: [[null, 'Ted Right'], [undefined, 'Jane Neat'], [null, 'Meg Jansen'], ['', 'Sean Hara'], ['', 'Eve Branson'], [6, 'Frank Honest'], [7, 'Joan Well'], [8, 'Sid Strong'], [9, 'Chuck Jackson'], [10, 'Rob Norris'], [11, 'Eve Well']],
  4525. columnSorting: true
  4526. });
  4527. hot.sort(0, true); // ASC
  4528. expect(hot.getDataAtCol(1)).toEqual(['Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris', 'Eve Well',
  4529. // empty cells below
  4530. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  4531. hot.sort(0, false); // DESC
  4532. expect(hot.getDataAtCol(1)).toEqual(['Eve Well', 'Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  4533. // empty cells below
  4534. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  4535. });
  4536. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` option is enabled ' + '(API call, data type: default)', function () {
  4537. var hot = handsontable({
  4538. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  4539. columnSorting: {
  4540. sortEmptyCells: true
  4541. }
  4542. });
  4543. hot.sort(0, true); // ASC
  4544. expect(hot.getDataAtCol(1)).toEqual(['Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson',
  4545. // empty cells above
  4546. 'Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris']);
  4547. hot.sort(0, false); // DESC
  4548. expect(hot.getDataAtCol(1)).toEqual(['Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  4549. // empty cells below
  4550. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  4551. });
  4552. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` ' + 'option is enabled and `column` property of `columnSorting` option is set (data type: default)', function () {
  4553. var hot = handsontable({
  4554. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  4555. columnSorting: {
  4556. sortEmptyCells: true,
  4557. sortOrder: true,
  4558. column: 0
  4559. }
  4560. });
  4561. // ASC
  4562. expect(hot.getDataAtCol(1)).toEqual(['Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson',
  4563. // empty cells above
  4564. 'Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris']);
  4565. if (this.$container) {
  4566. destroy();
  4567. this.$container.remove();
  4568. }
  4569. hot = handsontable({
  4570. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  4571. columnSorting: {
  4572. sortEmptyCells: true,
  4573. sortOrder: false,
  4574. column: 0
  4575. }
  4576. });
  4577. // DESC
  4578. expect(hot.getDataAtCol(1)).toEqual(['Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  4579. // empty cells below
  4580. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  4581. });
  4582. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` ' + 'option is enabled and `column` property of `columnSorting` option is set (data type: numeric)', function () {
  4583. var hot = handsontable({
  4584. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  4585. columns: [{
  4586. type: 'numeric'
  4587. }, {}],
  4588. columnSorting: {
  4589. sortEmptyCells: true,
  4590. sortOrder: true,
  4591. column: 0
  4592. }
  4593. });
  4594. // ASC
  4595. expect(hot.getDataAtCol(1)).toEqual(['Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson',
  4596. // empty cells above
  4597. 'Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris']);
  4598. if (this.$container) {
  4599. destroy();
  4600. this.$container.remove();
  4601. }
  4602. hot = handsontable({
  4603. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  4604. columnSorting: {
  4605. sortEmptyCells: true,
  4606. sortOrder: false,
  4607. column: 0
  4608. }
  4609. });
  4610. // DESC
  4611. expect(hot.getDataAtCol(1)).toEqual(['Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  4612. // empty cells below
  4613. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  4614. });
  4615. describe('data type: date', function () {
  4616. it('dateSort comparing function shouldn\'t change order when comparing empty string, null and undefined', function () {
  4617. var hot = handsontable({});
  4618. var dateSort = hot.getPlugin('columnSorting').dateSort;
  4619. expect(dateSort(false, {})(['key1', null], ['key2', null])).toEqual(0);
  4620. expect(dateSort(false, {})(['key1', ''], ['key2', ''])).toEqual(0);
  4621. expect(dateSort(false, {})(['key1', undefined], ['key2', undefined])).toEqual(0);
  4622. expect(dateSort(false, {})(['key1', ''], ['key2', null])).toEqual(0);
  4623. expect(dateSort(false, {})(['key1', null], ['key2', ''])).toEqual(0);
  4624. expect(dateSort(false, {})(['key1', ''], ['key2', undefined])).toEqual(0);
  4625. expect(dateSort(false, {})(['key1', undefined], ['key2', ''])).toEqual(0);
  4626. expect(dateSort(false, {})(['key1', null], ['key2', undefined])).toEqual(0);
  4627. expect(dateSort(false, {})(['key1', undefined], ['key2', null])).toEqual(0);
  4628. });
  4629. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` ' + 'option is enabled and `column` property of `columnSorting` option is set', function () {
  4630. var hot = handsontable({
  4631. data: [['Citroen1', 'C4 Coupe', null], ['Mercedes1', 'A 160', '12/01/2008'], ['Mercedes2', 'A 160', '01/14/2006'], ['Citroen2', 'C4 Coupe', undefined], ['Audi1', 'A4 Avant', '11/19/2011'], ['Opel1', 'Astra', '02/02/2004'], ['Citroen3', 'C4 Coupe', null], ['BMW1', '320i Coupe', '07/24/2011'], ['Citroen4', 'C4 Coupe', ''], ['Citroen5', 'C4 Coupe', '']],
  4632. columns: [{}, {}, {
  4633. type: 'date',
  4634. dateFormat: 'MM/DD/YYYY'
  4635. }],
  4636. columnSorting: {
  4637. sortEmptyCells: true,
  4638. sortOrder: true,
  4639. column: 2
  4640. }
  4641. });
  4642. // ASC
  4643. expect(hot.getDataAtCol(0)).toEqual(['Citroen1', 'Citroen2', 'Citroen3', 'Citroen4', 'Citroen5',
  4644. // empty cells above
  4645. 'Opel1', 'Mercedes2', 'Mercedes1', 'BMW1', 'Audi1']);
  4646. if (this.$container) {
  4647. destroy();
  4648. this.$container.remove();
  4649. }
  4650. hot = handsontable({
  4651. data: [['Citroen1', 'C4 Coupe', null], ['Mercedes1', 'A 160', '12/01/2008'], ['Mercedes2', 'A 160', '01/14/2006'], ['Citroen2', 'C4 Coupe', undefined], ['Audi1', 'A4 Avant', '11/19/2011'], ['Opel1', 'Astra', '02/02/2004'], ['Citroen3', 'C4 Coupe', null], ['BMW1', '320i Coupe', '07/24/2011'], ['Citroen4', 'C4 Coupe', ''], ['Citroen5', 'C4 Coupe', '']],
  4652. columns: [{}, {}, {
  4653. type: 'date',
  4654. dateFormat: 'MM/DD/YYYY'
  4655. }],
  4656. columnSorting: {
  4657. sortEmptyCells: true,
  4658. sortOrder: false,
  4659. column: 2
  4660. }
  4661. });
  4662. // DESC
  4663. expect(hot.getDataAtCol(0)).toEqual(['Audi1', 'BMW1', 'Mercedes1', 'Mercedes2', 'Opel1',
  4664. // empty cells below
  4665. 'Citroen1', 'Citroen2', 'Citroen3', 'Citroen4', 'Citroen5']);
  4666. });
  4667. it('should sort date columns (MM/DD/YYYY)', function () {
  4668. var hot = handsontable({
  4669. data: [['Mercedes', 'A 160', '01/14/2006', 6999.9999], ['Citroen', 'C4 Coupe', '12/01/2008', 8330], ['Audi', 'A4 Avant', '11/19/2011', 33900], ['Opel', 'Astra', '02/02/2004', 7000], ['BMW', '320i Coupe', '07/24/2011', 30500]],
  4670. columns: [{}, {}, {
  4671. type: 'date',
  4672. dateFormat: 'MM/DD/YYYY'
  4673. }, {
  4674. type: 'numeric'
  4675. }],
  4676. colHeaders: true,
  4677. columnSorting: true
  4678. });
  4679. hot.sort(2, true); // ASC
  4680. expect(hot.getDataAtRow(0)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  4681. expect(hot.getDataAtRow(1)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  4682. expect(hot.getDataAtRow(2)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  4683. expect(hot.getDataAtRow(3)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  4684. expect(hot.getDataAtRow(4)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  4685. hot.sort(2, false); // DESC
  4686. expect(hot.getDataAtRow(0)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  4687. expect(hot.getDataAtRow(1)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  4688. expect(hot.getDataAtRow(2)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  4689. expect(hot.getDataAtRow(3)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  4690. expect(hot.getDataAtRow(4)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  4691. });
  4692. it('should sort date columns (DD/MM/YYYY)', function () {
  4693. var hot = handsontable({
  4694. data: [['Mercedes', 'A 160', '01/12/2012', 6999.9999], ['Citroen', 'C4 Coupe', '12/01/2013', 8330], ['Audi', 'A4 Avant', '11/10/2014', 33900], ['Opel', 'Astra', '02/02/2015', 7000], ['BMW', '320i Coupe', '07/02/2013', 30500]],
  4695. columns: [{}, {}, {
  4696. type: 'date',
  4697. dateFormat: 'DD/MM/YYYY'
  4698. }, {
  4699. type: 'numeric'
  4700. }],
  4701. colHeaders: true,
  4702. columnSorting: true
  4703. });
  4704. hot.sort(2, true); // ASC
  4705. expect(hot.getDataAtRow(0)).toEqual(['Mercedes', 'A 160', '01/12/2012', 6999.9999]);
  4706. expect(hot.getDataAtRow(1)).toEqual(['Citroen', 'C4 Coupe', '12/01/2013', 8330]);
  4707. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/02/2013', 30500]);
  4708. expect(hot.getDataAtRow(3)).toEqual(['Audi', 'A4 Avant', '11/10/2014', 33900]);
  4709. expect(hot.getDataAtRow(4)).toEqual(['Opel', 'Astra', '02/02/2015', 7000]);
  4710. hot.sort(2, false); // DESC
  4711. expect(hot.getDataAtRow(0)).toEqual(['Opel', 'Astra', '02/02/2015', 7000]);
  4712. expect(hot.getDataAtRow(1)).toEqual(['Audi', 'A4 Avant', '11/10/2014', 33900]);
  4713. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/02/2013', 30500]);
  4714. expect(hot.getDataAtRow(3)).toEqual(['Citroen', 'C4 Coupe', '12/01/2013', 8330]);
  4715. expect(hot.getDataAtRow(4)).toEqual(['Mercedes', 'A 160', '01/12/2012', 6999.9999]);
  4716. });
  4717. it('should sort date columns (MMMM Do YYYY)', function () {
  4718. var hot = handsontable({
  4719. data: [['Mercedes', 'A 160', 'October 28th 2016', 6999.9999], ['Citroen', 'C4 Coupe', 'October 27th 2001', 8330], ['Audi', 'A4 Avant', 'July 8th 1999', 33900], ['Opel', 'Astra', 'June 1st 2001', 7000], ['BMW', '320i Coupe', 'August 3rd 2001', 30500]],
  4720. columns: [{}, {}, {
  4721. type: 'date',
  4722. dateFormat: 'MMMM Do YYYY'
  4723. }, {
  4724. type: 'numeric'
  4725. }],
  4726. colHeaders: true,
  4727. columnSorting: true
  4728. });
  4729. hot.sort(2, true); // ASC
  4730. expect(hot.getDataAtRow(0)).toEqual(['Audi', 'A4 Avant', 'July 8th 1999', 33900]);
  4731. expect(hot.getDataAtRow(1)).toEqual(['Opel', 'Astra', 'June 1st 2001', 7000]);
  4732. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', 'August 3rd 2001', 30500]);
  4733. expect(hot.getDataAtRow(3)).toEqual(['Citroen', 'C4 Coupe', 'October 27th 2001', 8330]);
  4734. expect(hot.getDataAtRow(4)).toEqual(['Mercedes', 'A 160', 'October 28th 2016', 6999.9999]);
  4735. hot.sort(2, false); // DESC
  4736. expect(hot.getDataAtRow(0)).toEqual(['Mercedes', 'A 160', 'October 28th 2016', 6999.9999]);
  4737. expect(hot.getDataAtRow(1)).toEqual(['Citroen', 'C4 Coupe', 'October 27th 2001', 8330]);
  4738. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', 'August 3rd 2001', 30500]);
  4739. expect(hot.getDataAtRow(3)).toEqual(['Opel', 'Astra', 'June 1st 2001', 7000]);
  4740. expect(hot.getDataAtRow(4)).toEqual(['Audi', 'A4 Avant', 'July 8th 1999', 33900]);
  4741. });
  4742. it('should sort date columns along with empty and null values', function () {
  4743. var hot = handsontable({
  4744. data: [['Mercedes', 'A 160', '01/14/2006', 6999.9999], ['Citroen', 'C4 Coupe', '12/01/2008', 8330], ['Citroen', 'C4 Coupe null', null, 8330], ['Citroen', 'C4 Coupe empty', '', 8330], ['Audi', 'A4 Avant', '11/19/2011', 33900], ['Opel', 'Astra', '02/02/2004', 7000], ['BMW', '320i Coupe', '07/24/2011', 30500]],
  4745. columns: [{}, {}, {
  4746. type: 'date',
  4747. dateFormat: 'mm/dd/yy'
  4748. }, {
  4749. type: 'numeric'
  4750. }],
  4751. colHeaders: true,
  4752. columnSorting: true
  4753. });
  4754. hot.sort(2, true); // ASC
  4755. expect(hot.getDataAtRow(0)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  4756. expect(hot.getDataAtRow(1)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  4757. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  4758. expect(hot.getDataAtRow(3)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  4759. expect(hot.getDataAtRow(4)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  4760. hot.sort(2, false); // DESC
  4761. expect(hot.getDataAtRow(0)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  4762. expect(hot.getDataAtRow(1)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  4763. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  4764. expect(hot.getDataAtRow(3)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  4765. expect(hot.getDataAtRow(4)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  4766. });
  4767. });
  4768. describe('data type: time', function () {
  4769. it('should properly rewrite time into correct format after sort', function (done) {
  4770. var hot = handsontable({
  4771. data: [['0:00:01 am'], ['5:30:14 pm'], ['8:00:00 pm'], ['11:15:05 am'], ['4:07:48 am']],
  4772. columns: [{
  4773. type: 'time',
  4774. dateFormat: 'h:mm:ss a',
  4775. correctFormat: true
  4776. }],
  4777. colHeaders: true,
  4778. columnSorting: {
  4779. column: 0,
  4780. sortOrder: false
  4781. }
  4782. });
  4783. hot.setDataAtCell(0, 0, '19:55', 'edit');
  4784. setTimeout(function () {
  4785. expect(hot.getDataAtCell(0, 0)).toEqual('7:55:00 pm');
  4786. done();
  4787. }, 250);
  4788. });
  4789. });
  4790. it('should properly sort numeric data', function () {
  4791. var hot = handsontable({
  4792. data: [['Mercedes', 'A 160', '01/14/2006', '6999.9999'], ['Citroen', 'C4 Coupe', '12/01/2008', 8330], ['Citroen', 'C4 Coupe null', null, '8330'], ['Citroen', 'C4 Coupe empty', '', 8333], ['Audi', 'A4 Avant', '11/19/2011', '33900'], ['Opel', 'Astra', '02/02/2004', '7000'], ['BMW', '320i Coupe', '07/24/2011', 30500]],
  4793. columns: [{}, {}, {}, {
  4794. type: 'numeric'
  4795. }],
  4796. colHeaders: true,
  4797. columnSorting: true
  4798. });
  4799. var htCore = getHtCore();
  4800. this.sortByColumn(3);
  4801. expect(hot.getDataAtCol(3)).toEqual(['6999.9999', '7000', 8330, '8330', 8333, 30500, '33900']);
  4802. this.sortByColumn(3);
  4803. expect(hot.getDataAtCol(3)).toEqual(['33900', 30500, 8333, 8330, '8330', '7000', '6999.9999']);
  4804. this.sortByColumn(3);
  4805. expect(hot.getDataAtCol(3)).toEqual(['6999.9999', 8330, '8330', 8333, '33900', '7000', 30500]);
  4806. });
  4807. it('numericSort comparing function shouldn\'t change order when comparing empty string, null and undefined', function () {
  4808. var hot = handsontable({});
  4809. var numericSort = hot.getPlugin('columnSorting').numericSort;
  4810. expect(numericSort(false, {})(['key1', null], ['key2', null])).toEqual(0);
  4811. expect(numericSort(false, {})(['key1', ''], ['key2', ''])).toEqual(0);
  4812. expect(numericSort(false, {})(['key1', undefined], ['key2', undefined])).toEqual(0);
  4813. expect(numericSort(false, {})(['key1', ''], ['key2', null])).toEqual(0);
  4814. expect(numericSort(false, {})(['key1', null], ['key2', ''])).toEqual(0);
  4815. expect(numericSort(false, {})(['key1', ''], ['key2', undefined])).toEqual(0);
  4816. expect(numericSort(false, {})(['key1', undefined], ['key2', ''])).toEqual(0);
  4817. expect(numericSort(false, {})(['key1', null], ['key2', undefined])).toEqual(0);
  4818. expect(numericSort(false, {})(['key1', undefined], ['key2', null])).toEqual(0);
  4819. });
  4820. it('should sort table with multiple row headers', function () {
  4821. var hot = handsontable({
  4822. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  4823. columns: [{}, {}, {
  4824. type: 'date',
  4825. dateFormat: 'mm/dd/yy'
  4826. }, {
  4827. type: 'numeric'
  4828. }],
  4829. colHeaders: true,
  4830. columnSorting: true,
  4831. removeRowPlugin: true // this plugin ads an extra row header, so now we have 2 instead of 1
  4832. });
  4833. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  4834. this.sortByColumn(0); // sort by first column
  4835. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4836. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('D');
  4837. this.sortByColumn(1); // sort by second column
  4838. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A');
  4839. });
  4840. it('should allow to define sorting column and order during initialization', function () {
  4841. var hot = handsontable({
  4842. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  4843. colHeaders: true,
  4844. columnSorting: {
  4845. column: 0,
  4846. sortOrder: true
  4847. }
  4848. });
  4849. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4850. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('D');
  4851. });
  4852. it('should allow to change sorting column with updateSettings', function () {
  4853. var hot = handsontable({
  4854. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  4855. colHeaders: true,
  4856. columnSorting: {
  4857. column: 0,
  4858. sortOrder: true
  4859. }
  4860. });
  4861. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4862. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('D');
  4863. updateSettings({
  4864. columnSorting: {
  4865. column: 1,
  4866. sortOrder: true
  4867. }
  4868. });
  4869. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  4870. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A');
  4871. });
  4872. it('should allow to change sorting order with updateSettings', function () {
  4873. var hot = handsontable({
  4874. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  4875. colHeaders: true,
  4876. columnSorting: {
  4877. column: 0,
  4878. sortOrder: true
  4879. }
  4880. });
  4881. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4882. updateSettings({
  4883. columnSorting: {
  4884. column: 0,
  4885. sortOrder: false
  4886. }
  4887. });
  4888. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  4889. });
  4890. it('should allow to change if sorting empty cells with updateSettings', function () {
  4891. var hot = handsontable({
  4892. data: [[1, 'B'], [2, ''], [3, 'A'], [4, ''], [6, 'E'], [7, ''], [8, 'F']],
  4893. colHeaders: true,
  4894. columnSorting: {
  4895. column: 1,
  4896. sortOrder: false,
  4897. sortEmptyCells: false
  4898. }
  4899. });
  4900. updateSettings({
  4901. columnSorting: {
  4902. column: 1,
  4903. sortOrder: true,
  4904. sortEmptyCells: true
  4905. }
  4906. });
  4907. // ASC with empty cells sorting
  4908. expect(hot.getDataAtCol(0)).toEqual([2, 4, 7, 3, 1, 6, 8]);
  4909. updateSettings({
  4910. columnSorting: {
  4911. column: 1,
  4912. sortOrder: true,
  4913. sortEmptyCells: false
  4914. }
  4915. });
  4916. // ASC without empty cells sorting
  4917. expect(hot.getDataAtCol(0)).toEqual([3, 1, 6, 8, 2, 4, 7]);
  4918. });
  4919. it('should NOT sort spare rows', function () {
  4920. var myData = [{ a: 'aaa', b: 2, c: 3 }, { a: 'z', b: 11, c: -4 }, { a: 'dddd', b: 13, c: 13 }, { a: 'bbbb', b: 10, c: 11 }];
  4921. function customIsEmptyRow(row) {
  4922. var data = this.getSourceData();
  4923. return data[row].isNew;
  4924. }
  4925. handsontable({
  4926. data: myData,
  4927. rowHeaders: true,
  4928. colHeaders: ['A', 'B', 'C'],
  4929. columns: [{ data: 'a', type: 'text' }, { data: 'b', type: 'text' }, { data: 'c', type: 'text' }],
  4930. dataSchema: { isNew: true, a: false }, // default for a to avoid #bad value#
  4931. columnSorting: true,
  4932. minSpareRows: 3,
  4933. isEmptyRow: customIsEmptyRow
  4934. });
  4935. // ASC
  4936. updateSettings({
  4937. columnSorting: {
  4938. column: 0,
  4939. sortOrder: true
  4940. }
  4941. });
  4942. expect(getData()).toEqual([['aaa', 2, 3], ['bbbb', 10, 11], ['dddd', 13, 13], ['z', 11, -4], [false, null, null], [false, null, null], [false, null, null]]);
  4943. updateSettings({
  4944. columnSorting: {
  4945. column: 0,
  4946. sortOrder: false
  4947. }
  4948. });
  4949. expect(getData()).toEqual([['z', 11, -4], ['dddd', 13, 13], ['bbbb', 10, 11], ['aaa', 2, 3], [false, null, null], [false, null, null], [false, null, null]]);
  4950. });
  4951. it('should reset column sorting with updateSettings', function () {
  4952. var hot = handsontable({
  4953. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  4954. colHeaders: true,
  4955. columnSorting: {
  4956. column: 0,
  4957. sortOrder: true
  4958. }
  4959. });
  4960. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4961. updateSettings({
  4962. columnSorting: void 0
  4963. });
  4964. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  4965. });
  4966. it('should expose sort method when columnSorting is enabled', function () {
  4967. var hot = handsontable();
  4968. expect(hot.getSettings().columnSorting).toBeFalsy();
  4969. expect(hot.sort).toBeUndefined();
  4970. updateSettings({
  4971. columnSorting: true
  4972. });
  4973. expect(hot.getSettings().columnSorting).toBe(true);
  4974. expect(hot.sort).toBeDefined();
  4975. expect(_typeof(hot.sort)).toBe('function');
  4976. updateSettings({
  4977. columnSorting: false
  4978. });
  4979. expect(hot.getSettings().columnSorting).toBeFalsy();
  4980. expect(hot.sort).toBeUndefined();
  4981. });
  4982. it('should sort table using HOT.sort method', function () {
  4983. var hot = handsontable({
  4984. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  4985. columnSorting: true
  4986. });
  4987. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  4988. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  4989. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  4990. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  4991. hot.sort(0, true);
  4992. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  4993. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  4994. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  4995. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  4996. });
  4997. it('should reset column sorting with updateSettings', function () {
  4998. var hot = handsontable({
  4999. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  5000. colHeaders: true,
  5001. columnSorting: {
  5002. column: 0,
  5003. sortOrder: true
  5004. }
  5005. });
  5006. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  5007. updateSettings({
  5008. columnSorting: void 0
  5009. });
  5010. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  5011. });
  5012. it('should fire beforeColumnSort event before sorting data', function () {
  5013. var hot = handsontable({
  5014. data: [[2], [4], [1], [3]],
  5015. columnSorting: true
  5016. });
  5017. this.beforeColumnSortHandler = function () {
  5018. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  5019. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('4');
  5020. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  5021. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  5022. };
  5023. spyOn(this, 'beforeColumnSortHandler');
  5024. hot.addHook('beforeColumnSort', this.beforeColumnSortHandler);
  5025. var sortColumn = 0;
  5026. var sortOrder = true;
  5027. hot.sort(sortColumn, sortOrder);
  5028. expect(this.beforeColumnSortHandler.calls.count()).toEqual(1);
  5029. expect(this.beforeColumnSortHandler).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  5030. });
  5031. it('should not sorting column when beforeColumnSort returns false', function (done) {
  5032. var hot = handsontable({
  5033. data: [[2], [4], [1], [3]],
  5034. columnSorting: true,
  5035. beforeColumnSort: function beforeColumnSort() {
  5036. return false;
  5037. }
  5038. });
  5039. hot.sort(0, true);
  5040. setTimeout(function () {
  5041. expect(spec().$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  5042. expect(spec().$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('4');
  5043. expect(spec().$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  5044. expect(spec().$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  5045. done();
  5046. }, 200);
  5047. });
  5048. it('should add beforeColumnSort event listener in constructor', function () {
  5049. var beforeColumnSortCallback = jasmine.createSpy('beforeColumnSortHandler');
  5050. var hot = handsontable({
  5051. data: [[2], [4], [1], [3]],
  5052. columnSorting: true,
  5053. beforeColumnSort: beforeColumnSortCallback
  5054. });
  5055. var sortColumn = 0;
  5056. var sortOrder = true;
  5057. hot.sort(sortColumn, sortOrder);
  5058. expect(beforeColumnSortCallback.calls.count()).toEqual(1);
  5059. expect(beforeColumnSortCallback).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  5060. });
  5061. it('should fire afterColumnSort event before data has been sorted but before table render', function () {
  5062. var hot = handsontable({
  5063. data: [[2], [4], [1], [3]],
  5064. columnSorting: true
  5065. });
  5066. var rendered = false;
  5067. var afterColumnSortHandler = jasmine.createSpy('afterColumnSortHandler');
  5068. var afterRenderSpy = jasmine.createSpy('afterRender');
  5069. hot.addHook('afterColumnSort', function () {
  5070. expect(rendered).toBe(false);
  5071. afterColumnSortHandler.apply(afterColumnSortHandler, arguments);
  5072. });
  5073. hot.addHook('afterRender', function () {
  5074. rendered = true;
  5075. afterRenderSpy.apply(afterRenderSpy, arguments);
  5076. });
  5077. var sortColumn = 0;
  5078. var sortOrder = true;
  5079. afterRenderSpy.calls.reset();
  5080. hot.sort(sortColumn, sortOrder);
  5081. expect(afterColumnSortHandler.calls.count()).toBe(1);
  5082. expect(afterColumnSortHandler).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  5083. expect(afterRenderSpy.calls.count()).toBe(1);
  5084. });
  5085. it('should add afterColumnSort event listener in constructor', function () {
  5086. var afterColumnSortCallback = jasmine.createSpy('afterColumnSortHandler');
  5087. var hot = handsontable({
  5088. data: [[2], [4], [1], [3]],
  5089. columnSorting: true,
  5090. afterColumnSort: afterColumnSortCallback
  5091. });
  5092. var sortColumn = 0;
  5093. var sortOrder = true;
  5094. hot.sort(sortColumn, sortOrder);
  5095. expect(afterColumnSortCallback.calls.count()).toEqual(1);
  5096. expect(afterColumnSortCallback).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  5097. });
  5098. it('should insert row when plugin is enabled, but table hasn\'t been sorted', function () {
  5099. var hot = handsontable({
  5100. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  5101. columnSorting: true
  5102. });
  5103. expect(countRows()).toEqual(4);
  5104. expect(hot.sortColumn).toBeUndefined();
  5105. alter('insert_row');
  5106. expect(countRows()).toEqual(5);
  5107. });
  5108. it('should remove row when plugin is enabled, but table hasn\'t been sorted', function () {
  5109. var hot = handsontable({
  5110. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  5111. columnSorting: true
  5112. });
  5113. expect(countRows()).toEqual(4);
  5114. expect(hot.sortColumn).toBeUndefined();
  5115. alter('remove_row');
  5116. expect(countRows()).toEqual(3);
  5117. });
  5118. it('should display new row added directly to dataSource, when observeChanges plugin is enabled', function (done) {
  5119. var data = [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']];
  5120. var hot = handsontable({
  5121. data: data,
  5122. colHeaders: true,
  5123. columnSorting: true,
  5124. observeChanges: true
  5125. });
  5126. var htCore = getHtCore();
  5127. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  5128. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  5129. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  5130. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  5131. this.sortByColumn(0);
  5132. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  5133. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  5134. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  5135. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  5136. expect(htCore.find('tbody tr').length).toEqual(4);
  5137. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  5138. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  5139. data.push([5, 'E']);
  5140. setTimeout(function () {
  5141. expect(countRows()).toEqual(5);
  5142. expect(spec().$container.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('5');
  5143. expect(spec().$container.find('tbody tr:eq(4) td:eq(1)').text()).toEqual('E');
  5144. done();
  5145. }, 200);
  5146. });
  5147. it('should not display new row added directly to dataSource, when observeChanges plugin is explicitly disabled', function (done) {
  5148. var data = [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']];
  5149. var hot = handsontable({
  5150. data: data,
  5151. colHeaders: true,
  5152. columnSorting: true,
  5153. observeChanges: false
  5154. });
  5155. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  5156. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  5157. var htCore = getHtCore();
  5158. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  5159. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  5160. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  5161. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  5162. this.sortByColumn(0);
  5163. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  5164. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  5165. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  5166. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  5167. expect(htCore.find('tbody tr').length).toEqual(4);
  5168. data.push([5, 'E']);
  5169. setTimeout(function () {
  5170. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  5171. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  5172. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  5173. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  5174. expect(htCore.find('tbody tr').length).toEqual(4);
  5175. expect(afterChangesObservedCallback).not.toHaveBeenCalled();
  5176. done();
  5177. }, 100);
  5178. });
  5179. it('should display new row added directly to dataSource, when observeChanges plugin status is undefined', function (done) {
  5180. var data = [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']];
  5181. var onUpdateSettings = jasmine.createSpy('onUpdateSettings');
  5182. var hot = handsontable({
  5183. data: data,
  5184. colHeaders: true,
  5185. columnSorting: true,
  5186. afterUpdateSettings: onUpdateSettings
  5187. });
  5188. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  5189. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  5190. var htCore = getHtCore();
  5191. // columnSorting enables observeChanges plugin by asynchronously invoking updateSettings
  5192. setTimeout(function () {
  5193. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  5194. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  5195. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  5196. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  5197. spec().sortByColumn(0);
  5198. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  5199. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  5200. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  5201. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  5202. expect(htCore.find('tbody tr').length).toEqual(4);
  5203. data.push([5, 'E']);
  5204. }, 100);
  5205. setTimeout(function () {
  5206. expect(countRows()).toEqual(5);
  5207. expect(htCore.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('5');
  5208. expect(htCore.find('tbody tr:eq(4) td:eq(1)').text()).toEqual('E');
  5209. done();
  5210. }, 2000); // 2s delayed needs for safari env
  5211. });
  5212. it('should apply sorting when there are two tables and only one has sorting enabled and has been already sorted (#1020)', function () {
  5213. var hot = handsontable({
  5214. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  5215. columnSorting: {
  5216. column: 1
  5217. }
  5218. });
  5219. this.$container2 = $('<div id="' + id + '-2"></div>').appendTo('body');
  5220. this.$container2.handsontable();
  5221. var hot2 = this.$container2.handsontable('getInstance');
  5222. selectCell(0, 1);
  5223. keyDown('enter');
  5224. expect($('.handsontableInput').val()).toEqual('A');
  5225. this.$container2.handsontable('destroy');
  5226. this.$container2.remove();
  5227. });
  5228. it('should reset sorting after loading new data', function () {
  5229. var hot = handsontable({
  5230. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  5231. columnSorting: true
  5232. });
  5233. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  5234. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  5235. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  5236. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  5237. hot.sort(0, true);
  5238. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  5239. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  5240. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  5241. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  5242. loadData([[50, 'E'], [10, 'G'], [30, 'F'], [60, 'I'], [40, 'J'], [20, 'H']]);
  5243. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('50');
  5244. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('10');
  5245. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('30');
  5246. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('60');
  5247. expect(this.$container.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('40');
  5248. expect(this.$container.find('tbody tr:eq(5) td:eq(0)').text()).toEqual('20');
  5249. });
  5250. it('should reset sorting after loading new data (default sorting column and order set)', function () {
  5251. var hot = handsontable({
  5252. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  5253. columnSorting: {
  5254. column: 1,
  5255. sortOrder: true
  5256. }
  5257. });
  5258. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  5259. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  5260. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  5261. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('0');
  5262. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A');
  5263. expect(this.$container.find('tbody tr:eq(1) td:eq(1)').text()).toEqual('B');
  5264. expect(this.$container.find('tbody tr:eq(2) td:eq(1)').text()).toEqual('C');
  5265. expect(this.$container.find('tbody tr:eq(3) td:eq(1)').text()).toEqual('D');
  5266. hot.sort(0, true);
  5267. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  5268. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  5269. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  5270. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  5271. loadData([[50, 'E'], [10, 'G'], [30, 'F'], [60, 'I'], [40, 'J'], [20, 'H']]);
  5272. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('50');
  5273. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('30');
  5274. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('10');
  5275. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('20');
  5276. expect(this.$container.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('60');
  5277. expect(this.$container.find('tbody tr:eq(5) td:eq(0)').text()).toEqual('40');
  5278. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('E');
  5279. expect(this.$container.find('tbody tr:eq(1) td:eq(1)').text()).toEqual('F');
  5280. expect(this.$container.find('tbody tr:eq(2) td:eq(1)').text()).toEqual('G');
  5281. expect(this.$container.find('tbody tr:eq(3) td:eq(1)').text()).toEqual('H');
  5282. expect(this.$container.find('tbody tr:eq(4) td:eq(1)').text()).toEqual('I');
  5283. expect(this.$container.find('tbody tr:eq(5) td:eq(1)').text()).toEqual('J');
  5284. });
  5285. it('should return updated data at specyfied row after sorted', function () {
  5286. var hot = handsontable({
  5287. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5288. colHeaders: true,
  5289. rowHeaders: true,
  5290. columnSorting: true
  5291. });
  5292. this.sortByColumn(0);
  5293. expect(getDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  5294. expect(getDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  5295. this.sortByColumn(0);
  5296. expect(getDataAtRow(0)).toEqual([5, 'Jane', 'Neat']);
  5297. expect(getDataAtRow(4)).toEqual([1, 'Ted', 'Right']);
  5298. this.sortByColumn(0);
  5299. expect(getDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  5300. expect(getDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  5301. });
  5302. it('should return updated data at specyfied col after sorted', function () {
  5303. var hot = handsontable({
  5304. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5305. colHeaders: true,
  5306. rowHeaders: true,
  5307. columnSorting: true
  5308. });
  5309. this.sortByColumn(0);
  5310. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  5311. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  5312. this.sortByColumn(0);
  5313. expect(getDataAtCol(0)).toEqual([5, 4, 3, 2, 1]);
  5314. expect(getDataAtCol(1)).toEqual(['Jane', 'Sid', 'Joan', 'Frank', 'Ted']);
  5315. this.sortByColumn(0);
  5316. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  5317. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  5318. });
  5319. it('should return original data source at specified row after sorted', function () {
  5320. var hot = handsontable({
  5321. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5322. colHeaders: true,
  5323. rowHeaders: true,
  5324. columnSorting: true
  5325. });
  5326. this.sortByColumn(0);
  5327. expect(getDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  5328. expect(getDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  5329. expect(getSourceDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  5330. expect(getSourceDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  5331. this.sortByColumn(0);
  5332. expect(getDataAtRow(0)).toEqual([5, 'Jane', 'Neat']);
  5333. expect(getDataAtRow(4)).toEqual([1, 'Ted', 'Right']);
  5334. expect(getSourceDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  5335. expect(getSourceDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  5336. });
  5337. it('should return original data source at specified col after sorted', function () {
  5338. var hot = handsontable({
  5339. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5340. colHeaders: true,
  5341. rowHeaders: true,
  5342. columnSorting: true
  5343. });
  5344. this.sortByColumn(0);
  5345. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  5346. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  5347. expect(getSourceDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  5348. expect(getSourceDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  5349. this.sortByColumn(0);
  5350. expect(getDataAtCol(0)).toEqual([5, 4, 3, 2, 1]);
  5351. expect(getDataAtCol(1)).toEqual(['Jane', 'Sid', 'Joan', 'Frank', 'Ted']);
  5352. expect(getSourceDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  5353. expect(getSourceDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  5354. this.sortByColumn(0);
  5355. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  5356. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  5357. expect(getSourceDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  5358. expect(getSourceDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  5359. });
  5360. it('should ignore case when sorting', function () {
  5361. var hot = handsontable({
  5362. data: [[1, 'albuquerque'], [2, 'Alabama'], [3, 'Missouri']],
  5363. colHeaders: true,
  5364. columnSorting: true
  5365. });
  5366. this.sortByColumn(1);
  5367. expect(getDataAtCol(0)).toEqual([2, 1, 3]);
  5368. expect(getDataAtCol(1)).toEqual(['Alabama', 'albuquerque', 'Missouri']);
  5369. this.sortByColumn(1);
  5370. expect(getDataAtCol(0)).toEqual([3, 1, 2]);
  5371. expect(getDataAtCol(1)).toEqual(['Missouri', 'albuquerque', 'Alabama']);
  5372. });
  5373. it('should push empty cells to the end of sorted column', function () {
  5374. var hot = handsontable({
  5375. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5376. colHeaders: true,
  5377. rowHeaders: true,
  5378. columnSorting: true,
  5379. minSpareRows: 1
  5380. });
  5381. this.sortByColumn(1);
  5382. expect(getDataAtCol(0)).toEqual([5, 4, 1, 2, 3, null]);
  5383. expect(getDataAtCol(1)).toEqual(['Jane', 'Sid', 'Ted', '', '', null]);
  5384. this.sortByColumn(1);
  5385. expect(getDataAtCol(0)).toEqual([1, 4, 5, 2, 3, null]);
  5386. expect(getDataAtCol(1)).toEqual(['Ted', 'Sid', 'Jane', '', '', null]);
  5387. });
  5388. it('should push numeric values before non-numeric values, when sorting ascending using the default sorting function', function () {
  5389. var hot = handsontable({
  5390. data: [[1, 'Ted', 123], [2, '', 'Some'], [3, '', 321], [4, 'Sid', 'String'], [5, 'Jane', 46]],
  5391. colHeaders: true,
  5392. columnSorting: true
  5393. });
  5394. this.sortByColumn(2);
  5395. expect(getDataAtCol(2)).toEqual([46, 123, 321, 'Some', 'String']);
  5396. this.sortByColumn(2);
  5397. expect(getDataAtCol(2)).toEqual(['String', 'Some', 321, 123, 46]);
  5398. });
  5399. it('should add a sorting indicator to the column header after it\'s been sorted, only if sortIndicator property is set to true', function () {
  5400. var hot = handsontable({
  5401. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5402. colHeaders: true,
  5403. columnSorting: true
  5404. });
  5405. this.sortByColumn(1);
  5406. var sortedColumn = this.$container.find('th span.columnSorting')[1],
  5407. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5408. expect(afterValue === '' || afterValue === 'none').toBe(true);
  5409. // ---------------------------------
  5410. // INDICATOR SET FOR THE WHOLE TABLE
  5411. // ---------------------------------
  5412. hot.updateSettings({
  5413. sortIndicator: true
  5414. });
  5415. this.sortByColumn(1);
  5416. // descending (updateSettings doesn't reset sorting stack)
  5417. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5418. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5419. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  5420. this.sortByColumn(1);
  5421. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5422. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5423. expect(afterValue === '' || afterValue === 'none').toBe(true);
  5424. this.sortByColumn(1);
  5425. // ascending
  5426. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5427. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5428. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5429. // ---------------------------------
  5430. // INDICATOR SET FOR A SINGLE COLUMN
  5431. // ---------------------------------
  5432. hot.updateSettings({
  5433. sortIndicator: void 0,
  5434. columns: [{}, {}, { sortIndicator: true }]
  5435. });
  5436. this.sortByColumn(0);
  5437. sortedColumn = this.$container.find('th span.columnSorting')[0];
  5438. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5439. expect(afterValue === '' || afterValue === 'none').toBe(true);
  5440. this.sortByColumn(1);
  5441. // descending
  5442. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5443. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5444. expect(afterValue === '' || afterValue === 'none').toBe(true);
  5445. this.sortByColumn(2);
  5446. sortedColumn = this.$container.find('th span.columnSorting')[2];
  5447. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5448. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5449. });
  5450. it('should change sorting indicator state on every `hot.sort()` method call (continuously for the same column)', function () {
  5451. var hot = handsontable({
  5452. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5453. colHeaders: true,
  5454. columnSorting: true,
  5455. sortIndicator: true
  5456. });
  5457. hot.sort(1);
  5458. // ascending
  5459. var sortedColumn = this.$container.find('th span.columnSorting')[1];
  5460. var afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5461. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5462. hot.sort(1);
  5463. // descending
  5464. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5465. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5466. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  5467. hot.sort(1);
  5468. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5469. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5470. expect(afterValue === '' || afterValue === 'none').toBe(true);
  5471. hot.sort(1);
  5472. // ascending
  5473. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5474. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5475. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5476. hot.sort(1);
  5477. // descending
  5478. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5479. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5480. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  5481. });
  5482. it('should change sorting indicator state on every `hot.sort()` method (calling for different columns)', function () {
  5483. var hot = handsontable({
  5484. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5485. colHeaders: true,
  5486. columnSorting: true,
  5487. sortIndicator: true
  5488. });
  5489. hot.sort(1);
  5490. // ascending
  5491. var sortedColumn = this.$container.find('th span.columnSorting')[1];
  5492. var afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5493. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5494. hot.sort(2);
  5495. // ascending
  5496. sortedColumn = this.$container.find('th span.columnSorting')[2];
  5497. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5498. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5499. hot.sort(1);
  5500. // ascending
  5501. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5502. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5503. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5504. hot.sort(2, false);
  5505. // descending
  5506. sortedColumn = this.$container.find('th span.columnSorting')[2];
  5507. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5508. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  5509. hot.sort(2, false);
  5510. // descending
  5511. sortedColumn = this.$container.find('th span.columnSorting')[2];
  5512. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5513. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  5514. hot.sort(2, true);
  5515. // ascending
  5516. sortedColumn = this.$container.find('th span.columnSorting')[2];
  5517. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5518. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5519. });
  5520. it('should change sorting indicator state when initial column sorting was provided', function () {
  5521. var hot = handsontable({
  5522. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  5523. colHeaders: true,
  5524. columnSorting: {
  5525. column: 1,
  5526. sortOrder: false
  5527. },
  5528. sortIndicator: true
  5529. });
  5530. // descending
  5531. var sortedColumn = this.$container.find('th span.columnSorting')[1];
  5532. var afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5533. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  5534. hot.sort(1);
  5535. // default
  5536. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5537. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5538. expect(afterValue === '' || afterValue === 'none').toBe(true);
  5539. hot.sort(1);
  5540. // ascending
  5541. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5542. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5543. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  5544. hot.sort(1);
  5545. // descending
  5546. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5547. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5548. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  5549. hot.sort(1);
  5550. // default
  5551. sortedColumn = this.$container.find('th span.columnSorting')[1];
  5552. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  5553. expect(afterValue === '' || afterValue === 'none').toBe(true);
  5554. });
  5555. it('should properly sort the table, when it\'s scrolled to the far right', function () {
  5556. var data = [['Jasmine Ferguson', 'Britney Carey', 'Kelly Decker', 'Lacey Mcleod', 'Leona Shaffer', 'Kelli Ochoa', 'Adele Roberson', 'Viola Snow', 'Barron Cherry', 'Calhoun Lane', 'Elvia Andrews', 'Katheryn Dale', 'Dorthy Hale', 'Munoz Randall', 'Fields Morse', 'Hubbard Nichols', 'Chang Yang', 'Osborn Anthony', 'Owens Warner', 'Gloria Hampton'], ['Lane Hill', 'Belinda Mathews', 'York Gray', 'Celina Stone', 'Victoria Mays', 'Angelina Lott', 'Joyce Mason', 'Shawn Rodriguez', 'Susanna Mayo', 'Wolf Fuller', 'Long Hester', 'Dudley Doyle', 'Wilder Sutton', 'Oneal Avery', 'James Mclaughlin', 'Lenora Guzman', 'Mcmahon Sullivan', 'Abby Weeks', 'Beverly Joseph', 'Rosalind Church'], ['Myrtle Landry', 'Hays Huff', 'Hernandez Benjamin', 'Mclaughlin Garza', 'Franklin Barton', 'Lara Buchanan', 'Ratliff Beck', 'Rosario Munoz', 'Isabelle Dalton', 'Smith Woodard', 'Marjorie Marshall', 'Spears Stein', 'Brianna Bowman', 'Marci Clay', 'Palmer Harrell', 'Ball Levy', 'Shelley Mendoza', 'Morrow Glass', 'Baker Knox', 'Adrian Holman'], ['Trisha Howell', 'Brooke Harrison', 'Anthony Watkins', 'Ellis Cobb', 'Sheppard Dillon', 'Mathis Bray', 'Foreman Burns', 'Lina Glenn', 'Giles Pollard', 'Weiss Ballard', 'Lynnette Smith', 'Flores Kline', 'Graciela Singleton', 'Santiago Mcclure', 'Claudette Battle', 'Nita Holloway', 'Eula Wolfe', 'Pruitt Stokes', 'Felicia Briggs', 'Melba Bradshaw']];
  5557. var hot = handsontable({
  5558. data: data,
  5559. colHeaders: true,
  5560. columnSorting: true
  5561. });
  5562. hot.view.wt.wtOverlays.leftOverlay.scrollTo(15);
  5563. hot.render();
  5564. hot.sort(15);
  5565. expect(getDataAtCell(0, 15)).toEqual('Ball Levy');
  5566. expect(getDataAtCell(1, 15)).toEqual('Hubbard Nichols');
  5567. expect(getDataAtCell(2, 15)).toEqual('Lenora Guzman');
  5568. expect(getDataAtCell(3, 15)).toEqual('Nita Holloway');
  5569. hot.sort(15);
  5570. expect(getDataAtCell(3, 15)).toEqual('Ball Levy');
  5571. expect(getDataAtCell(2, 15)).toEqual('Hubbard Nichols');
  5572. expect(getDataAtCell(1, 15)).toEqual('Lenora Guzman');
  5573. expect(getDataAtCell(0, 15)).toEqual('Nita Holloway');
  5574. hot.sort(15);
  5575. expect(getDataAtCell(0, 15)).toEqual('Hubbard Nichols');
  5576. expect(getDataAtCell(1, 15)).toEqual('Lenora Guzman');
  5577. expect(getDataAtCell(2, 15)).toEqual('Ball Levy');
  5578. expect(getDataAtCell(3, 15)).toEqual('Nita Holloway');
  5579. });
  5580. it('should allow specifiyng a custom sorting function', function () {
  5581. var data = [['1 inch'], ['1 yard'], ['2 feet'], ['0.2 miles']];
  5582. var hot = handsontable({
  5583. data: data,
  5584. colHeaders: true,
  5585. columnSorting: true,
  5586. columns: [{
  5587. sortFunction: function sortFunction(sortOrder) {
  5588. return function (a, b) {
  5589. var unitsRatios = {
  5590. inch: 1,
  5591. yard: 36,
  5592. feet: 12,
  5593. miles: 63360
  5594. };
  5595. var newA = a[1],
  5596. newB = b[1];
  5597. Handsontable.helper.objectEach(unitsRatios, function (val, prop) {
  5598. if (a[1].indexOf(prop) > -1) {
  5599. newA = parseFloat(a[1].replace(prop, '')) * val;
  5600. return false;
  5601. }
  5602. });
  5603. Handsontable.helper.objectEach(unitsRatios, function (val, prop) {
  5604. if (b[1].indexOf(prop) > -1) {
  5605. newB = parseFloat(b[1].replace(prop, '')) * val;
  5606. return false;
  5607. }
  5608. });
  5609. if (newA < newB) {
  5610. return sortOrder ? -1 : 1;
  5611. }
  5612. if (newA > newB) {
  5613. return sortOrder ? 1 : -1;
  5614. }
  5615. return 0;
  5616. };
  5617. }
  5618. }]
  5619. });
  5620. expect(getDataAtCell(0, 0)).toEqual('1 inch');
  5621. expect(getDataAtCell(1, 0)).toEqual('1 yard');
  5622. expect(getDataAtCell(2, 0)).toEqual('2 feet');
  5623. expect(getDataAtCell(3, 0)).toEqual('0.2 miles');
  5624. hot.sort(0);
  5625. expect(getDataAtCell(0, 0)).toEqual('1 inch');
  5626. expect(getDataAtCell(1, 0)).toEqual('2 feet');
  5627. expect(getDataAtCell(2, 0)).toEqual('1 yard');
  5628. expect(getDataAtCell(3, 0)).toEqual('0.2 miles');
  5629. hot.sort(0);
  5630. expect(getDataAtCell(0, 0)).toEqual('0.2 miles');
  5631. expect(getDataAtCell(1, 0)).toEqual('1 yard');
  5632. expect(getDataAtCell(2, 0)).toEqual('2 feet');
  5633. expect(getDataAtCell(3, 0)).toEqual('1 inch');
  5634. hot.sort(0);
  5635. expect(getDataAtCell(0, 0)).toEqual('1 inch');
  5636. expect(getDataAtCell(1, 0)).toEqual('1 yard');
  5637. expect(getDataAtCell(2, 0)).toEqual('2 feet');
  5638. expect(getDataAtCell(3, 0)).toEqual('0.2 miles');
  5639. });
  5640. it('should properly sort integers with nulls', function () {
  5641. var hot = handsontable({
  5642. data: [['12'], [null], ['10'], ['-5'], [null], ['1000']],
  5643. colHeaders: true,
  5644. columnSorting: true
  5645. });
  5646. this.sortByColumn(0);
  5647. expect(getDataAtCol(0)).toEqual(['-5', '10', '12', '1000', null, null]);
  5648. this.sortByColumn(0);
  5649. expect(getDataAtCol(0)).toEqual(['1000', '12', '10', '-5', null, null]);
  5650. });
  5651. it('should properly sort floating points', function () {
  5652. var hot = handsontable({
  5653. data: [['0.0561'], ['-10.67'], ['-4.1'], ['-0.01'], ['-127'], ['1000']],
  5654. colHeaders: true,
  5655. columnSorting: true
  5656. });
  5657. this.sortByColumn(0);
  5658. expect(getDataAtCol(0)).toEqual(['-127', '-10.67', '-4.1', '-0.01', '0.0561', '1000']);
  5659. this.sortByColumn(0);
  5660. expect(getDataAtCol(0)).toEqual(['1000', '0.0561', '-0.01', '-4.1', '-10.67', '-127']);
  5661. });
  5662. it('should properly sort floating points with nulls', function () {
  5663. var hot = handsontable({
  5664. data: [['0.0561'], ['-10.67'], [null], ['-4.1'], ['-0.01'], [null], ['-127'], ['1000'], [null]],
  5665. colHeaders: true,
  5666. columnSorting: true
  5667. });
  5668. this.sortByColumn(0);
  5669. expect(getDataAtCol(0)).toEqual(['-127', '-10.67', '-4.1', '-0.01', '0.0561', '1000', null, null, null]);
  5670. this.sortByColumn(0);
  5671. expect(getDataAtCol(0)).toEqual(['1000', '0.0561', '-0.01', '-4.1', '-10.67', '-127', null, null, null]);
  5672. });
  5673. it('should properly sort floating points with non-numerical values', function () {
  5674. var hot = handsontable({
  5675. data: [['0.0561'], ['-10.67'], ['a'], ['-4.1'], ['-0.01'], ['b'], ['-127'], ['1000'], ['hello']],
  5676. colHeaders: true,
  5677. columnSorting: true
  5678. });
  5679. this.sortByColumn(0);
  5680. expect(getDataAtCol(0)).toEqual(['-127', '-10.67', '-4.1', '-0.01', '0.0561', '1000', 'a', 'b', 'hello']);
  5681. this.sortByColumn(0);
  5682. expect(getDataAtCol(0)).toEqual(['hello', 'b', 'a', '1000', '0.0561', '-0.01', '-4.1', '-10.67', '-127']);
  5683. });
  5684. it('should modify row translating process when soring is applied (visual to physical and vice versa)', function () {
  5685. var hot = handsontable({
  5686. data: [[2], [4], [1], [3]],
  5687. colHeaders: true,
  5688. columnSorting: true
  5689. });
  5690. this.sortByColumn(0);
  5691. expect(hot.toPhysicalRow(0)).toBe(2);
  5692. expect(hot.toPhysicalRow(1)).toBe(0);
  5693. expect(hot.toPhysicalRow(2)).toBe(3);
  5694. expect(hot.toPhysicalRow(3)).toBe(1);
  5695. expect(hot.toVisualRow(0)).toBe(1);
  5696. expect(hot.toVisualRow(1)).toBe(3);
  5697. expect(hot.toVisualRow(2)).toBe(0);
  5698. expect(hot.toVisualRow(3)).toBe(2);
  5699. });
  5700. describe('should return sorted properly data when maxRows or / and minSpareRow options are set', function () {
  5701. var testSorting = function testSorting(desc, config, result) {
  5702. it(desc, function () {
  5703. handsontable({
  5704. data: Handsontable.helper.createSpreadsheetData(config.rows, config.columns),
  5705. maxRows: config.maxRow,
  5706. minSpareRows: config.minSpareRows,
  5707. columnSorting: {
  5708. column: config.sortByColumnIndex,
  5709. sortOrder: config.sortOrder
  5710. }
  5711. });
  5712. expect(getData().length).toEqual(result.dataLength);
  5713. for (var i = 0; i < result.expectations.length; i += 1) {
  5714. expect(getDataAtCell(result.expectations[i].rowIndex, result.expectations[i].columnIndex)).toEqual(result.expectations[i].value);
  5715. }
  5716. });
  5717. };
  5718. testSorting('maxRows < data.length', { rows: 9, columns: 9, maxRow: 6, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 6, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C6' }] });
  5719. testSorting('maxRows > data.length', { rows: 8, columns: 8, maxRow: 20, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 8, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C8' }] });
  5720. testSorting('minSpareRows is set; maxRows < data.length', { rows: 9, columns: 9, maxRow: 5, minSpareRows: 3, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 5, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C5' }] });
  5721. testSorting('minSpareRows is set; maxRows === data.length', { rows: 6, columns: 6, maxRow: 9, minSpareRows: 3, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 6 + 3, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C6' }] });
  5722. testSorting('minSpareRows is set; maxRows > data.length', { rows: 9, columns: 9, maxRow: 15, minSpareRows: 2, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 9 + 2, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C9' }] });
  5723. });
  5724. });
  5725. /***/ }),
  5726. /* 129 */
  5727. /***/ (function(module, exports, __webpack_require__) {
  5728. "use strict";
  5729. describe('Comments', function () {
  5730. var id = 'testContainer';
  5731. beforeEach(function () {
  5732. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  5733. });
  5734. afterEach(function () {
  5735. if (this.$container) {
  5736. destroy();
  5737. this.$container.remove();
  5738. }
  5739. });
  5740. describe('Enabling the plugin', function () {
  5741. it('should enable the plugin in the initial config', function () {
  5742. var hot = handsontable({
  5743. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5744. comments: true
  5745. });
  5746. expect(hot.getPlugin('comments').isEnabled()).toBe(true);
  5747. });
  5748. it('should enable the plugin using updateSettings', function () {
  5749. var hot = handsontable({
  5750. data: Handsontable.helper.createSpreadsheetData(4, 4)
  5751. });
  5752. expect(hot.getPlugin('comments').isEnabled()).toBe(false);
  5753. updateSettings({
  5754. comments: true
  5755. });
  5756. expect(hot.getPlugin('comments').isEnabled()).toBe(true);
  5757. });
  5758. });
  5759. describe('Styling', function () {
  5760. it('should display comment indicators in the appropriate cells', function () {
  5761. var hot = handsontable({
  5762. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5763. comments: true,
  5764. cell: [{ row: 1, col: 1, comment: { value: 'test' } }, { row: 2, col: 2, comment: { value: 'test' } }]
  5765. });
  5766. expect(getCell(1, 1).className.indexOf('htCommentCell')).toBeGreaterThan(-1);
  5767. expect(getCell(2, 2).className.indexOf('htCommentCell')).toBeGreaterThan(-1);
  5768. });
  5769. });
  5770. describe('API', function () {
  5771. it('should return the comment from a proper cell, when using the getCommentAtCell method', function () {
  5772. var hot = handsontable({
  5773. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5774. comments: true,
  5775. cell: [{ row: 1, col: 1, comment: { value: 'test' } }, { row: 2, col: 2, comment: { value: 'another test' } }]
  5776. });
  5777. var plugin = hot.getPlugin('comments');
  5778. expect(plugin.getCommentAtCell(1, 1)).toEqual('test');
  5779. expect(plugin.getCommentAtCell(2, 2)).toEqual('another test');
  5780. });
  5781. it('should return the comment from a proper cell, when using the setRange and getComment methods', function () {
  5782. var hot = handsontable({
  5783. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5784. comments: true,
  5785. cell: [{ row: 1, col: 1, comment: { value: 'test' } }, { row: 2, col: 2, comment: { value: 'another test' } }]
  5786. });
  5787. var plugin = hot.getPlugin('comments');
  5788. plugin.setRange({ from: { row: 1, col: 1 } });
  5789. expect(plugin.getComment()).toEqual('test');
  5790. plugin.setRange({ from: { row: 2, col: 2 } });
  5791. expect(plugin.getComment()).toEqual('another test');
  5792. });
  5793. it('should allow inserting comments using the `setCommentAtCell` method', function () {
  5794. var hot = handsontable({
  5795. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5796. comments: true
  5797. });
  5798. var plugin = hot.getPlugin('comments');
  5799. expect(getCellMeta(1, 1).comment).toEqual(void 0);
  5800. plugin.setCommentAtCell(1, 1, 'test comment');
  5801. expect(getCellMeta(1, 1).comment.value).toEqual('test comment');
  5802. });
  5803. it('should trigger `afterSetCellMeta` callback when `setCommentAtCell` function is invoked', function () {
  5804. var afterSetCellMetaCallback = jasmine.createSpy('afterSetCellMetaCallback');
  5805. var hot = handsontable({
  5806. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5807. comments: true,
  5808. afterSetCellMeta: afterSetCellMetaCallback
  5809. });
  5810. var plugin = hot.getPlugin('comments');
  5811. plugin.setCommentAtCell(1, 1, 'Added comment');
  5812. expect(afterSetCellMetaCallback).toHaveBeenCalledWith(1, 1, 'comment', { value: 'Added comment' }, undefined, undefined);
  5813. });
  5814. it('should allow removing comments using the `removeCommentAtCell` method', function () {
  5815. var hot = handsontable({
  5816. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5817. comments: true,
  5818. cell: [{ row: 1, col: 1, comment: { value: 'test' } }]
  5819. });
  5820. var plugin = hot.getPlugin('comments');
  5821. expect(getCellMeta(1, 1).comment.value).toEqual('test');
  5822. plugin.removeCommentAtCell(1, 1);
  5823. expect(getCellMeta(1, 1).comment).toEqual(void 0);
  5824. });
  5825. it('should trigger `afterSetCellMeta` callback when `removeCommentAtCell` function is invoked', function () {
  5826. var afterSetCellMetaCallback = jasmine.createSpy('afterSetCellMetaCallback');
  5827. var hot = handsontable({
  5828. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5829. comments: true,
  5830. cell: [{ row: 1, col: 1, comment: { value: 'test' } }],
  5831. afterSetCellMeta: afterSetCellMetaCallback
  5832. });
  5833. var plugin = hot.getPlugin('comments');
  5834. plugin.removeCommentAtCell(1, 1);
  5835. expect(afterSetCellMetaCallback).toHaveBeenCalledWith(1, 1, 'comment', undefined, undefined, undefined);
  5836. });
  5837. it('should allow opening the comment editor using the `showAtCell` method', function () {
  5838. var hot = handsontable({
  5839. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5840. comments: true
  5841. });
  5842. var plugin = hot.getPlugin('comments');
  5843. var editor = plugin.editor.getInputElement();
  5844. expect(editor.parentNode.style.display).toEqual('none');
  5845. plugin.showAtCell(1, 1);
  5846. expect(editor.parentNode.style.display).toEqual('block');
  5847. });
  5848. it('should allow closing the comment editor using the `hide` method', function () {
  5849. var hot = handsontable({
  5850. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5851. comments: true
  5852. });
  5853. var plugin = hot.getPlugin('comments');
  5854. var editor = plugin.editor.getInputElement();
  5855. plugin.showAtCell(1, 1);
  5856. expect(editor.parentNode.style.display).toEqual('block');
  5857. plugin.hide();
  5858. expect(editor.parentNode.style.display).toEqual('none');
  5859. });
  5860. });
  5861. it('`updateCommentMeta` & `setComment` functions should extend cellMetaObject properly', function () {
  5862. var comment, readOnly;
  5863. var hot = handsontable({
  5864. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5865. comments: true
  5866. });
  5867. var plugin = hot.getPlugin('comments');
  5868. setCellMeta(0, 0, 'comment', { readOnly: true });
  5869. plugin.updateCommentMeta(0, 0, { value: 'Test' });
  5870. comment = getCellMeta(0, 0).comment;
  5871. readOnly = comment && comment.readOnly;
  5872. expect(readOnly).toEqual(true);
  5873. plugin.setRange({ from: { row: 0, col: 0 }, to: { row: 0, col: 0 } });
  5874. plugin.setComment('Test2');
  5875. comment = getCellMeta(0, 0).comment;
  5876. readOnly = comment && comment.readOnly;
  5877. expect(readOnly).toEqual(true);
  5878. });
  5879. describe('Using the Context Menu', function () {
  5880. it('should open the comment editor when clicking the "Add comment" entry', function () {
  5881. var hot = handsontable({
  5882. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5883. contextMenu: true,
  5884. comments: true
  5885. });
  5886. selectCell(1, 1);
  5887. contextMenu();
  5888. var addCommentButton = $('.htItemWrapper').filter(function () {
  5889. return $(this).text() === 'Add comment';
  5890. })[0];
  5891. $(addCommentButton).simulate('mousedown');
  5892. var editor = hot.getPlugin('comments').editor.getInputElement();
  5893. expect($(editor).parents('.htComments')[0].style.display).toEqual('block');
  5894. });
  5895. it('should remove the comment from a cell after clicking the "Delete comment" entry', function () {
  5896. var hot = handsontable({
  5897. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5898. contextMenu: true,
  5899. comments: true,
  5900. cell: [{ row: 1, col: 1, comment: { value: 'Test comment' } }]
  5901. });
  5902. expect(getCellMeta(1, 1).comment.value).toEqual('Test comment');
  5903. selectCell(1, 1);
  5904. contextMenu();
  5905. var deleteCommentButton = $('.htItemWrapper').filter(function () {
  5906. return $(this).text() === 'Delete comment';
  5907. })[0];
  5908. $(deleteCommentButton).simulate('mousedown');
  5909. expect(getCellMeta(1, 1).comment).toEqual(void 0);
  5910. });
  5911. it('should remove comments from a selected group of cells after clicking the "Delete comment" entry', function () {
  5912. var hot = handsontable({
  5913. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5914. contextMenu: true,
  5915. comments: true,
  5916. cell: [{ row: 1, col: 1, comment: { value: 'Test comment' } }, { row: 2, col: 2, comment: { value: 'Test comment 2' } }]
  5917. });
  5918. expect(getCellMeta(1, 1).comment.value).toEqual('Test comment');
  5919. expect(getCellMeta(2, 2).comment.value).toEqual('Test comment 2');
  5920. selectCell(1, 1, 2, 2);
  5921. contextMenu();
  5922. var deleteCommentButton = $('.htItemWrapper').filter(function () {
  5923. return $(this).text() === 'Delete comment';
  5924. })[0];
  5925. $(deleteCommentButton).simulate('mousedown');
  5926. expect(getCellMeta(1, 1).comment).toEqual(void 0);
  5927. expect(getCellMeta(2, 2).comment).toEqual(void 0);
  5928. });
  5929. it('should make the comment editor\'s textarea read-only after clicking the "Read only comment" entry', function (done) {
  5930. var hot = handsontable({
  5931. data: Handsontable.helper.createSpreadsheetData(4, 4),
  5932. contextMenu: true,
  5933. comments: true,
  5934. cell: [{ row: 1, col: 1, comment: { value: 'Test comment' } }]
  5935. });
  5936. selectCell(1, 1);
  5937. contextMenu();
  5938. var editor = hot.getPlugin('comments').editor.getInputElement();
  5939. expect($(editor)[0].readOnly).toBe(false);
  5940. var readOnlyComment = $('.htItemWrapper').filter(function () {
  5941. return $(this).text() === 'Read only comment';
  5942. })[0];
  5943. $(readOnlyComment).simulate('mousedown');
  5944. $(document).simulate('mouseup');
  5945. $(getCell(1, 1)).simulate('mouseover', {
  5946. clientX: Handsontable.dom.offset(getCell(1, 1)).left + 5,
  5947. clientY: Handsontable.dom.offset(getCell(1, 1)).top + 5
  5948. });
  5949. setTimeout(function () {
  5950. expect($(editor)[0].readOnly).toBe(true);
  5951. done();
  5952. }, 550);
  5953. });
  5954. });
  5955. describe('Hooks invoked after changing cell meta', function () {
  5956. it('should trigger `afterSetCellMeta` callback after deleting comment by context menu', function () {
  5957. var afterSetCellMetaCallback = jasmine.createSpy('afterSetCellMetaCallback');
  5958. var rows = 10,
  5959. columns = 10;
  5960. handsontable({
  5961. data: Handsontable.helper.createSpreadsheetData(rows, columns),
  5962. rowHeaders: true,
  5963. colHeaders: true,
  5964. contextMenu: true,
  5965. comments: true,
  5966. columns: function columns() {
  5967. return {
  5968. comment: {
  5969. value: 'test'
  5970. }
  5971. };
  5972. },
  5973. afterSetCellMeta: afterSetCellMetaCallback
  5974. });
  5975. expect(afterSetCellMetaCallback).not.toHaveBeenCalled();
  5976. selectCell(1, 1);
  5977. contextMenu();
  5978. var deleteCommentButton = $('.htItemWrapper').filter(function () {
  5979. return $(this).text() === 'Delete comment';
  5980. })[0];
  5981. $(deleteCommentButton).simulate('mousedown');
  5982. expect(afterSetCellMetaCallback).toHaveBeenCalledWith(1, 1, 'comment', undefined, undefined, undefined);
  5983. });
  5984. // Don't work in PhantomJS
  5985. // It will work probably when #3961 will be fixed
  5986. xit('should trigger `afterSetCellMeta` callback after editing comment by context menu', function (done) {
  5987. var afterSetCellMetaCallback = jasmine.createSpy('afterSetCellMetaCallback');
  5988. var rows = 10,
  5989. columns = 10;
  5990. handsontable({
  5991. data: Handsontable.helper.createSpreadsheetData(rows, columns),
  5992. rowHeaders: true,
  5993. colHeaders: true,
  5994. contextMenu: true,
  5995. comments: true,
  5996. columns: function columns() {
  5997. return {
  5998. comment: {
  5999. value: 'test'
  6000. }
  6001. };
  6002. },
  6003. afterSetCellMeta: afterSetCellMetaCallback
  6004. });
  6005. selectCell(0, 0);
  6006. contextMenu();
  6007. var editCommentButton = $('.htItemWrapper').filter(function () {
  6008. return $(this).text() === 'Edit comment';
  6009. })[0];
  6010. $(editCommentButton).simulate('mousedown');
  6011. setTimeout(function () {
  6012. $('.htCommentTextArea').val('Edited comment');
  6013. // changing focus
  6014. $('body').simulate('mousedown');
  6015. setTimeout(function () {
  6016. expect(afterSetCellMetaCallback).toHaveBeenCalledWith(0, 0, 'comment', { value: 'Edited comment' }, undefined, undefined);
  6017. done();
  6018. }, 100);
  6019. }, 100);
  6020. });
  6021. });
  6022. });
  6023. /***/ }),
  6024. /* 130 */
  6025. /***/ (function(module, exports, __webpack_require__) {
  6026. "use strict";
  6027. describe('ContextMenu', function () {
  6028. var id = 'testContainer';
  6029. beforeEach(function () {
  6030. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  6031. });
  6032. afterEach(function () {
  6033. if (this.$container) {
  6034. destroy();
  6035. this.$container.remove();
  6036. }
  6037. });
  6038. describe('alignment', function () {
  6039. it('should align text left', function (done) {
  6040. var hot = handsontable({
  6041. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6042. contextMenu: true,
  6043. height: 100
  6044. });
  6045. contextMenu();
  6046. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6047. item.simulate('mouseover');
  6048. setTimeout(function () {
  6049. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6050. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(0);
  6051. button.simulate('mousedown'); // Text left
  6052. expect(getCellMeta(0, 0).className).toEqual('htLeft');
  6053. expect(getCell(0, 0).className).toContain('htLeft');
  6054. done();
  6055. }, 350);
  6056. });
  6057. it('should align text center', function (done) {
  6058. var hot = handsontable({
  6059. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6060. contextMenu: true,
  6061. height: 100
  6062. });
  6063. contextMenu();
  6064. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6065. item.simulate('mouseover');
  6066. setTimeout(function () {
  6067. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6068. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(1);
  6069. button.simulate('mousedown'); // Text center
  6070. expect(getCellMeta(0, 0).className).toEqual('htCenter');
  6071. expect(getCell(0, 0).className).toContain('htCenter');
  6072. done();
  6073. }, 350);
  6074. });
  6075. it('should align text right', function (done) {
  6076. var hot = handsontable({
  6077. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6078. contextMenu: true,
  6079. height: 100
  6080. });
  6081. contextMenu();
  6082. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6083. item.simulate('mouseover');
  6084. setTimeout(function () {
  6085. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6086. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(2);
  6087. button.simulate('mousedown'); // Text right
  6088. expect(getCellMeta(0, 0).className).toEqual('htRight');
  6089. expect(getCell(0, 0).className).toContain('htRight');
  6090. done();
  6091. }, 350);
  6092. });
  6093. it('should justify text', function (done) {
  6094. var hot = handsontable({
  6095. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6096. contextMenu: true,
  6097. height: 100
  6098. });
  6099. contextMenu();
  6100. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6101. item.simulate('mouseover');
  6102. setTimeout(function () {
  6103. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6104. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(3);
  6105. button.simulate('mousedown'); // Text justify
  6106. deselectCell();
  6107. expect(getCellMeta(0, 0).className).toEqual('htJustify');
  6108. expect(getCell(0, 0).className).toContain('htJustify');
  6109. done();
  6110. }, 350); // menu opens after 300ms
  6111. });
  6112. it('should vertical align text top', function (done) {
  6113. var hot = handsontable({
  6114. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6115. contextMenu: true,
  6116. height: 100
  6117. });
  6118. contextMenu();
  6119. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6120. item.simulate('mouseover');
  6121. setTimeout(function () {
  6122. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6123. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(4);
  6124. button.simulate('mousedown'); // Text top
  6125. deselectCell();
  6126. expect(getCellMeta(0, 0).className).toEqual('htTop');
  6127. expect(getCell(0, 0).className).toContain('htTop');
  6128. done();
  6129. }, 350); // menu opens after 300ms
  6130. });
  6131. it('should vertical align text middle', function (done) {
  6132. var hot = handsontable({
  6133. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6134. contextMenu: true,
  6135. height: 100
  6136. });
  6137. contextMenu();
  6138. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6139. item.simulate('mouseover');
  6140. setTimeout(function () {
  6141. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6142. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(5);
  6143. button.simulate('mousedown'); // Text middle
  6144. deselectCell();
  6145. expect(getCellMeta(0, 0).className).toEqual('htMiddle');
  6146. expect(getCell(0, 0).className).toContain('htMiddle');
  6147. done();
  6148. }, 350); // menu opens after 300ms
  6149. });
  6150. it('should vertical align text bottom', function (done) {
  6151. var hot = handsontable({
  6152. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6153. contextMenu: true,
  6154. height: 100
  6155. });
  6156. contextMenu();
  6157. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6158. item.simulate('mouseover');
  6159. setTimeout(function () {
  6160. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6161. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(6);
  6162. button.simulate('mousedown'); // Text bottom
  6163. deselectCell();
  6164. expect(getCellMeta(0, 0).className).toEqual('htBottom');
  6165. expect(getCell(0, 0).className).toContain('htBottom');
  6166. done();
  6167. }, 350); // menu opens after 300ms
  6168. });
  6169. it('should trigger `afterSetCellMeta` callback after changing alignment by context menu', function (done) {
  6170. var afterSetCellMetaCallback = jasmine.createSpy('afterSetCellMetaCallback');
  6171. var hot = handsontable({
  6172. data: Handsontable.helper.createSpreadsheetData(5, 5),
  6173. rowHeaders: true,
  6174. colHeaders: true,
  6175. contextMenu: true,
  6176. afterSetCellMeta: afterSetCellMetaCallback
  6177. });
  6178. selectCell(2, 3);
  6179. contextMenu();
  6180. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6181. item.simulate('mouseover');
  6182. setTimeout(function () {
  6183. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6184. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(2);
  6185. button.simulate('mousedown'); // Text bottom
  6186. deselectCell();
  6187. expect(afterSetCellMetaCallback).toHaveBeenCalledWith(2, 3, 'className', 'htRight', undefined, undefined);
  6188. done();
  6189. }, 350); // menu opens after 300ms
  6190. });
  6191. });
  6192. });
  6193. /***/ }),
  6194. /* 131 */
  6195. /***/ (function(module, exports, __webpack_require__) {
  6196. "use strict";
  6197. describe('ContextMenu', function () {
  6198. var id = 'testContainer';
  6199. beforeEach(function () {
  6200. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  6201. });
  6202. afterEach(function () {
  6203. if (this.$container) {
  6204. destroy();
  6205. this.$container.remove();
  6206. }
  6207. });
  6208. it('should update context menu items by calling `updateSettings` method', function () {
  6209. var hot = handsontable({
  6210. contextMenu: ['row_above', 'row_below', '---------', 'remove_row'],
  6211. height: 100
  6212. });
  6213. contextMenu();
  6214. var items = $('.htContextMenu tbody td');
  6215. var actions = items.not('.htSeparator');
  6216. var separators = items.filter('.htSeparator');
  6217. expect(actions.length).toEqual(3);
  6218. expect(separators.length).toEqual(1);
  6219. expect(actions.text()).toEqual(['Insert row above', 'Insert row below', 'Remove row'].join(''));
  6220. hot.updateSettings({
  6221. contextMenu: ['remove_row']
  6222. });
  6223. contextMenu();
  6224. items = $('.htContextMenu tbody td');
  6225. actions = items.not('.htSeparator');
  6226. separators = items.filter('.htSeparator');
  6227. expect(actions.length).toEqual(1);
  6228. expect(separators.length).toEqual(0);
  6229. expect(actions.text()).toEqual(['Remove row'].join(''));
  6230. hot.updateSettings({
  6231. contextMenu: {
  6232. items: {
  6233. remove_col: true,
  6234. hsep1: '---------',
  6235. custom: { name: 'My custom item' }
  6236. }
  6237. }
  6238. });
  6239. contextMenu();
  6240. items = $('.htContextMenu tbody td');
  6241. actions = items.not('.htSeparator');
  6242. separators = items.filter('.htSeparator');
  6243. expect(actions.length).toEqual(2);
  6244. expect(separators.length).toEqual(1);
  6245. expect(actions.text()).toEqual(['Remove column', 'My custom item'].join(''));
  6246. });
  6247. describe('menu opening', function () {
  6248. it('should open menu after right click on table cell', function () {
  6249. var hot = handsontable({
  6250. contextMenu: true,
  6251. height: 100
  6252. });
  6253. expect(hot.getPlugin('contextMenu')).toBeDefined();
  6254. expect($('.htContextMenu').is(':visible')).toBe(false);
  6255. contextMenu();
  6256. expect($('.htContextMenu').is(':visible')).toBe(true);
  6257. });
  6258. it('should not open the menu after clicking an open editor', function () {
  6259. var hot = handsontable({
  6260. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6261. contextMenu: true,
  6262. height: 100
  6263. });
  6264. selectCell(2, 2);
  6265. keyDownUp('enter');
  6266. expect(hot.getPlugin('contextMenu')).toBeDefined();
  6267. expect($('.htContextMenu').is(':visible')).toBe(false);
  6268. contextMenu(hot.getActiveEditor().TEXTAREA);
  6269. expect($('.htContextMenu').is(':visible')).toBe(false);
  6270. });
  6271. it('should open menu after right click on header cell when only header cells are visible', function () {
  6272. var hot = handsontable({
  6273. data: [],
  6274. colHeaders: ['Year', 'Kia'],
  6275. columns: [{ data: 0 }, { data: 1 }],
  6276. contextMenu: true,
  6277. height: 100
  6278. });
  6279. expect(hot.getPlugin('contextMenu')).toBeDefined();
  6280. expect($('.htContextMenu').is(':visible')).toBe(false);
  6281. contextMenu(hot.rootElement.querySelector('.ht_clone_top thead th'));
  6282. expect($('.htContextMenu').is(':visible')).toBe(true);
  6283. });
  6284. it('should open menu after right click on header corner', function () {
  6285. var hot = handsontable({
  6286. data: [],
  6287. colHeaders: true,
  6288. rowHeaders: true,
  6289. contextMenu: true,
  6290. height: 100
  6291. });
  6292. expect(hot.getPlugin('contextMenu')).toBeDefined();
  6293. expect($('.htContextMenu').is(':visible')).toBe(false);
  6294. contextMenu(hot.rootElement.querySelector('.ht_clone_top_left_corner thead th'));
  6295. expect($('.htContextMenu').is(':visible')).toBe(true);
  6296. });
  6297. it('should open menu after right click active cell border', function () {
  6298. var hot = handsontable({
  6299. contextMenu: true,
  6300. height: 100
  6301. });
  6302. expect(hot.getPlugin('contextMenu')).toBeDefined();
  6303. expect($('.htContextMenu').is(':visible')).toBe(false);
  6304. selectCell(0, 0);
  6305. this.$container.find('.wtBorder.current:eq(0)').simulate('contextmenu');
  6306. expect($('.htContextMenu').is(':visible')).toBe(true);
  6307. });
  6308. });
  6309. describe('menu closing', function () {
  6310. it('should close menu after click', function () {
  6311. var hot = handsontable({
  6312. contextMenu: true,
  6313. height: 100
  6314. });
  6315. contextMenu();
  6316. expect($('.htContextMenu').is(':visible')).toBe(true);
  6317. mouseDown(this.$container);
  6318. expect($('.htContextMenu').is(':visible')).toBe(false);
  6319. });
  6320. it('should close menu after click under the menu', function () {
  6321. var hot = handsontable({
  6322. data: Handsontable.helper.createSpreadsheetData(500, 10),
  6323. contextMenu: true,
  6324. height: 500
  6325. });
  6326. contextMenu();
  6327. expect($('.htContextMenu').is(':visible')).toBe(true);
  6328. var rect = $('.htContextMenu')[0].getBoundingClientRect();
  6329. var x = parseInt(rect.left + rect.width / 2, 10);
  6330. var y = parseInt(rect.top + rect.height, 10);
  6331. mouseDown(document.elementFromPoint(x, y));
  6332. expect($('.htContextMenu').is(':visible')).toBe(false);
  6333. });
  6334. });
  6335. describe('menu disabled', function () {
  6336. it('should not open menu after right click', function () {
  6337. var hot = handsontable({
  6338. contextMenu: true,
  6339. height: 100
  6340. });
  6341. hot.getPlugin('contextMenu').disablePlugin();
  6342. expect($('.htContextMenu').is(':visible')).toBe(false);
  6343. contextMenu();
  6344. expect($('.htContextMenu').is(':visible')).toBe(false);
  6345. });
  6346. it('should not create context menu if it\'s disabled in constructor options', function () {
  6347. var hot = handsontable({
  6348. contextMenu: false,
  6349. height: 100
  6350. });
  6351. expect(hot.getPlugin('contextMenu').isEnabled()).toBe(false);
  6352. });
  6353. it('should reenable menu', function () {
  6354. var hot = handsontable({
  6355. contextMenu: true,
  6356. height: 100
  6357. });
  6358. hot.getPlugin('contextMenu').disablePlugin();
  6359. expect($('.htContextMenu').is(':visible')).toBe(false);
  6360. contextMenu();
  6361. expect($('.htContextMenu').is(':visible')).toBe(false);
  6362. hot.getPlugin('contextMenu').enablePlugin();
  6363. contextMenu();
  6364. expect($('.htContextMenu').is(':visible')).toBe(true);
  6365. });
  6366. it('should reenable menu with updateSettings when it was disabled in constructor', function () {
  6367. var hot = handsontable({
  6368. contextMenu: false,
  6369. height: 100
  6370. });
  6371. expect(hot.getPlugin('contextMenu').isEnabled()).toBe(false);
  6372. updateSettings({
  6373. contextMenu: true
  6374. });
  6375. expect(hot.getPlugin('contextMenu').isEnabled()).toBe(true);
  6376. expect($('.htContextMenu').is(':visible')).toBe(false);
  6377. contextMenu();
  6378. expect($('.htContextMenu').is(':visible')).toBe(true);
  6379. });
  6380. it('should disable menu with updateSettings when it was enabled in constructor', function () {
  6381. var hot = handsontable({
  6382. contextMenu: true,
  6383. height: 100
  6384. });
  6385. expect(hot.getPlugin('contextMenu').isEnabled()).toBe(true);
  6386. updateSettings({
  6387. contextMenu: false
  6388. });
  6389. expect(hot.getPlugin('contextMenu').isEnabled()).toBe(false);
  6390. });
  6391. it('should work properly (remove row) after destroy and new init', function () {
  6392. var test = function test() {
  6393. handsontable({
  6394. startRows: 5,
  6395. contextMenu: ['remove_row'],
  6396. height: 100
  6397. });
  6398. selectCell(0, 0);
  6399. contextMenu();
  6400. $('.htContextMenu .ht_master .htCore tbody').find('td').not('.htSeparator').eq(0).simulate('mousedown');
  6401. expect(getData().length).toEqual(4);
  6402. };
  6403. test();
  6404. destroy();
  6405. test();
  6406. });
  6407. });
  6408. describe('menu hidden items', function () {
  6409. it('should remove separators from top, bottom and duplicated', function () {
  6410. var hot = handsontable({
  6411. contextMenu: ['---------', '---------', 'row_above', '---------', '---------', 'row_below', '---------', 'remove_row'],
  6412. height: 100
  6413. });
  6414. contextMenu();
  6415. var items = $('.htContextMenu tbody td');
  6416. var actions = items.not('.htSeparator');
  6417. var separators = items.filter('.htSeparator');
  6418. expect(actions.length).toEqual(3);
  6419. expect(separators.length).toEqual(2);
  6420. });
  6421. it('should hide option if hidden function return true', function () {
  6422. var hot = handsontable({
  6423. startCols: 5,
  6424. colHeaders: true,
  6425. contextMenu: [{
  6426. key: '',
  6427. name: 'Custom option',
  6428. hidden: function hidden() {
  6429. return !this.selection.selectedHeader.cols;
  6430. }
  6431. }]
  6432. });
  6433. contextMenu();
  6434. var items = $('.htContextMenu tbody td');
  6435. var actions = items.not('.htSeparator');
  6436. expect(actions.length).toEqual(0);
  6437. var header = $('.ht_clone_top thead th').eq(1);
  6438. header.simulate('mousedown');
  6439. contextMenu();
  6440. items = $('.htContextMenu tbody td');
  6441. actions = items.not('.htSeparator');
  6442. expect(actions.length).toEqual(1);
  6443. });
  6444. });
  6445. describe('menu destroy', function () {
  6446. it('should close context menu when HOT is being destroyed', function () {
  6447. var hot = handsontable({
  6448. contextMenu: true,
  6449. height: 100
  6450. });
  6451. contextMenu();
  6452. expect($('.htContextMenu').is(':visible')).toBe(true);
  6453. destroy();
  6454. expect($('.htContextMenu').is(':visible')).toBe(false);
  6455. });
  6456. });
  6457. describe('subMenu', function () {
  6458. it('should not open subMenu immediately', function (done) {
  6459. var hot = handsontable({
  6460. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6461. contextMenu: true,
  6462. height: 100
  6463. });
  6464. contextMenu();
  6465. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6466. item.simulate('mouseover');
  6467. var contextSubMenu = $('.htContextMenuSub_' + item.text()).find('tbody td');
  6468. expect(contextSubMenu.length).toEqual(0);
  6469. setTimeout(function () {
  6470. var contextSubMenu = $('.htContextMenuSub_' + item.text()).find('tbody td');
  6471. expect(contextSubMenu.length).toEqual(0);
  6472. done();
  6473. }, 100);
  6474. });
  6475. it('should open subMenu with delay', function (done) {
  6476. var hot = handsontable({
  6477. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6478. contextMenu: true,
  6479. height: 100
  6480. });
  6481. contextMenu();
  6482. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6483. item.simulate('mouseover');
  6484. setTimeout(function () {
  6485. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6486. expect(contextSubMenu.length).toEqual(1);
  6487. done();
  6488. }, 350); // menu opens after 300ms
  6489. });
  6490. it('should NOT open subMenu if there is no subMenu for item', function () {
  6491. var hot = handsontable({
  6492. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6493. contextMenu: true,
  6494. height: 100
  6495. });
  6496. contextMenu();
  6497. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(8);
  6498. item.simulate('mouseover');
  6499. expect(item.hasClass('htSubmenu')).toBe(false);
  6500. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6501. expect(contextSubMenu.length).toEqual(0);
  6502. });
  6503. it('should open subMenu on the left of main menu if on the right there\'s no space left', function () {
  6504. var hot = handsontable({
  6505. data: Handsontable.helper.createSpreadsheetData(4, Math.floor(window.innerWidth / 50)),
  6506. contextMenu: true,
  6507. width: window.innerWidth
  6508. });
  6509. selectCell(0, countCols() - 1);
  6510. contextMenu();
  6511. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6512. var contextMenuRoot = $('.htContextMenu');
  6513. item.simulate('mouseover');
  6514. expect(item.text()).toBe('Alignment');
  6515. expect(item.hasClass('htSubmenu')).toBe(true);
  6516. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6517. expect(contextSubMenu.offset().left).toBeLessThan(contextMenuRoot.offset().left - contextSubMenu.width() + 30); // 30 - scroll
  6518. });
  6519. it('should open subMenu on the right of main menu if there\'s free space', function (done) {
  6520. var hot = handsontable({
  6521. data: Handsontable.helper.createSpreadsheetData(4, Math.floor(window.innerWidth / 50)),
  6522. contextMenu: true,
  6523. width: window.innerWidth
  6524. });
  6525. selectCell(0, countCols() - 9);
  6526. contextMenu();
  6527. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6528. var contextMenuRoot = $('.htContextMenu');
  6529. item.simulate('mouseover');
  6530. setTimeout(function () {
  6531. expect(item.text()).toBe('Alignment');
  6532. expect(item.hasClass('htSubmenu')).toBe(true);
  6533. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6534. expect(contextSubMenu.offset().left).toBeGreaterThan(contextMenuRoot.offset().left + contextMenuRoot.width() - 30); // 30 - scroll
  6535. done();
  6536. }, 350); // menu opens after 300ms
  6537. });
  6538. it('should open subMenu on the left-bottom of main menu if there\'s free space', function (done) {
  6539. var hot = handsontable({
  6540. data: Handsontable.helper.createSpreadsheetData(Math.floor(window.innerHeight / 23), Math.floor(window.innerWidth / 50)),
  6541. contextMenu: true,
  6542. height: window.innerHeight
  6543. });
  6544. window.scrollTo(0, document.body.clientHeight);
  6545. selectCell(0, countCols() - 1);
  6546. contextMenu();
  6547. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6548. var contextMenuRoot = $('.htContextMenu');
  6549. item.simulate('mouseover');
  6550. setTimeout(function () {
  6551. expect(item.text()).toBe('Alignment');
  6552. expect(item.hasClass('htSubmenu')).toBe(true);
  6553. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6554. expect(parseInt(contextSubMenu.offset().top, 10)).toBeAroundValue(parseInt(item.offset().top, 10) - 1);
  6555. expect(parseInt(contextSubMenu.offset().left, 10)).toBeLessThan(contextMenuRoot.offset().left - contextSubMenu.width() + 30); // 30 - scroll
  6556. done();
  6557. }, 350); // menu opens after 300ms
  6558. });
  6559. it('should open subMenu on the right-bottom of main menu if there\'s free space', function (done) {
  6560. var hot = handsontable({
  6561. data: Handsontable.helper.createSpreadsheetData(Math.floor(window.innerHeight / 23), Math.floor(window.innerWidth / 50)),
  6562. contextMenu: true,
  6563. height: window.innerHeight
  6564. });
  6565. window.scrollTo(0, document.body.clientHeight);
  6566. selectCell(0, countCols() - 9);
  6567. contextMenu();
  6568. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6569. var contextMenuRoot = $('.htContextMenu');
  6570. item.simulate('mouseover');
  6571. setTimeout(function () {
  6572. expect(item.text()).toBe('Alignment');
  6573. expect(item.hasClass('htSubmenu')).toBe(true);
  6574. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6575. expect(parseInt(contextSubMenu.offset().top, 10)).toBeAroundValue(parseInt(item.offset().top, 10) - 1);
  6576. expect(parseInt(contextSubMenu.offset().left, 10)).toBeGreaterThan(contextMenuRoot.offset().left + contextMenuRoot.width() - 30); // 30 - scroll
  6577. done();
  6578. }, 350); // menu opens after 300ms
  6579. });
  6580. it('should open subMenu on the left-top of main menu if there\'s no free space on bottom', function (done) {
  6581. var hot = handsontable({
  6582. data: Handsontable.helper.createSpreadsheetData(Math.floor(window.innerHeight / 23), Math.floor(window.innerWidth / 50)),
  6583. contextMenu: true,
  6584. height: window.innerHeight
  6585. });
  6586. selectCell(countRows() - 1, countCols() - 1);
  6587. contextMenu();
  6588. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6589. var contextMenuRoot = $('.htContextMenu');
  6590. item.simulate('mouseover');
  6591. setTimeout(function () {
  6592. expect(item.text()).toBe('Alignment');
  6593. expect(item.hasClass('htSubmenu')).toBe(true);
  6594. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6595. expect(contextSubMenu.offset().top + contextSubMenu.height() - 28).toBeAroundValue(item.offset().top);
  6596. expect(contextSubMenu.offset().left).toBeLessThan(contextMenuRoot.offset().left - contextSubMenu.width() + 30); // 30 - scroll
  6597. done();
  6598. }, 350); // menu opens after 300ms
  6599. });
  6600. it('should open subMenu on the right-top of main menu if there\'s no free space on bottom', function (done) {
  6601. var hot = handsontable({
  6602. data: Handsontable.helper.createSpreadsheetData(Math.floor(window.innerHeight / 23), Math.floor(window.innerWidth / 50)),
  6603. contextMenu: true,
  6604. height: window.innerHeight
  6605. });
  6606. selectCell(countRows() - 1, countCols() - 9);
  6607. contextMenu();
  6608. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  6609. var contextMenuRoot = $('.htContextMenu');
  6610. item.simulate('mouseover');
  6611. setTimeout(function () {
  6612. expect(item.text()).toBe('Alignment');
  6613. expect(item.hasClass('htSubmenu')).toBe(true);
  6614. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  6615. expect(contextSubMenu.offset().top + contextSubMenu.height() - 28).toBeAroundValue(item.offset().top);
  6616. expect(contextSubMenu.offset().left).toBeGreaterThan(contextMenuRoot.offset().left + contextMenuRoot.width() - 30); // 30 - scroll
  6617. done();
  6618. }, 350); // menu opens after 300ms
  6619. });
  6620. });
  6621. describe('default context menu actions', function () {
  6622. it('should display the default set of actions', function () {
  6623. var hot = handsontable({
  6624. contextMenu: true,
  6625. comments: true,
  6626. height: 100
  6627. });
  6628. contextMenu();
  6629. var items = $('.htContextMenu tbody td');
  6630. var actions = items.not('.htSeparator');
  6631. var separators = items.filter('.htSeparator');
  6632. expect(actions.length).toEqual(13);
  6633. expect(separators.length).toEqual(6);
  6634. expect(actions.text()).toEqual(['Insert row above', 'Insert row below', 'Insert column on the left', 'Insert column on the right', 'Remove row', 'Remove column', 'Undo', 'Redo', 'Read only', 'Alignment', 'Add comment', 'Delete comment', 'Read only comment'].join(''));
  6635. });
  6636. it('should disable column manipulation when row header selected', function () {
  6637. var hot = handsontable({
  6638. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6639. contextMenu: true,
  6640. colHeaders: true,
  6641. rowHeaders: true,
  6642. height: 100
  6643. });
  6644. $('.ht_clone_left .htCore').eq(0).find('tbody').find('th').eq(0).simulate('mousedown', { which: 3 });
  6645. contextMenu();
  6646. expect($('.htContextMenu tbody td.htDisabled').text()).toBe(['Insert column on the left', 'Insert column on the right', 'Remove column', 'Undo', 'Redo'].join(''));
  6647. });
  6648. it('should disable row manipulation when column header selected', function () {
  6649. var hot = handsontable({
  6650. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6651. contextMenu: true,
  6652. colHeaders: true,
  6653. rowHeaders: true,
  6654. height: 100
  6655. });
  6656. $('.ht_clone_top .htCore').find('thead').find('th').eq(2).simulate('mousedown', { which: 3 });
  6657. contextMenu();
  6658. expect($('.htContextMenu tbody td.htDisabled').text()).toBe(['Insert row above', 'Insert row below', 'Remove row', 'Undo', 'Redo'].join(''));
  6659. });
  6660. it('should disable cells manipulation when corner header selected', function () {
  6661. var hot = handsontable({
  6662. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6663. contextMenu: true,
  6664. colHeaders: true,
  6665. rowHeaders: true,
  6666. height: 100
  6667. });
  6668. $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0).simulate('mousedown', { which: 3 });
  6669. contextMenu();
  6670. expect($('.htContextMenu tbody td.htDisabled').text()).toBe(['Remove row', 'Remove column', 'Undo', 'Redo', 'Read only', 'Alignment'].join(''));
  6671. });
  6672. it('should insert row above selection', function () {
  6673. var hot = handsontable({
  6674. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6675. contextMenu: true,
  6676. height: 400
  6677. });
  6678. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  6679. hot.addHook('afterCreateRow', afterCreateRowCallback);
  6680. expect(countRows()).toEqual(4);
  6681. selectCell(1, 0, 3, 0);
  6682. contextMenu();
  6683. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(0).simulate('mousedown'); // Insert row above
  6684. expect(afterCreateRowCallback).toHaveBeenCalledWith(1, 1, 'ContextMenu.rowAbove', undefined, undefined, undefined);
  6685. expect(countRows()).toEqual(5);
  6686. expect($('.htContextMenu').is(':visible')).toBe(false);
  6687. });
  6688. it('should insert row above selection when initial data is empty', function () {
  6689. var hot = handsontable({
  6690. rowHeaders: true,
  6691. colHeaders: true,
  6692. data: [],
  6693. dataSchema: [],
  6694. contextMenu: true,
  6695. height: 400
  6696. });
  6697. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  6698. hot.addHook('afterCreateRow', afterCreateRowCallback);
  6699. expect(countRows()).toEqual(0);
  6700. var cell = $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0);
  6701. cell.simulate('mousedown', { which: 3 });
  6702. contextMenu(cell[0]);
  6703. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(0).simulate('mousedown'); // Insert row above
  6704. expect(afterCreateRowCallback).toHaveBeenCalledWith(0, 1, 'ContextMenu.rowAbove', undefined, undefined, undefined);
  6705. expect(countRows()).toEqual(1);
  6706. expect($('.htContextMenu').is(':visible')).toBe(false);
  6707. });
  6708. it('should NOT display insert row selection', function () {
  6709. var hot = handsontable({
  6710. contextMenu: true,
  6711. allowInsertRow: false
  6712. });
  6713. contextMenu();
  6714. var items = $('.htContextMenu tbody td');
  6715. var actions = items.not('.htSeparator');
  6716. var separators = items.filter('.htSeparator');
  6717. expect(actions.length).toEqual(8);
  6718. expect(separators.length).toEqual(4);
  6719. expect(actions.text()).toEqual(['Insert column on the left', 'Insert column on the right', 'Remove row', 'Remove column', 'Undo', 'Redo', 'Read only', 'Alignment'].join(''));
  6720. });
  6721. it('should NOT display insert column selection', function () {
  6722. var hot = handsontable({
  6723. contextMenu: true,
  6724. allowInsertColumn: false
  6725. });
  6726. contextMenu();
  6727. var items = $('.htContextMenu tbody td');
  6728. var actions = items.not('.htSeparator');
  6729. expect(actions.length).toEqual(8);
  6730. expect(actions.text()).toEqual(['Insert row above', 'Insert row below', 'Remove row', 'Remove column', 'Undo', 'Redo', 'Read only', 'Alignment'].join(''));
  6731. });
  6732. it('should insert row above selection (reverse selection)', function () {
  6733. var hot = handsontable({
  6734. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6735. contextMenu: true,
  6736. height: 100
  6737. });
  6738. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  6739. hot.addHook('afterCreateRow', afterCreateRowCallback);
  6740. expect(countRows()).toEqual(4);
  6741. selectCell(3, 0, 1, 0);
  6742. contextMenu();
  6743. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(0).simulate('mousedown'); // Insert row above
  6744. expect(afterCreateRowCallback).toHaveBeenCalledWith(1, 1, 'ContextMenu.rowAbove', undefined, undefined, undefined);
  6745. expect(countRows()).toEqual(5);
  6746. expect($('.htContextMenu').is(':visible')).toBe(false);
  6747. });
  6748. it('should insert row below selection', function () {
  6749. var hot = handsontable({
  6750. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6751. contextMenu: true,
  6752. height: 100
  6753. });
  6754. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  6755. hot.addHook('afterCreateRow', afterCreateRowCallback);
  6756. expect(countRows()).toEqual(4);
  6757. selectCell(1, 0, 3, 0);
  6758. contextMenu();
  6759. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(1).simulate('mousedown'); // Insert row above
  6760. expect(afterCreateRowCallback).toHaveBeenCalledWith(4, 1, 'ContextMenu.rowBelow', undefined, undefined, undefined);
  6761. expect(countRows()).toEqual(5);
  6762. expect($('.htContextMenu').is(':visible')).toBe(false);
  6763. });
  6764. it('should insert row below selection when initial data is empty', function () {
  6765. var hot = handsontable({
  6766. rowHeaders: true,
  6767. colHeaders: true,
  6768. data: [],
  6769. dataSchema: [],
  6770. contextMenu: true,
  6771. height: 400
  6772. });
  6773. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  6774. hot.addHook('afterCreateRow', afterCreateRowCallback);
  6775. expect(countRows()).toEqual(0);
  6776. var cell = $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0);
  6777. cell.simulate('mousedown', { which: 3 });
  6778. contextMenu(cell[0]);
  6779. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(1).simulate('mousedown'); // Insert row below
  6780. expect(afterCreateRowCallback).toHaveBeenCalledWith(0, 1, 'ContextMenu.rowBelow', undefined, undefined, undefined);
  6781. expect(countRows()).toEqual(1);
  6782. expect($('.htContextMenu').is(':visible')).toBe(false);
  6783. });
  6784. it('should insert row below selection (reverse selection)', function () {
  6785. var hot = handsontable({
  6786. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6787. contextMenu: true,
  6788. height: 100
  6789. });
  6790. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  6791. hot.addHook('afterCreateRow', afterCreateRowCallback);
  6792. expect(countRows()).toEqual(4);
  6793. selectCell(3, 0, 1, 0);
  6794. contextMenu();
  6795. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(1).simulate('mousedown'); // Insert row below
  6796. expect(afterCreateRowCallback).toHaveBeenCalledWith(4, 1, 'ContextMenu.rowBelow', undefined, undefined, undefined);
  6797. expect(countRows()).toEqual(5);
  6798. expect($('.htContextMenu').is(':visible')).toBe(false);
  6799. });
  6800. it('should insert column on the left of selection', function () {
  6801. var hot = handsontable({
  6802. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6803. contextMenu: true,
  6804. width: 400,
  6805. height: 400
  6806. });
  6807. var afterCreateColCallback = jasmine.createSpy('afterCreateColCallback');
  6808. hot.addHook('afterCreateCol', afterCreateColCallback);
  6809. expect(countCols()).toEqual(4);
  6810. selectCell(0, 1, 0, 3);
  6811. contextMenu();
  6812. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(2).simulate('mousedown'); // Insert col left
  6813. expect(afterCreateColCallback).toHaveBeenCalledWith(1, 1, 'ContextMenu.columnLeft', undefined, undefined, undefined);
  6814. expect(countCols()).toEqual(5);
  6815. expect($('.htContextMenu').is(':visible')).toBe(false);
  6816. });
  6817. it('should insert column on the left of selection when initial data is empty', function () {
  6818. var hot = handsontable({
  6819. rowHeaders: true,
  6820. colHeaders: true,
  6821. data: [],
  6822. dataSchema: [],
  6823. contextMenu: true,
  6824. height: 400
  6825. });
  6826. var afterCreateColCallback = jasmine.createSpy('afterCreateColCallback');
  6827. hot.addHook('afterCreateCol', afterCreateColCallback);
  6828. expect(countCols()).toEqual(0);
  6829. var cell = $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0);
  6830. cell.simulate('mousedown', { which: 3 });
  6831. contextMenu(cell[0]);
  6832. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(3).simulate('mousedown'); // Insert column on the left
  6833. expect(afterCreateColCallback).toHaveBeenCalledWith(0, 1, 'ContextMenu.columnRight', undefined, undefined, undefined);
  6834. expect(countCols()).toEqual(1);
  6835. expect($('.htContextMenu').is(':visible')).toBe(false);
  6836. });
  6837. it('should insert column on the left of selection (reverse selection)', function () {
  6838. var hot = handsontable({
  6839. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6840. contextMenu: true,
  6841. height: 100
  6842. });
  6843. var afterCreateColCallback = jasmine.createSpy('afterCreateColCallback');
  6844. hot.addHook('afterCreateCol', afterCreateColCallback);
  6845. expect(countCols()).toEqual(4);
  6846. selectCell(0, 3, 0, 1);
  6847. contextMenu();
  6848. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(2).simulate('mousedown'); // Insert col left
  6849. expect(afterCreateColCallback).toHaveBeenCalledWith(1, 1, 'ContextMenu.columnLeft', undefined, undefined, undefined);
  6850. expect(countCols()).toEqual(5);
  6851. expect($('.htContextMenu').is(':visible')).toBe(false);
  6852. });
  6853. it('should insert column on the right of selection', function () {
  6854. var hot = handsontable({
  6855. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6856. contextMenu: true,
  6857. height: 100
  6858. });
  6859. var afterCreateColCallback = jasmine.createSpy('afterCreateColCallback');
  6860. hot.addHook('afterCreateCol', afterCreateColCallback);
  6861. expect(countCols()).toEqual(4);
  6862. selectCell(0, 1, 0, 3);
  6863. contextMenu();
  6864. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(2).simulate('mousedown'); // Insert col right
  6865. expect(afterCreateColCallback).toHaveBeenCalledWith(1, 1, 'ContextMenu.columnLeft', undefined, undefined, undefined);
  6866. expect(countCols()).toEqual(5);
  6867. expect($('.htContextMenu').is(':visible')).toBe(false);
  6868. });
  6869. it('should insert column on the right of selection when initial data is empty', function () {
  6870. var hot = handsontable({
  6871. rowHeaders: true,
  6872. colHeaders: true,
  6873. data: [],
  6874. dataSchema: [],
  6875. contextMenu: true,
  6876. height: 400
  6877. });
  6878. var afterCreateColCallback = jasmine.createSpy('afterCreateColCallback');
  6879. hot.addHook('afterCreateCol', afterCreateColCallback);
  6880. expect(countCols()).toEqual(0);
  6881. var cell = $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0);
  6882. cell.simulate('mousedown', { which: 3 });
  6883. contextMenu(cell[0]);
  6884. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(3).simulate('mousedown'); // Insert column on the right
  6885. expect(afterCreateColCallback).toHaveBeenCalledWith(0, 1, 'ContextMenu.columnRight', undefined, undefined, undefined);
  6886. expect(countCols()).toEqual(1);
  6887. expect($('.htContextMenu').is(':visible')).toBe(false);
  6888. });
  6889. it('should insert column on the right of selection (reverse selection)', function () {
  6890. var hot = handsontable({
  6891. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6892. contextMenu: true,
  6893. height: 100
  6894. });
  6895. var afterCreateColCallback = jasmine.createSpy('afterCreateColCallback');
  6896. hot.addHook('afterCreateCol', afterCreateColCallback);
  6897. expect(countCols()).toEqual(4);
  6898. selectCell(0, 3, 0, 1);
  6899. contextMenu();
  6900. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(3).simulate('mousedown'); // Insert col right
  6901. expect(afterCreateColCallback).toHaveBeenCalledWith(4, 1, 'ContextMenu.columnRight', undefined, undefined, undefined);
  6902. expect(countCols()).toEqual(5);
  6903. expect($('.htContextMenu').is(':visible')).toBe(false);
  6904. });
  6905. it('should remove selected rows', function () {
  6906. var hot = handsontable({
  6907. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6908. contextMenu: true,
  6909. height: 100
  6910. });
  6911. var afterRemoveRowCallback = jasmine.createSpy('afterRemoveRowCallback');
  6912. hot.addHook('afterRemoveRow', afterRemoveRowCallback);
  6913. expect(countRows()).toEqual(4);
  6914. selectCell(1, 0, 3, 0);
  6915. contextMenu();
  6916. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(4).simulate('mousedown'); // Remove row
  6917. expect(afterRemoveRowCallback).toHaveBeenCalledWith(1, 3, [1, 2, 3], 'ContextMenu.removeRow', undefined, undefined);
  6918. expect(countRows()).toEqual(1);
  6919. expect($('.htContextMenu').is(':visible')).toBe(false);
  6920. });
  6921. it('should allow to remove the latest row', function () {
  6922. var hot = handsontable({
  6923. data: Handsontable.helper.createSpreadsheetData(1, 4),
  6924. contextMenu: true,
  6925. height: 100
  6926. });
  6927. var afterRemoveRowCallback = jasmine.createSpy('afterRemoveRowCallback');
  6928. hot.addHook('afterRemoveRow', afterRemoveRowCallback);
  6929. expect(countRows()).toBe(1);
  6930. selectCell(0, 0, 0, 0);
  6931. contextMenu();
  6932. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(4).simulate('mousedown'); // Remove row
  6933. expect(afterRemoveRowCallback).toHaveBeenCalledWith(0, 1, [0], 'ContextMenu.removeRow', undefined, undefined);
  6934. expect(countRows()).toBe(0);
  6935. expect($('.htContextMenu').is(':visible')).toBe(false);
  6936. });
  6937. it('should remove selected rows (reverse selection)', function () {
  6938. var hot = handsontable({
  6939. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6940. contextMenu: true,
  6941. height: 100
  6942. });
  6943. var afterRemoveRowCallback = jasmine.createSpy('afterRemoveRowCallback');
  6944. hot.addHook('afterRemoveRow', afterRemoveRowCallback);
  6945. expect(countRows()).toBe(4);
  6946. selectCell(3, 0, 1, 0);
  6947. contextMenu();
  6948. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(4).simulate('mousedown'); // Remove row
  6949. expect(afterRemoveRowCallback).toHaveBeenCalledWith(1, 3, [1, 2, 3], 'ContextMenu.removeRow', undefined, undefined);
  6950. expect(countRows()).toBe(1);
  6951. expect($('.htContextMenu').is(':visible')).toBe(false);
  6952. });
  6953. it('should remove selected columns', function () {
  6954. var hot = handsontable({
  6955. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6956. contextMenu: true,
  6957. height: 100
  6958. });
  6959. var afterRemoveColCallback = jasmine.createSpy('afterRemoveColCallback');
  6960. hot.addHook('afterRemoveCol', afterRemoveColCallback);
  6961. expect(countCols()).toBe(4);
  6962. selectCell(0, 1, 0, 3);
  6963. contextMenu();
  6964. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(5).simulate('mousedown'); // Remove col
  6965. expect(afterRemoveColCallback).toHaveBeenCalledWith(1, 3, [1, 2, 3], 'ContextMenu.removeColumn', undefined, undefined);
  6966. expect(countCols()).toBe(1);
  6967. expect($('.htContextMenu').is(':visible')).toBe(false);
  6968. });
  6969. it('should allow to remove the latest column', function () {
  6970. var hot = handsontable({
  6971. data: Handsontable.helper.createSpreadsheetData(4, 1),
  6972. contextMenu: true,
  6973. height: 100
  6974. });
  6975. var afterRemoveColCallback = jasmine.createSpy('afterRemoveColCallback');
  6976. hot.addHook('afterRemoveCol', afterRemoveColCallback);
  6977. expect(countCols()).toBe(1);
  6978. selectCell(0, 0, 0, 0);
  6979. contextMenu();
  6980. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(5).simulate('mousedown'); // Remove column
  6981. expect(afterRemoveColCallback).toHaveBeenCalledWith(0, 1, [0], 'ContextMenu.removeColumn', undefined, undefined);
  6982. expect(countCols()).toBe(0);
  6983. expect($('.htContextMenu').is(':visible')).toBe(false);
  6984. });
  6985. it('should remove selected columns (reverse selection)', function () {
  6986. var hot = handsontable({
  6987. data: Handsontable.helper.createSpreadsheetData(4, 4),
  6988. contextMenu: true,
  6989. height: 100
  6990. });
  6991. var afterRemoveColCallback = jasmine.createSpy('afterRemoveColCallback');
  6992. hot.addHook('afterRemoveCol', afterRemoveColCallback);
  6993. expect(countCols()).toEqual(4);
  6994. selectCell(0, 3, 0, 1);
  6995. contextMenu();
  6996. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(5).simulate('mousedown'); // Remove col
  6997. expect(afterRemoveColCallback).toHaveBeenCalledWith(1, 3, [1, 2, 3], 'ContextMenu.removeColumn', undefined, undefined);
  6998. expect(countCols()).toEqual(1);
  6999. });
  7000. it('should undo changes', function () {
  7001. var hot = handsontable({
  7002. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7003. contextMenu: true,
  7004. height: 100
  7005. });
  7006. selectCell(0, 0);
  7007. expect(getDataAtCell(0, 0)).toEqual('A1');
  7008. setDataAtCell(0, 0, 'XX');
  7009. expect(getDataAtCell(0, 0)).toEqual('XX');
  7010. contextMenu();
  7011. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(6).simulate('mousedown'); // Undo
  7012. expect(getDataAtCell(0, 0)).toEqual('A1');
  7013. });
  7014. it('should redo changes', function () {
  7015. var hot = handsontable({
  7016. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7017. contextMenu: true,
  7018. height: 100
  7019. });
  7020. selectCell(0, 0);
  7021. expect(getDataAtCell(0, 0)).toEqual('A1');
  7022. setDataAtCell(0, 0, 'XX');
  7023. expect(getDataAtCell(0, 0)).toEqual('XX');
  7024. hot.undo();
  7025. expect(getDataAtCell(0, 0)).toEqual('A1');
  7026. contextMenu();
  7027. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(7).simulate('mousedown'); // Redo
  7028. expect(getDataAtCell(0, 0)).toEqual('XX');
  7029. });
  7030. it('should display only the specified actions', function () {
  7031. var hot = handsontable({
  7032. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7033. contextMenu: ['remove_row', 'undo'],
  7034. height: 100
  7035. });
  7036. contextMenu();
  7037. expect($('.htContextMenu .ht_master .htCore').find('tbody td').length).toEqual(2);
  7038. });
  7039. it('should make a single selected cell read-only', function () {
  7040. var hot = handsontable({
  7041. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7042. contextMenu: true,
  7043. height: 100
  7044. });
  7045. selectCell(0, 0);
  7046. expect(getDataAtCell(0, 0)).toEqual('A1');
  7047. expect(hot.getCellMeta(0, 0).readOnly).toBe(false);
  7048. selectCell(0, 0);
  7049. contextMenu();
  7050. var menu = $('.htContextMenu .ht_master .htCore tbody');
  7051. menu.find('td').not('.htSeparator').eq(8).simulate('mousedown'); // Make read-only
  7052. expect(hot.getCellMeta(0, 0).readOnly).toBe(true);
  7053. });
  7054. it('should make a single selected cell writable, when it\'s set to read-only', function () {
  7055. var hot = handsontable({
  7056. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7057. contextMenu: true,
  7058. height: 100
  7059. });
  7060. selectCell(0, 0);
  7061. expect(getDataAtCell(0, 0)).toEqual('A1');
  7062. hot.getCellMeta(0, 0).readOnly = true;
  7063. selectCell(0, 0);
  7064. contextMenu();
  7065. var menu = $('.htContextMenu .ht_master .htCore tbody');
  7066. menu.find('td').not('.htSeparator').eq(8).simulate('mousedown');
  7067. // $(hot.contextMenu.menu).find('tbody td').not('.htSeparator').eq(8).trigger('mousedown'); //Make writable
  7068. expect(hot.getCellMeta(0, 0).readOnly).toBe(false);
  7069. });
  7070. it('should make a group of selected cells read-only, if all of them are writable', function () {
  7071. var hot = handsontable({
  7072. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7073. contextMenu: true,
  7074. height: 100
  7075. });
  7076. for (var i = 0; i < 2; i++) {
  7077. for (var j = 0; j < 2; j++) {
  7078. expect(hot.getCellMeta(i, j).readOnly).toEqual(false);
  7079. }
  7080. }
  7081. selectCell(0, 0, 2, 2);
  7082. contextMenu();
  7083. var menu = $('.htContextMenu .ht_master .htCore tbody');
  7084. menu.find('td').not('.htSeparator').eq(8).simulate('mousedown');
  7085. // $(hot.contextMenu.menu).find('tbody td').not('.htSeparator').eq(8).trigger('mousedown'); //Make read-only
  7086. for (var _i = 0; _i < 2; _i++) {
  7087. for (var _j = 0; _j < 2; _j++) {
  7088. expect(hot.getCellMeta(_i, _j).readOnly).toEqual(true);
  7089. }
  7090. }
  7091. });
  7092. it('should not close menu after clicking on submenu root item', function () {
  7093. var hot = handsontable({
  7094. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7095. contextMenu: ['row_above', 'remove_row', '---------', 'alignment'],
  7096. height: 400
  7097. });
  7098. selectCell(1, 0, 3, 0);
  7099. contextMenu();
  7100. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(2).simulate('mousedown'); // Alignment
  7101. expect($('.htContextMenu').is(':visible')).toBe(true);
  7102. });
  7103. it('should make a group of selected cells read-only, if all of them are writable (reverse selection)', function () {
  7104. var hot = handsontable({
  7105. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7106. contextMenu: true,
  7107. height: 100
  7108. });
  7109. for (var i = 0; i < 2; i++) {
  7110. for (var j = 0; j < 2; j++) {
  7111. expect(hot.getCellMeta(i, j).readOnly).toEqual(false);
  7112. }
  7113. }
  7114. selectCell(2, 2, 0, 0);
  7115. contextMenu();
  7116. var menu = $('.htContextMenu .ht_master .htCore tbody');
  7117. menu.find('td').not('.htSeparator').eq(8).simulate('mousedown'); // Make read-only
  7118. for (var _i2 = 0; _i2 < 2; _i2++) {
  7119. for (var _j2 = 0; _j2 < 2; _j2++) {
  7120. expect(hot.getCellMeta(_i2, _j2).readOnly).toEqual(true);
  7121. }
  7122. }
  7123. });
  7124. it('should make a group of selected cells writable if at least one of them is read-only', function () {
  7125. var hot = handsontable({
  7126. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7127. contextMenu: true,
  7128. height: 100
  7129. });
  7130. for (var i = 0; i < 2; i++) {
  7131. for (var j = 0; j < 2; j++) {
  7132. expect(hot.getCellMeta(i, j).readOnly).toEqual(false);
  7133. }
  7134. }
  7135. hot.getCellMeta(1, 1).readOnly = true;
  7136. selectCell(0, 0, 2, 2);
  7137. contextMenu();
  7138. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(8).simulate('mousedown'); // Make writable
  7139. for (var _i3 = 0; _i3 < 2; _i3++) {
  7140. for (var _j3 = 0; _j3 < 2; _j3++) {
  7141. expect(hot.getCellMeta(_i3, _j3).readOnly).toEqual(false);
  7142. }
  7143. }
  7144. });
  7145. it('should make a group of selected cells writable if at least one of them is read-only (reverse selection)', function () {
  7146. var hot = handsontable({
  7147. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7148. contextMenu: true,
  7149. height: 100
  7150. });
  7151. for (var i = 0; i < 2; i++) {
  7152. for (var j = 0; j < 2; j++) {
  7153. expect(hot.getCellMeta(i, j).readOnly).toEqual(false);
  7154. }
  7155. }
  7156. hot.getCellMeta(1, 1).readOnly = true;
  7157. selectCell(2, 2, 0, 0);
  7158. contextMenu();
  7159. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(8).simulate('mousedown'); // Make writable
  7160. for (var _i4 = 0; _i4 < 2; _i4++) {
  7161. for (var _j4 = 0; _j4 < 2; _j4++) {
  7162. expect(hot.getCellMeta(_i4, _j4).readOnly).toEqual(false);
  7163. }
  7164. }
  7165. });
  7166. });
  7167. describe('disabling actions', function () {
  7168. it('should not close menu after clicking on disabled item', function () {
  7169. var hot = handsontable({
  7170. data: Handsontable.helper.createSpreadsheetData(4, 4),
  7171. contextMenu: ['undo', 'redo'],
  7172. height: 400
  7173. });
  7174. selectCell(1, 0, 3, 0);
  7175. contextMenu();
  7176. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(0).simulate('mousedown'); // Undo
  7177. expect($('.htContextMenu').is(':visible')).toBe(true);
  7178. });
  7179. it('should disable undo and redo action if undoRedo plugin is not enabled ', function () {
  7180. var hot = handsontable({
  7181. contextMenu: true,
  7182. undoRedo: false,
  7183. height: 100
  7184. });
  7185. contextMenu();
  7186. var $menu = $('.htContextMenu .ht_master .htCore');
  7187. expect($menu.find('tbody td:eq(9)').text()).toEqual('Undo');
  7188. expect($menu.find('tbody td:eq(9)').hasClass('htDisabled')).toBe(true);
  7189. expect($menu.find('tbody td:eq(10)').text()).toEqual('Redo');
  7190. expect($menu.find('tbody td:eq(10)').hasClass('htDisabled')).toBe(true);
  7191. });
  7192. it('should disable undo when there is nothing to undo ', function () {
  7193. var hot = handsontable({
  7194. contextMenu: true,
  7195. height: 100
  7196. });
  7197. contextMenu();
  7198. var $menu = $('.htContextMenu .ht_master .htCore');
  7199. expect(hot.undoRedo.isUndoAvailable()).toBe(false);
  7200. expect($menu.find('tbody td:eq(9)').text()).toEqual('Undo');
  7201. expect($menu.find('tbody td:eq(9)').hasClass('htDisabled')).toBe(true);
  7202. closeContextMenu();
  7203. setDataAtCell(0, 0, 'foo');
  7204. contextMenu();
  7205. $menu = $('.htContextMenu .ht_master .htCore');
  7206. expect(hot.undoRedo.isUndoAvailable()).toBe(true);
  7207. expect($menu.find('tbody td:eq(9)').hasClass('htDisabled')).toBe(false);
  7208. });
  7209. it('should disable redo when there is nothing to redo ', function () {
  7210. var hot = handsontable({
  7211. contextMenu: true,
  7212. height: 100
  7213. });
  7214. contextMenu();
  7215. var $menu = $('.htContextMenu .ht_master .htCore');
  7216. expect(hot.undoRedo.isRedoAvailable()).toBe(false);
  7217. expect($menu.find('tbody td:eq(10)').text()).toEqual('Redo');
  7218. expect($menu.find('tbody td:eq(10)').hasClass('htDisabled')).toBe(true);
  7219. closeContextMenu();
  7220. setDataAtCell(0, 0, 'foo');
  7221. hot.undo();
  7222. contextMenu();
  7223. $menu = $('.htContextMenu .ht_master .htCore');
  7224. expect(hot.undoRedo.isRedoAvailable()).toBe(true);
  7225. expect($menu.find('tbody td:eq(10)').hasClass('htDisabled')).toBe(false);
  7226. });
  7227. it('should disable Insert row in context menu when maxRows is reached', function () {
  7228. var hot = handsontable({
  7229. contextMenu: true,
  7230. maxRows: 6,
  7231. height: 100
  7232. });
  7233. contextMenu();
  7234. var $menu = $('.htContextMenu .ht_master .htCore');
  7235. expect($menu.find('tbody td:eq(0)').text()).toEqual('Insert row above');
  7236. expect($menu.find('tbody td:eq(0)').hasClass('htDisabled')).toBe(false);
  7237. expect($menu.find('tbody td:eq(1)').text()).toEqual('Insert row below');
  7238. expect($menu.find('tbody td:eq(1)').hasClass('htDisabled')).toBe(false);
  7239. closeContextMenu();
  7240. alter('insert_row');
  7241. contextMenu();
  7242. $menu = $('.htContextMenu .ht_master .htCore');
  7243. expect($menu.find('tbody td:eq(0)').hasClass('htDisabled')).toBe(true);
  7244. expect($menu.find('tbody td:eq(1)').hasClass('htDisabled')).toBe(true);
  7245. });
  7246. it('should disable Insert col in context menu when maxCols is reached', function () {
  7247. var hot = handsontable({
  7248. contextMenu: true,
  7249. maxCols: 6,
  7250. height: 100
  7251. });
  7252. contextMenu();
  7253. var $menu = $('.htContextMenu .ht_master .htCore');
  7254. expect($menu.find('tbody td:eq(3)').text()).toEqual('Insert column on the left');
  7255. expect($menu.find('tbody td:eq(3)').hasClass('htDisabled')).toBe(false);
  7256. expect($menu.find('tbody td:eq(4)').text()).toEqual('Insert column on the right');
  7257. expect($menu.find('tbody td:eq(4)').hasClass('htDisabled')).toBe(false);
  7258. closeContextMenu();
  7259. alter('insert_col');
  7260. contextMenu();
  7261. $menu = $('.htContextMenu .ht_master .htCore');
  7262. expect($menu.find('tbody td:eq(3)').hasClass('htDisabled')).toBe(true);
  7263. expect($menu.find('tbody td:eq(4)').hasClass('htDisabled')).toBe(true);
  7264. });
  7265. it('should NOT disable Insert col in context menu when only one column exists', function () {
  7266. var hot = handsontable({
  7267. data: [['single col']],
  7268. contextMenu: true,
  7269. maxCols: 10,
  7270. height: 100
  7271. });
  7272. selectCell(0, 0);
  7273. contextMenu();
  7274. var $menu = $('.htContextMenu .ht_master .htCore');
  7275. expect($menu.find('tbody td:eq(3)').text()).toEqual('Insert column on the left');
  7276. expect($menu.find('tbody td:eq(3)').hasClass('htDisabled')).toBe(false);
  7277. expect($menu.find('tbody td:eq(4)').text()).toEqual('Insert column on the right');
  7278. expect($menu.find('tbody td:eq(4)').hasClass('htDisabled')).toBe(false);
  7279. });
  7280. it('should disable Remove col in context menu when rows are selected by headers', function () {
  7281. var hot = handsontable({
  7282. contextMenu: ['remove_col', 'remove_row'],
  7283. height: 100,
  7284. colHeaders: true,
  7285. rowHeaders: true
  7286. });
  7287. var $rowsHeaders = this.$container.find('.ht_clone_left tr th');
  7288. $rowsHeaders.eq(1).simulate('mousedown');
  7289. $rowsHeaders.eq(2).simulate('mouseover');
  7290. $rowsHeaders.eq(3).simulate('mouseover');
  7291. $rowsHeaders.eq(3).simulate('mousemove');
  7292. $rowsHeaders.eq(3).simulate('mouseup');
  7293. contextMenu();
  7294. var $menu = $('.htContextMenu .ht_master .htCore');
  7295. expect($menu.find('tbody td:eq(0)').text()).toEqual('Remove column');
  7296. expect($menu.find('tbody td:eq(0)').hasClass('htDisabled')).toBe(true);
  7297. });
  7298. it('should disable Remove row in context menu when columns are selected by headers', function () {
  7299. var hot = handsontable({
  7300. contextMenu: ['remove_col', 'remove_row'],
  7301. height: 100,
  7302. colHeaders: true,
  7303. rowHeaders: true
  7304. });
  7305. this.$container.find('thead tr:eq(0) th:eq(1)').simulate('mousedown');
  7306. this.$container.find('thead tr:eq(0) th:eq(2)').simulate('mouseover');
  7307. this.$container.find('thead tr:eq(0) th:eq(3)').simulate('mouseover');
  7308. this.$container.find('thead tr:eq(0) th:eq(3)').simulate('mousemove');
  7309. this.$container.find('thead tr:eq(0) th:eq(3)').simulate('mouseup');
  7310. contextMenu();
  7311. var $menu = $('.htContextMenu .ht_master .htCore');
  7312. expect($menu.find('tbody td:eq(1)').text()).toEqual('Remove row');
  7313. expect($menu.find('tbody td:eq(1)').hasClass('htDisabled')).toBe(true);
  7314. });
  7315. });
  7316. describe('custom options', function () {
  7317. it('should have custom items list', function () {
  7318. var callback1 = jasmine.createSpy('callback1');
  7319. var callback2 = jasmine.createSpy('callback2');
  7320. var hot = handsontable({
  7321. contextMenu: {
  7322. items: {
  7323. cust1: {
  7324. name: 'CustomItem1',
  7325. callback: callback1
  7326. },
  7327. cust2: {
  7328. name: 'CustomItem2',
  7329. callback: callback2
  7330. }
  7331. }
  7332. },
  7333. height: 100
  7334. });
  7335. contextMenu();
  7336. expect($('.htContextMenu .ht_master .htCore').find('tbody td').length).toEqual(2);
  7337. expect($('.htContextMenu .ht_master .htCore').find('tbody td').text()).toEqual(['CustomItem1', 'CustomItem2'].join(''));
  7338. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(0)').simulate('mousedown');
  7339. expect(callback1.calls.count()).toEqual(1);
  7340. expect(callback2.calls.count()).toEqual(0);
  7341. contextMenu();
  7342. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(1)').simulate('mousedown');
  7343. expect(callback1.calls.count()).toEqual(1);
  7344. expect(callback2.calls.count()).toEqual(1);
  7345. });
  7346. it('should have custom items list (defined as a function)', function () {
  7347. var enabled = false;
  7348. var hot = handsontable({
  7349. contextMenu: {
  7350. items: {
  7351. cust1: {
  7352. name: function name() {
  7353. if (!enabled) {
  7354. return 'Enable my custom option';
  7355. }
  7356. return 'Disable my custom option';
  7357. },
  7358. callback: function callback() {}
  7359. }
  7360. }
  7361. },
  7362. height: 100
  7363. });
  7364. contextMenu();
  7365. expect($('.htContextMenu .ht_master .htCore').find('tbody td').text()).toEqual('Enable my custom option');
  7366. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(0)').simulate('mousedown');
  7367. enabled = true;
  7368. contextMenu();
  7369. expect($('.htContextMenu .ht_master .htCore').find('tbody td').text()).toEqual('Disable my custom option');
  7370. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(0)').simulate('mousedown');
  7371. });
  7372. it('should enable to define item options globally', function () {
  7373. var callback = jasmine.createSpy('callback');
  7374. var hot = handsontable({
  7375. contextMenu: {
  7376. callback: callback,
  7377. items: {
  7378. cust1: {
  7379. name: 'CustomItem1'
  7380. },
  7381. cust2: {
  7382. name: 'CustomItem2'
  7383. }
  7384. }
  7385. },
  7386. height: 100
  7387. });
  7388. contextMenu();
  7389. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(0)').simulate('mousedown');
  7390. expect(callback.calls.count()).toEqual(1);
  7391. contextMenu();
  7392. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(1)').simulate('mousedown');
  7393. expect(callback.calls.count()).toEqual(2);
  7394. });
  7395. it('should override default items options', function () {
  7396. var callback = jasmine.createSpy('callback');
  7397. var hot = handsontable({
  7398. contextMenu: {
  7399. items: {
  7400. remove_row: {
  7401. callback: callback
  7402. },
  7403. remove_col: {
  7404. name: 'Delete column'
  7405. }
  7406. }
  7407. },
  7408. height: 100
  7409. });
  7410. contextMenu();
  7411. expect($('.htContextMenu .ht_master .htCore').find('tbody td').length).toEqual(2);
  7412. expect($('.htContextMenu .ht_master .htCore').find('tbody td').text()).toEqual(['Remove row', 'Delete column'].join(''));
  7413. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(0)').simulate('mousedown');
  7414. expect(callback.calls.count()).toEqual(1);
  7415. expect(countCols()).toEqual(5);
  7416. contextMenu();
  7417. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(1)').simulate('mousedown');
  7418. expect(countCols()).toEqual(4);
  7419. });
  7420. it('should fire item callback after item has been clicked', function () {
  7421. var customItem = {
  7422. name: 'Custom item',
  7423. callback: function callback() {}
  7424. };
  7425. spyOn(customItem, 'callback');
  7426. var hot = handsontable({
  7427. contextMenu: {
  7428. items: {
  7429. customItemKey: customItem
  7430. }
  7431. },
  7432. height: 100
  7433. });
  7434. contextMenu();
  7435. $('.htContextMenu .ht_master .htCore').find('tbody td:eq(0)').simulate('mousedown');
  7436. expect(customItem.callback.calls.count()).toEqual(1);
  7437. expect(customItem.callback.calls.argsFor(0)[0]).toEqual('customItemKey');
  7438. });
  7439. });
  7440. describe('keyboard navigation', function () {
  7441. describe('no item selected', function () {
  7442. it('should select the first item in menu, when user hits ARROW_DOWN', function () {
  7443. var hot = handsontable({
  7444. contextMenu: true,
  7445. height: 100
  7446. });
  7447. contextMenu();
  7448. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7449. expect(menuHot.getSelected()).toBeUndefined();
  7450. keyDownUp('arrow_down');
  7451. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7452. });
  7453. it('should scroll down, when user hits ARROW_DOWN for item in menu below the viewport', function () {
  7454. var hot = handsontable({
  7455. height: 100,
  7456. contextMenu: {
  7457. items: {
  7458. item1: {
  7459. name: 'Item1'
  7460. },
  7461. item2: {
  7462. name: 'Item2'
  7463. },
  7464. item3: {
  7465. name: 'Item3'
  7466. },
  7467. item4: {
  7468. name: 'Item4'
  7469. },
  7470. item5: {
  7471. name: 'Item5'
  7472. },
  7473. item6: {
  7474. name: 'Item6'
  7475. },
  7476. item7: {
  7477. name: 'Item7'
  7478. },
  7479. item8: {
  7480. name: 'Item8'
  7481. },
  7482. item9: {
  7483. name: 'Item9'
  7484. },
  7485. item10: {
  7486. name: 'Item10'
  7487. },
  7488. item11: {
  7489. name: 'Item11'
  7490. },
  7491. item12: {
  7492. name: 'Item12'
  7493. },
  7494. item13: {
  7495. name: 'Item13'
  7496. },
  7497. item14: {
  7498. name: 'Item14'
  7499. },
  7500. item15: {
  7501. name: 'Item15'
  7502. },
  7503. item16: {
  7504. name: 'Item16'
  7505. },
  7506. item17: {
  7507. name: 'Item17'
  7508. },
  7509. item18: {
  7510. name: 'Item18'
  7511. },
  7512. item19: {
  7513. name: 'Item19'
  7514. },
  7515. item20: {
  7516. name: 'Item20'
  7517. },
  7518. item21: {
  7519. name: 'Item21'
  7520. },
  7521. item22: {
  7522. name: 'Item22'
  7523. },
  7524. item23: {
  7525. name: 'Item23'
  7526. },
  7527. item24: {
  7528. name: 'Item24'
  7529. },
  7530. item25: {
  7531. name: 'Item25'
  7532. },
  7533. item26: {
  7534. name: 'Item26'
  7535. },
  7536. item27: {
  7537. name: 'Item27'
  7538. },
  7539. item28: {
  7540. name: 'Item28'
  7541. },
  7542. item29: {
  7543. name: 'Item29'
  7544. },
  7545. item30: {
  7546. name: 'Item30'
  7547. },
  7548. item31: {
  7549. name: 'Item31'
  7550. },
  7551. item32: {
  7552. name: 'Item32'
  7553. },
  7554. item33: {
  7555. name: 'Item33'
  7556. },
  7557. item34: {
  7558. name: 'Item34'
  7559. },
  7560. item35: {
  7561. name: 'Item35'
  7562. },
  7563. item36: {
  7564. name: 'Item36'
  7565. },
  7566. item37: {
  7567. name: 'Item37'
  7568. },
  7569. item38: {
  7570. name: 'Item38'
  7571. },
  7572. item39: {
  7573. name: 'Item39'
  7574. },
  7575. item40: {
  7576. name: 'Item40'
  7577. }
  7578. }
  7579. }
  7580. }),
  7581. scrollHeight;
  7582. contextMenu();
  7583. keyDownUp('arrow_down');
  7584. keyDownUp('arrow_down');
  7585. keyDownUp('arrow_down');
  7586. keyDownUp('arrow_down');
  7587. keyDownUp('arrow_down');
  7588. keyDownUp('arrow_down');
  7589. keyDownUp('arrow_down');
  7590. keyDownUp('arrow_down');
  7591. keyDownUp('arrow_down');
  7592. keyDownUp('arrow_down');
  7593. keyDownUp('arrow_down');
  7594. keyDownUp('arrow_down');
  7595. keyDownUp('arrow_down');
  7596. keyDownUp('arrow_down');
  7597. keyDownUp('arrow_down');
  7598. keyDownUp('arrow_down');
  7599. keyDownUp('arrow_down');
  7600. keyDownUp('arrow_down');
  7601. keyDownUp('arrow_down');
  7602. keyDownUp('arrow_down');
  7603. keyDownUp('arrow_down');
  7604. keyDownUp('arrow_down');
  7605. keyDownUp('arrow_down');
  7606. keyDownUp('arrow_down');
  7607. keyDownUp('arrow_down');
  7608. keyDownUp('arrow_down');
  7609. keyDownUp('arrow_down');
  7610. keyDownUp('arrow_down');
  7611. keyDownUp('arrow_down');
  7612. keyDownUp('arrow_down');
  7613. keyDownUp('arrow_down');
  7614. keyDownUp('arrow_down');
  7615. keyDownUp('arrow_down');
  7616. keyDownUp('arrow_down');
  7617. keyDownUp('arrow_down');
  7618. keyDownUp('arrow_down');
  7619. keyDownUp('arrow_down');
  7620. keyDownUp('arrow_down');
  7621. keyDownUp('arrow_down');
  7622. keyDownUp('arrow_down');
  7623. if (typeof window.scrollY !== 'undefined') {
  7624. scrollHeight = window.scrollY;
  7625. } else {
  7626. scrollHeight = document.documentElement.scrollTop;
  7627. }
  7628. expect(scrollHeight).not.toBe(0);
  7629. });
  7630. it('should select the first NOT DISABLED item in menu, when user hits ARROW_DOWN', function () {
  7631. var hot = handsontable({
  7632. contextMenu: {
  7633. items: {
  7634. item1: {
  7635. name: 'Item1',
  7636. disabled: true
  7637. },
  7638. item2: {
  7639. name: 'Item2',
  7640. disabled: true
  7641. },
  7642. item3: {
  7643. name: 'Item3'
  7644. }
  7645. }
  7646. },
  7647. height: 100
  7648. });
  7649. contextMenu();
  7650. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7651. expect(menuHot.getSelected()).toBeUndefined();
  7652. keyDownUp('arrow_down');
  7653. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7654. });
  7655. it('should NOT select any items in menu, when user hits ARROW_DOWN and there is no items enabled', function () {
  7656. var hot = handsontable({
  7657. contextMenu: {
  7658. items: {
  7659. item1: {
  7660. name: 'Item1',
  7661. disabled: true
  7662. },
  7663. item2: {
  7664. name: 'Item2',
  7665. disabled: true
  7666. },
  7667. item3: {
  7668. name: 'Item3',
  7669. disabled: true
  7670. }
  7671. }
  7672. },
  7673. height: 100
  7674. });
  7675. contextMenu();
  7676. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7677. expect(menuHot.getSelected()).toBeUndefined();
  7678. keyDownUp('arrow_down');
  7679. expect(menuHot.getSelected()).toBeUndefined();
  7680. });
  7681. it('should select the last item in menu, when user hits ARROW_UP', function () {
  7682. var hot = handsontable({
  7683. contextMenu: {
  7684. items: {
  7685. item1: 'Item1',
  7686. item2: 'Item2',
  7687. item3: 'Item3'
  7688. }
  7689. },
  7690. height: 100
  7691. });
  7692. contextMenu();
  7693. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7694. expect(menuHot.getSelected()).toBeUndefined();
  7695. keyDownUp('arrow_up');
  7696. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7697. });
  7698. it('should select the last NOT DISABLED item in menu, when user hits ARROW_UP', function () {
  7699. var hot = handsontable({
  7700. contextMenu: {
  7701. items: {
  7702. item1: {
  7703. name: 'Item1'
  7704. },
  7705. item2: {
  7706. name: 'Item2',
  7707. disabled: true
  7708. },
  7709. item3: {
  7710. name: 'Item3',
  7711. disabled: true
  7712. }
  7713. }
  7714. },
  7715. height: 100
  7716. });
  7717. contextMenu();
  7718. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7719. expect(menuHot.getSelected()).toBeUndefined();
  7720. keyDownUp('arrow_up');
  7721. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7722. });
  7723. it('should NOT select any items in menu, when user hits ARROW_UP and there is no items enabled', function () {
  7724. var hot = handsontable({
  7725. contextMenu: {
  7726. items: {
  7727. item1: {
  7728. name: 'Item1',
  7729. disabled: true
  7730. },
  7731. item2: {
  7732. name: 'Item2',
  7733. disabled: true
  7734. },
  7735. item3: {
  7736. name: 'Item3',
  7737. disabled: true
  7738. }
  7739. }
  7740. },
  7741. height: 100
  7742. });
  7743. contextMenu();
  7744. var id = $('.htContextMenu')[0].id;
  7745. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7746. expect(menuHot.getSelected()).toBeUndefined();
  7747. keyDownUp('arrow_up');
  7748. expect(menuHot.getSelected()).toBeUndefined();
  7749. });
  7750. });
  7751. describe('item selected', function () {
  7752. it('should select next item when user hits ARROW_DOWN', function () {
  7753. var hot = handsontable({
  7754. contextMenu: {
  7755. items: {
  7756. item1: {
  7757. name: 'Item1'
  7758. },
  7759. item2: {
  7760. name: 'Item2'
  7761. },
  7762. item3: {
  7763. name: 'Item3'
  7764. }
  7765. }
  7766. },
  7767. height: 100
  7768. });
  7769. contextMenu();
  7770. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7771. keyDownUp('arrow_down');
  7772. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7773. keyDownUp('arrow_down');
  7774. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  7775. keyDownUp('arrow_down');
  7776. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7777. });
  7778. it('should select next item (skipping disabled items) when user hits ARROW_DOWN', function () {
  7779. var hot = handsontable({
  7780. contextMenu: {
  7781. items: {
  7782. item1: {
  7783. name: 'Item1'
  7784. },
  7785. item2: {
  7786. name: 'Item2',
  7787. disabled: true
  7788. },
  7789. item3: {
  7790. name: 'Item3'
  7791. }
  7792. }
  7793. },
  7794. height: 100
  7795. });
  7796. contextMenu();
  7797. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7798. keyDownUp('arrow_down');
  7799. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7800. keyDownUp('arrow_down');
  7801. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7802. });
  7803. it('should select next item (skipping separators) when user hits ARROW_DOWN', function () {
  7804. var hot = handsontable({
  7805. contextMenu: {
  7806. items: {
  7807. item1: {
  7808. name: 'Item1'
  7809. },
  7810. sep1: Handsontable.plugins.ContextMenu.SEPARATOR,
  7811. item2: {
  7812. name: 'Item2'
  7813. },
  7814. item3: {
  7815. name: 'Item3'
  7816. }
  7817. }
  7818. },
  7819. height: 100
  7820. });
  7821. contextMenu();
  7822. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7823. keyDownUp('arrow_down');
  7824. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7825. keyDownUp('arrow_down');
  7826. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7827. keyDownUp('arrow_down');
  7828. expect(menuHot.getSelected()).toEqual([3, 0, 3, 0]);
  7829. });
  7830. it('should not change selection when last item is selected and user hits ARROW_DOWN', function () {
  7831. var hot = handsontable({
  7832. contextMenu: {
  7833. items: {
  7834. item1: {
  7835. name: 'Item1'
  7836. },
  7837. item2: {
  7838. name: 'Item2'
  7839. },
  7840. item3: {
  7841. name: 'Item3'
  7842. }
  7843. }
  7844. },
  7845. height: 100
  7846. });
  7847. contextMenu();
  7848. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7849. keyDownUp('arrow_down');
  7850. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7851. keyDownUp('arrow_down');
  7852. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  7853. keyDownUp('arrow_down');
  7854. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7855. keyDownUp('arrow_down');
  7856. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7857. });
  7858. it('should not change selection when last enabled item is selected and user hits ARROW_DOWN', function () {
  7859. var hot = handsontable({
  7860. contextMenu: {
  7861. items: {
  7862. item1: {
  7863. name: 'Item1'
  7864. },
  7865. item2: {
  7866. name: 'Item2'
  7867. },
  7868. item3: {
  7869. name: 'Item3',
  7870. disabled: true
  7871. }
  7872. }
  7873. },
  7874. height: 100
  7875. });
  7876. contextMenu();
  7877. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7878. keyDownUp('arrow_down');
  7879. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7880. keyDownUp('arrow_down');
  7881. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  7882. keyDownUp('arrow_down');
  7883. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  7884. });
  7885. it('should select next item when user hits ARROW_UP', function () {
  7886. var hot = handsontable({
  7887. contextMenu: {
  7888. items: {
  7889. item1: {
  7890. name: 'Item1'
  7891. },
  7892. item2: {
  7893. name: 'Item2'
  7894. },
  7895. item3: {
  7896. name: 'Item3'
  7897. }
  7898. }
  7899. },
  7900. height: 100
  7901. });
  7902. contextMenu();
  7903. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7904. keyDownUp('arrow_up');
  7905. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7906. keyDownUp('arrow_up');
  7907. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  7908. keyDownUp('arrow_up');
  7909. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7910. });
  7911. it('should select next item (skipping disabled items) when user hits ARROW_UP', function () {
  7912. var hot = handsontable({
  7913. contextMenu: {
  7914. items: {
  7915. item1: {
  7916. name: 'Item1'
  7917. },
  7918. item2: {
  7919. name: 'Item2',
  7920. disabled: true
  7921. },
  7922. item3: {
  7923. name: 'Item3'
  7924. }
  7925. }
  7926. },
  7927. height: 100
  7928. });
  7929. contextMenu();
  7930. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7931. keyDownUp('arrow_up');
  7932. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7933. keyDownUp('arrow_up');
  7934. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7935. });
  7936. it('should select next item (skipping separators) when user hits ARROW_UP', function () {
  7937. var hot = handsontable({
  7938. contextMenu: {
  7939. items: {
  7940. item1: {
  7941. name: 'Item1'
  7942. },
  7943. sep1: Handsontable.plugins.ContextMenu.SEPARATOR,
  7944. item2: {
  7945. name: 'Item2'
  7946. },
  7947. item3: {
  7948. name: 'Item3'
  7949. }
  7950. }
  7951. },
  7952. height: 100
  7953. });
  7954. contextMenu();
  7955. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7956. keyDownUp('arrow_up');
  7957. expect(menuHot.getSelected()).toEqual([3, 0, 3, 0]);
  7958. keyDownUp('arrow_up');
  7959. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7960. keyDownUp('arrow_up');
  7961. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7962. });
  7963. it('should not change selection when first item is selected and user hits ARROW_UP', function () {
  7964. var hot = handsontable({
  7965. contextMenu: {
  7966. items: {
  7967. item1: {
  7968. name: 'Item1'
  7969. },
  7970. item2: {
  7971. name: 'Item2'
  7972. },
  7973. item3: {
  7974. name: 'Item3'
  7975. }
  7976. }
  7977. },
  7978. height: 100
  7979. });
  7980. contextMenu();
  7981. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  7982. keyDownUp('arrow_up');
  7983. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  7984. keyDownUp('arrow_up');
  7985. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  7986. keyDownUp('arrow_up');
  7987. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7988. keyDownUp('arrow_up');
  7989. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  7990. });
  7991. it('should not change selection when first enabled item is selected and user hits ARROW_UP', function () {
  7992. var hot = handsontable({
  7993. contextMenu: {
  7994. items: {
  7995. item1: {
  7996. name: 'Item1',
  7997. disabled: true
  7998. },
  7999. item2: {
  8000. name: 'Item2'
  8001. },
  8002. item3: {
  8003. name: 'Item3'
  8004. }
  8005. }
  8006. },
  8007. height: 100
  8008. });
  8009. contextMenu();
  8010. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  8011. keyDownUp('arrow_up');
  8012. expect(menuHot.getSelected()).toEqual([2, 0, 2, 0]);
  8013. keyDownUp('arrow_up');
  8014. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  8015. keyDownUp('arrow_up');
  8016. expect(menuHot.getSelected()).toEqual([1, 0, 1, 0]);
  8017. });
  8018. it('should perform a selected item action, when user hits ENTER', function () {
  8019. var itemAction = jasmine.createSpy('itemAction');
  8020. var hot = handsontable({
  8021. contextMenu: {
  8022. items: {
  8023. item1: {
  8024. name: 'Item1',
  8025. callback: itemAction
  8026. },
  8027. item2: 'Item2'
  8028. }
  8029. },
  8030. height: 100
  8031. });
  8032. contextMenu();
  8033. var menuHot = hot.getPlugin('contextMenu').menu.hotMenu;
  8034. keyDownUp('arrow_down');
  8035. expect(menuHot.getSelected()).toEqual([0, 0, 0, 0]);
  8036. expect(itemAction).not.toHaveBeenCalled();
  8037. keyDownUp('enter');
  8038. expect(itemAction).toHaveBeenCalled();
  8039. expect($(hot.getPlugin('contextMenu').menu).is(':visible')).toBe(false);
  8040. });
  8041. });
  8042. it('should close menu when user hits ESC', function () {
  8043. handsontable({
  8044. contextMenu: true,
  8045. height: 100
  8046. });
  8047. contextMenu();
  8048. expect($('.htContextMenu').is(':visible')).toBe(true);
  8049. keyDownUp('esc');
  8050. expect($('.htContextMenu').is(':visible')).toBe(false);
  8051. });
  8052. it('should close sub-menu and parent menu in proper order when user hits ESC twice', function (done) {
  8053. handsontable({
  8054. contextMenu: true,
  8055. height: 100
  8056. });
  8057. contextMenu();
  8058. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(9);
  8059. var contextMenuRoot = $('.htContextMenu');
  8060. item.simulate('mouseover');
  8061. setTimeout(function () {
  8062. expect($('.htContextMenuSub_Alignment').is(':visible')).toBe(true);
  8063. keyDownUp('esc');
  8064. expect($('.htContextMenuSub_Alignment').is(':visible')).toBe(false);
  8065. keyDownUp('esc');
  8066. expect($('.htContextMenu').is(':visible')).toBe(false);
  8067. done();
  8068. }, 350); // waits for submenu open delay
  8069. });
  8070. });
  8071. describe('mouse navigation', function () {
  8072. it('should not scroll window position after fireing mouseenter on menu item', function () {
  8073. var hot = handsontable({
  8074. data: Handsontable.helper.createSpreadsheetData(1000, 5),
  8075. contextMenu: true
  8076. }),
  8077. scrollHeight;
  8078. hot.selectCell(100, 0);
  8079. contextMenu();
  8080. window.scrollTo(0, 0);
  8081. $('.htContextMenu .ht_master .htCore').find('tr td:eq("0")').simulate('mouseenter');
  8082. if (typeof window.scrollY !== 'undefined') {
  8083. scrollHeight = window.scrollY;
  8084. } else {
  8085. scrollHeight = document.documentElement.scrollTop;
  8086. }
  8087. expect(scrollHeight).toBe(0);
  8088. });
  8089. it('should not scroll window position after fireing click on menu', function () {
  8090. var hot = handsontable({
  8091. data: Handsontable.helper.createSpreadsheetData(1000, 5),
  8092. contextMenu: {
  8093. items: {
  8094. item1: {
  8095. name: 'Item1'
  8096. },
  8097. sep1: Handsontable.plugins.ContextMenu.SEPARATOR,
  8098. item2: {
  8099. name: 'Item2'
  8100. },
  8101. item3: {
  8102. name: 'Item3'
  8103. }
  8104. }
  8105. }
  8106. }),
  8107. scrollHeight;
  8108. hot.selectCell(100, 0);
  8109. contextMenu();
  8110. window.scrollTo(0, 0);
  8111. $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(0).simulate('mousedown');
  8112. if (typeof window.scrollY !== 'undefined') {
  8113. scrollHeight = window.scrollY;
  8114. } else {
  8115. scrollHeight = document.documentElement.scrollTop;
  8116. }
  8117. expect(scrollHeight).toBe(0);
  8118. });
  8119. });
  8120. describe('working with multiple tables', function () {
  8121. beforeEach(function () {
  8122. this.$container2 = $('<div id="' + id + '-2"></div>').appendTo('body');
  8123. });
  8124. afterEach(function () {
  8125. if (this.$container2) {
  8126. this.$container2.handsontable('destroy');
  8127. this.$container2.remove();
  8128. }
  8129. });
  8130. it('should apply enabling/disabling contextMenu using updateSetting only to particular instance of HOT ', function () {
  8131. var hot1 = handsontable({
  8132. contextMenu: false,
  8133. height: 100
  8134. });
  8135. var hot2 = this.$container2.handsontable({
  8136. contextMenu: true,
  8137. height: 100
  8138. });
  8139. hot2 = hot2.handsontable('getInstance');
  8140. var contextMenuContainer = $('.htContextMenu');
  8141. contextMenu();
  8142. expect(hot1.getPlugin('contextMenu').isEnabled()).toBe(false);
  8143. expect(contextMenuContainer.is(':visible')).toBe(false);
  8144. contextMenu2();
  8145. expect(hot2.getPlugin('contextMenu').isEnabled()).toBe(true);
  8146. expect($('.htContextMenu').is(':visible')).toBe(true);
  8147. mouseDown(hot2.rootElement); // close menu
  8148. hot1.updateSettings({
  8149. contextMenu: true
  8150. });
  8151. hot2.updateSettings({
  8152. contextMenu: false
  8153. });
  8154. contextMenu2();
  8155. expect(hot2.getPlugin('contextMenu').isEnabled()).toBe(false);
  8156. contextMenu();
  8157. expect($('.htContextMenu').is(':visible')).toBe(true);
  8158. function contextMenu2() {
  8159. var hot = spec().$container2.data('handsontable');
  8160. var selected = hot.getSelected();
  8161. if (!selected) {
  8162. hot.selectCell(0, 0);
  8163. selected = hot.getSelected();
  8164. }
  8165. var cell = hot.getCell(selected[0], selected[1]);
  8166. var cellOffset = $(cell).offset();
  8167. $(cell).simulate('contextmenu', {
  8168. pageX: cellOffset.left,
  8169. pageY: cellOffset.top
  8170. });
  8171. }
  8172. });
  8173. it('should perform a contextMenu action only for particular instance of HOT ', function () {
  8174. var hot1 = handsontable({
  8175. contextMenu: true,
  8176. height: 100
  8177. });
  8178. var hot2 = this.$container2.handsontable({
  8179. contextMenu: true,
  8180. height: 100
  8181. });
  8182. hot2 = hot2.handsontable('getInstance');
  8183. hot1.selectCell(0, 0);
  8184. contextMenu();
  8185. expect(hot1.countRows()).toEqual(5);
  8186. expect(hot2.countRows()).toEqual(5);
  8187. $('.htContextMenu .ht_master .htCore').find('tr td:eq("0")').simulate('mousedown'); // insert row above
  8188. expect(hot1.countRows()).toEqual(6);
  8189. expect(hot2.countRows()).toEqual(5);
  8190. hot2.selectCell(0, 0);
  8191. contextMenu2();
  8192. expect(hot1.countRows()).toEqual(6);
  8193. expect(hot2.countRows()).toEqual(5);
  8194. $('.htContextMenu .ht_master .htCore').find('tr td:eq("0")').simulate('mousedown'); // insert row above
  8195. expect(hot1.countRows()).toEqual(6);
  8196. expect(hot2.countRows()).toEqual(6);
  8197. function contextMenu2() {
  8198. var hot = spec().$container2.data('handsontable');
  8199. var selected = hot.getSelected();
  8200. if (!selected) {
  8201. hot.selectCell(0, 0);
  8202. selected = hot.getSelected();
  8203. }
  8204. var cell = hot.getCell(selected[0], selected[1]);
  8205. var cellOffset = $(cell).offset();
  8206. $(cell).simulate('contextmenu', {
  8207. pageX: cellOffset.left,
  8208. pageY: cellOffset.top
  8209. });
  8210. }
  8211. });
  8212. });
  8213. describe('context menu with native scroll', function () {
  8214. beforeEach(function () {
  8215. var wrapper = $('<div></div>').css({
  8216. width: 400,
  8217. height: 200,
  8218. overflow: 'scroll'
  8219. });
  8220. this.$wrapper = this.$container.wrap(wrapper).parent();
  8221. });
  8222. afterEach(function () {
  8223. if (this.$container) {
  8224. destroy();
  8225. this.$container.remove();
  8226. }
  8227. this.$wrapper.remove();
  8228. });
  8229. it('should display menu table is not scrolled', function () {
  8230. var hot = handsontable({
  8231. data: Handsontable.helper.createSpreadsheetData(40, 30),
  8232. colWidths: 50, // can also be a number or a function
  8233. rowHeaders: true,
  8234. colHeaders: true,
  8235. contextMenu: true,
  8236. height: 100
  8237. });
  8238. contextMenu();
  8239. expect($('.htContextMenu').is(':visible')).toBe(true);
  8240. });
  8241. it('should display menu table is scrolled', function () {
  8242. var hot = handsontable({
  8243. data: Handsontable.helper.createSpreadsheetData(40, 30),
  8244. colWidths: 50, // can also be a number or a function
  8245. rowHeaders: true,
  8246. colHeaders: true,
  8247. contextMenu: true,
  8248. height: 100
  8249. });
  8250. var mainHolder = hot.view.wt.wtTable.holder;
  8251. $(mainHolder).scrollTop(300);
  8252. $(mainHolder).scroll();
  8253. selectCell(15, 3);
  8254. contextMenu();
  8255. expect($('.htContextMenu').is(':visible')).toBe(true);
  8256. });
  8257. it('should not close the menu, when table is scrolled', function () {
  8258. var hot = handsontable({
  8259. data: Handsontable.helper.createSpreadsheetData(40, 30),
  8260. colWidths: 50, // can also be a number or a function
  8261. rowHeaders: true,
  8262. colHeaders: true,
  8263. contextMenu: true,
  8264. height: 100
  8265. });
  8266. var $mainHolder = $(hot.view.wt.wtTable.holder);
  8267. selectCell(15, 3);
  8268. var scrollTop = $mainHolder.scrollTop();
  8269. contextMenu();
  8270. expect($('.htContextMenu').is(':visible')).toBe(true);
  8271. $mainHolder.scrollTop(scrollTop + 60).scroll();
  8272. expect($('.htContextMenu').is(':visible')).toBe(true);
  8273. contextMenu();
  8274. expect($('.htContextMenu').is(':visible')).toBe(true);
  8275. $mainHolder.scrollTop(scrollTop + 100).scroll();
  8276. expect($('.htContextMenu').is(':visible')).toBe(true);
  8277. });
  8278. it('should not attempt to close menu, when table is scrolled and the menu is already closed', function () {
  8279. var hot = handsontable({
  8280. data: Handsontable.helper.createSpreadsheetData(40, 30),
  8281. colWidths: 50, // can also be a number or a function
  8282. rowHeaders: true,
  8283. colHeaders: true,
  8284. contextMenu: true,
  8285. height: 100
  8286. });
  8287. var mainHolder = $(hot.view.wt.wtTable.holder);
  8288. selectCell(15, 3);
  8289. var scrollTop = mainHolder.scrollTop();
  8290. contextMenu();
  8291. var $menu = $('.htContextMenu');
  8292. spyOn(hot.getPlugin('contextMenu'), 'close');
  8293. mainHolder.scrollTop(scrollTop + 100).scroll();
  8294. expect(hot.getPlugin('contextMenu').close).not.toHaveBeenCalled();
  8295. });
  8296. it('should not scroll the window when hovering over context menu items (#1897 reopen)', function () {
  8297. this.$wrapper.css('overflow', 'visible');
  8298. var hot = handsontable({
  8299. data: Handsontable.helper.createSpreadsheetData(403, 303),
  8300. colWidths: 50, // can also be a number or a function
  8301. contextMenu: true
  8302. });
  8303. var beginningScrollX = window.scrollX;
  8304. selectCell(2, 4);
  8305. contextMenu();
  8306. var cmInstance = hot.getPlugin('contextMenu').menu.hotMenu;
  8307. cmInstance.selectCell(3, 0);
  8308. expect(window.scrollX).toEqual(beginningScrollX);
  8309. cmInstance.selectCell(4, 0);
  8310. expect(window.scrollX).toEqual(beginningScrollX);
  8311. cmInstance.selectCell(6, 0);
  8312. expect(window.scrollX).toEqual(beginningScrollX);
  8313. });
  8314. });
  8315. describe('afterContextMenuDefaultOptions hook', function () {
  8316. it('should call afterContextMenuDefaultOptions hook with context menu options as the first param', function () {
  8317. var options;
  8318. var afterContextMenuDefaultOptions = function afterContextMenuDefaultOptions(options_) {
  8319. options = options_;
  8320. options.items.cust1 = {
  8321. name: 'My custom item',
  8322. callback: function callback() {}
  8323. };
  8324. };
  8325. Handsontable.hooks.add('afterContextMenuDefaultOptions', afterContextMenuDefaultOptions);
  8326. var hot = handsontable({
  8327. contextMenu: true,
  8328. height: 100
  8329. });
  8330. contextMenu();
  8331. var $menu = $('.htContextMenu .ht_master .htCore');
  8332. expect(options).toBeDefined();
  8333. expect(options.items).toBeDefined();
  8334. expect($menu.find('tbody td').text()).toContain('My custom item');
  8335. $menu.find('tbody td:eq(0)').simulate('mousedown');
  8336. Handsontable.hooks.remove('afterContextMenuDefaultOptions', afterContextMenuDefaultOptions);
  8337. });
  8338. });
  8339. describe('beforeContextMenuSetItems hook', function () {
  8340. it('should add new menu item even when item is excluded from plugin settings', function () {
  8341. Handsontable.hooks.add('beforeContextMenuSetItems', function (options) {
  8342. if (this === hot || !hot) {
  8343. options.push({
  8344. key: 'test',
  8345. name: 'Test'
  8346. });
  8347. }
  8348. });
  8349. var hot = handsontable({
  8350. contextMenu: ['make_read_only'],
  8351. height: 100
  8352. });
  8353. contextMenu();
  8354. var items = $('.htContextMenu tbody td');
  8355. var actions = items.not('.htSeparator');
  8356. expect(actions.text()).toEqual(['Read only', 'Test'].join(''));
  8357. });
  8358. it('should be called only with items selected in plugin settings', function () {
  8359. var keys = [];
  8360. Handsontable.hooks.add('beforeContextMenuSetItems', function (items) {
  8361. if (this === hot || !hot) {
  8362. keys = items.map(function (v) {
  8363. return v.key;
  8364. });
  8365. }
  8366. });
  8367. var hot = handsontable({
  8368. contextMenu: ['make_read_only', 'col_left'],
  8369. height: 100
  8370. });
  8371. contextMenu();
  8372. expect(keys).toEqual(['make_read_only', 'col_left']);
  8373. });
  8374. });
  8375. });
  8376. /***/ }),
  8377. /* 132 */
  8378. /***/ (function(module, exports, __webpack_require__) {
  8379. "use strict";
  8380. describe('ContextMenuReadOnly', function () {
  8381. var id = 'testContainer';
  8382. beforeEach(function () {
  8383. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  8384. });
  8385. afterEach(function () {
  8386. if (this.$container) {
  8387. destroy();
  8388. this.$container.remove();
  8389. }
  8390. });
  8391. it('should trigger `afterSetCellMeta` callback after changing cell to read only by context menu', function () {
  8392. var afterSetCellMetaCallback = jasmine.createSpy('afterSetCellMetaCallback');
  8393. var rows = 5,
  8394. columns = 5;
  8395. handsontable({
  8396. data: Handsontable.helper.createSpreadsheetData(rows, columns),
  8397. rowHeaders: true,
  8398. colHeaders: true,
  8399. contextMenu: true,
  8400. afterSetCellMeta: afterSetCellMetaCallback
  8401. });
  8402. selectCell(2, 3);
  8403. contextMenu();
  8404. var changeToReadOnluButton = $('.htItemWrapper').filter(function () {
  8405. return $(this).text() === 'Read only';
  8406. })[0];
  8407. $(changeToReadOnluButton).simulate('mousedown');
  8408. expect(afterSetCellMetaCallback).toHaveBeenCalledWith(2, 3, 'readOnly', true, undefined, undefined);
  8409. });
  8410. });
  8411. /***/ }),
  8412. /* 133 */
  8413. /***/ (function(module, exports, __webpack_require__) {
  8414. "use strict";
  8415. describe('ContextMenuCopyPaste', function () {
  8416. var id = 'testContainer';
  8417. if (typeof navigator.mimeTypes['application/x-shockwave-flash'] === 'undefined') {
  8418. navigator.mimeTypes['application/x-shockwave-flash'] = {}; // mock Adobe Flash plugin so that contextMenuCopyPaste.js does not throw an error in PhantomJS
  8419. }
  8420. beforeEach(function () {
  8421. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  8422. var wrapper = $('<div></div>').css({
  8423. width: 400,
  8424. height: 200,
  8425. overflow: 'scroll'
  8426. });
  8427. this.$wrapper = this.$container.wrap(wrapper).parent();
  8428. });
  8429. afterEach(function () {
  8430. if (this.$container) {
  8431. destroy();
  8432. this.$container.remove();
  8433. }
  8434. this.$wrapper.remove();
  8435. $('head').find('script[src*=ZeroClipboard]').remove();
  8436. delete window.ZeroClipboard;
  8437. });
  8438. it('should add Copy and Paste context menu options at the beginning by default', function () {
  8439. var hot = handsontable({
  8440. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  8441. rowHeaders: true,
  8442. colHeaders: true,
  8443. minSpareRows: 1,
  8444. contextMenu: true,
  8445. contextMenuCopyPaste: {
  8446. swfPath: '../../demo/swf/ZeroClipboard.swf'
  8447. }
  8448. });
  8449. selectCell(1, 1);
  8450. contextMenu();
  8451. var $contextMenuEntries = $('.htContextMenu .ht_master .htCore tbody').find('td');
  8452. var $copyButton = $contextMenuEntries.find('div').filter(function () {
  8453. return (/Copy/i.test($(this).text())
  8454. );
  8455. }).parents('td');
  8456. var $pasteButton = $contextMenuEntries.find('div').filter(function () {
  8457. return (/Paste/i.test($(this).text())
  8458. );
  8459. }).parents('td');
  8460. expect($contextMenuEntries.index($copyButton)).toEqual(0);
  8461. expect($contextMenuEntries.index($pasteButton)).toEqual(1);
  8462. });
  8463. it('should add Copy and Paste context menu options at the provided index', function () {
  8464. var hot = handsontable({
  8465. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  8466. rowHeaders: true,
  8467. colHeaders: true,
  8468. minSpareRows: 1,
  8469. contextMenu: ['row_above', 'copy', 'paste', 'row_below'],
  8470. contextMenuCopyPaste: {
  8471. swfPath: '../../demo/swf/ZeroClipboard.swf'
  8472. }
  8473. });
  8474. selectCell(1, 1);
  8475. contextMenu();
  8476. var $contextMenuEntries = $('.htContextMenu .ht_master .htCore tbody').find('td');
  8477. var $copyButton = $contextMenuEntries.find('div').filter(function () {
  8478. return (/Copy/i.test($(this).text())
  8479. );
  8480. }).parents('td');
  8481. var $pasteButton = $contextMenuEntries.find('div').filter(function () {
  8482. return (/Paste/i.test($(this).text())
  8483. );
  8484. }).parents('td');
  8485. expect($contextMenuEntries.not('[class*=htSeparator]').index($copyButton)).toEqual(1);
  8486. expect($contextMenuEntries.not('[class*=htSeparator]').index($pasteButton)).toEqual(2);
  8487. });
  8488. it('should disable `Copy` and `Paste` items when context menu was triggered from corner header', function () {
  8489. var hot = handsontable({
  8490. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  8491. rowHeaders: true,
  8492. colHeaders: true,
  8493. minSpareRows: 1,
  8494. contextMenu: true,
  8495. contextMenuCopyPaste: {
  8496. swfPath: '../../demo/swf/ZeroClipboard.swf'
  8497. }
  8498. });
  8499. $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0).simulate('mousedown', { which: 3 });
  8500. contextMenu();
  8501. expect($('.htContextMenu tbody td.htDisabled').text()).toBe(['Copy', 'Paste', 'Insert column on the left', 'Insert column on the right', 'Remove row', 'Remove column', 'Undo', 'Redo', 'Read only', 'Alignment'].join(''));
  8502. });
  8503. // see https://github.com/handsontable/handsontable/issues/3140
  8504. it('should not throwing error when ContextMenu plugin is disabled', function () {
  8505. var spy = jasmine.createSpy();
  8506. var prevError = window.onerror;
  8507. window.onerror = function () {
  8508. spy();
  8509. };
  8510. var hot = handsontable({
  8511. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  8512. rowHeaders: true,
  8513. colHeaders: true,
  8514. minSpareRows: 1,
  8515. contextMenu: true,
  8516. contextMenuCopyPaste: {
  8517. swfPath: '../../demo/swf/ZeroClipboard.swf'
  8518. }
  8519. });
  8520. hot.getPlugin('contextMenu').disablePlugin();
  8521. $(getCell(0, 0)).simulate('mouseenter');
  8522. expect(spy).not.toHaveBeenCalled();
  8523. window.onerror = prevError;
  8524. });
  8525. });
  8526. /***/ }),
  8527. /* 134 */
  8528. /***/ (function(module, exports, __webpack_require__) {
  8529. "use strict";
  8530. describe('CopyPaste', function () {
  8531. var id = 'testContainer';
  8532. beforeEach(function () {
  8533. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  8534. });
  8535. afterEach(function () {
  8536. if (this.$container) {
  8537. destroy();
  8538. this.$container.remove();
  8539. }
  8540. });
  8541. it('should remove additional new line from copied text (only safari)', function () {
  8542. var getData = jasmine.createSpy().and.returnValue('a\nb\n\n');
  8543. var preventDefault = jasmine.createSpy();
  8544. var hot = handsontable();
  8545. $('.copyPaste')[0].onpaste({ clipboardData: { getData: getData },
  8546. preventDefault: preventDefault
  8547. });
  8548. if (Handsontable.helper.isSafari()) {
  8549. expect($('.copyPaste')[0].value).toEqual('a\nb\n');
  8550. expect(getData).toHaveBeenCalledWith('Text');
  8551. expect(preventDefault).toHaveBeenCalled();
  8552. } else if (Handsontable.helper.isChrome()) {
  8553. expect($('.copyPaste')[0].value).toBe('a\nb\n\n');
  8554. expect(getData).toHaveBeenCalledWith('Text');
  8555. expect(preventDefault).toHaveBeenCalled();
  8556. }
  8557. });
  8558. it('should allow blocking cutting cells by stopping the immediate propagation', function (done) {
  8559. var onCut = jasmine.createSpy();
  8560. var hot = handsontable({
  8561. data: [['2012', 10, 11, 12, 13, 15, 16], ['2013', 10, 11, 12, 13, 15, 16]],
  8562. beforeKeyDown: function beforeKeyDown(event) {
  8563. if (event.ctrlKey && event.keyCode === Handsontable.helper.KEY_CODES.X) {
  8564. event.isImmediatePropagationEnabled = false;
  8565. }
  8566. }
  8567. });
  8568. hot.copyPaste.copyPasteInstance.cutCallbacks.push(onCut);
  8569. selectCell(0, 0);
  8570. keyDown('ctrl+x');
  8571. setTimeout(function () {
  8572. expect(onCut).not.toHaveBeenCalled();
  8573. done();
  8574. }, 100);
  8575. });
  8576. describe('enabling/disabing plugin', function () {
  8577. it('should enable copyPaste by default', function () {
  8578. var hot = handsontable();
  8579. expect(hot.copyPaste).toBeDefined();
  8580. });
  8581. it('should create copyPaste div if enabled', function () {
  8582. expect($('#CopyPasteDiv').length).toEqual(0);
  8583. var hot = handsontable();
  8584. selectCell(0, 0);
  8585. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT); // copyPaste div isn't created until you click CTRL
  8586. expect($('#CopyPasteDiv').length).toEqual(1);
  8587. });
  8588. it('should not create copyPaste div if disabled', function () {
  8589. expect($('#CopyPasteDiv').length).toEqual(0);
  8590. var hot = handsontable({
  8591. copyPaste: false
  8592. });
  8593. selectCell(0, 0);
  8594. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT);
  8595. expect($('#CopyPasteDiv').length).toEqual(0);
  8596. });
  8597. it('should not create copyPaste property if plugin is disabled', function () {
  8598. var hot = handsontable({
  8599. copyPaste: false
  8600. });
  8601. expect(hot.copyPaste).toBeUndefined();
  8602. });
  8603. it('should enable/disable plugin using updateSettings', function () {
  8604. var hot = handsontable();
  8605. expect(hot.copyPaste).toBeDefined();
  8606. updateSettings({
  8607. copyPaste: false
  8608. });
  8609. expect(hot.copyPaste).toBe(null);
  8610. });
  8611. it('should remove copyPaste div if plugin has been disabled using updateSetting', function () {
  8612. expect($('#CopyPasteDiv').length).toEqual(0);
  8613. var hot = handsontable();
  8614. selectCell(0, 0);
  8615. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT);
  8616. expect($('#CopyPasteDiv').length).toEqual(1);
  8617. updateSettings({
  8618. copyPaste: false
  8619. });
  8620. expect($('#CopyPasteDiv').length).toEqual(0);
  8621. selectCell(0, 0);
  8622. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT);
  8623. expect($('#CopyPasteDiv').length).toEqual(0);
  8624. });
  8625. });
  8626. describe('setting values copyable', function () {
  8627. it('should set copyable text when selecting a single cell and hitting ctrl', function () {
  8628. handsontable({
  8629. data: Handsontable.helper.createSpreadsheetData(2, 2)
  8630. });
  8631. var copyPasteTextarea = $('textarea.copyPaste');
  8632. expect(copyPasteTextarea.val().length).toEqual(0);
  8633. selectCell(0, 0);
  8634. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT);
  8635. expect(copyPasteTextarea.val()).toEqual('A1');
  8636. });
  8637. it('should set copyable text when selecting a single cell and hitting left command', function () {
  8638. handsontable({
  8639. data: Handsontable.helper.createSpreadsheetData(2, 2)
  8640. });
  8641. var copyPasteTextarea = $('textarea.copyPaste');
  8642. expect(copyPasteTextarea.val().length).toEqual(0);
  8643. selectCell(0, 0);
  8644. keyDownUp(Handsontable.helper.KEY_CODES.COMMAND_LEFT);
  8645. expect(copyPasteTextarea.val()).toEqual('A1');
  8646. });
  8647. it('should set copyable text when selecting a single cell and hitting right command', function () {
  8648. handsontable({
  8649. data: Handsontable.helper.createSpreadsheetData(2, 2)
  8650. });
  8651. var copyPasteTextarea = $('textarea.copyPaste');
  8652. expect(copyPasteTextarea.val().length).toEqual(0);
  8653. selectCell(0, 0);
  8654. keyDownUp(Handsontable.helper.KEY_CODES.COMMAND_RIGHT);
  8655. expect(copyPasteTextarea.val()).toEqual('A1');
  8656. });
  8657. it('should set copyable text when selecting multiple cells and hitting ctrl', function () {
  8658. handsontable({
  8659. data: Handsontable.helper.createSpreadsheetData(2, 2)
  8660. });
  8661. var copyPasteTextarea = $('textarea.copyPaste');
  8662. expect(copyPasteTextarea.val().length).toEqual(0);
  8663. selectCell(0, 0, 1, 0);
  8664. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT);
  8665. expect(copyPasteTextarea.val()).toEqual('A1\nA2');
  8666. });
  8667. it('should set copyable text when selecting all cells with CTRL+A', function (done) {
  8668. handsontable({
  8669. data: Handsontable.helper.createSpreadsheetData(2, 2)
  8670. });
  8671. var copyPasteTextarea = $('textarea.copyPaste');
  8672. expect(copyPasteTextarea.val().length).toEqual(0);
  8673. selectCell(0, 0);
  8674. $(document.activeElement).simulate('keydown', { keyCode: Handsontable.helper.KEY_CODES.A, ctrlKey: true });
  8675. setTimeout(function () {
  8676. expect(getSelected()).toEqual([0, 0, 1, 1]);
  8677. expect(copyPasteTextarea.val()).toEqual('A1\tB1\nA2\tB2');
  8678. done();
  8679. }, 10);
  8680. });
  8681. it('should not throw error when no cell is selected (#1221)', function () {
  8682. handsontable({
  8683. data: Handsontable.helper.createSpreadsheetData(2, 2)
  8684. });
  8685. selectCell(0, 0);
  8686. deselectCell();
  8687. function keydownCtrl() {
  8688. $(document).simulate('keydown', {
  8689. keyCode: Handsontable.helper.KEY_CODES.COMMAND_LEFT
  8690. });
  8691. }
  8692. // expect no to throw any exception
  8693. expect(keydownCtrl).not.toThrow();
  8694. });
  8695. it('should set copyable text when selecting a single cell with specified type and hitting ctrl (#1300)', function () {
  8696. handsontable({
  8697. data: [['A', 1], ['B', 2]],
  8698. columns: [{
  8699. type: 'text'
  8700. }, {
  8701. type: 'numeric'
  8702. }]
  8703. });
  8704. var copyPasteTextarea = $('textarea.copyPaste');
  8705. expect(copyPasteTextarea.val().length).toEqual(0);
  8706. selectCell(0, 0, 1, 1);
  8707. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT);
  8708. expect(copyPasteTextarea.val()).toEqual('A\t1\nB\t2');
  8709. });
  8710. it('should set copyable text when selecting a single cell with editor type as false (#2574)', function () {
  8711. handsontable({
  8712. data: [['A', 1], ['B', 2]],
  8713. columns: [{
  8714. type: 'text'
  8715. }, {
  8716. editor: false
  8717. }]
  8718. });
  8719. var copyPasteTextarea = $('textarea.copyPaste');
  8720. expect(copyPasteTextarea.val().length).toEqual(0);
  8721. selectCell(1, 1, 1, 1);
  8722. keyDownUp(Handsontable.helper.KEY_CODES.CONTROL_LEFT);
  8723. expect(copyPasteTextarea.val()).toEqual('2');
  8724. });
  8725. describe('working with multiple tables', function () {
  8726. beforeEach(function () {
  8727. this.$container2 = $('<div id="' + id + '2"></div>').appendTo('body');
  8728. });
  8729. afterEach(function () {
  8730. if (this.$container2) {
  8731. this.$container2.handsontable('destroy');
  8732. this.$container2.remove();
  8733. }
  8734. });
  8735. it('should disable copyPaste only in particular table', function () {
  8736. var hot1 = handsontable();
  8737. var hot2 = this.$container2.handsontable({
  8738. copyPaste: false
  8739. });
  8740. expect(hot1.copyPaste).toBeDefined();
  8741. expect(hot2.copyPaste).toBeUndefined();
  8742. });
  8743. it('should create only one CopyPasteDiv regardless of the number of tables', function () {
  8744. var hot1 = handsontable();
  8745. var hot2 = this.$container2.handsontable();
  8746. expect($('#CopyPasteDiv').length).toEqual(1);
  8747. });
  8748. it('should leave CopyPasteDiv as long as at least one table has copyPaste enabled', function () {
  8749. var hot1 = handsontable();
  8750. var hot2 = this.$container2.handsontable().handsontable('getInstance');
  8751. expect($('#CopyPasteDiv').length).toEqual(1);
  8752. hot1.updateSettings({
  8753. copyPaste: false
  8754. });
  8755. expect($('#CopyPasteDiv').length).toEqual(1);
  8756. hot2.updateSettings({
  8757. copyPaste: false
  8758. });
  8759. expect($('#CopyPasteDiv').length).toEqual(0);
  8760. });
  8761. });
  8762. });
  8763. describe('hooks', function () {
  8764. it('should call beforeCut and afterCut during cutting out operation', function () {
  8765. var beforeCutSpy = jasmine.createSpy('beforeCut');
  8766. var afterCutSpy = jasmine.createSpy('afterCut');
  8767. var hot = handsontable({
  8768. data: Handsontable.helper.createSpreadsheetData(2, 2),
  8769. beforeCut: beforeCutSpy,
  8770. afterCut: afterCutSpy
  8771. });
  8772. selectCell(0, 0);
  8773. keyDown('ctrl');
  8774. keyDown('ctrl+x');
  8775. expect(beforeCutSpy.calls.count()).toEqual(1);
  8776. expect(beforeCutSpy).toHaveBeenCalledWith([['A1']], [{ startRow: 0, startCol: 0, endRow: 0, endCol: 0 }], void 0, void 0, void 0, void 0);
  8777. expect(afterCutSpy.calls.count()).toEqual(1);
  8778. expect(afterCutSpy).toHaveBeenCalledWith([['A1']], [{ startRow: 0, startCol: 0, endRow: 0, endCol: 0 }], void 0, void 0, void 0, void 0);
  8779. });
  8780. it('should call beforeCopy and afterCopy during copying operation', function () {
  8781. var beforeCopySpy = jasmine.createSpy('beforeCopy');
  8782. var afterCopySpy = jasmine.createSpy('afterCopy');
  8783. var hot = handsontable({
  8784. data: Handsontable.helper.createSpreadsheetData(2, 2),
  8785. beforeCopy: beforeCopySpy,
  8786. afterCopy: afterCopySpy
  8787. });
  8788. selectCell(0, 0);
  8789. keyDown('ctrl');
  8790. keyDown('ctrl+c');
  8791. expect(beforeCopySpy.calls.count()).toEqual(1);
  8792. expect(beforeCopySpy).toHaveBeenCalledWith([['A1']], [{ startRow: 0, startCol: 0, endRow: 0, endCol: 0 }], void 0, void 0, void 0, void 0);
  8793. expect(afterCopySpy.calls.count()).toEqual(1);
  8794. expect(afterCopySpy).toHaveBeenCalledWith([['A1']], [{ startRow: 0, startCol: 0, endRow: 0, endCol: 0 }], void 0, void 0, void 0, void 0);
  8795. });
  8796. it('should call beforePaste and afterPaste during copying operation', function (done) {
  8797. var beforePasteSpy = jasmine.createSpy('beforePaste');
  8798. var afterPasteSpy = jasmine.createSpy('afterPaste');
  8799. var hot = handsontable({
  8800. data: Handsontable.helper.createSpreadsheetData(2, 2),
  8801. beforePaste: beforePasteSpy,
  8802. afterPaste: afterPasteSpy
  8803. });
  8804. selectCell(0, 0);
  8805. keyDown('ctrl');
  8806. hot.copyPaste.triggerPaste(null, 'Kia');
  8807. setTimeout(function () {
  8808. expect(beforePasteSpy.calls.count()).toEqual(1);
  8809. expect(beforePasteSpy).toHaveBeenCalledWith([['Kia']], [{ startRow: 0, startCol: 0, endRow: 0, endCol: 0 }], void 0, void 0, void 0, void 0);
  8810. expect(afterPasteSpy.calls.count()).toEqual(1);
  8811. expect(afterPasteSpy).toHaveBeenCalledWith([['Kia']], [{ startRow: 0, startCol: 0, endRow: 0, endCol: 0 }], void 0, void 0, void 0, void 0);
  8812. done();
  8813. }, 60);
  8814. });
  8815. it('should be possible to block cutting out', function () {
  8816. var afterCutSpy = jasmine.createSpy('afterCut');
  8817. var hot = handsontable({
  8818. data: Handsontable.helper.createSpreadsheetData(2, 2),
  8819. beforeCut: function beforeCut() {
  8820. return false;
  8821. },
  8822. afterCut: afterCutSpy
  8823. });
  8824. selectCell(0, 0);
  8825. keyDown('ctrl');
  8826. keyDown('ctrl+x');
  8827. expect(afterCutSpy.calls.count()).toEqual(0);
  8828. });
  8829. it('should be possible to block copying', function () {
  8830. var afterCopySpy = jasmine.createSpy('afterCopy');
  8831. var hot = handsontable({
  8832. data: Handsontable.helper.createSpreadsheetData(2, 2),
  8833. beforeCopy: function beforeCopy() {
  8834. return false;
  8835. },
  8836. afterCopy: afterCopySpy
  8837. });
  8838. selectCell(0, 0);
  8839. keyDown('ctrl');
  8840. keyDown('ctrl+c');
  8841. expect(afterCopySpy.calls.count()).toEqual(0);
  8842. });
  8843. it('should be possible to block pasting', function (done) {
  8844. var afterPasteSpy = jasmine.createSpy('afterPaste');
  8845. var hot = handsontable({
  8846. data: Handsontable.helper.createSpreadsheetData(2, 2),
  8847. beforePaste: function beforePaste() {
  8848. return false;
  8849. },
  8850. afterPaste: afterPasteSpy
  8851. });
  8852. selectCell(0, 0);
  8853. keyDown('ctrl');
  8854. hot.copyPaste.triggerPaste(null, 'Kia');
  8855. setTimeout(function () {
  8856. expect(afterPasteSpy.calls.count()).toEqual(0);
  8857. done();
  8858. }, 60);
  8859. });
  8860. });
  8861. });
  8862. /***/ }),
  8863. /* 135 */
  8864. /***/ (function(module, exports, __webpack_require__) {
  8865. "use strict";
  8866. describe('CustomBorders', function () {
  8867. var id = 'testContainer';
  8868. beforeEach(function () {
  8869. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  8870. var wrapper = $('<div></div>').css({
  8871. width: 400,
  8872. height: 200,
  8873. overflow: 'scroll'
  8874. });
  8875. this.$wrapper = this.$container.wrap(wrapper).parent();
  8876. });
  8877. afterEach(function () {
  8878. if (this.$container) {
  8879. destroy();
  8880. this.$container.remove();
  8881. }
  8882. this.$wrapper.remove();
  8883. });
  8884. it('should draw custom borders for single td', function () {
  8885. handsontable({
  8886. data: Handsontable.helper.createSpreadsheetData(7, 7),
  8887. colHeaders: true,
  8888. rowHeaders: true,
  8889. customBorders: [{
  8890. row: 2,
  8891. col: 2,
  8892. left: {
  8893. width: 2,
  8894. color: 'red'
  8895. },
  8896. right: {
  8897. width: 1,
  8898. color: 'green'
  8899. }
  8900. }]
  8901. });
  8902. // [top,left, bottom, right]
  8903. var borders = $('.wtBorder.border_row2col2');
  8904. expect(borders.length).toEqual(20); // 4 times 5 elements (top,right, bottom, left, corner)
  8905. expect(borders[0].className).toContain('hidden'); // hidden top
  8906. expect(borders[1].style.backgroundColor).toEqual('red'); // left red
  8907. expect(borders[1].style.width).toEqual('2px'); // left 2px width
  8908. expect(borders[2].className).toContain('hidden'); // hidden bottom
  8909. expect(borders[3].style.backgroundColor).toEqual('green'); // green right
  8910. expect(borders[3].style.width).toEqual('1px'); // right 1px width
  8911. });
  8912. it('should draw custom borders for range', function () {
  8913. handsontable({
  8914. data: Handsontable.helper.createSpreadsheetData(7, 7),
  8915. colHeaders: true,
  8916. rowHeaders: true,
  8917. customBorders: [{
  8918. range: {
  8919. from: {
  8920. row: 1,
  8921. col: 1
  8922. },
  8923. to: {
  8924. row: 3,
  8925. col: 4
  8926. }
  8927. },
  8928. top: {
  8929. width: 2,
  8930. color: 'black'
  8931. },
  8932. left: {
  8933. width: 2,
  8934. color: 'red'
  8935. },
  8936. bottom: {
  8937. width: 2,
  8938. color: 'red'
  8939. },
  8940. right: {
  8941. width: 3,
  8942. color: 'black'
  8943. }
  8944. }]
  8945. });
  8946. for (var row = 1; row <= 3; row++) {
  8947. for (var column = 1; column <= 4; column++) {
  8948. if (row == 1) {
  8949. var topRow = $('.wtBorder.border_row' + row + 'col' + column);
  8950. expect(topRow.length).toEqual(20); // borders for all tables (main and hiders)
  8951. expect(topRow[0].style.backgroundColor).toEqual('black');
  8952. expect(topRow[0].style.height).toEqual('2px');
  8953. }
  8954. if (column == 1) {
  8955. var leftColumn = $('.wtBorder.border_row' + row + 'col' + column);
  8956. expect(leftColumn.length).toEqual(20); // borders for all tables (main and hiders)
  8957. expect(leftColumn[1].style.backgroundColor).toEqual('red');
  8958. expect(leftColumn[1].style.width).toEqual('2px');
  8959. }
  8960. if (row == 3) {
  8961. var bottomRow = $('.wtBorder.border_row' + row + 'col' + column);
  8962. expect(bottomRow.length).toEqual(20); // borders for all tables (main and hiders)
  8963. expect(bottomRow[2].style.backgroundColor).toEqual('red');
  8964. expect(bottomRow[2].style.height).toEqual('2px');
  8965. }
  8966. if (column == 4) {
  8967. var rightColumn = $('.wtBorder.border_row' + row + 'col' + column);
  8968. expect(rightColumn.length).toEqual(20); // borders for all tables (main and hiders)
  8969. expect(rightColumn[3].style.backgroundColor).toEqual('black');
  8970. expect(rightColumn[3].style.width).toEqual('3px');
  8971. }
  8972. }
  8973. }
  8974. });
  8975. it('should draw top border from context menu options', function (done) {
  8976. var hot = handsontable({
  8977. data: Handsontable.helper.createSpreadsheetData(4, 4),
  8978. contextMenu: true,
  8979. customBorders: true
  8980. });
  8981. var defaultBorder = {
  8982. color: '#000',
  8983. width: 1
  8984. },
  8985. empty = {
  8986. hide: true
  8987. };
  8988. contextMenu();
  8989. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(10);
  8990. item.simulate('mouseover');
  8991. setTimeout(function () {
  8992. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  8993. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(0);
  8994. button.simulate('mousedown');
  8995. // expect(getCellMeta(0,0).borders.hasOwnProperty('top')).toBe(true);
  8996. expect(getCellMeta(0, 0).borders.top).toEqual(defaultBorder);
  8997. expect(getCellMeta(0, 0).borders.left).toEqual(empty);
  8998. expect(getCellMeta(0, 0).borders.bottom).toEqual(empty);
  8999. expect(getCellMeta(0, 0).borders.right).toEqual(empty);
  9000. done();
  9001. }, 350);
  9002. });
  9003. it('should draw left border from context menu options', function (done) {
  9004. var hot = handsontable({
  9005. data: Handsontable.helper.createSpreadsheetData(4, 4),
  9006. contextMenu: true,
  9007. customBorders: true
  9008. });
  9009. var defaultBorder = {
  9010. color: '#000',
  9011. width: 1
  9012. },
  9013. empty = {
  9014. hide: true
  9015. };
  9016. contextMenu();
  9017. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(10);
  9018. item.simulate('mouseover');
  9019. setTimeout(function () {
  9020. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  9021. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(3);
  9022. button.simulate('mousedown');
  9023. /* eslint-disable no-prototype-builtins */
  9024. expect(getCellMeta(0, 0).borders.hasOwnProperty('left')).toBe(true);
  9025. expect(getCellMeta(0, 0).borders.top).toEqual(empty);
  9026. expect(getCellMeta(0, 0).borders.left).toEqual(defaultBorder);
  9027. expect(getCellMeta(0, 0).borders.bottom).toEqual(empty);
  9028. expect(getCellMeta(0, 0).borders.right).toEqual(empty);
  9029. done();
  9030. }, 350);
  9031. });
  9032. it('should draw right border from context menu options', function (done) {
  9033. var hot = handsontable({
  9034. data: Handsontable.helper.createSpreadsheetData(4, 4),
  9035. contextMenu: true,
  9036. customBorders: true
  9037. });
  9038. var defaultBorder = {
  9039. color: '#000',
  9040. width: 1
  9041. },
  9042. empty = {
  9043. hide: true
  9044. };
  9045. contextMenu();
  9046. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(10);
  9047. item.simulate('mouseover');
  9048. setTimeout(function () {
  9049. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  9050. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(1);
  9051. button.simulate('mousedown');
  9052. /* eslint-disable no-prototype-builtins */
  9053. expect(getCellMeta(0, 0).borders.hasOwnProperty('right')).toBe(true);
  9054. expect(getCellMeta(0, 0).borders.top).toEqual(empty);
  9055. expect(getCellMeta(0, 0).borders.left).toEqual(empty);
  9056. expect(getCellMeta(0, 0).borders.bottom).toEqual(empty);
  9057. expect(getCellMeta(0, 0).borders.right).toEqual(defaultBorder);
  9058. done();
  9059. }, 350);
  9060. });
  9061. it('should draw bottom border from context menu options', function (done) {
  9062. var hot = handsontable({
  9063. data: Handsontable.helper.createSpreadsheetData(4, 4),
  9064. contextMenu: true,
  9065. customBorders: true
  9066. });
  9067. var defaultBorder = {
  9068. color: '#000',
  9069. width: 1
  9070. },
  9071. empty = {
  9072. hide: true
  9073. };
  9074. contextMenu();
  9075. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(10);
  9076. item.simulate('mouseover');
  9077. setTimeout(function () {
  9078. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  9079. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(2);
  9080. button.simulate('mousedown');
  9081. /* eslint-disable no-prototype-builtins */
  9082. expect(getCellMeta(0, 0).borders.hasOwnProperty('right')).toBe(true);
  9083. expect(getCellMeta(0, 0).borders.top).toEqual(empty);
  9084. expect(getCellMeta(0, 0).borders.left).toEqual(empty);
  9085. expect(getCellMeta(0, 0).borders.bottom).toEqual(defaultBorder);
  9086. expect(getCellMeta(0, 0).borders.right).toEqual(empty);
  9087. done();
  9088. }, 350);
  9089. });
  9090. it('should remove all bottoms border from context menu options', function (done) {
  9091. var hot = handsontable({
  9092. data: Handsontable.helper.createSpreadsheetData(4, 4),
  9093. contextMenu: true,
  9094. customBorders: [{
  9095. row: 0,
  9096. col: 0,
  9097. left: {
  9098. width: 2,
  9099. color: 'red'
  9100. },
  9101. right: {
  9102. width: 1,
  9103. color: 'green'
  9104. }
  9105. }]
  9106. });
  9107. contextMenu();
  9108. var item = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator').eq(10);
  9109. item.simulate('mouseover');
  9110. setTimeout(function () {
  9111. var contextSubMenu = $('.htContextMenuSub_' + item.text());
  9112. var button = contextSubMenu.find('.ht_master .htCore tbody td').not('.htSeparator').eq(4);
  9113. button.simulate('mousedown');
  9114. expect(getCellMeta(0, 0).borders).toBeUndefined();
  9115. done();
  9116. }, 350);
  9117. });
  9118. it('should disable `Borders` context menu item when menu was triggered from corner header', function () {
  9119. var hot = handsontable({
  9120. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  9121. rowHeaders: true,
  9122. colHeaders: true,
  9123. contextMenu: true,
  9124. customBorders: true
  9125. });
  9126. $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0).simulate('mousedown', { which: 3 });
  9127. contextMenu();
  9128. expect($('.htContextMenu tbody td.htDisabled').text()).toBe(['Insert column on the left', 'Insert column on the right', 'Remove row', 'Remove column', 'Undo', 'Redo', 'Read only', 'Alignment', 'Borders'].join(''));
  9129. });
  9130. });
  9131. /***/ }),
  9132. /* 136 */
  9133. /***/ (function(module, exports, __webpack_require__) {
  9134. "use strict";
  9135. describe('DragToScroll', function () {
  9136. function createBoundaries() {
  9137. return {
  9138. top: 100,
  9139. left: 100,
  9140. width: 900,
  9141. height: 900,
  9142. bottom: 1000,
  9143. right: 1000
  9144. };
  9145. }
  9146. var dragToScroll = new Handsontable.plugins.DragToScroll();
  9147. dragToScroll.setBoundaries(createBoundaries());
  9148. it('exact top, exact left should be in boundaries', function () {
  9149. dragToScroll.setCallback(function (scrollX, scrollY) {
  9150. expect(scrollX).toEqual(0);
  9151. expect(scrollY).toEqual(0);
  9152. });
  9153. dragToScroll.check(100, 100);
  9154. });
  9155. it('exact bottom, exact right should be in boundaries', function () {
  9156. dragToScroll.setCallback(function (scrollX, scrollY) {
  9157. expect(scrollX).toEqual(0);
  9158. expect(scrollY).toEqual(0);
  9159. });
  9160. dragToScroll.check(1000, 1000);
  9161. });
  9162. it('less than top, less than left should be out in "top" direction', function () {
  9163. dragToScroll.setCallback(function (scrollX, scrollY) {
  9164. expect(scrollX).toEqual(-1);
  9165. expect(scrollY).toEqual(-1);
  9166. });
  9167. dragToScroll.check(99, 99);
  9168. });
  9169. it('exact top, less than left should be out in "left" direction', function () {
  9170. dragToScroll.setCallback(function (scrollX, scrollY) {
  9171. expect(scrollX).toEqual(-1);
  9172. expect(scrollY).toEqual(0);
  9173. });
  9174. dragToScroll.check(99, 100);
  9175. });
  9176. it('less than top, more than right should be out in "top" direction', function () {
  9177. dragToScroll.setCallback(function (scrollX, scrollY) {
  9178. expect(scrollX).toEqual(1);
  9179. expect(scrollY).toEqual(-1);
  9180. });
  9181. dragToScroll.check(1001, 99);
  9182. });
  9183. it('more than bottom, more than right should be out in "bottom" direction', function () {
  9184. dragToScroll.setCallback(function (scrollX, scrollY) {
  9185. expect(scrollX).toEqual(1);
  9186. expect(scrollY).toEqual(1);
  9187. });
  9188. dragToScroll.check(1001, 1001);
  9189. });
  9190. it('exact bottom, more than right should be out in "right" direction', function () {
  9191. dragToScroll.setCallback(function (scrollX, scrollY) {
  9192. expect(scrollX).toEqual(1);
  9193. expect(scrollY).toEqual(0);
  9194. });
  9195. dragToScroll.check(1001, 1000);
  9196. });
  9197. it('more than bottom, less than left should be out in "bottom" direction', function () {
  9198. dragToScroll.setCallback(function (scrollX, scrollY) {
  9199. expect(scrollX).toEqual(-1);
  9200. expect(scrollY).toEqual(1);
  9201. });
  9202. dragToScroll.check(99, 1001);
  9203. });
  9204. });
  9205. /***/ }),
  9206. /* 137 */
  9207. /***/ (function(module, exports, __webpack_require__) {
  9208. "use strict";
  9209. describe('manualColumnFreeze', function () {
  9210. var id = 'testContainer';
  9211. beforeEach(function () {
  9212. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  9213. });
  9214. afterEach(function () {
  9215. if (this.$container) {
  9216. destroy();
  9217. this.$container.remove();
  9218. }
  9219. });
  9220. describe('freezeColumn', function () {
  9221. it('should increase fixedColumnsLeft setting', function () {
  9222. var hot = handsontable({
  9223. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9224. manualColumnFreeze: true
  9225. });
  9226. var plugin = hot.getPlugin('manualColumnFreeze');
  9227. plugin.freezeColumn(4);
  9228. expect(hot.getSettings().fixedColumnsLeft).toEqual(1);
  9229. });
  9230. it('should freeze (make fixed) the column provided as an argument', function () {
  9231. var hot = handsontable({
  9232. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9233. manualColumnFreeze: true
  9234. });
  9235. var plugin = hot.getPlugin('manualColumnFreeze');
  9236. var movePlugin = hot.getPlugin('manualColumnMove');
  9237. plugin.freezeColumn(5);
  9238. expect(movePlugin.columnsMapper.getValueByIndex(0)).toEqual(5);
  9239. });
  9240. });
  9241. describe('unfreezeColumn', function () {
  9242. it('should decrease fixedColumnsLeft setting', function () {
  9243. var hot = handsontable({
  9244. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9245. manualColumnFreeze: true,
  9246. fixedColumnsLeft: 1
  9247. });
  9248. var plugin = hot.getPlugin('manualColumnFreeze');
  9249. plugin.unfreezeColumn(0);
  9250. expect(hot.getSettings().fixedColumnsLeft).toEqual(0);
  9251. });
  9252. it('should unfreeze (make non-fixed) the column provided as an argument', function () {
  9253. var hot = handsontable({
  9254. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9255. manualColumnFreeze: true,
  9256. fixedColumnsLeft: 3
  9257. });
  9258. var plugin = hot.getPlugin('manualColumnFreeze');
  9259. var movePlugin = hot.getPlugin('manualColumnMove');
  9260. plugin.unfreezeColumn(0);
  9261. expect(hot.getSettings().fixedColumnsLeft).toEqual(2);
  9262. expect(movePlugin.columnsMapper.getValueByIndex(0)).toEqual(1);
  9263. expect(movePlugin.columnsMapper.getValueByIndex(1)).toEqual(2);
  9264. expect(movePlugin.columnsMapper.getValueByIndex(2)).toEqual(0);
  9265. });
  9266. });
  9267. describe('functionality', function () {
  9268. it('should add a \'freeze this column\' context menu entry for non-fixed columns', function () {
  9269. var hot = handsontable({
  9270. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9271. manualColumnFreeze: true,
  9272. contextMenu: true
  9273. });
  9274. selectCell(1, 1);
  9275. contextMenu();
  9276. var freezeEntry = $(hot.getPlugin('contextMenu').menu.container).find('div').filter(function () {
  9277. return $(this).text() === 'Freeze this column';
  9278. });
  9279. expect(freezeEntry.size()).toEqual(1);
  9280. });
  9281. it('should add a \'unfreeze this column\' context menu entry for fixed columns', function () {
  9282. var hot = handsontable({
  9283. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9284. manualColumnFreeze: true,
  9285. contextMenu: true,
  9286. fixedColumnsLeft: 2
  9287. });
  9288. selectCell(1, 1);
  9289. contextMenu();
  9290. var freezeEntry = $(hot.getPlugin('contextMenu').menu.container).find('div').filter(function () {
  9291. return $(this).text() === 'Unfreeze this column';
  9292. });
  9293. expect(freezeEntry.size()).toEqual(1);
  9294. });
  9295. it('should fix the desired column after clicking the \'freeze this column\' context menu entry', function () {
  9296. var hot = handsontable({
  9297. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9298. manualColumnFreeze: true,
  9299. fixedColumnsLeft: 1,
  9300. contextMenu: true
  9301. });
  9302. selectCell(1, 3);
  9303. var dataAtCell = hot.getDataAtCell(1, 3);
  9304. contextMenu();
  9305. var freezeEntry = $(hot.getPlugin('contextMenu').menu.container).find('div').filter(function () {
  9306. if ($(this).text() === 'Freeze this column') {
  9307. return true;
  9308. }
  9309. return false;
  9310. });
  9311. expect(freezeEntry.size()).toEqual(1);
  9312. freezeEntry.eq(0).simulate('mousedown');
  9313. expect(hot.getSettings().fixedColumnsLeft).toEqual(2);
  9314. expect(hot.getDataAtCell(1, 1)).toEqual(dataAtCell);
  9315. });
  9316. it('should unfix the desired column (and revert it to it\'s original position) after clicking the \'unfreeze this column\' context menu entry', function () {
  9317. var hot = handsontable({
  9318. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9319. manualColumnFreeze: true,
  9320. fixedColumnsLeft: 3,
  9321. manualColumnMove: [0, 2, 5, 3, 4, 1, 6, 7, 8, 9],
  9322. contextMenu: true,
  9323. rowHeaders: true
  9324. });
  9325. var dataAtCell = hot.getDataAtCell(1, 0);
  9326. expect(dataAtCell).toEqual('A2');
  9327. dataAtCell = hot.getDataAtCell(1, 1);
  9328. expect(dataAtCell).toEqual('C2');
  9329. dataAtCell = hot.getDataAtCell(1, 2);
  9330. expect(dataAtCell).toEqual('F2');
  9331. selectCell(1, 1);
  9332. contextMenu();
  9333. var freezeEntry = $(hot.getPlugin('contextMenu').menu.container).find('div').filter(function () {
  9334. return $(this).text() === 'Unfreeze this column';
  9335. });
  9336. freezeEntry.eq(0).simulate('mousedown');
  9337. expect(hot.getSettings().fixedColumnsLeft).toEqual(2);
  9338. dataAtCell = hot.getDataAtCell(1, 0);
  9339. expect(dataAtCell).toEqual('A2');
  9340. dataAtCell = hot.getDataAtCell(1, 1);
  9341. expect(dataAtCell).toEqual('F2');
  9342. dataAtCell = hot.getDataAtCell(1, 2);
  9343. expect(dataAtCell).toEqual('C2');
  9344. selectCell(1, 1);
  9345. contextMenu();
  9346. freezeEntry = $(hot.getPlugin('contextMenu').menu.container).find('div').filter(function () {
  9347. if ($(this).text() === 'Unfreeze this column') {
  9348. return true;
  9349. }
  9350. return false;
  9351. });
  9352. freezeEntry.eq(0).simulate('mousedown');
  9353. expect(hot.getSettings().fixedColumnsLeft).toEqual(1);
  9354. dataAtCell = hot.getDataAtCell(1, 0);
  9355. expect(dataAtCell).toEqual('A2');
  9356. dataAtCell = hot.getDataAtCell(1, 1);
  9357. expect(dataAtCell).toEqual('C2');
  9358. dataAtCell = hot.getDataAtCell(1, 2);
  9359. expect(dataAtCell).toEqual('D2');
  9360. dataAtCell = hot.getDataAtCell(1, 5);
  9361. expect(dataAtCell).toEqual('F2');
  9362. // Use the modified columns position.
  9363. hot.updateSettings({
  9364. fixedColumnsLeft: 0,
  9365. manualColumnMove: [0, 2, 5, 3, 4, 1, 6, 7, 8, 9]
  9366. });
  9367. hot.getSettings().fixedColumnsLeft = 0;
  9368. selectCell(1, 2);
  9369. contextMenu();
  9370. freezeEntry = $(hot.getPlugin('contextMenu').menu.container).find('div').filter(function () {
  9371. return $(this).text() === 'Freeze this column';
  9372. });
  9373. freezeEntry.eq(0).simulate('mousedown');
  9374. expect(hot.getSettings().fixedColumnsLeft).toEqual(1);
  9375. dataAtCell = hot.getDataAtCell(1, 0);
  9376. expect(dataAtCell).toEqual('F2');
  9377. selectCell(1, 0);
  9378. contextMenu();
  9379. freezeEntry = $(hot.getPlugin('contextMenu').menu.container).find('div').filter(function () {
  9380. return $(this).text() === 'Unfreeze this column';
  9381. });
  9382. freezeEntry.eq(0).simulate('mousedown');
  9383. expect(hot.getSettings().fixedColumnsLeft).toEqual(0);
  9384. dataAtCell = hot.getDataAtCell(1, 2);
  9385. expect(dataAtCell).toEqual('F2');
  9386. });
  9387. });
  9388. });
  9389. /***/ }),
  9390. /* 138 */
  9391. /***/ (function(module, exports, __webpack_require__) {
  9392. "use strict";
  9393. describe('manualColumnMove', function () {
  9394. var id = 'testContainer';
  9395. beforeEach(function () {
  9396. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  9397. });
  9398. afterEach(function () {
  9399. if (this.$container) {
  9400. destroy();
  9401. this.$container.remove();
  9402. }
  9403. });
  9404. describe('init', function () {
  9405. it('should change column order at init', function () {
  9406. handsontable({
  9407. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9408. manualColumnMove: [1, 2, 0]
  9409. });
  9410. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('B1');
  9411. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('C1');
  9412. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('A1');
  9413. });
  9414. });
  9415. describe('persistentState', function () {
  9416. it('should load data from cache after initialization of new Handsontable instance', function (done) {
  9417. var hot = handsontable({
  9418. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9419. manualColumnMove: true,
  9420. persistentState: true
  9421. });
  9422. var dataAt0x2Cell = getDataAtCell(0, 2);
  9423. var manualColumnMovePlugin = hot.getPlugin('manualColumnMove');
  9424. manualColumnMovePlugin.moveColumn(2, 0);
  9425. manualColumnMovePlugin.persistentStateSave();
  9426. hot.destroy();
  9427. this.$container.remove();
  9428. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  9429. handsontable({
  9430. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9431. manualColumnMove: true,
  9432. persistentState: true
  9433. });
  9434. expect(getDataAtCell(0, 0)).toEqual(dataAt0x2Cell);
  9435. done();
  9436. });
  9437. it('should work with updateSettings properly', function () {
  9438. var hot = handsontable({
  9439. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9440. manualColumnMove: true,
  9441. persistentState: true
  9442. });
  9443. var dataAt0x2Cell = getDataAtCell(0, 2);
  9444. var manualColumnMovePlugin = hot.getPlugin('manualColumnMove');
  9445. manualColumnMovePlugin.moveColumn(2, 0);
  9446. manualColumnMovePlugin.persistentStateSave();
  9447. updateSettings({});
  9448. expect(getDataAtCell(0, 0)).toEqual(dataAt0x2Cell);
  9449. });
  9450. });
  9451. describe('updateSettings', function () {
  9452. it('should be enabled after specifying it in updateSettings config', function () {
  9453. handsontable({
  9454. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9455. colHeaders: true
  9456. });
  9457. updateSettings({
  9458. manualColumnMove: true
  9459. });
  9460. this.$container.find('thead tr:eq(0) th:eq(0)').simulate('mousedown');
  9461. this.$container.find('thead tr:eq(0) th:eq(0)').simulate('mouseup');
  9462. expect(this.$container.hasClass('after-selection--columns')).toBeGreaterThan(0);
  9463. });
  9464. it('should change the default column order with updateSettings', function () {
  9465. handsontable({
  9466. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9467. manualColumnMove: true
  9468. });
  9469. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9470. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9471. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9472. updateSettings({
  9473. manualColumnMove: [2, 1, 0]
  9474. });
  9475. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('C1');
  9476. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9477. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('A1');
  9478. });
  9479. it('should change column order with updateSettings', function () {
  9480. handsontable({
  9481. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9482. manualColumnMove: [1, 2, 0]
  9483. });
  9484. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('B1');
  9485. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('C1');
  9486. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('A1');
  9487. updateSettings({
  9488. manualColumnMove: [2, 1, 0]
  9489. });
  9490. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('C1');
  9491. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9492. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('A1');
  9493. });
  9494. it('should update columnsMapper when updateSettings change numbers of columns', function () {
  9495. var hot = handsontable({
  9496. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9497. manualColumnMove: true
  9498. });
  9499. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9500. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9501. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9502. hot.getPlugin('manualColumnMove').moveColumn(2, 0);
  9503. updateSettings({
  9504. columns: [{ data: 2 }, { data: 0 }, { data: 1 }]
  9505. });
  9506. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('B1');
  9507. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('C1');
  9508. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('A1');
  9509. });
  9510. it('should reset column order with updateSettings when undefined is passed', function () {
  9511. handsontable({
  9512. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9513. manualColumnMove: [1, 2, 0]
  9514. });
  9515. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('B1');
  9516. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('C1');
  9517. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('A1');
  9518. updateSettings({
  9519. manualColumnMove: void 0
  9520. });
  9521. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9522. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9523. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9524. });
  9525. });
  9526. describe('loadData', function () {
  9527. it('should increase numbers of columns if it is necessary', function () {
  9528. var hot = handsontable({
  9529. data: Handsontable.helper.createSpreadsheetData(5, 5),
  9530. manualColumnMove: true
  9531. });
  9532. hot.loadData(Handsontable.helper.createSpreadsheetData(10, 10));
  9533. expect(countRows()).toEqual(10);
  9534. expect(hot.getPlugin('manualColumnMove').columnsMapper.__arrayMap.length).toEqual(10);
  9535. });
  9536. it('should decrease numbers of columns if it is necessary', function () {
  9537. var hot = handsontable({
  9538. data: Handsontable.helper.createSpreadsheetData(5, 5),
  9539. manualColumnMove: true
  9540. });
  9541. hot.loadData(Handsontable.helper.createSpreadsheetData(2, 2));
  9542. expect(countRows()).toEqual(2);
  9543. expect(hot.getPlugin('manualColumnMove').columnsMapper.__arrayMap.length).toEqual(2);
  9544. });
  9545. });
  9546. describe('moving', function () {
  9547. it('should move column by API', function () {
  9548. var hot = handsontable({
  9549. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9550. colHeaders: true,
  9551. manualColumnMove: true
  9552. });
  9553. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9554. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9555. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9556. hot.getPlugin('manualColumnMove').moveColumn(2, 0);
  9557. hot.render();
  9558. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('C1');
  9559. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A1');
  9560. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('B1');
  9561. });
  9562. it('should move many columns by API', function () {
  9563. var hot = handsontable({
  9564. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9565. colHeaders: true,
  9566. manualColumnMove: true
  9567. });
  9568. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9569. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9570. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9571. hot.getPlugin('manualColumnMove').moveColumns([7, 9, 8], 0);
  9572. hot.render();
  9573. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('H1');
  9574. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('J1');
  9575. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('I1');
  9576. });
  9577. it('should trigger an beforeColumnMove event before column move', function () {
  9578. var beforeMoveColumnCallback = jasmine.createSpy('beforeMoveColumnCallback');
  9579. var hot = handsontable({
  9580. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9581. colHeaders: true,
  9582. manualColumnMove: true,
  9583. beforeColumnMove: beforeMoveColumnCallback
  9584. });
  9585. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9586. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9587. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9588. hot.getPlugin('manualColumnMove').moveColumns([8, 9, 7], 0);
  9589. hot.render();
  9590. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('I1');
  9591. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('J1');
  9592. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('H1');
  9593. expect(beforeMoveColumnCallback).toHaveBeenCalledWith([8, 9, 7], 0, void 0, void 0, void 0, void 0);
  9594. });
  9595. it('should trigger an afterColumnMove event after column move', function () {
  9596. var afterMoveColumnCallback = jasmine.createSpy('afterMoveColumnCallback');
  9597. this.$container.height(150);
  9598. var hot = handsontable({
  9599. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9600. colHeaders: true,
  9601. manualColumnMove: true,
  9602. afterColumnMove: afterMoveColumnCallback
  9603. });
  9604. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9605. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9606. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9607. hot.getPlugin('manualColumnMove').moveColumns([8, 9, 7], 0);
  9608. hot.render();
  9609. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('I1');
  9610. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('J1');
  9611. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('H1');
  9612. expect(afterMoveColumnCallback).toHaveBeenCalledWith([8, 9, 7], 0, void 0, void 0, void 0, void 0);
  9613. });
  9614. it('should move the second column to the first column', function () {
  9615. var hot = handsontable({
  9616. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9617. colHeaders: true,
  9618. manualColumnMove: true
  9619. });
  9620. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9621. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9622. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9623. var $rowsHeaders = this.$container.find('.ht_clone_top tr th');
  9624. $rowsHeaders.eq(1).simulate('mousedown');
  9625. $rowsHeaders.eq(1).simulate('mouseup');
  9626. $rowsHeaders.eq(1).simulate('mousedown');
  9627. $rowsHeaders.eq(0).simulate('mouseover');
  9628. $rowsHeaders.eq(0).simulate('mousemove');
  9629. $rowsHeaders.eq(0).simulate('mouseup');
  9630. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('B1');
  9631. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A1');
  9632. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9633. });
  9634. it('should move the second row to the third row', function () {
  9635. handsontable({
  9636. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9637. colHeaders: true,
  9638. manualColumnMove: true
  9639. });
  9640. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9641. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('B1');
  9642. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('C1');
  9643. var $rowsHeaders = this.$container.find('.ht_clone_top tr th');
  9644. $rowsHeaders.eq(1).simulate('mousedown');
  9645. $rowsHeaders.eq(1).simulate('mouseup');
  9646. $rowsHeaders.eq(1).simulate('mousedown');
  9647. $rowsHeaders.eq(3).simulate('mouseover');
  9648. $rowsHeaders.eq(3).simulate('mousemove');
  9649. $rowsHeaders.eq(3).simulate('mouseup');
  9650. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  9651. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('C1');
  9652. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('B1');
  9653. });
  9654. it('should properly scrolling viewport if mouse is over part-visible cell', function (done) {
  9655. var hot = handsontable({
  9656. data: Handsontable.helper.createSpreadsheetData(10, 20),
  9657. colHeaders: true,
  9658. rowHeaders: true,
  9659. manualColumnMove: true,
  9660. width: 600,
  9661. height: 600,
  9662. colWidths: 47
  9663. });
  9664. hot.selectCell(0, 19);
  9665. setTimeout(function () {
  9666. expect(hot.view.wt.wtTable.getFirstVisibleColumn()).toBeGreaterThan(8);
  9667. var $rowsHeaders = spec().$container.find('.ht_clone_top tr th');
  9668. $rowsHeaders.eq(2).simulate('mousedown');
  9669. $rowsHeaders.eq(2).simulate('mouseup');
  9670. $rowsHeaders.eq(2).simulate('mousedown');
  9671. $rowsHeaders.eq(1).simulate('mouseover');
  9672. $rowsHeaders.eq(1).simulate('mousemove');
  9673. $rowsHeaders.eq(1).simulate('mouseup');
  9674. }, 50);
  9675. setTimeout(function () {
  9676. expect(hot.view.wt.wtTable.getFirstVisibleColumn()).toBeLessThan(9);
  9677. done();
  9678. }, 150);
  9679. });
  9680. it('moving column should keep cell meta created using cells function', function () {
  9681. var hot = handsontable({
  9682. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9683. colHeaders: true,
  9684. manualColumnMove: true,
  9685. cells: function cells(row, col) {
  9686. if (row == 1 && col == 0) {
  9687. this.readOnly = true;
  9688. }
  9689. }
  9690. });
  9691. var htCore = getHtCore();
  9692. expect(htCore.find('tbody tr:eq(1) td:eq(0)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  9693. hot.getPlugin('manualColumnMove').moveColumn(0, 3);
  9694. hot.render();
  9695. expect(htCore.find('tbody tr:eq(1) td:eq(2)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  9696. });
  9697. it('moving column should keep cell meta created using cell array', function () {
  9698. var hot = handsontable({
  9699. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9700. colHeaders: true,
  9701. manualColumnMove: true,
  9702. cell: [{ row: 1, col: 0, readOnly: true }]
  9703. });
  9704. var htCore = getHtCore();
  9705. expect(htCore.find('tbody tr:eq(1) td:eq(0)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  9706. hot.getPlugin('manualColumnMove').moveColumn(3, 0);
  9707. hot.render();
  9708. expect(htCore.find('tbody tr:eq(1) td:eq(1)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  9709. });
  9710. });
  9711. describe('copy-paste', function () {
  9712. it('should create new columns is are needed', function () {
  9713. var hot = handsontable({
  9714. data: Handsontable.helper.createSpreadsheetData(5, 5),
  9715. colHeaders: true,
  9716. manualColumnMove: true
  9717. });
  9718. var changesSet = [[3, 4, 'A1'], [3, 5, 'B1'], [3, 6, 'C1'], [3, 7, 'D1']];
  9719. // unfortunately couse of security rules, we can't simulate native mechanism (e.g. CTRL+C -> CTRL+V)
  9720. hot.setDataAtCell(changesSet, void 0, void 0, 'CopyPaste.paste');
  9721. expect(hot.countCols()).toEqual(8);
  9722. });
  9723. });
  9724. describe('undoRedo', function () {
  9725. xit('should back changes', function () {
  9726. var hot = handsontable({
  9727. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9728. colHeaders: true,
  9729. manualColumnMove: true
  9730. });
  9731. hot.getPlugin('manualColumnMove').moveColumn(1, 4);
  9732. hot.render();
  9733. expect(hot.getDataAtCell(1, 3)).toBe('B2');
  9734. hot.undo();
  9735. expect(hot.getDataAtCell(1, 3)).toBe('D2');
  9736. });
  9737. xit('should revert changes', function () {
  9738. var hot = handsontable({
  9739. data: Handsontable.helper.createSpreadsheetData(10, 10),
  9740. colHeaders: true,
  9741. manualColumnMove: true
  9742. });
  9743. hot.getPlugin('manualColumnMove').moveColumn(1, 4);
  9744. hot.render();
  9745. expect(hot.getDataAtCell(1, 3)).toBe('A2');
  9746. hot.undo();
  9747. expect(hot.getDataAtCell(1, 1)).toBe('A2');
  9748. hot.redo();
  9749. expect(hot.getDataAtCell(1, 3)).toBe('A2');
  9750. });
  9751. });
  9752. });
  9753. /***/ }),
  9754. /* 139 */
  9755. /***/ (function(module, exports, __webpack_require__) {
  9756. "use strict";
  9757. describe('manualColumnMove', function () {
  9758. var id = 'testContainer';
  9759. var arrayOfArrays = Handsontable.helper.createSpreadsheetData(30, 30);
  9760. beforeEach(function () {
  9761. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  9762. });
  9763. afterEach(function () {
  9764. if (this.$container) {
  9765. destroy();
  9766. this.$container.remove();
  9767. }
  9768. });
  9769. describe('UI', function () {
  9770. it('should append UI elements to wtHider after click on row header', function () {
  9771. var hot = handsontable({
  9772. data: arrayOfArrays.slice(),
  9773. colHeaders: true,
  9774. manualColumnMove: true
  9775. });
  9776. var $headerTH = this.$container.find('thead tr:eq(0) th:eq(0)');
  9777. $headerTH.simulate('mousedown');
  9778. $headerTH.simulate('mouseup');
  9779. $headerTH.simulate('mousedown');
  9780. expect(this.$container.find('.ht__manualColumnMove--guideline').length).toBe(1);
  9781. expect(this.$container.find('.ht__manualColumnMove--backlight').length).toBe(1);
  9782. });
  9783. it('should part of UI elements be visible on dragging action', function () {
  9784. var hot = handsontable({
  9785. data: arrayOfArrays.slice(),
  9786. colHeaders: true,
  9787. manualColumnMove: true
  9788. });
  9789. var $headerTH = this.$container.find('thead tr:eq(0) th:eq(0)');
  9790. $headerTH.simulate('mousedown');
  9791. $headerTH.simulate('mouseup');
  9792. $headerTH.simulate('mousedown');
  9793. expect(this.$container.find('.ht__manualColumnMove--guideline:visible').length).toBe(0);
  9794. expect(this.$container.find('.ht__manualColumnMove--backlight:visible').length).toBe(1);
  9795. });
  9796. it('should all of UI elements be visible on dragging action', function () {
  9797. var hot = handsontable({
  9798. data: arrayOfArrays.slice(),
  9799. colHeaders: true,
  9800. manualColumnMove: true
  9801. });
  9802. var $headers = [this.$container.find('thead tr:eq(0) th:eq(0)'), this.$container.find('thead tr:eq(0) th:eq(1)'), this.$container.find('thead tr:eq(0) th:eq(2)')];
  9803. $headers[0].simulate('mousedown');
  9804. $headers[0].simulate('mouseup');
  9805. $headers[0].simulate('mousedown');
  9806. $headers[1].simulate('mouseover');
  9807. $headers[2].simulate('mouseover');
  9808. expect(this.$container.find('.ht__manualColumnMove--guideline:visible').length).toBe(1);
  9809. expect(this.$container.find('.ht__manualColumnMove--backlight:visible').length).toBe(1);
  9810. });
  9811. it('should set properly width for the backlight element when stretchH is enabled', function () {
  9812. var hot = handsontable({
  9813. data: Handsontable.helper.createSpreadsheetData(30, 5),
  9814. width: 600,
  9815. colHeaders: true,
  9816. stretchH: 'all',
  9817. manualColumnMove: true
  9818. });
  9819. var $headerTH = this.$container.find('thead tr:eq(0) th:eq(1)');
  9820. $headerTH.simulate('mousedown');
  9821. $headerTH.simulate('mouseup');
  9822. $headerTH.simulate('mousedown');
  9823. expect(this.$container.find('.ht__manualColumnMove--backlight')[0].offsetWidth).toBe($headerTH[0].offsetWidth);
  9824. });
  9825. it('should set properly width for the backlight element when stretchH is enabled and column order was changed', function () {
  9826. var hot = handsontable({
  9827. data: [{ id: 1, flag: 'EUR', currencyCode: 'EUR', currency: 'Euro', level: 0.9033, units: 'EUR / USD', asOf: '08/19/2015', onedChng: 0.0026 }],
  9828. width: 600,
  9829. colHeaders: true,
  9830. stretchH: 'all',
  9831. manualColumnMove: [2, 4, 6, 3, 1, 0],
  9832. columns: [{ data: 'id', type: 'numeric', width: 40 }, { data: 'currencyCode', type: 'text' }, { data: 'currency', type: 'text' }, { data: 'level', type: 'numeric', format: '0.0000' }, { data: 'units', type: 'text' }, { data: 'asOf', type: 'date', dateFormat: 'MM/DD/YYYY' }, { data: 'onedChng', type: 'numeric', format: '0.00%' }]
  9833. });
  9834. var $headerTH = this.$container.find('thead tr:eq(0) th:eq(6)');
  9835. $headerTH.simulate('mousedown');
  9836. $headerTH.simulate('mouseup');
  9837. $headerTH.simulate('mousedown');
  9838. $headerTH.simulate('mouseup');
  9839. $headerTH.simulate('mousedown');
  9840. expect(this.$container.find('.ht__manualColumnMove--backlight')[0].offsetWidth).toBe($headerTH[0].offsetWidth);
  9841. });
  9842. it('should not run moving ui if mousedown was fired on sorting element', function () {
  9843. var hot = handsontable({
  9844. data: arrayOfArrays.slice(),
  9845. colHeaders: true,
  9846. manualColumnMove: true,
  9847. columnSorting: true
  9848. });
  9849. var $headerTH = this.$container.find('thead tr:eq(0) th:eq(6)');
  9850. var $summaryElement = $headerTH.find('.columnSorting');
  9851. $headerTH.simulate('mousedown');
  9852. $headerTH.simulate('mouseup');
  9853. $headerTH.simulate('mousedown');
  9854. $headerTH.simulate('mouseup');
  9855. var $backlight = this.$container.find('.ht__manualColumnMove--backlight')[0];
  9856. $summaryElement.simulate('mousedown');
  9857. var displayProp = $backlight.currentStyle ? $backlight.currentStyle.display : getComputedStyle($backlight, null).display;
  9858. expect(displayProp).toEqual('none');
  9859. });
  9860. });
  9861. });
  9862. /***/ }),
  9863. /* 140 */
  9864. /***/ (function(module, exports, __webpack_require__) {
  9865. "use strict";
  9866. describe('manualColumnResize', function () {
  9867. var id = 'testContainer';
  9868. beforeEach(function () {
  9869. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  9870. });
  9871. afterEach(function () {
  9872. if (this.$container) {
  9873. destroy();
  9874. this.$container.remove();
  9875. }
  9876. });
  9877. it('should change column widths at init', function () {
  9878. handsontable({
  9879. manualColumnResize: [100, 150, 180]
  9880. });
  9881. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(100);
  9882. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(150);
  9883. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(180);
  9884. });
  9885. it('should be enabled after specifying it in updateSettings config', function () {
  9886. var hot = handsontable({
  9887. data: [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }],
  9888. colHeaders: true
  9889. });
  9890. updateSettings({ manualColumnResize: true });
  9891. this.$container.find('thead tr:eq(0) th:eq(0)').simulate('mouseover');
  9892. expect($('.manualColumnResizer').size()).toBeGreaterThan(0);
  9893. });
  9894. it('should change the default column widths with updateSettings', function () {
  9895. handsontable({
  9896. manualColumnResize: true
  9897. });
  9898. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(50);
  9899. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(50);
  9900. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(50);
  9901. updateSettings({
  9902. manualColumnResize: [60, 50, 80]
  9903. });
  9904. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(60);
  9905. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(50);
  9906. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(80);
  9907. });
  9908. it('should change column widths with updateSettings', function () {
  9909. handsontable({
  9910. manualColumnResize: [100, 150, 180]
  9911. });
  9912. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(100);
  9913. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(150);
  9914. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(180);
  9915. updateSettings({
  9916. manualColumnResize: [60, 50, 80]
  9917. });
  9918. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(60);
  9919. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(50);
  9920. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(80);
  9921. });
  9922. it('should reset column widths when undefined is passed', function () {
  9923. handsontable({
  9924. manualColumnResize: [100, 150, 180]
  9925. });
  9926. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(100);
  9927. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(150);
  9928. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(180);
  9929. updateSettings({
  9930. manualColumnResize: void 0
  9931. });
  9932. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(50);
  9933. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(50);
  9934. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(50);
  9935. });
  9936. it('should not reset column widths when `true` is passed', function () {
  9937. handsontable({
  9938. manualColumnResize: [100, 150, 180]
  9939. });
  9940. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(100);
  9941. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(150);
  9942. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(180);
  9943. updateSettings({
  9944. manualColumnResize: true
  9945. });
  9946. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').outerWidth()).toBe(100);
  9947. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').outerWidth()).toBe(150);
  9948. expect(this.$container.find('tbody tr:eq(0) td:eq(2)').outerWidth()).toBe(180);
  9949. });
  9950. it('should resize (narrowing) appropriate columns, even when stretchH `all` is enabled', function () {
  9951. this.$container.css('width', '910px');
  9952. handsontable({
  9953. colHeaders: true,
  9954. manualColumnResize: true,
  9955. stretchH: 'all'
  9956. });
  9957. resizeColumn(1, 65);
  9958. var $columnHeaders = this.$container.find('thead tr:eq(1) th');
  9959. expect($columnHeaders.eq(0).width()).toBe(209);
  9960. expect($columnHeaders.eq(1).width()).toBe(64);
  9961. expect($columnHeaders.eq(2).width()).toBe(210);
  9962. expect($columnHeaders.eq(3).width()).toBe(210);
  9963. expect($columnHeaders.eq(4).width()).toBe(211);
  9964. });
  9965. it('should resize (extending) appropriate columns, even when stretchH `all` is enabled', function () {
  9966. this.$container.css('width', '910px');
  9967. handsontable({
  9968. colHeaders: true,
  9969. manualColumnResize: true,
  9970. stretchH: 'all'
  9971. });
  9972. resizeColumn(1, 400);
  9973. var $columnHeaders = this.$container.find('thead tr:eq(1) th');
  9974. expect($columnHeaders.eq(0).width()).toBe(125);
  9975. expect($columnHeaders.eq(1).width()).toBe(399);
  9976. expect($columnHeaders.eq(2).width()).toBe(126);
  9977. expect($columnHeaders.eq(3).width()).toBe(126);
  9978. expect($columnHeaders.eq(4).width()).toBe(128);
  9979. });
  9980. it('should resize (narrowing) selected columns', function (done) {
  9981. var hot = handsontable({
  9982. data: Handsontable.helper.createSpreadsheetData(10, 20),
  9983. colHeaders: true,
  9984. manualColumnResize: true
  9985. });
  9986. var $columnHeaders = this.$container.find('thead tr:eq(0) th');
  9987. var $colHeader = this.$container.find('thead tr:eq(0) th:eq(1)');
  9988. $colHeader.simulate('mouseover');
  9989. var $resizer = this.$container.find('.manualColumnResizer');
  9990. var resizerPosition = $resizer.position();
  9991. this.$container.find('tr:eq(0) th:eq(1)').simulate('mousedown');
  9992. this.$container.find('tr:eq(0) th:eq(2)').simulate('mouseover');
  9993. this.$container.find('tr:eq(0) th:eq(3)').simulate('mouseover');
  9994. this.$container.find('tr:eq(0) th:eq(3)').simulate('mousemove');
  9995. this.$container.find('tr:eq(0) th:eq(3)').simulate('mouseup');
  9996. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  9997. $resizer.simulate('mousemove', { clientX: this.$container.find('tr:eq(0) th:eq(1)').position().left + 29 });
  9998. $resizer.simulate('mouseup');
  9999. setTimeout(function () {
  10000. expect($columnHeaders.eq(1).width()).toBe(33);
  10001. expect($columnHeaders.eq(2).width()).toBe(34);
  10002. expect($columnHeaders.eq(3).width()).toBe(34);
  10003. done();
  10004. }, 1000);
  10005. });
  10006. it('should resize (expanding) selected columns', function (done) {
  10007. var hot = handsontable({
  10008. data: Handsontable.helper.createSpreadsheetData(10, 20),
  10009. colHeaders: true,
  10010. manualColumnResize: true
  10011. });
  10012. var $columnHeaders = this.$container.find('thead tr:eq(0) th');
  10013. var $colHeader = this.$container.find('thead tr:eq(0) th:eq(1)');
  10014. $colHeader.simulate('mouseover');
  10015. var $resizer = this.$container.find('.manualColumnResizer');
  10016. var resizerPosition = $resizer.position();
  10017. this.$container.find('tr:eq(0) th:eq(1)').simulate('mousedown');
  10018. this.$container.find('tr:eq(0) th:eq(2)').simulate('mouseover');
  10019. this.$container.find('tr:eq(0) th:eq(3)').simulate('mouseover');
  10020. this.$container.find('tr:eq(0) th:eq(3)').simulate('mousemove');
  10021. this.$container.find('tr:eq(0) th:eq(3)').simulate('mouseup');
  10022. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10023. $resizer.simulate('mousemove', { clientX: this.$container.find('tr:eq(0) th:eq(1)').position().left + 150 });
  10024. $resizer.simulate('mouseup');
  10025. setTimeout(function () {
  10026. expect($columnHeaders.eq(1).width()).toBe(154);
  10027. expect($columnHeaders.eq(2).width()).toBe(155);
  10028. expect($columnHeaders.eq(3).width()).toBe(155);
  10029. done();
  10030. }, 1000);
  10031. });
  10032. it('should resize appropriate columns to calculated stretch width after double click on column handler when stretchH is set as `all`', function (done) {
  10033. this.$container.css('width', '910px');
  10034. handsontable({
  10035. colHeaders: true,
  10036. manualColumnResize: true,
  10037. stretchH: 'all'
  10038. });
  10039. resizeColumn(1, 65);
  10040. var $columnHeaders = this.$container.find('thead tr:eq(1) th');
  10041. expect($columnHeaders.eq(0).width()).toBe(209);
  10042. expect($columnHeaders.eq(1).width()).toBe(64);
  10043. expect($columnHeaders.eq(2).width()).toBe(210);
  10044. expect($columnHeaders.eq(3).width()).toBe(210);
  10045. expect($columnHeaders.eq(4).width()).toBe(211);
  10046. var $th = $columnHeaders.eq(1);
  10047. $th.simulate('mouseover');
  10048. var $resizer = this.$container.find('.manualColumnResizer');
  10049. var resizerPosition = $resizer.position();
  10050. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10051. $resizer.simulate('mouseup');
  10052. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10053. $resizer.simulate('mouseup');
  10054. setTimeout(function () {
  10055. expect($columnHeaders.eq(0).width()).toBe(180);
  10056. expect($columnHeaders.eq(1).width()).toBe(181);
  10057. expect($columnHeaders.eq(2).width()).toBe(181);
  10058. expect($columnHeaders.eq(3).width()).toBe(181);
  10059. expect($columnHeaders.eq(4).width()).toBe(181);
  10060. done();
  10061. }, 1000);
  10062. });
  10063. it('should resize appropriate columns to calculated autoColumnSize width after double click on column handler when stretchH is set as `last`', function (done) {
  10064. this.$container.css('width', '910px');
  10065. handsontable({
  10066. colHeaders: true,
  10067. manualColumnResize: true,
  10068. stretchH: 'last'
  10069. });
  10070. resizeColumn(0, 65);
  10071. var $columnHeaders = this.$container.find('thead tr:eq(0) th');
  10072. expect($columnHeaders.eq(0).width()).toBe(63);
  10073. expect($columnHeaders.eq(1).width()).toBe(48);
  10074. expect($columnHeaders.eq(2).width()).toBe(49);
  10075. expect($columnHeaders.eq(3).width()).toBe(49);
  10076. expect($columnHeaders.eq(4).width()).toBe(694);
  10077. var $th = $columnHeaders.eq(0);
  10078. $th.simulate('mouseover');
  10079. var $resizer = this.$container.find('.manualColumnResizer');
  10080. var resizerPosition = $resizer.position();
  10081. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10082. $resizer.simulate('mouseup');
  10083. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10084. $resizer.simulate('mouseup');
  10085. setTimeout(function () {
  10086. expect($columnHeaders.eq(0).width()).toBeAroundValue(19);
  10087. expect($columnHeaders.eq(1).width()).toBe(48);
  10088. expect($columnHeaders.eq(2).width()).toBe(49);
  10089. expect($columnHeaders.eq(3).width()).toBe(49);
  10090. expect($columnHeaders.eq(4).width()).toBeAroundValue(738);
  10091. done();
  10092. }, 1000);
  10093. });
  10094. it('should resize appropriate columns, even if the column order was changed with manualColumnMove plugin', function () {
  10095. handsontable({
  10096. colHeaders: ['First', 'Second', 'Third'],
  10097. manualColumnMove: [2, 1, 0, 3],
  10098. manualColumnResize: true
  10099. });
  10100. var $columnHeaders = this.$container.find('thead tr:eq(0) th');
  10101. var initialColumnWidths = [];
  10102. $columnHeaders.each(function () {
  10103. initialColumnWidths.push($(this).width());
  10104. });
  10105. resizeColumn.call(this, 0, 100);
  10106. var $resizedTh = $columnHeaders.eq(0);
  10107. expect($resizedTh.text()).toEqual('Third');
  10108. expect($resizedTh.outerWidth()).toEqual(100);
  10109. // Sizes of remaining columns should stay the same
  10110. for (var i = 1; i < $columnHeaders.length; i++) {
  10111. expect($columnHeaders.eq(i).width()).toEqual(initialColumnWidths[i]);
  10112. }
  10113. });
  10114. it('should trigger an afterColumnResize event after column size changes', function () {
  10115. var afterColumnResizeCallback = jasmine.createSpy('afterColumnResizeCallback');
  10116. handsontable({
  10117. data: Handsontable.helper.createSpreadsheetData(3, 3),
  10118. colHeaders: true,
  10119. manualColumnResize: true,
  10120. afterColumnResize: afterColumnResizeCallback
  10121. });
  10122. expect(colWidth(this.$container, 0)).toEqual(50);
  10123. resizeColumn(0, 100);
  10124. expect(afterColumnResizeCallback).toHaveBeenCalledWith(0, 100, void 0, void 0, void 0, void 0);
  10125. expect(colWidth(this.$container, 0)).toEqual(100);
  10126. });
  10127. it('should not trigger an afterColumnResize event if column size does not change (mouseMove event width delta = 0)', function () {
  10128. var afterColumnResizeCallback = jasmine.createSpy('afterColumnResizeCallback');
  10129. handsontable({
  10130. data: Handsontable.helper.createSpreadsheetData(3, 3),
  10131. colHeaders: true,
  10132. manualColumnResize: true,
  10133. afterColumnResize: afterColumnResizeCallback
  10134. });
  10135. expect(colWidth(this.$container, 0)).toEqual(50);
  10136. resizeColumn(0, 50);
  10137. expect(afterColumnResizeCallback).not.toHaveBeenCalled();
  10138. expect(colWidth(this.$container, 0)).toEqual(50);
  10139. });
  10140. it('should not trigger an afterColumnResize event if column size does not change (no mouseMove event)', function () {
  10141. var afterColumnResizeCallback = jasmine.createSpy('afterColumnResizeCallback');
  10142. handsontable({
  10143. data: Handsontable.helper.createSpreadsheetData(3, 3),
  10144. colHeaders: true,
  10145. manualColumnResize: true,
  10146. afterColumnResize: afterColumnResizeCallback
  10147. });
  10148. expect(colWidth(this.$container, 0)).toEqual(50);
  10149. var $th = this.$container.find('thead tr:eq(0) th:eq(0)');
  10150. $th.simulate('mouseover');
  10151. var $resizer = this.$container.find('.manualColumnResizer');
  10152. var resizerPosition = $resizer.position();
  10153. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10154. $resizer.simulate('mouseup');
  10155. expect(afterColumnResizeCallback).not.toHaveBeenCalled();
  10156. expect(colWidth(this.$container, 0)).toEqual(50);
  10157. });
  10158. it('should trigger an afterColumnResize after column size changes, after double click', function (done) {
  10159. var afterColumnResizeCallback = jasmine.createSpy('afterColumnResizeCallback');
  10160. handsontable({
  10161. data: Handsontable.helper.createSpreadsheetData(3, 3),
  10162. colHeaders: true,
  10163. manualColumnResize: true,
  10164. afterColumnResize: afterColumnResizeCallback
  10165. });
  10166. expect(colWidth(this.$container, 0)).toEqual(50);
  10167. var $th = this.$container.find('thead tr:eq(0) th:eq(0)');
  10168. $th.simulate('mouseover');
  10169. var $resizer = this.$container.find('.manualColumnResizer');
  10170. var resizerPosition = $resizer.position();
  10171. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10172. $resizer.simulate('mouseup');
  10173. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10174. $resizer.simulate('mouseup');
  10175. setTimeout(function () {
  10176. expect(afterColumnResizeCallback.calls.count()).toEqual(1);
  10177. expect(afterColumnResizeCallback.calls.argsFor(0)[0]).toEqual(0);
  10178. // All modern browsers returns width = 25px, but IE8 seems to compute width differently and returns 24px
  10179. expect(afterColumnResizeCallback.calls.argsFor(0)[1]).toBeInArray([30, 31, 32, 24, 25]);
  10180. expect(colWidth(spec().$container, 0)).toBeInArray([30, 31, 32, 24, 25]);
  10181. done();
  10182. }, 1000);
  10183. });
  10184. it('should autosize column after double click (when initial width is not defined)', function (done) {
  10185. handsontable({
  10186. data: Handsontable.helper.createSpreadsheetData(3, 3),
  10187. colHeaders: true,
  10188. manualColumnResize: true,
  10189. columns: [{ width: 100 }, { width: 200 }, {}]
  10190. });
  10191. expect(colWidth(this.$container, 0)).toEqual(100);
  10192. expect(colWidth(this.$container, 1)).toEqual(200);
  10193. expect(colWidth(this.$container, 2)).toEqual(50);
  10194. resizeColumn(2, 300);
  10195. var $resizer = this.$container.find('.manualColumnResizer');
  10196. var resizerPosition = $resizer.position();
  10197. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10198. $resizer.simulate('mouseup');
  10199. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10200. $resizer.simulate('mouseup');
  10201. setTimeout(function () {
  10202. expect(colWidth(spec().$container, 2)).toBeAroundValue(29, 3);
  10203. done();
  10204. }, 1000);
  10205. });
  10206. it('should autosize selected columns after double click on handler', function (done) {
  10207. handsontable({
  10208. data: Handsontable.helper.createSpreadsheetData(9, 9),
  10209. colHeaders: true,
  10210. manualColumnResize: true
  10211. });
  10212. resizeColumn(2, 300);
  10213. this.$container.find('thead tr:eq(0) th:eq(1)').simulate('mousedown');
  10214. this.$container.find('thead tr:eq(0) th:eq(2)').simulate('mouseover');
  10215. this.$container.find('thead tr:eq(0) th:eq(3)').simulate('mouseover');
  10216. this.$container.find('thead tr:eq(0) th:eq(3)').simulate('mousemove');
  10217. this.$container.find('thead tr:eq(0) th:eq(3)').simulate('mouseup');
  10218. var $resizer = spec().$container.find('.manualColumnResizer');
  10219. var resizerPosition = $resizer.position();
  10220. setTimeout(function () {
  10221. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10222. $resizer.simulate('mouseup');
  10223. $resizer.simulate('mousedown', { clientX: resizerPosition.left });
  10224. $resizer.simulate('mouseup');
  10225. }, 600);
  10226. setTimeout(function () {
  10227. expect(colWidth(spec().$container, 1)).toBeAroundValue(32, 2);
  10228. expect(colWidth(spec().$container, 2)).toBeAroundValue(32, 2);
  10229. expect(colWidth(spec().$container, 3)).toBeAroundValue(32, 2);
  10230. done();
  10231. }, 1200);
  10232. });
  10233. it('should adjust resize handles position after table size changed', function () {
  10234. var maxed = false;
  10235. handsontable({
  10236. colHeaders: true,
  10237. manualColumnResize: true,
  10238. stretchH: 'all',
  10239. width: function width() {
  10240. return maxed ? 614 : 200;
  10241. }
  10242. });
  10243. this.$container.find('thead th:eq(0)').simulate('mouseover');
  10244. var handle = this.$container.find('.manualColumnResizer');
  10245. var handleBox = handle[0].getBoundingClientRect();
  10246. var th0 = this.$container.find('thead th:eq(0)');
  10247. var thBox = th0[0].getBoundingClientRect();
  10248. expect(handleBox.left + handleBox.width).toEqual(thBox.left + thBox.width - 1);
  10249. maxed = true;
  10250. render();
  10251. this.$container.find('thead th:eq(0)').simulate('mouseover');
  10252. handleBox = handle[0].getBoundingClientRect();
  10253. thBox = th0[0].getBoundingClientRect();
  10254. expect(handleBox.left + handleBox.width).toEqual(thBox.left + thBox.width - 1);
  10255. });
  10256. it('should display the resize handle in the correct place after the table has been scrolled', function () {
  10257. var hot = handsontable({
  10258. data: Handsontable.helper.createSpreadsheetData(10, 20),
  10259. colHeaders: true,
  10260. manualColumnResize: true,
  10261. height: 100,
  10262. width: 200
  10263. });
  10264. var mainHolder = hot.view.wt.wtTable.holder;
  10265. var $colHeader = this.$container.find('.ht_clone_top thead tr:eq(0) th:eq(2)');
  10266. $colHeader.simulate('mouseover');
  10267. var $handle = this.$container.find('.manualColumnResizer');
  10268. $handle[0].style.background = 'red';
  10269. expect($colHeader.offset().left + $colHeader.width() - 5).toBeCloseTo($handle.offset().left, 0);
  10270. expect($colHeader.offset().top).toBeCloseTo($handle.offset().top, 0);
  10271. $(mainHolder).scrollLeft(200);
  10272. hot.render();
  10273. $colHeader = this.$container.find('.ht_clone_top thead tr:eq(0) th:eq(3)');
  10274. $colHeader.simulate('mouseover');
  10275. expect($colHeader.offset().left + $colHeader.width() - 5).toBeCloseTo($handle.offset().left, 0);
  10276. expect($colHeader.offset().top).toBeCloseTo($handle.offset().top, 0);
  10277. });
  10278. describe('handle and guide', function () {
  10279. it('should display the resize handle in the proper position and with a proper size', function () {
  10280. var hot = handsontable({
  10281. data: [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }],
  10282. colHeaders: true,
  10283. manualColumnResize: true
  10284. });
  10285. var $headerTH = this.$container.find('thead tr:eq(0) th:eq(1)');
  10286. $headerTH.simulate('mouseover');
  10287. var $handle = $('.manualColumnResizer');
  10288. expect($handle.offset().left).toEqual($headerTH.offset().left + $headerTH.outerWidth() - $handle.outerWidth() - 1);
  10289. expect($handle.height()).toEqual($headerTH.outerHeight());
  10290. });
  10291. });
  10292. });
  10293. /***/ }),
  10294. /* 141 */
  10295. /***/ (function(module, exports, __webpack_require__) {
  10296. "use strict";
  10297. describe('manualRowMove', function () {
  10298. var id = 'testContainer';
  10299. var arrayOfObjects = [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }, { id: 6, name: 'Chuck', lastName: 'Jackson' }, { id: 7, name: 'Meg', lastName: 'Jansen' }, { id: 8, name: 'Rob', lastName: 'Norris' }, { id: 9, name: 'Sean', lastName: 'O\'Hara' }, { id: 10, name: 'Eve', lastName: 'Branson' }];
  10300. beforeEach(function () {
  10301. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  10302. });
  10303. afterEach(function () {
  10304. if (this.$container) {
  10305. destroy();
  10306. this.$container.remove();
  10307. }
  10308. });
  10309. describe('init', function () {
  10310. it('should change row order at init', function () {
  10311. handsontable({
  10312. data: arrayOfObjects,
  10313. manualRowMove: [1, 2, 0]
  10314. });
  10315. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  10316. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('3');
  10317. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  10318. });
  10319. });
  10320. describe('updateSettings', function () {
  10321. it('should be enabled after specifying it in updateSettings config', function () {
  10322. handsontable({
  10323. data: arrayOfObjects,
  10324. rowHeaders: true
  10325. });
  10326. updateSettings({
  10327. manualRowMove: true
  10328. });
  10329. this.$container.find('tbody tr:eq(0) th:eq(0)').simulate('mousedown');
  10330. this.$container.find('tbody tr:eq(0) th:eq(0)').simulate('mouseup');
  10331. expect(this.$container.hasClass('after-selection--rows')).toBeGreaterThan(0);
  10332. });
  10333. it('should change the default row order with updateSettings', function () {
  10334. handsontable({
  10335. data: arrayOfObjects,
  10336. manualRowMove: true
  10337. });
  10338. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10339. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10340. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10341. updateSettings({
  10342. manualRowMove: [2, 1, 0]
  10343. });
  10344. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  10345. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10346. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  10347. });
  10348. it('should change row order with updateSettings', function () {
  10349. handsontable({
  10350. data: arrayOfObjects,
  10351. manualRowMove: [1, 2, 0]
  10352. });
  10353. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  10354. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('3');
  10355. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  10356. updateSettings({
  10357. manualRowMove: [2, 1, 0]
  10358. });
  10359. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  10360. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10361. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  10362. });
  10363. it('should reset row order with updateSettings when undefined is passed', function () {
  10364. handsontable({
  10365. data: arrayOfObjects,
  10366. manualRowMove: [1, 2, 0]
  10367. });
  10368. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  10369. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('3');
  10370. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  10371. updateSettings({
  10372. manualRowMove: void 0
  10373. });
  10374. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10375. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10376. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10377. });
  10378. it('should not change row order with updateSettings when `true` is passed', function () {
  10379. handsontable({
  10380. data: arrayOfObjects,
  10381. manualRowMove: [1, 2, 0]
  10382. });
  10383. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  10384. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('3');
  10385. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  10386. updateSettings({
  10387. manualRowMove: true
  10388. });
  10389. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  10390. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('3');
  10391. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  10392. });
  10393. });
  10394. describe('loadData', function () {
  10395. it('should increase numbers of rows if it is necessary', function () {
  10396. var hot = handsontable({
  10397. data: Handsontable.helper.createSpreadsheetData(5, 5),
  10398. manualRowMove: true
  10399. });
  10400. hot.loadData(Handsontable.helper.createSpreadsheetData(10, 10));
  10401. expect(countRows()).toEqual(10);
  10402. expect(hot.getPlugin('manualRowMove').rowsMapper.__arrayMap.length).toEqual(10);
  10403. });
  10404. it('should decrease numbers of rows if it is necessary', function () {
  10405. var hot = handsontable({
  10406. data: Handsontable.helper.createSpreadsheetData(5, 5),
  10407. manualRowMove: true
  10408. });
  10409. hot.loadData(Handsontable.helper.createSpreadsheetData(2, 2));
  10410. expect(countRows()).toEqual(2);
  10411. expect(hot.getPlugin('manualRowMove').rowsMapper.__arrayMap.length).toEqual(2);
  10412. });
  10413. });
  10414. describe('moving', function () {
  10415. it('should move row by API', function () {
  10416. var hot = handsontable({
  10417. data: arrayOfObjects,
  10418. rowHeaders: true,
  10419. manualRowMove: true
  10420. });
  10421. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10422. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10423. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10424. hot.getPlugin('manualRowMove').moveRow(2, 0);
  10425. hot.render();
  10426. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  10427. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  10428. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  10429. });
  10430. it('should move many rows by API', function () {
  10431. var hot = handsontable({
  10432. data: arrayOfObjects,
  10433. rowHeaders: true,
  10434. manualRowMove: true
  10435. });
  10436. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10437. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10438. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10439. hot.getPlugin('manualRowMove').moveRows([7, 9, 8], 0);
  10440. hot.render();
  10441. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('8');
  10442. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('10');
  10443. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('9');
  10444. });
  10445. it('should trigger an beforeRowMove event before row move', function () {
  10446. var beforeMoveRowCallback = jasmine.createSpy('beforeMoveRowCallback');
  10447. var hot = handsontable({
  10448. data: arrayOfObjects,
  10449. rowHeaders: true,
  10450. manualRowMove: true,
  10451. beforeRowMove: beforeMoveRowCallback
  10452. });
  10453. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10454. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10455. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10456. hot.getPlugin('manualRowMove').moveRows([8, 9, 7], 0);
  10457. hot.render();
  10458. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('9');
  10459. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('10');
  10460. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('8');
  10461. expect(beforeMoveRowCallback).toHaveBeenCalledWith([8, 9, 7], 0, void 0, void 0, void 0, void 0);
  10462. });
  10463. it('should trigger an afterRowMove event after row move', function () {
  10464. var afterMoveRowCallback = jasmine.createSpy('afterMoveRowCallback');
  10465. this.$container.height(150);
  10466. var hot = handsontable({
  10467. data: arrayOfObjects,
  10468. rowHeaders: true,
  10469. manualRowMove: true,
  10470. afterRowMove: afterMoveRowCallback
  10471. });
  10472. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10473. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10474. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10475. hot.getPlugin('manualRowMove').moveRows([8, 9, 7], 0);
  10476. hot.render();
  10477. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('9');
  10478. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('10');
  10479. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('8');
  10480. expect(afterMoveRowCallback).toHaveBeenCalledWith([8, 9, 7], 0, void 0, void 0, void 0, void 0);
  10481. });
  10482. it('should move the second row to the first row', function () {
  10483. var hot = handsontable({
  10484. data: arrayOfObjects,
  10485. rowHeaders: true,
  10486. manualRowMove: true
  10487. });
  10488. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10489. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10490. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10491. var $rowsHeaders = this.$container.find('.ht_clone_left tr th');
  10492. $rowsHeaders.eq(1).simulate('mousedown');
  10493. $rowsHeaders.eq(1).simulate('mouseup');
  10494. $rowsHeaders.eq(1).simulate('mousedown');
  10495. $rowsHeaders.eq(0).simulate('mouseover');
  10496. $rowsHeaders.eq(0).simulate('mousemove');
  10497. $rowsHeaders.eq(0).simulate('mouseup');
  10498. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  10499. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  10500. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10501. });
  10502. it('should move the second row to the third row', function () {
  10503. handsontable({
  10504. data: arrayOfObjects,
  10505. rowHeaders: true,
  10506. manualRowMove: true
  10507. });
  10508. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10509. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  10510. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  10511. var $rowsHeaders = this.$container.find('.ht_clone_left tr th');
  10512. $rowsHeaders.eq(1).simulate('mousedown');
  10513. $rowsHeaders.eq(1).simulate('mouseup');
  10514. $rowsHeaders.eq(1).simulate('mousedown');
  10515. $rowsHeaders.eq(3).simulate('mouseover');
  10516. $rowsHeaders.eq(3).simulate('mousemove');
  10517. $rowsHeaders.eq(3).simulate('mouseup');
  10518. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  10519. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('3');
  10520. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  10521. });
  10522. it('should not move row if it\'s not needed', function () {
  10523. var cache = [];
  10524. handsontable({
  10525. data: arrayOfObjects,
  10526. rowHeaders: true,
  10527. manualRowMove: true,
  10528. afterRowMove: function afterRowMove(rows, target) {
  10529. cache.push(rows);
  10530. }
  10531. });
  10532. var $rowsHeaders = this.$container.find('.ht_clone_left tr th');
  10533. $rowsHeaders.eq(1).simulate('mousedown');
  10534. $rowsHeaders.eq(1).simulate('mouseup');
  10535. $rowsHeaders.eq(1).simulate('mousedown');
  10536. $rowsHeaders.eq(3).simulate('mouseup');
  10537. expect(cache.length).toEqual(0);
  10538. });
  10539. it('should properly scrolling viewport if mouse is over part-visible cell', function (done) {
  10540. var hot = handsontable({
  10541. data: Handsontable.helper.createSpreadsheetData(20, 20),
  10542. colHeaders: true,
  10543. rowHeaders: true,
  10544. manualRowMove: true,
  10545. width: 600,
  10546. height: 600,
  10547. rowHeights: 47
  10548. });
  10549. var ev = {};
  10550. hot.selectCell(19, 0);
  10551. setTimeout(function () {
  10552. expect(hot.view.wt.wtTable.getFirstVisibleRow()).toBeGreaterThan(8);
  10553. var $rowsHeaders = spec().$container.find('.ht_clone_left tr th');
  10554. $rowsHeaders.eq(10).simulate('mousedown');
  10555. $rowsHeaders.eq(10).simulate('mouseup');
  10556. $rowsHeaders.eq(10).simulate('mousedown');
  10557. $rowsHeaders.eq(8).simulate('mouseover');
  10558. $rowsHeaders.eq(8).simulate('mousemove');
  10559. $rowsHeaders.eq(8).simulate('mouseup');
  10560. }, 50);
  10561. setTimeout(function () {
  10562. expect(hot.view.wt.wtTable.getFirstVisibleRow()).toBeLessThan(8);
  10563. done();
  10564. }, 150);
  10565. });
  10566. it('moving row should keep cell meta created using cells function', function () {
  10567. var hot = handsontable({
  10568. data: arrayOfObjects,
  10569. rowHeaders: true,
  10570. manualRowMove: true,
  10571. cells: function cells(row, col) {
  10572. if (row == 1 && col == 0) {
  10573. this.readOnly = true;
  10574. }
  10575. }
  10576. });
  10577. var htCore = getHtCore();
  10578. expect(htCore.find('tbody tr:eq(1) td:eq(0)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  10579. hot.getPlugin('manualRowMove').moveRow(1, 3);
  10580. hot.render();
  10581. expect(htCore.find('tbody tr:eq(2) td:eq(0)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  10582. });
  10583. it('moving row should keep cell meta created using cell array', function () {
  10584. var hot = handsontable({
  10585. data: arrayOfObjects,
  10586. rowHeaders: true,
  10587. manualRowMove: true,
  10588. cell: [{ row: 1, col: 0, readOnly: true }]
  10589. });
  10590. var htCore = getHtCore();
  10591. expect(htCore.find('tbody tr:eq(1) td:eq(0)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  10592. hot.getPlugin('manualRowMove').moveRow(3, 1);
  10593. hot.render();
  10594. expect(htCore.find('tbody tr:eq(2) td:eq(0)')[0].className.indexOf('htDimmed')).toBeGreaterThan(-1);
  10595. });
  10596. });
  10597. describe('undoRedo', function () {
  10598. it('should back changes', function () {
  10599. var hot = handsontable({
  10600. data: Handsontable.helper.createSpreadsheetData(10, 10),
  10601. rowHeaders: true,
  10602. manualRowMove: true
  10603. });
  10604. hot.getPlugin('manualRowMove').moveRow(1, 4);
  10605. hot.render();
  10606. expect(hot.getDataAtCell(3, 0)).toBe('A2');
  10607. hot.undo();
  10608. expect(hot.getDataAtCell(1, 0)).toBe('A2');
  10609. });
  10610. it('should revert changes', function () {
  10611. var hot = handsontable({
  10612. data: Handsontable.helper.createSpreadsheetData(10, 10),
  10613. rowHeaders: true,
  10614. manualRowMove: true
  10615. });
  10616. hot.getPlugin('manualRowMove').moveRow(1, 4);
  10617. hot.render();
  10618. expect(hot.getDataAtCell(3, 0)).toBe('A2');
  10619. hot.undo();
  10620. expect(hot.getDataAtCell(1, 0)).toBe('A2');
  10621. hot.redo();
  10622. expect(hot.getDataAtCell(3, 0)).toBe('A2');
  10623. });
  10624. });
  10625. });
  10626. /***/ }),
  10627. /* 142 */
  10628. /***/ (function(module, exports, __webpack_require__) {
  10629. "use strict";
  10630. describe('manualRowMove', function () {
  10631. var id = 'testContainer';
  10632. beforeEach(function () {
  10633. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  10634. });
  10635. afterEach(function () {
  10636. if (this.$container) {
  10637. destroy();
  10638. this.$container.remove();
  10639. }
  10640. });
  10641. describe('UI', function () {
  10642. it('should append UI elements to wtHider after click on row header', function () {
  10643. var hot = handsontable({
  10644. data: Handsontable.helper.createSpreadsheetData(30, 30),
  10645. rowHeaders: true,
  10646. manualRowMove: true
  10647. });
  10648. var $headerTH = this.$container.find('tbody tr:eq(0) th:eq(0)');
  10649. $headerTH.simulate('mousedown');
  10650. $headerTH.simulate('mouseup');
  10651. $headerTH.simulate('mousedown');
  10652. expect(this.$container.find('.ht__manualRowMove--guideline').length).toBe(1);
  10653. expect(this.$container.find('.ht__manualRowMove--backlight').length).toBe(1);
  10654. });
  10655. it('should part of UI elements be visible on dragging action', function () {
  10656. var hot = handsontable({
  10657. data: Handsontable.helper.createSpreadsheetData(30, 30),
  10658. rowHeaders: true,
  10659. manualRowMove: true
  10660. });
  10661. var $headerTH = this.$container.find('tbody tr:eq(0) th:eq(0)');
  10662. $headerTH.simulate('mousedown');
  10663. $headerTH.simulate('mouseup');
  10664. $headerTH.simulate('mousedown');
  10665. expect(this.$container.find('.ht__manualRowMove--guideline:visible').length).toBe(0);
  10666. expect(this.$container.find('.ht__manualRowMove--backlight:visible').length).toBe(1);
  10667. });
  10668. it('should all of UI elements be visible on dragging action', function () {
  10669. var hot = handsontable({
  10670. data: Handsontable.helper.createSpreadsheetData(30, 30),
  10671. rowHeaders: true,
  10672. manualRowMove: true
  10673. });
  10674. var $headers = [this.$container.find('tbody tr:eq(0) th:eq(0)'), this.$container.find('tbody tr:eq(1) th:eq(0)'), this.$container.find('tbody tr:eq(2) th:eq(0)')];
  10675. $headers[0].simulate('mousedown');
  10676. $headers[0].simulate('mouseup');
  10677. $headers[0].simulate('mousedown');
  10678. $headers[1].simulate('mouseover');
  10679. $headers[2].simulate('mouseover');
  10680. expect(this.$container.find('.ht__manualRowMove--guideline:visible').length).toBe(1);
  10681. expect(this.$container.find('.ht__manualRowMove--backlight:visible').length).toBe(1);
  10682. });
  10683. });
  10684. });
  10685. /***/ }),
  10686. /* 143 */
  10687. /***/ (function(module, exports, __webpack_require__) {
  10688. "use strict";
  10689. describe('manualRowResize', function () {
  10690. var id = 'test';
  10691. var defaultRowHeight = 22;
  10692. beforeEach(function () {
  10693. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  10694. });
  10695. afterEach(function () {
  10696. if (this.$container) {
  10697. destroy();
  10698. this.$container.remove();
  10699. }
  10700. });
  10701. it('should change row heights at init', function () {
  10702. handsontable({
  10703. rowHeaders: true,
  10704. manualRowResize: [50, 40, 100]
  10705. });
  10706. expect(rowHeight(this.$container, 0)).toEqual(51);
  10707. expect(rowHeight(this.$container, 1)).toEqual(40);
  10708. expect(rowHeight(this.$container, 2)).toEqual(100);
  10709. });
  10710. it('should be enabled after specifying it in updateSettings config', function () {
  10711. var hot = handsontable({
  10712. data: [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }],
  10713. rowHeaders: true
  10714. });
  10715. updateSettings({ manualRowResize: true });
  10716. this.$container.find('tbody tr:eq(0) th:eq(0)').simulate('mouseover');
  10717. expect($('.manualRowResizer').size()).toBeGreaterThan(0);
  10718. });
  10719. it('should change the default row height with updateSettings', function () {
  10720. handsontable({
  10721. manualRowResize: true
  10722. });
  10723. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2); // + Double border
  10724. expect(rowHeight(this.$container, 1)).toEqual(defaultRowHeight + 1); // + Single border
  10725. expect(rowHeight(this.$container, 2)).toEqual(defaultRowHeight + 1); // + Single border
  10726. updateSettings({
  10727. manualRowResize: [60, 50, 80]
  10728. });
  10729. expect(rowHeight(this.$container, 0)).toEqual(61);
  10730. expect(rowHeight(this.$container, 1)).toEqual(50);
  10731. expect(rowHeight(this.$container, 2)).toEqual(80);
  10732. });
  10733. it('should change the row height with updateSettings', function () {
  10734. handsontable({
  10735. manualRowResize: [60, 50, 80]
  10736. });
  10737. expect(rowHeight(this.$container, 0)).toEqual(61);
  10738. expect(rowHeight(this.$container, 1)).toEqual(50);
  10739. expect(rowHeight(this.$container, 2)).toEqual(80);
  10740. updateSettings({
  10741. manualRowResize: [30, 80, 100]
  10742. });
  10743. expect(rowHeight(this.$container, 0)).toEqual(31);
  10744. expect(rowHeight(this.$container, 1)).toEqual(80);
  10745. expect(rowHeight(this.$container, 2)).toEqual(100);
  10746. });
  10747. it('should not change the row height when `true` is passing', function () {
  10748. handsontable({
  10749. manualRowResize: [60, 50, 80]
  10750. });
  10751. expect(rowHeight(this.$container, 0)).toEqual(61);
  10752. expect(rowHeight(this.$container, 1)).toEqual(50);
  10753. expect(rowHeight(this.$container, 2)).toEqual(80);
  10754. updateSettings({
  10755. manualRowResize: true
  10756. });
  10757. expect(rowHeight(this.$container, 0)).toEqual(61);
  10758. expect(rowHeight(this.$container, 1)).toEqual(50);
  10759. expect(rowHeight(this.$container, 2)).toEqual(80);
  10760. });
  10761. it('should change the row height to defaults when undefined is passed', function () {
  10762. handsontable({
  10763. manualRowResize: [60, 50, 80]
  10764. });
  10765. expect(rowHeight(this.$container, 0)).toEqual(61);
  10766. expect(rowHeight(this.$container, 1)).toEqual(50);
  10767. expect(rowHeight(this.$container, 2)).toEqual(80);
  10768. updateSettings({
  10769. manualRowResize: void 0
  10770. });
  10771. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2); // + Double border
  10772. expect(rowHeight(this.$container, 1)).toEqual(defaultRowHeight + 1); // + Single border
  10773. expect(rowHeight(this.$container, 2)).toEqual(defaultRowHeight + 1); // + Single border
  10774. });
  10775. it('should reset row height', function () {
  10776. handsontable({
  10777. manualRowResize: true
  10778. });
  10779. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10780. expect(rowHeight(this.$container, 1)).toEqual(defaultRowHeight + 1);
  10781. expect(rowHeight(this.$container, 2)).toEqual(defaultRowHeight + 1);
  10782. updateSettings({
  10783. manualRowResize: true
  10784. });
  10785. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10786. expect(rowHeight(this.$container, 1)).toEqual(defaultRowHeight + 1);
  10787. expect(rowHeight(this.$container, 2)).toEqual(defaultRowHeight + 1);
  10788. });
  10789. it('should trigger afterRowResize event after row height changes', function () {
  10790. var afterRowResizeCallback = jasmine.createSpy('afterRowResizeCallback');
  10791. handsontable({
  10792. data: Handsontable.helper.createSpreadsheetData(5, 5),
  10793. rowHeaders: true,
  10794. manualRowResize: true,
  10795. afterRowResize: afterRowResizeCallback
  10796. });
  10797. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10798. resizeRow(0, 100);
  10799. expect(afterRowResizeCallback).toHaveBeenCalledWith(0, 100, void 0, void 0, void 0, void 0);
  10800. expect(rowHeight(this.$container, 0)).toEqual(101);
  10801. });
  10802. it('should not trigger afterRowResize event if row height does not change (delta = 0)', function () {
  10803. var afterRowResizeCallback = jasmine.createSpy('afterRowResizeCallback');
  10804. handsontable({
  10805. data: Handsontable.helper.createSpreadsheetData(5, 5),
  10806. rowHeaders: true,
  10807. manualRowResize: true,
  10808. afterRowResize: afterRowResizeCallback
  10809. });
  10810. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10811. resizeRow(0, defaultRowHeight);
  10812. expect(afterRowResizeCallback).not.toHaveBeenCalled();
  10813. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10814. });
  10815. it('should not trigger afterRowResize event after if row height does not change (no mousemove event)', function () {
  10816. var afterRowResizeCallback = jasmine.createSpy('afterRowResizeCallback');
  10817. handsontable({
  10818. data: Handsontable.helper.createSpreadsheetData(5, 5),
  10819. rowHeaders: true,
  10820. manualRowResize: true,
  10821. afterRowResize: afterRowResizeCallback
  10822. });
  10823. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10824. var $th = this.$container.find('tbody tr:eq(0) th:eq(0)');
  10825. $th.simulate('mouseover');
  10826. var $resizer = this.$container.find('.manualRowResizer');
  10827. var resizerPosition = $resizer.position();
  10828. $resizer.simulate('mousedown', {
  10829. clientY: resizerPosition.top
  10830. });
  10831. $resizer.simulate('mouseup');
  10832. expect(afterRowResizeCallback).not.toHaveBeenCalled();
  10833. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10834. });
  10835. it('should trigger an afterRowResize after row size changes, after double click', function (done) {
  10836. var afterRowResizeCallback = jasmine.createSpy('afterRowResizeCallback');
  10837. handsontable({
  10838. data: Handsontable.helper.createSpreadsheetData(5, 5),
  10839. rowHeaders: true,
  10840. manualRowResize: true,
  10841. autoRowSize: true,
  10842. afterRowResize: afterRowResizeCallback
  10843. });
  10844. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10845. var $th = this.$container.find('tbody tr:eq(2) th:eq(0)');
  10846. $th.simulate('mouseover');
  10847. var $resizer = this.$container.find('.manualRowResizer');
  10848. var resizerPosition = $resizer.position();
  10849. $resizer.simulate('mousedown', {
  10850. clientY: resizerPosition.top
  10851. });
  10852. $resizer.simulate('mouseup');
  10853. $resizer.simulate('mousedown', {
  10854. clientY: resizerPosition.top
  10855. });
  10856. $resizer.simulate('mouseup');
  10857. setTimeout(function () {
  10858. expect(afterRowResizeCallback.calls.count()).toEqual(1);
  10859. expect(afterRowResizeCallback.calls.argsFor(0)[0]).toEqual(2);
  10860. expect(afterRowResizeCallback.calls.argsFor(0)[1]).toEqual(defaultRowHeight + 1);
  10861. expect(rowHeight(spec().$container, 2)).toEqual(defaultRowHeight + 1);
  10862. done();
  10863. }, 1000);
  10864. });
  10865. it('should not trigger afterRowResize event after if row height does not change (no dblclick event)', function () {
  10866. var afterRowResizeCallback = jasmine.createSpy('afterRowResizeCallback');
  10867. handsontable({
  10868. data: Handsontable.helper.createSpreadsheetData(5, 5),
  10869. rowHeaders: true,
  10870. manualRowResize: true,
  10871. afterRowResize: afterRowResizeCallback
  10872. });
  10873. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10874. var $th = this.$container.find('tbody tr:eq(2) th:eq(0)');
  10875. $th.simulate('mouseover');
  10876. var $resizer = this.$container.find('.manualRowResizer');
  10877. var resizerPosition = $resizer.position();
  10878. $resizer.simulate('mousedown', {
  10879. clientY: resizerPosition.top
  10880. });
  10881. $resizer.simulate('mouseup');
  10882. expect(afterRowResizeCallback).not.toHaveBeenCalled();
  10883. expect(rowHeight(this.$container, 0)).toEqual(defaultRowHeight + 2);
  10884. });
  10885. it('should display the resize handle in the correct place after the table has been scrolled', function () {
  10886. var hot = handsontable({
  10887. data: Handsontable.helper.createSpreadsheetData(20, 20),
  10888. rowHeaders: true,
  10889. manualRowResize: true,
  10890. height: 100,
  10891. width: 200
  10892. });
  10893. var mainHolder = hot.view.wt.wtTable.holder;
  10894. var $rowHeader = this.$container.find('.ht_clone_left tbody tr:eq(2) th:eq(0)');
  10895. $rowHeader.simulate('mouseover');
  10896. var $handle = this.$container.find('.manualRowResizer');
  10897. $handle[0].style.background = 'red';
  10898. expect($rowHeader.offset().left).toBeCloseTo($handle.offset().left, 0);
  10899. expect($rowHeader.offset().top + $rowHeader.height() - 5).toBeCloseTo($handle.offset().top, 0);
  10900. $(mainHolder).scrollTop(200);
  10901. $(mainHolder).scroll();
  10902. $rowHeader = this.$container.find('.ht_clone_left tbody tr:eq(2) th:eq(0)');
  10903. $rowHeader.simulate('mouseover');
  10904. expect($rowHeader.offset().left).toBeCloseTo($handle.offset().left, 0);
  10905. expect($rowHeader.offset().top + $rowHeader.height() - 5).toBeCloseTo($handle.offset().top, 0);
  10906. });
  10907. it('should autosize selected rows after double click on handler', function (done) {
  10908. handsontable({
  10909. data: Handsontable.helper.createSpreadsheetData(9, 9),
  10910. rowHeaders: true,
  10911. manualRowResize: true
  10912. });
  10913. resizeRow(2, 300);
  10914. var $resizer = this.$container.find('.manualRowResizer');
  10915. var resizerPosition = $resizer.position();
  10916. this.$container.find('.ht_clone_left tbody tr:eq(1) th:eq(0)').simulate('mousedown');
  10917. this.$container.find('.ht_clone_left tbody tr:eq(2) th:eq(0)').simulate('mouseover');
  10918. this.$container.find('.ht_clone_left tbody tr:eq(3) th:eq(0)').simulate('mouseover');
  10919. this.$container.find('.ht_clone_left tbody tr:eq(3) th:eq(0)').simulate('mousemove');
  10920. this.$container.find('.ht_clone_left tbody tr:eq(3) th:eq(0)').simulate('mouseup');
  10921. setTimeout(function () {
  10922. $resizer.simulate('mousedown', { clientY: resizerPosition.top });
  10923. $resizer.simulate('mouseup');
  10924. $resizer.simulate('mousedown', { clientY: resizerPosition.top });
  10925. $resizer.simulate('mouseup');
  10926. }, 600);
  10927. setTimeout(function () {
  10928. expect(rowHeight(spec().$container, 1)).toBeAroundValue(24);
  10929. expect(rowHeight(spec().$container, 2)).toBeAroundValue(24);
  10930. expect(rowHeight(spec().$container, 3)).toBeAroundValue(24);
  10931. done();
  10932. }, 1600);
  10933. });
  10934. it('should resize (expanding and narrowing) selected rows', function (done) {
  10935. var hot = handsontable({
  10936. data: Handsontable.helper.createSpreadsheetData(10, 20),
  10937. rowHeaders: true,
  10938. manualRowResize: true
  10939. });
  10940. resizeRow(2, 60);
  10941. var $rowsHeaders = this.$container.find('.ht_clone_left tr th');
  10942. this.$container.find('.ht_clone_left tbody tr:eq(1) th:eq(0)').simulate('mouseover');
  10943. $rowsHeaders.eq(1).simulate('mousedown');
  10944. $rowsHeaders.eq(2).simulate('mouseover');
  10945. $rowsHeaders.eq(3).simulate('mouseover');
  10946. $rowsHeaders.eq(3).simulate('mousemove');
  10947. $rowsHeaders.eq(3).simulate('mouseup');
  10948. var $resizer = this.$container.find('.manualRowResizer');
  10949. var resizerPosition = $resizer.position();
  10950. setTimeout(function () {
  10951. $resizer.simulate('mousedown', { clientY: resizerPosition.top });
  10952. $resizer.simulate('mousemove', { clientY: resizerPosition.top - $rowsHeaders.eq(3).height() + 80 });
  10953. $resizer.simulate('mouseup');
  10954. expect($rowsHeaders.eq(1).height()).toEqual(80);
  10955. expect($rowsHeaders.eq(2).height()).toEqual(80);
  10956. expect($rowsHeaders.eq(3).height()).toEqual(80);
  10957. }, 600);
  10958. setTimeout(function () {
  10959. $resizer.simulate('mousedown', { clientY: resizerPosition.top });
  10960. $resizer.simulate('mousemove', { clientY: resizerPosition.top - $rowsHeaders.eq(3).height() + 35 });
  10961. $resizer.simulate('mouseup');
  10962. expect($rowsHeaders.eq(1).height()).toEqual(35);
  10963. expect($rowsHeaders.eq(2).height()).toEqual(35);
  10964. expect($rowsHeaders.eq(3).height()).toEqual(35);
  10965. done();
  10966. }, 1800);
  10967. });
  10968. describe('handle and guide', function () {
  10969. it('should display the resize handle in the proper position and with a proper size', function () {
  10970. var hot = handsontable({
  10971. data: [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }],
  10972. rowHeaders: true,
  10973. manualRowResize: true
  10974. });
  10975. var $headerTH = this.$container.find('tbody tr:eq(1) th:eq(0)');
  10976. $headerTH.simulate('mouseover');
  10977. var $handle = $('.manualRowResizer');
  10978. expect($handle.offset().top).toBeCloseTo($headerTH.offset().top + $headerTH.outerHeight() - $handle.outerHeight() - 1, 0);
  10979. expect($handle.width()).toBeCloseTo($headerTH.outerWidth(), 0);
  10980. });
  10981. });
  10982. });
  10983. /***/ }),
  10984. /* 144 */
  10985. /***/ (function(module, exports, __webpack_require__) {
  10986. "use strict";
  10987. describe('MergeCells', function () {
  10988. var id = 'testContainer';
  10989. beforeEach(function () {
  10990. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  10991. });
  10992. afterEach(function () {
  10993. if (this.$container) {
  10994. destroy();
  10995. this.$container.remove();
  10996. }
  10997. });
  10998. describe('mergeCells option', function () {
  10999. it('should merge cell in startup', function () {
  11000. var hot = handsontable({
  11001. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  11002. mergeCells: [{ row: 0, col: 0, rowspan: 2, colspan: 2 }]
  11003. });
  11004. var TD = hot.rootElement.querySelector('td');
  11005. expect(TD.getAttribute('rowspan')).toBe('2');
  11006. expect(TD.getAttribute('colspan')).toBe('2');
  11007. });
  11008. });
  11009. describe('mergeCells updateSettings', function () {
  11010. it('should allow to overwrite the initial settings using the updateSettings method', function () {
  11011. var hot = handsontable({
  11012. data: Handsontable.helper.createSpreadsheetObjectData(10, 10),
  11013. mergeCells: [{ row: 0, col: 0, rowspan: 2, colspan: 2 }]
  11014. });
  11015. var TD = hot.rootElement.querySelector('td');
  11016. expect(TD.getAttribute('rowspan')).toBe('2');
  11017. expect(TD.getAttribute('colspan')).toBe('2');
  11018. updateSettings({
  11019. mergeCells: [{ row: 2, col: 2, rowspan: 2, colspan: 2 }]
  11020. });
  11021. TD = hot.rootElement.querySelector('td');
  11022. expect(TD.getAttribute('rowspan')).toBe(null);
  11023. expect(TD.getAttribute('colspan')).toBe(null);
  11024. TD = getCell(2, 2);
  11025. expect(TD.getAttribute('rowspan')).toBe('2');
  11026. expect(TD.getAttribute('colspan')).toBe('2');
  11027. });
  11028. it('should allow resetting the merged cells by changing it to \'true\'', function () {
  11029. var hot = handsontable({
  11030. data: Handsontable.helper.createSpreadsheetObjectData(10, 10),
  11031. mergeCells: [{ row: 0, col: 0, rowspan: 2, colspan: 2 }]
  11032. });
  11033. var TD = hot.rootElement.querySelector('td');
  11034. expect(TD.getAttribute('rowspan')).toBe('2');
  11035. expect(TD.getAttribute('colspan')).toBe('2');
  11036. updateSettings({
  11037. mergeCells: true
  11038. });
  11039. TD = hot.rootElement.querySelector('td');
  11040. expect(TD.getAttribute('rowspan')).toBe(null);
  11041. expect(TD.getAttribute('colspan')).toBe(null);
  11042. });
  11043. it('should allow resetting and turning off the mergeCells plugin by changing mergeCells to \'false\'', function () {
  11044. var hot = handsontable({
  11045. data: Handsontable.helper.createSpreadsheetObjectData(10, 10),
  11046. mergeCells: [{ row: 0, col: 0, rowspan: 2, colspan: 2 }]
  11047. });
  11048. var TD = hot.rootElement.querySelector('td');
  11049. expect(TD.getAttribute('rowspan')).toBe('2');
  11050. expect(TD.getAttribute('colspan')).toBe('2');
  11051. updateSettings({
  11052. mergeCells: false
  11053. });
  11054. TD = hot.rootElement.querySelector('td');
  11055. expect(TD.getAttribute('rowspan')).toBe(null);
  11056. expect(TD.getAttribute('colspan')).toBe(null);
  11057. });
  11058. });
  11059. describe('mergeCells copy', function () {
  11060. it('should not copy text of cells that are merged into another cell', function () {
  11061. var hot = handsontable({
  11062. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  11063. mergeCells: [{ row: 0, col: 0, rowspan: 2, colspan: 2 }]
  11064. });
  11065. expect(hot.getCopyableText(0, 0, 2, 2)).toBe('A1\t\tC1\n\t\tC2\nA3\tB3\tC3');
  11066. });
  11067. });
  11068. describe('merged cells selection', function () {
  11069. it('should select the whole range of cells which form a merged cell', function () {
  11070. var hot = handsontable({
  11071. data: Handsontable.helper.createSpreadsheetObjectData(4, 4),
  11072. mergeCells: [{
  11073. row: 0,
  11074. col: 0,
  11075. colspan: 4,
  11076. rowspan: 1
  11077. }]
  11078. });
  11079. var $table = this.$container.find('table.htCore');
  11080. var $td = $table.find('tr:eq(0) td:eq(0)');
  11081. expect($td.attr('rowspan')).toEqual('1');
  11082. expect($td.attr('colspan')).toEqual('4');
  11083. expect(hot.getSelected()).toBeUndefined();
  11084. hot.selectCell(0, 0);
  11085. expect(hot.getSelected()).toEqual([0, 0, 0, 3]);
  11086. deselectCell();
  11087. hot.selectCell(0, 1);
  11088. expect(hot.getSelected()).toEqual([0, 0, 0, 3]);
  11089. });
  11090. it('should always make a rectangular selection, when selecting merged and not merged cells', function () {
  11091. var hot = handsontable({
  11092. data: Handsontable.helper.createSpreadsheetObjectData(4, 4),
  11093. mergeCells: [{
  11094. row: 1,
  11095. col: 1,
  11096. colspan: 3,
  11097. rowspan: 2
  11098. }]
  11099. });
  11100. var $table = this.$container.find('table.htCore');
  11101. var $td = $table.find('tr:eq(1) td:eq(1)');
  11102. expect($td.attr('rowspan')).toEqual('2');
  11103. expect($td.attr('colspan')).toEqual('3');
  11104. expect(hot.getSelected()).toBeUndefined();
  11105. hot.selectCell(0, 0);
  11106. expect(hot.getSelected()).toEqual([0, 0, 0, 0]);
  11107. deselectCell();
  11108. hot.selectCell(0, 0, 1, 1);
  11109. expect(hot.getSelected()).not.toEqual([0, 0, 1, 1]);
  11110. expect(hot.getSelected()).toEqual([0, 0, 2, 3]);
  11111. deselectCell();
  11112. hot.selectCell(0, 1, 1, 1);
  11113. expect(hot.getSelected()).toEqual([0, 1, 2, 3]);
  11114. });
  11115. it('should not switch the selection start point when selecting from non-merged cells to merged cells', function () {
  11116. var hot = handsontable({
  11117. data: Handsontable.helper.createSpreadsheetObjectData(10, 10),
  11118. mergeCells: [{ row: 1, col: 1, rowspan: 3, colspan: 3 }, { row: 3, col: 4, rowspan: 2, colspan: 2 }]
  11119. });
  11120. $(hot.getCell(6, 6)).simulate('mousedown');
  11121. expect(hot.getSelectedRange().from.col).toEqual(6);
  11122. expect(hot.getSelectedRange().from.row).toEqual(6);
  11123. $(hot.getCell(1, 1)).simulate('mouseenter');
  11124. expect(hot.getSelectedRange().from.col).toEqual(6);
  11125. expect(hot.getSelectedRange().from.row).toEqual(6);
  11126. $(hot.getCell(3, 3)).simulate('mouseenter');
  11127. expect(hot.getSelectedRange().from.col).toEqual(6);
  11128. expect(hot.getSelectedRange().from.row).toEqual(6);
  11129. $(hot.getCell(4, 4)).simulate('mouseenter');
  11130. expect(hot.getSelectedRange().from.col).toEqual(6);
  11131. expect(hot.getSelectedRange().from.row).toEqual(6);
  11132. });
  11133. it('should select cells in the correct direction when changing selections around a merged range', function () {
  11134. var hot = handsontable({
  11135. data: Handsontable.helper.createSpreadsheetObjectData(10, 10),
  11136. mergeCells: [{ row: 4, col: 4, rowspan: 2, colspan: 2 }]
  11137. });
  11138. hot.selectCell(5, 5, 5, 2);
  11139. expect(hot.getSelectedRange().getDirection()).toEqual('SE-NW');
  11140. hot.selectCell(4, 4, 2, 5);
  11141. expect(hot.getSelectedRange().getDirection()).toEqual('SW-NE');
  11142. hot.selectCell(4, 4, 5, 7);
  11143. expect(hot.getSelectedRange().getDirection()).toEqual('NW-SE');
  11144. hot.selectCell(4, 5, 7, 5);
  11145. expect(hot.getSelectedRange().getDirection()).toEqual('NE-SW');
  11146. });
  11147. it('should not add an area class to the selected cell if a single merged cell is selected', function () {
  11148. var hot = handsontable({
  11149. data: Handsontable.helper.createSpreadsheetObjectData(6, 6),
  11150. mergeCells: [{
  11151. row: 1,
  11152. col: 1,
  11153. colspan: 3,
  11154. rowspan: 2
  11155. }]
  11156. });
  11157. selectCell(1, 1);
  11158. expect(getCell(1, 1).className.indexOf('area')).toEqual(-1);
  11159. selectCell(1, 1, 4, 4);
  11160. expect(getCell(1, 1).className.indexOf('area')).not.toEqual(-1);
  11161. selectCell(1, 1);
  11162. expect(getCell(1, 1).className.indexOf('area')).toEqual(-1);
  11163. selectCell(0, 0);
  11164. expect(getCell(1, 1).className.indexOf('area')).toEqual(-1);
  11165. });
  11166. });
  11167. describe('merged cells scroll', function () {
  11168. it('getCell should return merged cell parent', function () {
  11169. var hot = handsontable({
  11170. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  11171. mergeCells: [{ row: 0, col: 0, rowspan: 2, colspan: 2 }],
  11172. height: 100,
  11173. width: 400
  11174. });
  11175. var mergedCellParent = hot.getCell(0, 0);
  11176. var mergedCellHidden = hot.getCell(1, 1);
  11177. expect(mergedCellHidden).toBe(mergedCellParent);
  11178. });
  11179. it('should scroll viewport to beginning of a merged cell when it\'s clicked', function () {
  11180. var hot = handsontable({
  11181. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  11182. mergeCells: [{ row: 5, col: 0, rowspan: 2, colspan: 2 }],
  11183. height: 100,
  11184. width: 400
  11185. });
  11186. var mainHolder = hot.view.wt.wtTable.holder;
  11187. mainHolder.scrollTop = 130;
  11188. hot.render();
  11189. expect(mainHolder.scrollTop).toBe(130);
  11190. var TD = hot.getCell(5, 0);
  11191. mouseDown(TD);
  11192. mouseUp(TD);
  11193. var mergedCellScrollTop = mainHolder.scrollTop;
  11194. expect(mergedCellScrollTop).toBeLessThan(130);
  11195. expect(mergedCellScrollTop).toBeGreaterThan(0);
  11196. mainHolder.scrollTop = 0;
  11197. hot.render();
  11198. mainHolder.scrollTop = 130;
  11199. hot.render();
  11200. TD = hot.getCell(5, 2);
  11201. mouseDown(TD);
  11202. mouseUp(TD);
  11203. var regularCellScrollTop = mainHolder.scrollTop;
  11204. expect(mergedCellScrollTop).toBe(regularCellScrollTop);
  11205. });
  11206. it('should render whole merged cell even when most rows are not in the viewport - scrolled to top', function () {
  11207. var hot = handsontable({
  11208. data: Handsontable.helper.createSpreadsheetObjectData(40, 5),
  11209. mergeCells: [{ row: 1, col: 0, rowspan: 21, colspan: 2 }, { row: 21, col: 2, rowspan: 18, colspan: 2 }],
  11210. height: 100,
  11211. width: 400
  11212. });
  11213. expect(hot.countRenderedRows()).toBe(39);
  11214. });
  11215. it('should render whole merged cell even when most rows are not in the viewport - scrolled to bottom', function () {
  11216. var hot = handsontable({
  11217. data: Handsontable.helper.createSpreadsheetObjectData(40, 5),
  11218. mergeCells: [{ row: 1, col: 0, rowspan: 21, colspan: 2 }, { row: 21, col: 2, rowspan: 18, colspan: 2 }],
  11219. height: 100,
  11220. width: 400
  11221. });
  11222. var mainHolder = hot.view.wt.wtTable.holder;
  11223. $(mainHolder).scrollTop(99999);
  11224. hot.render();
  11225. expect(hot.countRenderedRows()).toBe(39);
  11226. });
  11227. it('should render whole merged cell even when most columns are not in the viewport - scrolled to the left', function () {
  11228. var hot = handsontable({
  11229. data: Handsontable.helper.createSpreadsheetObjectData(5, 40),
  11230. mergeCells: [{ row: 0, col: 1, rowspan: 2, colspan: 21 }, { row: 2, col: 21, rowspan: 2, colspan: 18 }],
  11231. height: 100,
  11232. width: 400
  11233. });
  11234. expect(hot.countRenderedCols()).toBe(39);
  11235. });
  11236. it('should render whole merged cell even when most columns are not in the viewport - scrolled to the right', function () {
  11237. var hot = handsontable({
  11238. data: Handsontable.helper.createSpreadsheetObjectData(5, 40),
  11239. mergeCells: [{ row: 0, col: 1, rowspan: 2, colspan: 21 }, { row: 2, col: 21, rowspan: 2, colspan: 18 }],
  11240. height: 100,
  11241. width: 400
  11242. });
  11243. this.$container.scrollLeft(99999);
  11244. hot.render();
  11245. expect(hot.countRenderedCols()).toBe(39);
  11246. });
  11247. });
  11248. describe('merge cells shift', function () {
  11249. it('should shift the merged cells right, when inserting a column on the left side of them', function () {
  11250. var hot = handsontable({
  11251. data: Handsontable.helper.createSpreadsheetData(20, 20),
  11252. mergeCells: [{ row: 1, col: 1, rowspan: 2, colspan: 2 }, { row: 2, col: 5, rowspan: 2, colspan: 2 }],
  11253. height: 400,
  11254. width: 400
  11255. });
  11256. hot.alter('insert_col', 3, 2);
  11257. expect(hot.mergeCells.mergedCellInfoCollection[0].col).toEqual(1);
  11258. expect(hot.mergeCells.mergedCellInfoCollection[1].col).toEqual(6);
  11259. });
  11260. it('should shift the merged cells left, when removing a column on the left side of them', function () {
  11261. var hot = handsontable({
  11262. data: Handsontable.helper.createSpreadsheetData(20, 20),
  11263. mergeCells: [{ row: 1, col: 1, rowspan: 2, colspan: 2 }, { row: 2, col: 5, rowspan: 2, colspan: 2 }],
  11264. height: 400,
  11265. width: 400
  11266. });
  11267. hot.alter('remove_col', 3, 2);
  11268. expect(hot.mergeCells.mergedCellInfoCollection[0].col).toEqual(1);
  11269. expect(hot.mergeCells.mergedCellInfoCollection[1].col).toEqual(4);
  11270. });
  11271. it('should shift the merged cells down, when inserting a row above them', function () {
  11272. var hot = handsontable({
  11273. data: Handsontable.helper.createSpreadsheetData(20, 20),
  11274. mergeCells: [{ row: 1, col: 1, rowspan: 2, colspan: 2 }, { row: 5, col: 5, rowspan: 2, colspan: 2 }],
  11275. height: 400,
  11276. width: 400
  11277. });
  11278. hot.alter('insert_row', 3, 2);
  11279. expect(hot.mergeCells.mergedCellInfoCollection[0].row).toEqual(1);
  11280. expect(hot.mergeCells.mergedCellInfoCollection[1].row).toEqual(6);
  11281. });
  11282. it('should shift the merged cells down, when inserting a row above them', function () {
  11283. var hot = handsontable({
  11284. data: Handsontable.helper.createSpreadsheetData(20, 20),
  11285. mergeCells: [{ row: 1, col: 1, rowspan: 2, colspan: 2 }, { row: 5, col: 5, rowspan: 2, colspan: 2 }],
  11286. height: 400,
  11287. width: 400
  11288. });
  11289. hot.alter('remove_row', 3, 2);
  11290. expect(hot.mergeCells.mergedCellInfoCollection[0].row).toEqual(1);
  11291. expect(hot.mergeCells.mergedCellInfoCollection[1].row).toEqual(4);
  11292. });
  11293. });
  11294. xdescribe('canMergeRange', function () {
  11295. it('should return false if start and end cell is the same', function () {
  11296. var hot = handsontable({
  11297. data: Handsontable.helper.createSpreadsheetObjectData(10, 5)
  11298. });
  11299. var mergeCells = new Handsontable.plugins.MergeCells(hot);
  11300. var coordsFrom = new WalkontableCellCoords(0, 1);
  11301. var cellRange = new WalkontableCellRange(coordsFrom, coordsFrom, new WalkontableCellCoords(0, 1));
  11302. var result = mergeCells.canMergeRange(cellRange);
  11303. expect(result).toBe(false);
  11304. });
  11305. it('should return true for 2 consecutive cells in the same column', function () {
  11306. var hot = handsontable({
  11307. data: Handsontable.helper.createSpreadsheetObjectData(10, 5)
  11308. });
  11309. var mergeCells = new Handsontable.plugins.MergeCells(hot);
  11310. var coordsFrom = new WalkontableCellCoords(0, 1);
  11311. var cellRange = new WalkontableCellRange(coordsFrom, coordsFrom, new WalkontableCellCoords(1, 1));
  11312. var result = mergeCells.canMergeRange(cellRange);
  11313. expect(result).toBe(true);
  11314. });
  11315. it('should return true for 2 consecutive cells in the same row', function () {
  11316. var hot = handsontable({
  11317. data: Handsontable.helper.createSpreadsheetObjectData(10, 5)
  11318. });
  11319. var mergeCells = new Handsontable.MergeCells(hot);
  11320. var coordsFrom = new WalkontableCellCoords(0, 1);
  11321. var cellRange = new WalkontableCellRange(coordsFrom, coordsFrom, new WalkontableCellCoords(0, 2));
  11322. var result = mergeCells.canMergeRange(cellRange);
  11323. expect(result).toBe(true);
  11324. });
  11325. it('should return true for 4 neighboring cells', function () {
  11326. var hot = handsontable({
  11327. data: Handsontable.helper.createSpreadsheetObjectData(10, 5)
  11328. });
  11329. var mergeCells = new Handsontable.MergeCells(hot);
  11330. var coordsFrom = new WalkontableCellCoords(0, 1);
  11331. var cellRange = new WalkontableCellRange(coordsFrom, coordsFrom, new WalkontableCellCoords(1, 2));
  11332. var result = mergeCells.canMergeRange(cellRange);
  11333. expect(result).toBe(true);
  11334. });
  11335. });
  11336. xdescribe('modifyTransform', function () {
  11337. it('should not transform arrow right when entering a merged cell', function () {
  11338. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11339. var coords = new WalkontableCellCoords(1, 0);
  11340. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11341. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11342. var inDelta = new WalkontableCellCoords(0, 1);
  11343. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11344. expect(inDelta).toEqual(new WalkontableCellCoords(0, 1));
  11345. });
  11346. it('should transform arrow right when leaving a merged cell', function () {
  11347. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11348. var coords = new WalkontableCellCoords(1, 1);
  11349. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11350. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11351. var inDelta = new WalkontableCellCoords(0, 1);
  11352. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11353. expect(inDelta).toEqual(new WalkontableCellCoords(0, 3));
  11354. });
  11355. it('should transform arrow right when leaving a merged cell (return to desired row)', function () {
  11356. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11357. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11358. var coords = new WalkontableCellCoords(2, 0);
  11359. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11360. var inDelta = new WalkontableCellCoords(0, 1);
  11361. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11362. expect(inDelta).toEqual(new WalkontableCellCoords(-1, 1));
  11363. coords = new WalkontableCellCoords(1, 1);
  11364. currentSelection = new WalkontableCellRange(coords, coords, coords);
  11365. inDelta = new WalkontableCellCoords(0, 1);
  11366. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11367. expect(inDelta).toEqual(new WalkontableCellCoords(1, 3));
  11368. });
  11369. it('should transform arrow left when entering a merged cell', function () {
  11370. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11371. var coords = new WalkontableCellCoords(1, 4);
  11372. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11373. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11374. var inDelta = new WalkontableCellCoords(0, -1);
  11375. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11376. expect(inDelta).toEqual(new WalkontableCellCoords(0, -3));
  11377. });
  11378. it('should not transform arrow left when leaving a merged cell', function () {
  11379. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11380. var coords = new WalkontableCellCoords(1, 1);
  11381. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11382. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11383. var inDelta = new WalkontableCellCoords(0, -1);
  11384. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11385. expect(inDelta).toEqual(new WalkontableCellCoords(0, -1));
  11386. });
  11387. it('should transform arrow left when leaving a merged cell (return to desired row)', function () {
  11388. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11389. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11390. var coords = new WalkontableCellCoords(2, 4);
  11391. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11392. var inDelta = new WalkontableCellCoords(0, -1);
  11393. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11394. expect(inDelta).toEqual(new WalkontableCellCoords(-1, -3));
  11395. coords = new WalkontableCellCoords(1, 1);
  11396. currentSelection = new WalkontableCellRange(coords, coords, coords);
  11397. inDelta = new WalkontableCellCoords(0, -1);
  11398. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11399. expect(inDelta).toEqual(new WalkontableCellCoords(1, -1));
  11400. });
  11401. it('should not transform arrow down when entering a merged cell', function () {
  11402. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11403. var coords = new WalkontableCellCoords(0, 1);
  11404. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11405. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11406. var inDelta = new WalkontableCellCoords(0, -1);
  11407. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11408. expect(inDelta).toEqual(new WalkontableCellCoords(0, -1));
  11409. });
  11410. it('should transform arrow down when leaving a merged cell', function () {
  11411. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11412. var coords = new WalkontableCellCoords(1, 1);
  11413. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11414. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11415. var inDelta = new WalkontableCellCoords(1, 0);
  11416. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11417. expect(inDelta).toEqual(new WalkontableCellCoords(3, 0));
  11418. });
  11419. it('should transform arrow up when entering a merged cell', function () {
  11420. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11421. var coords = new WalkontableCellCoords(4, 1);
  11422. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11423. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11424. var inDelta = new WalkontableCellCoords(-1, 0);
  11425. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11426. expect(inDelta).toEqual(new WalkontableCellCoords(-3, 0));
  11427. });
  11428. it('should not transform arrow up when leaving a merged cell', function () {
  11429. var mergeCellsSettings = [{ row: 1, col: 1, rowspan: 3, colspan: 3 }];
  11430. var coords = new WalkontableCellCoords(1, 1);
  11431. var currentSelection = new WalkontableCellRange(coords, coords, coords);
  11432. var mergeCells = new Handsontable.MergeCells(mergeCellsSettings);
  11433. var inDelta = new WalkontableCellCoords(-1, 0);
  11434. mergeCells.modifyTransform('modifyTransformStart', currentSelection, inDelta);
  11435. expect(inDelta).toEqual(new WalkontableCellCoords(-1, 0));
  11436. });
  11437. });
  11438. describe('ContextMenu', function () {
  11439. it('should disable `Merge cells` context menu item when context menu was triggered from corner header', function () {
  11440. var hot = handsontable({
  11441. data: Handsontable.helper.createSpreadsheetObjectData(10, 5),
  11442. rowHeaders: true,
  11443. colHeaders: true,
  11444. contextMenu: true,
  11445. mergeCells: true
  11446. });
  11447. $('.ht_clone_top_left_corner .htCore').find('thead').find('th').eq(0).simulate('mousedown', { which: 3 });
  11448. contextMenu();
  11449. expect($('.htContextMenu tbody td.htDisabled').text()).toBe(['Insert column on the left', 'Insert column on the right', 'Remove row', 'Remove column', 'Undo', 'Redo', 'Read only', 'Alignment', 'Merge cells'].join(''));
  11450. });
  11451. });
  11452. });
  11453. /***/ }),
  11454. /* 145 */
  11455. /***/ (function(module, exports, __webpack_require__) {
  11456. "use strict";
  11457. describe('HandsontableObserveChanges', function () {
  11458. var id = 'testContainer';
  11459. beforeEach(function () {
  11460. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  11461. });
  11462. afterEach(function () {
  11463. if (this.$container) {
  11464. destroy();
  11465. this.$container.remove();
  11466. }
  11467. });
  11468. function createHOT(data, observeChanges) {
  11469. return handsontable({
  11470. data: data,
  11471. width: 200,
  11472. height: 200,
  11473. observeChanges: observeChanges
  11474. });
  11475. }
  11476. describe('refreshing table after changes have been detected', function () {
  11477. describe('array data', function () {
  11478. it('should render newly added row', function (done) {
  11479. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11480. var hot = createHOT(data, true);
  11481. data.push(['A3', 'B3']);
  11482. var htCore = getHtCore();
  11483. setTimeout(function () {
  11484. expect(htCore.find('tr').length).toEqual(3);
  11485. expect(htCore.find('col').length).toEqual(2);
  11486. done();
  11487. }, 200);
  11488. });
  11489. it('should render newly added column', function (done) {
  11490. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11491. var hot = createHOT(data, true);
  11492. var htCore = getHtCore();
  11493. data[0].push('C1');
  11494. data[1].push('C2');
  11495. setTimeout(function () {
  11496. expect(htCore.find('tr').length).toEqual(2);
  11497. expect(htCore.find('col').length).toEqual(3);
  11498. done();
  11499. }, 200);
  11500. });
  11501. it('should render removed row', function (done) {
  11502. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11503. var hot = createHOT(data, true);
  11504. var htCore = getHtCore();
  11505. data.splice(0, 1); // removes one row at index 0
  11506. setTimeout(function () {
  11507. expect(htCore.find('tr').length).toEqual(1);
  11508. expect(htCore.find('col').length).toEqual(2);
  11509. done();
  11510. }, 200);
  11511. });
  11512. it('should render removed column', function (done) {
  11513. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11514. var hot = createHOT(data, true);
  11515. var htCore = getHtCore();
  11516. data[0].splice(0, 1); // removes one column at index 0 in first row
  11517. data[1].splice(0, 1); // removes one column at index 0 in second row
  11518. setTimeout(function () {
  11519. expect(htCore.find('tr').length).toEqual(2);
  11520. expect(htCore.find('col').length).toEqual(1);
  11521. done();
  11522. }, 200);
  11523. });
  11524. it('should render cell change from string to string', function (done) {
  11525. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11526. var hot = createHOT(data, true);
  11527. var htCore = getHtCore();
  11528. data[0][0] = 'new string';
  11529. setTimeout(function () {
  11530. expect(htCore.find('td:eq(0)').html()).toEqual('new string');
  11531. done();
  11532. }, 200);
  11533. });
  11534. it('should render cell change in a new row', function (done) {
  11535. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11536. var hot = createHOT(data, true);
  11537. var htCore = getHtCore();
  11538. data.push(['A3', 'B3']);
  11539. setTimeout(function () {
  11540. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  11541. data[2][0] = 'new string';
  11542. }, 200);
  11543. setTimeout(function () {
  11544. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('new string');
  11545. done();
  11546. }, 1200);
  11547. });
  11548. it('should not render cell change when turned off (`observeChanges: false`)', function (done) {
  11549. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11550. createHOT(data, false);
  11551. var htCore = getHtCore();
  11552. data[0][0] = 'new string';
  11553. setTimeout(function () {
  11554. expect(htCore.find('td:eq(0)').html()).toEqual('A1');
  11555. done();
  11556. }, 100);
  11557. });
  11558. });
  11559. describe('object data', function () {
  11560. it('should render newly added row', function (done) {
  11561. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11562. var hot = createHOT(data, true);
  11563. var htCore = getHtCore();
  11564. data.push({ prop0: 'A3', prop1: 'B3' });
  11565. setTimeout(function () {
  11566. expect(htCore.find('tr').length).toEqual(3);
  11567. expect(htCore.find('col').length).toEqual(2);
  11568. done();
  11569. }, 200);
  11570. });
  11571. it('should render removed row', function (done) {
  11572. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11573. var hot = createHOT(data, true);
  11574. var htCore = getHtCore();
  11575. data.splice(0, 1); // removes one row at index 0
  11576. setTimeout(function () {
  11577. expect(htCore.find('tr').length).toEqual(1);
  11578. expect(htCore.find('col').length).toEqual(2);
  11579. done();
  11580. }, 200);
  11581. });
  11582. it('should render cell change from string to string', function (done) {
  11583. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11584. var hot = createHOT(data, true);
  11585. var htCore = getHtCore();
  11586. data[0].prop0 = 'new string';
  11587. setTimeout(function () {
  11588. expect(htCore.find('td:eq(0)').html()).toEqual('new string');
  11589. done();
  11590. }, 200);
  11591. });
  11592. it('should render cell change in a new row', function (done) {
  11593. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11594. var hot = createHOT(data, true);
  11595. var htCore = getHtCore();
  11596. data.push({ prop0: 'A3', prop1: 'B3' });
  11597. setTimeout(function () {
  11598. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  11599. data[2].prop0 = 'new string';
  11600. }, 200);
  11601. setTimeout(function () {
  11602. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('new string');
  11603. done();
  11604. }, 1200);
  11605. });
  11606. it('should not break with undefined data properties', function () {
  11607. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11608. data[0].prop0 = undefined;
  11609. expect(function () {
  11610. var hot = createHOT(data, true);
  11611. var htCore = getHtCore();
  11612. }).not.toThrow();
  11613. });
  11614. it('should not render cell change when turned off (`observeChanges: false`)', function (done) {
  11615. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11616. createHOT(data, false);
  11617. var htCore = getHtCore();
  11618. data[0].prop0 = 'new string';
  11619. setTimeout(function () {
  11620. expect(htCore.find('td:eq(0)').html()).toEqual('A1');
  11621. done();
  11622. }, 200);
  11623. });
  11624. });
  11625. });
  11626. describe('enabling/disabling plugin', function () {
  11627. it('should be possible to enable plugin using updateSettings', function (done) {
  11628. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11629. var hot = createHOT(data, false);
  11630. var htCore = getHtCore();
  11631. data[0][0] = 'new string';
  11632. setTimeout(function () {
  11633. expect(htCore.find('td:eq(0)').html()).toEqual('A1');
  11634. updateSettings({
  11635. observeChanges: true
  11636. });
  11637. data[1][0] = 'another new string';
  11638. }, 200);
  11639. setTimeout(function () {
  11640. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('another new string');
  11641. done();
  11642. }, 400);
  11643. });
  11644. it('should be possible to disable plugin using updateSettings', function (done) {
  11645. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11646. var hot = createHOT(data, true);
  11647. var htCore = getHtCore();
  11648. data[0][0] = 'new string';
  11649. setTimeout(function () {
  11650. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('new string');
  11651. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('A2');
  11652. updateSettings({
  11653. observeChanges: false
  11654. });
  11655. data[1][0] = 'another new string';
  11656. }, 200);
  11657. setTimeout(function () {
  11658. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('new string');
  11659. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('A2');
  11660. hot.render();
  11661. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('new string');
  11662. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('another new string');
  11663. done();
  11664. }, 300);
  11665. });
  11666. it('should be possible to pause observing changes without disabling the plugin', function (done) {
  11667. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11668. var hot = createHOT(data, true);
  11669. var htCore = getHtCore();
  11670. data[0][0] = 'new string';
  11671. setTimeout(function () {
  11672. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('new string');
  11673. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('A2');
  11674. hot.pauseObservingChanges();
  11675. data[1][0] = 'another new string';
  11676. }, 200);
  11677. setTimeout(function () {
  11678. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('new string');
  11679. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('A2');
  11680. hot.render();
  11681. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('new string');
  11682. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('another new string');
  11683. done();
  11684. }, 300);
  11685. });
  11686. it('should be possible to resume observing changes after it was paused', function (done) {
  11687. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11688. var hot = createHOT(data, true);
  11689. var htCore = getHtCore();
  11690. hot.pauseObservingChanges();
  11691. data[0][0] = 'new string';
  11692. setTimeout(function () {
  11693. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('A1');
  11694. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('A2');
  11695. hot.resumeObservingChanges();
  11696. data[1][0] = 'another new string';
  11697. }, 100);
  11698. setTimeout(function () {
  11699. expect(htCore.find('tbody tr:eq(0) td:eq(0)').html()).toEqual('new string');
  11700. expect(htCore.find('tbody tr:eq(1) td:eq(0)').html()).toEqual('another new string');
  11701. done();
  11702. }, 1200);
  11703. });
  11704. });
  11705. describe('observeChanges fires appropriate events when changes are detected', function () {
  11706. describe('array data', function () {
  11707. it('should fire afterChangesObserved event after changes has been noticed', function (done) {
  11708. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11709. var hot = createHOT(data, true);
  11710. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  11711. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  11712. data[0][0] = 'new string';
  11713. setTimeout(function () {
  11714. expect(afterChangesObservedCallback.calls.count()).toEqual(1);
  11715. done();
  11716. }, 200);
  11717. });
  11718. it('should fire afterCreateRow event after detecting that new row has been added', function (done) {
  11719. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11720. var hot = createHOT(data, true);
  11721. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  11722. hot.addHook('afterCreateRow', afterCreateRowCallback);
  11723. data.push(['A2', 'B2']);
  11724. setTimeout(function () {
  11725. expect(afterCreateRowCallback.calls.count()).toEqual(1);
  11726. expect(afterCreateRowCallback).toHaveBeenCalledWith(2, 1, 'ObserveChanges.change', undefined, undefined, undefined);
  11727. done();
  11728. }, 200);
  11729. });
  11730. it('should fire afterRemoveRow event after detecting that row has been removed', function (done) {
  11731. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11732. var hot = createHOT(data, true);
  11733. var afterRemoveRowCallback = jasmine.createSpy('afterRemoveRowCallback');
  11734. hot.addHook('afterRemoveRow', afterRemoveRowCallback);
  11735. data.pop();
  11736. setTimeout(function () {
  11737. expect(afterRemoveRowCallback.calls.count()).toEqual(1);
  11738. expect(afterRemoveRowCallback).toHaveBeenCalledWith(1, 1, 'ObserveChanges.change', undefined, undefined, undefined);
  11739. done();
  11740. }, 200);
  11741. });
  11742. it('should fire afterRemoveRow event after detecting that multiple rows have been removed', function (done) {
  11743. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11744. var hot = createHOT(data, true);
  11745. var afterRemoveRowCallback = jasmine.createSpy('afterRemoveRowCallback');
  11746. hot.addHook('afterRemoveRow', afterRemoveRowCallback);
  11747. data.splice(0, 2);
  11748. setTimeout(function () {
  11749. expect(afterRemoveRowCallback.calls.count()).toEqual(2);
  11750. // The order of run hooks depends on whether objectObserve uses native Object.observe or a shim
  11751. var args = [];
  11752. args.push(afterRemoveRowCallback.calls.argsFor(0));
  11753. args.push(afterRemoveRowCallback.calls.argsFor(1));
  11754. expect(args).toContain([1, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11755. expect(args).toContain([0, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11756. done();
  11757. }, 200);
  11758. });
  11759. it('should fire afterCreateCol event after detecting that new col has been added', function (done) {
  11760. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11761. var hot = createHOT(data, true);
  11762. var afterCreateColCallback = jasmine.createSpy('afterCreateColCallback');
  11763. hot.addHook('afterCreateCol', afterCreateColCallback);
  11764. data[0].push('C1');
  11765. data[1].push('C2');
  11766. setTimeout(function () {
  11767. expect(afterCreateColCallback.calls.count()).toEqual(1);
  11768. expect(afterCreateColCallback.calls.argsFor(0)).toEqual([2, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11769. done();
  11770. }, 200);
  11771. });
  11772. it('should fire afterRemoveCol event after detecting that col has been removed', function (done) {
  11773. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11774. var hot = createHOT(data, true);
  11775. var afterRemoveColCallback = jasmine.createSpy('afterRemoveColCallback');
  11776. hot.addHook('afterRemoveCol', afterRemoveColCallback);
  11777. data[0].pop();
  11778. data[1].pop();
  11779. setTimeout(function () {
  11780. expect(afterRemoveColCallback.calls.count()).toEqual(1);
  11781. expect(afterRemoveColCallback.calls.argsFor(0)).toEqual([1, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11782. done();
  11783. }, 200);
  11784. });
  11785. it('should fire afterRemoveCol event after detecting that multiple cols have been removed', function (done) {
  11786. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11787. var hot = createHOT(data, true);
  11788. var afterRemoveColCallback = jasmine.createSpy('afterRemoveColCallback');
  11789. hot.addHook('afterRemoveCol', afterRemoveColCallback);
  11790. data[0].pop();
  11791. data[0].pop();
  11792. data[1].pop();
  11793. data[1].pop();
  11794. setTimeout(function () {
  11795. expect(afterRemoveColCallback.calls.count()).toEqual(2);
  11796. // The order of run hooks depends on whether objectObserve uses native Object.observe or a shim
  11797. var args = [];
  11798. args.push(afterRemoveColCallback.calls.argsFor(0));
  11799. args.push(afterRemoveColCallback.calls.argsFor(1));
  11800. expect(args).toContain([1, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11801. expect(args).toContain([0, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11802. done();
  11803. }, 200);
  11804. });
  11805. it('should fire afterChange event after detecting that table data has changed', function (done) {
  11806. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11807. var hot = createHOT(data, true);
  11808. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  11809. hot.addHook('afterChange', afterChangeCallback);
  11810. data[0][0] = 'new string';
  11811. setTimeout(function () {
  11812. expect(afterChangeCallback.calls.count()).toEqual(1);
  11813. expect(afterChangeCallback).toHaveBeenCalledWith([0, 0, null, 'new string'], 'ObserveChanges.change', undefined, undefined, undefined, undefined);
  11814. done();
  11815. }, 200);
  11816. });
  11817. });
  11818. describe('object data', function () {
  11819. it('should fire afterChangesObserved event after changes has been noticed', function (done) {
  11820. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11821. var hot = createHOT(data, true);
  11822. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  11823. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  11824. data[0].prop0 = 'new string';
  11825. setTimeout(function () {
  11826. expect(afterChangesObservedCallback.calls.count()).toEqual(1);
  11827. done();
  11828. }, 200);
  11829. });
  11830. it('should fire afterCreateRow event after detecting that new row has been added', function (done) {
  11831. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11832. var hot = createHOT(data, true);
  11833. var afterCreateRowCallback = jasmine.createSpy('afterCreateRowCallback');
  11834. hot.addHook('afterCreateRow', afterCreateRowCallback);
  11835. data.push({ prop0: 'A2', prop1: 'B2' });
  11836. setTimeout(function () {
  11837. expect(afterCreateRowCallback.calls.count()).toEqual(1);
  11838. expect(afterCreateRowCallback).toHaveBeenCalledWith(2, 1, 'ObserveChanges.change', undefined, undefined, undefined);
  11839. done();
  11840. }, 200);
  11841. });
  11842. it('should fire afterRemoveRow event after detecting that row has been removed', function (done) {
  11843. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11844. var hot = createHOT(data, true);
  11845. var afterRemoveRowCallback = jasmine.createSpy('afterRemoveRowCallback');
  11846. hot.addHook('afterRemoveRow', afterRemoveRowCallback);
  11847. data.pop();
  11848. setTimeout(function () {
  11849. expect(afterRemoveRowCallback.calls.count()).toEqual(1);
  11850. expect(afterRemoveRowCallback).toHaveBeenCalledWith(1, 1, 'ObserveChanges.change', undefined, undefined, undefined);
  11851. done();
  11852. }, 200);
  11853. });
  11854. it('should fire afterRemoveRow event after detecting that multiple rows have been removed', function (done) {
  11855. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11856. var hot = createHOT(data, true);
  11857. var afterRemoveRowCallback = jasmine.createSpy('afterRemoveRowCallback');
  11858. hot.addHook('afterRemoveRow', afterRemoveRowCallback);
  11859. data.splice(0, 2);
  11860. setTimeout(function () {
  11861. expect(afterRemoveRowCallback.calls.count()).toEqual(2);
  11862. // The order of run hooks depends on whether objectObserve uses native Object.observe or a shim
  11863. var args = [];
  11864. args.push(afterRemoveRowCallback.calls.argsFor(0));
  11865. args.push(afterRemoveRowCallback.calls.argsFor(1));
  11866. expect(args).toContain([1, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11867. expect(args).toContain([0, 1, 'ObserveChanges.change', undefined, undefined, undefined]);
  11868. done();
  11869. }, 200);
  11870. });
  11871. it('should fire afterChange event after detecting that table data has changed', function (done) {
  11872. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11873. var hot = createHOT(data, true);
  11874. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  11875. hot.addHook('afterChange', afterChangeCallback);
  11876. data[0].prop0 = 'new string';
  11877. setTimeout(function () {
  11878. expect(afterChangeCallback.calls.count()).toEqual(1);
  11879. expect(afterChangeCallback).toHaveBeenCalledWith([0, 'prop0', null, 'new string'], 'ObserveChanges.change', undefined, undefined, undefined, undefined);
  11880. done();
  11881. }, 200);
  11882. });
  11883. });
  11884. });
  11885. describe('using HOT data manipulation methods, when observeChanges plugin is enabled', function () {
  11886. describe('array data', function () {
  11887. it('should run render ONCE after detecting that new row has been added', function (done) {
  11888. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11889. var hot = createHOT(data, true);
  11890. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11891. hot.addHook('afterRender', afterRenderSpy);
  11892. alter('insert_row');
  11893. setTimeout(function () {
  11894. expect(countRows()).toEqual(3);
  11895. expect(afterRenderSpy.calls.count()).toEqual(1);
  11896. done();
  11897. }, 200);
  11898. });
  11899. it('should run render ONCE after detecting that row has been removed', function (done) {
  11900. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11901. var hot = createHOT(data, true);
  11902. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11903. hot.addHook('afterRender', afterRenderSpy);
  11904. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  11905. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  11906. alter('remove_row');
  11907. setTimeout(function () {
  11908. expect(countRows()).toEqual(1);
  11909. expect(afterChangesObservedCallback.calls.count()).toEqual(1);
  11910. expect(afterRenderSpy.calls.count()).toEqual(1);
  11911. done();
  11912. }, 200);
  11913. });
  11914. it('should run render ONCE after detecting that new column has been added', function (done) {
  11915. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11916. var hot = createHOT(data, true);
  11917. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11918. hot.addHook('afterRender', afterRenderSpy);
  11919. alter('insert_col');
  11920. setTimeout(function () {
  11921. expect(countCols()).toEqual(3);
  11922. expect(afterRenderSpy.calls.count()).toEqual(1);
  11923. done();
  11924. }, 200);
  11925. });
  11926. it('should run render ONCE after detecting that column has been removed', function (done) {
  11927. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11928. var hot = createHOT(data, true);
  11929. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11930. hot.addHook('afterRender', afterRenderSpy);
  11931. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  11932. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  11933. alter('remove_col');
  11934. setTimeout(function () {
  11935. expect(countCols()).toEqual(1);
  11936. expect(afterChangesObservedCallback.calls.count()).toEqual(1);
  11937. expect(afterRenderSpy.calls.count()).toEqual(1);
  11938. done();
  11939. }, 200);
  11940. });
  11941. it('should run render ONCE after detecting that table data has changed', function (done) {
  11942. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  11943. var hot = createHOT(data, true);
  11944. var htCore = getHtCore();
  11945. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11946. hot.addHook('afterRender', afterRenderSpy);
  11947. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  11948. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  11949. setDataAtCell(0, 0, 'new value');
  11950. setTimeout(function () {
  11951. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('new value');
  11952. expect(afterChangesObservedCallback.calls.count()).toEqual(1);
  11953. expect(afterRenderSpy.calls.count()).toEqual(1);
  11954. done();
  11955. }, 200);
  11956. });
  11957. });
  11958. describe('object data', function () {
  11959. it('should run render ONCE after detecting that new row has been added', function (done) {
  11960. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11961. var hot = createHOT(data, true);
  11962. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11963. hot.addHook('afterRender', afterRenderSpy);
  11964. alter('insert_row');
  11965. setTimeout(function () {
  11966. expect(countRows()).toEqual(3);
  11967. expect(afterRenderSpy.calls.count()).toEqual(1);
  11968. done();
  11969. }, 200);
  11970. });
  11971. it('should run render ONCE after detecting that row has been removed', function (done) {
  11972. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11973. var hot = createHOT(data, true);
  11974. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11975. hot.addHook('afterRender', afterRenderSpy);
  11976. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  11977. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  11978. alter('remove_row');
  11979. setTimeout(function () {
  11980. expect(countRows()).toEqual(1);
  11981. expect(afterChangesObservedCallback.calls.count()).toEqual(1);
  11982. expect(afterRenderSpy.calls.count()).toEqual(1);
  11983. done();
  11984. }, 200);
  11985. });
  11986. it('should run render ONCE after detecting that table data has changed', function (done) {
  11987. var data = Handsontable.helper.createSpreadsheetObjectData(2, 2);
  11988. var hot = createHOT(data, true);
  11989. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  11990. hot.addHook('afterRender', afterRenderSpy);
  11991. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  11992. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  11993. setDataAtRowProp(0, 'prop0', 'new value');
  11994. setTimeout(function () {
  11995. expect(spec().$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('new value');
  11996. expect(afterChangesObservedCallback.calls.count()).toEqual(1);
  11997. expect(afterRenderSpy.calls.count()).toEqual(1);
  11998. done();
  11999. }, 200);
  12000. });
  12001. });
  12002. });
  12003. describe('refreshing table after changes have been detected', function () {
  12004. it('should observe changes to new data bound using loadData', function (done) {
  12005. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  12006. var newData = Handsontable.helper.createSpreadsheetData(2, 2);
  12007. var hot = createHOT(data, true);
  12008. var htCore = getHtCore();
  12009. hot.loadData(newData);
  12010. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  12011. hot.addHook('afterRender', afterRenderSpy);
  12012. newData.push(['A3', 'B3']);
  12013. setTimeout(function () {
  12014. expect(afterRenderSpy.calls.count()).toBe(1);
  12015. expect(htCore.find('tr').length).toEqual(3);
  12016. expect(htCore.find('col').length).toEqual(2);
  12017. done();
  12018. }, 200);
  12019. });
  12020. it('should not observe changes to old data after it was replaced using loadData', function (done) {
  12021. var data = Handsontable.helper.createSpreadsheetData(2, 2);
  12022. var newData = Handsontable.helper.createSpreadsheetData(2, 2);
  12023. var hot = createHOT(data, true);
  12024. var htCore = getHtCore();
  12025. hot.loadData(newData);
  12026. var afterRenderSpy = jasmine.createSpy('afterRenderSpy');
  12027. hot.addHook('afterRender', afterRenderSpy);
  12028. data.push(['A3', 'B3']);
  12029. setTimeout(function () {
  12030. expect(afterRenderSpy.calls.count()).toBe(0);
  12031. expect(htCore.find('tr').length).toEqual(2);
  12032. expect(htCore.find('col').length).toEqual(2);
  12033. done();
  12034. }, 1000);
  12035. });
  12036. });
  12037. });
  12038. /***/ }),
  12039. /* 146 */
  12040. /***/ (function(module, exports, __webpack_require__) {
  12041. "use strict";
  12042. describe('persistentState', function () {
  12043. var id = 'testContainer';
  12044. beforeEach(function () {
  12045. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  12046. });
  12047. afterEach(function () {
  12048. if (this.$container) {
  12049. destroy();
  12050. this.$container.remove();
  12051. }
  12052. window.localStorage.clear();
  12053. });
  12054. it('should save data, when persistentStateSave is run', function () {
  12055. var hot = handsontable({
  12056. persistentState: true
  12057. });
  12058. hot.runHooks('persistentStateSave', 'testData', 100);
  12059. var rawStoredData = window.localStorage[id + '_testData'];
  12060. expect(rawStoredData).toBeDefined();
  12061. var storedData = JSON.parse(rawStoredData);
  12062. expect(storedData).toEqual(100);
  12063. });
  12064. it('should NOT save data, when persistentStateSave is run, if plugin is not enabled', function () {
  12065. var hot = handsontable({
  12066. persistentState: false
  12067. });
  12068. hot.runHooks('persistentStateSave', 'testData', 100);
  12069. var rawStoredData = window.localStorage[id + '_testData'];
  12070. expect(rawStoredData).toBeUndefined();
  12071. });
  12072. it('should load data, when persistentStateLoad is run', function () {
  12073. var hot = handsontable({
  12074. persistentState: true
  12075. });
  12076. hot.runHooks('persistentStateSave', 'testData', 100);
  12077. var storedData = {};
  12078. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12079. expect(storedData.value).toEqual(100);
  12080. });
  12081. it('should NOT load data, when persistentStateLoad is run, if plugin is not enabled', function () {
  12082. var hot = handsontable({
  12083. persistentState: false
  12084. });
  12085. // We have to manually save data, as persistentStateSave won't work when the plugin is disabled
  12086. window.localStorage[id + '_testData'] = JSON.stringify(100);
  12087. var storedData = {};
  12088. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12089. expect(storedData.value).toBeUndefined();
  12090. });
  12091. it('should clear the data under the given key, when persistentStateReset is run', function () {
  12092. var hot = handsontable({
  12093. persistentState: true
  12094. });
  12095. hot.runHooks('persistentStateSave', 'testData', 100);
  12096. var storedData = {};
  12097. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12098. expect(storedData.value).toEqual(100);
  12099. hot.runHooks('persistentStateReset', 'testData');
  12100. storedData = {};
  12101. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12102. expect(storedData.value).toBeUndefined();
  12103. });
  12104. it('should NOT clear the data under the given key, when persistentStateReset is run', function () {
  12105. var hot = handsontable({
  12106. persistentState: false
  12107. });
  12108. // We have to manually save data, as persistentStateSave won't work when the plugin is disabled
  12109. window.localStorage[id + '_testData'] = JSON.stringify(100);
  12110. var storedData = {};
  12111. hot.runHooks('persistentStateReset', 'testData');
  12112. expect(JSON.parse(window.localStorage[id + '_testData'])).toEqual(100);
  12113. });
  12114. it('should clear all data, when persistentStateReset is run without specifying a key to reset', function () {
  12115. var hot = handsontable({
  12116. persistentState: true
  12117. });
  12118. hot.runHooks('persistentStateSave', 'testData0', 100);
  12119. hot.runHooks('persistentStateSave', 'testData1', 'foo');
  12120. hot.runHooks('persistentStateSave', 'testData2', 200);
  12121. var storedData = [{}, {}, {}];
  12122. hot.runHooks('persistentStateLoad', 'testData0', storedData[0]);
  12123. hot.runHooks('persistentStateLoad', 'testData1', storedData[1]);
  12124. hot.runHooks('persistentStateLoad', 'testData2', storedData[2]);
  12125. expect(storedData[0].value).toEqual(100);
  12126. expect(storedData[1].value).toEqual('foo');
  12127. expect(storedData[2].value).toEqual(200);
  12128. hot.runHooks('persistentStateReset');
  12129. storedData = [{}, {}, {}];
  12130. hot.runHooks('persistentStateLoad', 'testData0', storedData[0]);
  12131. hot.runHooks('persistentStateLoad', 'testData1', storedData[1]);
  12132. hot.runHooks('persistentStateLoad', 'testData2', storedData[2]);
  12133. expect(storedData[0].value).toBeUndefined();
  12134. expect(storedData[1].value).toBeUndefined();
  12135. expect(storedData[2].value).toBeUndefined();
  12136. });
  12137. it('should allow to DISABLE plugin with updateSettings', function () {
  12138. var hot = handsontable({
  12139. persistentState: true
  12140. });
  12141. hot.runHooks('persistentStateSave', 'testData', 100);
  12142. var storedData = {};
  12143. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12144. expect(storedData.value).toEqual(100);
  12145. updateSettings({
  12146. persistentState: false
  12147. });
  12148. storedData = {};
  12149. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12150. expect(storedData.value).toBeUndefined();
  12151. });
  12152. it('should allow to ENABLE plugin with updateSettings', function () {
  12153. var hot = handsontable({
  12154. persistentState: false
  12155. });
  12156. hot.runHooks('persistentStateSave', 'testData', 100);
  12157. var storedData = {};
  12158. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12159. expect(storedData.value).toBeUndefined();
  12160. updateSettings({
  12161. persistentState: true
  12162. });
  12163. hot.runHooks('persistentStateSave', 'testData', 100);
  12164. storedData = {};
  12165. hot.runHooks('persistentStateLoad', 'testData', storedData);
  12166. expect(storedData.value).toEqual(100);
  12167. });
  12168. });
  12169. /***/ }),
  12170. /* 147 */
  12171. /***/ (function(module, exports, __webpack_require__) {
  12172. "use strict";
  12173. describe('Search plugin', function () {
  12174. var id = 'testContainer';
  12175. beforeEach(function () {
  12176. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  12177. });
  12178. afterEach(function () {
  12179. if (this.$container) {
  12180. destroy();
  12181. this.$container.remove();
  12182. }
  12183. });
  12184. describe('enabling/disabling plugin', function () {
  12185. it('should expose `search` object when plugin is enabled', function () {
  12186. var hot = handsontable({
  12187. search: true
  12188. });
  12189. expect(hot.search).toBeDefined();
  12190. });
  12191. it('should NOT expose `search` object when plugin is disabled', function () {
  12192. var hot = handsontable({
  12193. search: false
  12194. });
  12195. expect(hot.search).not.toBeDefined();
  12196. });
  12197. it('plugin should be disabled by default', function () {
  12198. var hot = handsontable();
  12199. expect(hot.search).not.toBeDefined();
  12200. });
  12201. it('should disable plugin using updateSettings', function () {
  12202. var hot = handsontable({
  12203. search: true
  12204. });
  12205. expect(hot.search).toBeDefined();
  12206. updateSettings({
  12207. search: false
  12208. });
  12209. expect(hot.search).not.toBeDefined();
  12210. });
  12211. it('should enable plugin using updateSettings', function () {
  12212. var hot = handsontable({
  12213. search: false
  12214. });
  12215. expect(hot.search).not.toBeDefined();
  12216. updateSettings({
  12217. search: true
  12218. });
  12219. expect(hot.search).toBeDefined();
  12220. });
  12221. });
  12222. describe('query method', function () {
  12223. afterEach(function () {
  12224. Handsontable.plugins.Search.global.setDefaultQueryMethod(Handsontable.plugins.Search.DEFAULT_QUERY_METHOD);
  12225. });
  12226. it('should use the default query method if no queryMethod is passed to query function', function () {
  12227. spyOn(Handsontable.plugins.Search, 'DEFAULT_QUERY_METHOD');
  12228. var defaultQueryMethod = Handsontable.plugins.Search.DEFAULT_QUERY_METHOD;
  12229. Handsontable.plugins.Search.global.setDefaultQueryMethod(defaultQueryMethod);
  12230. var hot = handsontable({
  12231. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12232. search: true
  12233. });
  12234. var searchResult = hot.search.query('A');
  12235. expect(defaultQueryMethod.calls.count()).toEqual(25);
  12236. });
  12237. it('should use the custom default query method if no queryMethod is passed to query function', function () {
  12238. var customDefaultQueryMethod = jasmine.createSpy('customDefaultQueryMethod');
  12239. var hot = handsontable({
  12240. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12241. search: true
  12242. });
  12243. Handsontable.plugins.Search.global.setDefaultQueryMethod(customDefaultQueryMethod);
  12244. var searchResult = hot.search.query('A');
  12245. expect(customDefaultQueryMethod.calls.count()).toEqual(25);
  12246. });
  12247. it('should use the query method from the constructor if no queryMethod is passed to query function', function () {
  12248. var customQueryMethod = jasmine.createSpy('customDefaultQueryMethod');
  12249. var hot = handsontable({
  12250. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12251. search: {
  12252. queryMethod: customQueryMethod
  12253. }
  12254. });
  12255. var searchResult = hot.search.query('A');
  12256. expect(customQueryMethod.calls.count()).toEqual(25);
  12257. });
  12258. it('should use method passed to query function', function () {
  12259. var customQueryMethod = jasmine.createSpy('customQueryMethod');
  12260. var hot = handsontable({
  12261. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12262. search: true
  12263. });
  12264. var searchResult = hot.search.query('A', null, customQueryMethod);
  12265. expect(customQueryMethod.calls.count()).toEqual(25);
  12266. });
  12267. });
  12268. describe('default query method', function () {
  12269. it('should use query method to find phrase', function () {
  12270. var hot = handsontable({
  12271. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12272. search: true
  12273. });
  12274. var searchResult = hot.search.query('A');
  12275. expect(searchResult.length).toEqual(5);
  12276. for (var i = 0; i < searchResult.length; i++) {
  12277. expect(searchResult[i].row).toEqual(i);
  12278. expect(searchResult[i].col).toEqual(0);
  12279. expect(searchResult[i].data).toEqual(hot.getDataAtCell(i, 0));
  12280. }
  12281. });
  12282. it('default query method should be case insensitive', function () {
  12283. var hot = handsontable({
  12284. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12285. search: true
  12286. });
  12287. var searchResult = hot.search.query('a');
  12288. expect(searchResult.length).toEqual(5);
  12289. searchResult = hot.search.query('A');
  12290. expect(searchResult.length).toEqual(5);
  12291. });
  12292. it('default query method should work with numeric values', function () {
  12293. var hot = handsontable({
  12294. data: [[1, 2], [22, 4]],
  12295. search: true
  12296. });
  12297. var searchResult = hot.search.query('2');
  12298. expect(searchResult.length).toEqual(2);
  12299. });
  12300. it('default query method should interpret query as string, not regex', function () {
  12301. var hot = handsontable({
  12302. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12303. search: true
  12304. });
  12305. var searchResult = hot.search.query('A*');
  12306. expect(searchResult.length).toEqual(0);
  12307. });
  12308. it('default query method should always return false if query string is empty', function () {
  12309. var hot = handsontable({
  12310. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12311. search: true
  12312. });
  12313. var searchResult = hot.search.query('A');
  12314. expect(searchResult.length).toEqual(5);
  12315. searchResult = hot.search.query('');
  12316. expect(searchResult.length).toEqual(0);
  12317. });
  12318. it('default query method should always return false if no query string has been specified', function () {
  12319. var hot = handsontable({
  12320. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12321. search: true
  12322. });
  12323. var searchResult = hot.search.query('A');
  12324. expect(searchResult.length).toEqual(5);
  12325. searchResult = hot.search.query();
  12326. expect(searchResult.length).toEqual(0);
  12327. });
  12328. it('default query method should always return false if no query string is not a string', function () {
  12329. var hot = handsontable({
  12330. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12331. search: true
  12332. });
  12333. var searchResult = hot.search.query('A');
  12334. expect(searchResult.length).toEqual(5);
  12335. searchResult = hot.search.query([1, 2, 3]);
  12336. expect(searchResult.length).toEqual(0);
  12337. });
  12338. });
  12339. describe('search callback', function () {
  12340. afterEach(function () {
  12341. Handsontable.plugins.Search.global.setDefaultCallback(Handsontable.plugins.Search.DEFAULT_CALLBACK);
  12342. });
  12343. it('should invoke default callback for each cell', function () {
  12344. spyOn(Handsontable.plugins.Search, 'DEFAULT_CALLBACK');
  12345. var defaultCallback = Handsontable.plugins.Search.DEFAULT_CALLBACK;
  12346. Handsontable.plugins.Search.global.setDefaultCallback(defaultCallback);
  12347. var hot = handsontable({
  12348. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12349. search: true
  12350. });
  12351. var searchResult = hot.search.query('A');
  12352. expect(defaultCallback.calls.count()).toEqual(25);
  12353. });
  12354. it('should change the default callback', function () {
  12355. spyOn(Handsontable.plugins.Search, 'DEFAULT_CALLBACK');
  12356. var hot = handsontable({
  12357. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12358. search: true
  12359. });
  12360. var defaultCallback = jasmine.createSpy('defaultCallback');
  12361. Handsontable.plugins.Search.global.setDefaultCallback(defaultCallback);
  12362. var searchResult = hot.search.query('A');
  12363. expect(Handsontable.plugins.Search.DEFAULT_CALLBACK).not.toHaveBeenCalled();
  12364. expect(defaultCallback.calls.count()).toEqual(25);
  12365. });
  12366. it('should invoke callback passed in constructor', function () {
  12367. var searchCallback = jasmine.createSpy('searchCallback');
  12368. var hot = handsontable({
  12369. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12370. search: {
  12371. callback: searchCallback
  12372. }
  12373. });
  12374. var searchResult = hot.search.query('A');
  12375. expect(searchCallback.calls.count()).toEqual(25);
  12376. });
  12377. it('should invoke custom callback for each cell which has been tested', function () {
  12378. var hot = handsontable({
  12379. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12380. search: true
  12381. });
  12382. var searchCallback = jasmine.createSpy('searchCallback');
  12383. var searchResult = hot.search.query('A', searchCallback);
  12384. expect(searchCallback.calls.count()).toEqual(25);
  12385. for (var rowIndex = 0, rowCount = countRows(); rowIndex < rowCount; rowIndex++) {
  12386. for (var colIndex = 0, colCount = countCols(); colIndex < colCount; colIndex++) {
  12387. var callArgs = searchCallback.calls.argsFor(rowIndex * 5 + colIndex);
  12388. expect(callArgs[0]).toEqual(hot);
  12389. expect(callArgs[1]).toEqual(rowIndex);
  12390. expect(callArgs[2]).toEqual(colIndex);
  12391. expect(callArgs[3]).toEqual(hot.getDataAtCell(rowIndex, colIndex));
  12392. if (colIndex == 0) {
  12393. expect(callArgs[4]).toBe(true);
  12394. } else {
  12395. expect(callArgs[4]).toBe(false);
  12396. }
  12397. }
  12398. }
  12399. });
  12400. });
  12401. describe('default search callback', function () {
  12402. it('should add isSearchResult = true, to cell properties of all matched cells', function () {
  12403. var hot = handsontable({
  12404. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12405. search: true
  12406. });
  12407. var searchResult = hot.search.query('2');
  12408. for (var rowIndex = 0, rowCount = countRows(); rowIndex < rowCount; rowIndex++) {
  12409. for (var colIndex = 0, colCount = countCols(); colIndex < colCount; colIndex++) {
  12410. var cellProperties = getCellMeta(rowIndex, colIndex);
  12411. if (rowIndex == 1) {
  12412. expect(cellProperties.isSearchResult).toBeTruthy();
  12413. } else {
  12414. expect(cellProperties.isSearchResult).toBeFalsy();
  12415. }
  12416. }
  12417. }
  12418. });
  12419. });
  12420. describe('search result decorator', function () {
  12421. it('should add default search result class to cells which mach the query', function () {
  12422. var hot = handsontable({
  12423. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12424. search: true
  12425. });
  12426. var searchResult = hot.search.query('2');
  12427. render();
  12428. for (var rowIndex = 0, rowCount = countRows(); rowIndex < rowCount; rowIndex++) {
  12429. for (var colIndex = 0, colCount = countCols(); colIndex < colCount; colIndex++) {
  12430. var cell = getCell(rowIndex, colIndex);
  12431. if (rowIndex == 1) {
  12432. expect($(cell).hasClass(Handsontable.plugins.Search.DEFAULT_SEARCH_RESULT_CLASS)).toBe(true);
  12433. } else {
  12434. expect($(cell).hasClass(Handsontable.plugins.Search.DEFAULT_SEARCH_RESULT_CLASS)).toBe(false);
  12435. }
  12436. }
  12437. }
  12438. });
  12439. it('should add custom search result class to cells which mach the query', function () {
  12440. var hot = handsontable({
  12441. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12442. search: {
  12443. searchResultClass: 'customSearchResultClass'
  12444. }
  12445. });
  12446. var searchResult = hot.search.query('2');
  12447. render();
  12448. for (var rowIndex = 0, rowCount = countRows(); rowIndex < rowCount; rowIndex++) {
  12449. for (var colIndex = 0, colCount = countCols(); colIndex < colCount; colIndex++) {
  12450. var cell = getCell(rowIndex, colIndex);
  12451. if (rowIndex == 1) {
  12452. expect($(cell).hasClass('customSearchResultClass')).toBe(true);
  12453. } else {
  12454. expect($(cell).hasClass('customSearchResultClass')).toBe(false);
  12455. }
  12456. }
  12457. }
  12458. });
  12459. });
  12460. describe('HOT properties compatibility', function () {
  12461. it('should work properly when the last row is empty', function () {
  12462. // connected with https://github.com/handsontable/handsontable/issues/1606
  12463. var hot = handsontable({
  12464. data: Handsontable.helper.createSpreadsheetData(5, 5),
  12465. colHeaders: true,
  12466. search: true,
  12467. minSpareRows: 1
  12468. }),
  12469. errorThrown = false;
  12470. try {
  12471. hot.search.query('A');
  12472. } catch (err) {
  12473. errorThrown = true;
  12474. }
  12475. expect(errorThrown).toBe(false);
  12476. });
  12477. });
  12478. });
  12479. /***/ }),
  12480. /* 148 */
  12481. /***/ (function(module, exports, __webpack_require__) {
  12482. "use strict";
  12483. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  12484. describe('UndoRedo', function () {
  12485. var id = 'testContainer';
  12486. beforeEach(function () {
  12487. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  12488. });
  12489. afterEach(function () {
  12490. if (this.$container) {
  12491. destroy();
  12492. this.$container.remove();
  12493. }
  12494. });
  12495. describe('core features', function () {
  12496. describe('Array data', function () {
  12497. describe('undo', function () {
  12498. it('should undo single change', function () {
  12499. handsontable({
  12500. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12501. });
  12502. var HOT = getInstance();
  12503. setDataAtCell(0, 0, 'X1');
  12504. expect(getDataAtCell(0, 0)).toBe('X1');
  12505. HOT.undo();
  12506. expect(getDataAtCell(0, 0)).toBe('A1');
  12507. });
  12508. it('should undo single change on cell with validator', function (done) {
  12509. handsontable({
  12510. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12511. });
  12512. var HOT = getInstance();
  12513. setDataAtCell(0, 0, 'X1');
  12514. setTimeout(function () {
  12515. expect(getDataAtCell(0, 0)).toBe('X1');
  12516. HOT.undo();
  12517. }, 200);
  12518. setTimeout(function () {
  12519. expect(getDataAtCell(0, 0)).toBe('A1');
  12520. done();
  12521. }, 400);
  12522. });
  12523. it('should undo creation of a single row', function () {
  12524. var HOT = handsontable({
  12525. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12526. });
  12527. expect(countRows()).toEqual(2);
  12528. alter('insert_row');
  12529. expect(countRows()).toEqual(3);
  12530. HOT.undo();
  12531. expect(countRows()).toEqual(2);
  12532. });
  12533. it('should undo creation of multiple rows', function () {
  12534. var HOT = handsontable({
  12535. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12536. });
  12537. expect(countRows()).toEqual(2);
  12538. alter('insert_row', 0, 5);
  12539. expect(countRows()).toEqual(7);
  12540. HOT.undo();
  12541. expect(countRows()).toEqual(2);
  12542. });
  12543. it('should undo creation of multiple rows with minSpareRows', function () {
  12544. var HOT = handsontable({
  12545. data: Handsontable.helper.createSpreadsheetData(2, 1),
  12546. minSpareRows: 2
  12547. });
  12548. expect(getData()).toEqual([['A1'], ['A2'], [null], [null]]);
  12549. setDataAtCell(2, 0, 'A3');
  12550. setDataAtCell(4, 0, 'A4');
  12551. expect(getData()).toEqual([['A1'], ['A2'], ['A3'], [null], ['A4'], [null], [null]]);
  12552. HOT.undo();
  12553. HOT.undo();
  12554. expect(getData()).toEqual([['A1'], ['A2'], [null], [null]]);
  12555. });
  12556. it('should undo removal of single row', function () {
  12557. var HOT = handsontable({
  12558. data: Handsontable.helper.createSpreadsheetData(3, 2)
  12559. });
  12560. expect(countRows()).toEqual(3);
  12561. expect(getDataAtCell(0, 0)).toEqual('A1');
  12562. expect(getDataAtCell(0, 1)).toEqual('B1');
  12563. expect(getDataAtCell(1, 0)).toEqual('A2');
  12564. expect(getDataAtCell(1, 1)).toEqual('B2');
  12565. expect(getDataAtCell(2, 0)).toEqual('A3');
  12566. expect(getDataAtCell(2, 1)).toEqual('B3');
  12567. alter('remove_row', 1);
  12568. expect(countRows()).toEqual(2);
  12569. expect(getDataAtCell(0, 0)).toEqual('A1');
  12570. expect(getDataAtCell(0, 1)).toEqual('B1');
  12571. expect(getDataAtCell(1, 0)).toEqual('A3');
  12572. expect(getDataAtCell(1, 1)).toEqual('B3');
  12573. HOT.undo();
  12574. expect(countRows()).toEqual(3);
  12575. expect(getDataAtCell(0, 0)).toEqual('A1');
  12576. expect(getDataAtCell(0, 1)).toEqual('B1');
  12577. expect(getDataAtCell(1, 0)).toEqual('A2');
  12578. expect(getDataAtCell(1, 1)).toEqual('B2');
  12579. expect(getDataAtCell(2, 0)).toEqual('A3');
  12580. expect(getDataAtCell(2, 1)).toEqual('B3');
  12581. });
  12582. it('should undo removal of multiple rows', function () {
  12583. var HOT = handsontable({
  12584. data: Handsontable.helper.createSpreadsheetData(4, 2)
  12585. });
  12586. expect(countRows()).toEqual(4);
  12587. expect(getDataAtCell(0, 0)).toEqual('A1');
  12588. expect(getDataAtCell(0, 1)).toEqual('B1');
  12589. expect(getDataAtCell(1, 0)).toEqual('A2');
  12590. expect(getDataAtCell(1, 1)).toEqual('B2');
  12591. expect(getDataAtCell(2, 0)).toEqual('A3');
  12592. expect(getDataAtCell(2, 1)).toEqual('B3');
  12593. expect(getDataAtCell(3, 0)).toEqual('A4');
  12594. expect(getDataAtCell(3, 1)).toEqual('B4');
  12595. alter('remove_row', 1, 2);
  12596. expect(countRows()).toEqual(2);
  12597. expect(getDataAtCell(0, 0)).toEqual('A1');
  12598. expect(getDataAtCell(0, 1)).toEqual('B1');
  12599. expect(getDataAtCell(1, 0)).toEqual('A4');
  12600. expect(getDataAtCell(1, 1)).toEqual('B4');
  12601. HOT.undo();
  12602. expect(countRows()).toEqual(4);
  12603. expect(getDataAtCell(0, 0)).toEqual('A1');
  12604. expect(getDataAtCell(0, 1)).toEqual('B1');
  12605. expect(getDataAtCell(1, 0)).toEqual('A2');
  12606. expect(getDataAtCell(1, 1)).toEqual('B2');
  12607. expect(getDataAtCell(2, 0)).toEqual('A3');
  12608. expect(getDataAtCell(2, 1)).toEqual('B3');
  12609. expect(getDataAtCell(3, 0)).toEqual('A4');
  12610. expect(getDataAtCell(3, 1)).toEqual('B4');
  12611. });
  12612. it('should undo creation of a single column (colHeaders: undefined)', function () {
  12613. var HOT = handsontable({
  12614. data: Handsontable.helper.createSpreadsheetData(2, 3)
  12615. });
  12616. expect(countCols()).toEqual(3);
  12617. alter('insert_col');
  12618. expect(countCols()).toEqual(4);
  12619. HOT.undo();
  12620. expect(countCols()).toEqual(3);
  12621. });
  12622. it('should undo creation of a single column (colHeaders: true)', function () {
  12623. var HOT = handsontable({
  12624. data: Handsontable.helper.createSpreadsheetData(2, 3),
  12625. colHeaders: true
  12626. });
  12627. expect(countCols()).toEqual(3);
  12628. expect(getColHeader()).toEqual(['A', 'B', 'C']);
  12629. alter('insert_col');
  12630. expect(countCols()).toEqual(4);
  12631. expect(getColHeader()).toEqual(['A', 'B', 'C', 'D']);
  12632. HOT.undo();
  12633. expect(countCols()).toEqual(3);
  12634. expect(getColHeader()).toEqual(['A', 'B', 'C']);
  12635. });
  12636. it('should undo creation of a single column (colHeaders: Array)', function () {
  12637. var HOT = handsontable({
  12638. data: Handsontable.helper.createSpreadsheetData(2, 3),
  12639. colHeaders: ['Header1', 'Header2', 'Header3']
  12640. });
  12641. expect(countCols()).toEqual(3);
  12642. expect(getColHeader()).toEqual(['Header1', 'Header2', 'Header3']);
  12643. alter('insert_col', 1);
  12644. expect(countCols()).toEqual(4);
  12645. expect(getColHeader()).toEqual(['Header1', 'B', 'Header2', 'Header3']);
  12646. HOT.undo();
  12647. expect(countCols()).toEqual(3);
  12648. expect(getColHeader()).toEqual(['Header1', 'Header2', 'Header3']);
  12649. });
  12650. it('should undo creation of multiple columns (colHeaders: undefined)', function () {
  12651. var HOT = handsontable({
  12652. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12653. });
  12654. expect(countCols()).toEqual(2);
  12655. alter('insert_col', 1, 5);
  12656. expect(countCols()).toEqual(7);
  12657. HOT.undo();
  12658. expect(countCols()).toEqual(2);
  12659. });
  12660. it('should undo creation of multiple columns (colHeaders: true)', function () {
  12661. var HOT = handsontable({
  12662. data: Handsontable.helper.createSpreadsheetData(2, 2),
  12663. colHeaders: true
  12664. });
  12665. expect(countCols()).toEqual(2);
  12666. expect(getColHeader()).toEqual(['A', 'B']);
  12667. alter('insert_col', 1, 5);
  12668. expect(countCols()).toEqual(7);
  12669. expect(getColHeader()).toEqual(['A', 'B', 'C', 'D', 'E', 'F', 'G']);
  12670. HOT.undo();
  12671. expect(countCols()).toEqual(2);
  12672. expect(getColHeader()).toEqual(['A', 'B']);
  12673. });
  12674. it('should undo creation of multiple columns (colHeaders: Array)', function () {
  12675. var HOT = handsontable({
  12676. data: Handsontable.helper.createSpreadsheetData(2, 2),
  12677. colHeaders: ['Header1', 'Header2']
  12678. });
  12679. expect(countCols()).toEqual(2);
  12680. expect(getColHeader()).toEqual(['Header1', 'Header2']);
  12681. alter('insert_col', 1, 5);
  12682. expect(countCols()).toEqual(7);
  12683. expect(getColHeader()).toEqual(['Header1', 'B', 'C', 'D', 'E', 'F', 'Header2']);
  12684. HOT.undo();
  12685. expect(countCols()).toEqual(2);
  12686. expect(getColHeader()).toEqual(['Header1', 'Header2']);
  12687. });
  12688. it('should undo creation of multiple columns with minSpareCols', function () {
  12689. var HOT = handsontable({
  12690. data: Handsontable.helper.createSpreadsheetData(1, 1),
  12691. minSpareCols: 2
  12692. });
  12693. expect(getData()).toEqual([['A1', null, null]]);
  12694. setDataAtCell(0, 1, 'B1');
  12695. setDataAtCell(0, 3, 'C1');
  12696. expect(getData()).toEqual([['A1', 'B1', null, 'C1', null, null]]);
  12697. HOT.undo();
  12698. HOT.undo();
  12699. expect(getData()).toEqual([['A1', null, null]]);
  12700. });
  12701. it('should undo removal of single column (colHeaders: undefined)', function () {
  12702. var HOT = handsontable({
  12703. data: Handsontable.helper.createSpreadsheetData(2, 3)
  12704. });
  12705. expect(countCols()).toEqual(3);
  12706. expect(getDataAtCell(0, 0)).toEqual('A1');
  12707. expect(getDataAtCell(0, 1)).toEqual('B1');
  12708. expect(getDataAtCell(0, 2)).toEqual('C1');
  12709. expect(getDataAtCell(1, 0)).toEqual('A2');
  12710. expect(getDataAtCell(1, 1)).toEqual('B2');
  12711. expect(getDataAtCell(1, 2)).toEqual('C2');
  12712. alter('remove_col', 1);
  12713. expect(countCols()).toEqual(2);
  12714. expect(getDataAtCell(0, 0)).toEqual('A1');
  12715. expect(getDataAtCell(0, 1)).toEqual('C1');
  12716. expect(getDataAtCell(1, 0)).toEqual('A2');
  12717. expect(getDataAtCell(1, 1)).toEqual('C2');
  12718. HOT.undo();
  12719. expect(countCols()).toEqual(3);
  12720. expect(getDataAtCell(0, 0)).toEqual('A1');
  12721. expect(getDataAtCell(0, 1)).toEqual('B1');
  12722. expect(getDataAtCell(0, 2)).toEqual('C1');
  12723. expect(getDataAtCell(1, 0)).toEqual('A2');
  12724. expect(getDataAtCell(1, 1)).toEqual('B2');
  12725. expect(getDataAtCell(1, 2)).toEqual('C2');
  12726. });
  12727. it('should undo removal of single column (colHeaders: true)', function () {
  12728. var HOT = handsontable({
  12729. data: Handsontable.helper.createSpreadsheetData(2, 2),
  12730. colHeaders: true
  12731. });
  12732. expect(countCols()).toEqual(2);
  12733. expect(getDataAtCell(0, 0)).toEqual('A1');
  12734. expect(getDataAtCell(0, 1)).toEqual('B1');
  12735. expect(getDataAtCell(1, 0)).toEqual('A2');
  12736. expect(getDataAtCell(1, 1)).toEqual('B2');
  12737. expect(getColHeader()).toEqual(['A', 'B']);
  12738. alter('remove_col');
  12739. expect(countCols()).toEqual(1);
  12740. expect(getDataAtCell(0, 0)).toEqual('A1');
  12741. expect(getDataAtCell(0, 1)).toBeNull();
  12742. expect(getDataAtCell(1, 0)).toEqual('A2');
  12743. expect(getDataAtCell(1, 1)).toBeNull();
  12744. expect(getColHeader()).toEqual(['A']);
  12745. HOT.undo();
  12746. expect(countCols()).toEqual(2);
  12747. expect(getDataAtCell(0, 0)).toEqual('A1');
  12748. expect(getDataAtCell(0, 1)).toEqual('B1');
  12749. expect(getDataAtCell(1, 0)).toEqual('A2');
  12750. expect(getDataAtCell(1, 1)).toEqual('B2');
  12751. expect(getColHeader()).toEqual(['A', 'B']);
  12752. });
  12753. it('should undo removal of single column (colHeaders: Array)', function () {
  12754. var HOT = handsontable({
  12755. data: Handsontable.helper.createSpreadsheetData(2, 2),
  12756. colHeaders: ['Header1', 'Header2']
  12757. });
  12758. expect(countCols()).toEqual(2);
  12759. expect(getDataAtCell(0, 0)).toEqual('A1');
  12760. expect(getDataAtCell(0, 1)).toEqual('B1');
  12761. expect(getDataAtCell(1, 0)).toEqual('A2');
  12762. expect(getDataAtCell(1, 1)).toEqual('B2');
  12763. expect(getColHeader()).toEqual(['Header1', 'Header2']);
  12764. alter('remove_col');
  12765. expect(countCols()).toEqual(1);
  12766. expect(getDataAtCell(0, 0)).toEqual('A1');
  12767. expect(getDataAtCell(0, 1)).toBeNull();
  12768. expect(getDataAtCell(1, 0)).toEqual('A2');
  12769. expect(getDataAtCell(1, 1)).toBeNull();
  12770. expect(getColHeader()).toEqual(['Header1']);
  12771. HOT.undo();
  12772. expect(countCols()).toEqual(2);
  12773. expect(getDataAtCell(0, 0)).toEqual('A1');
  12774. expect(getDataAtCell(0, 1)).toEqual('B1');
  12775. expect(getDataAtCell(1, 0)).toEqual('A2');
  12776. expect(getDataAtCell(1, 1)).toEqual('B2');
  12777. expect(getColHeader()).toEqual(['Header1', 'Header2']);
  12778. });
  12779. it('should undo removal of multiple columns (colHeaders: undefined)', function () {
  12780. var HOT = handsontable({
  12781. data: Handsontable.helper.createSpreadsheetData(2, 4)
  12782. });
  12783. expect(countCols()).toEqual(4);
  12784. expect(getDataAtCell(0, 0)).toEqual('A1');
  12785. expect(getDataAtCell(0, 1)).toEqual('B1');
  12786. expect(getDataAtCell(0, 2)).toEqual('C1');
  12787. expect(getDataAtCell(0, 3)).toEqual('D1');
  12788. expect(getDataAtCell(1, 0)).toEqual('A2');
  12789. expect(getDataAtCell(1, 1)).toEqual('B2');
  12790. expect(getDataAtCell(1, 2)).toEqual('C2');
  12791. expect(getDataAtCell(1, 3)).toEqual('D2');
  12792. alter('remove_col', 1, 2);
  12793. expect(countCols()).toEqual(2);
  12794. expect(getDataAtCell(0, 0)).toEqual('A1');
  12795. expect(getDataAtCell(0, 1)).toEqual('D1');
  12796. expect(getDataAtCell(0, 2)).toBeNull();
  12797. expect(getDataAtCell(0, 3)).toBeNull();
  12798. expect(getDataAtCell(1, 0)).toEqual('A2');
  12799. expect(getDataAtCell(1, 1)).toEqual('D2');
  12800. expect(getDataAtCell(1, 2)).toBeNull();
  12801. expect(getDataAtCell(1, 3)).toBeNull();
  12802. HOT.undo();
  12803. expect(countCols()).toEqual(4);
  12804. expect(getDataAtCell(0, 0)).toEqual('A1');
  12805. expect(getDataAtCell(0, 1)).toEqual('B1');
  12806. expect(getDataAtCell(0, 2)).toEqual('C1');
  12807. expect(getDataAtCell(0, 3)).toEqual('D1');
  12808. expect(getDataAtCell(1, 0)).toEqual('A2');
  12809. expect(getDataAtCell(1, 1)).toEqual('B2');
  12810. expect(getDataAtCell(1, 2)).toEqual('C2');
  12811. expect(getDataAtCell(1, 3)).toEqual('D2');
  12812. });
  12813. it('should undo removal of multiple columns (colHeaders: true)', function () {
  12814. var HOT = handsontable({
  12815. data: Handsontable.helper.createSpreadsheetData(2, 4),
  12816. colHeaders: true
  12817. });
  12818. expect(countCols()).toEqual(4);
  12819. expect(getDataAtCell(0, 0)).toEqual('A1');
  12820. expect(getDataAtCell(0, 1)).toEqual('B1');
  12821. expect(getDataAtCell(0, 2)).toEqual('C1');
  12822. expect(getDataAtCell(0, 3)).toEqual('D1');
  12823. expect(getDataAtCell(1, 0)).toEqual('A2');
  12824. expect(getDataAtCell(1, 1)).toEqual('B2');
  12825. expect(getDataAtCell(1, 2)).toEqual('C2');
  12826. expect(getDataAtCell(1, 3)).toEqual('D2');
  12827. expect(getColHeader()).toEqual(['A', 'B', 'C', 'D']);
  12828. alter('remove_col', 1, 3);
  12829. expect(countCols()).toEqual(1);
  12830. expect(getDataAtCell(0, 0)).toEqual('A1');
  12831. expect(getDataAtCell(0, 1)).toBeNull();
  12832. expect(getDataAtCell(0, 2)).toBeNull();
  12833. expect(getDataAtCell(0, 3)).toBeNull();
  12834. expect(getDataAtCell(1, 0)).toEqual('A2');
  12835. expect(getDataAtCell(1, 1)).toBeNull();
  12836. expect(getDataAtCell(1, 2)).toBeNull();
  12837. expect(getDataAtCell(1, 3)).toBeNull();
  12838. expect(getColHeader()).toEqual(['A']);
  12839. HOT.undo();
  12840. expect(countCols()).toEqual(4);
  12841. expect(getDataAtCell(0, 0)).toEqual('A1');
  12842. expect(getDataAtCell(0, 1)).toEqual('B1');
  12843. expect(getDataAtCell(0, 2)).toEqual('C1');
  12844. expect(getDataAtCell(0, 3)).toEqual('D1');
  12845. expect(getDataAtCell(1, 0)).toEqual('A2');
  12846. expect(getDataAtCell(1, 1)).toEqual('B2');
  12847. expect(getDataAtCell(1, 2)).toEqual('C2');
  12848. expect(getDataAtCell(1, 3)).toEqual('D2');
  12849. expect(getColHeader()).toEqual(['A', 'B', 'C', 'D']);
  12850. });
  12851. it('should undo removal of multiple columns (colHeaders: Array)', function () {
  12852. var HOT = handsontable({
  12853. data: Handsontable.helper.createSpreadsheetData(2, 4),
  12854. colHeaders: ['Header1', 'Header2', 'Header3', 'Header4']
  12855. });
  12856. expect(countCols()).toEqual(4);
  12857. expect(getDataAtCell(0, 0)).toEqual('A1');
  12858. expect(getDataAtCell(0, 1)).toEqual('B1');
  12859. expect(getDataAtCell(0, 2)).toEqual('C1');
  12860. expect(getDataAtCell(0, 3)).toEqual('D1');
  12861. expect(getDataAtCell(1, 0)).toEqual('A2');
  12862. expect(getDataAtCell(1, 1)).toEqual('B2');
  12863. expect(getDataAtCell(1, 2)).toEqual('C2');
  12864. expect(getDataAtCell(1, 3)).toEqual('D2');
  12865. expect(getColHeader()).toEqual(['Header1', 'Header2', 'Header3', 'Header4']);
  12866. alter('remove_col', 1, 2);
  12867. expect(countCols()).toEqual(2);
  12868. expect(getDataAtCell(0, 0)).toEqual('A1');
  12869. expect(getDataAtCell(0, 1)).toEqual('D1');
  12870. expect(getDataAtCell(0, 2)).toBeNull();
  12871. expect(getDataAtCell(0, 3)).toBeNull();
  12872. expect(getDataAtCell(1, 0)).toEqual('A2');
  12873. expect(getDataAtCell(1, 1)).toEqual('D2');
  12874. expect(getDataAtCell(1, 2)).toBeNull();
  12875. expect(getDataAtCell(1, 3)).toBeNull();
  12876. expect(getColHeader()).toEqual(['Header1', 'Header4']);
  12877. HOT.undo();
  12878. expect(countCols()).toEqual(4);
  12879. expect(getDataAtCell(0, 0)).toEqual('A1');
  12880. expect(getDataAtCell(0, 1)).toEqual('B1');
  12881. expect(getDataAtCell(0, 2)).toEqual('C1');
  12882. expect(getDataAtCell(0, 3)).toEqual('D1');
  12883. expect(getDataAtCell(1, 0)).toEqual('A2');
  12884. expect(getDataAtCell(1, 1)).toEqual('B2');
  12885. expect(getDataAtCell(1, 2)).toEqual('C2');
  12886. expect(getDataAtCell(1, 3)).toEqual('D2');
  12887. expect(getColHeader()).toEqual(['Header1', 'Header2', 'Header3', 'Header4']);
  12888. });
  12889. it('should undo removal of multiple columns (with a used manualColumnMove)', function () {
  12890. var HOT = handsontable({
  12891. data: Handsontable.helper.createSpreadsheetData(2, 7),
  12892. manualColumnMove: [3, 2, 0, 6, 1, 5, 4]
  12893. });
  12894. expect(countCols()).toEqual(7);
  12895. expect(getDataAtRow(0)).toEqual(['D1', 'C1', 'A1', 'G1', 'B1', 'F1', 'E1']);
  12896. alter('remove_col', 1, 3);
  12897. expect(countCols()).toEqual(4);
  12898. expect(getDataAtRow(0)).toEqual(['D1', 'B1', 'F1', 'E1']);
  12899. // HOT.undo();
  12900. //
  12901. // expect(countCols()).toEqual(7);
  12902. // expect(getDataAtRow(0)).toEqual(['D1', 'C1', 'A1', 'G1', 'B1', 'F1', 'E1']);
  12903. });
  12904. it('should undo multiple changes', function () {
  12905. handsontable({
  12906. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12907. });
  12908. var HOT = getInstance();
  12909. setDataAtCell(0, 0, 'X1');
  12910. setDataAtCell(1, 0, 'X2');
  12911. setDataAtCell(0, 1, 'Y1');
  12912. setDataAtCell(1, 1, 'Y2');
  12913. expect(getDataAtCell(0, 0)).toBe('X1');
  12914. expect(getDataAtCell(1, 0)).toBe('X2');
  12915. expect(getDataAtCell(0, 1)).toBe('Y1');
  12916. expect(getDataAtCell(1, 1)).toBe('Y2');
  12917. HOT.undo();
  12918. expect(getDataAtCell(0, 0)).toBe('X1');
  12919. expect(getDataAtCell(1, 0)).toBe('X2');
  12920. expect(getDataAtCell(0, 1)).toBe('Y1');
  12921. expect(getDataAtCell(1, 1)).toBe('B2');
  12922. HOT.undo();
  12923. expect(getDataAtCell(0, 0)).toBe('X1');
  12924. expect(getDataAtCell(1, 0)).toBe('X2');
  12925. expect(getDataAtCell(0, 1)).toBe('B1');
  12926. expect(getDataAtCell(1, 1)).toBe('B2');
  12927. HOT.undo();
  12928. expect(getDataAtCell(0, 0)).toBe('X1');
  12929. expect(getDataAtCell(1, 0)).toBe('A2');
  12930. expect(getDataAtCell(0, 1)).toBe('B1');
  12931. expect(getDataAtCell(1, 1)).toBe('B2');
  12932. HOT.undo();
  12933. expect(getDataAtCell(0, 0)).toBe('A1');
  12934. expect(getDataAtCell(1, 0)).toBe('A2');
  12935. expect(getDataAtCell(0, 1)).toBe('B1');
  12936. expect(getDataAtCell(1, 1)).toBe('B2');
  12937. HOT.undo();
  12938. expect(getDataAtCell(0, 0)).toBe('A1');
  12939. expect(getDataAtCell(1, 0)).toBe('A2');
  12940. expect(getDataAtCell(0, 1)).toBe('B1');
  12941. expect(getDataAtCell(1, 1)).toBe('B2');
  12942. });
  12943. it('should undo multiple changes in cells with validators', function (done) {
  12944. handsontable({
  12945. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12946. });
  12947. var HOT = getInstance();
  12948. setDataAtCell(0, 0, 'X1');
  12949. setDataAtCell(1, 0, 'X2');
  12950. setDataAtCell(0, 1, 'Y1');
  12951. setDataAtCell(1, 1, 'Y2');
  12952. setTimeout(function () {
  12953. expect(getDataAtCell(0, 0)).toBe('X1');
  12954. expect(getDataAtCell(1, 0)).toBe('X2');
  12955. expect(getDataAtCell(0, 1)).toBe('Y1');
  12956. expect(getDataAtCell(1, 1)).toBe('Y2');
  12957. HOT.undo();
  12958. }, 200);
  12959. setTimeout(function () {
  12960. expect(getDataAtCell(0, 0)).toBe('X1');
  12961. expect(getDataAtCell(1, 0)).toBe('X2');
  12962. expect(getDataAtCell(0, 1)).toBe('Y1');
  12963. expect(getDataAtCell(1, 1)).toBe('B2');
  12964. HOT.undo();
  12965. }, 400);
  12966. setTimeout(function () {
  12967. expect(getDataAtCell(0, 0)).toBe('X1');
  12968. expect(getDataAtCell(1, 0)).toBe('X2');
  12969. expect(getDataAtCell(0, 1)).toBe('B1');
  12970. expect(getDataAtCell(1, 1)).toBe('B2');
  12971. HOT.undo();
  12972. }, 600);
  12973. setTimeout(function () {
  12974. expect(getDataAtCell(0, 0)).toBe('X1');
  12975. expect(getDataAtCell(1, 0)).toBe('A2');
  12976. expect(getDataAtCell(0, 1)).toBe('B1');
  12977. expect(getDataAtCell(1, 1)).toBe('B2');
  12978. HOT.undo();
  12979. }, 800);
  12980. setTimeout(function () {
  12981. expect(getDataAtCell(0, 0)).toBe('A1');
  12982. expect(getDataAtCell(1, 0)).toBe('A2');
  12983. expect(getDataAtCell(0, 1)).toBe('B1');
  12984. expect(getDataAtCell(1, 1)).toBe('B2');
  12985. HOT.undo();
  12986. }, 1000);
  12987. setTimeout(function () {
  12988. expect(getDataAtCell(0, 0)).toBe('A1');
  12989. expect(getDataAtCell(1, 0)).toBe('A2');
  12990. expect(getDataAtCell(0, 1)).toBe('B1');
  12991. expect(getDataAtCell(1, 1)).toBe('B2');
  12992. done();
  12993. }, 1200);
  12994. });
  12995. it('should undo multiple row creations', function () {
  12996. var HOT = handsontable({
  12997. data: Handsontable.helper.createSpreadsheetData(2, 2)
  12998. });
  12999. expect(countRows()).toEqual(2);
  13000. alter('insert_row');
  13001. alter('insert_row');
  13002. alter('insert_row');
  13003. alter('insert_row');
  13004. expect(countRows()).toEqual(6);
  13005. HOT.undo();
  13006. expect(countRows()).toEqual(5);
  13007. HOT.undo();
  13008. expect(countRows()).toEqual(4);
  13009. HOT.undo();
  13010. expect(countRows()).toEqual(3);
  13011. HOT.undo();
  13012. expect(countRows()).toEqual(2);
  13013. HOT.undo();
  13014. expect(countRows()).toEqual(2);
  13015. });
  13016. it('should undo multiple row removals', function () {
  13017. var HOT = handsontable({
  13018. data: Handsontable.helper.createSpreadsheetData(4, 2)
  13019. });
  13020. expect(countRows()).toEqual(4);
  13021. expect(getDataAtCell(0, 0)).toEqual('A1');
  13022. expect(getDataAtCell(0, 1)).toEqual('B1');
  13023. expect(getDataAtCell(1, 0)).toEqual('A2');
  13024. expect(getDataAtCell(1, 1)).toEqual('B2');
  13025. expect(getDataAtCell(2, 0)).toEqual('A3');
  13026. expect(getDataAtCell(2, 1)).toEqual('B3');
  13027. expect(getDataAtCell(3, 0)).toEqual('A4');
  13028. expect(getDataAtCell(3, 1)).toEqual('B4');
  13029. alter('remove_row');
  13030. alter('remove_row');
  13031. alter('remove_row');
  13032. expect(countRows()).toEqual(1);
  13033. expect(getDataAtCell(0, 0)).toEqual('A1');
  13034. expect(getDataAtCell(0, 1)).toEqual('B1');
  13035. HOT.undo();
  13036. expect(countRows()).toEqual(2);
  13037. expect(getDataAtCell(0, 0)).toEqual('A1');
  13038. expect(getDataAtCell(0, 1)).toEqual('B1');
  13039. expect(getDataAtCell(1, 0)).toEqual('A2');
  13040. expect(getDataAtCell(1, 1)).toEqual('B2');
  13041. HOT.undo();
  13042. expect(countRows()).toEqual(3);
  13043. expect(getDataAtCell(0, 0)).toEqual('A1');
  13044. expect(getDataAtCell(0, 1)).toEqual('B1');
  13045. expect(getDataAtCell(1, 0)).toEqual('A2');
  13046. expect(getDataAtCell(1, 1)).toEqual('B2');
  13047. expect(getDataAtCell(2, 0)).toEqual('A3');
  13048. expect(getDataAtCell(2, 1)).toEqual('B3');
  13049. HOT.undo();
  13050. expect(countRows()).toEqual(4);
  13051. expect(getDataAtCell(0, 0)).toEqual('A1');
  13052. expect(getDataAtCell(0, 1)).toEqual('B1');
  13053. expect(getDataAtCell(1, 0)).toEqual('A2');
  13054. expect(getDataAtCell(1, 1)).toEqual('B2');
  13055. expect(getDataAtCell(2, 0)).toEqual('A3');
  13056. expect(getDataAtCell(2, 1)).toEqual('B3');
  13057. expect(getDataAtCell(3, 0)).toEqual('A4');
  13058. expect(getDataAtCell(3, 1)).toEqual('B4');
  13059. HOT.undo();
  13060. expect(countRows()).toEqual(4);
  13061. expect(getDataAtCell(0, 0)).toEqual('A1');
  13062. expect(getDataAtCell(0, 1)).toEqual('B1');
  13063. expect(getDataAtCell(1, 0)).toEqual('A2');
  13064. expect(getDataAtCell(1, 1)).toEqual('B2');
  13065. expect(getDataAtCell(2, 0)).toEqual('A3');
  13066. expect(getDataAtCell(2, 1)).toEqual('B3');
  13067. expect(getDataAtCell(3, 0)).toEqual('A4');
  13068. expect(getDataAtCell(3, 1)).toEqual('B4');
  13069. });
  13070. it('should undo changes only for table where the change actually took place', function () {
  13071. this.$container2 = $('<div id="' + id + '-2"></div>').appendTo('body');
  13072. var hot1 = handsontable({
  13073. data: [[1], [2], [3]]
  13074. });
  13075. this.$container2.handsontable({
  13076. data: [['A'], ['B'], ['C']]
  13077. });
  13078. var hot2 = this.$container2.handsontable('getInstance');
  13079. hot1.setDataAtCell(0, 0, 4);
  13080. expect(hot1.getDataAtCell(0, 0)).toEqual(4);
  13081. expect(hot2.getDataAtCell(0, 0)).toEqual('A');
  13082. hot2.undo();
  13083. expect(hot2.getDataAtCell(0, 0)).toEqual('A');
  13084. expect(hot1.getDataAtCell(0, 0)).toEqual(4);
  13085. hot1.undo();
  13086. expect(hot2.getDataAtCell(0, 0)).toEqual('A');
  13087. expect(hot1.getDataAtCell(0, 0)).toEqual(1);
  13088. hot2.destroy();
  13089. this.$container2.remove();
  13090. });
  13091. });
  13092. describe('redo', function () {
  13093. it('should redo single change', function () {
  13094. handsontable({
  13095. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13096. });
  13097. var HOT = getInstance();
  13098. setDataAtCell(0, 0, 'new value');
  13099. expect(getDataAtCell(0, 0)).toBe('new value');
  13100. HOT.undo();
  13101. expect(getDataAtCell(0, 0)).toBe('A1');
  13102. HOT.redo();
  13103. expect(getDataAtCell(0, 0)).toBe('new value');
  13104. });
  13105. it('should redo single change in cell with validator', function (done) {
  13106. handsontable({
  13107. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13108. });
  13109. var HOT = getInstance();
  13110. setDataAtCell(0, 0, 'new value');
  13111. setTimeout(function () {
  13112. expect(getDataAtCell(0, 0)).toBe('new value');
  13113. HOT.undo();
  13114. }, 200);
  13115. setTimeout(function () {
  13116. expect(getDataAtCell(0, 0)).toBe('A1');
  13117. HOT.redo();
  13118. }, 400);
  13119. setTimeout(function () {
  13120. expect(getDataAtCell(0, 0)).toBe('new value');
  13121. done();
  13122. }, 600);
  13123. });
  13124. it('should redo creation of a single row', function () {
  13125. var HOT = handsontable({
  13126. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13127. });
  13128. expect(countRows()).toEqual(2);
  13129. alter('insert_row');
  13130. expect(countRows()).toEqual(3);
  13131. HOT.undo();
  13132. expect(countRows()).toEqual(2);
  13133. HOT.redo();
  13134. expect(countRows()).toEqual(3);
  13135. });
  13136. it('should redo creation of multiple rows', function () {
  13137. var HOT = handsontable({
  13138. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13139. });
  13140. expect(countRows()).toEqual(2);
  13141. alter('insert_row', 0, 5);
  13142. expect(countRows()).toEqual(7);
  13143. HOT.undo();
  13144. expect(countRows()).toEqual(2);
  13145. HOT.redo();
  13146. expect(countRows()).toEqual(7);
  13147. });
  13148. it('should redo removal of single row', function () {
  13149. var HOT = handsontable({
  13150. data: Handsontable.helper.createSpreadsheetData(3, 2)
  13151. });
  13152. expect(countRows()).toEqual(3);
  13153. expect(getDataAtCell(0, 0)).toEqual('A1');
  13154. expect(getDataAtCell(0, 1)).toEqual('B1');
  13155. expect(getDataAtCell(1, 0)).toEqual('A2');
  13156. expect(getDataAtCell(1, 1)).toEqual('B2');
  13157. expect(getDataAtCell(2, 0)).toEqual('A3');
  13158. expect(getDataAtCell(2, 1)).toEqual('B3');
  13159. alter('remove_row', 1);
  13160. expect(countRows()).toEqual(2);
  13161. expect(getDataAtCell(0, 0)).toEqual('A1');
  13162. expect(getDataAtCell(0, 1)).toEqual('B1');
  13163. expect(getDataAtCell(1, 0)).toEqual('A3');
  13164. expect(getDataAtCell(1, 1)).toEqual('B3');
  13165. HOT.undo();
  13166. expect(countRows()).toEqual(3);
  13167. expect(getDataAtCell(0, 0)).toEqual('A1');
  13168. expect(getDataAtCell(0, 1)).toEqual('B1');
  13169. expect(getDataAtCell(1, 0)).toEqual('A2');
  13170. expect(getDataAtCell(1, 1)).toEqual('B2');
  13171. expect(getDataAtCell(2, 0)).toEqual('A3');
  13172. expect(getDataAtCell(2, 1)).toEqual('B3');
  13173. HOT.redo();
  13174. expect(countRows()).toEqual(2);
  13175. expect(getDataAtCell(0, 0)).toEqual('A1');
  13176. expect(getDataAtCell(0, 1)).toEqual('B1');
  13177. expect(getDataAtCell(1, 0)).toEqual('A3');
  13178. expect(getDataAtCell(1, 1)).toEqual('B3');
  13179. });
  13180. it('should redo removal of multiple rows', function () {
  13181. var HOT = handsontable({
  13182. data: Handsontable.helper.createSpreadsheetData(4, 2)
  13183. });
  13184. expect(countRows()).toEqual(4);
  13185. expect(getDataAtCell(0, 0)).toEqual('A1');
  13186. expect(getDataAtCell(0, 1)).toEqual('B1');
  13187. expect(getDataAtCell(1, 0)).toEqual('A2');
  13188. expect(getDataAtCell(1, 1)).toEqual('B2');
  13189. expect(getDataAtCell(2, 0)).toEqual('A3');
  13190. expect(getDataAtCell(2, 1)).toEqual('B3');
  13191. expect(getDataAtCell(3, 0)).toEqual('A4');
  13192. expect(getDataAtCell(3, 1)).toEqual('B4');
  13193. alter('remove_row', 1, 2);
  13194. expect(countRows()).toEqual(2);
  13195. expect(getDataAtCell(0, 0)).toEqual('A1');
  13196. expect(getDataAtCell(0, 1)).toEqual('B1');
  13197. expect(getDataAtCell(1, 0)).toEqual('A4');
  13198. expect(getDataAtCell(1, 1)).toEqual('B4');
  13199. HOT.undo();
  13200. expect(countRows()).toEqual(4);
  13201. expect(getDataAtCell(0, 0)).toEqual('A1');
  13202. expect(getDataAtCell(0, 1)).toEqual('B1');
  13203. expect(getDataAtCell(1, 0)).toEqual('A2');
  13204. expect(getDataAtCell(1, 1)).toEqual('B2');
  13205. expect(getDataAtCell(2, 0)).toEqual('A3');
  13206. expect(getDataAtCell(2, 1)).toEqual('B3');
  13207. expect(getDataAtCell(3, 0)).toEqual('A4');
  13208. expect(getDataAtCell(3, 1)).toEqual('B4');
  13209. HOT.redo();
  13210. expect(countRows()).toEqual(2);
  13211. expect(getDataAtCell(0, 0)).toEqual('A1');
  13212. expect(getDataAtCell(0, 1)).toEqual('B1');
  13213. expect(getDataAtCell(1, 0)).toEqual('A4');
  13214. expect(getDataAtCell(1, 1)).toEqual('B4');
  13215. });
  13216. it('should redo creation of a single column', function () {
  13217. var HOT = handsontable({
  13218. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13219. });
  13220. expect(countCols()).toEqual(2);
  13221. alter('insert_col');
  13222. expect(countCols()).toEqual(3);
  13223. HOT.undo();
  13224. expect(countCols()).toEqual(2);
  13225. HOT.redo();
  13226. expect(countCols()).toEqual(3);
  13227. });
  13228. it('should redo creation of multiple columns', function () {
  13229. var HOT = handsontable({
  13230. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13231. });
  13232. expect(countCols()).toEqual(2);
  13233. alter('insert_col', 1, 5);
  13234. expect(countCols()).toEqual(7);
  13235. HOT.undo();
  13236. expect(countCols()).toEqual(2);
  13237. HOT.redo();
  13238. expect(countCols()).toEqual(7);
  13239. });
  13240. it('should redo removal of single column', function () {
  13241. var HOT = handsontable({
  13242. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13243. });
  13244. expect(countCols()).toEqual(2);
  13245. expect(getDataAtCell(0, 0)).toEqual('A1');
  13246. expect(getDataAtCell(0, 1)).toEqual('B1');
  13247. expect(getDataAtCell(1, 0)).toEqual('A2');
  13248. expect(getDataAtCell(1, 1)).toEqual('B2');
  13249. alter('remove_col');
  13250. expect(countCols()).toEqual(1);
  13251. expect(getDataAtCell(0, 0)).toEqual('A1');
  13252. expect(getDataAtCell(0, 1)).toBeNull();
  13253. expect(getDataAtCell(1, 0)).toEqual('A2');
  13254. expect(getDataAtCell(1, 1)).toBeNull();
  13255. HOT.undo();
  13256. expect(countCols()).toEqual(2);
  13257. expect(getDataAtCell(0, 0)).toEqual('A1');
  13258. expect(getDataAtCell(0, 1)).toEqual('B1');
  13259. expect(getDataAtCell(1, 0)).toEqual('A2');
  13260. expect(getDataAtCell(1, 1)).toEqual('B2');
  13261. HOT.redo();
  13262. expect(countCols()).toEqual(1);
  13263. expect(getDataAtCell(0, 0)).toEqual('A1');
  13264. expect(getDataAtCell(0, 1)).toBeNull();
  13265. expect(getDataAtCell(1, 0)).toEqual('A2');
  13266. expect(getDataAtCell(1, 1)).toBeNull();
  13267. });
  13268. it('should redo removal of multiple columns', function () {
  13269. var HOT = handsontable({
  13270. data: Handsontable.helper.createSpreadsheetData(2, 4)
  13271. });
  13272. expect(countCols()).toEqual(4);
  13273. expect(getDataAtCell(0, 0)).toEqual('A1');
  13274. expect(getDataAtCell(0, 1)).toEqual('B1');
  13275. expect(getDataAtCell(0, 2)).toEqual('C1');
  13276. expect(getDataAtCell(0, 3)).toEqual('D1');
  13277. expect(getDataAtCell(1, 0)).toEqual('A2');
  13278. expect(getDataAtCell(1, 1)).toEqual('B2');
  13279. expect(getDataAtCell(1, 2)).toEqual('C2');
  13280. expect(getDataAtCell(1, 3)).toEqual('D2');
  13281. alter('remove_col', 1, 3);
  13282. expect(countCols()).toEqual(1);
  13283. expect(getDataAtCell(0, 0)).toEqual('A1');
  13284. expect(getDataAtCell(0, 1)).toBeNull();
  13285. expect(getDataAtCell(0, 2)).toBeNull();
  13286. expect(getDataAtCell(0, 3)).toBeNull();
  13287. expect(getDataAtCell(1, 0)).toEqual('A2');
  13288. expect(getDataAtCell(1, 1)).toBeNull();
  13289. expect(getDataAtCell(1, 2)).toBeNull();
  13290. expect(getDataAtCell(1, 3)).toBeNull();
  13291. HOT.undo();
  13292. expect(countCols()).toEqual(4);
  13293. expect(getDataAtCell(0, 0)).toEqual('A1');
  13294. expect(getDataAtCell(0, 1)).toEqual('B1');
  13295. expect(getDataAtCell(0, 2)).toEqual('C1');
  13296. expect(getDataAtCell(0, 3)).toEqual('D1');
  13297. expect(getDataAtCell(1, 0)).toEqual('A2');
  13298. expect(getDataAtCell(1, 1)).toEqual('B2');
  13299. expect(getDataAtCell(1, 2)).toEqual('C2');
  13300. expect(getDataAtCell(1, 3)).toEqual('D2');
  13301. HOT.redo();
  13302. expect(countCols()).toEqual(1);
  13303. expect(getDataAtCell(0, 0)).toEqual('A1');
  13304. expect(getDataAtCell(0, 1)).toBeNull();
  13305. expect(getDataAtCell(0, 2)).toBeNull();
  13306. expect(getDataAtCell(0, 3)).toBeNull();
  13307. expect(getDataAtCell(1, 0)).toEqual('A2');
  13308. expect(getDataAtCell(1, 1)).toBeNull();
  13309. expect(getDataAtCell(1, 2)).toBeNull();
  13310. expect(getDataAtCell(1, 3)).toBeNull();
  13311. });
  13312. it('should redo multiple changes', function () {
  13313. handsontable({
  13314. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13315. });
  13316. var HOT = getInstance();
  13317. setDataAtCell(0, 0, 'X1');
  13318. setDataAtCell(1, 0, 'X2');
  13319. setDataAtCell(0, 1, 'Y1');
  13320. setDataAtCell(1, 1, 'Y2');
  13321. expect(getDataAtCell(0, 0)).toBe('X1');
  13322. expect(getDataAtCell(1, 0)).toBe('X2');
  13323. expect(getDataAtCell(0, 1)).toBe('Y1');
  13324. expect(getDataAtCell(1, 1)).toBe('Y2');
  13325. HOT.undo();
  13326. HOT.undo();
  13327. HOT.undo();
  13328. HOT.undo();
  13329. expect(getDataAtCell(0, 0)).toBe('A1');
  13330. expect(getDataAtCell(1, 0)).toBe('A2');
  13331. expect(getDataAtCell(0, 1)).toBe('B1');
  13332. expect(getDataAtCell(1, 1)).toBe('B2');
  13333. HOT.redo();
  13334. expect(getDataAtCell(0, 0)).toBe('X1');
  13335. expect(getDataAtCell(1, 0)).toBe('A2');
  13336. expect(getDataAtCell(0, 1)).toBe('B1');
  13337. expect(getDataAtCell(1, 1)).toBe('B2');
  13338. HOT.redo();
  13339. expect(getDataAtCell(0, 0)).toBe('X1');
  13340. expect(getDataAtCell(1, 0)).toBe('X2');
  13341. expect(getDataAtCell(0, 1)).toBe('B1');
  13342. expect(getDataAtCell(1, 1)).toBe('B2');
  13343. HOT.redo();
  13344. expect(getDataAtCell(0, 0)).toBe('X1');
  13345. expect(getDataAtCell(1, 0)).toBe('X2');
  13346. expect(getDataAtCell(0, 1)).toBe('Y1');
  13347. expect(getDataAtCell(1, 1)).toBe('B2');
  13348. HOT.redo();
  13349. expect(getDataAtCell(0, 0)).toBe('X1');
  13350. expect(getDataAtCell(1, 0)).toBe('X2');
  13351. expect(getDataAtCell(0, 1)).toBe('Y1');
  13352. expect(getDataAtCell(1, 1)).toBe('Y2');
  13353. HOT.redo();
  13354. expect(getDataAtCell(0, 0)).toBe('X1');
  13355. expect(getDataAtCell(1, 0)).toBe('X2');
  13356. expect(getDataAtCell(0, 1)).toBe('Y1');
  13357. expect(getDataAtCell(1, 1)).toBe('Y2');
  13358. });
  13359. it('should redo multiple changes in cell with validator', function (done) {
  13360. var HOT = handsontable({
  13361. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13362. });
  13363. setDataAtCell(0, 0, 'X1');
  13364. setDataAtCell(1, 0, 'X2');
  13365. setDataAtCell(0, 1, 'Y1');
  13366. setDataAtCell(1, 1, 'Y2');
  13367. setTimeout(function () {
  13368. expect(getDataAtCell(0, 0)).toBe('X1');
  13369. expect(getDataAtCell(1, 0)).toBe('X2');
  13370. expect(getDataAtCell(0, 1)).toBe('Y1');
  13371. expect(getDataAtCell(1, 1)).toBe('Y2');
  13372. HOT.undo();
  13373. }, 200);
  13374. setTimeout(function () {
  13375. HOT.undo();
  13376. }, 400);
  13377. setTimeout(function () {
  13378. HOT.undo();
  13379. }, 600);
  13380. setTimeout(function () {
  13381. HOT.undo();
  13382. }, 800);
  13383. setTimeout(function () {
  13384. expect(getDataAtCell(0, 0)).toBe('A1');
  13385. expect(getDataAtCell(1, 0)).toBe('A2');
  13386. expect(getDataAtCell(0, 1)).toBe('B1');
  13387. expect(getDataAtCell(1, 1)).toBe('B2');
  13388. HOT.redo();
  13389. }, 1000);
  13390. setTimeout(function () {
  13391. expect(getDataAtCell(0, 0)).toBe('X1');
  13392. expect(getDataAtCell(1, 0)).toBe('A2');
  13393. expect(getDataAtCell(0, 1)).toBe('B1');
  13394. expect(getDataAtCell(1, 1)).toBe('B2');
  13395. HOT.redo();
  13396. }, 1200);
  13397. setTimeout(function () {
  13398. expect(getDataAtCell(0, 0)).toBe('X1');
  13399. expect(getDataAtCell(1, 0)).toBe('X2');
  13400. expect(getDataAtCell(0, 1)).toBe('B1');
  13401. expect(getDataAtCell(1, 1)).toBe('B2');
  13402. HOT.redo();
  13403. }, 1400);
  13404. setTimeout(function () {
  13405. expect(getDataAtCell(0, 0)).toBe('X1');
  13406. expect(getDataAtCell(1, 0)).toBe('X2');
  13407. expect(getDataAtCell(0, 1)).toBe('Y1');
  13408. expect(getDataAtCell(1, 1)).toBe('B2');
  13409. HOT.redo();
  13410. }, 1600);
  13411. setTimeout(function () {
  13412. expect(getDataAtCell(0, 0)).toBe('X1');
  13413. expect(getDataAtCell(1, 0)).toBe('X2');
  13414. expect(getDataAtCell(0, 1)).toBe('Y1');
  13415. expect(getDataAtCell(1, 1)).toBe('Y2');
  13416. HOT.redo();
  13417. }, 1800);
  13418. setTimeout(function () {
  13419. expect(getDataAtCell(0, 0)).toBe('X1');
  13420. expect(getDataAtCell(1, 0)).toBe('X2');
  13421. expect(getDataAtCell(0, 1)).toBe('Y1');
  13422. expect(getDataAtCell(1, 1)).toBe('Y2');
  13423. done();
  13424. }, 2000);
  13425. });
  13426. it('should redo multiple row creations', function () {
  13427. var HOT = handsontable({
  13428. data: Handsontable.helper.createSpreadsheetData(2, 2)
  13429. });
  13430. expect(countRows()).toEqual(2);
  13431. alter('insert_row');
  13432. alter('insert_row');
  13433. alter('insert_row');
  13434. alter('insert_row');
  13435. expect(countRows()).toEqual(6);
  13436. HOT.undo();
  13437. HOT.undo();
  13438. HOT.undo();
  13439. HOT.undo();
  13440. expect(countRows()).toEqual(2);
  13441. HOT.redo();
  13442. expect(countRows()).toEqual(3);
  13443. HOT.redo();
  13444. expect(countRows()).toEqual(4);
  13445. HOT.redo();
  13446. expect(countRows()).toEqual(5);
  13447. HOT.redo();
  13448. expect(countRows()).toEqual(6);
  13449. HOT.redo();
  13450. expect(countRows()).toEqual(6);
  13451. });
  13452. it('should undo multiple row removals', function () {
  13453. var HOT = handsontable({
  13454. data: Handsontable.helper.createSpreadsheetData(4, 2)
  13455. });
  13456. expect(countRows()).toEqual(4);
  13457. expect(getDataAtCell(0, 0)).toEqual('A1');
  13458. expect(getDataAtCell(0, 1)).toEqual('B1');
  13459. expect(getDataAtCell(1, 0)).toEqual('A2');
  13460. expect(getDataAtCell(1, 1)).toEqual('B2');
  13461. expect(getDataAtCell(2, 0)).toEqual('A3');
  13462. expect(getDataAtCell(2, 1)).toEqual('B3');
  13463. expect(getDataAtCell(3, 0)).toEqual('A4');
  13464. expect(getDataAtCell(3, 1)).toEqual('B4');
  13465. alter('remove_row');
  13466. alter('remove_row');
  13467. alter('remove_row');
  13468. expect(countRows()).toEqual(1);
  13469. expect(getDataAtCell(0, 0)).toEqual('A1');
  13470. expect(getDataAtCell(0, 1)).toEqual('B1');
  13471. HOT.undo();
  13472. HOT.undo();
  13473. HOT.undo();
  13474. expect(countRows()).toEqual(4);
  13475. expect(getDataAtCell(0, 0)).toEqual('A1');
  13476. expect(getDataAtCell(0, 1)).toEqual('B1');
  13477. expect(getDataAtCell(1, 0)).toEqual('A2');
  13478. expect(getDataAtCell(1, 1)).toEqual('B2');
  13479. expect(getDataAtCell(2, 0)).toEqual('A3');
  13480. expect(getDataAtCell(2, 1)).toEqual('B3');
  13481. expect(getDataAtCell(3, 0)).toEqual('A4');
  13482. expect(getDataAtCell(3, 1)).toEqual('B4');
  13483. HOT.redo();
  13484. expect(countRows()).toEqual(3);
  13485. expect(getDataAtCell(0, 0)).toEqual('A1');
  13486. expect(getDataAtCell(0, 1)).toEqual('B1');
  13487. expect(getDataAtCell(1, 0)).toEqual('A2');
  13488. expect(getDataAtCell(1, 1)).toEqual('B2');
  13489. expect(getDataAtCell(2, 0)).toEqual('A3');
  13490. expect(getDataAtCell(2, 1)).toEqual('B3');
  13491. HOT.redo();
  13492. expect(countRows()).toEqual(2);
  13493. expect(getDataAtCell(0, 0)).toEqual('A1');
  13494. expect(getDataAtCell(0, 1)).toEqual('B1');
  13495. expect(getDataAtCell(1, 0)).toEqual('A2');
  13496. expect(getDataAtCell(1, 1)).toEqual('B2');
  13497. HOT.redo();
  13498. expect(countRows()).toEqual(1);
  13499. expect(getDataAtCell(0, 0)).toEqual('A1');
  13500. expect(getDataAtCell(0, 1)).toEqual('B1');
  13501. HOT.redo();
  13502. expect(countRows()).toEqual(1);
  13503. expect(getDataAtCell(0, 0)).toEqual('A1');
  13504. expect(getDataAtCell(0, 1)).toEqual('B1');
  13505. });
  13506. it('should redo changes only for table where the change actually took place', function () {
  13507. this.$container2 = $('<div id="' + id + '-2"></div>').appendTo('body');
  13508. var hot1 = handsontable({
  13509. data: [[1], [2], [3]]
  13510. });
  13511. this.$container2.handsontable({
  13512. data: [['A'], ['B'], ['C']]
  13513. });
  13514. var hot2 = this.$container2.handsontable('getInstance');
  13515. hot1.setDataAtCell(0, 0, 4);
  13516. expect(hot1.getDataAtCell(0, 0)).toEqual(4);
  13517. expect(hot2.getDataAtCell(0, 0)).toEqual('A');
  13518. hot1.undo();
  13519. expect(hot1.getDataAtCell(0, 0)).toEqual(1);
  13520. expect(hot2.getDataAtCell(0, 0)).toEqual('A');
  13521. hot2.redo();
  13522. expect(hot1.getDataAtCell(0, 0)).toEqual(1);
  13523. expect(hot2.getDataAtCell(0, 0)).toEqual('A');
  13524. hot1.redo();
  13525. expect(hot1.getDataAtCell(0, 0)).toEqual(4);
  13526. expect(hot2.getDataAtCell(0, 0)).toEqual('A');
  13527. hot2.destroy();
  13528. this.$container2.remove();
  13529. });
  13530. });
  13531. });
  13532. describe('Object data', function () {
  13533. function createObjectData() {
  13534. return [{ name: 'Timothy', surname: 'Dalton' }, { name: 'Sean', surname: 'Connery' }, { name: 'Roger', surname: 'Moore' }];
  13535. }
  13536. describe('undo', function () {
  13537. it('should undo single change', function () {
  13538. handsontable({
  13539. data: createObjectData()
  13540. });
  13541. var HOT = getInstance();
  13542. setDataAtRowProp(0, 0, 'Pearce');
  13543. expect(getDataAtRowProp(0, 0)).toBe('Pearce');
  13544. HOT.undo();
  13545. expect(getDataAtCell(0, 0)).toBe('Timothy');
  13546. });
  13547. it('should undo single change in cell with validator', function (done) {
  13548. handsontable({
  13549. data: createObjectData()
  13550. });
  13551. var HOT = getInstance();
  13552. setDataAtRowProp(0, 0, 'Pearce');
  13553. setTimeout(function () {
  13554. expect(getDataAtRowProp(0, 0)).toBe('Pearce');
  13555. HOT.undo();
  13556. }, 200);
  13557. setTimeout(function () {
  13558. expect(getDataAtCell(0, 0)).toBe('Timothy');
  13559. done();
  13560. }, 400);
  13561. });
  13562. it('should undo creation of a single row', function () {
  13563. var HOT = handsontable({
  13564. data: createObjectData().slice(0, 2)
  13565. });
  13566. expect(countRows()).toEqual(2);
  13567. alter('insert_row');
  13568. expect(countRows()).toEqual(3);
  13569. HOT.undo();
  13570. expect(countRows()).toEqual(2);
  13571. });
  13572. it('should undo creation of multiple rows', function () {
  13573. var HOT = handsontable({
  13574. data: createObjectData().slice(0, 2)
  13575. });
  13576. expect(countRows()).toEqual(2);
  13577. alter('insert_row', 0, 5);
  13578. expect(countRows()).toEqual(7);
  13579. HOT.undo();
  13580. expect(countRows()).toEqual(2);
  13581. });
  13582. it('should undo removal of single row', function () {
  13583. var HOT = handsontable({
  13584. data: createObjectData().slice(0, 2)
  13585. });
  13586. expect(countRows()).toEqual(2);
  13587. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13588. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13589. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13590. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13591. alter('remove_row');
  13592. expect(countRows()).toEqual(1);
  13593. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13594. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13595. expect(getDataAtRowProp(1, 'name')).toBeNull();
  13596. expect(getDataAtRowProp(1, 'surname')).toBeNull();
  13597. HOT.undo();
  13598. expect(countRows()).toEqual(2);
  13599. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13600. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13601. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13602. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13603. });
  13604. it('should undo removal of multiple rows', function () {
  13605. var HOT = handsontable({
  13606. data: createObjectData()
  13607. });
  13608. expect(countRows()).toEqual(3);
  13609. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13610. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13611. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13612. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13613. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  13614. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  13615. alter('remove_row', 1, 2);
  13616. expect(countRows()).toEqual(1);
  13617. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13618. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13619. expect(getDataAtRowProp(1, 'name')).toBeNull();
  13620. expect(getDataAtRowProp(1, 'surname')).toBeNull();
  13621. expect(getDataAtRowProp(2, 'name')).toBeNull();
  13622. expect(getDataAtRowProp(2, 'surname')).toBeNull();
  13623. HOT.undo();
  13624. expect(countRows()).toEqual(3);
  13625. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13626. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13627. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13628. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13629. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  13630. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  13631. });
  13632. it('should undo multiple changes', function () {
  13633. handsontable({
  13634. data: createObjectData().slice(0, 2)
  13635. });
  13636. var HOT = getInstance();
  13637. setDataAtRowProp(0, 'name', 'Pierce');
  13638. setDataAtRowProp(0, 'surname', 'Brosnan');
  13639. setDataAtRowProp(1, 'name', 'Daniel');
  13640. setDataAtRowProp(1, 'surname', 'Craig');
  13641. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13642. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13643. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13644. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  13645. HOT.undo();
  13646. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13647. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13648. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13649. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13650. HOT.undo();
  13651. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13652. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13653. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13654. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13655. HOT.undo();
  13656. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13657. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13658. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13659. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13660. HOT.undo();
  13661. expect(getDataAtRowProp(0, 'name')).toBe('Timothy');
  13662. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13663. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13664. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13665. HOT.undo();
  13666. expect(getDataAtRowProp(0, 'name')).toBe('Timothy');
  13667. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13668. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13669. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13670. });
  13671. it('should undo multiple changes in cells with validators', function (done) {
  13672. handsontable({
  13673. data: createObjectData().slice(0, 2)
  13674. });
  13675. var HOT = getInstance();
  13676. setDataAtRowProp(0, 'name', 'Pierce');
  13677. setDataAtRowProp(0, 'surname', 'Brosnan');
  13678. setDataAtRowProp(1, 'name', 'Daniel');
  13679. setDataAtRowProp(1, 'surname', 'Craig');
  13680. setTimeout(function () {
  13681. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13682. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13683. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13684. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  13685. HOT.undo();
  13686. }, 200);
  13687. setTimeout(function () {
  13688. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13689. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13690. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13691. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13692. HOT.undo();
  13693. }, 400);
  13694. setTimeout(function () {
  13695. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13696. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13697. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13698. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13699. HOT.undo();
  13700. }, 600);
  13701. setTimeout(function () {
  13702. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13703. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13704. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13705. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13706. HOT.undo();
  13707. }, 800);
  13708. setTimeout(function () {
  13709. expect(getDataAtRowProp(0, 'name')).toBe('Timothy');
  13710. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13711. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13712. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13713. HOT.undo();
  13714. }, 1000);
  13715. setTimeout(function () {
  13716. expect(getDataAtRowProp(0, 'name')).toBe('Timothy');
  13717. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13718. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13719. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13720. done();
  13721. }, 1200);
  13722. });
  13723. it('should undo multiple row creations', function () {
  13724. var HOT = handsontable({
  13725. data: createObjectData().slice(0, 2)
  13726. });
  13727. expect(countRows()).toEqual(2);
  13728. alter('insert_row');
  13729. alter('insert_row');
  13730. alter('insert_row');
  13731. alter('insert_row');
  13732. expect(countRows()).toEqual(6);
  13733. HOT.undo();
  13734. expect(countRows()).toEqual(5);
  13735. HOT.undo();
  13736. expect(countRows()).toEqual(4);
  13737. HOT.undo();
  13738. expect(countRows()).toEqual(3);
  13739. HOT.undo();
  13740. expect(countRows()).toEqual(2);
  13741. HOT.undo();
  13742. expect(countRows()).toEqual(2);
  13743. });
  13744. it('should undo multiple row removals', function () {
  13745. var HOT = handsontable({
  13746. data: createObjectData()
  13747. });
  13748. expect(countRows()).toEqual(3);
  13749. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13750. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13751. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13752. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13753. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  13754. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  13755. alter('remove_row');
  13756. alter('remove_row');
  13757. expect(countRows()).toEqual(1);
  13758. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13759. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13760. HOT.undo();
  13761. expect(countRows()).toEqual(2);
  13762. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13763. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13764. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13765. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13766. HOT.undo();
  13767. expect(countRows()).toEqual(3);
  13768. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13769. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13770. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13771. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13772. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  13773. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  13774. HOT.undo();
  13775. expect(countRows()).toEqual(3);
  13776. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13777. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13778. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13779. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13780. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  13781. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  13782. });
  13783. });
  13784. describe('redo', function () {
  13785. it('should redo single change', function () {
  13786. handsontable({
  13787. data: createObjectData()
  13788. });
  13789. var HOT = getInstance();
  13790. setDataAtRowProp(0, 0, 'Pearce');
  13791. expect(getDataAtRowProp(0, 0)).toBe('Pearce');
  13792. HOT.undo();
  13793. expect(getDataAtCell(0, 0)).toBe('Timothy');
  13794. HOT.redo();
  13795. expect(getDataAtRowProp(0, 0)).toBe('Pearce');
  13796. });
  13797. it('should redo single change in cell with validator', function (done) {
  13798. handsontable({
  13799. data: createObjectData()
  13800. });
  13801. var HOT = getInstance();
  13802. setDataAtRowProp(0, 0, 'Pearce');
  13803. setTimeout(function () {
  13804. expect(getDataAtRowProp(0, 0)).toBe('Pearce');
  13805. HOT.undo();
  13806. }, 200);
  13807. setTimeout(function () {
  13808. expect(getDataAtCell(0, 0)).toBe('Timothy');
  13809. HOT.redo();
  13810. }, 400);
  13811. setTimeout(function () {
  13812. expect(getDataAtRowProp(0, 0)).toBe('Pearce');
  13813. done();
  13814. }, 600);
  13815. });
  13816. it('should redo creation of a single row', function () {
  13817. var HOT = handsontable({
  13818. data: createObjectData().slice(0, 2)
  13819. });
  13820. expect(countRows()).toEqual(2);
  13821. alter('insert_row');
  13822. expect(countRows()).toEqual(3);
  13823. HOT.undo();
  13824. expect(countRows()).toEqual(2);
  13825. HOT.redo();
  13826. expect(countRows()).toEqual(3);
  13827. });
  13828. it('should redo creation of multiple rows', function () {
  13829. var HOT = handsontable({
  13830. data: createObjectData().slice(0, 2)
  13831. });
  13832. expect(countRows()).toEqual(2);
  13833. alter('insert_row', 0, 5);
  13834. expect(countRows()).toEqual(7);
  13835. HOT.undo();
  13836. expect(countRows()).toEqual(2);
  13837. HOT.redo();
  13838. expect(countRows()).toEqual(7);
  13839. });
  13840. it('should redo removal of single row', function () {
  13841. var HOT = handsontable({
  13842. data: createObjectData().slice(0, 2)
  13843. });
  13844. expect(countRows()).toEqual(2);
  13845. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13846. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13847. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13848. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13849. alter('remove_row');
  13850. expect(countRows()).toEqual(1);
  13851. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13852. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13853. expect(getDataAtRowProp(1, 'name')).toBeNull();
  13854. expect(getDataAtRowProp(1, 'surname')).toBeNull();
  13855. HOT.undo();
  13856. expect(countRows()).toEqual(2);
  13857. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13858. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13859. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13860. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13861. HOT.redo();
  13862. expect(countRows()).toEqual(1);
  13863. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13864. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13865. expect(getDataAtRowProp(1, 'name')).toBeNull();
  13866. expect(getDataAtRowProp(1, 'surname')).toBeNull();
  13867. });
  13868. it('should redo removal of multiple rows', function () {
  13869. var HOT = handsontable({
  13870. data: createObjectData()
  13871. });
  13872. expect(countRows()).toEqual(3);
  13873. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13874. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13875. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13876. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13877. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  13878. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  13879. alter('remove_row', 1, 2);
  13880. expect(countRows()).toEqual(1);
  13881. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13882. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13883. expect(getDataAtRowProp(1, 'name')).toBeNull();
  13884. expect(getDataAtRowProp(1, 'surname')).toBeNull();
  13885. expect(getDataAtRowProp(2, 'name')).toBeNull();
  13886. expect(getDataAtRowProp(2, 'surname')).toBeNull();
  13887. HOT.undo();
  13888. expect(countRows()).toEqual(3);
  13889. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13890. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13891. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  13892. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  13893. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  13894. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  13895. HOT.redo();
  13896. expect(countRows()).toEqual(1);
  13897. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  13898. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  13899. expect(getDataAtRowProp(1, 'name')).toBeNull();
  13900. expect(getDataAtRowProp(1, 'surname')).toBeNull();
  13901. expect(getDataAtRowProp(2, 'name')).toBeNull();
  13902. expect(getDataAtRowProp(2, 'surname')).toBeNull();
  13903. });
  13904. it('should redo multiple changes', function () {
  13905. handsontable({
  13906. data: createObjectData().slice(0, 2)
  13907. });
  13908. var HOT = getInstance();
  13909. setDataAtRowProp(0, 'name', 'Pierce');
  13910. setDataAtRowProp(0, 'surname', 'Brosnan');
  13911. setDataAtRowProp(1, 'name', 'Daniel');
  13912. setDataAtRowProp(1, 'surname', 'Craig');
  13913. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13914. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13915. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13916. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  13917. HOT.undo();
  13918. HOT.undo();
  13919. HOT.undo();
  13920. HOT.undo();
  13921. expect(getDataAtRowProp(0, 'name')).toBe('Timothy');
  13922. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13923. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13924. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13925. HOT.redo();
  13926. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13927. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13928. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13929. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13930. HOT.redo();
  13931. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13932. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13933. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13934. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13935. HOT.redo();
  13936. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13937. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13938. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13939. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13940. HOT.redo();
  13941. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13942. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13943. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13944. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  13945. HOT.redo();
  13946. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13947. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13948. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13949. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  13950. });
  13951. it('should redo multiple changes in cells with validators', function (done) {
  13952. handsontable({
  13953. data: createObjectData().slice(0, 2)
  13954. });
  13955. var HOT = getInstance();
  13956. setDataAtRowProp(0, 'name', 'Pierce');
  13957. setDataAtRowProp(0, 'surname', 'Brosnan');
  13958. setDataAtRowProp(1, 'name', 'Daniel');
  13959. setDataAtRowProp(1, 'surname', 'Craig');
  13960. setTimeout(function () {
  13961. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13962. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13963. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  13964. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  13965. HOT.undo();
  13966. }, 200);
  13967. setTimeout(function () {
  13968. HOT.undo();
  13969. }, 400);
  13970. setTimeout(function () {
  13971. HOT.undo();
  13972. }, 600);
  13973. setTimeout(function () {
  13974. HOT.undo();
  13975. }, 800);
  13976. setTimeout(function () {
  13977. expect(getDataAtRowProp(0, 'name')).toBe('Timothy');
  13978. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13979. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13980. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13981. HOT.redo();
  13982. }, 1000);
  13983. setTimeout(function () {
  13984. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13985. expect(getDataAtRowProp(0, 'surname')).toBe('Dalton');
  13986. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13987. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13988. HOT.redo();
  13989. }, 1200);
  13990. setTimeout(function () {
  13991. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13992. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  13993. expect(getDataAtRowProp(1, 'name')).toBe('Sean');
  13994. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  13995. HOT.redo();
  13996. }, 1400);
  13997. setTimeout(function () {
  13998. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  13999. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  14000. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  14001. expect(getDataAtRowProp(1, 'surname')).toBe('Connery');
  14002. HOT.redo();
  14003. }, 1600);
  14004. setTimeout(function () {
  14005. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  14006. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  14007. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  14008. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  14009. HOT.redo();
  14010. }, 1800);
  14011. setTimeout(function () {
  14012. expect(getDataAtRowProp(0, 'name')).toBe('Pierce');
  14013. expect(getDataAtRowProp(0, 'surname')).toBe('Brosnan');
  14014. expect(getDataAtRowProp(1, 'name')).toBe('Daniel');
  14015. expect(getDataAtRowProp(1, 'surname')).toBe('Craig');
  14016. done();
  14017. }, 2000);
  14018. });
  14019. it('should redo multiple row creations', function () {
  14020. var HOT = handsontable({
  14021. data: createObjectData().slice(0, 2)
  14022. });
  14023. expect(countRows()).toEqual(2);
  14024. alter('insert_row');
  14025. alter('insert_row');
  14026. alter('insert_row');
  14027. alter('insert_row');
  14028. expect(countRows()).toEqual(6);
  14029. HOT.undo();
  14030. HOT.undo();
  14031. HOT.undo();
  14032. HOT.undo();
  14033. expect(countRows()).toEqual(2);
  14034. HOT.redo();
  14035. expect(countRows()).toEqual(3);
  14036. HOT.redo();
  14037. expect(countRows()).toEqual(4);
  14038. HOT.redo();
  14039. expect(countRows()).toEqual(5);
  14040. HOT.redo();
  14041. expect(countRows()).toEqual(6);
  14042. HOT.redo();
  14043. expect(countRows()).toEqual(6);
  14044. });
  14045. it('should undo multiple row removals', function () {
  14046. var HOT = handsontable({
  14047. data: createObjectData()
  14048. });
  14049. expect(countRows()).toEqual(3);
  14050. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  14051. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  14052. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  14053. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  14054. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  14055. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  14056. alter('remove_row');
  14057. alter('remove_row');
  14058. expect(countRows()).toEqual(1);
  14059. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  14060. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  14061. HOT.undo();
  14062. HOT.undo();
  14063. HOT.undo();
  14064. expect(countRows()).toEqual(3);
  14065. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  14066. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  14067. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  14068. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  14069. expect(getDataAtRowProp(2, 'name')).toEqual('Roger');
  14070. expect(getDataAtRowProp(2, 'surname')).toEqual('Moore');
  14071. HOT.redo();
  14072. expect(countRows()).toEqual(2);
  14073. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  14074. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  14075. expect(getDataAtRowProp(1, 'name')).toEqual('Sean');
  14076. expect(getDataAtRowProp(1, 'surname')).toEqual('Connery');
  14077. HOT.redo();
  14078. expect(countRows()).toEqual(1);
  14079. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  14080. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  14081. HOT.redo();
  14082. expect(countRows()).toEqual(1);
  14083. expect(getDataAtRowProp(0, 'name')).toEqual('Timothy');
  14084. expect(getDataAtRowProp(0, 'surname')).toEqual('Dalton');
  14085. });
  14086. });
  14087. });
  14088. });
  14089. describe('plugin features', function () {
  14090. describe('cell alignment', function () {
  14091. it('should undo a sequence of aligning cells', function () {
  14092. var hot = handsontable({
  14093. data: Handsontable.helper.createSpreadsheetData(9, 9),
  14094. contextMenu: true,
  14095. colWidths: [50, 50, 50, 50, 50, 50, 50, 50, 50],
  14096. rowHeights: [50, 50, 50, 50, 50, 50, 50, 50, 50]
  14097. });
  14098. // top 3 rows center
  14099. selectCell(0, 0, 2, 8);
  14100. hot.getPlugin('contextMenu').executeCommand('alignment:center');
  14101. // middle 3 rows unchanged - left
  14102. // bottom 3 rows right
  14103. selectCell(6, 0, 8, 8);
  14104. hot.getPlugin('contextMenu').executeCommand('alignment:right');
  14105. // left 3 columns - middle
  14106. selectCell(0, 0, 8, 2);
  14107. hot.getPlugin('contextMenu').executeCommand('alignment:middle');
  14108. // middle 3 columns unchanged - top
  14109. // right 3 columns - bottom
  14110. selectCell(0, 6, 8, 8);
  14111. hot.getPlugin('contextMenu').executeCommand('alignment:bottom');
  14112. var cellMeta = hot.getCellMeta(0, 0);
  14113. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14114. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14115. cellMeta = hot.getCellMeta(0, 7);
  14116. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14117. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14118. cellMeta = hot.getCellMeta(5, 1);
  14119. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14120. cellMeta = hot.getCellMeta(5, 7);
  14121. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14122. cellMeta = hot.getCellMeta(7, 1);
  14123. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14124. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14125. cellMeta = hot.getCellMeta(7, 5);
  14126. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14127. cellMeta = hot.getCellMeta(7, 7);
  14128. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14129. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14130. hot.undo();
  14131. cellMeta = hot.getCellMeta(0, 7);
  14132. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14133. expect(cellMeta.className.indexOf('htBottom')).toEqual(-1);
  14134. cellMeta = hot.getCellMeta(5, 7);
  14135. expect(cellMeta.className.indexOf('htBottom')).toEqual(-1);
  14136. cellMeta = hot.getCellMeta(7, 7);
  14137. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14138. expect(cellMeta.className.indexOf('htBottom')).toEqual(-1);
  14139. hot.undo();
  14140. cellMeta = hot.getCellMeta(0, 0);
  14141. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14142. expect(cellMeta.className.indexOf('htMiddle')).toEqual(-1);
  14143. cellMeta = hot.getCellMeta(5, 1);
  14144. expect(cellMeta.className.indexOf('htMiddle')).toEqual(-1);
  14145. cellMeta = hot.getCellMeta(7, 1);
  14146. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14147. expect(cellMeta.className.indexOf('htMiddle')).toEqual(-1);
  14148. hot.undo();
  14149. cellMeta = hot.getCellMeta(7, 1);
  14150. expect(cellMeta.className.indexOf('htRight')).toEqual(-1);
  14151. expect(cellMeta.className.indexOf('htMiddle')).toEqual(-1);
  14152. cellMeta = hot.getCellMeta(7, 5);
  14153. expect(cellMeta.className.indexOf('htRight')).toEqual(-1);
  14154. cellMeta = hot.getCellMeta(7, 7);
  14155. expect(cellMeta.className.indexOf('htRight')).toEqual(-1);
  14156. expect(cellMeta.className.indexOf('htBottom')).toEqual(-1);
  14157. hot.undo();
  14158. // check if all cells are either non-adjusted or adjusted to the left (as default)
  14159. var finish;
  14160. for (var i = 0; i < 9; i++) {
  14161. for (var j = 0; j < 9; j++) {
  14162. cellMeta = hot.getCellMeta(i, j);
  14163. finish = cellMeta.className === void 0 || cellMeta.className.trim() === '' || cellMeta.className.trim() === 'htLeft';
  14164. expect(finish).toBe(true);
  14165. }
  14166. }
  14167. });
  14168. it('should redo a sequence of aligning cells', function () {
  14169. var hot = handsontable({
  14170. data: Handsontable.helper.createSpreadsheetData(9, 9),
  14171. contextMenu: true,
  14172. colWidths: [50, 50, 50, 50, 50, 50, 50, 50, 50],
  14173. rowHeights: [50, 50, 50, 50, 50, 50, 50, 50, 50]
  14174. });
  14175. // top 3 rows center
  14176. selectCell(0, 0, 2, 8);
  14177. hot.getPlugin('contextMenu').executeCommand('alignment:center');
  14178. // middle 3 rows unchanged - left
  14179. // bottom 3 rows right
  14180. selectCell(6, 0, 8, 8);
  14181. hot.getPlugin('contextMenu').executeCommand('alignment:right');
  14182. // left 3 columns - middle
  14183. selectCell(0, 0, 8, 2);
  14184. hot.getPlugin('contextMenu').executeCommand('alignment:middle');
  14185. // middle 3 columns unchanged - top
  14186. // right 3 columns - bottom
  14187. selectCell(0, 6, 8, 8);
  14188. hot.getPlugin('contextMenu').executeCommand('alignment:bottom');
  14189. var cellMeta = hot.getCellMeta(0, 0);
  14190. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14191. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14192. cellMeta = hot.getCellMeta(0, 7);
  14193. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14194. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14195. cellMeta = hot.getCellMeta(5, 1);
  14196. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14197. cellMeta = hot.getCellMeta(5, 7);
  14198. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14199. cellMeta = hot.getCellMeta(7, 1);
  14200. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14201. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14202. cellMeta = hot.getCellMeta(7, 5);
  14203. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14204. cellMeta = hot.getCellMeta(7, 7);
  14205. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14206. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14207. hot.undo();
  14208. hot.undo();
  14209. hot.undo();
  14210. hot.undo();
  14211. // check if all cells are either non-adjusted or adjusted to the left (as default)
  14212. var finish;
  14213. for (var i = 0; i < 9; i++) {
  14214. for (var j = 0; j < 9; j++) {
  14215. cellMeta = hot.getCellMeta(i, j);
  14216. finish = cellMeta.className === void 0 || cellMeta.className.trim() === '' || cellMeta.className.trim() === 'htLeft';
  14217. expect(finish).toBe(true);
  14218. }
  14219. }
  14220. hot.redo();
  14221. cellMeta = hot.getCellMeta(0, 0);
  14222. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14223. cellMeta = hot.getCellMeta(1, 5);
  14224. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14225. cellMeta = hot.getCellMeta(2, 8);
  14226. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14227. hot.redo();
  14228. cellMeta = hot.getCellMeta(6, 0);
  14229. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14230. cellMeta = hot.getCellMeta(7, 5);
  14231. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14232. cellMeta = hot.getCellMeta(8, 8);
  14233. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14234. hot.redo();
  14235. cellMeta = hot.getCellMeta(0, 0);
  14236. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14237. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14238. cellMeta = hot.getCellMeta(5, 1);
  14239. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14240. cellMeta = hot.getCellMeta(8, 2);
  14241. expect(cellMeta.className.indexOf('htMiddle')).toBeGreaterThan(-1);
  14242. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14243. hot.redo();
  14244. cellMeta = hot.getCellMeta(0, 6);
  14245. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14246. expect(cellMeta.className.indexOf('htCenter')).toBeGreaterThan(-1);
  14247. cellMeta = hot.getCellMeta(5, 7);
  14248. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14249. cellMeta = hot.getCellMeta(8, 8);
  14250. expect(cellMeta.className.indexOf('htBottom')).toBeGreaterThan(-1);
  14251. expect(cellMeta.className.indexOf('htRight')).toBeGreaterThan(-1);
  14252. });
  14253. });
  14254. it('should exposed new methods when plugin is enabled', function () {
  14255. var hot = handsontable({
  14256. undo: false
  14257. });
  14258. expect(hot.undo).toBeUndefined();
  14259. expect(hot.redo).toBeUndefined();
  14260. expect(hot.isUndoAvailable).toBeUndefined();
  14261. expect(hot.isRedoAvailable).toBeUndefined();
  14262. expect(hot.clearUndo).toBeUndefined();
  14263. updateSettings({
  14264. undo: true
  14265. });
  14266. expect(_typeof(hot.undo)).toEqual('function');
  14267. expect(_typeof(hot.redo)).toEqual('function');
  14268. expect(_typeof(hot.isUndoAvailable)).toEqual('function');
  14269. expect(_typeof(hot.isRedoAvailable)).toEqual('function');
  14270. expect(_typeof(hot.clearUndo)).toEqual('function');
  14271. });
  14272. it('should remove exposed methods when plugin is disbaled', function () {
  14273. var hot = handsontable({
  14274. undo: true
  14275. });
  14276. expect(_typeof(hot.undo)).toEqual('function');
  14277. expect(_typeof(hot.redo)).toEqual('function');
  14278. expect(_typeof(hot.isUndoAvailable)).toEqual('function');
  14279. expect(_typeof(hot.isRedoAvailable)).toEqual('function');
  14280. expect(_typeof(hot.clearUndo)).toEqual('function');
  14281. updateSettings({
  14282. undo: false
  14283. });
  14284. expect(hot.undo).toBeUndefined();
  14285. expect(hot.redo).toBeUndefined();
  14286. expect(hot.isUndoAvailable).toBeUndefined();
  14287. expect(hot.isRedoAvailable).toBeUndefined();
  14288. expect(hot.clearUndo).toBeUndefined();
  14289. });
  14290. describe('Keyboard shortcuts', function () {
  14291. it('should undo single change after hitting CTRL+Z', function () {
  14292. handsontable({
  14293. data: Handsontable.helper.createSpreadsheetData(2, 2)
  14294. });
  14295. var HOT = getInstance();
  14296. selectCell(0, 0);
  14297. setDataAtCell(0, 0, 'new value');
  14298. this.$container.simulate('keydown', { ctrlKey: true, keyCode: 'Z'.charCodeAt(0) });
  14299. expect(getDataAtCell(0, 0)).toBe('A1');
  14300. });
  14301. it('should redo single change after hitting CTRL+Y', function () {
  14302. handsontable({
  14303. data: Handsontable.helper.createSpreadsheetData(2, 2)
  14304. });
  14305. var HOT = getInstance();
  14306. selectCell(0, 0);
  14307. setDataAtCell(0, 0, 'new value');
  14308. expect(getDataAtCell(0, 0)).toBe('new value');
  14309. HOT.undo();
  14310. expect(getDataAtCell(0, 0)).toBe('A1');
  14311. this.$container.simulate('keydown', { ctrlKey: true, keyCode: 'Y'.charCodeAt(0) });
  14312. expect(getDataAtCell(0, 0)).toBe('new value');
  14313. });
  14314. it('should redo single change after hitting CTRL+SHIFT+Z', function () {
  14315. handsontable({
  14316. data: Handsontable.helper.createSpreadsheetData(2, 2)
  14317. });
  14318. var HOT = getInstance();
  14319. selectCell(0, 0);
  14320. setDataAtCell(0, 0, 'new value');
  14321. expect(getDataAtCell(0, 0)).toBe('new value');
  14322. HOT.undo();
  14323. expect(getDataAtCell(0, 0)).toBe('A1');
  14324. this.$container.simulate('keydown', { ctrlKey: true, shiftKey: true, keyCode: 'Z'.charCodeAt(0) });
  14325. expect(getDataAtCell(0, 0)).toBe('new value');
  14326. });
  14327. });
  14328. });
  14329. describe('Hooks', function () {
  14330. it('should fire a `beforeUndo` hook after the undo process begins', function (done) {
  14331. var beforeUndoSpy = jasmine.createSpy('beforeUndo');
  14332. var hot = handsontable({
  14333. data: Handsontable.helper.createSpreadsheetData(2, 2)
  14334. });
  14335. var hookData = null;
  14336. hot.addHook('beforeUndo', beforeUndoSpy);
  14337. hot.addHook('beforeUndo', function (data) {
  14338. hookData = data;
  14339. });
  14340. alter('remove_row', 1);
  14341. setTimeout(function () {
  14342. hot.undo();
  14343. }, 10);
  14344. setTimeout(function () {
  14345. expect(beforeUndoSpy.calls.count()).toEqual(1);
  14346. expect(hookData).not.toBe(null);
  14347. expect(hookData.actionType).toEqual('remove_row');
  14348. expect(hookData.data).toEqual([['A2', 'B2']]);
  14349. done();
  14350. }, 100);
  14351. });
  14352. it('should fire a `beforeRedo` hook before the redo process begins', function (done) {
  14353. var beforeRedoSpy = jasmine.createSpy('beforeRedo');
  14354. var hot = handsontable({
  14355. data: Handsontable.helper.createSpreadsheetData(2, 2)
  14356. });
  14357. var hookData = null;
  14358. hot.addHook('beforeRedo', beforeRedoSpy);
  14359. hot.addHook('beforeRedo', function (data) {
  14360. hookData = data;
  14361. });
  14362. alter('remove_row', 1);
  14363. setTimeout(function () {
  14364. hot.undo();
  14365. hot.redo();
  14366. }, 10);
  14367. setTimeout(function () {
  14368. expect(beforeRedoSpy.calls.count()).toEqual(1);
  14369. expect(hookData).not.toBe(null);
  14370. expect(hookData.actionType).toEqual('remove_row');
  14371. expect(hookData.data).toEqual([['A2', 'B2']]);
  14372. done();
  14373. }, 100);
  14374. });
  14375. it('should fire a `afterRedo` hook after the redo process begins', function (done) {
  14376. var afterRedoSpy = jasmine.createSpy('afterRedo');
  14377. var hot = handsontable({
  14378. data: Handsontable.helper.createSpreadsheetData(2, 2)
  14379. });
  14380. var hookData = null;
  14381. hot.addHook('beforeRedo', afterRedoSpy);
  14382. hot.addHook('beforeRedo', function (data) {
  14383. hookData = data;
  14384. });
  14385. alter('remove_row', 1);
  14386. setTimeout(function () {
  14387. hot.undo();
  14388. hot.redo();
  14389. }, 10);
  14390. setTimeout(function () {
  14391. expect(afterRedoSpy.calls.count()).toEqual(1);
  14392. expect(hookData).not.toBe(null);
  14393. expect(hookData.actionType).toEqual('remove_row');
  14394. expect(hookData.data).toEqual([['A2', 'B2']]);
  14395. done();
  14396. }, 100);
  14397. });
  14398. });
  14399. });
  14400. /***/ }),
  14401. /* 149 */
  14402. /***/ (function(module, exports, __webpack_require__) {
  14403. "use strict";
  14404. describe('ColHeader', function () {
  14405. var id = 'testContainer';
  14406. beforeEach(function () {
  14407. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  14408. });
  14409. afterEach(function () {
  14410. if (this.$container) {
  14411. destroy();
  14412. this.$container.remove();
  14413. }
  14414. });
  14415. it('should not show col headers by default', function () {
  14416. var that = this;
  14417. handsontable();
  14418. expect(that.$container.find('thead th').length).toEqual(0);
  14419. });
  14420. it('should show col headers if true', function () {
  14421. var that = this;
  14422. handsontable({
  14423. colHeaders: true
  14424. });
  14425. expect(that.$container.find('thead th').length).toBeGreaterThan(0);
  14426. });
  14427. it('should show default columns headers labelled A-(Z * n)', function () {
  14428. var that = this;
  14429. var startCols = 5;
  14430. handsontable({
  14431. startCols: startCols,
  14432. colHeaders: true
  14433. });
  14434. var ths = getHtCore().find('thead th');
  14435. expect(ths.length).toEqual(startCols);
  14436. expect($.trim(ths.eq(0).text())).toEqual('A');
  14437. expect($.trim(ths.eq(1).text())).toEqual('B');
  14438. expect($.trim(ths.eq(2).text())).toEqual('C');
  14439. expect($.trim(ths.eq(3).text())).toEqual('D');
  14440. expect($.trim(ths.eq(4).text())).toEqual('E');
  14441. });
  14442. it('should show default columns headers labelled A-(Z * n) when columns as an array is present', function () {
  14443. var that = this;
  14444. var startCols = 5;
  14445. handsontable({
  14446. startCols: startCols,
  14447. colHeaders: true,
  14448. columns: [{}, {}, {}, {}, {}]
  14449. });
  14450. var ths = getHtCore().find('thead th');
  14451. expect(ths.length).toEqual(startCols);
  14452. expect($.trim(ths.eq(0).text())).toEqual('A');
  14453. expect($.trim(ths.eq(1).text())).toEqual('B');
  14454. expect($.trim(ths.eq(2).text())).toEqual('C');
  14455. expect($.trim(ths.eq(3).text())).toEqual('D');
  14456. expect($.trim(ths.eq(4).text())).toEqual('E');
  14457. });
  14458. it('should show default columns headers labelled A-(Z * n) when columns as a function is present', function () {
  14459. var that = this;
  14460. var startCols = 5;
  14461. handsontable({
  14462. startCols: startCols,
  14463. colHeaders: true,
  14464. columns: function columns(column) {
  14465. return {};
  14466. }
  14467. });
  14468. var ths = getHtCore().find('thead th');
  14469. expect(ths.length).toEqual(startCols);
  14470. expect($.trim(ths.eq(0).text())).toEqual('A');
  14471. expect($.trim(ths.eq(1).text())).toEqual('B');
  14472. expect($.trim(ths.eq(2).text())).toEqual('C');
  14473. expect($.trim(ths.eq(3).text())).toEqual('D');
  14474. expect($.trim(ths.eq(4).text())).toEqual('E');
  14475. });
  14476. it('should show col headers with custom label', function () {
  14477. var that = this;
  14478. var startCols = 5;
  14479. handsontable({
  14480. startCols: startCols,
  14481. colHeaders: ['First', 'Second', 'Third']
  14482. });
  14483. var ths = getHtCore().find('thead th');
  14484. expect(ths.length).toEqual(startCols);
  14485. expect($.trim(ths.eq(0).text())).toEqual('First');
  14486. expect($.trim(ths.eq(1).text())).toEqual('Second');
  14487. expect($.trim(ths.eq(2).text())).toEqual('Third');
  14488. expect($.trim(ths.eq(3).text())).toEqual('D');
  14489. expect($.trim(ths.eq(4).text())).toEqual('E');
  14490. });
  14491. it('should not show col headers if false', function () {
  14492. var that = this;
  14493. handsontable({
  14494. colHeaders: false
  14495. });
  14496. expect(that.$container.find('th.htColHeader').length).toEqual(0);
  14497. });
  14498. it('should hide columns headers after updateSettings', function () {
  14499. var hot = handsontable({
  14500. startCols: 5,
  14501. colHeaders: true
  14502. });
  14503. expect(getHtCore().find('thead th').length).toEqual(5);
  14504. expect(getTopClone().find('thead th').length).toEqual(5);
  14505. hot.updateSettings({
  14506. colHeaders: false
  14507. });
  14508. expect(getHtCore().find('thead th').length).toEqual(0);
  14509. expect(getTopClone().width()).toEqual(0);
  14510. });
  14511. it('should show/hide columns headers after updateSettings', function () {
  14512. var hot = handsontable({
  14513. startCols: 5,
  14514. colHeaders: true
  14515. });
  14516. expect(getHtCore().find('thead th').length).toEqual(5);
  14517. expect(getTopClone().find('thead th').length).toEqual(5);
  14518. hot.updateSettings({
  14519. colHeaders: false
  14520. });
  14521. expect(getHtCore().find('thead th').length).toEqual(0);
  14522. expect(getTopClone().width()).toEqual(0);
  14523. hot.updateSettings({
  14524. colHeaders: true
  14525. });
  14526. expect(getHtCore().find('thead th').length).toEqual(5);
  14527. expect(getTopClone().width()).toBeGreaterThan(0);
  14528. hot.updateSettings({
  14529. colHeaders: false
  14530. });
  14531. expect(getHtCore().find('thead th').length).toEqual(0);
  14532. expect(getTopClone().width()).toEqual(0);
  14533. });
  14534. it('should show columns headers after updateSettings', function () {
  14535. var hot = handsontable({
  14536. startCols: 5,
  14537. colHeaders: false
  14538. });
  14539. expect(getHtCore().find('thead th').length).toEqual(0);
  14540. expect(getTopClone().find('thead th').length).toEqual(0);
  14541. hot.updateSettings({
  14542. colHeaders: true
  14543. });
  14544. expect(getHtCore().find('thead th').length).toEqual(5);
  14545. expect(getTopClone().find('thead th').length).toEqual(5);
  14546. });
  14547. it('should show new columns headers after updateSettings', function () {
  14548. var hot = handsontable({
  14549. startCols: 3,
  14550. colHeaders: ['A', 'B', 'C']
  14551. });
  14552. var htCore = getHtCore();
  14553. expect(htCore.find('thead th:eq(0)').text()).toEqual('A');
  14554. expect(htCore.find('thead th:eq(1)').text()).toEqual('B');
  14555. expect(htCore.find('thead th:eq(2)').text()).toEqual('C');
  14556. hot.updateSettings({
  14557. colHeaders: ['X', 'Y', 'Z']
  14558. });
  14559. expect(htCore.find('thead th:eq(0)').text()).toEqual('X');
  14560. expect(htCore.find('thead th:eq(1)').text()).toEqual('Y');
  14561. expect(htCore.find('thead th:eq(2)').text()).toEqual('Z');
  14562. });
  14563. it('should be possible to define colHeaders with a function', function () {
  14564. var hot = handsontable({
  14565. startCols: 2,
  14566. colHeaders: function colHeaders(col) {
  14567. switch (col) {
  14568. case 0:
  14569. return 'One';
  14570. case 1:
  14571. return 'Two';
  14572. default:
  14573. break;
  14574. }
  14575. }
  14576. });
  14577. var htCore = getHtCore();
  14578. expect(htCore.find('thead th:eq(0)').text()).toEqual('One');
  14579. expect(htCore.find('thead th:eq(1)').text()).toEqual('Two');
  14580. });
  14581. it('should be possible to set HTML in colHeaders', function () {
  14582. var hot = handsontable({
  14583. startCols: 2,
  14584. colHeaders: ['One <input type="checkbox">', 'Two <input type="checkbox">']
  14585. });
  14586. var htCore = getHtCore();
  14587. expect(htCore.find('thead th:eq(0) input[type=checkbox]').length).toEqual(1);
  14588. expect(htCore.find('thead th:eq(1) input[type=checkbox]').length).toEqual(1);
  14589. });
  14590. it('should be possible to set colHeaders when columns array is present', function () {
  14591. var hot = handsontable({
  14592. startCols: 2,
  14593. colHeaders: ['One', 'Two'],
  14594. columns: [{ type: 'text' }, { type: 'text' }]
  14595. });
  14596. var htCore = getHtCore();
  14597. expect(htCore.find('thead th:eq(0)').text()).toEqual('One');
  14598. expect(htCore.find('thead th:eq(1)').text()).toEqual('Two');
  14599. });
  14600. it('should be possible to set colHeaders when columns function is present', function () {
  14601. var hot = handsontable({
  14602. startCols: 2,
  14603. colHeaders: ['One', 'Two'],
  14604. columns: function columns(column) {
  14605. var colMeta = { type: 'text' };
  14606. if ([0, 1].indexOf(column) < 0) {
  14607. colMeta = null;
  14608. }
  14609. return colMeta;
  14610. }
  14611. });
  14612. var htCore = getHtCore();
  14613. expect(htCore.find('thead th:eq(0)').text()).toEqual('One');
  14614. expect(htCore.find('thead th:eq(1)').text()).toEqual('Two');
  14615. });
  14616. it('should be possible to set colHeaders using columns title property', function () {
  14617. var hot = handsontable({
  14618. startCols: 2,
  14619. colHeaders: ['One', 'Two'],
  14620. columns: [{ type: 'text', title: 'Special title' }, { type: 'text' }]
  14621. });
  14622. var htCore = getHtCore();
  14623. expect(htCore.find('thead th:eq(0)').text()).toEqual('Special title');
  14624. expect(htCore.find('thead th:eq(1)').text()).toEqual('Two');
  14625. });
  14626. it('should be possible to set colHeaders using columns title property when columns is a function', function () {
  14627. var hot = handsontable({
  14628. startCols: 2,
  14629. colHeaders: ['One', 'Two'],
  14630. columns: function columns(column) {
  14631. var colMeta = { type: 'text' };
  14632. if (column === 0) {
  14633. colMeta.title = 'Special title';
  14634. }
  14635. if ([0, 1].indexOf(column) < 0) {
  14636. colMeta = null;
  14637. }
  14638. return colMeta;
  14639. }
  14640. });
  14641. var htCore = getHtCore();
  14642. expect(htCore.find('thead th:eq(0)').text()).toEqual('Special title');
  14643. expect(htCore.find('thead th:eq(1)').text()).toEqual('Two');
  14644. });
  14645. it('should resize all the column headers in the overlays, according to the other overlays\' height', function () {
  14646. var hot = handsontable({
  14647. startCols: 5,
  14648. colHeaders: ['a', 'a', 'a', 'a<BR>a', 'a'],
  14649. fixedColumnsLeft: 2
  14650. });
  14651. var topHeaderExample = $('.ht_clone_top').find('thead tr:first-child th:nth-child(1)'),
  14652. masterHeaderExample = $('.ht_master').find('thead tr:first-child th:nth-child(3)');
  14653. expect(topHeaderExample.height()).toEqual(masterHeaderExample.height());
  14654. });
  14655. it('should allow defining custom column header height using the columnHeaderHeight config option', function () {
  14656. var hot = handsontable({
  14657. startCols: 3,
  14658. colHeaders: true,
  14659. columnHeaderHeight: 40
  14660. });
  14661. hot.render();
  14662. expect(this.$container.find('th').eq(0).height()).toEqual(40);
  14663. });
  14664. it('should allow defining custom column header heights using the columnHeaderHeight config option, when multiple column header levels are defined', function () {
  14665. var hot = handsontable({
  14666. startCols: 3,
  14667. colHeaders: true,
  14668. columnHeaderHeight: [45, 65],
  14669. afterGetColumnHeaderRenderers: function afterGetColumnHeaderRenderers(array) {
  14670. array.push(function (index, TH) {
  14671. TH.innerHTML = '';
  14672. var div = document.createElement('div');
  14673. var span = document.createElement('span');
  14674. div.className = 'relative';
  14675. span.className = 'colHeader';
  14676. span.innerText = index;
  14677. div.appendChild(span);
  14678. TH.appendChild(div);
  14679. });
  14680. return array;
  14681. }
  14682. });
  14683. hot.render();
  14684. expect(this.$container.find('.handsontable.ht_clone_top tr:nth-child(1) th:nth-child(1)').height()).toEqual(45);
  14685. expect(this.$container.find('.handsontable.ht_clone_top tr:nth-child(2) th:nth-child(1)').height()).toEqual(65);
  14686. });
  14687. });
  14688. /***/ }),
  14689. /* 150 */
  14690. /***/ (function(module, exports, __webpack_require__) {
  14691. "use strict";
  14692. describe('Core_alter', function () {
  14693. var id = 'testContainer';
  14694. beforeEach(function () {
  14695. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  14696. });
  14697. afterEach(function () {
  14698. if (this.$container) {
  14699. destroy();
  14700. this.$container.remove();
  14701. }
  14702. });
  14703. var arrayOfNestedObjects = function arrayOfNestedObjects() {
  14704. return [{ id: 1,
  14705. name: {
  14706. first: 'Ted',
  14707. last: 'Right'
  14708. },
  14709. address: 'Street Name',
  14710. zip: '80410',
  14711. city: 'City Name' }, { id: 2,
  14712. name: {
  14713. first: 'Frank',
  14714. last: 'Honest'
  14715. },
  14716. address: 'Street Name',
  14717. zip: '80410',
  14718. city: 'City Name' }, { id: 3,
  14719. name: {
  14720. first: 'Joan',
  14721. last: 'Well'
  14722. },
  14723. address: 'Street Name',
  14724. zip: '80410',
  14725. city: 'City Name' }];
  14726. };
  14727. var arrayOfArrays = function arrayOfArrays() {
  14728. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  14729. };
  14730. describe('remove row', function () {
  14731. it('should remove row', function () {
  14732. handsontable({
  14733. minRows: 5,
  14734. data: arrayOfNestedObjects(),
  14735. columns: [{ data: 'id' }, { data: 'name.first' }]
  14736. });
  14737. alter('remove_row', 1);
  14738. expect(getDataAtCell(1, 1)).toEqual('Joan'); // Joan should be moved up
  14739. expect(getData().length).toEqual(5); // new row should be added by keepEmptyRows
  14740. });
  14741. it('should fire beforeRemoveRow event before removing row', function () {
  14742. var onBeforeRemoveRow = jasmine.createSpy('onBeforeRemoveRow');
  14743. var hot = handsontable({
  14744. data: arrayOfNestedObjects(),
  14745. columns: [{ data: 'id' }, { data: 'name.first' }],
  14746. beforeRemoveRow: onBeforeRemoveRow
  14747. });
  14748. alter('remove_row', 2, 1, 'customSource');
  14749. expect(onBeforeRemoveRow).toHaveBeenCalledWith(countRows(), 1, [2], 'customSource', undefined, undefined);
  14750. });
  14751. it('should not remove row if removing has been canceled by beforeRemoveRow event handler', function () {
  14752. var onBeforeRemoveRow = jasmine.createSpy('onBeforeRemoveRow');
  14753. onBeforeRemoveRow.and.callFake(function () {
  14754. return false;
  14755. });
  14756. var hot = handsontable({
  14757. data: arrayOfNestedObjects(),
  14758. columns: [{ data: 'id' }, { data: 'name.first' }],
  14759. beforeRemoveRow: onBeforeRemoveRow
  14760. });
  14761. expect(countRows()).toEqual(3);
  14762. alter('remove_row');
  14763. expect(countRows()).toEqual(3);
  14764. });
  14765. it('should not remove rows below minRows', function () {
  14766. handsontable({
  14767. startRows: 5,
  14768. minRows: 4
  14769. });
  14770. alter('remove_row', 1);
  14771. alter('remove_row', 1);
  14772. alter('remove_row', 1);
  14773. expect(countRows()).toEqual(4);
  14774. });
  14775. it('should not remove cols below minCols', function () {
  14776. handsontable({
  14777. startCols: 5,
  14778. minCols: 4
  14779. });
  14780. alter('remove_col', 1);
  14781. alter('remove_col', 1);
  14782. alter('remove_col', 1);
  14783. expect(countCols()).toEqual(4);
  14784. });
  14785. it('should remove one row if amount parameter is empty', function () {
  14786. handsontable({
  14787. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  14788. });
  14789. alter('remove_row', 1);
  14790. expect(countRows()).toEqual(4);
  14791. expect(this.$container.find('tr:eq(0) td:eq(0)').html()).toEqual('a1');
  14792. expect(this.$container.find('tr:eq(1) td:eq(1)').html()).toEqual('c2');
  14793. });
  14794. it('should remove as many rows as given in the amount parameter', function () {
  14795. handsontable({
  14796. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  14797. });
  14798. alter('remove_row', 1, 3);
  14799. expect(countRows()).toEqual(2);
  14800. expect(this.$container.find('tr:eq(0) td:eq(0)').html()).toEqual('a1');
  14801. expect(this.$container.find('tr:eq(1) td:eq(1)').html()).toEqual('e2');
  14802. });
  14803. it('should not remove more rows that exist', function () {
  14804. handsontable({
  14805. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  14806. });
  14807. alter('remove_row', 1, 10);
  14808. expect(countRows()).toEqual(1);
  14809. expect(getHtCore().find('tr:last td:last').html()).toEqual('a3');
  14810. });
  14811. it('should remove one row from end if no parameters are given', function () {
  14812. handsontable({
  14813. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  14814. });
  14815. alter('remove_row');
  14816. expect(countRows()).toEqual(4);
  14817. expect(getHtCore().find('tr:last td:eq(0)').html()).toEqual('d1');
  14818. });
  14819. it('should remove amount of rows from end if index parameter is not given', function () {
  14820. handsontable({
  14821. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  14822. });
  14823. alter('remove_row', null, 3);
  14824. expect(countRows()).toEqual(2);
  14825. expect(getHtCore().find('tr:last td:eq(0)').html()).toEqual('b1');
  14826. });
  14827. it('should remove rows from table with fixedRows', function () {
  14828. handsontable({
  14829. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']],
  14830. fixedRowsTop: 1,
  14831. minSpareRows: 0
  14832. });
  14833. alter('remove_row', 1);
  14834. expect(countRows()).toEqual(1);
  14835. });
  14836. it('should remove all rows from table with fixedRows', function () {
  14837. handsontable({
  14838. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']],
  14839. fixedRowsTop: 1,
  14840. minSpareRows: 0
  14841. });
  14842. alter('remove_row', 1);
  14843. alter('remove_row', 1);
  14844. expect(countRows()).toEqual(0);
  14845. });
  14846. it('should remove row\'s cellProperties', function () {
  14847. handsontable({
  14848. startCols: 1,
  14849. startRows: 3
  14850. });
  14851. getCellMeta(0, 0).someValue = [0, 0];
  14852. getCellMeta(1, 0).someValue = [1, 0];
  14853. getCellMeta(2, 0).someValue = [2, 0];
  14854. alter('remove_row', 0);
  14855. expect(getCellMeta(0, 0).someValue).toEqual([1, 0]);
  14856. expect(getCellMeta(1, 0).someValue).toEqual([2, 0]);
  14857. });
  14858. it('should fire callback on remove row', function () {
  14859. var outputBefore;
  14860. var outputAfter;
  14861. handsontable({
  14862. minRows: 5,
  14863. data: arrayOfNestedObjects(),
  14864. columns: [{ data: 'id' }, { data: 'name.first' }],
  14865. beforeRemoveRow: function beforeRemoveRow(index, amount, removedRows, source) {
  14866. outputBefore = [index, amount, removedRows, source];
  14867. },
  14868. afterRemoveRow: function afterRemoveRow(index, amount, removedRows, source) {
  14869. outputAfter = [index, amount, removedRows, source];
  14870. }
  14871. });
  14872. alter('remove_row', 1, 2, 'customSource');
  14873. expect(outputBefore).toEqual([1, 2, [1, 2], 'customSource']);
  14874. expect(outputAfter).toEqual([1, 2, [1, 2], 'customSource']);
  14875. });
  14876. it('should decrement the number of fixed rows, if a fix row is removed', function () {
  14877. var hot = handsontable({
  14878. startCols: 1,
  14879. startRows: 3,
  14880. fixedRowsTop: 4
  14881. });
  14882. alter('remove_row', 1, 1);
  14883. expect(hot.getSettings().fixedRowsTop).toEqual(3);
  14884. alter('remove_row', 1, 2);
  14885. expect(hot.getSettings().fixedRowsTop).toEqual(1);
  14886. });
  14887. it('should shift the cell meta according to the new row layout', function () {
  14888. var hot = handsontable({
  14889. startCols: 3,
  14890. startRows: 4
  14891. });
  14892. setCellMeta(2, 1, 'className', 'test');
  14893. alter('remove_row', 1, 1);
  14894. expect(getCellMeta(1, 1).className).toEqual('test');
  14895. });
  14896. it('should shift the cell meta according to the new rows (>1) layout', function () {
  14897. var hot = handsontable({
  14898. startCols: 3,
  14899. startRows: 4
  14900. });
  14901. setCellMeta(2, 1, 'className', 'test');
  14902. alter('remove_row', 0, 2);
  14903. expect(getCellMeta(0, 1).className).toEqual('test');
  14904. });
  14905. });
  14906. describe('remove column', function () {
  14907. it('should remove one column if amount parameter is empty', function () {
  14908. handsontable({
  14909. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  14910. });
  14911. alter('remove_col', 1);
  14912. expect(countCols()).toEqual(7);
  14913. expect(this.$container.find('tr:eq(0) td:eq(0)').html()).toEqual('a');
  14914. expect(this.$container.find('tr:eq(1) td:eq(1)').html()).toEqual('c');
  14915. });
  14916. it('should remove as many columns as given in the amount parameter', function () {
  14917. handsontable({
  14918. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  14919. });
  14920. alter('remove_col', 1, 3);
  14921. expect(countCols()).toEqual(5);
  14922. expect(this.$container.find('tr:eq(0) td:eq(0)').html()).toEqual('a');
  14923. expect(this.$container.find('tr:eq(1) td:eq(1)').html()).toEqual('e');
  14924. });
  14925. it('should not remove more columns that exist', function () {
  14926. handsontable({
  14927. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  14928. });
  14929. alter('remove_col', 6, 3);
  14930. expect(countCols()).toEqual(6);
  14931. expect(this.$container.find('tr:eq(1) td:last').html()).toEqual('f');
  14932. });
  14933. it('should remove one column from end if no parameters are given', function () {
  14934. handsontable({
  14935. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  14936. });
  14937. alter('remove_col');
  14938. expect(countCols()).toEqual(7);
  14939. expect(this.$container.find('tr:eq(1) td:last').html()).toEqual('g');
  14940. });
  14941. it('should remove amount of columns from end if index parameter is not given', function () {
  14942. handsontable({
  14943. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  14944. });
  14945. alter('remove_col', null, 3);
  14946. expect(countCols()).toEqual(5);
  14947. expect(this.$container.find('tr:eq(1) td:last').html()).toEqual('e');
  14948. });
  14949. it('should fire beforeRemoveCol event before removing col', function () {
  14950. var onBeforeRemoveCol = jasmine.createSpy('onBeforeRemoveCol');
  14951. var hot = handsontable({
  14952. beforeRemoveCol: onBeforeRemoveCol
  14953. });
  14954. alter('remove_col');
  14955. expect(onBeforeRemoveCol).toHaveBeenCalledWith(countCols(), 1, [4], undefined, undefined, undefined);
  14956. });
  14957. it('should not remove column if removing has been canceled by beforeRemoveCol event handler', function () {
  14958. var onBeforeRemoveCol = jasmine.createSpy('onBeforeRemoveCol');
  14959. onBeforeRemoveCol.and.callFake(function () {
  14960. return false;
  14961. });
  14962. var hot = handsontable({
  14963. beforeRemoveCol: onBeforeRemoveCol
  14964. });
  14965. expect(countCols()).toEqual(5);
  14966. alter('remove_col');
  14967. expect(countCols()).toEqual(5);
  14968. });
  14969. it('should fire callback on remove col', function () {
  14970. var outputBefore;
  14971. var outputAfter;
  14972. handsontable({
  14973. minRows: 5,
  14974. data: arrayOfArrays(),
  14975. beforeRemoveCol: function beforeRemoveCol(index, amount, removedCols, source) {
  14976. outputBefore = [index, amount, removedCols, source];
  14977. },
  14978. afterRemoveCol: function afterRemoveCol(index, amount, removedCols, source) {
  14979. outputAfter = [index, amount, removedCols, source];
  14980. }
  14981. });
  14982. alter('remove_col', 1, 2, 'customSource');
  14983. expect(outputBefore).toEqual([1, 2, [1, 2], 'customSource']);
  14984. expect(outputAfter).toEqual([1, 2, [1, 2], 'customSource']);
  14985. });
  14986. it('should remove column\'s properties', function () {
  14987. handsontable({
  14988. startCols: 3,
  14989. startRows: 1
  14990. });
  14991. getCellMeta(0, 0).someValue = [0, 0];
  14992. getCellMeta(0, 1).someValue = [0, 1];
  14993. getCellMeta(0, 2).someValue = [0, 2];
  14994. alter('remove_col', 0);
  14995. expect(getCellMeta(0, 0).someValue).toEqual([0, 1]);
  14996. expect(getCellMeta(0, 1).someValue).toEqual([0, 2]);
  14997. });
  14998. it('should remove column when not all rows are visible in the viewport', function () {
  14999. this.$container.css({
  15000. height: '100',
  15001. overflow: 'auto'
  15002. });
  15003. handsontable({
  15004. startCols: 3,
  15005. startRows: 20
  15006. });
  15007. expect(getHtCore().find('tbody tr').length).toBeLessThan(20);
  15008. expect(countCols()).toEqual(3);
  15009. alter('remove_col', 0);
  15010. expect(countCols()).toEqual(2);
  15011. });
  15012. it('should not remove column header together with the column, if headers were NOT specified explicitly', function () {
  15013. handsontable({
  15014. startCols: 3,
  15015. startRows: 2,
  15016. colHeaders: true
  15017. });
  15018. expect(getColHeader()).toEqual(['A', 'B', 'C']);
  15019. expect(countCols()).toEqual(3);
  15020. alter('remove_col', 1);
  15021. expect(countCols()).toEqual(2);
  15022. expect(getColHeader()).toEqual(['A', 'B']);
  15023. });
  15024. it('should remove column header together with the column, if headers were specified explicitly', function () {
  15025. handsontable({
  15026. startCols: 3,
  15027. startRows: 2,
  15028. colHeaders: ['Header0', 'Header1', 'Header2']
  15029. });
  15030. expect(getColHeader()).toEqual(['Header0', 'Header1', 'Header2']);
  15031. expect(countCols()).toEqual(3);
  15032. alter('remove_col', 1);
  15033. expect(countCols()).toEqual(2);
  15034. expect(getColHeader()).toEqual(['Header0', 'Header2']);
  15035. });
  15036. it('should decrement the number of fixed columns, if a fix column is removed', function () {
  15037. var hot = handsontable({
  15038. startCols: 1,
  15039. startRows: 3,
  15040. fixedColumnsLeft: 4
  15041. });
  15042. alter('remove_col', 1, 1);
  15043. expect(hot.getSettings().fixedColumnsLeft).toEqual(3);
  15044. alter('remove_col', 1, 2);
  15045. expect(hot.getSettings().fixedColumnsLeft).toEqual(1);
  15046. });
  15047. it('should shift the cell meta according to the new column layout', function () {
  15048. var hot = handsontable({
  15049. startCols: 4,
  15050. startRows: 3
  15051. });
  15052. setCellMeta(1, 2, 'className', 'test');
  15053. alter('remove_col', 1, 1);
  15054. expect(getCellMeta(1, 1).className).toEqual('test');
  15055. });
  15056. it('should shift the cell meta according to the new columns (>1) layout', function () {
  15057. var hot = handsontable({
  15058. startCols: 4,
  15059. startRows: 3
  15060. });
  15061. setCellMeta(1, 2, 'className', 'test');
  15062. alter('remove_col', 0, 2);
  15063. expect(getCellMeta(1, 0).className).toEqual('test');
  15064. });
  15065. });
  15066. describe('insert row', function () {
  15067. it('should insert row at given index', function () {
  15068. handsontable({
  15069. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  15070. });
  15071. alter('insert_row', 1);
  15072. expect(countRows()).toEqual(6);
  15073. expect(this.$container.find('tr:eq(2) td:eq(0)').html()).toEqual('b1');
  15074. });
  15075. it('should insert row at the end if index is not given', function () {
  15076. handsontable({
  15077. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  15078. });
  15079. alter('insert_row');
  15080. expect(countRows()).toEqual(6);
  15081. expect(getHtCore().find('tr:eq(4) td:eq(0)').html()).toEqual('e1');
  15082. expect(getHtCore().find('tr:last td:eq(0)').html()).toEqual('');
  15083. });
  15084. it('should not change cellMeta after executing `insert row` without parameters (#3581, #3989, #2114)', function () {
  15085. var greenRenderer = function greenRenderer(instance, td, row, col, prop, value, cellProperties) {
  15086. Handsontable.renderers.TextRenderer.apply(this, arguments);
  15087. td.style.backgroundColor = 'green';
  15088. };
  15089. handsontable({
  15090. data: [[0, 'a', true], [1, 'b', false], [2, 'c', true], [3, 'd', true]],
  15091. cell: [{ row: 0, col: 0, renderer: greenRenderer, type: 'text', readOnly: true }],
  15092. columns: [{ type: 'numeric' }, { type: 'text' }, { type: 'checkbox' }]
  15093. });
  15094. alter('insert_row');
  15095. expect(getCellMeta(1, 0).renderer).not.toBe(greenRenderer);
  15096. expect(getCellMeta(1, 0).readOnly).toBe(false);
  15097. expect(getCellMeta(4, 0).renderer).not.toBe(greenRenderer);
  15098. expect(getCellMeta(4, 0).readOnly).toBe(false);
  15099. });
  15100. it('should add new row which respect defined type of cells after executing `insert_row`', function () {
  15101. handsontable({
  15102. data: [[0, 'a', true], [1, 'b', false], [2, 'c', true], [3, 'd', true]],
  15103. cell: [{ row: 0, col: 0, type: 'text' }],
  15104. columns: [{ type: 'numeric' }, { type: 'text' }, { type: 'checkbox' }]
  15105. });
  15106. alter('insert_row');
  15107. // added row
  15108. expect(getCellMeta(4, 0).type).toEqual('numeric');
  15109. expect(getDataAtCell(4, 0)).toEqual(null);
  15110. expect(getCellMeta(4, 2).type).toEqual('checkbox');
  15111. expect(getDataAtCell(4, 2)).toEqual(null);
  15112. });
  15113. it('should insert the amount of rows at given index', function () {
  15114. handsontable({
  15115. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  15116. });
  15117. alter('insert_row', 1, 3);
  15118. expect(countRows()).toEqual(8);
  15119. expect(this.$container.find('tr:eq(1) td:eq(0)').html()).toEqual('');
  15120. expect(this.$container.find('tr:eq(4) td:eq(0)').html()).toEqual('b1');
  15121. });
  15122. it('should insert the amount of rows at the end if index is not given', function () {
  15123. handsontable({
  15124. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']]
  15125. });
  15126. alter('insert_row', null, 3);
  15127. expect(countRows()).toEqual(8);
  15128. expect(getHtCore().find('tr:eq(4) td:eq(0)').html()).toEqual('e1');
  15129. expect(getHtCore().find('tr:eq(5) td:eq(0)').html()).toEqual('');
  15130. expect(getHtCore().find('tr:eq(6) td:eq(0)').html()).toEqual('');
  15131. expect(getHtCore().find('tr:eq(7) td:eq(0)').html()).toEqual('');
  15132. });
  15133. it('should insert not more rows than maxRows', function () {
  15134. handsontable({
  15135. startRows: 5,
  15136. maxRows: 7
  15137. });
  15138. alter('insert_row', 1);
  15139. alter('insert_row', 1);
  15140. alter('insert_row', 1);
  15141. expect(countRows()).toEqual(7);
  15142. });
  15143. it('when amount parameter is used, should not insert more rows than allowed by maxRows', function () {
  15144. handsontable({
  15145. data: [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3'], ['d1', 'd2', 'd3'], ['e1', 'e2', 'e3']],
  15146. maxRows: 10
  15147. });
  15148. alter('insert_row', 1, 10);
  15149. expect(countRows()).toEqual(10);
  15150. expect(this.$container.find('tr:eq(6) td:eq(0)').html()).toEqual('b1');
  15151. });
  15152. it('should not add more source rows than defined in maxRows when trimming rows using the modifyRow hook', function () {
  15153. var hot = handsontable({
  15154. data: Handsontable.helper.createSpreadsheetData(10, 4),
  15155. modifyRow: function modifyRow(row) {
  15156. return [8, 9].indexOf(row) > -1 ? null : row;
  15157. },
  15158. maxRows: 10
  15159. });
  15160. expect(hot.countRows()).toEqual(8);
  15161. hot.populateFromArray(7, 0, [['a'], ['b'], ['c']]);
  15162. expect(hot.countSourceRows()).toEqual(10);
  15163. expect(hot.getDataAtCell(7, 0)).toEqual('a');
  15164. });
  15165. it('should fire callback on create row', function () {
  15166. var outputBefore;
  15167. var outputAfter;
  15168. handsontable({
  15169. minRows: 5,
  15170. data: arrayOfNestedObjects(),
  15171. columns: [{ data: 'id' }, { data: 'name.first' }],
  15172. beforeCreateRow: function beforeCreateRow(index, amount, source) {
  15173. outputBefore = [index, amount, source];
  15174. },
  15175. afterCreateRow: function afterCreateRow(index, amount, source) {
  15176. outputAfter = [index, amount, source];
  15177. }
  15178. });
  15179. alter('insert_row', 3, 1, 'customSource');
  15180. expect(outputBefore).toEqual([3, 1, 'customSource']);
  15181. expect(outputAfter).toEqual([3, 1, 'customSource']);
  15182. });
  15183. it('should keep the single-cell selection in the same position as before inserting the row', function () {
  15184. handsontable({
  15185. minRows: 5,
  15186. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  15187. });
  15188. selectCell(2, 2);
  15189. alter('insert_row', 2);
  15190. var selected = getSelected();
  15191. expect(selected[0]).toEqual(3);
  15192. expect(selected[2]).toEqual(3);
  15193. });
  15194. it('should shift the cell meta according to the new row layout', function () {
  15195. var hot = handsontable({
  15196. startCols: 4,
  15197. startRows: 3
  15198. });
  15199. setCellMeta(2, 1, 'className', 'test');
  15200. alter('insert_row', 1, 1);
  15201. expect(getCellMeta(3, 1).className).toEqual('test');
  15202. });
  15203. it('should shift the cell meta according to the new rows (>1) layout', function () {
  15204. var hot = handsontable({
  15205. startCols: 4,
  15206. startRows: 3
  15207. });
  15208. setCellMeta(2, 1, 'className', 'test');
  15209. alter('insert_row', 0, 3);
  15210. expect(getCellMeta(5, 1).className).toEqual('test');
  15211. });
  15212. });
  15213. describe('insert column', function () {
  15214. it('should insert column at given index', function () {
  15215. handsontable({
  15216. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  15217. });
  15218. alter('insert_col', 1);
  15219. expect(countCols()).toEqual(9);
  15220. expect(this.$container.find('tr:eq(1) td:eq(2)').html()).toEqual('b');
  15221. });
  15222. it('should insert column at the end if index is not given', function () {
  15223. handsontable({
  15224. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  15225. });
  15226. alter('insert_col');
  15227. expect(countCols()).toEqual(9);
  15228. expect(this.$container.find('tr:eq(1) td:eq(7)').html()).toEqual('h');
  15229. });
  15230. it('should insert the amount of columns at given index', function () {
  15231. handsontable({
  15232. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  15233. });
  15234. alter('insert_col', 1, 3);
  15235. expect(countCols()).toEqual(11);
  15236. expect(this.$container.find('tr:eq(1) td:eq(4)').html()).toEqual('b');
  15237. });
  15238. it('should insert the amount of columns at the end if index is not given', function () {
  15239. handsontable({
  15240. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']]
  15241. });
  15242. alter('insert_col', null, 3);
  15243. expect(countCols()).toEqual(11);
  15244. expect(this.$container.find('tr:eq(1) td:eq(7)').html()).toEqual('h');
  15245. expect(this.$container.find('tr:eq(1) td:eq(8)').html()).toEqual('');
  15246. expect(this.$container.find('tr:eq(1) td:eq(9)').html()).toEqual('');
  15247. expect(this.$container.find('tr:eq(1) td:eq(10)').html()).toEqual('');
  15248. });
  15249. it('should insert not more cols than maxCols', function () {
  15250. handsontable({
  15251. startCols: 5,
  15252. maxCols: 7
  15253. });
  15254. alter('insert_col', 1);
  15255. alter('insert_col', 1);
  15256. alter('insert_col', 1);
  15257. expect(countCols()).toEqual(7);
  15258. });
  15259. it('should not insert more columns than allowed by maxCols, when amount parameter is used', function () {
  15260. handsontable({
  15261. data: [['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']],
  15262. maxCols: 10
  15263. });
  15264. alter('insert_col', 1, 10);
  15265. expect(countCols()).toEqual(10);
  15266. expect(this.$container.find('tr:eq(1) td:eq(1)').html()).toEqual('');
  15267. expect(this.$container.find('tr:eq(1) td:eq(2)').html()).toEqual('');
  15268. expect(this.$container.find('tr:eq(1) td:eq(3)').html()).toEqual('b');
  15269. });
  15270. it('should fire callback on create col', function () {
  15271. var outputBefore;
  15272. var outputAfter;
  15273. handsontable({
  15274. minRows: 5,
  15275. data: arrayOfArrays(),
  15276. beforeCreateCol: function beforeCreateCol(index, amount, source) {
  15277. outputBefore = [index, amount, source];
  15278. },
  15279. afterCreateCol: function afterCreateCol(index, amount, source) {
  15280. outputAfter = [index, amount, source];
  15281. }
  15282. });
  15283. alter('insert_col', 2, 1, 'customSource');
  15284. expect(outputBefore).toEqual([2, 1, 'customSource']);
  15285. expect(outputAfter).toEqual([2, 1, 'customSource']);
  15286. });
  15287. it('should not create column header together with the column, if headers were NOT specified explicitly', function () {
  15288. handsontable({
  15289. startCols: 3,
  15290. startRows: 2,
  15291. colHeaders: true
  15292. });
  15293. expect(getColHeader()).toEqual(['A', 'B', 'C']);
  15294. expect(countCols()).toEqual(3);
  15295. alter('insert_col', 1);
  15296. expect(countCols()).toEqual(4);
  15297. expect(getColHeader()).toEqual(['A', 'B', 'C', 'D']);
  15298. });
  15299. it('should create column header together with the column, if headers were specified explicitly', function () {
  15300. handsontable({
  15301. startCols: 3,
  15302. startRows: 2,
  15303. colHeaders: ['Header0', 'Header1', 'Header2']
  15304. });
  15305. expect(getColHeader()).toEqual(['Header0', 'Header1', 'Header2']);
  15306. expect(countCols()).toEqual(3);
  15307. alter('insert_col', 1);
  15308. expect(countCols()).toEqual(4);
  15309. expect(getColHeader()).toEqual(['Header0', 'B', 'Header1', 'Header2']);
  15310. });
  15311. it('should stretch the table after adding another column (if stretching is set to \'all\')', function () {
  15312. this.$container.css({
  15313. width: 500
  15314. });
  15315. var hot = handsontable({
  15316. startCols: 5,
  15317. startRows: 10,
  15318. stretchH: 'all'
  15319. });
  15320. expect(Handsontable.dom.outerWidth(hot.view.TBODY)).toEqual(500);
  15321. alter('insert_col', null, 1);
  15322. expect(Handsontable.dom.outerWidth(hot.view.TBODY)).toEqual(500);
  15323. alter('insert_col', null, 1);
  15324. expect(Handsontable.dom.outerWidth(hot.view.TBODY)).toEqual(500);
  15325. });
  15326. it('should shift the cell meta according to the new column layout', function () {
  15327. var hot = handsontable({
  15328. startCols: 4,
  15329. startRows: 3
  15330. });
  15331. setCellMeta(1, 2, 'className', 'test');
  15332. alter('insert_col', 1, 1);
  15333. expect(getCellMeta(1, 3).className).toEqual('test');
  15334. });
  15335. it('should shift the cell meta according to the new columns (>1) layout', function () {
  15336. var hot = handsontable({
  15337. startCols: 4,
  15338. startRows: 3
  15339. });
  15340. setCellMeta(1, 2, 'className', 'test');
  15341. alter('insert_col', 0, 3);
  15342. expect(getCellMeta(1, 5).className).toEqual('test');
  15343. });
  15344. });
  15345. });
  15346. /***/ }),
  15347. /* 151 */
  15348. /***/ (function(module, exports, __webpack_require__) {
  15349. "use strict";
  15350. describe('Core_beforeKeyDown', function () {
  15351. var id = 'testContainer';
  15352. beforeEach(function () {
  15353. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  15354. });
  15355. afterEach(function () {
  15356. if (this.$container) {
  15357. destroy();
  15358. this.$container.remove();
  15359. }
  15360. });
  15361. it('should run beforeKeyDown hook', function () {
  15362. var called = false;
  15363. handsontable({
  15364. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  15365. beforeKeyDown: function beforeKeyDown(event) {
  15366. called = true;
  15367. }
  15368. });
  15369. selectCell(0, 0);
  15370. keyDown('arrow_right');
  15371. expect(called).toEqual(true);
  15372. });
  15373. it('should run afterDocumentKeyDown and beforeKeyDown hook', function () {
  15374. var called = [];
  15375. handsontable({
  15376. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  15377. afterDocumentKeyDown: function afterDocumentKeyDown() {
  15378. called.push('afterDocumentKeyDown');
  15379. },
  15380. beforeKeyDown: function beforeKeyDown() {
  15381. called.push('beforeKeyDown');
  15382. }
  15383. });
  15384. selectCell(0, 0);
  15385. keyDown('arrow_right');
  15386. expect(called).toEqual(['afterDocumentKeyDown', 'beforeKeyDown']);
  15387. });
  15388. it('should prevent hook from running default action', function () {
  15389. var called = false;
  15390. handsontable({
  15391. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  15392. beforeKeyDown: function beforeKeyDown(event) {
  15393. event = serveImmediatePropagation(event);
  15394. event.stopImmediatePropagation();
  15395. called = true;
  15396. }
  15397. });
  15398. selectCell(0, 0);
  15399. keyDown('arrow_right');
  15400. expect(getSelected()).toEqual([0, 0, 0, 0]);
  15401. expect(getSelected()).not.toEqual([0, 1, 0, 1]);
  15402. });
  15403. it('should overwrite default behavior of delete key, but not this of right arrow', function () {
  15404. var called = 0;
  15405. handsontable({
  15406. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  15407. beforeKeyDown: function beforeKeyDown(event) {
  15408. if (event.keyCode === 8) {
  15409. event.stopImmediatePropagation();
  15410. getInstance().alter('insert_row', 1, 1);
  15411. }
  15412. called++;
  15413. }
  15414. });
  15415. selectCell(0, 0);
  15416. keyDown('backspace');
  15417. keyDown('arrow_right');
  15418. expect(getData().length).toEqual(3);
  15419. expect(getSelected()).toEqual([0, 1, 0, 1]);
  15420. });
  15421. it('should run beforeKeyDown hook in cell editor handler', function () {
  15422. var called = 0;
  15423. handsontable({
  15424. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  15425. beforeKeyDown: function beforeKeyDown(event) {
  15426. called++;
  15427. }
  15428. });
  15429. selectCell(0, 0);
  15430. keyDown('enter');
  15431. keyDown('enter');
  15432. expect(called).toEqual(2);
  15433. });
  15434. });
  15435. /***/ }),
  15436. /* 152 */
  15437. /***/ (function(module, exports, __webpack_require__) {
  15438. "use strict";
  15439. describe('Core_beforechange', function () {
  15440. var id = 'testContainer';
  15441. beforeEach(function () {
  15442. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  15443. });
  15444. afterEach(function () {
  15445. if (this.$container) {
  15446. destroy();
  15447. this.$container.remove();
  15448. }
  15449. });
  15450. it('this.rootElement should point to handsontable rootElement', function () {
  15451. var output = null;
  15452. handsontable({
  15453. beforeChange: function beforeChange() {
  15454. output = this.rootElement;
  15455. }
  15456. });
  15457. setDataAtCell(0, 0, 'test');
  15458. expect(output).toEqual(this.$container[0]);
  15459. });
  15460. it('should remove change from stack', function () {
  15461. var output = null;
  15462. handsontable({
  15463. data: [['a', 'b'], ['c', 'd']],
  15464. beforeChange: function beforeChange(changes) {
  15465. changes[1] = null;
  15466. },
  15467. afterChange: function afterChange(changes) {
  15468. output = changes;
  15469. }
  15470. });
  15471. setDataAtCell([[0, 0, 'test'], [1, 0, 'test'], [1, 1, 'test']]);
  15472. expect(getDataAtCell(0, 0)).toEqual('test');
  15473. expect(getDataAtCell(1, 0)).toEqual('c');
  15474. expect(getDataAtCell(1, 1)).toEqual('test');
  15475. expect(output).toEqual([[0, 0, 'a', 'test'], [1, 1, 'd', 'test']]);
  15476. });
  15477. it('should drop all changes when beforeChange return false', function () {
  15478. var fired = false;
  15479. handsontable({
  15480. data: [['a', 'b'], ['c', 'd']],
  15481. beforeChange: function beforeChange(changes) {
  15482. fired = true;
  15483. return false;
  15484. }
  15485. });
  15486. setDataAtCell([[0, 0, 'test'], [1, 0, 'test'], [1, 1, 'test']]);
  15487. expect(getDataAtCell(0, 0)).toEqual('a');
  15488. expect(getDataAtCell(1, 0)).toEqual('c');
  15489. expect(getDataAtCell(1, 1)).toEqual('d');
  15490. });
  15491. function beforechangeOnKeyFactory(keyCode) {
  15492. return function () {
  15493. var called = false;
  15494. handsontable({
  15495. beforeChange: function beforeChange(changes) {
  15496. if (changes[0][2] === 'test' && changes[0][3] === '') {
  15497. called = true;
  15498. }
  15499. }
  15500. });
  15501. setDataAtCell(0, 0, 'test');
  15502. selectCell(0, 0);
  15503. keyDown(keyCode);
  15504. expect(called).toEqual(true);
  15505. };
  15506. }
  15507. it('should be called on Delete key', beforechangeOnKeyFactory(46)); // 46 = Delete key
  15508. it('should be called on Backspace key', beforechangeOnKeyFactory(8)); // 8 = Backspace key
  15509. });
  15510. /***/ }),
  15511. /* 153 */
  15512. /***/ (function(module, exports, __webpack_require__) {
  15513. "use strict";
  15514. function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
  15515. describe('Core_copy', function () {
  15516. var id = 'testContainer';
  15517. beforeEach(function () {
  15518. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  15519. });
  15520. afterEach(function () {
  15521. if (this.$container) {
  15522. destroy();
  15523. this.$container.remove();
  15524. }
  15525. });
  15526. var arrayOfArrays = function arrayOfArrays() {
  15527. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  15528. };
  15529. it('should set copyable text until copyRowsLimit is reached', function () {
  15530. handsontable({
  15531. data: arrayOfArrays(),
  15532. copyRowsLimit: 2
  15533. });
  15534. selectCell(0, 0, countRows() - 1, countCols() - 1); // selectAll
  15535. keyDownUp('ctrl');
  15536. // should prepare 2 rows for copying
  15537. expect($('textarea.copyPaste').val()).toEqual('\tKia\tNissan\tToyota\tHonda\n2008\t10\t11\t12\t13');
  15538. });
  15539. it('should set copyable text until copyColsLimit is reached', function () {
  15540. handsontable({
  15541. data: arrayOfArrays(),
  15542. copyColsLimit: 2
  15543. });
  15544. selectCell(0, 0, countRows() - 1, countCols() - 1); // selectAll
  15545. keyDownUp('ctrl');
  15546. // should prepare 2 columns for copying
  15547. expect($('textarea.copyPaste').val()).toEqual('\tKia\n2008\t10\n2009\t20\n2010\t30');
  15548. });
  15549. it('should call onCopyLimit callback when copy limit was reached', function () {
  15550. var result;
  15551. handsontable({
  15552. data: arrayOfArrays(),
  15553. copyRowsLimit: 2,
  15554. copyColsLimit: 2,
  15555. afterCopyLimit: function afterCopyLimit(selectedRowsCount, selectedColsCount, copyRowsLimit, copyColsLimit) {
  15556. result = [selectedRowsCount, selectedColsCount, copyRowsLimit, copyColsLimit];
  15557. }
  15558. });
  15559. selectCell(0, 0, countRows() - 1, countCols() - 1); // selectAll
  15560. keyDownUp('ctrl');
  15561. expect(result).toEqual([4, 5, 2, 2]);
  15562. });
  15563. it('ctrl+x should cut selected data', _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
  15564. var hot;
  15565. return regeneratorRuntime.wrap(function _callee$(_context) {
  15566. while (1) {
  15567. switch (_context.prev = _context.next) {
  15568. case 0:
  15569. hot = handsontable({
  15570. data: arrayOfArrays()
  15571. });
  15572. selectCell(0, 0, countRows() - 1, countCols() - 1); // selectAll
  15573. keyDownUp('ctrl+x');
  15574. _context.next = 5;
  15575. return sleep(300);
  15576. case 5:
  15577. expect(hot.getDataAtCell(0, 0)).toEqual('');
  15578. expect(hot.getDataAtCell(1, 1)).toEqual('');
  15579. expect(hot.getDataAtCell(2, 2)).toEqual('');
  15580. case 8:
  15581. case 'end':
  15582. return _context.stop();
  15583. }
  15584. }
  15585. }, _callee, undefined);
  15586. })));
  15587. it('ctrl+v should paste copied data to selected range', _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
  15588. var hot;
  15589. return regeneratorRuntime.wrap(function _callee2$(_context2) {
  15590. while (1) {
  15591. switch (_context2.prev = _context2.next) {
  15592. case 0:
  15593. hot = handsontable({
  15594. data: arrayOfArrays()
  15595. });
  15596. $('textarea.copyPaste').val('\tKia\tNissan\tToyota\tHonda\n2008\t10\t11\t12\t13');
  15597. selectCell(0, 0, countRows() - 1, countCols() - 1); // selectAll
  15598. keyDownUp('ctrl+v');
  15599. _context2.next = 6;
  15600. return sleep(200);
  15601. case 6:
  15602. expect(hot.getDataAtCell(0, 0)).toEqual('');
  15603. expect(hot.getDataAtCell(0, 1)).toEqual('Kia');
  15604. expect(hot.getDataAtCell(0, 2)).toEqual('Nissan');
  15605. expect(hot.getDataAtCell(0, 3)).toEqual('Toyota');
  15606. expect(hot.getDataAtCell(1, 0)).toEqual('2008');
  15607. expect(hot.getDataAtCell(1, 1)).toEqual('10');
  15608. expect(hot.getDataAtCell(1, 2)).toEqual('11');
  15609. expect(hot.getDataAtCell(1, 3)).toEqual('12');
  15610. case 14:
  15611. case 'end':
  15612. return _context2.stop();
  15613. }
  15614. }
  15615. }, _callee2, undefined);
  15616. })));
  15617. });
  15618. /***/ }),
  15619. /* 154 */
  15620. /***/ (function(module, exports, __webpack_require__) {
  15621. "use strict";
  15622. describe('Core_count', function () {
  15623. var id = 'testContainer';
  15624. beforeEach(function () {
  15625. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  15626. });
  15627. afterEach(function () {
  15628. destroy();
  15629. this.$container.remove();
  15630. });
  15631. describe('countVisibleRows', function () {
  15632. it('should return number of visible rows', function () {
  15633. var instance = handsontable({
  15634. data: Handsontable.helper.createSpreadsheetData(10, 10),
  15635. height: 100,
  15636. width: 600
  15637. });
  15638. expect(instance.countVisibleRows()).toEqual(4);
  15639. });
  15640. it('should return -1 if table is not rendered', function () {
  15641. this.$container.remove();
  15642. var instance = handsontable({
  15643. data: Handsontable.helper.createSpreadsheetData(10, 10),
  15644. width: 100
  15645. });
  15646. expect(instance.countVisibleRows()).toEqual(-1);
  15647. });
  15648. });
  15649. describe('countRenderedRows', function () {
  15650. it('should return number of rendered rows', function () {
  15651. var instance = handsontable({
  15652. data: Handsontable.helper.createSpreadsheetData(10, 10),
  15653. height: 100,
  15654. viewportRowRenderingOffset: 0
  15655. });
  15656. expect(instance.countRenderedRows()).toEqual(5);
  15657. });
  15658. it('should return number of rendered rows, including rows rendered becausee of viewportRowRenderingOffset', function () {
  15659. var instance = handsontable({
  15660. data: Handsontable.helper.createSpreadsheetData(50, 10),
  15661. height: 100,
  15662. viewportRowRenderingOffset: 20
  15663. });
  15664. expect(instance.countRenderedRows()).toEqual(25);
  15665. });
  15666. it('should return -1 if table is not rendered', function () {
  15667. this.$container.remove();
  15668. var instance = handsontable({
  15669. data: Handsontable.helper.createSpreadsheetData(10, 10),
  15670. width: 100
  15671. });
  15672. expect(instance.countRenderedRows()).toEqual(-1);
  15673. });
  15674. });
  15675. describe('countVisibleCols', function () {
  15676. it('should return number of visible columns', function () {
  15677. var instance = handsontable({
  15678. data: Handsontable.helper.createSpreadsheetData(10, 10),
  15679. width: 100
  15680. });
  15681. expect(instance.countVisibleCols()).toEqual(10);
  15682. });
  15683. it('should return -1 if table is not rendered', function () {
  15684. this.$container.remove();
  15685. var instance = handsontable({
  15686. data: Handsontable.helper.createSpreadsheetData(10, 10),
  15687. width: 100
  15688. });
  15689. expect(instance.countVisibleCols()).toEqual(-1);
  15690. });
  15691. });
  15692. });
  15693. /***/ }),
  15694. /* 155 */
  15695. /***/ (function(module, exports, __webpack_require__) {
  15696. "use strict";
  15697. describe('Core_dataSchema', function () {
  15698. var id = 'testContainer';
  15699. beforeEach(function () {
  15700. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  15701. });
  15702. afterEach(function () {
  15703. if (this.$container) {
  15704. destroy();
  15705. this.$container.remove();
  15706. }
  15707. });
  15708. it('should be equal to `hot.getSchema()` when dataSchema is defined in settings (as object)', function () {
  15709. var schema = { id: null, name: { first: null, last: null }, cars: [{ brand: null }] },
  15710. hot = handsontable({
  15711. data: [],
  15712. dataSchema: schema,
  15713. minRows: 5,
  15714. minCols: 4,
  15715. colHeaders: ['ID', 'First Name', 'Last Name'],
  15716. columns: [{ data: 'id' }, { data: 'name.first' }, { data: 'name.last' }],
  15717. minSpareRows: 1
  15718. });
  15719. expect(JSON.stringify(hot.getSchema())).toEqual(JSON.stringify(schema));
  15720. });
  15721. it('should be equal to `hot.getSchema()` when dataSchema is defined in settings (as object) when columns is a function', function () {
  15722. var schema = { id: null, name: { first: null, last: null }, cars: [{ brand: null }] },
  15723. hot = handsontable({
  15724. data: [],
  15725. dataSchema: schema,
  15726. minRows: 5,
  15727. minCols: 4,
  15728. colHeaders: ['ID', 'First Name', 'Last Name'],
  15729. columns: function columns(column) {
  15730. var colMeta = {};
  15731. if (column === 0) {
  15732. colMeta.data = 'id';
  15733. } else if (column === 1) {
  15734. colMeta.data = 'name.first';
  15735. } else if (column === 2) {
  15736. colMeta.data = 'name.last';
  15737. } else {
  15738. colMeta = null;
  15739. }
  15740. return colMeta;
  15741. },
  15742. minSpareRows: 1
  15743. });
  15744. expect(JSON.stringify(hot.getSchema())).toEqual(JSON.stringify(schema));
  15745. });
  15746. it('should be equal to `hot.getSchema()` when dataSchema is defined in settings (as function)', function () {
  15747. var schema = { id: null, name: { first: null, last: null }, cars: [{ brand: null }] },
  15748. hot = handsontable({
  15749. data: [],
  15750. dataSchema: function dataSchema() {
  15751. return schema;
  15752. },
  15753. minRows: 5,
  15754. minCols: 4,
  15755. colHeaders: ['ID', 'First Name', 'Last Name'],
  15756. columns: [{ data: 'id' }, { data: 'name.first' }, { data: 'name.last' }],
  15757. minSpareRows: 1
  15758. });
  15759. expect(JSON.stringify(hot.getSchema())).toEqual(JSON.stringify(schema));
  15760. });
  15761. it('should be equal to `hot.getSchema()` when dataSchema is defined in settings (as function) when columns is a function', function () {
  15762. var schema = { id: null, name: { first: null, last: null }, cars: [{ brand: null }] },
  15763. hot = handsontable({
  15764. data: [],
  15765. dataSchema: function dataSchema() {
  15766. return schema;
  15767. },
  15768. minRows: 5,
  15769. minCols: 4,
  15770. colHeaders: ['ID', 'First Name', 'Last Name'],
  15771. columns: function columns(column) {
  15772. var colMeta = {};
  15773. if (column === 0) {
  15774. colMeta.data = 'id';
  15775. } else if (column === 1) {
  15776. colMeta.data = 'name.first';
  15777. } else if (column === 2) {
  15778. colMeta.data = 'name.last';
  15779. } else {
  15780. colMeta = null;
  15781. }
  15782. return colMeta;
  15783. },
  15784. minSpareRows: 1
  15785. });
  15786. expect(JSON.stringify(hot.getSchema())).toEqual(JSON.stringify(schema));
  15787. });
  15788. it('should be equal to `hot.getSchema()` when dataSchema is generated based on data structure', function () {
  15789. var hot = handsontable({
  15790. data: [{ id: 1, name: { first: 'Alan', last: 'Pakoli' }, cars: [{ brand: 'Ford' }] }],
  15791. minRows: 5,
  15792. minCols: 4,
  15793. colHeaders: ['ID', 'First Name', 'Last Name'],
  15794. columns: [{ data: 'id' }, { data: 'name.first' }, { data: 'name.last' }],
  15795. minSpareRows: 1
  15796. });
  15797. expect(JSON.stringify(hot.getSchema())).toEqual(JSON.stringify({ id: null, name: { first: null, last: null }, cars: [{ brand: null }] }));
  15798. });
  15799. it('should be equal to `hot.getSchema()` when dataSchema is generated based on data structure when columns is a function', function () {
  15800. var hot = handsontable({
  15801. data: [{ id: 1, name: { first: 'Alan', last: 'Pakoli' }, cars: [{ brand: 'Ford' }] }],
  15802. minRows: 5,
  15803. minCols: 4,
  15804. colHeaders: ['ID', 'First Name', 'Last Name'],
  15805. columns: function columns(column) {
  15806. var colMeta = {};
  15807. if (column === 0) {
  15808. colMeta.data = 'id';
  15809. } else if (column === 1) {
  15810. colMeta.data = 'name.first';
  15811. } else if (column === 2) {
  15812. colMeta.data = 'name.last';
  15813. } else {
  15814. colMeta = null;
  15815. }
  15816. return colMeta;
  15817. },
  15818. minSpareRows: 1
  15819. });
  15820. expect(JSON.stringify(hot.getSchema())).toEqual(JSON.stringify({ id: null, name: { first: null, last: null }, cars: [{ brand: null }] }));
  15821. });
  15822. it('should create new row from dataSchema', function () {
  15823. handsontable({
  15824. data: [],
  15825. dataSchema: { id: null, name: { first: null, last: null }, address: null },
  15826. minRows: 5,
  15827. minCols: 4,
  15828. colHeaders: ['ID', 'First Name', 'Last Name', 'Address'],
  15829. columns: [{ data: 'id' }, { data: 'name.first' }, { data: 'name.last' }, { data: 'address' }],
  15830. minSpareRows: 1
  15831. });
  15832. selectCell(0, 1);
  15833. keyDownUp('enter');
  15834. keyProxy().val('Ted');
  15835. keyDownUp('enter');
  15836. expect(getData()[0][1]).toEqual('Ted');
  15837. expect(getSourceData()[0].name.first).toEqual('Ted');
  15838. });
  15839. it('should create new row from dataSchema when columns is a function', function () {
  15840. handsontable({
  15841. data: [],
  15842. dataSchema: { id: null, name: { first: null, last: null }, address: null },
  15843. minRows: 5,
  15844. minCols: 4,
  15845. colHeaders: ['ID', 'First Name', 'Last Name', 'Address'],
  15846. columns: function columns(column) {
  15847. var colMeta = {};
  15848. if (column === 0) {
  15849. colMeta.data = 'id';
  15850. } else if (column === 1) {
  15851. colMeta.data = 'name.first';
  15852. } else if (column === 2) {
  15853. colMeta.data = 'name.last';
  15854. } else if (column === 3) {
  15855. colMeta.data = 'address';
  15856. } else {
  15857. colMeta = null;
  15858. }
  15859. return colMeta;
  15860. },
  15861. minSpareRows: 1
  15862. });
  15863. selectCell(0, 1);
  15864. keyDownUp('enter');
  15865. keyProxy().val('Ted');
  15866. keyDownUp('enter');
  15867. expect(getData()[0][1]).toEqual('Ted');
  15868. expect(getSourceData()[0].name.first).toEqual('Ted');
  15869. });
  15870. it('should create new row from dataSchema (functional)', function () {
  15871. handsontable({
  15872. data: [],
  15873. dataSchema: function dataSchema(index) {
  15874. return { id: 1000 + index, name: { first: null, last: null }, address: null };
  15875. },
  15876. isEmptyRow: function isEmptyRow(r) {
  15877. var row = this.getSourceData()[r];
  15878. return (row.name.first === null || row.name.first === '') && (row.name.last === null || row.name.last === '') && (row.address === null || row.address === '');
  15879. },
  15880. minRows: 5,
  15881. minCols: 4,
  15882. colHeaders: ['ID', 'First Name', 'Last Name', 'Address'],
  15883. columns: [{ data: 'id' }, { data: 'name.first' }, { data: 'name.last' }, { data: 'address' }],
  15884. minSpareRows: 1
  15885. });
  15886. selectCell(4, 1);
  15887. expect(countRows()).toEqual(5);
  15888. keyDownUp('enter');
  15889. keyProxy().val('Ted');
  15890. // need it in next frame as long as HT is rendered in async
  15891. keyDownUp('enter');
  15892. // need it in next frame as long as HT is rendered in async
  15893. keyDownUp('enter');
  15894. expect(getSourceData()[4].name.first).toEqual('Ted');
  15895. expect(getSourceData()[4].id).toEqual(1004);
  15896. expect(getData()[4][1]).toEqual('Ted');
  15897. expect(getData()[4][0]).toEqual(1004);
  15898. expect(countRows()).toEqual(6); // row should be added by keepEmptyRows
  15899. });
  15900. it('should create new row from dataSchema (functional) when columns is a function', function () {
  15901. handsontable({
  15902. data: [],
  15903. dataSchema: function dataSchema(index) {
  15904. return { id: 1000 + index, name: { first: null, last: null }, address: null };
  15905. },
  15906. isEmptyRow: function isEmptyRow(r) {
  15907. var row = this.getSourceData()[r];
  15908. return (row.name.first === null || row.name.first === '') && (row.name.last === null || row.name.last === '') && (row.address === null || row.address === '');
  15909. },
  15910. minRows: 5,
  15911. minCols: 4,
  15912. colHeaders: ['ID', 'First Name', 'Last Name', 'Address'],
  15913. columns: function columns(column) {
  15914. var colMeta = {};
  15915. if (column === 0) {
  15916. colMeta.data = 'id';
  15917. } else if (column === 1) {
  15918. colMeta.data = 'name.first';
  15919. } else if (column === 2) {
  15920. colMeta.data = 'name.last';
  15921. } else if (column === 3) {
  15922. colMeta.data = 'address';
  15923. } else {
  15924. colMeta = null;
  15925. }
  15926. return colMeta;
  15927. },
  15928. minSpareRows: 1
  15929. });
  15930. selectCell(4, 1);
  15931. expect(countRows()).toEqual(5);
  15932. keyDownUp('enter');
  15933. keyProxy().val('Ted');
  15934. // need it in next frame as long as HT is rendered in async
  15935. keyDownUp('enter');
  15936. // need it in next frame as long as HT is rendered in async
  15937. keyDownUp('enter');
  15938. expect(getSourceData()[4].name.first).toEqual('Ted');
  15939. expect(getSourceData()[4].id).toEqual(1004);
  15940. expect(getData()[4][1]).toEqual('Ted');
  15941. expect(getData()[4][0]).toEqual(1004);
  15942. expect(countRows()).toEqual(6); // row should be added by keepEmptyRows
  15943. });
  15944. it('should translate prop to col, when prop is a function', function () {
  15945. var idAccessor = createAccessorForProperty('id');
  15946. var nameAccessor = createAccessorForProperty('name');
  15947. hot = handsontable({
  15948. data: [Model({
  15949. id: 1,
  15950. name: 'Tom'
  15951. }), Model({
  15952. id: 2,
  15953. name: 'Hanna'
  15954. }), Model({
  15955. id: 3,
  15956. name: 'Jerry'
  15957. })],
  15958. dataSchema: Model,
  15959. columns: [{
  15960. data: idAccessor
  15961. }, {
  15962. data: nameAccessor
  15963. }]
  15964. });
  15965. expect(hot.propToCol(idAccessor)).toEqual(0);
  15966. expect(hot.propToCol(nameAccessor)).toEqual(1);
  15967. });
  15968. it('should translate prop to col, when prop and columns is a function', function () {
  15969. var idAccessor = createAccessorForProperty('id');
  15970. var nameAccessor = createAccessorForProperty('name');
  15971. hot = handsontable({
  15972. data: [Model({
  15973. id: 1,
  15974. name: 'Tom'
  15975. }), Model({
  15976. id: 2,
  15977. name: 'Hanna'
  15978. }), Model({
  15979. id: 3,
  15980. name: 'Jerry'
  15981. })],
  15982. dataSchema: Model,
  15983. columns: function columns(column) {
  15984. var colMeta = {};
  15985. if (column === 0) {
  15986. colMeta.data = idAccessor;
  15987. } else if (column === 1) {
  15988. colMeta.data = nameAccessor;
  15989. } else {
  15990. colMeta = null;
  15991. }
  15992. return colMeta;
  15993. }
  15994. });
  15995. expect(hot.propToCol(idAccessor)).toEqual(0);
  15996. expect(hot.propToCol(nameAccessor)).toEqual(1);
  15997. });
  15998. it('should create new row data matched to dataSchema (data type as `array`)', function () {
  15999. var spy = jasmine.createSpy();
  16000. var hot = handsontable({
  16001. data: [[{ id: 1 }]],
  16002. dataSchema: [{ id: null }],
  16003. columns: [{ data: '0', renderer: spy }],
  16004. autoColumnSize: false,
  16005. autoRowSize: false
  16006. });
  16007. expect(spy.calls.count()).toBe(1);
  16008. expect(spy.calls.argsFor(0)[5]).toEqual({ id: 1 });
  16009. spy.calls.reset();
  16010. hot.alter('insert_row', 0);
  16011. expect(spy.calls.count()).toBe(2);
  16012. expect(spy.calls.argsFor(0)[5]).toEqual({ id: null });
  16013. expect(spy.calls.argsFor(1)[5]).toEqual({ id: 1 });
  16014. });
  16015. it('should create new row data matched to dataSchema (data type as `array`) when columns is a function', function () {
  16016. var spy = jasmine.createSpy();
  16017. var hot = handsontable({
  16018. data: [[{ id: 1 }]],
  16019. dataSchema: [{ id: null }],
  16020. columns: function columns(column) {
  16021. var colMeta = {};
  16022. if (column === 0) {
  16023. colMeta.data = '0';
  16024. colMeta.renderer = spy;
  16025. } else {
  16026. colMeta = null;
  16027. }
  16028. return colMeta;
  16029. },
  16030. autoColumnSize: false,
  16031. autoRowSize: false
  16032. });
  16033. expect(spy.calls.count()).toBe(1);
  16034. expect(spy.calls.argsFor(0)[5]).toEqual({ id: 1 });
  16035. spy.calls.reset();
  16036. hot.alter('insert_row', 0);
  16037. expect(spy.calls.count()).toBe(2);
  16038. expect(spy.calls.argsFor(0)[5]).toEqual({ id: null });
  16039. expect(spy.calls.argsFor(1)[5]).toEqual({ id: 1 });
  16040. });
  16041. it('should create an array of objects as the source structure, when dataSchema is defined (as an object) but no data is provided', function () {
  16042. var hot = handsontable({
  16043. startCols: 2,
  16044. minSpareRows: 4,
  16045. dataSchema: { id: null, name: null, surname: null }
  16046. });
  16047. var dataAtRow = hot.getSourceDataAtRow(0);
  16048. expect(Array.isArray(dataAtRow)).toBe(false);
  16049. expect(dataAtRow.id).toEqual(null);
  16050. expect(dataAtRow.name).toEqual(null);
  16051. expect(dataAtRow.surname).toEqual(null);
  16052. });
  16053. it('should create an array of objects as the source structure, when dataSchema is defined (as a function) but no data is provided', function () {
  16054. var hot = handsontable({
  16055. startCols: 2,
  16056. minSpareRows: 4,
  16057. dataSchema: function dataSchema() {
  16058. return { id: null, name: null, surname: null };
  16059. }
  16060. });
  16061. var dataAtRow = hot.getSourceDataAtRow(0);
  16062. expect(Array.isArray(dataAtRow)).toBe(false);
  16063. expect(dataAtRow.id).toEqual(null);
  16064. expect(dataAtRow.name).toEqual(null);
  16065. expect(dataAtRow.surname).toEqual(null);
  16066. });
  16067. it('should create an array of objects as the source structure, when dataSchema is defined (as an array with an object) but no data is provided', function () {
  16068. var hot = handsontable({
  16069. startCols: 2,
  16070. minSpareRows: 4,
  16071. dataSchema: [{ id: null, name: null, surname: null }]
  16072. });
  16073. var dataAtRow = hot.getSourceDataAtRow(0);
  16074. expect(Array.isArray(dataAtRow)).toBe(false);
  16075. expect(dataAtRow.id).toEqual(null);
  16076. expect(dataAtRow.name).toEqual(null);
  16077. expect(dataAtRow.surname).toEqual(null);
  16078. });
  16079. });
  16080. /***/ }),
  16081. /* 156 */
  16082. /***/ (function(module, exports, __webpack_require__) {
  16083. "use strict";
  16084. describe('Core_datachange', function () {
  16085. var id = 'testContainer';
  16086. beforeEach(function () {
  16087. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16088. });
  16089. afterEach(function () {
  16090. if (this.$container) {
  16091. destroy();
  16092. this.$container.remove();
  16093. }
  16094. });
  16095. it('should call onChange callback', function () {
  16096. var output = null;
  16097. handsontable({
  16098. afterChange: function afterChange(changes) {
  16099. output = changes;
  16100. }
  16101. });
  16102. setDataAtCell(1, 2, 'test');
  16103. expect(output[0][0]).toEqual(1);
  16104. expect(output[0][1]).toEqual(2);
  16105. expect(output[0][2]).toEqual(null);
  16106. expect(output[0][3]).toEqual('test');
  16107. });
  16108. it('should use custom source for datachange', function () {
  16109. var output = null,
  16110. src = null;
  16111. handsontable({
  16112. afterChange: function afterChange(changes, source) {
  16113. output = changes;
  16114. src = source;
  16115. }
  16116. });
  16117. setDataAtCell(1, 2, 'abc', 'test');
  16118. expect(output[0][3]).toEqual('abc');
  16119. expect(src).toEqual('test');
  16120. });
  16121. it('should use custom source for datachange with array', function () {
  16122. var output = null,
  16123. src = null;
  16124. handsontable({
  16125. afterChange: function afterChange(changes, source) {
  16126. output = changes;
  16127. src = source;
  16128. }
  16129. });
  16130. setDataAtCell([[1, 2, 'abc']], 'test');
  16131. expect(output[0][3]).toEqual('abc');
  16132. expect(src).toEqual('test');
  16133. });
  16134. it('should trigger datachange event', function () {
  16135. var output = null;
  16136. handsontable();
  16137. Handsontable.hooks.add('afterChange', function (changes) {
  16138. output = changes;
  16139. });
  16140. setDataAtCell(1, 2, 'test');
  16141. expect(output[0][0]).toEqual(1);
  16142. expect(output[0][1]).toEqual(2);
  16143. expect(output[0][2]).toEqual(null);
  16144. expect(output[0][3]).toEqual('test');
  16145. });
  16146. it('this.rootElement should point to handsontable rootElement', function () {
  16147. var output = null;
  16148. var $container = this.$container;
  16149. handsontable({
  16150. afterChange: function afterChange() {
  16151. output = this.rootElement;
  16152. }
  16153. });
  16154. setDataAtCell(0, 0, 'test');
  16155. expect(output).toEqual($container[0]);
  16156. });
  16157. it('onChange should be triggered after data is rendered to DOM (init)', function () {
  16158. var output = null;
  16159. var $container = this.$container;
  16160. handsontable({
  16161. data: [['Joe Red']],
  16162. afterChange: function afterChange(changes, source) {
  16163. if (source === 'loadData') {
  16164. output = $container.find('table.htCore tbody td:first').html();
  16165. }
  16166. }
  16167. });
  16168. expect(output).toEqual('Joe Red');
  16169. });
  16170. it('onChange should be triggered after data is rendered to DOM (setDataAtCell)', function () {
  16171. var output = null;
  16172. var $container = this.$container;
  16173. handsontable({
  16174. data: [['Joe Red']],
  16175. afterChange: function afterChange(changes, source) {
  16176. if (source === 'edit') {
  16177. output = $container.find('table.htCore tbody td:first').html();
  16178. }
  16179. }
  16180. });
  16181. setDataAtCell(0, 0, 'Alice Red');
  16182. expect(output).toEqual('Alice Red');
  16183. });
  16184. it('onChange event object should contain documented keys and values when triggered by edit', function () {
  16185. var sampleData = [{
  16186. col1: 'a',
  16187. col2: 'b',
  16188. col3: 'c'
  16189. }];
  16190. var event = null;
  16191. handsontable({
  16192. data: sampleData,
  16193. afterChange: function afterChange(changes, source) {
  16194. if (source === 'edit') {
  16195. event = changes.shift();
  16196. }
  16197. }
  16198. });
  16199. setDataAtCell(0, 0, 'test');
  16200. expect(event[0]).toEqual(0);
  16201. expect(event[1]).toEqual('col1');
  16202. expect(event[2]).toEqual('a');
  16203. expect(event[3]).toEqual('test');
  16204. });
  16205. it('source parameter should be `edit` when cell value is changed through editor', function () {
  16206. var sources = [];
  16207. handsontable({
  16208. data: [['Joe Red']],
  16209. afterChange: function afterChange(changes, source) {
  16210. sources.push(source);
  16211. }
  16212. });
  16213. selectCell(0, 0);
  16214. keyDown('enter');
  16215. document.activeElement.value = 'Ted';
  16216. keyDown('enter');
  16217. expect(sources).toEqual(['loadData', 'edit']); // loadData is always the first source
  16218. });
  16219. });
  16220. /***/ }),
  16221. /* 157 */
  16222. /***/ (function(module, exports, __webpack_require__) {
  16223. "use strict";
  16224. describe('Core_destroy', function () {
  16225. var id = 'testContainer';
  16226. beforeEach(function () {
  16227. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16228. });
  16229. afterEach(function () {
  16230. if (this.$container) {
  16231. destroy();
  16232. this.$container.remove();
  16233. }
  16234. });
  16235. it('should remove table from the root element', function () {
  16236. handsontable();
  16237. destroy();
  16238. expect(this.$container.html()).toEqual('');
  16239. });
  16240. it('should remove events from the root element, document element and window', function () {
  16241. var x = handsontable();
  16242. expect(x.eventListeners.length > 0).toBeTruthy();
  16243. destroy();
  16244. expect(x.eventListeners).toBeNull();
  16245. $(document.documentElement).off('.copypaste'); // remove copypaste.js listeners, which are not removed by destroy (because copypaste is a singleton for whole page)
  16246. });
  16247. it('should NOT remove events from document element and window for other Handsontable instances on the page', function () {
  16248. // test based on Core_selectionSpec.js (should deselect currently selected cell)
  16249. handsontable();
  16250. var $tmp = $('<div id="tmp"></div>').appendTo(document.body);
  16251. $tmp.handsontable();
  16252. $tmp.handsontable('destroy');
  16253. $tmp.remove();
  16254. selectCell(0, 0);
  16255. $('html').simulate('mousedown');
  16256. expect(getSelected()).toBeUndefined();
  16257. });
  16258. });
  16259. /***/ }),
  16260. /* 158 */
  16261. /***/ (function(module, exports, __webpack_require__) {
  16262. "use strict";
  16263. describe('Core_destroyEditor', function () {
  16264. var id = 'testContainer';
  16265. beforeEach(function () {
  16266. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16267. });
  16268. afterEach(function () {
  16269. if (this.$container) {
  16270. destroy();
  16271. this.$container.remove();
  16272. }
  16273. });
  16274. it('editor should not be visible', function () {
  16275. handsontable();
  16276. selectCell(1, 1);
  16277. keyDownUp('enter');
  16278. destroyEditor();
  16279. expect(isEditorVisible()).toEqual(false);
  16280. });
  16281. it('value should be saved', function () {
  16282. handsontable();
  16283. selectCell(1, 1);
  16284. keyDownUp('enter');
  16285. keyProxy().val('Ted');
  16286. destroyEditor();
  16287. expect(getDataAtCell(1, 1)).toEqual('Ted');
  16288. });
  16289. it('cell should be selected', function () {
  16290. handsontable();
  16291. selectCell(1, 1);
  16292. keyDownUp('enter');
  16293. destroyEditor();
  16294. expect(getSelected()).toEqual([1, 1, 1, 1]);
  16295. });
  16296. it('should revert original value when param set to true', function () {
  16297. handsontable();
  16298. selectCell(1, 1);
  16299. keyDownUp('enter');
  16300. keyProxy().val('Ted');
  16301. destroyEditor(true);
  16302. expect(getDataAtCell(1, 1)).toEqual(null);
  16303. });
  16304. it('should not destroy editor on scroll', function () {
  16305. this.$container.css({
  16306. width: 200,
  16307. height: 100
  16308. });
  16309. handsontable({
  16310. data: Handsontable.helper.createSpreadsheetData(20, 10)
  16311. });
  16312. selectCell(0, 0);
  16313. keyDown('enter');
  16314. var editor = $('.handsontableInputHolder');
  16315. expect(editor.is(':visible')).toBe(true);
  16316. this.$container.scroll();
  16317. expect(editor.is(':visible')).toBe(true);
  16318. });
  16319. });
  16320. /***/ }),
  16321. /* 159 */
  16322. /***/ (function(module, exports, __webpack_require__) {
  16323. "use strict";
  16324. describe('Core_getCellMeta', function () {
  16325. var id = 'testContainer';
  16326. beforeEach(function () {
  16327. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16328. });
  16329. afterEach(function () {
  16330. if (this.$container) {
  16331. destroy();
  16332. this.$container.remove();
  16333. }
  16334. });
  16335. it('should not allow manual editing of a read only cell', function () {
  16336. var allCellsReadOnly = false;
  16337. handsontable({
  16338. cells: function cells() {
  16339. return { readOnly: allCellsReadOnly };
  16340. }
  16341. });
  16342. allCellsReadOnly = true;
  16343. selectCell(2, 2);
  16344. keyDown('enter');
  16345. expect(isEditorVisible()).toEqual(false);
  16346. });
  16347. it('should allow manual editing of cell that is no longer read only', function () {
  16348. var allCellsReadOnly = true;
  16349. handsontable({
  16350. cells: function cells() {
  16351. return { readOnly: allCellsReadOnly };
  16352. }
  16353. });
  16354. allCellsReadOnly = false;
  16355. selectCell(2, 2);
  16356. keyDown('enter');
  16357. expect(isEditorVisible()).toEqual(true);
  16358. });
  16359. it('should move the selection to the cell below, when hitting the ENTER key on a read-only cell', function () {
  16360. handsontable({
  16361. data: Handsontable.helper.createSpreadsheetData(3, 3),
  16362. cells: function cells() {
  16363. return { readOnly: true };
  16364. }
  16365. });
  16366. selectCell(0, 0);
  16367. expect(getCellMeta(0, 0).readOnly).toBe(true);
  16368. keyDown('enter');
  16369. expect(getSelected()).toEqual([1, 0, 1, 0]);
  16370. });
  16371. it('should use default cell editor for a cell that has declared only cell renderer', function () {
  16372. handsontable({
  16373. cells: function cells() {
  16374. return {
  16375. renderer: function renderer(instance, td, row, col, prop, value, cellProperties) {
  16376. // taken from demo/renderers.html
  16377. Handsontable.renderers.TextRenderer.apply(this, arguments);
  16378. $(td).css({
  16379. background: 'yellow'
  16380. });
  16381. }
  16382. };
  16383. }
  16384. });
  16385. selectCell(2, 2);
  16386. keyDown('enter');
  16387. document.activeElement.value = 'new value';
  16388. destroyEditor();
  16389. expect(getDataAtCell(2, 2)).toEqual('new value');
  16390. });
  16391. it('should allow to use type and renderer in `flat` notation', function () {
  16392. handsontable({
  16393. data: [[1, 2, 3, 4], [5, 6, 7, 8], [0, 9, 8, 7]],
  16394. cells: function cells(row, col) {
  16395. if (row === 2 && col === 2) {
  16396. return {
  16397. type: 'checkbox',
  16398. renderer: function renderer(instance, td, row, col, prop, value, cellProperties) {
  16399. // taken from demo/renderers.html
  16400. Handsontable.renderers.TextRenderer.apply(this, arguments);
  16401. td.style.backgroundColor = 'yellow';
  16402. }
  16403. };
  16404. }
  16405. }
  16406. });
  16407. expect(getCell(2, 2).style.backgroundColor).toEqual('yellow');
  16408. expect(getCell(1, 1).style.backgroundColor).toEqual('');
  16409. });
  16410. it('this in cells should point to cellProperties', function () {
  16411. var called = 0,
  16412. _row,
  16413. _this;
  16414. handsontable({
  16415. cells: function cells(row, col, prop) {
  16416. called++;
  16417. _row = row;
  16418. _this = this;
  16419. }
  16420. });
  16421. var HOT = getInstance();
  16422. expect(called).toBeGreaterThan(0);
  16423. expect(_this.row).toEqual(_row);
  16424. expect(_this.instance).toBe(HOT);
  16425. });
  16426. it('should get proper cellProperties when order of displayed rows is different than order of stored data', function () {
  16427. var hot = handsontable({
  16428. data: [['C'], ['A'], ['B']],
  16429. minSpareRows: 1,
  16430. cells: function cells(row, col, prop) {
  16431. var cellProperties = {};
  16432. if (getSourceData()[row][col] === 'A') {
  16433. cellProperties.readOnly = true;
  16434. }
  16435. return cellProperties;
  16436. }
  16437. });
  16438. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('C');
  16439. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').hasClass('htDimmed')).toBe(false);
  16440. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('A');
  16441. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').hasClass('htDimmed')).toBe(true);
  16442. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('B');
  16443. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').hasClass('htDimmed')).toBe(false);
  16444. // Column sorting changes the order of displayed rows while keeping table data unchanged
  16445. updateSettings({
  16446. columnSorting: {
  16447. column: 0,
  16448. sortOrder: true
  16449. }
  16450. });
  16451. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A');
  16452. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').hasClass('htDimmed')).toBe(true);
  16453. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('B');
  16454. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').hasClass('htDimmed')).toBe(false);
  16455. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('C');
  16456. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').hasClass('htDimmed')).toBe(false);
  16457. });
  16458. });
  16459. /***/ }),
  16460. /* 160 */
  16461. /***/ (function(module, exports, __webpack_require__) {
  16462. "use strict";
  16463. describe('Core.getColHeader', function () {
  16464. var id = 'testContainer';
  16465. beforeEach(function () {
  16466. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16467. });
  16468. afterEach(function () {
  16469. if (this.$container) {
  16470. destroy();
  16471. this.$container.remove();
  16472. }
  16473. });
  16474. it('when not configured, should return undefined', function () {
  16475. handsontable();
  16476. expect(getColHeader(1)).toBe(null);
  16477. });
  16478. it('when configured as true, should return the Excel-style column title', function () {
  16479. handsontable({
  16480. colHeaders: true
  16481. });
  16482. expect(getColHeader(30)).toEqual('AE');
  16483. });
  16484. it('when configured as array, should return value at index', function () {
  16485. handsontable({
  16486. colHeaders: ['One', 'Two', 'Three', 'Four', 'Five']
  16487. });
  16488. expect(getColHeader(1)).toEqual('Two');
  16489. });
  16490. it('when configured as function, should return function output', function () {
  16491. handsontable({
  16492. colHeaders: function colHeaders(index) {
  16493. return 'col' + index;
  16494. }
  16495. });
  16496. expect(getColHeader(1)).toEqual('col1');
  16497. });
  16498. it('when configured as static value, should return the value', function () {
  16499. handsontable({
  16500. colHeaders: 'static'
  16501. });
  16502. expect(getColHeader(1)).toEqual('static');
  16503. });
  16504. it('when configured as HTML value, should render that as HTML', function () {
  16505. handsontable({
  16506. colHeaders: function colHeaders(index) {
  16507. return '<b>col' + index + '</b>';
  16508. }
  16509. });
  16510. expect(getColHeader(1)).toEqual('<b>col1</b>');
  16511. });
  16512. it('when no argument given, should return as much column headers as there are columns', function () {
  16513. handsontable({
  16514. colHeaders: true,
  16515. startCols: 3
  16516. });
  16517. expect(getColHeader()).toEqual(['A', 'B', 'C']);
  16518. });
  16519. });
  16520. /***/ }),
  16521. /* 161 */
  16522. /***/ (function(module, exports, __webpack_require__) {
  16523. "use strict";
  16524. describe('Core_getDataAt*', function () {
  16525. var id = 'testContainer';
  16526. beforeEach(function () {
  16527. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16528. });
  16529. afterEach(function () {
  16530. if (this.$container) {
  16531. destroy();
  16532. this.$container.remove();
  16533. }
  16534. });
  16535. var arrayOfArrays = function arrayOfArrays() {
  16536. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  16537. };
  16538. var arrayOfObjects = function arrayOfObjects() {
  16539. return [{
  16540. 'id.a.b.c': 1,
  16541. id: 1,
  16542. name: 'Nannie Patel',
  16543. address: 'Jenkin ville',
  16544. details: {
  16545. city: 'Chicago'
  16546. }
  16547. }, {
  16548. 'id.a.b.c': 2,
  16549. id: 2,
  16550. name: 'Łucja Grożny and Środeńczak',
  16551. address: 'Gardiner',
  16552. details: {
  16553. city: 'New York'
  16554. }
  16555. }];
  16556. };
  16557. it('should return data at specified row', function () {
  16558. handsontable({
  16559. data: arrayOfArrays()
  16560. });
  16561. expect(getDataAtRow(0)).toEqual(['', 'Kia', 'Nissan', 'Toyota', 'Honda']);
  16562. });
  16563. it('should return data at specified col', function () {
  16564. handsontable({
  16565. data: arrayOfArrays()
  16566. });
  16567. expect(getDataAtCol(1)).toEqual(['Kia', 10, 20, 30]);
  16568. });
  16569. describe('Core_getDataAtRowProp', function () {
  16570. it('should return data at specified column', function () {
  16571. handsontable({
  16572. data: arrayOfObjects()
  16573. });
  16574. expect(getDataAtRowProp(1, 'id.a.b.c')).toBe(2);
  16575. expect(getDataAtRowProp(1, 'id')).toBe(2);
  16576. expect(getDataAtRowProp(1, 'id')).toBe(2);
  16577. expect(getDataAtRowProp(1, 'details.city')).toBe('New York');
  16578. });
  16579. });
  16580. describe('`modifyData` hook', function () {
  16581. it('should be fired with specified arguments on every `set`, `get` operation (array of arrays)', function () {
  16582. var spy = jasmine.createSpy();
  16583. handsontable({
  16584. data: arrayOfArrays(),
  16585. autoColumnSize: false,
  16586. modifyData: spy
  16587. });
  16588. expect(spy.calls.count()).toBe(20); // call for all cells
  16589. expect(spy.calls.argsFor(1)[0]).toBe(0);
  16590. expect(spy.calls.argsFor(1)[1]).toBe(1);
  16591. expect(spy.calls.argsFor(1)[2].value).toBe('Kia');
  16592. expect(spy.calls.argsFor(1)[3]).toBe('get');
  16593. spy.calls.reset();
  16594. setDataAtCell(2, 3, 'foo');
  16595. expect(spy.calls.count()).toBe(21); // call for all cells + 1 from setDataAtCell
  16596. expect(spy.calls.argsFor(0)[0]).toBe(2);
  16597. expect(spy.calls.argsFor(0)[1]).toBe(3);
  16598. expect(spy.calls.argsFor(0)[2].value).toBe('foo');
  16599. expect(spy.calls.argsFor(0)[3]).toBe('set');
  16600. });
  16601. it('should be fired with specified arguments on every `set`, `get` operation (array of objects)', function () {
  16602. var spy = jasmine.createSpy();
  16603. handsontable({
  16604. data: arrayOfObjects(),
  16605. autoColumnSize: false,
  16606. modifyData: spy
  16607. });
  16608. expect(spy.calls.count()).toBe(10); // call for all cells
  16609. expect(spy.calls.argsFor(2)[0]).toBe(0);
  16610. expect(spy.calls.argsFor(2)[1]).toBe(2);
  16611. expect(spy.calls.argsFor(2)[2].value).toBe('Nannie Patel');
  16612. expect(spy.calls.argsFor(2)[3]).toBe('get');
  16613. spy.calls.reset();
  16614. setDataAtRowProp(2, 'name', 'foo');
  16615. expect(spy.calls.count()).toBe(16);
  16616. expect(spy.calls.argsFor(0)[0]).toBe(2);
  16617. expect(spy.calls.argsFor(0)[1]).toBe(2);
  16618. expect(spy.calls.argsFor(0)[2].value).toBe('foo');
  16619. expect(spy.calls.argsFor(0)[3]).toBe('set');
  16620. });
  16621. it('should overwrite value while loading data', function () {
  16622. handsontable({
  16623. data: arrayOfArrays(),
  16624. modifyData: function modifyData(row, column, valueHolder, ioMode) {
  16625. if (ioMode === 'get' && row === 1 && column === 2) {
  16626. valueHolder.value = 'foo';
  16627. }
  16628. }
  16629. });
  16630. expect(getDataAtCell(1, 2)).toBe('foo');
  16631. expect(getSourceDataAtCell(1, 2)).toBe(11);
  16632. });
  16633. it('should overwrite value while saving data', function () {
  16634. handsontable({
  16635. data: arrayOfArrays(),
  16636. modifyData: function modifyData(row, column, valueHolder, ioMode) {
  16637. if (ioMode === 'set' && row === 1 && column === 2) {
  16638. valueHolder.value = 'foo';
  16639. }
  16640. }
  16641. });
  16642. setDataAtCell(1, 2, 'bar');
  16643. expect(getDataAtCell(1, 2)).toBe('foo');
  16644. expect(getSourceDataAtCell(1, 2)).toBe('foo');
  16645. });
  16646. });
  16647. });
  16648. /***/ }),
  16649. /* 162 */
  16650. /***/ (function(module, exports, __webpack_require__) {
  16651. "use strict";
  16652. describe('Core_getDataType', function () {
  16653. var id = 'testContainer';
  16654. beforeEach(function () {
  16655. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16656. });
  16657. afterEach(function () {
  16658. if (this.$container) {
  16659. destroy();
  16660. this.$container.remove();
  16661. }
  16662. });
  16663. var arrayOfArrays = function arrayOfArrays() {
  16664. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  16665. };
  16666. it('should return data type at specyfied range (default type)', function () {
  16667. handsontable({
  16668. data: arrayOfArrays()
  16669. });
  16670. expect(getDataType(0, 0)).toEqual('text');
  16671. expect(getDataType(0, 0, 1, 1)).toEqual('text');
  16672. });
  16673. it('should return data type at specyfied range (type defined in columns)', function () {
  16674. handsontable({
  16675. data: arrayOfArrays(),
  16676. columns: [{ type: 'numeric' }, { type: 'text' }, { type: 'date' }, { type: 'autocomplete' }, { type: 'dropdown' }]
  16677. });
  16678. expect(getDataType(0, 0)).toEqual('numeric');
  16679. expect(getDataType(0, 0, 1, 1)).toEqual('mixed');
  16680. expect(getDataType(0, 1, 1, 1)).toEqual('text');
  16681. expect(getDataType(0, 2, 1, 2)).toEqual('date');
  16682. expect(getDataType(3, 3, 3, 3)).toEqual('autocomplete');
  16683. expect(getDataType(3, 4, 3, 4)).toEqual('dropdown');
  16684. });
  16685. it('should return data type at specyfied range (type defined in columns) when columns is a function', function () {
  16686. handsontable({
  16687. data: arrayOfArrays(),
  16688. columns: function columns(column) {
  16689. var colMeta = {};
  16690. if (column === 0) {
  16691. colMeta.type = 'numeric';
  16692. } else if (column === 1) {
  16693. colMeta.type = 'text';
  16694. } else if (column === 2) {
  16695. colMeta.type = 'date';
  16696. } else if (column === 3) {
  16697. colMeta.type = 'autocomplete';
  16698. } else if (column === 4) {
  16699. colMeta.type = 'dropdown';
  16700. } else {
  16701. colMeta = null;
  16702. }
  16703. return colMeta;
  16704. }
  16705. });
  16706. expect(getDataType(0, 0)).toEqual('numeric');
  16707. expect(getDataType(0, 0, 1, 1)).toEqual('mixed');
  16708. expect(getDataType(0, 1, 1, 1)).toEqual('text');
  16709. expect(getDataType(0, 2, 1, 2)).toEqual('date');
  16710. expect(getDataType(3, 3, 3, 3)).toEqual('autocomplete');
  16711. expect(getDataType(3, 4, 3, 4)).toEqual('dropdown');
  16712. });
  16713. it('should return data type at specyfied range (type defined in cells)', function () {
  16714. handsontable({
  16715. data: arrayOfArrays(),
  16716. cells: function cells(row, column) {
  16717. var cellMeta = {};
  16718. if (row === 1 && column === 1) {
  16719. cellMeta.type = 'date';
  16720. }
  16721. if (column === 2) {
  16722. cellMeta.type = 'checkbox';
  16723. }
  16724. return cellMeta;
  16725. }
  16726. });
  16727. expect(getDataType(0, 0)).toEqual('text');
  16728. expect(getDataType(1, 1)).toEqual('date');
  16729. expect(getDataType(1, 2)).toEqual('checkbox');
  16730. expect(getDataType(0, 0, 1, 1)).toEqual('mixed');
  16731. });
  16732. });
  16733. /***/ }),
  16734. /* 163 */
  16735. /***/ (function(module, exports, __webpack_require__) {
  16736. "use strict";
  16737. describe('Core.getRowHeader', function () {
  16738. var id = 'testContainer';
  16739. beforeEach(function () {
  16740. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16741. });
  16742. afterEach(function () {
  16743. if (this.$container) {
  16744. destroy();
  16745. this.$container.remove();
  16746. }
  16747. });
  16748. it('when not configured, should return undefined', function () {
  16749. handsontable();
  16750. expect(getRowHeader(1)).toEqual(void 0);
  16751. });
  16752. it('when configured as true, should return the index incremented by 1', function () {
  16753. handsontable({
  16754. rowHeaders: true
  16755. });
  16756. expect(getRowHeader(1)).toEqual(2);
  16757. });
  16758. it('when configured as array, should return value at index', function () {
  16759. handsontable({
  16760. rowHeaders: ['One', 'Two', 'Three', 'Four', 'Five']
  16761. });
  16762. expect(getRowHeader(1)).toEqual('Two');
  16763. });
  16764. it('when configured as function, should return function output', function () {
  16765. handsontable({
  16766. rowHeaders: function rowHeaders(index) {
  16767. return 'row' + index;
  16768. }
  16769. });
  16770. expect(getRowHeader(1)).toEqual('row1');
  16771. });
  16772. it('when configured as static value, should return the value', function () {
  16773. handsontable({
  16774. rowHeaders: 'static'
  16775. });
  16776. expect(getRowHeader(1)).toEqual('static');
  16777. });
  16778. it('when configured as HTML value, should render that as HTML', function () {
  16779. handsontable({
  16780. rowHeaders: function rowHeaders(index) {
  16781. return '<b>row' + index + '</b>';
  16782. }
  16783. });
  16784. expect(getRowHeader(1)).toEqual('<b>row1</b>');
  16785. });
  16786. it('when no argument given, should return as much row headers as there are rows', function () {
  16787. handsontable({
  16788. rowHeaders: true,
  16789. startRows: 3
  16790. });
  16791. expect(getRowHeader()).toEqual([1, 2, 3]);
  16792. });
  16793. });
  16794. /***/ }),
  16795. /* 164 */
  16796. /***/ (function(module, exports, __webpack_require__) {
  16797. "use strict";
  16798. describe('Core_init', function () {
  16799. var id = 'testContainer';
  16800. beforeEach(function () {
  16801. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16802. });
  16803. afterEach(function () {
  16804. if (this.$container) {
  16805. destroy();
  16806. this.$container.remove();
  16807. }
  16808. });
  16809. it('should respect startRows and startCols when no data is provided', function () {
  16810. this.$container.remove();
  16811. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16812. handsontable();
  16813. expect(countRows()).toEqual(5); // as given in README.md
  16814. expect(countCols()).toEqual(5); // as given in README.md
  16815. });
  16816. it('should respect width provided in inline style', function () {
  16817. this.$container.css({
  16818. overflow: 'auto',
  16819. width: '200px'
  16820. });
  16821. handsontable({
  16822. data: [['ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC']]
  16823. });
  16824. expect(this.$container.width()).toEqual(200);
  16825. });
  16826. it('should respect width provided in CSS class', function () {
  16827. $('<style>.myTable {overflow: auto; width: 200px}</style>').appendTo('head');
  16828. this.$container.addClass('myTable');
  16829. handsontable({
  16830. data: [['ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC', 'ABC']]
  16831. });
  16832. expect(this.$container.width()).toEqual(200);
  16833. });
  16834. it('should construct when container is not appended to document', function () {
  16835. this.$container.remove();
  16836. handsontable();
  16837. expect(getData()).toBeTruthy();
  16838. });
  16839. it('Handsontable.Dom should be available as a helper to the plugins', function () {
  16840. // all public methods of Handsontable.Dom should be exposed here
  16841. expect(Handsontable.dom.closest).toBeDefined();
  16842. expect(Handsontable.dom.isChildOf).toBeDefined();
  16843. expect(Handsontable.dom.index).toBeDefined();
  16844. expect(Handsontable.dom.hasClass).toBeDefined();
  16845. expect(Handsontable.dom.addClass).toBeDefined();
  16846. expect(Handsontable.dom.removeClass).toBeDefined();
  16847. expect(Handsontable.dom.removeTextNodes).toBeDefined();
  16848. expect(Handsontable.dom.empty).toBeDefined();
  16849. expect(Handsontable.dom.fastInnerHTML).toBeDefined();
  16850. expect(Handsontable.dom.fastInnerText).toBeDefined();
  16851. expect(Handsontable.dom.isVisible).toBeDefined();
  16852. expect(Handsontable.dom.offset).toBeDefined();
  16853. expect(Handsontable.dom.getComputedStyle).toBeDefined();
  16854. expect(Handsontable.dom.outerWidth).toBeDefined();
  16855. expect(Handsontable.dom.outerHeight).toBeDefined();
  16856. expect(Handsontable.dom.getCaretPosition).toBeDefined();
  16857. expect(Handsontable.dom.setCaretPosition).toBeDefined();
  16858. });
  16859. });
  16860. /***/ }),
  16861. /* 165 */
  16862. /***/ (function(module, exports, __webpack_require__) {
  16863. "use strict";
  16864. describe('Core.isEmpty*', function () {
  16865. var id = 'testContainer';
  16866. beforeEach(function () {
  16867. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16868. });
  16869. afterEach(function () {
  16870. if (this.$container) {
  16871. destroy();
  16872. this.$container.remove();
  16873. }
  16874. });
  16875. describe('isEmptyRow', function () {
  16876. it('should be empty row', function () {
  16877. handsontable();
  16878. var hot = getInstance();
  16879. expect(hot.isEmptyRow(0)).toEqual(true);
  16880. });
  16881. it('should not be empty row', function () {
  16882. handsontable();
  16883. setDataAtCell(0, 0, 'test');
  16884. var hot = getInstance();
  16885. expect(hot.isEmptyRow(0)).toEqual(false);
  16886. });
  16887. it('should bind this to instance', function () {
  16888. handsontable();
  16889. var hot = getInstance();
  16890. var check = hot.isEmptyRow;
  16891. expect(check(0)).toEqual(true); // this may be change in future when we switch to define isEmptyCol in prototype
  16892. });
  16893. });
  16894. describe('isEmptyCol', function () {
  16895. it('should be empty row', function () {
  16896. handsontable();
  16897. var hot = getInstance();
  16898. expect(hot.isEmptyCol(0)).toEqual(true);
  16899. });
  16900. it('should not be empty row', function () {
  16901. handsontable();
  16902. setDataAtCell(0, 0, 'test');
  16903. var hot = getInstance();
  16904. expect(hot.isEmptyCol(0)).toEqual(false);
  16905. });
  16906. it('should bind this to instance', function () {
  16907. handsontable();
  16908. var hot = getInstance();
  16909. var check = hot.isEmptyCol;
  16910. expect(check(0)).toEqual(true); // this may be change in future when we switch to define isEmptyCol in prototype
  16911. });
  16912. });
  16913. });
  16914. /***/ }),
  16915. /* 166 */
  16916. /***/ (function(module, exports, __webpack_require__) {
  16917. "use strict";
  16918. describe('Core_keepEmptyRows', function () {
  16919. var id = 'testContainer';
  16920. beforeEach(function () {
  16921. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  16922. });
  16923. afterEach(function () {
  16924. if (this.$container) {
  16925. destroy();
  16926. this.$container.remove();
  16927. }
  16928. });
  16929. var arrayOfNestedObjects = function arrayOfNestedObjects() {
  16930. return [{ id: 1,
  16931. name: {
  16932. first: 'Ted',
  16933. last: 'Right'
  16934. },
  16935. address: 'Street Name',
  16936. zip: '80410',
  16937. city: 'City Name' }, { id: 2,
  16938. name: {
  16939. first: 'Frank',
  16940. last: 'Honest'
  16941. },
  16942. address: 'Street Name',
  16943. zip: '80410',
  16944. city: 'City Name' }, { id: 3,
  16945. name: {
  16946. first: 'Joan',
  16947. last: 'Well'
  16948. },
  16949. address: 'Street Name',
  16950. zip: '80410',
  16951. city: 'City Name' }];
  16952. };
  16953. it('should remove columns if needed', function () {
  16954. handsontable({
  16955. data: arrayOfNestedObjects(),
  16956. columns: [{ data: 'id' }, { data: 'name.first' }]
  16957. });
  16958. expect(this.$container.find('tbody tr:first td').length).toEqual(2);
  16959. });
  16960. it('should remove columns if needed when columns is a function', function () {
  16961. handsontable({
  16962. data: arrayOfNestedObjects(),
  16963. columns: function columns(column) {
  16964. var colMeta = {};
  16965. if (column === 0) {
  16966. colMeta.data = 'id';
  16967. } else if (column === 1) {
  16968. colMeta.data = 'name.first';
  16969. } else {
  16970. colMeta = null;
  16971. }
  16972. return colMeta;
  16973. }
  16974. });
  16975. expect(this.$container.find('tbody tr:first td').length).toEqual(2);
  16976. });
  16977. it('should create columns if needed', function () {
  16978. handsontable({
  16979. data: arrayOfNestedObjects(),
  16980. columns: [{ data: 'id' }, { data: 'name.first' }, { data: 'name.last' }, { data: 'address' }, { data: 'zip' }, { data: 'city' }]
  16981. });
  16982. expect(this.$container.find('tbody tr:first td').length).toEqual(6);
  16983. });
  16984. it('should create columns if needed when columns is a function', function () {
  16985. handsontable({
  16986. data: arrayOfNestedObjects(),
  16987. columns: function columns(column) {
  16988. var colMeta = {};
  16989. if (column === 0) {
  16990. colMeta.data = 'id';
  16991. } else if (column === 1) {
  16992. colMeta.data = 'name.first';
  16993. } else if (column === 2) {
  16994. colMeta.data = 'name.last';
  16995. } else if (column === 3) {
  16996. colMeta.data = 'address';
  16997. } else if (column === 4) {
  16998. colMeta.data = 'zip';
  16999. } else if (column === 5) {
  17000. colMeta.data = 'city';
  17001. } else {
  17002. colMeta = null;
  17003. }
  17004. return colMeta;
  17005. }
  17006. });
  17007. expect(this.$container.find('tbody tr:first td').length).toEqual(6);
  17008. });
  17009. it('should create spare cols and rows on init (array data source)', function () {
  17010. handsontable({
  17011. data: [['one', 'two'], ['three', 'four']],
  17012. minCols: 4,
  17013. minRows: 4,
  17014. minSpareRows: 4,
  17015. minSpareCols: 4
  17016. });
  17017. expect(countCells()).toEqual(36);
  17018. });
  17019. it('should create spare cols and rows on init (object data source)', function () {
  17020. handsontable({
  17021. data: arrayOfNestedObjects(),
  17022. minRows: 4,
  17023. minSpareRows: 1
  17024. });
  17025. expect(countRows()).toEqual(4);
  17026. expect(countCols()).toEqual(6); // because arrayOfNestedObjects has 6 nested properites and they should be figured out if dataSchema/columns is not given
  17027. expect(this.$container.find('tbody tr:first td:last').text()).toEqual('City Name');
  17028. });
  17029. it('should create new row when last cell in last row is edited', function () {
  17030. var data = [['one', 'two'], ['three', 'four']];
  17031. handsontable({
  17032. data: data,
  17033. minRows: 4,
  17034. minCols: 4,
  17035. minSpareRows: 1
  17036. });
  17037. setDataAtCell(3, 3, 'test');
  17038. expect(data.length).toEqual(5);
  17039. });
  17040. it('should create new col when last cell in last row is edited', function () {
  17041. var data = [['one', 'two'], ['three', 'four']];
  17042. handsontable({
  17043. data: data,
  17044. minRows: 4,
  17045. minCols: 4,
  17046. minSpareCols: 1
  17047. });
  17048. setDataAtCell(3, 3, 'test');
  17049. expect(countCols()).toEqual(5);
  17050. });
  17051. it('should create new row when last cell in last row is edited by autocomplete', function (done) {
  17052. var data = [{ id: 1, color: 'orange' }];
  17053. var syncSources = jasmine.createSpy('syncSources');
  17054. syncSources.and.callFake(function (query, process) {
  17055. process(['red', 'dark-yellow', 'yellow', 'light-yellow', 'black']);
  17056. });
  17057. handsontable({
  17058. data: data,
  17059. startRows: 5,
  17060. colHeaders: true,
  17061. minSpareRows: 1,
  17062. columns: [{ data: 'id', type: 'text' }, {
  17063. data: 'color',
  17064. editor: 'autocomplete',
  17065. source: syncSources
  17066. }]
  17067. });
  17068. selectCell(1, 1);
  17069. keyDownUp('enter');
  17070. setTimeout(function () {
  17071. keyDown('arrow_down');
  17072. keyDownUp('enter');
  17073. expect(data.length).toEqual(3);
  17074. done();
  17075. }, 200);
  17076. });
  17077. it('should create new row when last cell in last row is edited by autocomplete when columns is a function', function (done) {
  17078. var data = [{ id: 1, color: 'orange' }];
  17079. var syncSources = jasmine.createSpy('syncSources');
  17080. syncSources.and.callFake(function (query, process) {
  17081. process(['red', 'dark-yellow', 'yellow', 'light-yellow', 'black']);
  17082. });
  17083. handsontable({
  17084. data: data,
  17085. startRows: 5,
  17086. colHeaders: true,
  17087. minSpareRows: 1,
  17088. columns: function columns(column) {
  17089. var colMeta = {};
  17090. if (column === 0) {
  17091. colMeta.data = 'id';
  17092. colMeta.type = 'text';
  17093. } else if (column === 1) {
  17094. colMeta.data = 'color';
  17095. colMeta.editor = 'autocomplete';
  17096. colMeta.source = syncSources;
  17097. } else {
  17098. colMeta = null;
  17099. }
  17100. return colMeta;
  17101. }
  17102. });
  17103. selectCell(1, 1);
  17104. keyDownUp('enter');
  17105. setTimeout(function () {
  17106. keyDown('arrow_down');
  17107. keyDownUp('enter');
  17108. expect(data.length).toEqual(3);
  17109. done();
  17110. }, 200);
  17111. });
  17112. it('should not create more rows that maxRows', function () {
  17113. handsontable({
  17114. startRows: 4,
  17115. maxRows: 6,
  17116. minSpareRows: 1
  17117. });
  17118. setDataAtCell(3, 0, 'test');
  17119. setDataAtCell(4, 0, 'test');
  17120. setDataAtCell(5, 0, 'test');
  17121. expect(countRows()).toEqual(6);
  17122. });
  17123. it('should not create more cols that maxCols', function () {
  17124. handsontable({
  17125. startCols: 4,
  17126. maxCols: 6,
  17127. minSpareCols: 1
  17128. });
  17129. setDataAtCell(0, 3, 'test');
  17130. setDataAtCell(0, 4, 'test');
  17131. setDataAtCell(0, 5, 'test');
  17132. expect(countCols()).toEqual(6);
  17133. });
  17134. it('should ignore minCols if columns is set', function () {
  17135. handsontable({
  17136. startCols: 1,
  17137. minCols: 6,
  17138. columns: [{}, {}]
  17139. });
  17140. expect(countCols()).toEqual(2);
  17141. });
  17142. it('should ignore minCols if columns is set when columns is a function', function () {
  17143. handsontable({
  17144. startCols: 1,
  17145. minCols: 6,
  17146. columns: function columns(column) {
  17147. var colMeta = {};
  17148. if ([0, 1].indexOf(column) < 0) {
  17149. colMeta = null;
  17150. }
  17151. return colMeta;
  17152. }
  17153. });
  17154. expect(countCols()).toEqual(1);
  17155. });
  17156. it('columns should have priority over startCols', function () {
  17157. handsontable({
  17158. startCols: 3,
  17159. minCols: 6,
  17160. columns: [{}, {}]
  17161. });
  17162. expect(countCols()).toEqual(2);
  17163. });
  17164. it('columns should have priority over startCols when columns is a function', function () {
  17165. handsontable({
  17166. startCols: 3,
  17167. minCols: 6,
  17168. columns: function columns(column) {
  17169. var colMeta = {};
  17170. if ([0, 1].indexOf(column) < 0) {
  17171. colMeta = null;
  17172. }
  17173. return colMeta;
  17174. }
  17175. });
  17176. expect(countCols()).toEqual(2);
  17177. });
  17178. });
  17179. /***/ }),
  17180. /* 167 */
  17181. /***/ (function(module, exports, __webpack_require__) {
  17182. "use strict";
  17183. describe('Core_listen', function () {
  17184. var id = 'testContainer';
  17185. beforeEach(function () {
  17186. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  17187. });
  17188. afterEach(function () {
  17189. if (this.$container) {
  17190. destroy();
  17191. this.$container.remove();
  17192. }
  17193. });
  17194. it('should listen to changes when cell is selected', function () {
  17195. var hot = handsontable();
  17196. hot.selectCell(0, 0);
  17197. expect(hot.isListening()).toEqual(true);
  17198. });
  17199. it('should\'t listen to changes when cell is selected via `selectCell` when `changeListener` argument is `false`', function () {
  17200. var hot = handsontable();
  17201. hot.unlisten();
  17202. expect(hot.isListening()).toEqual(false);
  17203. hot.selectCell(0, 0, undefined, undefined, true, false);
  17204. expect(hot.isListening()).toEqual(false);
  17205. });
  17206. it('should unlisten changes', function () {
  17207. var hot = handsontable();
  17208. hot.selectCell(0, 0);
  17209. expect(hot.isListening()).toEqual(true);
  17210. hot.unlisten();
  17211. expect(hot.isListening()).toEqual(false);
  17212. });
  17213. it('should listen to changes, when called after unlisten', function () {
  17214. var hot = handsontable();
  17215. hot.selectCell(0, 0);
  17216. hot.unlisten();
  17217. hot.listen();
  17218. expect(hot.isListening()).toEqual(true);
  17219. });
  17220. it('when second instance is created, first should unlisten automatically', function () {
  17221. var $container1 = $('<div id="hot1"></div>').appendTo('body').handsontable();
  17222. $container1.handsontable('selectCell', 0, 0);
  17223. var $container2 = $('<div id="hot2"></div>').appendTo('body').handsontable();
  17224. $container2.handsontable('selectCell', 0, 0);
  17225. expect($container1.handsontable('isListening')).toEqual(false);
  17226. expect($container2.handsontable('isListening')).toEqual(true);
  17227. $container1.handsontable('destroy');
  17228. $container1.remove();
  17229. $container2.handsontable('destroy');
  17230. $container2.remove();
  17231. });
  17232. it('when listen is called on first instance, second should unlisten automatically', function () {
  17233. var $container1 = $('<div id="hot1"></div>').appendTo('body').handsontable();
  17234. $container1.handsontable('selectCell', 0, 0);
  17235. var $container2 = $('<div id="hot2"></div>').appendTo('body').handsontable();
  17236. $container2.handsontable('selectCell', 0, 0);
  17237. $container1.handsontable('listen');
  17238. expect($container1.handsontable('isListening')).toEqual(true);
  17239. expect($container2.handsontable('isListening')).toEqual(false);
  17240. $container1.handsontable('destroy');
  17241. $container1.remove();
  17242. $container2.handsontable('destroy');
  17243. $container2.remove();
  17244. });
  17245. });
  17246. /***/ }),
  17247. /* 168 */
  17248. /***/ (function(module, exports, __webpack_require__) {
  17249. "use strict";
  17250. describe('Core_loadData', function () {
  17251. var id = 'testContainer';
  17252. beforeEach(function () {
  17253. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  17254. });
  17255. afterEach(function () {
  17256. if (this.$container) {
  17257. destroy();
  17258. this.$container.remove();
  17259. }
  17260. });
  17261. var arrayOfArrays = function arrayOfArrays() {
  17262. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  17263. };
  17264. var arrayOfObjects = function arrayOfObjects() {
  17265. return [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }, { id: 6, name: 'Chuck', lastName: 'Jackson' }, { id: 7, name: 'Meg', lastName: 'Jansen' }, { id: 8, name: 'Rob', lastName: 'Norris' }, { id: 9, name: 'Sean', lastName: 'O\'Hara' }, { id: 10, name: 'Eve', lastName: 'Branson' }];
  17266. };
  17267. var arrayOfNestedObjects = function arrayOfNestedObjects() {
  17268. return [{
  17269. id: 1,
  17270. name: {
  17271. first: 'Ted',
  17272. last: 'Right'
  17273. },
  17274. 'full.street': 'Street I'
  17275. }, {
  17276. id: 2,
  17277. name: {
  17278. first: 'Frank',
  17279. last: 'Honest'
  17280. },
  17281. 'full.street': 'Street II'
  17282. }, {
  17283. id: 3,
  17284. name: {
  17285. first: 'Joan',
  17286. last: 'Well'
  17287. },
  17288. 'full.street': 'Street III'
  17289. }];
  17290. };
  17291. var htmlData = [['<b>H&M</b>']];
  17292. it('should allow array of arrays', function () {
  17293. handsontable();
  17294. loadData(arrayOfArrays());
  17295. expect(getDataAtCell(0, 2)).toEqual('Nissan');
  17296. });
  17297. it('should allow array of objects', function () {
  17298. handsontable({
  17299. columns: [{ data: 'id' }, { data: 'lastName' }, { data: 'name' }]
  17300. });
  17301. loadData(arrayOfObjects());
  17302. expect(getDataAtCell(0, 2)).toEqual('Ted');
  17303. });
  17304. it('should allow array of objects when columns as a function', function () {
  17305. handsontable({
  17306. columns: function columns(column) {
  17307. var colMeta = {};
  17308. if (column === 0) {
  17309. colMeta.data = 'id';
  17310. } else if (column === 1) {
  17311. colMeta.data = 'lastName';
  17312. } else if (column === 2) {
  17313. colMeta.data = 'name';
  17314. } else {
  17315. colMeta = null;
  17316. }
  17317. return colMeta;
  17318. }
  17319. });
  17320. loadData(arrayOfObjects());
  17321. expect(getDataAtCell(0, 2)).toEqual('Ted');
  17322. });
  17323. it('should allow array of nested objects', function () {
  17324. handsontable({
  17325. data: arrayOfNestedObjects(),
  17326. colHeaders: true,
  17327. columns: [{ data: 'id' }, { data: 'name.last' }, { data: 'name.first' }, { data: 'full.street' }]
  17328. });
  17329. expect(getDataAtCell(0, 2)).toEqual('Ted');
  17330. expect(getDataAtCell(1, 3)).toEqual('Street II');
  17331. expect(getDataAtRowProp(2, 'full.street')).toEqual('Street III');
  17332. });
  17333. it('should allow array of nested objects when columns as a function', function () {
  17334. handsontable({
  17335. data: arrayOfNestedObjects(),
  17336. colHeaders: true,
  17337. columns: function columns(column) {
  17338. var colMeta = {};
  17339. if (column === 0) {
  17340. colMeta.data = 'id';
  17341. } else if (column === 1) {
  17342. colMeta.data = 'name.last';
  17343. } else if (column === 2) {
  17344. colMeta.data = 'name.first';
  17345. } else if (column === 3) {
  17346. colMeta.data = 'full.street';
  17347. } else {
  17348. colMeta = null;
  17349. }
  17350. return colMeta;
  17351. }
  17352. });
  17353. expect(getDataAtCell(0, 2)).toEqual('Ted');
  17354. expect(getDataAtCell(1, 3)).toEqual('Street II');
  17355. expect(getDataAtRowProp(2, 'full.street')).toEqual('Street III');
  17356. });
  17357. it('should figure out default column names for array of nested objects', function () {
  17358. handsontable({
  17359. data: arrayOfNestedObjects(),
  17360. colHeaders: true
  17361. });
  17362. expect(getDataAtCell(0, 2)).toEqual('Right');
  17363. });
  17364. it('should trigger onChange callback when loaded array of arrays', function () {
  17365. var called = false;
  17366. handsontable({
  17367. afterChange: function afterChange(changes, source) {
  17368. if (source === 'loadData') {
  17369. called = true;
  17370. }
  17371. }
  17372. });
  17373. loadData(arrayOfArrays());
  17374. expect(called).toEqual(true);
  17375. });
  17376. it('should trigger onChange callback when loaded array of objects', function () {
  17377. var called = false;
  17378. handsontable({
  17379. afterChange: function afterChange(changes, source) {
  17380. if (source === 'loadData') {
  17381. called = true;
  17382. }
  17383. }
  17384. });
  17385. loadData(arrayOfObjects());
  17386. expect(called).toEqual(true);
  17387. });
  17388. it('should trigger onChange callback when loaded array of nested objects', function () {
  17389. var called = false;
  17390. handsontable({
  17391. afterChange: function afterChange(changes, source) {
  17392. if (source === 'loadData') {
  17393. called = true;
  17394. }
  17395. }
  17396. });
  17397. loadData(arrayOfNestedObjects());
  17398. expect(called).toEqual(true);
  17399. });
  17400. it('should create new rows for array of arrays (and respect minRows)', function () {
  17401. handsontable({
  17402. minRows: 20, // minRows should be respected
  17403. data: arrayOfArrays()
  17404. });
  17405. expect(countRows()).toEqual(20); // TODO why this must be checked after render?
  17406. });
  17407. it('should create new rows for array of nested objects (and respect minRows)', function () {
  17408. handsontable({
  17409. minRows: 20, // minRows should be respected
  17410. data: arrayOfNestedObjects()
  17411. });
  17412. expect(countRows()).toEqual(20); // TODO why this must be checked after render?
  17413. });
  17414. it('HTML special chars should be escaped by default', function () {
  17415. handsontable();
  17416. loadData(htmlData);
  17417. expect(getCell(0, 0).innerHTML).toEqual('&lt;b&gt;H&amp;M&lt;/b&gt;');
  17418. });
  17419. it('should create as many rows as needed by array of objects', function () {
  17420. handsontable({
  17421. minRows: 6,
  17422. data: arrayOfObjects()
  17423. });
  17424. expect(getCell(9, 1).innerHTML).toEqual('Eve');
  17425. });
  17426. // https://github.com/handsontable/handsontable/pull/233
  17427. it('should not invoke the cells callback multiple times with the same row/col (without overlays)', function () {
  17428. var cellsSpy = jasmine.createSpy('cellsSpy');
  17429. handsontable({
  17430. data: arrayOfNestedObjects(),
  17431. colWidths: [90, 90, 90, 90],
  17432. rowHeights: [23, 23, 23, 23],
  17433. cells: cellsSpy
  17434. });
  17435. //
  17436. expect(cellsSpy.calls.count()).toEqual(43);
  17437. });
  17438. it('should not invoke the cells callback multiple times with the same row/col (with overlays)', function () {
  17439. var cellsSpy = jasmine.createSpy('cellsSpy');
  17440. handsontable({
  17441. data: arrayOfNestedObjects(),
  17442. colHeaders: true,
  17443. rowHeaders: true,
  17444. colWidths: [90, 90, 90, 90],
  17445. rowHeights: [90, 90, 90, 90],
  17446. cells: cellsSpy
  17447. });
  17448. expect(cellsSpy.calls.count()).toEqual(56);
  17449. });
  17450. it('should remove grid rows if new data source has less of them', function () {
  17451. var data1 = [['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['g'], ['h']];
  17452. var data2 = [['a'], ['b'], ['c'], ['d'], ['e']];
  17453. handsontable({
  17454. data: data1,
  17455. rowHeaders: true,
  17456. colHeaders: true
  17457. });
  17458. selectCell(7, 0);
  17459. loadData(data2);
  17460. expect(countRows()).toBe(data2.length);
  17461. expect(getSelected()).toEqual([4, 0, 4, 0]);
  17462. });
  17463. it('should remove grid rows if new data source has less of them (with minSpareRows)', function () {
  17464. var data1 = [['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['g'], ['h']];
  17465. var data2 = [['a'], ['b'], ['c'], ['d'], ['e']];
  17466. handsontable({
  17467. data: data1,
  17468. minSpareCols: 1,
  17469. minSpareRows: 1,
  17470. rowHeaders: true,
  17471. colHeaders: true
  17472. });
  17473. selectCell(8, 0);
  17474. loadData(data2);
  17475. expect(countRows()).toBe(6); // +1 because of minSpareRows
  17476. expect(getSelected()).toEqual([5, 0, 5, 0]);
  17477. });
  17478. it('loading empty data should remove all rows', function () {
  17479. var data1 = [['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['g'], ['h']];
  17480. var data2 = [];
  17481. handsontable({
  17482. data: data1,
  17483. rowHeaders: true,
  17484. colHeaders: true
  17485. });
  17486. selectCell(7, 0);
  17487. loadData(data2);
  17488. expect(countRows()).toBe(0);
  17489. expect(getSelected()).toBe(void 0);
  17490. });
  17491. it('should only have as many columns as in settings', function () {
  17492. var data1 = arrayOfArrays();
  17493. handsontable({
  17494. data: data1,
  17495. columns: [{ data: 1 }, { data: 3 }]
  17496. });
  17497. expect(countCols()).toBe(2);
  17498. });
  17499. it('should only have as many columns as in settings when columns is a function', function () {
  17500. var data1 = arrayOfArrays();
  17501. handsontable({
  17502. data: data1,
  17503. columns: function columns(column) {
  17504. var colMeta = {
  17505. data: column
  17506. };
  17507. if ([1, 3].indexOf(column) < 0) {
  17508. colMeta = null;
  17509. }
  17510. return colMeta;
  17511. }
  17512. });
  17513. expect(countCols()).toBe(2);
  17514. });
  17515. it('should throw error when trying to load a string (constructor)', function () {
  17516. var errors = 0;
  17517. try {
  17518. handsontable({
  17519. data: 'string'
  17520. });
  17521. } catch (e) {
  17522. errors++;
  17523. }
  17524. expect(errors).toBe(1);
  17525. });
  17526. it('should throw error when trying to load a string (loadData)', function () {
  17527. var errors = 0;
  17528. try {
  17529. handsontable();
  17530. loadData('string');
  17531. } catch (e) {
  17532. errors++;
  17533. }
  17534. expect(errors).toBe(1);
  17535. });
  17536. it('should load Backbone Collection as data source', function () {
  17537. // code borrowed from demo/backbone.js
  17538. var CarModel = Backbone.Model.extend({});
  17539. var CarCollection = Backbone.Collection.extend({
  17540. model: CarModel,
  17541. // Backbone.Collection doesn't support `splice`, yet! Easy to add.
  17542. splice: hackedSplice
  17543. });
  17544. var cars = new CarCollection();
  17545. cars.add([{ make: 'Dodge', model: 'Ram', year: 2012, weight: 6811 }, { make: 'Toyota', model: 'Camry', year: 2012, weight: 3190 }, { make: 'Smart', model: 'Fortwo', year: 2012, weight: 1808 }]);
  17546. handsontable({
  17547. data: cars,
  17548. columns: [attr('make'), attr('model'), attr('year')]
  17549. });
  17550. // use the "good" Collection methods to emulate Array.splice
  17551. function hackedSplice(index, howMany /* model1, ... modelN */) {
  17552. var args = _.toArray(arguments).slice(2).concat({ at: index }),
  17553. removed = this.models.slice(index, index + howMany);
  17554. this.remove(removed).add.apply(this, args);
  17555. return removed;
  17556. }
  17557. // normally, you'd get these from the server with .fetch()
  17558. function attr(attr) {
  17559. // this lets us remember `attr` for when when it is get/set
  17560. return {
  17561. data: function data(car, value) {
  17562. if (_.isUndefined(value)) {
  17563. return car.get(attr);
  17564. }
  17565. car.set(attr, value);
  17566. }
  17567. };
  17568. }
  17569. expect(countRows()).toBe(3);
  17570. });
  17571. it('should load Backbone Collection as data source when columns is a function', function () {
  17572. // code borrowed from demo/backbone.js
  17573. var CarModel = Backbone.Model.extend({});
  17574. var CarCollection = Backbone.Collection.extend({
  17575. model: CarModel,
  17576. // Backbone.Collection doesn't support `splice`, yet! Easy to add.
  17577. splice: hackedSplice
  17578. });
  17579. var cars = new CarCollection();
  17580. cars.add([{ make: 'Dodge', model: 'Ram', year: 2012, weight: 6811 }, { make: 'Toyota', model: 'Camry', year: 2012, weight: 3190 }, { make: 'Smart', model: 'Fortwo', year: 2012, weight: 1808 }]);
  17581. handsontable({
  17582. data: cars,
  17583. columns: function columns(column) {
  17584. var colMeta = null;
  17585. if (column === 0) {
  17586. colMeta = attr('make');
  17587. } else if (column === 1) {
  17588. colMeta = attr('model');
  17589. } else if (column === 2) {
  17590. colMeta = attr('year');
  17591. }
  17592. return colMeta;
  17593. }
  17594. });
  17595. // use the "good" Collection methods to emulate Array.splice
  17596. function hackedSplice(index, howMany /* model1, ... modelN */) {
  17597. var args = _.toArray(arguments).slice(2).concat({ at: index }),
  17598. removed = this.models.slice(index, index + howMany);
  17599. this.remove(removed).add.apply(this, args);
  17600. return removed;
  17601. }
  17602. // normally, you'd get these from the server with .fetch()
  17603. function attr(attr) {
  17604. // this lets us remember `attr` for when when it is get/set
  17605. return {
  17606. data: function data(car, value) {
  17607. if (_.isUndefined(value)) {
  17608. return car.get(attr);
  17609. }
  17610. car.set(attr, value);
  17611. }
  17612. };
  17613. }
  17614. expect(countRows()).toBe(3);
  17615. });
  17616. it('should clear cell properties after loadData', function () {
  17617. handsontable();
  17618. loadData(arrayOfArrays());
  17619. getCellMeta(0, 0).foo = 'bar';
  17620. expect(getCellMeta(0, 0).foo).toEqual('bar');
  17621. loadData(arrayOfArrays());
  17622. expect(getCellMeta(0, 0).foo).toBeUndefined();
  17623. });
  17624. it('should clear cell properties after loadData, but before rendering new data', function () {
  17625. handsontable();
  17626. loadData(arrayOfArrays());
  17627. getCellMeta(0, 0).valid = false;
  17628. render();
  17629. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(true);
  17630. loadData(arrayOfArrays());
  17631. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(false);
  17632. });
  17633. // https://github.com/handsontable/handsontable/issues/1700
  17634. // can't edit anything after starting editing cell with no nested object
  17635. it('should correct behave with cell with no nested object data source corresponding to column mapping', function () {
  17636. var objectData = [{ id: 1, user: { name: { first: 'Ted', last: 'Right' } } }, { id: 2, user: { name: {} } }, { id: 3 }];
  17637. handsontable({
  17638. data: objectData,
  17639. columns: [{ data: 'id' }, { data: 'user.name.first' }, { data: 'user.name.last' }]
  17640. });
  17641. mouseDoubleClick(getCell(1, 1));
  17642. document.activeElement.value = 'Harry';
  17643. deselectCell();
  17644. expect(objectData[1].user.name.first).toEqual('Harry');
  17645. mouseDoubleClick(getCell(2, 1));
  17646. document.activeElement.value = 'Barry';
  17647. deselectCell();
  17648. expect(objectData[2].user.name.first).toEqual('Barry');
  17649. });
  17650. it('should correct behave with cell with no nested object data source corresponding to column mapping when columns is a function', function () {
  17651. var objectData = [{ id: 1, user: { name: { first: 'Ted', last: 'Right' } } }, { id: 2, user: { name: {} } }, { id: 3 }];
  17652. handsontable({
  17653. data: objectData,
  17654. columns: function columns(column) {
  17655. var colMeta = null;
  17656. if (column === 0) {
  17657. colMeta = { data: 'id' };
  17658. } else if (column === 1) {
  17659. colMeta = { data: 'user.name.first' };
  17660. } else if (column === 2) {
  17661. colMeta = { data: 'user.name.last' };
  17662. }
  17663. return colMeta;
  17664. }
  17665. });
  17666. mouseDoubleClick(getCell(1, 1));
  17667. document.activeElement.value = 'Harry';
  17668. deselectCell();
  17669. expect(objectData[1].user.name.first).toEqual('Harry');
  17670. mouseDoubleClick(getCell(2, 1));
  17671. document.activeElement.value = 'Barry';
  17672. deselectCell();
  17673. expect(objectData[2].user.name.first).toEqual('Barry');
  17674. });
  17675. });
  17676. /***/ }),
  17677. /* 169 */
  17678. /***/ (function(module, exports, __webpack_require__) {
  17679. "use strict";
  17680. describe('Core_navigation', function () {
  17681. var id = 'testContainer';
  17682. beforeEach(function () {
  17683. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  17684. });
  17685. afterEach(function () {
  17686. if (this.$container) {
  17687. destroy();
  17688. this.$container.remove();
  17689. }
  17690. });
  17691. it('should move to the next cell', function () {
  17692. handsontable({
  17693. startRows: 5,
  17694. startCols: 5
  17695. });
  17696. selectCell(0, 0);
  17697. keyDown('arrow_right');
  17698. expect(getSelected()).toEqual([0, 1, 0, 1]);
  17699. });
  17700. it('should move to the previous cell', function () {
  17701. handsontable({
  17702. startRows: 5,
  17703. startCols: 5
  17704. });
  17705. selectCell(1, 2);
  17706. keyDown('arrow_left');
  17707. expect(getSelected()).toEqual([1, 1, 1, 1]);
  17708. });
  17709. it('should move to the cell above', function () {
  17710. handsontable({
  17711. startRows: 5,
  17712. startCols: 5
  17713. });
  17714. selectCell(1, 2);
  17715. keyDown('arrow_up');
  17716. expect(getSelected()).toEqual([0, 2, 0, 2]);
  17717. });
  17718. it('should move to the cell below', function () {
  17719. handsontable({
  17720. startRows: 5,
  17721. startCols: 5
  17722. });
  17723. selectCell(1, 2);
  17724. keyDown('arrow_down');
  17725. expect(getSelected()).toEqual([2, 2, 2, 2]);
  17726. });
  17727. describe('autoWrap disabled', function () {
  17728. it('should NOT move to the next cell, if already at the last cell in row', function () {
  17729. handsontable({
  17730. startRows: 5,
  17731. startCols: 5,
  17732. autoWrapRow: false
  17733. });
  17734. selectCell(0, 4);
  17735. keyDown('arrow_right');
  17736. expect(getSelected()).toEqual([0, 4, 0, 4]);
  17737. });
  17738. it('should NOT move to the previous cell, if already at the first cell in row', function () {
  17739. handsontable({
  17740. startRows: 5,
  17741. startCols: 5,
  17742. autoWrapRow: false
  17743. });
  17744. selectCell(1, 0);
  17745. keyDown('arrow_left');
  17746. expect(getSelected()).toEqual([1, 0, 1, 0]);
  17747. });
  17748. it('should NOT move to the cell below, if already at the last cell in column', function () {
  17749. handsontable({
  17750. startRows: 5,
  17751. startCols: 5,
  17752. autoWrapCol: false
  17753. });
  17754. selectCell(4, 0);
  17755. keyDown('arrow_down');
  17756. expect(getSelected()).toEqual([4, 0, 4, 0]);
  17757. });
  17758. it('should NOT move to the cell above, if already at the first cell in column', function () {
  17759. handsontable({
  17760. startRows: 5,
  17761. startCols: 5,
  17762. autoWrapCol: false
  17763. });
  17764. selectCell(0, 1);
  17765. keyDown('arrow_up');
  17766. expect(getSelected()).toEqual([0, 1, 0, 1]);
  17767. });
  17768. });
  17769. describe('autoWrap enabled', function () {
  17770. it('should move to the first cell of the next row, if already at the last cell in row', function () {
  17771. handsontable({
  17772. startRows: 5,
  17773. startCols: 5,
  17774. autoWrapRow: true
  17775. });
  17776. selectCell(0, 4);
  17777. keyDown('arrow_right');
  17778. expect(getSelected()).toEqual([1, 0, 1, 0]);
  17779. });
  17780. it('should move to the first cell of the previous row, if already at the first cell in row', function () {
  17781. handsontable({
  17782. startRows: 5,
  17783. startCols: 5,
  17784. autoWrapRow: true
  17785. });
  17786. selectCell(1, 0);
  17787. keyDown('arrow_left');
  17788. expect(getSelected()).toEqual([0, 4, 0, 4]);
  17789. });
  17790. it('should move to the first cell of the next column, if already at the last cell in column', function () {
  17791. handsontable({
  17792. startRows: 5,
  17793. startCols: 5,
  17794. autoWrapCol: true
  17795. });
  17796. selectCell(4, 1);
  17797. keyDown('arrow_down');
  17798. expect(getSelected()).toEqual([0, 2, 0, 2]);
  17799. });
  17800. it('should move to the last cell of the previous column, if already at the first cell in column', function () {
  17801. handsontable({
  17802. startRows: 5,
  17803. startCols: 5,
  17804. autoWrapCol: true
  17805. });
  17806. selectCell(0, 1);
  17807. keyDown('arrow_up');
  17808. expect(getSelected()).toEqual([4, 0, 4, 0]);
  17809. });
  17810. it('should move to the first cell of the first row, after trying to get to the next cell in row, being already at the last cell in table', function () {
  17811. handsontable({
  17812. startRows: 5,
  17813. startCols: 5,
  17814. autoWrapRow: true
  17815. });
  17816. selectCell(4, 4);
  17817. keyDown('arrow_right');
  17818. expect(getSelected()).toEqual([0, 0, 0, 0]);
  17819. });
  17820. it('should move to the first cell of the first row, after trying to get to the next cell in column, being already at the last cell in table', function () {
  17821. handsontable({
  17822. startRows: 5,
  17823. startCols: 5,
  17824. autoWrapCol: true
  17825. });
  17826. selectCell(4, 4);
  17827. keyDown('arrow_down');
  17828. expect(getSelected()).toEqual([0, 0, 0, 0]);
  17829. });
  17830. it('should move to the last cell of the last row, after trying to get to the previous cell in row, being already at the first cell in table', function () {
  17831. handsontable({
  17832. startRows: 5,
  17833. startCols: 5,
  17834. autoWrapRow: true
  17835. });
  17836. selectCell(0, 0);
  17837. keyDown('arrow_left');
  17838. expect(getSelected()).toEqual([4, 4, 4, 4]);
  17839. });
  17840. it('should move to the last cell of the last row, after trying to get to the previous cell in column, being already at the first cell in table', function () {
  17841. handsontable({
  17842. startRows: 5,
  17843. startCols: 5,
  17844. autoWrapCol: true
  17845. });
  17846. selectCell(0, 0);
  17847. keyDown('arrow_up');
  17848. expect(getSelected()).toEqual([4, 4, 4, 4]);
  17849. });
  17850. it('should traverse whole table by constantly selecting next cell in row', function () {
  17851. handsontable({
  17852. startRows: 5,
  17853. startCols: 5,
  17854. autoWrapRow: true
  17855. });
  17856. selectCell(0, 0);
  17857. for (var row = 0, rlen = countRows(); row < rlen; row++) {
  17858. for (var col = 0, clen = countCols(); col < clen; col++) {
  17859. expect(getSelected()).toEqual([row, col, row, col]);
  17860. keyDown('arrow_right');
  17861. }
  17862. }
  17863. expect(getSelected()).toEqual([0, 0, 0, 0]);
  17864. });
  17865. it('should traverse whole table by constantly selecting previous cell in row', function () {
  17866. handsontable({
  17867. startRows: 5,
  17868. startCols: 5,
  17869. autoWrapRow: true
  17870. });
  17871. selectCell(4, 4);
  17872. for (var row = countRows() - 1; row >= 0; row--) {
  17873. for (var col = countCols() - 1; col >= 0; col--) {
  17874. expect(getSelected()).toEqual([row, col, row, col]);
  17875. keyDown('arrow_left');
  17876. }
  17877. }
  17878. expect(getSelected()).toEqual([4, 4, 4, 4]);
  17879. });
  17880. it('should traverse whole table by constantly selecting next cell in column', function () {
  17881. handsontable({
  17882. startRows: 5,
  17883. startCols: 5,
  17884. autoWrapCol: true
  17885. });
  17886. selectCell(0, 0);
  17887. for (var col = 0, clen = countCols(); col < clen; col++) {
  17888. for (var row = 0, rlen = countRows(); row < rlen; row++) {
  17889. expect(getSelected()).toEqual([row, col, row, col]);
  17890. keyDown('arrow_down');
  17891. }
  17892. }
  17893. expect(getSelected()).toEqual([0, 0, 0, 0]);
  17894. });
  17895. it('should traverse whole table by constantly selecting previous cell in column', function () {
  17896. handsontable({
  17897. startRows: 5,
  17898. startCols: 5,
  17899. autoWrapCol: true
  17900. });
  17901. selectCell(4, 4);
  17902. for (var col = countCols() - 1; col >= 0; col--) {
  17903. for (var row = countRows() - 1; row >= 0; row--) {
  17904. expect(getSelected()).toEqual([row, col, row, col]);
  17905. keyDown('arrow_up');
  17906. }
  17907. }
  17908. expect(getSelected()).toEqual([4, 4, 4, 4]);
  17909. });
  17910. });
  17911. });
  17912. /***/ }),
  17913. /* 170 */
  17914. /***/ (function(module, exports, __webpack_require__) {
  17915. "use strict";
  17916. describe('Core_onKeyDown', function () {
  17917. var id = 'testContainer';
  17918. beforeEach(function () {
  17919. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  17920. });
  17921. afterEach(function () {
  17922. if (this.$container) {
  17923. destroy();
  17924. this.$container.remove();
  17925. }
  17926. });
  17927. it('should advance to next cell when TAB is pressed', function () {
  17928. // https://github.com/handsontable/handsontable/issues/151
  17929. handsontable();
  17930. selectCell(0, 0);
  17931. keyDownUp('tab');
  17932. expect(getSelected()).toEqual([0, 1, 0, 1]);
  17933. });
  17934. it('should advance to previous cell when shift+TAB is pressed', function () {
  17935. handsontable();
  17936. selectCell(1, 1);
  17937. keyDownUp('shift+tab');
  17938. expect(getSelected()).toEqual([1, 0, 1, 0]);
  17939. });
  17940. describe('while editing (quick edit mode)', function () {
  17941. it('should finish editing and advance to next cell when TAB is pressed', function () {
  17942. // https://github.com/handsontable/handsontable/issues/215
  17943. handsontable();
  17944. selectCell(1, 1);
  17945. keyDownUp('x'); // value to cell trigger quick edit mode
  17946. keyProxy().val('Ted');
  17947. keyDownUp('tab');
  17948. expect(getData()[1][1]).toEqual('Ted');
  17949. expect(getSelected()).toEqual([1, 2, 1, 2]);
  17950. });
  17951. it('should finish editing and advance to lower cell when enter is pressed', function () {
  17952. // https://github.com/handsontable/handsontable/issues/215
  17953. handsontable();
  17954. selectCell(1, 1);
  17955. keyDownUp('x'); // value to cell trigger quick edit mode
  17956. keyProxy().val('Ted');
  17957. keyDownUp('enter');
  17958. expect(getData()[1][1]).toEqual('Ted');
  17959. expect(getSelected()).toEqual([2, 1, 2, 1]);
  17960. });
  17961. it('should finish editing and advance to higher cell when shift+enter is pressed', function () {
  17962. // https://github.com/handsontable/handsontable/issues/215
  17963. handsontable();
  17964. selectCell(1, 1);
  17965. keyDownUp('x'); // trigger quick edit mode
  17966. keyProxy().val('Ted');
  17967. keyDownUp('shift+enter');
  17968. expect(getData()[1][1]).toEqual('Ted');
  17969. expect(getSelected()).toEqual([0, 1, 0, 1]);
  17970. });
  17971. it('should finish editing and advance to lower cell when down arrow is pressed', function () {
  17972. handsontable();
  17973. selectCell(1, 1);
  17974. keyDownUp('x');
  17975. keyProxy().val('Ted');
  17976. keyDownUp('arrow_down');
  17977. expect(getData()[1][1]).toEqual('Ted');
  17978. expect(getSelected()).toEqual([2, 1, 2, 1]);
  17979. });
  17980. it('should finish editing and advance to higher cell when up arrow is pressed', function () {
  17981. handsontable();
  17982. selectCell(1, 1);
  17983. keyDownUp('x');
  17984. keyProxy().val('Ted');
  17985. keyDownUp('arrow_up');
  17986. expect(getData()[1][1]).toEqual('Ted');
  17987. expect(getSelected()).toEqual([0, 1, 0, 1]);
  17988. });
  17989. it('should finish editing and advance to right cell when right arrow is pressed', function () {
  17990. handsontable();
  17991. selectCell(1, 1);
  17992. keyDownUp('x');
  17993. keyProxy().val('Ted');
  17994. keyDownUp('arrow_right');
  17995. keyDownUp('arrow_right');
  17996. keyDownUp('arrow_right');
  17997. keyDownUp('arrow_right');
  17998. expect(getData()[1][1]).toEqual('Ted');
  17999. expect(getSelected()).toEqual([1, 4, 1, 4]);
  18000. });
  18001. it('should finish editing and advance to left cell when left arrow is pressed', function () {
  18002. handsontable();
  18003. selectCell(1, 1);
  18004. keyDownUp('x');
  18005. keyProxy().val('Ted');
  18006. Handsontable.dom.setCaretPosition(keyProxy()[0], 0, 0);
  18007. keyDownUp('arrow_left');
  18008. keyDownUp('arrow_left');
  18009. keyDownUp('arrow_left');
  18010. keyDownUp('arrow_left');
  18011. keyDownUp('arrow_left');
  18012. expect(getData()[1][1]).toEqual('Ted');
  18013. expect(getSelected()).toEqual([1, 0, 1, 0]);
  18014. });
  18015. it('should finish editing and advance to lower cell when enter is pressed (with sync validator)', function (done) {
  18016. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  18017. handsontable({
  18018. validator: function validator(val, cb) {
  18019. cb(true);
  18020. },
  18021. afterValidate: onAfterValidate
  18022. });
  18023. selectCell(1, 1);
  18024. keyDownUp('x');
  18025. keyProxy().val('Ted');
  18026. onAfterValidate.calls.reset();
  18027. keyDownUp('enter');
  18028. setTimeout(function () {
  18029. expect(onAfterValidate).toHaveBeenCalled();
  18030. expect(getData()[1][1]).toEqual('Ted');
  18031. expect(getSelected()).toEqual([2, 1, 2, 1]);
  18032. done();
  18033. }, 200);
  18034. });
  18035. it('should finish editing and advance to lower cell when enter is pressed (with async validator)', function (done) {
  18036. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  18037. handsontable({
  18038. validator: function validator(val, cb) {
  18039. setTimeout(function () {
  18040. cb(true);
  18041. }, 10);
  18042. },
  18043. afterValidate: onAfterValidate
  18044. });
  18045. selectCell(1, 1);
  18046. keyDownUp('x');
  18047. keyProxy().val('Ted');
  18048. onAfterValidate.calls.reset();
  18049. keyDownUp('enter');
  18050. setTimeout(function () {
  18051. expect(onAfterValidate).toHaveBeenCalled();
  18052. expect(getData()[1][1]).toEqual('Ted');
  18053. expect(getSelected()).toEqual([2, 1, 2, 1]);
  18054. done();
  18055. }, 200);
  18056. });
  18057. });
  18058. describe('while editing (full edit mode)', function () {
  18059. it('should finish editing and advance to next cell when TAB is pressed', function () {
  18060. // https://github.com/handsontable/handsontable/issues/215
  18061. handsontable();
  18062. selectCell(1, 1);
  18063. keyDownUp('enter');
  18064. keyProxy().val('Ted');
  18065. keyDownUp('tab');
  18066. expect(getData()[1][1]).toEqual('Ted');
  18067. expect(getSelected()).toEqual([1, 2, 1, 2]);
  18068. });
  18069. it('should finish editing and advance to lower cell when enter is pressed', function () {
  18070. // https://github.com/handsontable/handsontable/issues/215
  18071. handsontable();
  18072. selectCell(1, 1);
  18073. keyDownUp('enter');
  18074. keyProxy().val('Ted');
  18075. keyDownUp('enter');
  18076. expect(getData()[1][1]).toEqual('Ted');
  18077. expect(getSelected()).toEqual([2, 1, 2, 1]);
  18078. });
  18079. it('should finish editing and advance to higher cell when shift+enter is pressed', function () {
  18080. // https://github.com/handsontable/handsontable/issues/215
  18081. handsontable();
  18082. selectCell(1, 1);
  18083. keyDownUp('enter');
  18084. keyProxy().val('Ted');
  18085. keyDownUp('shift+enter');
  18086. expect(getData()[1][1]).toEqual('Ted');
  18087. expect(getSelected()).toEqual([0, 1, 0, 1]);
  18088. });
  18089. it('shouldn\'t finish editing and advance to lower cell when down arrow is pressed', function () {
  18090. handsontable();
  18091. selectCell(1, 1);
  18092. keyDownUp('enter');
  18093. keyProxy().val('Ted');
  18094. keyDownUp('arrow_down');
  18095. expect(getData()[1][1]).toEqual(null);
  18096. expect(getSelected()).toEqual([1, 1, 1, 1]);
  18097. });
  18098. it('shouldn\'t finish editing and advance to higher cell when up arrow is pressed', function () {
  18099. handsontable();
  18100. selectCell(1, 1);
  18101. keyDownUp('enter');
  18102. keyProxy().val('Ted');
  18103. keyDownUp('arrow_up');
  18104. expect(getData()[1][1]).toEqual(null);
  18105. expect(getSelected()).toEqual([1, 1, 1, 1]);
  18106. });
  18107. it('shouldn\'t finish editing and advance to right cell when right arrow is pressed', function () {
  18108. handsontable();
  18109. selectCell(1, 1);
  18110. keyDownUp('enter');
  18111. keyProxy().val('Ted');
  18112. keyDownUp('arrow_right');
  18113. keyDownUp('arrow_right');
  18114. keyDownUp('arrow_right');
  18115. keyDownUp('arrow_right');
  18116. expect(getData()[1][1]).toEqual(null);
  18117. expect(getSelected()).toEqual([1, 1, 1, 1]);
  18118. });
  18119. it('shouldn\'t finish editing and advance to left cell when left arrow is pressed', function () {
  18120. handsontable();
  18121. selectCell(1, 1);
  18122. keyDownUp('enter');
  18123. keyProxy().val('Ted');
  18124. keyDownUp('arrow_left');
  18125. keyDownUp('arrow_left');
  18126. keyDownUp('arrow_left');
  18127. keyDownUp('arrow_left');
  18128. expect(getData()[1][1]).toEqual(null);
  18129. expect(getSelected()).toEqual([1, 1, 1, 1]);
  18130. });
  18131. it('should finish editing and advance to lower cell when enter is pressed (with sync validator)', function (done) {
  18132. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  18133. handsontable({
  18134. validator: function validator(val, cb) {
  18135. cb(true);
  18136. },
  18137. afterValidate: onAfterValidate
  18138. });
  18139. selectCell(1, 1);
  18140. keyDownUp('enter');
  18141. keyProxy().val('Ted');
  18142. onAfterValidate.calls.reset();
  18143. keyDownUp('enter');
  18144. setTimeout(function () {
  18145. expect(onAfterValidate).toHaveBeenCalled();
  18146. expect(getData()[1][1]).toEqual('Ted');
  18147. expect(getSelected()).toEqual([2, 1, 2, 1]);
  18148. done();
  18149. }, 200);
  18150. });
  18151. it('should finish editing and advance to lower cell when enter is pressed (with async validator)', function (done) {
  18152. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  18153. handsontable({
  18154. validator: function validator(val, cb) {
  18155. setTimeout(function () {
  18156. cb(true);
  18157. }, 10);
  18158. },
  18159. afterValidate: onAfterValidate
  18160. });
  18161. selectCell(1, 1);
  18162. keyDownUp('enter');
  18163. keyProxy().val('Ted');
  18164. onAfterValidate.calls.reset();
  18165. keyDownUp('enter');
  18166. setTimeout(function () {
  18167. expect(onAfterValidate).toHaveBeenCalled();
  18168. expect(getData()[1][1]).toEqual('Ted');
  18169. expect(getSelected()).toEqual([2, 1, 2, 1]);
  18170. done();
  18171. }, 200);
  18172. });
  18173. });
  18174. });
  18175. /***/ }),
  18176. /* 171 */
  18177. /***/ (function(module, exports, __webpack_require__) {
  18178. "use strict";
  18179. describe('Core_paste', function () {
  18180. var id = 'testContainer';
  18181. beforeEach(function () {
  18182. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  18183. });
  18184. afterEach(function () {
  18185. if (this.$container) {
  18186. destroy();
  18187. this.$container.remove();
  18188. }
  18189. });
  18190. var arrayOfArrays = function arrayOfArrays() {
  18191. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  18192. };
  18193. it('should not create new rows or columns when allowInsertRow and allowInsertColumn equal false', function (done) {
  18194. handsontable({
  18195. data: arrayOfArrays(),
  18196. pasteMode: 'shift_down',
  18197. allowInsertRow: false,
  18198. allowInsertColumn: false
  18199. });
  18200. selectCell(3, 4); // selectAll
  18201. triggerPaste('Kia\tNissan\tToyota');
  18202. setTimeout(function () {
  18203. var expected = arrayOfArrays();
  18204. expected[3][4] = 'Kia';
  18205. expect(getData()).toEqual(expected);
  18206. done();
  18207. }, 60);
  18208. });
  18209. it('should shift data down instead of overwrite when paste (when allowInsertRow = false)', function (done) {
  18210. handsontable({
  18211. data: arrayOfArrays(),
  18212. pasteMode: 'shift_down',
  18213. allowInsertRow: false
  18214. });
  18215. selectCell(1, 0); // selectAll
  18216. triggerPaste('Kia\tNissan\tToyota');
  18217. setTimeout(function () {
  18218. expect(getData().length).toEqual(4);
  18219. expect(getData(0, 0, 2, 4)).toEqual([['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['Kia', 'Nissan', 'Toyota', 12, 13], ['2008', 10, 11, 14, 13]]);
  18220. done();
  18221. }, 60);
  18222. });
  18223. it('should shift data down instead of overwrite when paste (minSpareRows > 0)', function (done) {
  18224. handsontable({
  18225. data: arrayOfArrays(),
  18226. pasteMode: 'shift_down',
  18227. minSpareRows: 1
  18228. });
  18229. selectCell(1, 0); // selectAll
  18230. triggerPaste('Kia\tNissan\tToyota');
  18231. setTimeout(function () {
  18232. expect(getData().length).toEqual(6);
  18233. expect(getData(0, 0, 2, 4)).toEqual([['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['Kia', 'Nissan', 'Toyota', 12, 13], ['2008', 10, 11, 14, 13]]);
  18234. done();
  18235. }, 60);
  18236. });
  18237. it('should shift right insert instead of overwrite when paste', function (done) {
  18238. handsontable({
  18239. data: arrayOfArrays(),
  18240. pasteMode: 'shift_right',
  18241. allowInsertColumn: false
  18242. });
  18243. selectCell(1, 0); // selectAll
  18244. triggerPaste('Kia\tNissan\tToyota');
  18245. setTimeout(function () {
  18246. expect(getData()[0].length).toEqual(5);
  18247. expect(getDataAtRow(1)).toEqual(['Kia', 'Nissan', 'Toyota', '2008', 10]);
  18248. done();
  18249. }, 60);
  18250. });
  18251. it('should shift right insert instead of overwrite when paste (minSpareCols > 0)', function (done) {
  18252. handsontable({
  18253. data: arrayOfArrays(),
  18254. pasteMode: 'shift_right',
  18255. minSpareCols: 1
  18256. });
  18257. selectCell(1, 0); // selectAll
  18258. triggerPaste('Kia\tNissan\tToyota');
  18259. setTimeout(function () {
  18260. expect(getData()[0].length).toEqual(9);
  18261. expect(getDataAtRow(1)).toEqual(['Kia', 'Nissan', 'Toyota', '2008', 10, 11, 12, 13, null]);
  18262. done();
  18263. }, 60);
  18264. });
  18265. it('should not throw an error when changes are null in `once` hook', function (done) {
  18266. var errors = 0;
  18267. try {
  18268. handsontable({
  18269. data: arrayOfArrays(),
  18270. afterChange: function afterChange(changes, source) {
  18271. if (source === 'loadData') {
  18272. return;
  18273. }
  18274. loadData(arrayOfArrays());
  18275. }
  18276. });
  18277. selectCell(1, 0); // selectAll
  18278. triggerPaste('Kia\tNissan\tToyota');
  18279. } catch (e) {
  18280. errors++;
  18281. }
  18282. setTimeout(function () {
  18283. expect(errors).toEqual(0);
  18284. done();
  18285. }, 60);
  18286. });
  18287. it('should not paste any data, if no cell is selected', function (done) {
  18288. var hot = handsontable({
  18289. data: Handsontable.helper.createSpreadsheetData(3, 1)
  18290. });
  18291. var copiedData1 = 'foo';
  18292. var copiedData2 = 'bar';
  18293. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  18294. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('A2');
  18295. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('A3');
  18296. expect(getSelected()).toBeUndefined();
  18297. hot.copyPaste.triggerPaste($.Event(), copiedData1);
  18298. setTimeout(function () {
  18299. expect(spec().$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  18300. expect(spec().$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('A2');
  18301. expect(spec().$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('A3');
  18302. }, 100);
  18303. setTimeout(function () {
  18304. selectCell(1, 0, 2, 0);
  18305. hot.copyPaste.triggerPaste($.Event(), copiedData2);
  18306. }, 200);
  18307. setTimeout(function () {
  18308. expect(spec().$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  18309. expect(spec().$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual(copiedData2);
  18310. expect(spec().$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual(copiedData2);
  18311. done();
  18312. }, 300);
  18313. });
  18314. it('should not paste any data, if no cell is selected (select/deselect cell using mouse)', function (done) {
  18315. var hot = handsontable({
  18316. data: Handsontable.helper.createSpreadsheetData(3, 1)
  18317. });
  18318. var copiedData = 'foo';
  18319. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  18320. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('A2');
  18321. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('A3');
  18322. this.$container.find('tbody tr:eq(1) td:eq(0)').simulate('mousedown');
  18323. this.$container.find('tbody tr:eq(1) td:eq(0)').simulate('mouseup');
  18324. expect(getSelected()).toEqual([1, 0, 1, 0]);
  18325. $('html').simulate('mousedown');
  18326. expect(getSelected()).toBeUndefined();
  18327. hot.copyPaste.triggerPaste($.Event(), copiedData);
  18328. setTimeout(function () {
  18329. expect(spec().$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('A1');
  18330. expect(spec().$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('A2');
  18331. expect(spec().$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('A3');
  18332. done();
  18333. }, 100);
  18334. });
  18335. });
  18336. /***/ }),
  18337. /* 172 */
  18338. /***/ (function(module, exports, __webpack_require__) {
  18339. "use strict";
  18340. describe('Core_populateFromArray', function () {
  18341. var id = 'testContainer';
  18342. beforeEach(function () {
  18343. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  18344. });
  18345. afterEach(function () {
  18346. if (this.$container) {
  18347. destroy();
  18348. this.$container.remove();
  18349. }
  18350. });
  18351. var arrayOfArrays = function arrayOfArrays() {
  18352. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda', 'Mix'], ['2008', 10, 11, 12, 13, { a: 1, b: 2 }], ['2009', 20, 11, 14, 13, { a: 1, b: 2 }], ['2010', 30, 15, 12, 13, { a: 1, b: 2 }]];
  18353. };
  18354. it('should call onChange callback', function () {
  18355. var output = null;
  18356. handsontable({
  18357. data: arrayOfArrays(),
  18358. afterChange: function afterChange(changes) {
  18359. output = changes;
  18360. }
  18361. });
  18362. populateFromArray(0, 0, [['test', 'test'], ['test', 'test']], 1, 1);
  18363. expect(output).toEqual([[0, 0, '', 'test'], [0, 1, 'Kia', 'test'], [1, 0, '2008', 'test'], [1, 1, 10, 'test']]);
  18364. });
  18365. it('should populate single value for whole selection', function () {
  18366. var output = null;
  18367. handsontable({
  18368. data: arrayOfArrays(),
  18369. afterChange: function afterChange(changes) {
  18370. output = changes;
  18371. }
  18372. });
  18373. populateFromArray(0, 0, [['test']], 3, 0);
  18374. expect(output).toEqual([[0, 0, '', 'test'], [1, 0, '2008', 'test'], [2, 0, '2009', 'test'], [3, 0, '2010', 'test']]);
  18375. });
  18376. it('should populate value for whole selection only if populated data isn\'t an array', function () {
  18377. var output = null;
  18378. handsontable({
  18379. data: arrayOfArrays(),
  18380. afterChange: function afterChange(changes) {
  18381. output = changes;
  18382. }
  18383. });
  18384. populateFromArray(0, 0, [['test'], [[1, 2, 3]]], 3, 0);
  18385. expect(output).toEqual([[0, 0, '', 'test'], [2, 0, '2009', 'test']]);
  18386. });
  18387. it('should populate value for whole selection only if populated data isn\'t an object', function () {
  18388. var output = null;
  18389. handsontable({
  18390. data: arrayOfArrays(),
  18391. afterChange: function afterChange(changes) {
  18392. output = changes;
  18393. }
  18394. });
  18395. populateFromArray(0, 0, [['test'], [{ test: 1 }]], 3, 0);
  18396. expect(output).toEqual([[0, 0, '', 'test'], [2, 0, '2009', 'test']]);
  18397. });
  18398. it('shouldn\'t populate value if original value doesn\'t have the same data structure', function () {
  18399. var output = null;
  18400. handsontable({
  18401. data: arrayOfArrays(),
  18402. afterChange: function afterChange(changes) {
  18403. output = changes;
  18404. }
  18405. });
  18406. populateFromArray(1, 3, [['test']], 1, 5);
  18407. expect(output).toEqual([[1, 3, 12, 'test'], [1, 4, 13, 'test']]);
  18408. });
  18409. it('should shift values down', function () {
  18410. var output = null;
  18411. handsontable({
  18412. data: arrayOfArrays(),
  18413. afterChange: function afterChange(changes) {
  18414. output = changes;
  18415. },
  18416. minSpareRows: 1
  18417. });
  18418. populateFromArray(0, 0, [['test', 'test2'], ['test3', 'test4']], 2, 2, null, 'shift_down');
  18419. expect(getData()).toEqual([['test', 'test2', 'test', 'Toyota', 'Honda', 'Mix'], ['test3', 'test4', 'test3', 12, 13, { a: 1, b: 2 }], ['test', 'test2', 'test', 14, 13, { a: 1, b: 2 }], ['', 'Kia', 'Nissan', 12, 13, { a: 1, b: 2 }], ['2008', 10, 11, null, null, null], ['2009', 20, 11, null, null, null], ['2010', 30, 15, null, null, null], [null, null, null, null, null, null]]);
  18420. });
  18421. it('should shift values right', function () {
  18422. var output = null;
  18423. handsontable({
  18424. data: arrayOfArrays(),
  18425. afterChange: function afterChange(changes) {
  18426. output = changes;
  18427. },
  18428. minSpareCols: 1
  18429. });
  18430. populateFromArray(0, 0, [['test', 'test2'], ['test3', 'test4']], 2, 2, null, 'shift_right');
  18431. expect(getData()).toEqual([['test', 'test2', 'test', '', 'Kia', 'Nissan', 'Toyota', 'Honda', 'Mix', null], ['test3', 'test4', 'test3', '2008', 10, { a: 1, b: 2 }, 12, 13, null, null], ['test', 'test2', 'test', '2009', 20, { a: 1, b: 2 }, 14, 13, null, null], ['2010', 30, 15, 12, 13, { a: 1, b: 2 }, null, null, null, null]]);
  18432. });
  18433. it('should run beforeAutofillInsidePopulate hook for each inserted value', function () {
  18434. var called = 0;
  18435. var hot = handsontable({
  18436. data: arrayOfArrays()
  18437. });
  18438. hot.addHook('beforeAutofillInsidePopulate', function (index) {
  18439. called++;
  18440. });
  18441. populateFromArray(0, 0, [['test', 'test2'], ['test3', 'test4']], 1, 1, 'Autofill.fill', 'overwrite');
  18442. expect(called).toEqual(4);
  18443. });
  18444. it('should run beforeAutofillInsidePopulate hook and could change cell data before insert if returned object with value property', function () {
  18445. var hot = handsontable({
  18446. data: arrayOfArrays()
  18447. });
  18448. hot.addHook('beforeAutofillInsidePopulate', function (index) {
  18449. return {
  18450. value: 'my_test'
  18451. };
  18452. });
  18453. populateFromArray(0, 0, [['test', 'test2'], ['test3', 'test4']], 1, 1, 'Autofill.fill', 'overwrite');
  18454. expect(getDataAtCell(0, 0)).toEqual('my_test');
  18455. });
  18456. it('should populate 1 row from 2 selected rows', function () {
  18457. var hot = handsontable({
  18458. data: arrayOfArrays()
  18459. });
  18460. populateFromArray(2, 0, [['A1'], ['A2']], 2, 0, 'autofill', null, 'down', [[0]]);
  18461. expect(getDataAtCell(2, 0)).toEqual('A1');
  18462. expect(getDataAtCell(3, 0)).toEqual('2010');
  18463. });
  18464. it('should populate 1 column from 2 selected columns`', function () {
  18465. var hot = handsontable({
  18466. data: arrayOfArrays()
  18467. });
  18468. populateFromArray(0, 2, [['A1', 'A2']], 0, 2, 'autofill', null, 'right', [[0]]);
  18469. expect(getDataAtCell(0, 2)).toEqual('A1');
  18470. expect(getDataAtCell(0, 3)).toEqual('Toyota');
  18471. });
  18472. });
  18473. /***/ }),
  18474. /* 173 */
  18475. /***/ (function(module, exports, __webpack_require__) {
  18476. "use strict";
  18477. describe('Core_reCreate', function () {
  18478. var id = 'testContainer';
  18479. beforeEach(function () {
  18480. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  18481. });
  18482. afterEach(function () {
  18483. if (this.$container) {
  18484. destroy();
  18485. this.$container.remove();
  18486. }
  18487. });
  18488. it('should correctly re-render corner header when there is multiline content', function () {
  18489. var settings = {
  18490. rowHeaders: true,
  18491. colHeaders: function colHeaders(col) {
  18492. return 'Column<br>' + col;
  18493. }
  18494. };
  18495. handsontable(settings);
  18496. destroy();
  18497. handsontable(settings);
  18498. expect(getTopLeftClone().width()).toBe(54);
  18499. expect(getTopLeftClone().height()).toBe(51);
  18500. });
  18501. });
  18502. /***/ }),
  18503. /* 174 */
  18504. /***/ (function(module, exports, __webpack_require__) {
  18505. "use strict";
  18506. describe('Core_removeCellMeta', function () {
  18507. var id = 'testContainer';
  18508. beforeEach(function () {
  18509. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  18510. });
  18511. afterEach(function () {
  18512. if (this.$container) {
  18513. destroy();
  18514. this.$container.remove();
  18515. }
  18516. });
  18517. it('should remove meta for cell', function () {
  18518. handsontable({
  18519. data: [[1, 2, 3, 4], [5, 6, 7, 8], [0, 9, 8, 7]]
  18520. });
  18521. var border = {
  18522. top: {},
  18523. left: {}
  18524. };
  18525. setCellMeta(0, 0, 'borders', border);
  18526. expect(getCellMeta(0, 0).borders).toEqual(border);
  18527. removeCellMeta(0, 0, 'borders');
  18528. expect(getCellMeta(0, 0).borders).toBeUndefined();
  18529. });
  18530. });
  18531. /***/ }),
  18532. /* 175 */
  18533. /***/ (function(module, exports, __webpack_require__) {
  18534. "use strict";
  18535. describe('Core_render', function () {
  18536. var id = 'testContainer';
  18537. beforeEach(function () {
  18538. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  18539. });
  18540. afterEach(function () {
  18541. if (this.$container) {
  18542. destroy();
  18543. this.$container.remove();
  18544. }
  18545. });
  18546. it('all cells should get green background', function () {
  18547. function greenCell(instance, td, row, col, prop, value, cellProperties) {
  18548. Handsontable.renderers.TextRenderer.apply(this, arguments);
  18549. td.style.backgroundColor = 'green';
  18550. }
  18551. handsontable({
  18552. data: [['a', 'b'], ['c', 'd']],
  18553. minRows: 4,
  18554. minCols: 4,
  18555. minSpareRows: 4,
  18556. minSpareCols: 4,
  18557. cells: function cells() {
  18558. return {
  18559. renderer: greenCell
  18560. };
  18561. }
  18562. });
  18563. var $tds = this.$container.find('.htCore tbody td');
  18564. $tds.each(function () {
  18565. expect(this.style.backgroundColor).toEqual('green');
  18566. });
  18567. });
  18568. it('render should update border dimensions', function () {
  18569. var data = [['a', 'b'], ['c', 'd']];
  18570. handsontable({
  18571. data: data,
  18572. minRows: 4,
  18573. minCols: 4,
  18574. minSpareRows: 4,
  18575. minSpareCols: 4
  18576. });
  18577. selectCell(1, 1);
  18578. data[1][1] = 'dddddddddddddddddddd';
  18579. render();
  18580. var $td = this.$container.find('.htCore tbody tr:eq(1) td:eq(1)');
  18581. expect(this.$container.find('.wtBorder.current').width()).toBeGreaterThan($td.width());
  18582. });
  18583. it('should not render table twice', function () {
  18584. var counter = 0;
  18585. handsontable({
  18586. data: [['Joe Red']],
  18587. afterRender: function afterRender() {
  18588. counter++;
  18589. }
  18590. });
  18591. populateFromArray(0, 0, [['t', 'e', 's', 't']]);
  18592. expect(counter).toEqual(2); // 1 from load and 1 from populateFromArray
  18593. });
  18594. it('should run afterRenderer hook', function () {
  18595. var lastCellProperties;
  18596. handsontable({
  18597. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  18598. afterRenderer: function afterRenderer(td, row, col, prop, value, cellProperties) {
  18599. td.innerHTML = 'Changed by plugin';
  18600. if (!cellProperties) {
  18601. throw new Error();
  18602. }
  18603. lastCellProperties = cellProperties;
  18604. }
  18605. });
  18606. expect(this.$container.find('td:eq(0)')[0].innerHTML).toEqual('Changed by plugin');
  18607. expect(lastCellProperties.row).toEqual(1);
  18608. expect(lastCellProperties.col).toEqual(4);
  18609. });
  18610. it('should run beforeRenderer hook', function () {
  18611. var lastCellProperties;
  18612. handsontable({
  18613. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  18614. beforeRenderer: function beforeRenderer(td, row, col, prop, value, cellProperties) {
  18615. td.innerHTML = 'Changed by plugin';
  18616. lastCellProperties = cellProperties;
  18617. }
  18618. });
  18619. // Value is overwritten by text renderer
  18620. expect(this.$container.find('td:eq(0)')[0].innerHTML).toEqual('1');
  18621. expect(lastCellProperties.row).toEqual(1);
  18622. expect(lastCellProperties.col).toEqual(4);
  18623. });
  18624. it('should reflect changes applied in beforeRenderer into afterRenderer', function () {
  18625. var afterRenderer = jasmine.createSpy();
  18626. handsontable({
  18627. data: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
  18628. beforeRenderer: function beforeRenderer(td, row, col, prop, value, cellProperties) {
  18629. cellProperties.foo = 'bar';
  18630. },
  18631. afterRenderer: afterRenderer
  18632. });
  18633. expect(afterRenderer.calls.count()).toBe(10);
  18634. expect(afterRenderer.calls.argsFor(0)[0] instanceof HTMLTableCellElement).toBe(true);
  18635. expect(afterRenderer.calls.argsFor(0)[1]).toBe(0);
  18636. expect(afterRenderer.calls.argsFor(0)[2]).toBe(0);
  18637. expect(afterRenderer.calls.argsFor(0)[3]).toBe(0);
  18638. expect(afterRenderer.calls.argsFor(0)[4]).toBe(1);
  18639. expect(afterRenderer.calls.argsFor(0)[5].foo).toBe('bar');
  18640. });
  18641. });
  18642. /***/ }),
  18643. /* 176 */
  18644. /***/ (function(module, exports, __webpack_require__) {
  18645. "use strict";
  18646. describe('Core_selection', function () {
  18647. var id = 'testContainer';
  18648. beforeEach(function () {
  18649. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  18650. });
  18651. afterEach(function () {
  18652. if (this.$container) {
  18653. destroy();
  18654. this.$container.remove();
  18655. }
  18656. });
  18657. it('should call onSelection callback', function () {
  18658. var output = null;
  18659. handsontable({
  18660. afterSelection: function afterSelection(r, c) {
  18661. output = [r, c];
  18662. }
  18663. });
  18664. selectCell(1, 2);
  18665. expect(output[0]).toEqual(1);
  18666. expect(output[1]).toEqual(2);
  18667. });
  18668. it('should trigger selection event', function () {
  18669. var output = null;
  18670. handsontable();
  18671. Handsontable.hooks.add('afterSelection', function (r, c) {
  18672. output = [r, c];
  18673. });
  18674. selectCell(1, 2);
  18675. expect(output[0]).toEqual(1);
  18676. expect(output[1]).toEqual(2);
  18677. });
  18678. it('this.rootElement should point to handsontable rootElement (onSelection)', function () {
  18679. var output = null;
  18680. handsontable({
  18681. afterSelection: function afterSelection() {
  18682. output = this.rootElement;
  18683. }
  18684. });
  18685. selectCell(0, 0);
  18686. expect(output).toEqual(this.$container[0]);
  18687. });
  18688. it('this.rootElement should point to handsontable rootElement (onSelectionByProp)', function () {
  18689. var output = null;
  18690. handsontable({
  18691. afterSelectionByProp: function afterSelectionByProp() {
  18692. output = this.rootElement;
  18693. }
  18694. });
  18695. selectCell(0, 0);
  18696. expect(output).toEqual(this.$container[0]);
  18697. });
  18698. it('should focus external textarea when clicked during editing', function () {
  18699. var textarea = $('<input type="text">').prependTo($('body'));
  18700. handsontable();
  18701. selectCell(0, 0);
  18702. keyDown('enter');
  18703. // $("html").triggerHandler('mouseup');
  18704. $('html').simulate('mouseup');
  18705. textarea.focus();
  18706. expect(document.activeElement).toBe(textarea[0]);
  18707. textarea.remove();
  18708. });
  18709. it('should deselect currently selected cell', function () {
  18710. handsontable();
  18711. selectCell(0, 0);
  18712. $('html').simulate('mousedown');
  18713. expect(getSelected()).toBeUndefined();
  18714. });
  18715. it('should not deselect the currently selected cell after clicking on a scrollbar', function () {
  18716. var hot = handsontable({
  18717. outsideClickDeselects: false,
  18718. minRows: 20,
  18719. minCols: 2,
  18720. width: 400,
  18721. height: 100
  18722. });
  18723. selectCell(0, 0);
  18724. var holderBoundingBox = hot.view.wt.wtTable.holder.getBoundingClientRect(),
  18725. verticalScrollbarCoords = {
  18726. x: holderBoundingBox.left + holderBoundingBox.width - 3,
  18727. y: holderBoundingBox.top + holderBoundingBox.height / 2
  18728. },
  18729. horizontalScrollbarCoords = {
  18730. x: holderBoundingBox.left + holderBoundingBox.width / 2,
  18731. y: holderBoundingBox.top + holderBoundingBox.height - 3
  18732. };
  18733. $(hot.view.wt.wtTable.holder).simulate('mousedown', {
  18734. clientX: verticalScrollbarCoords.x,
  18735. clientY: verticalScrollbarCoords.y
  18736. });
  18737. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18738. $(hot.view.wt.wtTable.holder).simulate('mousedown', {
  18739. clientX: horizontalScrollbarCoords.x,
  18740. clientY: horizontalScrollbarCoords.y
  18741. });
  18742. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18743. });
  18744. it('should not deselect currently selected cell', function () {
  18745. handsontable({
  18746. outsideClickDeselects: false
  18747. });
  18748. selectCell(0, 0);
  18749. $('html').simulate('mousedown');
  18750. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18751. });
  18752. it('should allow to focus on external input and hold current selection informations', function () {
  18753. var textarea = $('<input id="test_textarea" type="text">').prependTo($('body'));
  18754. handsontable({
  18755. outsideClickDeselects: false
  18756. });
  18757. selectCell(0, 0);
  18758. textarea.simulate('mousedown');
  18759. textarea.focus();
  18760. expect(document.activeElement.id).toEqual('test_textarea');
  18761. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18762. textarea.remove();
  18763. });
  18764. it('should allow to type in external input while holding current selection information', function () {
  18765. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  18766. var keyPressed;
  18767. handsontable({
  18768. outsideClickDeselects: false
  18769. });
  18770. selectCell(0, 0);
  18771. textarea.focus();
  18772. textarea.simulate('mousedown');
  18773. textarea.simulate('mouseup');
  18774. textarea.on('keydown', function (event) {
  18775. keyPressed = event.keyCode;
  18776. });
  18777. var LETTER_A_KEY = 97;
  18778. $(document.activeElement).simulate('keydown', {
  18779. keyCode: LETTER_A_KEY
  18780. });
  18781. // textarea should receive the event and be an active element
  18782. expect(keyPressed).toEqual(LETTER_A_KEY);
  18783. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  18784. // should preserve selection, close editor and save changes
  18785. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18786. expect(getDataAtCell(0, 0)).toBeNull();
  18787. textarea.remove();
  18788. });
  18789. it('should allow to type in external input after opening cell editor', function () {
  18790. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  18791. var keyPressed;
  18792. handsontable({
  18793. outsideClickDeselects: false
  18794. });
  18795. selectCell(0, 0);
  18796. keyDown('enter');
  18797. document.activeElement.value = 'Foo';
  18798. textarea.focus();
  18799. textarea.simulate('mousedown');
  18800. textarea.simulate('mouseup');
  18801. textarea.on('keydown', function (event) {
  18802. keyPressed = event.keyCode;
  18803. });
  18804. var LETTER_A_KEY = 97;
  18805. $(document.activeElement).simulate('keydown', {
  18806. keyCode: LETTER_A_KEY
  18807. });
  18808. // textarea should receive the event and be an active element
  18809. expect(keyPressed).toEqual(LETTER_A_KEY);
  18810. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  18811. // should preserve selection, close editor and save changes
  18812. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18813. expect(getDataAtCell(0, 0)).toEqual('Foo');
  18814. textarea.remove();
  18815. });
  18816. it('should deselect on outside click if outsideClickDeselects is a function that returns true', function () {
  18817. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  18818. var keyPressed;
  18819. handsontable({
  18820. outsideClickDeselects: function outsideClickDeselects() {
  18821. return true;
  18822. }
  18823. });
  18824. selectCell(0, 0);
  18825. keyDown('enter');
  18826. document.activeElement.value = 'Foo';
  18827. textarea.focus();
  18828. textarea.simulate('mousedown');
  18829. textarea.simulate('mouseup');
  18830. textarea.on('keydown', function (event) {
  18831. keyPressed = event.keyCode;
  18832. });
  18833. var LETTER_A_KEY = 97;
  18834. $(document.activeElement).simulate('keydown', {
  18835. keyCode: LETTER_A_KEY
  18836. });
  18837. // textarea should receive the event and be an active element
  18838. expect(keyPressed).toEqual(LETTER_A_KEY);
  18839. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  18840. // should NOT preserve selection
  18841. expect(getSelected()).toEqual(undefined);
  18842. expect(getDataAtCell(0, 0)).toEqual('Foo');
  18843. textarea.remove();
  18844. });
  18845. it('should not deselect on outside click if outsideClickDeselects is a function that returns false', function () {
  18846. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  18847. var keyPressed;
  18848. handsontable({
  18849. outsideClickDeselects: function outsideClickDeselects() {
  18850. return false;
  18851. }
  18852. });
  18853. selectCell(0, 0);
  18854. keyDown('enter');
  18855. document.activeElement.value = 'Foo';
  18856. textarea.focus();
  18857. textarea.simulate('mousedown');
  18858. textarea.simulate('mouseup');
  18859. textarea.on('keydown', function (event) {
  18860. keyPressed = event.keyCode;
  18861. });
  18862. var LETTER_A_KEY = 97;
  18863. $(document.activeElement).simulate('keydown', {
  18864. keyCode: LETTER_A_KEY
  18865. });
  18866. // textarea should receive the event and be an active element
  18867. expect(keyPressed).toEqual(LETTER_A_KEY);
  18868. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  18869. // should preserve selection, close editor and save changes
  18870. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18871. expect(getDataAtCell(0, 0)).toEqual('Foo');
  18872. textarea.remove();
  18873. });
  18874. it('should fix start range if provided is out of bounds (to the left)', function () {
  18875. handsontable({
  18876. startRows: 5,
  18877. startCols: 5
  18878. });
  18879. selectCell(0, 0);
  18880. keyDownUp('arrow_left');
  18881. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18882. });
  18883. it('should fix start range if provided is out of bounds (to the top)', function () {
  18884. handsontable({
  18885. startRows: 5,
  18886. startCols: 5
  18887. });
  18888. selectCell(0, 0);
  18889. keyDownUp('arrow_up');
  18890. expect(getSelected()).toEqual([0, 0, 0, 0]);
  18891. });
  18892. it('should fix start range if provided is out of bounds (to the right)', function () {
  18893. handsontable({
  18894. startRows: 5,
  18895. startCols: 5
  18896. });
  18897. selectCell(0, 4);
  18898. keyDownUp('arrow_right');
  18899. expect(getSelected()).toEqual([0, 4, 0, 4]);
  18900. });
  18901. it('should fix start range if provided is out of bounds (to the bottom)', function () {
  18902. handsontable({
  18903. startRows: 5,
  18904. startCols: 5
  18905. });
  18906. selectCell(4, 0);
  18907. keyDownUp('arrow_down');
  18908. expect(getSelected()).toEqual([4, 0, 4, 0]);
  18909. });
  18910. it('should fix end range if provided is out of bounds (to the left)', function () {
  18911. handsontable({
  18912. startRows: 5,
  18913. startCols: 5
  18914. });
  18915. selectCell(0, 1);
  18916. keyDownUp('shift+arrow_left');
  18917. keyDownUp('shift+arrow_left');
  18918. expect(getSelected()).toEqual([0, 1, 0, 0]);
  18919. });
  18920. it('should fix end range if provided is out of bounds (to the top)', function () {
  18921. handsontable({
  18922. startRows: 5,
  18923. startCols: 5
  18924. });
  18925. selectCell(1, 0);
  18926. keyDownUp('shift+arrow_up');
  18927. keyDownUp('shift+arrow_up');
  18928. expect(getSelected()).toEqual([1, 0, 0, 0]);
  18929. });
  18930. it('should fix end range if provided is out of bounds (to the right)', function () {
  18931. handsontable({
  18932. startRows: 5,
  18933. startCols: 5
  18934. });
  18935. selectCell(0, 3);
  18936. keyDownUp('shift+arrow_right');
  18937. keyDownUp('shift+arrow_right');
  18938. expect(getSelected()).toEqual([0, 3, 0, 4]);
  18939. });
  18940. it('should fix end range if provided is out of bounds (to the bottom)', function () {
  18941. handsontable({
  18942. startRows: 5,
  18943. startCols: 5
  18944. });
  18945. selectCell(3, 0);
  18946. keyDownUp('shift+arrow_down');
  18947. keyDownUp('shift+arrow_down');
  18948. keyDownUp('shift+arrow_down');
  18949. expect(getSelected()).toEqual([3, 0, 4, 0]);
  18950. });
  18951. it('should select multiple cells', function () {
  18952. handsontable({
  18953. startRows: 5,
  18954. startCols: 5
  18955. });
  18956. selectCell(3, 0, 4, 1);
  18957. expect(getSelected()).toEqual([3, 0, 4, 1]);
  18958. });
  18959. it('should call onSelectionEnd as many times as onSelection when `selectCell` is called', function () {
  18960. var tick = 0,
  18961. tickEnd = 0;
  18962. handsontable({
  18963. startRows: 5,
  18964. startCols: 5,
  18965. afterSelection: function afterSelection() {
  18966. tick++;
  18967. },
  18968. afterSelectionEnd: function afterSelectionEnd() {
  18969. tickEnd++;
  18970. }
  18971. });
  18972. selectCell(3, 0);
  18973. selectCell(1, 1);
  18974. expect(tick).toEqual(2);
  18975. expect(tickEnd).toEqual(2);
  18976. });
  18977. it('should call onSelectionEnd when user finishes selection by releasing SHIFT key (3 times)', function () {
  18978. var tick = 0;
  18979. handsontable({
  18980. startRows: 5,
  18981. startCols: 5,
  18982. afterSelectionEnd: function afterSelectionEnd() {
  18983. tick++;
  18984. }
  18985. });
  18986. selectCell(3, 0); // makes tick++
  18987. keyDownUp('shift+arrow_down'); // makes tick++
  18988. keyDownUp('shift+arrow_down'); // makes tick++
  18989. keyDownUp('shift+arrow_down'); // makes tick++
  18990. expect(getSelected()).toEqual([3, 0, 4, 0]);
  18991. expect(tick).toEqual(4);
  18992. });
  18993. it('should call onSelectionEnd when user finishes selection by releasing SHIFT key (1 time)', function () {
  18994. var tick = 0;
  18995. handsontable({
  18996. startRows: 5,
  18997. startCols: 5,
  18998. afterSelectionEnd: function afterSelectionEnd() {
  18999. tick++;
  19000. }
  19001. });
  19002. selectCell(3, 0); // makes tick++
  19003. keyDown('shift+arrow_down');
  19004. keyDown('shift+arrow_down');
  19005. keyDownUp('shift+arrow_down'); // makes tick++
  19006. expect(getSelected()).toEqual([3, 0, 4, 0]);
  19007. expect(tick).toEqual(2);
  19008. });
  19009. it('should select columns by click on header with SHIFT key', function () {
  19010. handsontable({
  19011. startRows: 5,
  19012. startCols: 5,
  19013. colHeaders: true
  19014. });
  19015. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mousedown');
  19016. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mouseup');
  19017. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mousedown', { shiftKey: true });
  19018. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mouseup');
  19019. expect(getSelected()).toEqual([0, 1, 4, 4]);
  19020. });
  19021. it('should select rows by click on header with SHIFT key', function () {
  19022. handsontable({
  19023. startRows: 5,
  19024. startCols: 5,
  19025. rowHeaders: true
  19026. });
  19027. this.$container.find('.ht_clone_left tr:eq(1) th:eq(0)').simulate('mousedown');
  19028. this.$container.find('.ht_clone_left tr:eq(1) th:eq(0)').simulate('mouseup');
  19029. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mousedown', { shiftKey: true });
  19030. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mouseup');
  19031. expect(getSelected()).toEqual([1, 0, 4, 4]);
  19032. });
  19033. it('should select columns by click on header with SHIFT key', function () {
  19034. handsontable({
  19035. startRows: 5,
  19036. startCols: 5,
  19037. colHeaders: true
  19038. });
  19039. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mousedown');
  19040. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mouseup');
  19041. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mousedown', { shiftKey: true });
  19042. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mouseup');
  19043. expect(getSelected()).toEqual([0, 1, 4, 4]);
  19044. });
  19045. it('should change selection after click on row header with SHIFT key', function () {
  19046. handsontable({
  19047. startRows: 5,
  19048. startCols: 5,
  19049. rowHeaders: true
  19050. });
  19051. selectCell(1, 1, 3, 3);
  19052. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mousedown', { shiftKey: true });
  19053. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mouseup');
  19054. expect(getSelected()).toEqual([1, 0, 4, 4]);
  19055. });
  19056. it('should change selection after click on column header with SHIFT key', function () {
  19057. handsontable({
  19058. startRows: 5,
  19059. startCols: 5,
  19060. colHeaders: true
  19061. });
  19062. selectCell(1, 1, 3, 3);
  19063. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mousedown', { shiftKey: true });
  19064. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mouseup');
  19065. expect(getSelected()).toEqual([0, 1, 4, 4]);
  19066. });
  19067. it('should call onSelection while user selects cells with mouse; onSelectionEnd when user finishes selection', function () {
  19068. var tick = 0,
  19069. tickEnd = 0;
  19070. handsontable({
  19071. startRows: 5,
  19072. startCols: 5,
  19073. afterSelection: function afterSelection() {
  19074. tick++;
  19075. },
  19076. afterSelectionEnd: function afterSelectionEnd() {
  19077. tickEnd++;
  19078. }
  19079. });
  19080. this.$container.find('tr:eq(0) td:eq(0)').simulate('mousedown');
  19081. this.$container.find('tr:eq(0) td:eq(1)').simulate('mouseover');
  19082. this.$container.find('tr:eq(1) td:eq(3)').simulate('mouseover');
  19083. this.$container.find('tr:eq(1) td:eq(3)').simulate('mouseup');
  19084. expect(getSelected()).toEqual([0, 0, 1, 3]);
  19085. expect(tick).toEqual(3);
  19086. expect(tickEnd).toEqual(1);
  19087. });
  19088. it('should properly select columns, when the user moves the cursor over column headers across two overlays', function () {
  19089. handsontable({
  19090. startRows: 5,
  19091. startCols: 5,
  19092. colHeaders: true,
  19093. fixedColumnsLeft: 2
  19094. });
  19095. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mousedown');
  19096. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mouseover');
  19097. this.$container.find('.ht_clone_top tr:eq(0) th:eq(2)').simulate('mouseover');
  19098. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mouseover');
  19099. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mouseup');
  19100. expect(getSelected()).toEqual([0, 1, 4, 1]);
  19101. });
  19102. it('should move focus to selected cell', function () {
  19103. var $input = $('<input>').appendTo(document.body);
  19104. handsontable({
  19105. startRows: 5,
  19106. startCols: 5
  19107. });
  19108. $input[0].focus();
  19109. selectCell(0, 0);
  19110. keyDownUp('enter');
  19111. expect(isEditorVisible()).toEqual(true);
  19112. $input.remove();
  19113. });
  19114. // This test should cover the #893 case, but it always passes. It seems like the keydown event (with CTRL key pressed) isn't delivered.
  19115. it('should not move focus from outside elements on CTRL keydown event, when no cell is selected', function () {
  19116. var $input = $('<input type="text"/>');
  19117. $('body').append($input);
  19118. handsontable();
  19119. selectCell(0, 0);
  19120. expect(document.activeElement.nodeName).toBeInArray(['BODY', 'HTML']);
  19121. $input.focus();
  19122. expect(document.activeElement.nodeName).toBe('INPUT');
  19123. // var keyDownEvent = $.Event('keydown', {ctrlKey: true, metaKey: true});
  19124. // $input.trigger(keyDownEvent);
  19125. $input.simulate('keydown', { ctrlKey: true, metaKey: true });
  19126. expect(document.activeElement.nodeName).toBe('INPUT');
  19127. $input.remove();
  19128. });
  19129. it('should select the entire column after column header is clicked', function () {
  19130. var hot = handsontable({
  19131. width: 200,
  19132. height: 100,
  19133. startRows: 50,
  19134. startCols: 5,
  19135. colHeaders: true
  19136. });
  19137. this.$container.find('thead th:eq(0)').simulate('mousedown');
  19138. expect(getSelected()).toEqual([0, 0, 49, 0]);
  19139. expect(hot.selection.selectedHeader.rows).toBe(false);
  19140. expect(hot.selection.selectedHeader.cols).toBe(true);
  19141. expect(hot.selection.selectedHeader.corner).toBe(false);
  19142. });
  19143. it('should add classname after select column', function () {
  19144. var hot = handsontable({
  19145. width: 200,
  19146. height: 100,
  19147. startRows: 50,
  19148. startCols: 5,
  19149. colHeaders: true
  19150. });
  19151. this.$container.find('thead th:eq(0)').simulate('mousedown');
  19152. expect(this.$container.hasClass('ht__selection--columns')).toBeTruthy();
  19153. });
  19154. it('should select the entire column after column header is clicked (in fixed rows/cols corner)', function () {
  19155. var hot = handsontable({
  19156. width: 200,
  19157. height: 100,
  19158. startRows: 50,
  19159. startCols: 5,
  19160. colHeaders: true,
  19161. rowHeaders: true,
  19162. fixedRowsTop: 2,
  19163. fixedColumnsLeft: 2
  19164. });
  19165. this.$container.find('.ht_master thead th:eq(1)').simulate('mousedown');
  19166. expect(getSelected()).toEqual([0, 0, 49, 0]);
  19167. expect(hot.selection.selectedHeader.rows).toBe(false);
  19168. expect(hot.selection.selectedHeader.cols).toBe(true);
  19169. expect(hot.selection.selectedHeader.corner).toBe(false);
  19170. });
  19171. it('should select the entire fixed column after column header is clicked, after scroll horizontally', function () {
  19172. var hot = handsontable({
  19173. width: 200,
  19174. height: 100,
  19175. startRows: 50,
  19176. startCols: 50,
  19177. colHeaders: true,
  19178. rowHeaders: true,
  19179. fixedColumnsLeft: 2
  19180. });
  19181. hot.render();
  19182. hot.view.wt.scrollHorizontal(20);
  19183. this.$container.find('.ht_master thead th:eq(2)').simulate('mousedown');
  19184. this.$container.find('.ht_master thead th:eq(2)').simulate('mouseup');
  19185. expect(getSelected()).toEqual([0, 1, 49, 1]);
  19186. expect(hot.selection.selectedHeader.rows).toBe(false);
  19187. expect(hot.selection.selectedHeader.cols).toBe(true);
  19188. expect(hot.selection.selectedHeader.corner).toBe(false);
  19189. });
  19190. it('should set the selection end to the first visible row, when dragging the selection from a cell to a column header', function (done) {
  19191. var hot = handsontable({
  19192. width: 200,
  19193. height: 200,
  19194. startRows: 20,
  19195. startCols: 20,
  19196. colHeaders: true,
  19197. rowHeaders: true
  19198. });
  19199. hot.view.wt.scrollVertical(10);
  19200. hot.view.wt.scrollHorizontal(10);
  19201. hot.render();
  19202. setTimeout(function () {
  19203. $(getCell(12, 11)).simulate('mousedown');
  19204. spec().$container.find('.ht_clone_top thead th:eq(2)').simulate('mouseover');
  19205. }, 30);
  19206. setTimeout(function () {
  19207. expect(getSelected()).toEqual([12, 11, 10, 11]);
  19208. done();
  19209. }, 60);
  19210. });
  19211. it('should set the selection end to the first visible column, when dragging the selection from a cell to a row header', function (done) {
  19212. var hot = handsontable({
  19213. width: 200,
  19214. height: 200,
  19215. startRows: 20,
  19216. startCols: 20,
  19217. colHeaders: true,
  19218. rowHeaders: true
  19219. });
  19220. hot.view.wt.scrollVertical(10);
  19221. hot.view.wt.scrollHorizontal(10);
  19222. hot.render();
  19223. setTimeout(function () {
  19224. $(getCell(12, 11)).simulate('mousedown');
  19225. spec().$container.find('.ht_clone_left tbody th:eq(12)').simulate('mouseover');
  19226. }, 30);
  19227. setTimeout(function () {
  19228. expect(getSelected()).toEqual([12, 11, 12, 10]);
  19229. done();
  19230. }, 60);
  19231. });
  19232. it('should allow to scroll the table when a whole column is selected and table is longer than it\'s container', function (done) {
  19233. var errCount = 0;
  19234. $(window).on('error.selectionTest', function () {
  19235. errCount++;
  19236. });
  19237. var onAfterScrollVertically = jasmine.createSpy('onAfterScrollVertically');
  19238. var hot = handsontable({
  19239. height: 100,
  19240. width: 300,
  19241. startRows: 100,
  19242. startCols: 5,
  19243. colHeaders: true,
  19244. rowHeaders: true,
  19245. afterScrollVertically: onAfterScrollVertically
  19246. });
  19247. var mainHolder = hot.view.wt.wtTable.holder;
  19248. mainHolder.scrollTop = 0;
  19249. this.$container.find('thead tr:eq(0) th:eq(2)').simulate('mousedown');
  19250. this.$container.find('thead tr:eq(0) th:eq(2)').simulate('mouseup');
  19251. mainHolder.scrollTop = 120;
  19252. setTimeout(function () {
  19253. expect(errCount).toEqual(0); // expect no errors to be thrown
  19254. $(window).off('error.selectionTest');
  19255. done();
  19256. }, 100);
  19257. });
  19258. it('should scroll to the end of the selection, when selecting cells using the keyboard', function () {
  19259. var hot = handsontable({
  19260. height: 300,
  19261. width: 300,
  19262. startRows: 50,
  19263. startCols: 50,
  19264. colHeaders: true,
  19265. rowHeaders: true,
  19266. fixedRowsTop: 2,
  19267. fixedColumnsLeft: 2
  19268. });
  19269. var mainHolder = hot.view.wt.wtTable.holder;
  19270. mainHolder.scrollTop = 100;
  19271. selectCell(1, 3);
  19272. keyDownUp('arrow_down');
  19273. expect(mainHolder.scrollTop).toEqual(0);
  19274. mainHolder.scrollTop = 100;
  19275. selectCell(1, 3);
  19276. keyDownUp('shift+arrow_down');
  19277. expect(mainHolder.scrollTop).toEqual(0);
  19278. mainHolder.scrollLeft = 100;
  19279. selectCell(3, 1);
  19280. keyDownUp('arrow_right');
  19281. expect(mainHolder.scrollLeft).toEqual(0);
  19282. mainHolder.scrollLeft = 100;
  19283. selectCell(3, 1);
  19284. keyDownUp('shift+arrow_right');
  19285. expect(mainHolder.scrollLeft).toEqual(0);
  19286. var lastVisibleColumn = hot.view.wt.wtTable.getLastVisibleColumn();
  19287. selectCell(3, lastVisibleColumn);
  19288. keyDownUp('arrow_right');
  19289. expect(hot.view.wt.wtTable.getLastVisibleColumn()).toEqual(lastVisibleColumn + 1);
  19290. keyDownUp('arrow_right');
  19291. expect(hot.view.wt.wtTable.getLastVisibleColumn()).toEqual(lastVisibleColumn + 2);
  19292. keyDownUp('shift+arrow_right');
  19293. expect(hot.view.wt.wtTable.getLastVisibleColumn()).toEqual(lastVisibleColumn + 3);
  19294. var lastVisibleRow = hot.view.wt.wtTable.getLastVisibleRow();
  19295. selectCell(lastVisibleRow, 3);
  19296. keyDownUp('arrow_down');
  19297. expect(hot.view.wt.wtTable.getLastVisibleRow()).toEqual(lastVisibleRow + 1);
  19298. keyDownUp('arrow_down');
  19299. expect(hot.view.wt.wtTable.getLastVisibleRow()).toEqual(lastVisibleRow + 2);
  19300. keyDownUp('shift+arrow_down');
  19301. expect(hot.view.wt.wtTable.getLastVisibleRow()).toEqual(lastVisibleRow + 3);
  19302. });
  19303. it('should select the entire row after row header is clicked', function () {
  19304. var hot = handsontable({
  19305. startRows: 5,
  19306. startCols: 5,
  19307. colHeaders: true,
  19308. rowHeaders: true
  19309. });
  19310. this.$container.find('tr:eq(2) th:eq(0)').simulate('mousedown');
  19311. expect(getSelected()).toEqual([1, 0, 1, 4]);
  19312. expect(hot.selection.selectedHeader.rows).toBe(true);
  19313. expect(hot.selection.selectedHeader.cols).toBe(false);
  19314. expect(hot.selection.selectedHeader.corner).toBe(false);
  19315. });
  19316. it('should add classname after select row', function () {
  19317. var hot = handsontable({
  19318. width: 200,
  19319. height: 100,
  19320. startRows: 50,
  19321. startCols: 5,
  19322. rowHeaders: true
  19323. });
  19324. this.$container.find('tbody tr:eq(0) th:eq(0)').simulate('mousedown');
  19325. expect(this.$container.hasClass('ht__selection--rows')).toBeTruthy();
  19326. });
  19327. it('should select the entire row of a partially fixed table after row header is clicked', function () {
  19328. handsontable({
  19329. startRows: 5,
  19330. startCols: 5,
  19331. colHeaders: true,
  19332. rowHeaders: true,
  19333. fixedRowsTop: 2,
  19334. fixedColumnsLeft: 2
  19335. });
  19336. this.$container.find('tr:eq(2) th:eq(0)').simulate('mousedown');
  19337. expect(getSelected()).toEqual([1, 0, 1, 4]);
  19338. this.$container.find('tr:eq(3) th:eq(0)').simulate('mousedown');
  19339. expect(getSelected()).toEqual([2, 0, 2, 4]);
  19340. });
  19341. it('should select a cell in a newly added row after automatic row adding, triggered by editing a cell in the last row with minSpareRows > 0, ' + 'unless editing happened within the fixed bottom rows', function (done) {
  19342. var hot = handsontable({
  19343. startRows: 5,
  19344. startCols: 2,
  19345. minSpareRows: 1
  19346. });
  19347. setTimeout(function () {
  19348. selectCell(4, 0);
  19349. keyDownUp('enter');
  19350. }, 10);
  19351. setTimeout(function () {
  19352. keyDownUp('enter');
  19353. }, 100);
  19354. setTimeout(function () {
  19355. expect(countRows()).toEqual(6);
  19356. expect(getSelected()).toEqual([5, 0, 5, 0]);
  19357. }, 200);
  19358. setTimeout(function () {
  19359. done();
  19360. }, 250);
  19361. });
  19362. it('should change selected coords by modifying coords object via `modifyTransformStart` hook', function () {
  19363. var hot = handsontable({
  19364. startRows: 5,
  19365. startCols: 5
  19366. });
  19367. selectCell(0, 0);
  19368. hot.addHook('modifyTransformStart', function (coords) {
  19369. coords.col += 1;
  19370. coords.row += 1;
  19371. });
  19372. keyDown('arrow_down');
  19373. expect(getSelected()).toEqual([2, 1, 2, 1]);
  19374. });
  19375. it('should change selected coords by modifying coords object via `modifyTransformEnd` hook', function () {
  19376. var hot = handsontable({
  19377. startRows: 5,
  19378. startCols: 5
  19379. });
  19380. selectCell(0, 0);
  19381. hot.addHook('modifyTransformEnd', function (coords) {
  19382. coords.col += 2;
  19383. coords.row += 1;
  19384. });
  19385. keyDown('shift+arrow_down');
  19386. expect(getSelected()).toEqual([0, 0, 2, 2]);
  19387. });
  19388. it('should indicate is coords is out of bounds via `afterModifyTransformStart` hook', function () {
  19389. var spy = jasmine.createSpy();
  19390. var hot = handsontable({
  19391. startRows: 5,
  19392. startCols: 5
  19393. });
  19394. hot.addHook('afterModifyTransformStart', spy);
  19395. selectCell(2, 0);
  19396. keyDownUp('arrow_left');
  19397. expect(spy.calls.mostRecent().args[1]).toBe(0);
  19398. expect(spy.calls.mostRecent().args[2]).toBe(-1);
  19399. spy.calls.reset();
  19400. selectCell(2, 4);
  19401. keyDownUp('arrow_right');
  19402. expect(spy.calls.mostRecent().args[1]).toBe(0);
  19403. expect(spy.calls.mostRecent().args[2]).toBe(1);
  19404. spy.calls.reset();
  19405. selectCell(4, 2);
  19406. keyDownUp('arrow_down');
  19407. expect(spy.calls.mostRecent().args[1]).toBe(1);
  19408. expect(spy.calls.mostRecent().args[2]).toBe(0);
  19409. spy.calls.reset();
  19410. selectCell(0, 2);
  19411. keyDownUp('arrow_up');
  19412. expect(spy.calls.mostRecent().args[1]).toBe(-1);
  19413. expect(spy.calls.mostRecent().args[2]).toBe(0);
  19414. });
  19415. it('should indicate is coords is out of bounds via `afterModifyTransformEnd` hook', function () {
  19416. var spy = jasmine.createSpy();
  19417. var hot = handsontable({
  19418. startRows: 5,
  19419. startCols: 5
  19420. });
  19421. hot.addHook('afterModifyTransformEnd', spy);
  19422. selectCell(2, 0);
  19423. keyDownUp('shift+arrow_left');
  19424. expect(spy.calls.mostRecent().args[1]).toBe(0);
  19425. expect(spy.calls.mostRecent().args[2]).toBe(-1);
  19426. spy.calls.reset();
  19427. selectCell(2, 4);
  19428. keyDownUp('shift+arrow_right');
  19429. expect(spy.calls.mostRecent().args[1]).toBe(0);
  19430. expect(spy.calls.mostRecent().args[2]).toBe(1);
  19431. spy.calls.reset();
  19432. selectCell(4, 2);
  19433. keyDownUp('shift+arrow_down');
  19434. expect(spy.calls.mostRecent().args[1]).toBe(1);
  19435. expect(spy.calls.mostRecent().args[2]).toBe(0);
  19436. spy.calls.reset();
  19437. selectCell(0, 2);
  19438. keyDownUp('shift+arrow_up');
  19439. expect(spy.calls.mostRecent().args[1]).toBe(-1);
  19440. expect(spy.calls.mostRecent().args[2]).toBe(0);
  19441. });
  19442. it('should change selection after left mouse button on one of selected cell', function () {
  19443. var hot = handsontable({
  19444. startRows: 5,
  19445. startCols: 5
  19446. });
  19447. var cells = $('.ht_master.handsontable td');
  19448. cells.eq(6).simulate('mousedown');
  19449. cells.eq(18).simulate('mouseover');
  19450. cells.eq(18).simulate('mouseup');
  19451. expect(hot.getSelected()).toEqual([1, 1, 3, 3]);
  19452. cells.eq(16).simulate('mousedown');
  19453. cells.eq(16).simulate('mouseup');
  19454. expect(hot.getSelected()).toEqual([3, 1, 3, 1]);
  19455. });
  19456. it('should select the first row after corner header is clicked', function () {
  19457. var hot = handsontable({
  19458. startRows: 5,
  19459. startCols: 5,
  19460. colHeaders: true,
  19461. rowHeaders: true
  19462. });
  19463. this.$container.find('thead').find('th').eq(0).simulate('mousedown');
  19464. expect(getSelected()).toEqual([0, 0, 0, 0]);
  19465. expect(hot.selection.selectedHeader.rows).toBe(false);
  19466. expect(hot.selection.selectedHeader.cols).toBe(false);
  19467. expect(hot.selection.selectedHeader.corner).toBe(true);
  19468. });
  19469. it('should redraw selection when option `colHeaders` is set and user scrolled', function (done) {
  19470. var hot = handsontable({
  19471. startRows: 20,
  19472. startCols: 20,
  19473. colHeaders: true,
  19474. rowHeaders: true,
  19475. width: 400,
  19476. height: 200
  19477. });
  19478. var cellVerticalPosition;
  19479. var borderOffsetInPixels = 1;
  19480. var topBorder;
  19481. selectCell(5, 5);
  19482. hot.view.wt.wtOverlays.topOverlay.scrollTo(2);
  19483. setTimeout(function () {
  19484. cellVerticalPosition = hot.getCell(5, 5).offsetTop;
  19485. topBorder = $('.wtBorder.current')[0];
  19486. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  19487. hot.view.wt.wtOverlays.topOverlay.scrollTo(0);
  19488. }, 100);
  19489. setTimeout(function () {
  19490. cellVerticalPosition = hot.getCell(5, 5).offsetTop;
  19491. topBorder = $('.wtBorder.current')[0];
  19492. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  19493. done();
  19494. }, 200);
  19495. });
  19496. it('should redraw selection on `leftOverlay` when options `colHeaders` and `fixedColumnsLeft` are set, and user scrolled', function (done) {
  19497. var hot = handsontable({
  19498. fixedColumnsLeft: 2,
  19499. startRows: 20,
  19500. startCols: 20,
  19501. colHeaders: true,
  19502. rowHeaders: true,
  19503. width: 400,
  19504. height: 200
  19505. });
  19506. var cellVerticalPosition;
  19507. var borderOffsetInPixels = 1;
  19508. var topBorder;
  19509. selectCell(1, 0);
  19510. hot.view.wt.wtOverlays.topOverlay.scrollTo(5);
  19511. setTimeout(function () {
  19512. cellVerticalPosition = hot.getCell(1, 0).offsetTop;
  19513. topBorder = $('.wtBorder.current')[0];
  19514. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  19515. hot.view.wt.wtOverlays.topOverlay.scrollTo(0);
  19516. }, 100);
  19517. setTimeout(function () {
  19518. cellVerticalPosition = hot.getCell(1, 0).offsetTop;
  19519. topBorder = $('.wtBorder.current')[0];
  19520. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  19521. done();
  19522. }, 200);
  19523. });
  19524. });
  19525. /***/ }),
  19526. /* 177 */
  19527. /***/ (function(module, exports, __webpack_require__) {
  19528. "use strict";
  19529. describe('Core_setDataAtCell', function () {
  19530. var id = 'testContainer';
  19531. beforeEach(function () {
  19532. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  19533. });
  19534. afterEach(function () {
  19535. if (this.$container) {
  19536. destroy();
  19537. this.$container.remove();
  19538. }
  19539. });
  19540. var arrayOfNestedObjects = function arrayOfNestedObjects() {
  19541. return [{ id: 1,
  19542. name: {
  19543. first: 'Ted',
  19544. last: 'Right'
  19545. } }, { id: 2,
  19546. name: {
  19547. first: 'Frank',
  19548. last: 'Honest'
  19549. } }, { id: 3,
  19550. name: {
  19551. first: 'Joan',
  19552. last: 'Well'
  19553. } }];
  19554. };
  19555. var htmlText = 'Ben & Jerry\'s';
  19556. it('HTML special chars should be preserved in data map but escaped in DOM', function () {
  19557. // https://github.com/handsontable/handsontable/issues/147
  19558. handsontable();
  19559. var td = setDataAtCell(0, 0, htmlText);
  19560. selectCell(0, 0);
  19561. $(td).simulate('dblclick');
  19562. deselectCell();
  19563. expect(getDataAtCell(0, 0)).toEqual(htmlText);
  19564. });
  19565. it('should correctly paste string that contains "quotes"', function (done) {
  19566. // https://github.com/handsontable/handsontable/issues/205
  19567. handsontable({});
  19568. selectCell(0, 0);
  19569. triggerPaste('1\nThis is a "test" and a test\n2');
  19570. setTimeout(function () {
  19571. expect(getDataAtCell(0, 0)).toEqual('1');
  19572. expect(getDataAtCell(1, 0)).toEqual('This is a "test" and a test');
  19573. expect(getDataAtCell(2, 0)).toEqual('2');
  19574. done();
  19575. }, 200);
  19576. });
  19577. it('should correctly paste string when dataSchema is used', function (done) {
  19578. // https://github.com/handsontable/handsontable/issues/237
  19579. handsontable({
  19580. colHeaders: true,
  19581. dataSchema: {
  19582. col1: null,
  19583. col2: null,
  19584. col3: null
  19585. }
  19586. });
  19587. selectCell(0, 0);
  19588. triggerPaste('1\tTest\t2');
  19589. setTimeout(function () {
  19590. expect(getDataAtCell(0, 0)).toEqual('1');
  19591. expect(getDataAtCell(0, 1)).toEqual('Test');
  19592. expect(getDataAtCell(0, 2)).toEqual('2');
  19593. done();
  19594. }, 200);
  19595. });
  19596. it('should paste not more rows than maxRows', function (done) {
  19597. handsontable({
  19598. minSpareRows: 1,
  19599. minRows: 5,
  19600. maxRows: 10
  19601. });
  19602. selectCell(4, 0);
  19603. triggerPaste('1\n2\n3\n4\n5\n6\n7\n8\n9\n10');
  19604. setTimeout(function () {
  19605. expect(countRows()).toEqual(10);
  19606. expect(getDataAtCell(9, 0)).toEqual('6');
  19607. done();
  19608. }, 200);
  19609. });
  19610. it('should paste not more cols than maxCols', function (done) {
  19611. handsontable({
  19612. minSpareCols: 1,
  19613. minCols: 5,
  19614. maxCols: 10
  19615. });
  19616. selectCell(0, 4);
  19617. triggerPaste('1\t2\t3\t4\t5\t6\t7\t8\t9\t10');
  19618. setTimeout(function () {
  19619. expect(countCols()).toEqual(10);
  19620. expect(getDataAtCell(0, 9)).toEqual('6');
  19621. done();
  19622. }, 200);
  19623. });
  19624. it('should paste not more rows & cols than maxRows & maxCols', function (done) {
  19625. handsontable({
  19626. minSpareRows: 1,
  19627. minSpareCols: 1,
  19628. minRows: 5,
  19629. minCols: 5,
  19630. maxRows: 6,
  19631. maxCols: 6
  19632. });
  19633. selectCell(4, 4);
  19634. triggerPaste('1\t2\t3\n4\t5\t6\n7\t8\t9');
  19635. setTimeout(function () {
  19636. expect(countRows()).toEqual(6);
  19637. expect(countCols()).toEqual(6);
  19638. expect(getDataAtCell(5, 5)).toEqual('5');
  19639. done();
  19640. }, 200);
  19641. });
  19642. // https://github.com/handsontable/handsontable/issues/250
  19643. it('should create new rows when pasting into grid with object data source', function (done) {
  19644. handsontable({
  19645. data: arrayOfNestedObjects(),
  19646. colHeaders: true,
  19647. columns: [{ data: 'id' }, { data: 'name.last' }, { data: 'name.first' }],
  19648. minSpareRows: 1
  19649. });
  19650. selectCell(3, 0);
  19651. triggerPaste('a\tb\tc\nd\te\tf\ng\th\ti');
  19652. setTimeout(function () {
  19653. expect(countRows()).toEqual(7);
  19654. expect(getDataAtCell(5, 2)).toEqual('i');
  19655. done();
  19656. }, 200);
  19657. });
  19658. // https://handsontable.com/demo/datasources.html
  19659. it('should work with functional data source', function () {
  19660. handsontable({
  19661. data: [model({ id: 1, name: 'Ted Right', address: '' }), model({ id: 2, name: 'Frank Honest', address: '' }), model({ id: 3, name: 'Joan Well', address: '' })],
  19662. dataSchema: model,
  19663. startRows: 5,
  19664. startCols: 3,
  19665. colHeaders: ['ID', 'Name', 'Address'],
  19666. columns: [{ data: property('id') }, { data: property('name') }, { data: property('address') }],
  19667. minSpareRows: 1
  19668. });
  19669. function model(opts) {
  19670. var _pub = {},
  19671. _priv = $.extend({
  19672. id: undefined,
  19673. name: undefined,
  19674. address: undefined
  19675. }, opts);
  19676. _pub.attr = function (attr, val) {
  19677. if (typeof val === 'undefined') {
  19678. return _priv[attr];
  19679. }
  19680. _priv[attr] = val;
  19681. return _pub;
  19682. };
  19683. return _pub;
  19684. }
  19685. function property(attr) {
  19686. return function (row, value) {
  19687. return row.attr(attr, value);
  19688. };
  19689. }
  19690. expect(getDataAtCell(1, 1)).toEqual('Frank Honest');
  19691. setDataAtCell(1, 1, 'Something Else');
  19692. expect(getDataAtCell(1, 1)).toEqual('Something Else');
  19693. });
  19694. it('should accept changes array as 1st param and source as 2nd param', function () {
  19695. var callCount = 0,
  19696. lastSource = '';
  19697. handsontable({
  19698. afterChange: function afterChange(changes, source) {
  19699. callCount++;
  19700. lastSource = source;
  19701. }
  19702. });
  19703. setDataAtCell([[0, 0, 'new value']], 'customSource');
  19704. expect(getDataAtCell(0, 0)).toEqual('new value');
  19705. expect(lastSource).toEqual('customSource');
  19706. });
  19707. it('should trigger `afterSetDataAtCell` hook with applied changes', function () {
  19708. var _changes;
  19709. var _source;
  19710. handsontable({
  19711. afterSetDataAtCell: function afterSetDataAtCell(changes, source) {
  19712. _changes = changes;
  19713. _source = source;
  19714. }
  19715. });
  19716. setDataAtCell(0, 0, 'foo bar', 'customSource');
  19717. expect(_changes).toEqual([[0, 0, null, 'foo bar']]);
  19718. expect(_source).toBe('customSource');
  19719. expect(getDataAtCell(0, 0)).toEqual('foo bar');
  19720. });
  19721. it('should modify value on the fly using `afterSetDataAtCell` hook', function () {
  19722. handsontable({
  19723. data: [['a', 'b', 'c'], [1, 2, 3]],
  19724. afterSetDataAtCell: function afterSetDataAtCell(changes, source) {
  19725. if (changes[0][3] === 'foo bar') {
  19726. changes[0][3] = 'bar';
  19727. }
  19728. if (changes[0][3] === 22) {
  19729. changes[0][3] = 33;
  19730. }
  19731. }
  19732. });
  19733. setDataAtCell(0, 0, 'foo bar', 'customSource');
  19734. setDataAtCell(1, 2, 22, 'customSource');
  19735. expect(getDataAtCell(0, 0)).toBe('bar');
  19736. expect(getDataAtCell(1, 2)).toBe(33);
  19737. expect(getData()).toEqual([['bar', 'b', 'c'], [1, 2, 33]]);
  19738. });
  19739. it('should trigger `afterSetDataAtRowProp` hook with applied changes', function () {
  19740. var _changes;
  19741. var _source;
  19742. handsontable({
  19743. columns: [{ data: 'name' }, { data: 'id' }],
  19744. afterSetDataAtRowProp: function afterSetDataAtRowProp(changes, source) {
  19745. _changes = changes;
  19746. _source = source;
  19747. }
  19748. });
  19749. setDataAtRowProp(0, 'name', 'foo bar', 'customSource');
  19750. expect(_changes).toEqual([[0, 'name', void 0, 'foo bar']]);
  19751. expect(_source).toBe('customSource');
  19752. expect(getDataAtCell(0, 0)).toBe('foo bar');
  19753. });
  19754. it('should modify value on the fly using `afterSetDataAtRowProp` hook', function () {
  19755. handsontable({
  19756. data: [{ name: 'a', id: 1 }, { name: 'b', id: 2 }, { name: 'c', id: 3 }],
  19757. columns: [{ data: 'name' }, { data: 'id' }],
  19758. afterSetDataAtRowProp: function afterSetDataAtRowProp(changes, source) {
  19759. if (changes[0][3] === 'foo bar') {
  19760. changes[0][3] = 'bar';
  19761. }
  19762. if (changes[0][3] === 22) {
  19763. changes[0][3] = 33;
  19764. }
  19765. }
  19766. });
  19767. setDataAtRowProp(0, 'name', 'foo bar', 'customSource');
  19768. setDataAtRowProp(1, 'id', 22, 'customSource');
  19769. expect(getDataAtRowProp(0, 'name')).toEqual('bar');
  19770. expect(getDataAtRowProp(1, 'id')).toBe(33);
  19771. expect(getData()).toEqual([['bar', 1], ['b', 33], ['c', 3]]);
  19772. });
  19773. });
  19774. /***/ }),
  19775. /* 178 */
  19776. /***/ (function(module, exports, __webpack_require__) {
  19777. "use strict";
  19778. describe('Core_splice', function () {
  19779. var id = 'testContainer';
  19780. beforeEach(function () {
  19781. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  19782. });
  19783. afterEach(function () {
  19784. if (this.$container) {
  19785. destroy();
  19786. this.$container.remove();
  19787. }
  19788. });
  19789. var arrayOfArrays = function arrayOfArrays() {
  19790. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  19791. };
  19792. describe('spliceCol', function () {
  19793. it('should remove data from specified col', function () {
  19794. handsontable({
  19795. data: arrayOfArrays(),
  19796. minSpareRows: 1
  19797. });
  19798. expect(spliceCol(1, 0, 2)).toEqual(['Kia', 10]);
  19799. expect(getData(0, 1, 3, 1)).toEqual([[20], [30], [null], [null]]);
  19800. });
  19801. it('should insert data into specified col', function () {
  19802. handsontable({
  19803. data: arrayOfArrays(),
  19804. minSpareRows: 1
  19805. });
  19806. expect(spliceCol(1, 1, 0, 'test', 'test', 'test')).toEqual([]);
  19807. expect(getData(0, 1, 6, 1)).toEqual([['Kia'], ['test'], ['test'], ['test'], [10], [20], [30]]);
  19808. });
  19809. it('should remove and insert data into specified col', function () {
  19810. handsontable({
  19811. data: arrayOfArrays(),
  19812. minSpareRows: 1
  19813. });
  19814. expect(spliceCol(1, 0, 2, 'test', 'test', 'test')).toEqual(['Kia', 10]);
  19815. expect(getData(0, 1, 4, 1)).toEqual([['test'], ['test'], ['test'], [20], [30]]);
  19816. });
  19817. });
  19818. describe('spliceRow', function () {
  19819. it('should remove data from specified row', function () {
  19820. handsontable({
  19821. data: arrayOfArrays(),
  19822. minSpareCols: 1
  19823. });
  19824. expect(spliceRow(0, 0, 3)).toEqual(['', 'Kia', 'Nissan']);
  19825. expect(getData(0, 0, 0, 4)).toEqual([['Toyota', 'Honda', null, null, null]]);
  19826. });
  19827. it('should insert data into specified row', function () {
  19828. handsontable({
  19829. data: arrayOfArrays(),
  19830. minSpareCols: 1
  19831. });
  19832. expect(spliceRow(0, 0, 0, 'test', 'test', 'test')).toEqual([]);
  19833. expect(getData(0, 0, 0, 7)).toEqual([['test', 'test', 'test', '', 'Kia', 'Nissan', 'Toyota', 'Honda']]);
  19834. });
  19835. it('should remove and insert data into specified row', function () {
  19836. handsontable({
  19837. data: arrayOfArrays(),
  19838. minSpareCols: 1
  19839. });
  19840. expect(spliceRow(0, 0, 2, 'test', 'test', 'test')).toEqual(['', 'Kia']);
  19841. expect(getData(0, 0, 0, 5)).toEqual([['test', 'test', 'test', 'Nissan', 'Toyota', 'Honda']]);
  19842. });
  19843. });
  19844. });
  19845. /***/ }),
  19846. /* 179 */
  19847. /***/ (function(module, exports, __webpack_require__) {
  19848. "use strict";
  19849. describe('Core_updateSettings', function () {
  19850. var id = 'testContainer';
  19851. beforeEach(function () {
  19852. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  19853. });
  19854. afterEach(function () {
  19855. if (this.$container) {
  19856. destroy();
  19857. this.$container.remove();
  19858. }
  19859. });
  19860. it('should inherit cell type', function () {
  19861. handsontable({
  19862. data: [[1, 2]],
  19863. columns: [{}, { type: 'checkbox' }],
  19864. cells: function cells(row, col, prop) {
  19865. if (row === 0 && col === 0) {
  19866. return {
  19867. type: 'numeric'
  19868. };
  19869. }
  19870. }
  19871. });
  19872. expect(getCellMeta(0, 0).type).toEqual('numeric');
  19873. expect(getCellMeta(0, 1).type).toEqual('checkbox');
  19874. });
  19875. it('should inherit cell type when columns is a function', function () {
  19876. handsontable({
  19877. data: [[1, 2]],
  19878. columns: function columns(column) {
  19879. var colMeta = null;
  19880. if (column === 0) {
  19881. colMeta = {};
  19882. } else if (column === 1) {
  19883. colMeta = { type: 'checkbox' };
  19884. }
  19885. return colMeta;
  19886. },
  19887. cells: function cells(row, col, prop) {
  19888. if (row === 0 && col === 0) {
  19889. return {
  19890. type: 'numeric'
  19891. };
  19892. }
  19893. }
  19894. });
  19895. expect(getCellMeta(0, 0).type).toEqual('numeric');
  19896. expect(getCellMeta(0, 1).type).toEqual('checkbox');
  19897. });
  19898. it('should ignore mixed in properties to the cell array option', function () {
  19899. /* eslint-disable no-array-constructor */
  19900. /* eslint-disable no-extend-native */
  19901. Array.prototype.willFail = 'BOOM';
  19902. handsontable({
  19903. data: [[1, true]],
  19904. columns: [{ type: 'numeric' }, { type: 'checkbox' }]
  19905. });
  19906. expect(function () {
  19907. updateSettings({ cell: new Array() });
  19908. }).not.toThrow();
  19909. });
  19910. it('should ignore mixed in properties to the cell array option when columns is a function', function () {
  19911. /* eslint-disable no-array-constructor */
  19912. /* eslint-disable no-extend-native */
  19913. Array.prototype.willFail = 'BOOM';
  19914. handsontable({
  19915. data: [[1, true]],
  19916. columns: function columns(column) {
  19917. var colMeta = null;
  19918. if (column === 0) {
  19919. colMeta = { type: 'numeric' };
  19920. } else if (column === 1) {
  19921. colMeta = { type: 'checkbox' };
  19922. }
  19923. return colMeta;
  19924. }
  19925. });
  19926. expect(function () {
  19927. updateSettings({ cell: new Array() });
  19928. }).not.toThrow();
  19929. });
  19930. it('should not reset columns types to text', function () {
  19931. handsontable({
  19932. data: [[1, true]],
  19933. columns: [{ type: 'numeric' }, { type: 'checkbox' }]
  19934. });
  19935. var td = this.$container.find('td');
  19936. expect(td.eq(0).text()).toEqual('1');
  19937. expect(td.eq(1).text()).toEqual('');
  19938. updateSettings({});
  19939. expect(td.eq(0).text()).toEqual('1');
  19940. expect(td.eq(1).text()).toEqual('');
  19941. });
  19942. it('should not reset columns types to text when columns is a function', function () {
  19943. handsontable({
  19944. data: [[1, true]],
  19945. columns: function columns(column) {
  19946. var colMeta = null;
  19947. if (column === 0) {
  19948. colMeta = { type: 'numeric' };
  19949. } else if (column === 1) {
  19950. colMeta = { type: 'checkbox' };
  19951. }
  19952. return colMeta;
  19953. }
  19954. });
  19955. var td = this.$container.find('td');
  19956. expect(td.eq(0).text()).toEqual('1');
  19957. expect(td.eq(1).text()).toEqual('');
  19958. updateSettings({});
  19959. expect(td.eq(0).text()).toEqual('1');
  19960. expect(td.eq(1).text()).toEqual('');
  19961. });
  19962. it('should update readOnly global setting', function () {
  19963. handsontable({
  19964. readOnly: true,
  19965. data: [['foo', 'bar']],
  19966. columns: [{}, {}]
  19967. });
  19968. expect(getCellMeta(0, 0).readOnly).toBe(true);
  19969. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(true);
  19970. expect(getCellMeta(0, 1).readOnly).toBe(true);
  19971. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(true);
  19972. updateSettings({
  19973. readOnly: false
  19974. });
  19975. expect(getCellMeta(0, 0).readOnly).toBe(false);
  19976. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(false);
  19977. expect(getCellMeta(0, 1).readOnly).toBe(false);
  19978. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(false);
  19979. });
  19980. it('should update readOnly global setting when columns is a function', function () {
  19981. handsontable({
  19982. readOnly: true,
  19983. data: [['foo', 'bar']],
  19984. columns: function columns(column) {
  19985. var colMeta = {};
  19986. if ([0, 1].indexOf(column) < 0) {
  19987. colMeta = null;
  19988. }
  19989. return colMeta;
  19990. }
  19991. });
  19992. expect(getCellMeta(0, 0).readOnly).toBe(true);
  19993. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(true);
  19994. expect(getCellMeta(0, 1).readOnly).toBe(true);
  19995. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(true);
  19996. updateSettings({
  19997. readOnly: false
  19998. });
  19999. expect(getCellMeta(0, 0).readOnly).toBe(false);
  20000. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(false);
  20001. expect(getCellMeta(0, 1).readOnly).toBe(false);
  20002. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(false);
  20003. });
  20004. it('should update readOnly columns setting', function () {
  20005. handsontable({
  20006. data: [['foo', true]],
  20007. columns: [{ type: 'text', readOnly: true }, { type: 'checkbox' }]
  20008. });
  20009. expect(getCellMeta(0, 0).readOnly).toBe(true);
  20010. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(true);
  20011. expect(getCellMeta(0, 1).readOnly).toBe(false);
  20012. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(false);
  20013. updateSettings({
  20014. columns: [{ type: 'text', readOnly: false }, { type: 'checkbox' }]
  20015. });
  20016. expect(getCellMeta(0, 0).readOnly).toBe(false);
  20017. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(false);
  20018. expect(getCellMeta(0, 1).readOnly).toBe(false);
  20019. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(false);
  20020. });
  20021. it('should update readOnly columns setting when columns is a function', function () {
  20022. handsontable({
  20023. data: [['foo', true]],
  20024. columns: function columns(column) {
  20025. var colMeta = null;
  20026. if (column === 0) {
  20027. colMeta = { type: 'text', readOnly: true };
  20028. } else if (column === 1) {
  20029. colMeta = { type: 'checkbox' };
  20030. }
  20031. return colMeta;
  20032. }
  20033. });
  20034. expect(getCellMeta(0, 0).readOnly).toBe(true);
  20035. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(true);
  20036. expect(getCellMeta(0, 1).readOnly).toBe(false);
  20037. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(false);
  20038. updateSettings({
  20039. columns: function columns(column) {
  20040. var colMeta = null;
  20041. if (column === 0) {
  20042. colMeta = { type: 'text', readOnly: false };
  20043. } else if (column === 1) {
  20044. colMeta = { type: 'checkbox' };
  20045. }
  20046. return colMeta;
  20047. }
  20048. });
  20049. expect(getCellMeta(0, 0).readOnly).toBe(false);
  20050. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(false);
  20051. expect(getCellMeta(0, 1).readOnly).toBe(false);
  20052. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(false);
  20053. });
  20054. it('should update readOnly columns setting and override global setting', function () {
  20055. handsontable({
  20056. readOnly: true,
  20057. data: [['foo', true]],
  20058. columns: [{ type: 'text' }, { type: 'checkbox' }]
  20059. });
  20060. expect(getCellMeta(0, 0).readOnly).toBe(true);
  20061. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(true);
  20062. expect(getCellMeta(0, 1).readOnly).toBe(true);
  20063. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(true);
  20064. updateSettings({
  20065. columns: [{ type: 'text', readOnly: false }, { type: 'checkbox' }]
  20066. });
  20067. expect(getCellMeta(0, 0).readOnly).toBe(false);
  20068. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(false);
  20069. expect(getCellMeta(0, 1).readOnly).toBe(true);
  20070. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(true);
  20071. });
  20072. it('should update readOnly columns setting and override global setting when columns is a function', function () {
  20073. handsontable({
  20074. readOnly: true,
  20075. data: [['foo', true]],
  20076. columns: function columns(column) {
  20077. var colMeta = null;
  20078. if (column === 0) {
  20079. colMeta = { type: 'text' };
  20080. } else if (column === 1) {
  20081. colMeta = { type: 'checkbox' };
  20082. }
  20083. return colMeta;
  20084. }
  20085. });
  20086. expect(getCellMeta(0, 0).readOnly).toBe(true);
  20087. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(true);
  20088. expect(getCellMeta(0, 1).readOnly).toBe(true);
  20089. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(true);
  20090. updateSettings({
  20091. columns: function columns(column) {
  20092. var colMeta = null;
  20093. if (column === 0) {
  20094. colMeta = { type: 'text', readOnly: false };
  20095. } else if (column === 1) {
  20096. colMeta = { type: 'checkbox' };
  20097. }
  20098. return colMeta;
  20099. }
  20100. });
  20101. expect(getCellMeta(0, 0).readOnly).toBe(false);
  20102. expect($(getCell(0, 0)).hasClass('htDimmed')).toBe(false);
  20103. expect(getCellMeta(0, 1).readOnly).toBe(true);
  20104. expect($(getCell(0, 1)).hasClass('htDimmed')).toBe(true);
  20105. });
  20106. it('should not alter the columns object during init', function () {
  20107. var columns = [{
  20108. type: 'text'
  20109. }];
  20110. var columnsCopy = JSON.parse(JSON.stringify(columns));
  20111. handsontable({
  20112. columns: columns
  20113. });
  20114. expect(columns).toEqual(columnsCopy);
  20115. });
  20116. it('should update column type', function () {
  20117. var columns = [{
  20118. type: 'text'
  20119. }];
  20120. handsontable({
  20121. columns: columns
  20122. });
  20123. expect(getCellMeta(0, 0).type).toEqual('text');
  20124. expect(getCellRenderer(0, 0)).toBe(Handsontable.renderers.TextRenderer);
  20125. expect(getCellEditor(0, 0)).toBe(Handsontable.editors.TextEditor);
  20126. columns[0].type = 'date';
  20127. updateSettings({
  20128. columns: columns
  20129. });
  20130. expect(getCellMeta(0, 0).type).toEqual('date');
  20131. expect(getCellRenderer(0, 0)).toBe(Handsontable.renderers.AutocompleteRenderer);
  20132. expect(getCellEditor(0, 0)).toEqual(Handsontable.editors.DateEditor);
  20133. });
  20134. it('should update cell type functions, even if new type does not implement all of those functions', function () {
  20135. var columns = [{
  20136. type: 'numeric'
  20137. }];
  20138. handsontable({
  20139. columns: columns
  20140. });
  20141. expect(getCellMeta(0, 0).type).toEqual('numeric');
  20142. expect(getCellRenderer(0, 0)).toBe(Handsontable.renderers.NumericRenderer);
  20143. expect(getCellEditor(0, 0)).toBe(Handsontable.editors.NumericEditor);
  20144. expect(getCellValidator(0, 0)).toBe(Handsontable.cellTypes.numeric.validator);
  20145. columns[0].type = 'text';
  20146. updateSettings({
  20147. columns: columns
  20148. });
  20149. expect(getCellMeta(0, 0).type).toEqual('text');
  20150. expect(getCellRenderer(0, 0)).toBe(Handsontable.renderers.TextRenderer);
  20151. expect(getCellEditor(0, 0)).toEqual(Handsontable.editors.TextEditor);
  20152. expect(Handsontable.cellTypes.text.validator).toBeUndefined();
  20153. expect(getCellValidator(0, 0)).toBeUndefined();
  20154. });
  20155. it('should allow updating the table height', function () {
  20156. var hot = handsontable({
  20157. startRows: 22,
  20158. startCols: 5
  20159. });
  20160. var initialHeight = parseInt(this.$container[0].style.height, 10);
  20161. updateSettings({
  20162. height: 300
  20163. });
  20164. expect(parseInt(this.$container[0].style.height, 10)).toEqual(300);
  20165. expect(parseInt(this.$container[0].style.height, 10)).not.toEqual(initialHeight);
  20166. });
  20167. it('should not reset the table height, when the updateSettings config object doesn\'t have any height specified', function () {
  20168. var hot = handsontable({
  20169. startRows: 22,
  20170. startCols: 5,
  20171. height: 300
  20172. });
  20173. var initialHeight = this.$container[0].style.height;
  20174. updateSettings({
  20175. rowHeaders: true
  20176. });
  20177. expect(parseInt(this.$container[0].style.height, 10)).toEqual(parseInt(initialHeight, 10));
  20178. });
  20179. it('should allow resetting the table height', function () {
  20180. var hot = handsontable({
  20181. startRows: 22,
  20182. startCols: 5,
  20183. height: 300
  20184. });
  20185. var initialHeight = this.$container[0].style.height;
  20186. updateSettings({
  20187. height: null
  20188. });
  20189. expect(parseInt(this.$container[0].style.height, 10)).not.toEqual(parseInt(initialHeight, 10));
  20190. });
  20191. it('should allow updating the stretching type', function () {
  20192. var hot = handsontable({
  20193. stretchH: 'last'
  20194. });
  20195. expect(hot.view.wt.getSetting('stretchH')).toEqual('last');
  20196. updateSettings({
  20197. stretchH: 'all'
  20198. });
  20199. expect(hot.view.wt.getSetting('stretchH')).toEqual('all');
  20200. updateSettings({
  20201. stretchH: 'none'
  20202. });
  20203. expect(hot.view.wt.getSetting('stretchH')).toEqual('none');
  20204. updateSettings({
  20205. stretchH: 'last'
  20206. });
  20207. expect(hot.view.wt.getSetting('stretchH')).toEqual('last');
  20208. });
  20209. it('should change colHeader\'s row height if is needed', function () {
  20210. var hot = handsontable({
  20211. colHeaders: true,
  20212. rowHeaders: true
  20213. });
  20214. var rowHeights = [];
  20215. rowHeights.push(this.$container.find('.ht_clone_top_left_corner thead th')[0].clientHeight);
  20216. updateSettings({
  20217. colHeaders: ['A<br/>A']
  20218. });
  20219. rowHeights.push(this.$container.find('.ht_clone_top_left_corner thead th')[0].clientHeight);
  20220. expect(rowHeights[0]).toBeLessThan(rowHeights[1]);
  20221. });
  20222. it('should not overwrite properties (created by columns defined as function) of cells below the viewport by updateSettings #4029', function () {
  20223. var rows = 50;
  20224. var columns = 2;
  20225. handsontable({
  20226. data: Handsontable.helper.createSpreadsheetObjectData(columns, rows),
  20227. columns: function columns(col) {
  20228. var colProp = {
  20229. data: 'prop' + col,
  20230. readOnly: true
  20231. };
  20232. if (col === 1) {
  20233. colProp.type = 'checkbox';
  20234. }
  20235. return colProp;
  20236. }
  20237. });
  20238. updateSettings({});
  20239. expect(getCellMeta(rows, 0).readOnly).toEqual(true);
  20240. expect(getCellMeta(rows, 1).type).toEqual('checkbox');
  20241. rows = 100;
  20242. updateSettings({ data: Handsontable.helper.createSpreadsheetObjectData(columns, rows) });
  20243. expect(getCellMeta(rows, 0).readOnly).toEqual(true);
  20244. expect(getCellMeta(rows, 1).type).toEqual('checkbox');
  20245. updateSettings({
  20246. columns: function columns(col) {
  20247. var colProp = {
  20248. data: 'prop' + col,
  20249. type: 'numeric'
  20250. };
  20251. return colProp;
  20252. }
  20253. });
  20254. expect(getCellMeta(0, 1).type).toEqual('numeric');
  20255. expect(getCellMeta(0, 1).readOnly).toEqual(false);
  20256. expect(getCellMeta(rows, 1).type).toEqual('numeric');
  20257. expect(getCellMeta(rows, 1).readOnly).toEqual(false);
  20258. });
  20259. it('should not overwrite properties (created by columns defined as array) of cells below the viewport by updateSettings #4029', function () {
  20260. var rows = 50;
  20261. var columns = 2;
  20262. handsontable({
  20263. data: Handsontable.helper.createSpreadsheetObjectData(columns, rows),
  20264. columns: [{
  20265. type: 'numeric',
  20266. format: '0,0.00 $'
  20267. }, {
  20268. type: 'text',
  20269. readOnly: true
  20270. }]
  20271. });
  20272. updateSettings({});
  20273. expect(getCellMeta(rows, 0).type).toEqual('numeric');
  20274. expect(getCellMeta(rows, 1).readOnly).toEqual(true);
  20275. rows = 100;
  20276. updateSettings({ data: Handsontable.helper.createSpreadsheetObjectData(columns, rows) });
  20277. expect(getCellMeta(rows, 0).type).toEqual('numeric');
  20278. expect(getCellMeta(rows, 1).readOnly).toEqual(true);
  20279. updateSettings({
  20280. columns: [{
  20281. type: 'text',
  20282. readOnly: true
  20283. }, {
  20284. type: 'numeric',
  20285. format: '0,0.00 $'
  20286. }]
  20287. });
  20288. expect(getCellMeta(0, 0).type).toEqual('text');
  20289. expect(getCellMeta(0, 0).readOnly).toEqual(true);
  20290. expect(getCellMeta(0, 1).type).toEqual('numeric');
  20291. expect(getCellMeta(0, 1).readOnly).toEqual(false);
  20292. expect(getCellMeta(rows, 0).type).toEqual('text');
  20293. expect(getCellMeta(rows, 1).type).toEqual('numeric');
  20294. });
  20295. });
  20296. /***/ }),
  20297. /* 180 */
  20298. /***/ (function(module, exports, __webpack_require__) {
  20299. "use strict";
  20300. describe('Core_validate', function () {
  20301. var id = 'testContainer';
  20302. beforeEach(function () {
  20303. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  20304. });
  20305. afterEach(function () {
  20306. if (this.$container) {
  20307. destroy();
  20308. this.$container.remove();
  20309. }
  20310. });
  20311. var arrayOfObjects = function arrayOfObjects() {
  20312. return [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }, { id: 6, name: 'Chuck', lastName: 'Jackson' }, { id: 7, name: 'Meg', lastName: 'Jansen' }, { id: 8, name: 'Rob', lastName: 'Norris' }, { id: 9, name: 'Sean', lastName: 'O\'Hara' }, { id: 10, name: 'Eve', lastName: 'Branson' }];
  20313. };
  20314. it('should call beforeValidate', function () {
  20315. var fired = null;
  20316. handsontable({
  20317. data: arrayOfObjects(),
  20318. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  20319. beforeValidate: function beforeValidate() {
  20320. fired = true;
  20321. }
  20322. });
  20323. setDataAtCell(2, 0, 'test');
  20324. expect(fired).toEqual(true);
  20325. });
  20326. it('should call beforeValidate when columns is a function', function () {
  20327. var fired = null;
  20328. handsontable({
  20329. data: arrayOfObjects(),
  20330. columns: function columns(column) {
  20331. var colMeta = {};
  20332. if (column === 0) {
  20333. colMeta.data = 'id';
  20334. colMeta.type = 'numeric';
  20335. } else if (column === 1) {
  20336. colMeta.data = 'name';
  20337. } else if (column === 2) {
  20338. colMeta.data = 'lastName';
  20339. } else {
  20340. colMeta = null;
  20341. }
  20342. return colMeta;
  20343. },
  20344. beforeValidate: function beforeValidate() {
  20345. fired = true;
  20346. }
  20347. });
  20348. setDataAtCell(2, 0, 'test');
  20349. expect(fired).toBe(true);
  20350. });
  20351. it('should call afterValidate', function (done) {
  20352. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20353. handsontable({
  20354. data: arrayOfObjects(),
  20355. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  20356. afterValidate: onAfterValidate
  20357. });
  20358. setDataAtCell(2, 0, 'test');
  20359. setTimeout(function () {
  20360. expect(onAfterValidate.calls.count()).toBe(1);
  20361. done();
  20362. }, 200);
  20363. });
  20364. it('should call afterValidate when columns is a function', function (done) {
  20365. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20366. handsontable({
  20367. data: arrayOfObjects(),
  20368. columns: function columns(column) {
  20369. var colMeta = {};
  20370. if (column === 0) {
  20371. colMeta.data = 'id';
  20372. colMeta.type = 'numeric';
  20373. } else if (column === 1) {
  20374. colMeta.data = 'name';
  20375. } else if (column === 2) {
  20376. colMeta.data = 'lastName';
  20377. } else {
  20378. colMeta = null;
  20379. }
  20380. return colMeta;
  20381. },
  20382. afterValidate: onAfterValidate
  20383. });
  20384. setDataAtCell(2, 0, 'test');
  20385. setTimeout(function () {
  20386. expect(onAfterValidate.calls.count()).toBe(1);
  20387. done();
  20388. }, 200);
  20389. });
  20390. it('beforeValidate can manipulate value', function (done) {
  20391. var result = null;
  20392. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20393. onAfterValidate.and.callFake(function (valid, value) {
  20394. result = value;
  20395. });
  20396. handsontable({
  20397. data: arrayOfObjects(),
  20398. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  20399. beforeValidate: function beforeValidate(value) {
  20400. value = 999;
  20401. return value;
  20402. },
  20403. afterValidate: onAfterValidate
  20404. });
  20405. setDataAtCell(2, 0, 123);
  20406. setTimeout(function () {
  20407. expect(result).toBe(999);
  20408. done();
  20409. }, 200);
  20410. });
  20411. it('beforeValidate can manipulate value when columns is a function', function (done) {
  20412. var result = null;
  20413. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20414. onAfterValidate.and.callFake(function (valid, value) {
  20415. result = value;
  20416. });
  20417. handsontable({
  20418. data: arrayOfObjects(),
  20419. columns: function columns(column) {
  20420. var colMeta = {};
  20421. if (column === 0) {
  20422. colMeta.data = 'id';
  20423. colMeta.type = 'numeric';
  20424. } else if (column === 1) {
  20425. colMeta.data = 'name';
  20426. } else if (column === 2) {
  20427. colMeta.data = 'lastName';
  20428. } else {
  20429. colMeta = null;
  20430. }
  20431. return colMeta;
  20432. },
  20433. beforeValidate: function beforeValidate(value) {
  20434. value = 999;
  20435. return value;
  20436. },
  20437. afterValidate: onAfterValidate
  20438. });
  20439. setDataAtCell(2, 0, 123);
  20440. setTimeout(function () {
  20441. expect(result).toBe(999);
  20442. done();
  20443. }, 200);
  20444. });
  20445. it('should be able to define custom validator function', function (done) {
  20446. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20447. handsontable({
  20448. data: arrayOfObjects(),
  20449. columns: [{ data: 'id',
  20450. validator: function validator(value, cb) {
  20451. cb(true);
  20452. }
  20453. }, { data: 'name' }, { data: 'lastName' }],
  20454. afterValidate: onAfterValidate
  20455. });
  20456. setDataAtCell(2, 0, 123);
  20457. setTimeout(function () {
  20458. expect(onAfterValidate).toHaveBeenCalledWith(true, 123, 2, 'id', undefined, undefined);
  20459. done();
  20460. }, 200);
  20461. });
  20462. it('should be able to define custom validator function when columns is a function', function (done) {
  20463. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20464. handsontable({
  20465. data: arrayOfObjects(),
  20466. columns: function columns(column) {
  20467. var colMeta = null;
  20468. if (column === 0) {
  20469. colMeta = {
  20470. data: 'id',
  20471. validator: function validator(value, cb) {
  20472. cb(true);
  20473. }
  20474. };
  20475. } else if (column === 1) {
  20476. colMeta = { data: 'name' };
  20477. } else if (column === 2) {
  20478. colMeta = { data: 'lastName' };
  20479. }
  20480. return colMeta;
  20481. },
  20482. afterValidate: onAfterValidate
  20483. });
  20484. setDataAtCell(2, 0, 123);
  20485. setTimeout(function () {
  20486. expect(onAfterValidate).toHaveBeenCalledWith(true, 123, 2, 'id', undefined, undefined);
  20487. done();
  20488. }, 200);
  20489. });
  20490. it('should be able to define custom validator RegExp', function (done) {
  20491. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20492. handsontable({
  20493. data: arrayOfObjects(),
  20494. columns: [{ data: 'id', validator: /^\d+$/ }, { data: 'name' }, { data: 'lastName' }],
  20495. afterValidate: onAfterValidate
  20496. });
  20497. setDataAtCell(2, 0, 'test');
  20498. setTimeout(function () {
  20499. expect(onAfterValidate).toHaveBeenCalledWith(false, 'test', 2, 'id', undefined, undefined);
  20500. done();
  20501. }, 200);
  20502. });
  20503. it('should be able to define custom validator RegExp when columns is a function', function (done) {
  20504. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20505. handsontable({
  20506. data: arrayOfObjects(),
  20507. columns: function columns(column) {
  20508. var colMeta = null;
  20509. if (column === 0) {
  20510. colMeta = { data: 'id', validator: /^\d+$/ };
  20511. } else if (column === 1) {
  20512. colMeta = { data: 'name' };
  20513. } else if (column === 2) {
  20514. colMeta = { data: 'lastName' };
  20515. }
  20516. return colMeta;
  20517. },
  20518. afterValidate: onAfterValidate
  20519. });
  20520. setDataAtCell(2, 0, 'test');
  20521. setTimeout(function () {
  20522. expect(onAfterValidate).toHaveBeenCalledWith(false, 'test', 2, 'id', undefined, undefined);
  20523. done();
  20524. }, 200);
  20525. });
  20526. it('this in validator should point to cellProperties', function (done) {
  20527. var result = null;
  20528. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20529. handsontable({
  20530. data: arrayOfObjects(),
  20531. columns: [{
  20532. data: 'id',
  20533. validator: function validator(value, cb) {
  20534. result = this;
  20535. cb(true);
  20536. }
  20537. }, { data: 'name' }, { data: 'lastName' }],
  20538. afterValidate: onAfterValidate
  20539. });
  20540. setDataAtCell(2, 0, 123);
  20541. setTimeout(function () {
  20542. expect(result.instance).toEqual(getInstance());
  20543. done();
  20544. }, 200);
  20545. });
  20546. it('this in validator should point to cellProperties when columns is a function', function (done) {
  20547. var result = null;
  20548. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20549. handsontable({
  20550. data: arrayOfObjects(),
  20551. columns: function columns(column) {
  20552. var colMeta = null;
  20553. if (column === 0) {
  20554. colMeta = {
  20555. data: 'id',
  20556. validator: function validator(value, cb) {
  20557. result = this;
  20558. cb(true);
  20559. }
  20560. };
  20561. } else if (column === 1) {
  20562. colMeta = { data: 'name' };
  20563. } else if (column === 2) {
  20564. colMeta = { data: 'lastName' };
  20565. }
  20566. return colMeta;
  20567. },
  20568. afterValidate: onAfterValidate
  20569. });
  20570. setDataAtCell(2, 0, 123);
  20571. setTimeout(function () {
  20572. expect(result.instance).toEqual(getInstance());
  20573. done();
  20574. }, 200);
  20575. });
  20576. it('should not throw error after calling validateCells without first argument', function (done) {
  20577. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20578. var hot = handsontable({
  20579. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20580. validator: function validator(value, callb) {
  20581. if (value == 'B1') {
  20582. callb(false);
  20583. } else {
  20584. callb(true);
  20585. }
  20586. },
  20587. afterValidate: onAfterValidate
  20588. });
  20589. expect(hot.validateCells).not.toThrow();
  20590. setTimeout(function () {
  20591. expect(spec().$container.find('td.htInvalid').length).toEqual(1);
  20592. expect(spec().$container.find('td:not(.htInvalid)').length).toEqual(3);
  20593. done();
  20594. }, 200);
  20595. });
  20596. it('should add class name `htInvalid` to an cell that does not validate - on validateCells', function (done) {
  20597. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20598. var hot = handsontable({
  20599. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20600. validator: function validator(value, callb) {
  20601. if (value == 'B1') {
  20602. callb(false);
  20603. } else {
  20604. callb(true);
  20605. }
  20606. },
  20607. afterValidate: onAfterValidate
  20608. });
  20609. hot.validateCells(function () {
  20610. hot.render();
  20611. });
  20612. setTimeout(function () {
  20613. expect(spec().$container.find('td.htInvalid').length).toEqual(1);
  20614. expect(spec().$container.find('td:not(.htInvalid)').length).toEqual(3);
  20615. done();
  20616. }, 200);
  20617. });
  20618. it('should add class name `htInvalid` to an cell that does not validate - when we trigger validateCell', function (done) {
  20619. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20620. var hot = handsontable({
  20621. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20622. validator: function validator(value, cb) {
  20623. cb(false);
  20624. },
  20625. afterValidate: onAfterValidate
  20626. });
  20627. expect(this.$container.find('td:not(.htInvalid)').length).toEqual(4);
  20628. hot.validateCell(hot.getDataAtCell(1, 1), hot.getCellMeta(1, 1), function () {});
  20629. setTimeout(function () {
  20630. expect(spec().$container.find('td.htInvalid').length).toEqual(1);
  20631. expect(spec().$container.find('td:not(.htInvalid)').length).toEqual(3);
  20632. done();
  20633. }, 200);
  20634. });
  20635. it('should remove class name `htInvalid` from an cell that does validate - when we change validator rules', function (done) {
  20636. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20637. var isValid = false;
  20638. var _validator = function _validator() {
  20639. return isValid;
  20640. };
  20641. var hot = handsontable({
  20642. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20643. validator: function validator(value, cb) {
  20644. cb(_validator());
  20645. },
  20646. afterValidate: onAfterValidate
  20647. });
  20648. hot.validateCells(function () {});
  20649. setTimeout(function () {
  20650. expect(spec().$container.find('td.htInvalid').length).toEqual(4);
  20651. expect(spec().$container.find('td:not(.htInvalid)').length).toEqual(0);
  20652. isValid = true;
  20653. onAfterValidate.calls.reset();
  20654. hot.validateCell(hot.getDataAtCell(1, 1), hot.getCellMeta(1, 1), function () {});
  20655. }, 200);
  20656. setTimeout(function () {
  20657. expect(spec().$container.find('td.htInvalid').length).toEqual(3);
  20658. expect(spec().$container.find('td:not(.htInvalid)').length).toEqual(1);
  20659. done();
  20660. }, 400);
  20661. });
  20662. it('should add class name `htInvalid` to an cell that does not validate - on edit', function (done) {
  20663. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20664. handsontable({
  20665. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20666. validator: function validator(value, callb) {
  20667. if (value == 'test') {
  20668. callb(false);
  20669. } else {
  20670. callb(true);
  20671. }
  20672. },
  20673. afterValidate: onAfterValidate
  20674. });
  20675. setDataAtCell(0, 0, 'test');
  20676. setTimeout(function () {
  20677. expect(spec().$container.find('td.htInvalid').length).toEqual(1);
  20678. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(true);
  20679. done();
  20680. }, 200);
  20681. });
  20682. it('should add class name `htInvalid` to a cell without removing other classes', function (done) {
  20683. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20684. var validator = jasmine.createSpy('validator');
  20685. validator.and.callFake(function (value, callb) {
  20686. if (value == 123) {
  20687. callb(false);
  20688. } else {
  20689. callb(true);
  20690. }
  20691. });
  20692. handsontable({
  20693. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20694. type: 'numeric',
  20695. validator: validator,
  20696. afterValidate: onAfterValidate
  20697. });
  20698. setDataAtCell(0, 0, 123);
  20699. setTimeout(function () {
  20700. expect(validator.calls.count()).toEqual(1);
  20701. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(true);
  20702. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htNumeric')).toEqual(true);
  20703. onAfterValidate.calls.reset();
  20704. setDataAtCell(0, 0, 124);
  20705. }, 200);
  20706. setTimeout(function () {
  20707. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(false);
  20708. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htNumeric')).toEqual(true);
  20709. done();
  20710. }, 400);
  20711. });
  20712. it('should add class name `htInvalid` to an cell that does not validate - after validateCells', function (done) {
  20713. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20714. var hot = handsontable({
  20715. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20716. afterValidate: onAfterValidate
  20717. });
  20718. setDataAtCell(0, 0, 'test');
  20719. setTimeout(function () {
  20720. expect(spec().$container.find('td.htInvalid').length).toEqual(0);
  20721. updateSettings({
  20722. validator: function validator(value, callb) {
  20723. if (value == 'test') {
  20724. callb(false);
  20725. } else {
  20726. callb(true);
  20727. }
  20728. }
  20729. });
  20730. onAfterValidate.calls.reset();
  20731. hot.validateCells(function () {});
  20732. }, 200);
  20733. setTimeout(function () {
  20734. expect(spec().$container.find('td.htInvalid').length).toEqual(1);
  20735. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(true);
  20736. done();
  20737. }, 400);
  20738. });
  20739. it('should remove class name `htInvalid` when cell is edited to validate', function (done) {
  20740. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20741. var hot = handsontable({
  20742. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20743. validator: function validator(value, callb) {
  20744. if (value == 'A1') {
  20745. callb(false);
  20746. } else {
  20747. callb(true);
  20748. }
  20749. },
  20750. afterValidate: onAfterValidate
  20751. });
  20752. hot.validateCells(function () {
  20753. hot.render();
  20754. });
  20755. setTimeout(function () {
  20756. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(true);
  20757. onAfterValidate.calls.reset();
  20758. setDataAtCell(0, 0, 'test');
  20759. }, 200);
  20760. setTimeout(function () {
  20761. expect(spec().$container.find('tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(false);
  20762. done();
  20763. }, 400);
  20764. });
  20765. it('should call callback with first argument as `true` if all cells are valid', function (done) {
  20766. var onValidate = jasmine.createSpy('onValidate');
  20767. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20768. var hot = handsontable({
  20769. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20770. validator: function validator(value, callback) {
  20771. callback(true);
  20772. },
  20773. afterValidate: onAfterValidate
  20774. });
  20775. hot.validateCells(onValidate);
  20776. setTimeout(function () {
  20777. expect(onValidate).toHaveBeenCalledWith(true);
  20778. done();
  20779. }, 200);
  20780. });
  20781. it('should call callback with first argument as `false` if one of cells is invalid', function (done) {
  20782. var onValidate = jasmine.createSpy('onValidate');
  20783. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20784. var hot = handsontable({
  20785. data: Handsontable.helper.createSpreadsheetData(2, 2),
  20786. validator: function validator(value, callback) {
  20787. callback(false);
  20788. },
  20789. afterValidate: onAfterValidate
  20790. });
  20791. hot.validateCells(onValidate);
  20792. setTimeout(function () {
  20793. expect(onValidate).toHaveBeenCalledWith(false);
  20794. done();
  20795. }, 200);
  20796. });
  20797. it('should not allow for changes where data is invalid (multiple changes, async)', function (done) {
  20798. var validatedChanges;
  20799. handsontable({
  20800. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20801. allowInvalid: false,
  20802. validator: function validator(value, callb) {
  20803. setTimeout(function () {
  20804. if (value === 'fail') {
  20805. callb(false);
  20806. } else {
  20807. callb(true);
  20808. }
  20809. }, 10);
  20810. },
  20811. afterChange: function afterChange(changes, source) {
  20812. if (source !== 'loadData') {
  20813. validatedChanges = changes;
  20814. }
  20815. }
  20816. });
  20817. populateFromArray(0, 0, [['A1-new'], ['fail'], ['A3-new']]);
  20818. setTimeout(function () {
  20819. expect(validatedChanges.length).toEqual(2);
  20820. expect(validatedChanges[0]).toEqual([0, 0, 'A1', 'A1-new']);
  20821. expect(validatedChanges[1]).toEqual([2, 0, 'A3', 'A3-new']);
  20822. expect(getDataAtCell(0, 0)).toEqual('A1-new');
  20823. expect(getDataAtCell(1, 0)).toEqual('A2');
  20824. expect(getDataAtCell(2, 0)).toEqual('A3-new');
  20825. expect(getCellMeta(0, 0).valid).toBe(true);
  20826. expect(getCellMeta(1, 0).valid).toBe(true);
  20827. expect(getCellMeta(2, 0).valid).toBe(true);
  20828. done();
  20829. }, 200);
  20830. });
  20831. it('should call beforeChange exactly once after cell value edit and validator is synchronous', function (done) {
  20832. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20833. var onBeforeChange = jasmine.createSpy('onBeforeChange');
  20834. var hot = handsontable({
  20835. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20836. allowInvalid: false,
  20837. validator: function validator(value, callback) {
  20838. callback(true);
  20839. },
  20840. beforeChange: onBeforeChange,
  20841. afterValidate: onAfterValidate
  20842. });
  20843. expect(onBeforeChange.calls.count()).toEqual(0);
  20844. hot.setDataAtCell(0, 0, 10);
  20845. setTimeout(function () {
  20846. expect(onBeforeChange.calls.count()).toEqual(1);
  20847. done();
  20848. }, 200);
  20849. });
  20850. it('should call beforeChange exactly once after cell value edit and validator is asynchronous', function (done) {
  20851. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20852. var onBeforeChange = jasmine.createSpy('onBeforeChange');
  20853. var hot = handsontable({
  20854. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20855. allowInvalid: false,
  20856. validator: function validator(value, callback) {
  20857. setTimeout(function () {
  20858. callback(true);
  20859. }, 10);
  20860. },
  20861. beforeChange: onBeforeChange,
  20862. afterValidate: onAfterValidate
  20863. });
  20864. expect(onBeforeChange.calls.count()).toEqual(0);
  20865. hot.setDataAtCell(0, 0, 10);
  20866. setTimeout(function () {
  20867. expect(onBeforeChange.calls.count()).toEqual(1);
  20868. done();
  20869. }, 200);
  20870. });
  20871. it('should call afterChange exactly once after cell value edit and validator is synchronous', function (done) {
  20872. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20873. var onAfterChange = jasmine.createSpy('onAfterChange');
  20874. var hot = handsontable({
  20875. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20876. allowInvalid: false,
  20877. validator: function validator(value, callback) {
  20878. callback(true);
  20879. },
  20880. afterChange: onAfterChange,
  20881. afterValidate: onAfterValidate
  20882. });
  20883. expect(onAfterChange.calls.count()).toEqual(1); // loadData
  20884. hot.setDataAtCell(0, 0, 10);
  20885. setTimeout(function () {
  20886. expect(onAfterChange.calls.count()).toEqual(2);
  20887. done();
  20888. }, 200);
  20889. });
  20890. it('should call afterChange exactly once after cell value edit and validator is asynchronous', function (done) {
  20891. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20892. var onAfterChange = jasmine.createSpy('onAfterChange');
  20893. var hot = handsontable({
  20894. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20895. allowInvalid: false,
  20896. validator: function validator(value, callback) {
  20897. setTimeout(function () {
  20898. callback(true);
  20899. }, 10);
  20900. },
  20901. afterChange: onAfterChange,
  20902. afterValidate: onAfterValidate
  20903. });
  20904. expect(onAfterChange.calls.count()).toEqual(1); // loadData
  20905. hot.setDataAtCell(0, 0, 10);
  20906. setTimeout(function () {
  20907. expect(onAfterChange.calls.count()).toEqual(2);
  20908. done();
  20909. }, 200);
  20910. });
  20911. it('edited cell should stay on screen until value is validated', function (done) {
  20912. var isEditorVisibleBeforeChange;
  20913. var isEditorVisibleAfterChange;
  20914. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  20915. var onAfterChange = jasmine.createSpy('onAfterChange');
  20916. onAfterValidate.and.callFake(function () {
  20917. isEditorVisibleBeforeChange = isEditorVisible();
  20918. });
  20919. onAfterChange.and.callFake(function () {
  20920. isEditorVisibleAfterChange = isEditorVisible();
  20921. });
  20922. handsontable({
  20923. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20924. allowInvalid: false,
  20925. afterValidate: onAfterValidate,
  20926. afterChange: onAfterChange,
  20927. validator: function validator(value, callback) {
  20928. setTimeout(function () {
  20929. callback(true);
  20930. }, 100);
  20931. }
  20932. });
  20933. selectCell(0, 0);
  20934. keyDown('enter');
  20935. document.activeElement.value = 'Ted';
  20936. onAfterValidate.calls.reset();
  20937. onAfterChange.calls.reset();
  20938. keyDown('enter');
  20939. expect(document.activeElement.nodeName).toEqual('TEXTAREA');
  20940. setTimeout(function () {
  20941. expect(isEditorVisibleBeforeChange).toBe(true);
  20942. expect(isEditorVisibleAfterChange).toBe(true);
  20943. expect(isEditorVisible()).toBe(false);
  20944. done();
  20945. }, 200);
  20946. });
  20947. it('should validate edited cell after selecting another cell', function (done) {
  20948. var validated = false;
  20949. var validatedValue;
  20950. handsontable({
  20951. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20952. allowInvalid: false,
  20953. validator: function validator(value, callback) {
  20954. setTimeout(function () {
  20955. validated = true;
  20956. validatedValue = value;
  20957. callback(true);
  20958. }, 100);
  20959. }
  20960. });
  20961. selectCell(0, 0);
  20962. keyDown('enter');
  20963. document.activeElement.value = 'Ted';
  20964. selectCell(0, 1);
  20965. setTimeout(function () {
  20966. expect(validatedValue).toEqual('Ted');
  20967. done();
  20968. }, 200);
  20969. });
  20970. it('should leave the new value in editor if it does not validate (async validation), after hitting ENTER', function (done) {
  20971. var validated = false;
  20972. var validationResult;
  20973. handsontable({
  20974. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20975. allowInvalid: false,
  20976. validator: function validator(value, callback) {
  20977. setTimeout(function () {
  20978. validated = true;
  20979. validationResult = value.length == 2;
  20980. callback(validationResult);
  20981. }, 100);
  20982. }
  20983. });
  20984. selectCell(0, 0);
  20985. keyDown('enter');
  20986. document.activeElement.value = 'Ted';
  20987. keyDown('enter');
  20988. setTimeout(function () {
  20989. expect(validationResult).toBe(false);
  20990. expect(document.activeElement.value).toEqual('Ted');
  20991. done();
  20992. }, 200);
  20993. });
  20994. it('should leave the new value in editor if it does not validate (sync validation), after hitting ENTER', function (done) {
  20995. var validated = false;
  20996. var validationResult;
  20997. handsontable({
  20998. data: Handsontable.helper.createSpreadsheetData(5, 2),
  20999. allowInvalid: false,
  21000. validator: function validator(value, callback) {
  21001. validated = true;
  21002. validationResult = value.length == 2;
  21003. callback(validationResult);
  21004. }
  21005. });
  21006. selectCell(0, 0);
  21007. keyDown('enter');
  21008. document.activeElement.value = 'Ted';
  21009. keyDown('enter');
  21010. setTimeout(function () {
  21011. expect(validationResult).toBe(false);
  21012. expect(document.activeElement.value).toEqual('Ted');
  21013. done();
  21014. }, 200);
  21015. });
  21016. it('should leave the new value in editor if it does not validate (async validation), after selecting another cell', function (done) {
  21017. var validated = false;
  21018. var validationResult;
  21019. handsontable({
  21020. data: Handsontable.helper.createSpreadsheetData(5, 2),
  21021. allowInvalid: false,
  21022. validator: function validator(value, callback) {
  21023. setTimeout(function () {
  21024. setTimeout(function () {
  21025. validated = true;
  21026. }, 0);
  21027. validationResult = value.length == 2;
  21028. callback(validationResult);
  21029. }, 100);
  21030. }
  21031. });
  21032. selectCell(0, 0);
  21033. keyDown('enter');
  21034. document.activeElement.value = 'Ted';
  21035. selectCell(1, 0);
  21036. setTimeout(function () {
  21037. expect(validationResult).toBe(false);
  21038. expect(document.activeElement.value).toEqual('Ted');
  21039. done();
  21040. }, 200);
  21041. });
  21042. it('should leave the new value in editor if it does not validate (sync validation), after selecting another cell', function (done) {
  21043. var validated = false;
  21044. var validationResult;
  21045. handsontable({
  21046. data: Handsontable.helper.createSpreadsheetData(5, 2),
  21047. allowInvalid: false,
  21048. validator: function validator(value, callback) {
  21049. validationResult = value.length == 2;
  21050. callback(validationResult);
  21051. /* Setting this variable has to be async, because we are not interested in when the validation happens, but when
  21052. the callback is being called. Since internally all the callbacks are processed asynchronously (even if they are
  21053. synchronous) end of validator function is not the equivalent of whole validation routine end.
  21054. If it still sounds weird, take a look at HandsontableTextEditorClass.prototype.finishEditing method.
  21055. */
  21056. setTimeout(function () {
  21057. validated = true;
  21058. }, 0);
  21059. }
  21060. });
  21061. selectCell(0, 0);
  21062. keyDown('enter');
  21063. document.activeElement.value = 'Ted';
  21064. selectCell(1, 0);
  21065. setTimeout(function () {
  21066. expect(validationResult).toBe(false);
  21067. expect(document.activeElement.value).toEqual('Ted');
  21068. done();
  21069. }, 200);
  21070. });
  21071. it('should close the editor and save the new value if validation fails and allowInvalid is set to "true"', function (done) {
  21072. var validated = false;
  21073. var validationResult;
  21074. handsontable({
  21075. data: Handsontable.helper.createSpreadsheetData(5, 2),
  21076. allowInvalid: true,
  21077. validator: function validator(value, callback) {
  21078. setTimeout(function () {
  21079. validated = true;
  21080. validationResult = value.length == 2;
  21081. callback(validationResult);
  21082. }, 100);
  21083. }
  21084. });
  21085. selectCell(0, 0);
  21086. keyDown('enter');
  21087. document.activeElement.value = 'Ted';
  21088. selectCell(1, 0);
  21089. setTimeout(function () {
  21090. expect(validationResult).toBe(false);
  21091. expect(getDataAtCell(0, 0)).toEqual('Ted');
  21092. expect(getCell(0, 0).className).toMatch(/htInvalid/);
  21093. done();
  21094. }, 200);
  21095. });
  21096. it('should close the editor and save the new value after double clicking on a cell, if the previously edited cell validated correctly', function (done) {
  21097. var validated = false;
  21098. var validationResult;
  21099. handsontable({
  21100. data: Handsontable.helper.createSpreadsheetData(5, 2),
  21101. allowInvalid: false,
  21102. validator: function validator(value, callback) {
  21103. setTimeout(function () {
  21104. validated = true;
  21105. validationResult = value.length == 2;
  21106. callback(validationResult);
  21107. }, 100);
  21108. }
  21109. });
  21110. selectCell(0, 0);
  21111. keyDown('enter');
  21112. var editor = $('.handsontableInputHolder');
  21113. expect(editor.is(':visible')).toBe(true);
  21114. document.activeElement.value = 'AA';
  21115. expect(document.activeElement.value).toEqual('AA');
  21116. var cell = $(getCell(1, 0));
  21117. var clicks = 0;
  21118. setTimeout(function () {
  21119. mouseDown(cell);
  21120. mouseUp(cell);
  21121. clicks++;
  21122. }, 0);
  21123. setTimeout(function () {
  21124. mouseDown(cell);
  21125. mouseUp(cell);
  21126. clicks++;
  21127. }, 100);
  21128. setTimeout(function () {
  21129. expect(editor.is(':visible')).toBe(false);
  21130. expect(validationResult).toBe(true);
  21131. expect(getDataAtCell(0, 0)).toEqual('AA');
  21132. done();
  21133. }, 300);
  21134. });
  21135. it('should close the editor and restore the original value after double clicking on a cell, if the previously edited cell have not validated', function (done) {
  21136. var validated = false;
  21137. var validationResult;
  21138. handsontable({
  21139. data: Handsontable.helper.createSpreadsheetData(5, 2),
  21140. allowInvalid: false,
  21141. validator: function validator(value, callback) {
  21142. setTimeout(function () {
  21143. validated = true;
  21144. validationResult = value.length == 2;
  21145. callback(validationResult);
  21146. }, 100);
  21147. }
  21148. });
  21149. selectCell(0, 0);
  21150. keyDown('enter');
  21151. document.activeElement.value = 'AAA';
  21152. expect(document.activeElement.value).toEqual('AAA');
  21153. var cell = $(getCell(1, 0));
  21154. var clicks = 0;
  21155. setTimeout(function () {
  21156. mouseDown(cell);
  21157. mouseUp(cell);
  21158. clicks++;
  21159. }, 0);
  21160. setTimeout(function () {
  21161. mouseDown(cell);
  21162. mouseUp(cell);
  21163. clicks++;
  21164. }, 100);
  21165. setTimeout(function () {
  21166. expect(validationResult).toBe(false);
  21167. expect(getDataAtCell(0, 0)).toEqual('A1');
  21168. done();
  21169. }, 300);
  21170. });
  21171. it('should listen to key changes after cell is corrected (allowInvalid: false)', function (done) {
  21172. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21173. handsontable({
  21174. data: arrayOfObjects(),
  21175. allowInvalid: false,
  21176. columns: [{ data: 'id',
  21177. type: 'numeric',
  21178. validator: function validator(val, cb) {
  21179. cb(parseInt(val, 10) > 100);
  21180. }
  21181. }, { data: 'name' }, { data: 'lastName' }],
  21182. afterValidate: onAfterValidate
  21183. });
  21184. selectCell(2, 0);
  21185. keyDownUp('enter');
  21186. document.activeElement.value = '99';
  21187. onAfterValidate.calls.reset();
  21188. keyDownUp('enter'); // should be ignored
  21189. setTimeout(function () {
  21190. expect(isEditorVisible()).toBe(true);
  21191. document.activeElement.value = '999';
  21192. onAfterValidate.calls.reset();
  21193. keyDownUp('enter'); // should be accepted
  21194. }, 200);
  21195. setTimeout(function () {
  21196. expect(isEditorVisible()).toBe(false);
  21197. expect(getSelected()).toEqual([3, 0, 3, 0]);
  21198. keyDownUp('arrow_up');
  21199. expect(getSelected()).toEqual([2, 0, 2, 0]);
  21200. done();
  21201. }, 400);
  21202. });
  21203. it('should allow keyboard movement when cell is being validated (move DOWN)', function (done) {
  21204. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21205. handsontable({
  21206. data: arrayOfObjects(),
  21207. allowInvalid: false,
  21208. columns: [{ data: 'id',
  21209. type: 'numeric',
  21210. validator: function validator(val, cb) {
  21211. setTimeout(function () {
  21212. cb(parseInt(val, 10) > 100);
  21213. }, 100);
  21214. }
  21215. }, { data: 'name' }, { data: 'lastName' }],
  21216. afterValidate: onAfterValidate
  21217. });
  21218. selectCell(2, 0);
  21219. keyDownUp('enter');
  21220. document.activeElement.value = '999';
  21221. keyDownUp('enter');
  21222. expect(getSelected()).toEqual([3, 0, 3, 0]);
  21223. keyDownUp('arrow_down');
  21224. keyDownUp('arrow_down');
  21225. expect(isEditorVisible()).toBe(true);
  21226. expect(getSelected()).toEqual([5, 0, 5, 0]);
  21227. setTimeout(function () {
  21228. expect(isEditorVisible()).toBe(false);
  21229. expect(getSelected()).toEqual([5, 0, 5, 0]); // only enterMove and first arrow_down is performed
  21230. done();
  21231. }, 200);
  21232. });
  21233. it('should not allow keyboard movement until cell is validated (move UP)', function (done) {
  21234. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21235. handsontable({
  21236. data: arrayOfObjects(),
  21237. allowInvalid: false,
  21238. columns: [{ data: 'id',
  21239. type: 'numeric',
  21240. validator: function validator(val, cb) {
  21241. setTimeout(function () {
  21242. cb(parseInt(val, 10) > 100);
  21243. }, 100);
  21244. }
  21245. }, { data: 'name' }, { data: 'lastName' }],
  21246. afterValidate: onAfterValidate
  21247. });
  21248. selectCell(2, 0);
  21249. keyDownUp('enter');
  21250. document.activeElement.value = '999';
  21251. keyDownUp('enter');
  21252. expect(getSelected()).toEqual([3, 0, 3, 0]);
  21253. keyDownUp('arrow_up');
  21254. keyDownUp('arrow_up');
  21255. expect(isEditorVisible()).toBe(true);
  21256. expect(getSelected()).toEqual([1, 0, 1, 0]);
  21257. setTimeout(function () {
  21258. expect(isEditorVisible()).toBe(false);
  21259. expect(getSelected()).toEqual([1, 0, 1, 0]);
  21260. done();
  21261. }, 200);
  21262. });
  21263. it('should not allow keyboard movement until cell is validated (move RIGHT)', function (done) {
  21264. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21265. handsontable({
  21266. data: arrayOfObjects(),
  21267. allowInvalid: false,
  21268. columns: [{ data: 'id',
  21269. type: 'numeric',
  21270. validator: function validator(val, cb) {
  21271. setTimeout(function () {
  21272. cb(parseInt(val, 10) > 100);
  21273. }, 100);
  21274. }
  21275. }, { data: 'name' }, { data: 'lastName' }],
  21276. afterValidate: onAfterValidate
  21277. });
  21278. selectCell(2, 0);
  21279. keyDownUp('enter');
  21280. document.activeElement.value = '999';
  21281. keyDownUp('enter'); // should be accepted but only after 100 ms
  21282. expect(getSelected()).toEqual([3, 0, 3, 0]);
  21283. keyDownUp('arrow_right');
  21284. keyDownUp('arrow_right');
  21285. expect(isEditorVisible()).toBe(true);
  21286. expect(getSelected()).toEqual([3, 2, 3, 2]);
  21287. setTimeout(function () {
  21288. expect(isEditorVisible()).toBe(false);
  21289. expect(getSelected()).toEqual([3, 2, 3, 2]);
  21290. done();
  21291. }, 200);
  21292. });
  21293. it('should not allow keyboard movement until cell is validated (move LEFT)', function (done) {
  21294. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21295. hot = handsontable({
  21296. data: arrayOfObjects(),
  21297. allowInvalid: false,
  21298. columns: [{ data: 'name' }, { data: 'lastName' }, { data: 'id',
  21299. type: 'numeric',
  21300. validator: function validator(val, cb) {
  21301. setTimeout(function () {
  21302. cb(parseInt(val, 10) > 100);
  21303. }, 100);
  21304. }
  21305. }],
  21306. afterValidate: onAfterValidate
  21307. });
  21308. selectCell(2, 2);
  21309. keyDownUp('enter');
  21310. document.activeElement.value = '999';
  21311. keyDownUp('enter'); // should be accepted but only after 100 ms
  21312. expect(getSelected()).toEqual([3, 2, 3, 2]);
  21313. this.$container.simulate('keydown', { keyCode: Handsontable.helper.KEY_CODES.ARROW_LEFT });
  21314. this.$container.simulate('keyup', { keyCode: Handsontable.helper.KEY_CODES.ARROW_LEFT });
  21315. this.$container.simulate('keydown', { keyCode: Handsontable.helper.KEY_CODES.ARROW_LEFT });
  21316. this.$container.simulate('keyup', { keyCode: Handsontable.helper.KEY_CODES.ARROW_LEFT });
  21317. expect(isEditorVisible()).toBe(true);
  21318. expect(getSelected()).toEqual([3, 0, 3, 0]);
  21319. setTimeout(function () {
  21320. expect(isEditorVisible()).toBe(false);
  21321. expect(getSelected()).toEqual([3, 0, 3, 0]);
  21322. done();
  21323. }, 200);
  21324. });
  21325. it('should not validate cell if editing has been canceled', function (done) {
  21326. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21327. handsontable({
  21328. data: arrayOfObjects(),
  21329. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }],
  21330. afterValidate: onAfterValidate
  21331. });
  21332. selectCell(0, 0);
  21333. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21334. keyDownUp(Handsontable.helper.KEY_CODES.ESCAPE); // cancel editing
  21335. setTimeout(function () {
  21336. expect(onAfterValidate).not.toHaveBeenCalled();
  21337. done();
  21338. }, 100);
  21339. });
  21340. it('should not validate cell if editing has been canceled when columns is a function', function (done) {
  21341. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21342. handsontable({
  21343. data: arrayOfObjects(),
  21344. columns: function columns(column) {
  21345. var colMeta = null;
  21346. if (column === 0) {
  21347. colMeta = { data: 'id' };
  21348. } else if (column === 1) {
  21349. colMeta = { data: 'name' };
  21350. } else if (column === 2) {
  21351. colMeta = { data: 'lastName' };
  21352. }
  21353. return colMeta;
  21354. },
  21355. afterValidate: onAfterValidate
  21356. });
  21357. selectCell(0, 0);
  21358. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21359. keyDownUp(Handsontable.helper.KEY_CODES.ESCAPE); // cancel editing
  21360. setTimeout(function () {
  21361. expect(onAfterValidate).not.toHaveBeenCalled();
  21362. done();
  21363. }, 100);
  21364. });
  21365. it('should leave cell invalid if editing has been canceled', function (done) {
  21366. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21367. handsontable({
  21368. data: arrayOfObjects(),
  21369. columns: [{ data: 'id',
  21370. validator: function validator(value, cb) {
  21371. cb(false);
  21372. }
  21373. }, { data: 'name' }, { data: 'lastName' }],
  21374. afterValidate: onAfterValidate
  21375. });
  21376. setDataAtCell(0, 0, 'foo');
  21377. setTimeout(function () {
  21378. expect(getCellMeta(0, 0).valid).toBe(false);
  21379. selectCell(0, 0);
  21380. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21381. keyDownUp(Handsontable.helper.KEY_CODES.ESCAPE); // cancel editing
  21382. expect(getCellMeta(0, 0).valid).toBe(false);
  21383. done();
  21384. }, 200);
  21385. });
  21386. it('should leave cell invalid if editing has been canceled when columns is a function', function (done) {
  21387. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21388. handsontable({
  21389. data: arrayOfObjects(),
  21390. columns: function columns(column) {
  21391. var colMeta = null;
  21392. if (column === 0) {
  21393. colMeta = {
  21394. data: 'id',
  21395. validator: function validator(value, cb) {
  21396. cb(false);
  21397. }
  21398. };
  21399. } else if (column === 1) {
  21400. colMeta = { data: 'name' };
  21401. } else if (column === 2) {
  21402. colMeta = { data: 'lastName' };
  21403. }
  21404. return colMeta;
  21405. },
  21406. afterValidate: onAfterValidate
  21407. });
  21408. setDataAtCell(0, 0, 'foo');
  21409. setTimeout(function () {
  21410. expect(getCellMeta(0, 0).valid).toBe(false);
  21411. selectCell(0, 0);
  21412. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21413. keyDownUp(Handsontable.helper.KEY_CODES.ESCAPE); // cancel editing
  21414. expect(getCellMeta(0, 0).valid).toBe(false);
  21415. done();
  21416. }, 200);
  21417. });
  21418. it('should open an appropriate editor after cell value is valid again', function (done) {
  21419. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21420. var hot = handsontable({
  21421. data: arrayOfObjects(),
  21422. columns: [{
  21423. data: 'id',
  21424. validator: function validator(value, cb) {
  21425. cb(value == parseInt(value, 10));
  21426. },
  21427. allowInvalid: false
  21428. }, { data: 'name' }, { data: 'lastName' }],
  21429. afterValidate: onAfterValidate
  21430. });
  21431. selectCell(0, 0);
  21432. var activeEditor = hot.getActiveEditor();
  21433. expect(activeEditor.row).toEqual(0);
  21434. expect(activeEditor.col).toEqual(0);
  21435. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21436. activeEditor.setValue('foo');
  21437. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // save changes, close editor
  21438. setTimeout(function () {
  21439. onAfterValidate.calls.reset();
  21440. activeEditor = hot.getActiveEditor();
  21441. expect(activeEditor.isOpened()).toBe(true); // value is invalid, so editor stays opened
  21442. expect(activeEditor.row).toEqual(0);
  21443. expect(activeEditor.col).toEqual(0);
  21444. activeEditor.setValue(2);
  21445. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // save changes and move to cell below (row: 1, col: ś0)
  21446. }, 200);
  21447. setTimeout(function () {
  21448. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21449. activeEditor = hot.getActiveEditor();
  21450. expect(activeEditor.row).toEqual(1);
  21451. expect(activeEditor.col).toEqual(0);
  21452. done();
  21453. }, 400);
  21454. });
  21455. it('should open an appropriate editor after cell value is valid again when columns is a function', function (done) {
  21456. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21457. var hot = handsontable({
  21458. data: arrayOfObjects(),
  21459. columns: function columns(column) {
  21460. var colMeta = null;
  21461. if (column === 0) {
  21462. colMeta = {
  21463. data: 'id',
  21464. validator: function validator(value, cb) {
  21465. cb(value == parseInt(value, 10));
  21466. },
  21467. allowInvalid: false
  21468. };
  21469. } else if (column === 1) {
  21470. colMeta = { data: 'name' };
  21471. } else if (column === 2) {
  21472. colMeta = { data: 'lastName' };
  21473. }
  21474. return colMeta;
  21475. },
  21476. afterValidate: onAfterValidate
  21477. });
  21478. selectCell(0, 0);
  21479. var activeEditor = hot.getActiveEditor();
  21480. expect(activeEditor.row).toEqual(0);
  21481. expect(activeEditor.col).toEqual(0);
  21482. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21483. activeEditor.setValue('foo');
  21484. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // save changes, close editor
  21485. setTimeout(function () {
  21486. onAfterValidate.calls.reset();
  21487. activeEditor = hot.getActiveEditor();
  21488. expect(activeEditor.isOpened()).toBe(true); // value is invalid, so editor stays opened
  21489. expect(activeEditor.row).toEqual(0);
  21490. expect(activeEditor.col).toEqual(0);
  21491. activeEditor.setValue(2);
  21492. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // save changes and move to cell below (row: 1, col: ś0)
  21493. }, 200);
  21494. setTimeout(function () {
  21495. keyDownUp(Handsontable.helper.KEY_CODES.ENTER); // open editor
  21496. activeEditor = hot.getActiveEditor();
  21497. expect(activeEditor.row).toEqual(1);
  21498. expect(activeEditor.col).toEqual(0);
  21499. done();
  21500. }, 400);
  21501. });
  21502. it('should call the validation callback only once, when using the validateCells method on a mixed set of data', function (done) {
  21503. var onValidate = jasmine.createSpy('onValidate');
  21504. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21505. var hot = handsontable({
  21506. data: [{ id: 'sth', name: 'Steve' }, { id: 'sth else', name: 'Bob' }],
  21507. columns: [{
  21508. data: 'id',
  21509. validator: function validator(value, cb) {
  21510. cb(value == parseInt(value, 10));
  21511. }
  21512. }, { data: 'name' }],
  21513. afterValidate: onAfterValidate
  21514. });
  21515. hot.validateCells(onValidate);
  21516. setTimeout(function () {
  21517. expect(onValidate).toHaveBeenCalledWith(false);
  21518. expect(onValidate.calls.count()).toEqual(1);
  21519. done();
  21520. }, 200);
  21521. });
  21522. it('should call the validation callback only once, when using the validateCells method on a mixed set of data and when columns is a function', function (done) {
  21523. var onValidate = jasmine.createSpy('onValidate');
  21524. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  21525. var hot = handsontable({
  21526. data: [{ id: 'sth', name: 'Steve' }, { id: 'sth else', name: 'Bob' }],
  21527. columns: function columns(column) {
  21528. var colMeta = null;
  21529. if (column === 0) {
  21530. colMeta = {
  21531. data: 'id',
  21532. validator: function validator(value, cb) {
  21533. cb(value == parseInt(value, 10));
  21534. }
  21535. };
  21536. } else if (column === 1) {
  21537. colMeta = { data: 'name' };
  21538. }
  21539. return colMeta;
  21540. },
  21541. afterValidate: onAfterValidate
  21542. });
  21543. hot.validateCells(onValidate);
  21544. setTimeout(function () {
  21545. expect(onValidate).toHaveBeenCalledWith(false);
  21546. expect(onValidate.calls.count()).toEqual(1);
  21547. done();
  21548. }, 200);
  21549. });
  21550. });
  21551. /***/ }),
  21552. /* 181 */
  21553. /***/ (function(module, exports, __webpack_require__) {
  21554. "use strict";
  21555. describe('Core_view', function () {
  21556. var id = 'testContainer';
  21557. beforeEach(function () {
  21558. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  21559. });
  21560. afterEach(function () {
  21561. if (this.$container) {
  21562. destroy();
  21563. this.$container.remove();
  21564. }
  21565. });
  21566. it('should focus cell after viewport is scrolled using down arrow', function () {
  21567. this.$container[0].style.width = '400px';
  21568. this.$container[0].style.height = '60px';
  21569. handsontable({
  21570. startRows: 20
  21571. });
  21572. selectCell(0, 0);
  21573. keyDown('arrow_down');
  21574. keyDown('arrow_down');
  21575. keyDown('arrow_down');
  21576. keyDown('arrow_down');
  21577. expect(getSelected()).toEqual([4, 0, 4, 0]);
  21578. keyDown('enter');
  21579. expect(isEditorVisible()).toEqual(true);
  21580. });
  21581. it('should not render "undefined" class name', function () {
  21582. this.$container[0].style.width = '501px';
  21583. this.$container[0].style.height = '100px';
  21584. this.$container[0].style.overflow = 'hidden';
  21585. var hot = handsontable({
  21586. startRows: 10,
  21587. startCols: 5,
  21588. colWidths: [47, 47, 47, 47, 47],
  21589. rowHeaders: true,
  21590. colHeaders: true,
  21591. stretchH: 'all'
  21592. });
  21593. selectCell(0, 0);
  21594. expect(this.$container.find('.undefined').length).toBe(0);
  21595. });
  21596. it('should scroll viewport when partially visible cell is clicked', function () {
  21597. this.$container[0].style.width = '400px';
  21598. this.$container[0].style.height = '60px';
  21599. var hot = handsontable({
  21600. data: Handsontable.helper.createSpreadsheetData(10, 3),
  21601. height: 60
  21602. });
  21603. var htCore = getHtCore();
  21604. var scrollTop = hot.rootElement.querySelector('.wtHolder').scrollTop;
  21605. expect(scrollTop).toBe(0);
  21606. expect(this.$container.height()).toEqual(60);
  21607. expect(this.$container.find('.wtHolder .wtHider').height()).toBeGreaterThan(60);
  21608. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21609. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21610. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21611. htCore.find('tr:eq(3) td:eq(0)').simulate('mousedown');
  21612. expect(hot.rootElement.querySelector('.wtHolder').scrollTop).toBeGreaterThan(scrollTop);
  21613. expect(getSelected()).toEqual([3, 0, 3, 0]);
  21614. });
  21615. it('should scroll viewport without cell selection', function () {
  21616. this.$container[0].style.width = '400px';
  21617. var hot1 = handsontable({
  21618. data: Handsontable.helper.createSpreadsheetData(20, 20),
  21619. height: 100
  21620. });
  21621. hot1.scrollViewportTo(10, 10);
  21622. var wtHolder = this.$container.find('.ht_master .wtHolder');
  21623. expect(wtHolder[0].scrollTop).toEqual(230);
  21624. expect(wtHolder[0].scrollLeft).toEqual(500);
  21625. });
  21626. it('should not throw error while scrolling viewport to 0, 0 (empty data)', function () {
  21627. this.$container[0].style.width = '400px';
  21628. var hot1 = handsontable({
  21629. data: [],
  21630. height: 100
  21631. });
  21632. expect(function () {
  21633. hot1.view.scrollViewport({ row: 0, col: 0 });
  21634. }).not.toThrow();
  21635. });
  21636. it('should throw error while scrolling viewport below 0 (empty data)', function () {
  21637. this.$container[0].style.width = '400px';
  21638. var hot1 = handsontable({
  21639. data: [],
  21640. height: 100
  21641. });
  21642. expect(function () {
  21643. hot1.view.scrollViewport({ row: -1, col: 0 });
  21644. }).toThrow();
  21645. expect(function () {
  21646. hot1.view.scrollViewport({ row: 0, col: -1 });
  21647. }).toThrow();
  21648. expect(function () {
  21649. hot1.view.scrollViewport({ row: -1, col: -1 });
  21650. }).toThrow();
  21651. });
  21652. it('should scroll viewport, respecting fixed rows', function () {
  21653. this.$container[0].style.width = '400px';
  21654. this.$container[0].style.height = '60px';
  21655. var hot = handsontable({
  21656. data: Handsontable.helper.createSpreadsheetData(10, 9),
  21657. fixedRowsTop: 1,
  21658. height: 60
  21659. });
  21660. var htCore = getHtCore();
  21661. var scrollTop = hot.rootElement.querySelector('.wtHolder').scrollTop;
  21662. expect(scrollTop).toBe(0);
  21663. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21664. expect(htCore.find('tr:eq(0) td:eq(1)').html()).toEqual('B1');
  21665. expect(htCore.find('tr:eq(0) td:eq(2)').html()).toEqual('C1');
  21666. selectCell(0, 0);
  21667. keyDown('arrow_down');
  21668. keyDown('arrow_down');
  21669. keyDown('arrow_down');
  21670. keyDown('arrow_down');
  21671. expect(hot.rootElement.querySelector('.wtHolder').scrollTop).toBeGreaterThan(scrollTop);
  21672. });
  21673. it('should enable to change fixedRowsTop with updateSettings', function () {
  21674. this.$container[0].style.width = '400px';
  21675. this.$container[0].style.height = '60px';
  21676. var HOT = handsontable({
  21677. data: Handsontable.helper.createSpreadsheetData(10, 9),
  21678. fixedRowsTop: 1,
  21679. width: 200,
  21680. height: 100
  21681. });
  21682. selectCell(0, 0);
  21683. var htCore = getHtCore();
  21684. var topClone = getTopClone();
  21685. expect(topClone.find('tr').length).toEqual(1);
  21686. expect(topClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21687. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21688. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21689. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21690. expect(htCore.find('tr:eq(3) td:eq(0)').html()).toEqual('A4');
  21691. keyDown('arrow_down');
  21692. keyDown('arrow_down');
  21693. keyDown('arrow_down');
  21694. keyDown('arrow_down');
  21695. expect(topClone.find('tr').length).toEqual(1);
  21696. expect(topClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21697. HOT.updateSettings({
  21698. fixedRowsTop: 2
  21699. });
  21700. expect(topClone.find('tr').length).toEqual(2);
  21701. expect(topClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21702. expect(topClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21703. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21704. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21705. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21706. expect(htCore.find('tr:eq(3) td:eq(0)').html()).toEqual('A4');
  21707. });
  21708. it('should scroll viewport, respecting fixed columns', function () {
  21709. this.$container[0].style.width = '200px';
  21710. this.$container[0].style.height = '100px';
  21711. handsontable({
  21712. data: Handsontable.helper.createSpreadsheetData(10, 9),
  21713. fixedColumnsLeft: 1
  21714. });
  21715. var htCore = getHtCore();
  21716. var leftClone = this.$container.find('.ht_clone_left');
  21717. expect(leftClone.find('tr:eq(0) td').length).toEqual(1);
  21718. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21719. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21720. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21721. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21722. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21723. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21724. selectCell(0, 3);
  21725. keyDown('arrow_right');
  21726. keyDown('arrow_right');
  21727. keyDown('arrow_right');
  21728. keyDown('arrow_right');
  21729. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21730. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21731. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21732. });
  21733. it('should enable to change fixedColumnsLeft with updateSettings', function () {
  21734. this.$container[0].style.width = '200px';
  21735. this.$container[0].style.height = '100px';
  21736. var HOT = handsontable({
  21737. data: Handsontable.helper.createSpreadsheetData(10, 9),
  21738. fixedColumnsLeft: 1
  21739. });
  21740. selectCell(0, 0);
  21741. var leftClone = this.$container.find('.ht_clone_left');
  21742. expect(leftClone.find('tr:eq(0) td').length).toEqual(1);
  21743. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21744. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21745. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21746. keyDown('arrow_right');
  21747. keyDown('arrow_right');
  21748. keyDown('arrow_right');
  21749. keyDown('arrow_right');
  21750. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21751. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21752. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21753. selectCell(0, 0);
  21754. HOT.updateSettings({
  21755. fixedColumnsLeft: 2
  21756. });
  21757. expect(leftClone.find('tr:eq(0) td').length).toEqual(2);
  21758. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  21759. expect(leftClone.find('tr:eq(0) td:eq(1)').html()).toEqual('B1');
  21760. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  21761. expect(leftClone.find('tr:eq(1) td:eq(1)').html()).toEqual('B2');
  21762. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  21763. expect(leftClone.find('tr:eq(2) td:eq(1)').html()).toEqual('B3');
  21764. });
  21765. it('should not scroll viewport when last cell is clicked', function () {
  21766. handsontable({
  21767. startRows: 40
  21768. });
  21769. var lastScroll;
  21770. $(window).scrollTop(10000);
  21771. lastScroll = $(window).scrollTop();
  21772. render(); // renders synchronously so we don't have to put stuff in waits/runs
  21773. selectCell(39, 0);
  21774. expect($(window).scrollTop()).toEqual(lastScroll);
  21775. keyDown('arrow_right');
  21776. expect(getSelected()).toEqual([39, 1, 39, 1]);
  21777. expect($(window).scrollTop()).toEqual(lastScroll);
  21778. });
  21779. it('should not shrink table when width and height is not specified for container', function (done) {
  21780. var initHeight;
  21781. this.$container[0].style.overflow = 'hidden';
  21782. this.$container.wrap('<div style="width: 50px;"></div>');
  21783. handsontable({
  21784. startRows: 10,
  21785. startCols: 10
  21786. });
  21787. setTimeout(function () {
  21788. initHeight = spec().$container.height();
  21789. }, 250);
  21790. setTimeout(function () {
  21791. expect(spec().$container.height()).toEqual(initHeight);
  21792. done();
  21793. }, 500);
  21794. });
  21795. it('should allow height to be a number', function () {
  21796. handsontable({
  21797. startRows: 10,
  21798. startCols: 10,
  21799. height: 107
  21800. });
  21801. expect(this.$container.height()).toEqual(107);
  21802. });
  21803. it('should allow height to be a function', function () {
  21804. handsontable({
  21805. startRows: 10,
  21806. startCols: 10,
  21807. height: function height() {
  21808. return 107;
  21809. }
  21810. });
  21811. expect(this.$container.height()).toEqual(107);
  21812. });
  21813. it('should allow width to be a number', function () {
  21814. handsontable({
  21815. startRows: 10,
  21816. startCols: 10,
  21817. width: 107
  21818. });
  21819. expect(this.$container.width()).toEqual(107); // rootElement is full width but this should do the trick
  21820. });
  21821. it('should allow width to be a function', function () {
  21822. handsontable({
  21823. startRows: 10,
  21824. startCols: 10,
  21825. width: function width() {
  21826. return 107;
  21827. }
  21828. });
  21829. expect(this.$container.width()).toEqual(107); // rootElement is full width but this should do the trick
  21830. });
  21831. it('should fire beforeRender event after table has been scrolled', function (done) {
  21832. this.$container[0].style.width = '400px';
  21833. this.$container[0].style.height = '60px';
  21834. this.$container[0].style.overflow = 'hidden';
  21835. var hot = handsontable({
  21836. data: Handsontable.helper.createSpreadsheetData(100, 3)
  21837. });
  21838. var beforeRenderCallback = jasmine.createSpy('beforeRenderCallback');
  21839. hot.addHook('beforeRender', beforeRenderCallback);
  21840. this.$container.find('.ht_master .wtHolder').scrollTop(1000);
  21841. setTimeout(function () {
  21842. expect(beforeRenderCallback.calls.count()).toBe(1);
  21843. done();
  21844. }, 200);
  21845. });
  21846. it('should fire afterRender event after table has been scrolled', function (done) {
  21847. this.$container[0].style.width = '400px';
  21848. this.$container[0].style.height = '60px';
  21849. this.$container[0].style.overflow = 'hidden';
  21850. var hot = handsontable({
  21851. data: Handsontable.helper.createSpreadsheetData(20, 3)
  21852. });
  21853. var afterRenderCallback = jasmine.createSpy('afterRenderCallback');
  21854. hot.addHook('afterRender', afterRenderCallback);
  21855. this.$container.find('.ht_master .wtHolder').first().scrollTop(1000);
  21856. setTimeout(function () {
  21857. expect(afterRenderCallback.calls.count()).toBe(1);
  21858. done();
  21859. }, 200);
  21860. });
  21861. it('should fire afterRender event after table physically rendered', function (done) {
  21862. this.$container[0].style.width = '400px';
  21863. this.$container[0].style.height = '60px';
  21864. this.$container[0].style.overflow = 'hidden';
  21865. var hot = handsontable({
  21866. data: Handsontable.helper.createSpreadsheetData(20, 3)
  21867. });
  21868. hot.addHook('afterRender', function () {
  21869. hot.view.wt.wtTable.holder.style.overflow = 'scroll';
  21870. hot.view.wt.wtTable.holder.style.width = '220px';
  21871. });
  21872. this.$container.find('.ht_master .wtHolder').first().scrollTop(1000);
  21873. setTimeout(function () {
  21874. // after afterRender hook triggered element style shouldn't changed
  21875. expect(hot.view.wt.wtTable.holder.style.overflow).toBe('scroll');
  21876. expect(hot.view.wt.wtTable.holder.style.width).toBe('220px');
  21877. done();
  21878. }, 100);
  21879. });
  21880. // TODO fix these tests - https://github.com/handsontable/handsontable/issues/1559
  21881. describe('maximumVisibleElementWidth', function () {
  21882. it('should return maximum width until right edge of the viewport', function () {
  21883. var hot = handsontable({
  21884. startRows: 2,
  21885. startCols: 10,
  21886. width: 100,
  21887. height: 100
  21888. });
  21889. expect(hot.view.maximumVisibleElementWidth(0)).toEqual(100);
  21890. });
  21891. it('should return maximum width until right edge of the viewport (excluding the scrollbar)', function () {
  21892. var hot = handsontable({
  21893. startRows: 10,
  21894. startCols: 10,
  21895. width: 100,
  21896. height: 100
  21897. });
  21898. expect(hot.view.maximumVisibleElementWidth(200)).toBeLessThan(100);
  21899. });
  21900. });
  21901. describe('maximumVisibleElementHeight', function () {
  21902. it('should return maximum height until bottom edge of the viewport', function () {
  21903. var hot = handsontable({
  21904. startRows: 10,
  21905. startCols: 2,
  21906. width: 120,
  21907. height: 100
  21908. });
  21909. expect(hot.view.maximumVisibleElementHeight(0)).toEqual(100);
  21910. });
  21911. it('should return maximum height until bottom edge of the viewport (excluding the scrollbar)', function () {
  21912. var hot = handsontable({
  21913. startRows: 10,
  21914. startCols: 10,
  21915. width: 120,
  21916. height: 100
  21917. });
  21918. expect(hot.view.maximumVisibleElementHeight()).toBeLessThan(100);
  21919. });
  21920. });
  21921. describe('fixed column row heights', function () {
  21922. it('should be the same as the row heights in the main table', function () {
  21923. var hot = handsontable({
  21924. data: [['A', 'B', 'C', 'D'], ['a', 'b', 'c\nc', 'd'], ['aa', 'bb', 'cc', 'dd']],
  21925. startRows: 3,
  21926. startCols: 4,
  21927. fixedColumnsLeft: 2
  21928. });
  21929. expect(hot.getCell(1, 2).clientHeight).toEqual(hot.getCell(1, 1).clientHeight);
  21930. hot.setDataAtCell(1, 2, 'c');
  21931. expect(hot.getCell(1, 2).clientHeight).toEqual(hot.getCell(1, 1).clientHeight);
  21932. });
  21933. it('should be the same as the row heights in the main table (after scroll)', function () {
  21934. var myData = Handsontable.helper.createSpreadsheetData(20, 4);
  21935. myData[1][3] = 'very\nlong\ntext';
  21936. myData[5][3] = 'very\nlong\ntext';
  21937. myData[10][3] = 'very\nlong\ntext';
  21938. myData[15][3] = 'very\nlong\ntext';
  21939. var hot = handsontable({
  21940. data: myData,
  21941. startRows: 3,
  21942. startCols: 4,
  21943. fixedRowsTop: 2,
  21944. fixedColumnsLeft: 2,
  21945. width: 200,
  21946. height: 200
  21947. });
  21948. var mainHolder = hot.view.wt.wtTable.holder;
  21949. $(mainHolder).scrollTop(200);
  21950. hot.render();
  21951. var masterTD = this.$container.find('.ht_master tbody tr:eq(5) td:eq(1)')[0];
  21952. var cloneTD = this.$container.find('.ht_clone_left tbody tr:eq(5) td:eq(1)')[0];
  21953. expect(cloneTD.clientHeight).toEqual(masterTD.clientHeight);
  21954. });
  21955. it('should be the same as the row heights in the main table (after scroll, in corner)', function () {
  21956. var myData = Handsontable.helper.createSpreadsheetData(20, 4);
  21957. myData[1][3] = 'very\nlong\ntext';
  21958. myData[5][3] = 'very\nlong\ntext';
  21959. myData[10][3] = 'very\nlong\ntext';
  21960. myData[15][3] = 'very\nlong\ntext';
  21961. var hot = handsontable({
  21962. data: myData,
  21963. startRows: 3,
  21964. startCols: 4,
  21965. fixedRowsTop: 2,
  21966. fixedColumnsLeft: 2,
  21967. width: 200,
  21968. height: 200
  21969. });
  21970. var rowHeight = hot.getCell(1, 3).clientHeight;
  21971. var mainHolder = hot.view.wt.wtTable.holder;
  21972. expect(this.$container.find('.ht_clone_top_left_corner tbody tr:eq(1) td:eq(1)')[0].clientHeight).toEqual(rowHeight);
  21973. $(mainHolder).scrollTop(200);
  21974. hot.render();
  21975. expect(this.$container.find('.ht_clone_top_left_corner tbody tr:eq(1) td:eq(1)')[0].clientHeight).toEqual(rowHeight);
  21976. });
  21977. });
  21978. describe('fixed column widths', function () {
  21979. it('should set the columns width correctly after changes made during updateSettings', function () {
  21980. var hot = handsontable({
  21981. startRows: 2,
  21982. fixedColumnsLeft: 2,
  21983. columns: [{
  21984. width: 50
  21985. }, {
  21986. width: 80
  21987. }, {
  21988. width: 110
  21989. }, {
  21990. width: 140
  21991. }, {
  21992. width: 30
  21993. }, {
  21994. width: 30
  21995. }, {
  21996. width: 30
  21997. }]
  21998. });
  21999. var leftClone = this.$container.find('.ht_clone_left');
  22000. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  22001. hot.updateSettings({
  22002. manualColumnMove: [2, 0, 1],
  22003. fixedColumnsLeft: 1
  22004. });
  22005. expect(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0]).toBe(undefined);
  22006. hot.updateSettings({
  22007. manualColumnMove: false,
  22008. fixedColumnsLeft: 2
  22009. });
  22010. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  22011. });
  22012. it('should set the columns width correctly after changes made during updateSettings when columns is a function', function () {
  22013. var hot = handsontable({
  22014. startCols: 7,
  22015. startRows: 2,
  22016. fixedColumnsLeft: 2,
  22017. columns: function columns(column) {
  22018. var colMeta = {};
  22019. if (column === 0) {
  22020. colMeta.width = 50;
  22021. } else if (column === 1) {
  22022. colMeta.width = 80;
  22023. } else if (column === 2) {
  22024. colMeta.width = 110;
  22025. } else if (column === 3) {
  22026. colMeta.width = 140;
  22027. } else if ([4, 5, 6].indexOf(column) > -1) {
  22028. colMeta.width = 30;
  22029. } else {
  22030. colMeta = null;
  22031. }
  22032. return colMeta;
  22033. }
  22034. });
  22035. var leftClone = this.$container.find('.ht_clone_left');
  22036. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  22037. hot.updateSettings({
  22038. manualColumnMove: [2, 0, 1],
  22039. fixedColumnsLeft: 1
  22040. });
  22041. expect(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0]).toBe(undefined);
  22042. hot.updateSettings({
  22043. manualColumnMove: false,
  22044. fixedColumnsLeft: 2
  22045. });
  22046. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  22047. });
  22048. });
  22049. describe('stretchH', function () {
  22050. it('should stretch all visible columns with the ratio appropriate to the container\'s width', function () {
  22051. this.$container[0].style.width = '300px';
  22052. var hot = handsontable({
  22053. startRows: 5,
  22054. startCols: 5,
  22055. rowHeaders: true,
  22056. colHeaders: true,
  22057. stretchH: 'all'
  22058. }),
  22059. rowHeaderWidth = hot.view.wt.wtViewport.getRowHeaderWidth(),
  22060. expectedCellWidth = (parseInt(this.$container[0].style.width, 10) - rowHeaderWidth) / 5;
  22061. expect(getCell(0, 0).offsetWidth).toEqual(expectedCellWidth);
  22062. expect(getCell(0, 1).offsetWidth).toEqual(expectedCellWidth);
  22063. expect(getCell(0, 2).offsetWidth).toEqual(expectedCellWidth);
  22064. expect(getCell(0, 3).offsetWidth).toEqual(expectedCellWidth);
  22065. expect(getCell(0, 4).offsetWidth).toEqual(expectedCellWidth);
  22066. this.$container[0].style.width = '';
  22067. this.$container.wrap('<div class="temp_wrapper" style="width:400px;"></div>');
  22068. hot.render();
  22069. expectedCellWidth = (parseInt($('.temp_wrapper')[0].style.width, 10) - rowHeaderWidth) / 5;
  22070. expect(getCell(0, 0).offsetWidth).toEqual(expectedCellWidth);
  22071. expect(getCell(0, 1).offsetWidth).toEqual(expectedCellWidth);
  22072. expect(getCell(0, 2).offsetWidth).toEqual(expectedCellWidth);
  22073. expect(getCell(0, 3).offsetWidth).toEqual(expectedCellWidth);
  22074. expect(getCell(0, 4).offsetWidth).toEqual(expectedCellWidth);
  22075. this.$container.unwrap();
  22076. });
  22077. it('should stretch all visible columns with overflow hidden', function () {
  22078. this.$container[0].style.width = '501px';
  22079. this.$container[0].style.height = '100px';
  22080. this.$container[0].style.overflow = 'hidden';
  22081. var hot = handsontable({
  22082. startRows: 10,
  22083. startCols: 5,
  22084. colWidths: [47, 47, 47, 47, 47],
  22085. rowHeaders: true,
  22086. colHeaders: true,
  22087. stretchH: 'all'
  22088. });
  22089. var masterTH = this.$container[0].querySelectorAll('.ht_master thead tr th');
  22090. var overlayTH = this.$container[0].querySelectorAll('.ht_clone_top thead tr th');
  22091. expect(masterTH[0].offsetWidth).toEqual(50);
  22092. expect(overlayTH[0].offsetWidth).toEqual(50);
  22093. expect(masterTH[1].offsetWidth).toBeInArray([86, 87, 88, 90]);
  22094. expect(overlayTH[1].offsetWidth).toBeInArray([86, 87, 88, 90]); // if you get 90, it means it is calculated before scrollbars were applied, or show scroll on scrolling is enabled
  22095. expect(masterTH[2].offsetWidth).toEqual(overlayTH[2].offsetWidth);
  22096. expect(masterTH[3].offsetWidth).toEqual(overlayTH[3].offsetWidth);
  22097. expect(masterTH[4].offsetWidth).toEqual(overlayTH[4].offsetWidth);
  22098. expect(masterTH[5].offsetWidth).toEqual(overlayTH[5].offsetWidth);
  22099. });
  22100. it('should respect stretched widths returned in beforeStretchingColumnWidth hook', function () {
  22101. this.$container[0].style.width = '501px';
  22102. this.$container[0].style.height = '100px';
  22103. this.$container[0].style.overflow = 'hidden';
  22104. var callbackSpy = jasmine.createSpy();
  22105. callbackSpy.and.callFake(function (width, column) {
  22106. if (column === 1) {
  22107. return 150;
  22108. }
  22109. return width;
  22110. });
  22111. var hot = handsontable({
  22112. startRows: 2,
  22113. startCols: 5,
  22114. rowHeaders: true,
  22115. colHeaders: true,
  22116. stretchH: 'all',
  22117. beforeStretchingColumnWidth: callbackSpy
  22118. });
  22119. var $columnHeaders = this.$container.find('thead tr:eq(0) th');
  22120. expect($columnHeaders.eq(0).width()).toEqual(48);
  22121. expect($columnHeaders.eq(1).width()).toEqual(73);
  22122. expect($columnHeaders.eq(2).width()).toEqual(149);
  22123. expect($columnHeaders.eq(3).width()).toEqual(74);
  22124. expect($columnHeaders.eq(4).width()).toEqual(74);
  22125. expect(callbackSpy).toHaveBeenCalled();
  22126. // First cycle to check what columns has permanent width
  22127. expect(callbackSpy.calls.argsFor(0)[0]).not.toBeDefined();
  22128. expect(callbackSpy.calls.argsFor(0)[1]).toBe(0);
  22129. expect(callbackSpy.calls.argsFor(1)[0]).not.toBeDefined();
  22130. expect(callbackSpy.calls.argsFor(1)[1]).toBe(1);
  22131. expect(callbackSpy.calls.argsFor(2)[0]).not.toBeDefined();
  22132. expect(callbackSpy.calls.argsFor(2)[1]).toBe(2);
  22133. expect(callbackSpy.calls.argsFor(3)[0]).not.toBeDefined();
  22134. expect(callbackSpy.calls.argsFor(3)[1]).toBe(3);
  22135. expect(callbackSpy.calls.argsFor(4)[0]).not.toBeDefined();
  22136. expect(callbackSpy.calls.argsFor(4)[1]).toBe(4);
  22137. // // Second cycle retrieve stretched width or permanent width
  22138. expect(callbackSpy.calls.argsFor(5)[0]).toBe(75);
  22139. expect(callbackSpy.calls.argsFor(6)[0]).toBe(75);
  22140. expect(callbackSpy.calls.argsFor(7)[0]).toBe(75);
  22141. expect(callbackSpy.calls.argsFor(8)[0]).toBe(75);
  22142. expect(callbackSpy.calls.argsFor(9)[0]).toBe(75);
  22143. });
  22144. });
  22145. });
  22146. /***/ }),
  22147. /* 182 */
  22148. /***/ (function(module, exports, __webpack_require__) {
  22149. "use strict";
  22150. describe('Handsontable.Dom', function () {
  22151. describe('offset', function () {
  22152. var $window = $(window),
  22153. $forceScrollbar = $('<div id="forceScrollbar"></div>').css({
  22154. position: 'absolute',
  22155. height: '4000px',
  22156. width: '4000px',
  22157. top: 0,
  22158. left: 0
  22159. });
  22160. beforeEach(function () {
  22161. $forceScrollbar.appendTo(document.body);
  22162. this.$div = $('<div id="test"></div>').appendTo($forceScrollbar);
  22163. this.div = this.$div[0];
  22164. });
  22165. afterEach(function () {
  22166. this.$div.remove();
  22167. $forceScrollbar.remove();
  22168. });
  22169. describe('top', function () {
  22170. it('should return offset top with position absolute', function () {
  22171. this.$div.css({ position: 'absolute', top: 200 });
  22172. expect(Handsontable.dom.offset(this.div).top).toEqual(200);
  22173. });
  22174. it('should return offset top with position absolute & scrolled window', function () {
  22175. this.$div.css({ position: 'absolute', top: 200 });
  22176. $window.scrollTop(1900);
  22177. expect(Handsontable.dom.offset(this.div).top).toEqual(200);
  22178. $window.scrollTop(0);
  22179. });
  22180. it('should return offset top with position fixed', function () {
  22181. this.$div.css({ position: 'fixed', top: 200 });
  22182. expect(Handsontable.dom.offset(this.div).top).toEqual(200);
  22183. });
  22184. it('should return offset top with position fixed & scrolled window', function () {
  22185. this.$div.css({ position: 'fixed', top: 200 });
  22186. $window.scrollTop(1900);
  22187. expect(Handsontable.dom.offset(this.div).top).toEqual(2100); // this is the same jQuery offset returns
  22188. $window.scrollTop(0);
  22189. });
  22190. });
  22191. describe('left', function () {
  22192. it('should return offset left with position absolute', function () {
  22193. this.$div.css({ position: 'absolute', left: 200 });
  22194. expect(Handsontable.dom.offset(this.div).left).toEqual(200);
  22195. });
  22196. it('should return offset left with position absolute & scrolled window', function () {
  22197. this.$div.css({ position: 'absolute', left: 200 });
  22198. $window.scrollLeft(1900);
  22199. expect(Handsontable.dom.offset(this.div).left).toEqual(200);
  22200. $window.scrollLeft(0);
  22201. });
  22202. it('should return offset left with position fixed', function () {
  22203. this.$div.css({ position: 'fixed', left: 200 });
  22204. expect(Handsontable.dom.offset(this.div).left).toEqual(200);
  22205. });
  22206. it('should return offset left with position fixed & scrolled window', function () {
  22207. this.$div.css({ position: 'fixed', left: 200 });
  22208. $window.scrollLeft(1900);
  22209. expect(Handsontable.dom.offset(this.div).left).toEqual(2100); // this is the same jQuery offset returns
  22210. $window.scrollLeft(0);
  22211. });
  22212. });
  22213. });
  22214. describe('isVisible', function () {
  22215. it('should return true for appended table', function () {
  22216. var $table = $('<table></table>').appendTo('body');
  22217. expect(Handsontable.dom.isVisible($table[0])).toBe(true);
  22218. $table.remove();
  22219. });
  22220. it('should return false for not appended table', function () {
  22221. var $table = $('<table></table>');
  22222. expect(Handsontable.dom.isVisible($table[0])).toBe(false);
  22223. $table.remove();
  22224. });
  22225. it('should return false for table with `display: none`', function () {
  22226. var $table = $('<table style="display: none"></table>').appendTo('body');
  22227. expect(Handsontable.dom.isVisible($table[0])).toBe(false);
  22228. $table.remove();
  22229. });
  22230. it('should return false for table with parent `display: none`', function () {
  22231. var $div = $('<div style="display: none"></div>').appendTo('body');
  22232. var $table = $('<table></table>').appendTo($div);
  22233. expect(Handsontable.dom.isVisible($table[0])).toBe(false);
  22234. $table.remove();
  22235. });
  22236. it('should return false for something detached from DOM', function () {
  22237. var $table = $('<table><tr><td></td></tr></table>').appendTo('body');
  22238. var TD = $table.find('td')[0];
  22239. var TR = TD.parentNode;
  22240. expect(Handsontable.dom.isVisible(TD)).toBe(true);
  22241. TR.parentNode.removeChild(TR);
  22242. expect(Handsontable.dom.isVisible(TD)).toBe(false);
  22243. $table.remove();
  22244. });
  22245. });
  22246. describe('outerHeight', function () {
  22247. it('should return correct outerHeight for table', function () {
  22248. var $table = $('<table style="border-width: 0;"><tbody><tr><td style="border: 1px solid black"><div style="height: 30px">test</div></td>' + '</tr></tbody></table>').appendTo('body');
  22249. expect(Handsontable.dom.outerHeight($table[0])).toBe(38); // this is according to current stylesheet
  22250. expect($table.outerHeight()).toBe(38); // jQuery check to confirm
  22251. $table.remove();
  22252. });
  22253. it('should return correct outerHeight for table (with caption)', function () {
  22254. var $table = $('<table style="border-width: 0;"><caption style="padding: 0; margin:0"><div style="height: 30px">caption</div></caption><tbody>' + '<tr><td style="border: 1px solid black"><div style="height: 30px">test</div></td></tr></tbody></table>').appendTo('body');
  22255. expect(Handsontable.dom.outerHeight($table[0])).toBe(68); // this is according to current stylesheet
  22256. $table.remove();
  22257. });
  22258. });
  22259. it('should return correct offset for table cell (table with caption)', function () {
  22260. var $table = $('<table style="border-width: 0;"><caption style="padding: 0; margin:0"><div style="height: 30px">caption</div></caption><tbody>' + '<tr><td style="border: 1px solid black"><div style="height: 30px">test</div></td></tr></tbody></table>').appendTo('body');
  22261. var tableOffset = Handsontable.dom.offset($table[0]);
  22262. var tdOffset = Handsontable.dom.offset($table.find('td')[0]);
  22263. expect(parseInt(tdOffset.left - tableOffset.left, 10)).toBeAroundValue(2); // this is according to current stylesheet
  22264. expect(parseInt(tdOffset.top - tableOffset.top, 10)).toBeAroundValue(32); // this is according to current stylesheet
  22265. $table.remove();
  22266. });
  22267. it('should return font size', function () {
  22268. var $html = $('<style>.bigText{font: 12px serif;}</style><div class="bigText"><span id="testable"></span></div>').appendTo('body');
  22269. var span = document.getElementById('testable');
  22270. var compStyle = Handsontable.dom.getComputedStyle(span);
  22271. expect(compStyle.fontSize).toBe('12px');
  22272. $html.remove();
  22273. });
  22274. it('should return top border width', function () {
  22275. var $html = $('<style>.redBorder{border: 10px solid red;}</style><div class="redBorder" id="testable"></div>').appendTo('body');
  22276. var div = document.getElementById('testable');
  22277. var compStyle = Handsontable.dom.getComputedStyle(div);
  22278. expect(compStyle.borderTopWidth).toBe('10px');
  22279. $html.remove();
  22280. });
  22281. it('should insert HTML properly', function () {
  22282. var $html = $('<div id="testable"></div>').appendTo('body');
  22283. var text = '<span>test<br>test</span>';
  22284. var div = document.getElementById('testable');
  22285. Handsontable.dom.fastInnerHTML(div, text);
  22286. Handsontable.dom.fastInnerHTML(div, text);
  22287. expect(div.childNodes[0].childNodes.length).toEqual(3);
  22288. $html.remove();
  22289. });
  22290. it('should set the immediatePropagation properties properly for given event', function () {
  22291. var event = document.createEvent('MouseEvents');
  22292. event.initMouseEvent('mousedown', true, true, window, null, null, null, null, null, null, null, null, null, null, null);
  22293. Handsontable.dom.stopImmediatePropagation(event);
  22294. expect(event.isImmediatePropagationEnabled).toBe(false);
  22295. expect(Handsontable.dom.isImmediatePropagationStopped(event)).toBe(true);
  22296. });
  22297. describe('getScrollableElement', function () {
  22298. it('should return scrollable element with \'scroll\' value of \'overflow\', \'overflowX\' or \'overflowY\' property', function () {
  22299. var $html = $(['<div style="overflow: scroll"><span class="overflow"></span></div>', '<div style="overflow-x: scroll"><span class="overflowX"></span></div>', '<div style="overflow-y: scroll"><span class="overflowY"></span></div>'].join('')).appendTo('body');
  22300. expect(Handsontable.dom.getScrollableElement($html.find('.overflow')[0])).toBe($html[0]);
  22301. expect(Handsontable.dom.getScrollableElement($html.find('.overflowX')[0])).toBe($html[1]);
  22302. expect(Handsontable.dom.getScrollableElement($html.find('.overflowY')[0])).toBe($html[2]);
  22303. $html.remove();
  22304. });
  22305. it('should return scrollable element with \'auto\' value of \'overflow\' or \'overflowY\' property', function () {
  22306. var $html = $(['<div style="overflow: auto; height: 50px;"><div class="knob" style="height: 100px"></div></div>', '<div style="overflow-y: auto; height: 50px;"><div class="knob" style="height: 100px"></div></div>', '<div style="overflow-y: auto; height: 50px;">', '<div>', '<div class="knob" style="height: 100px;"></div>', '</div>', '</div>'].join('')).appendTo('body');
  22307. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[0])).toBe($html[0]);
  22308. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[1])).toBe($html[1]);
  22309. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[2])).toBe($html[2]);
  22310. $html.remove();
  22311. });
  22312. it('should return scrollable element with \'auto\' value of \'overflow\' or \'overflowX\' property', function () {
  22313. var $html = $(['<div style="overflow: auto; width: 50px; height: 10px"><div class="knob" style="width: 100px; height: 5px"></div></div>', '<div style="overflow-x: auto; width: 50px; height: 10px"><div class="knob" style="width: 100px; height: 5px"></div></div>', '<div style="overflow-x: auto; width: 50px; height: 10px">', '<div>', '<div class="knob" style="width: 100px; height: 5px"></div>', '</div>', '</div>'].join('')).appendTo('body');
  22314. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[0])).toBe($html[0]);
  22315. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[1])).toBe($html[1]);
  22316. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[2])).toBe($html[2]);
  22317. $html.remove();
  22318. });
  22319. it('should return window object as scrollable element', function () {
  22320. var $html = $(['<div style="overflow: hidden; width: 50px; height: 10px"><div class="knob" style="width: 100px; height: 5px"></div></div>', '<div style="width: 50px; height: 10px"><div class="knob" style="width: 100px; height: 5px"></div></div>'].join('')).appendTo('body');
  22321. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[0])).toBe(window);
  22322. expect(Handsontable.dom.getScrollableElement($html.find('.knob')[1])).toBe(window);
  22323. $html.remove();
  22324. });
  22325. });
  22326. //
  22327. // Handsontable.dom.isChildOfWebComponentTable
  22328. //
  22329. describe('isChildOfWebComponentTable', function () {
  22330. it('should return correct Boolean value depending on whether an element exists in `hot-table` or not', function () {
  22331. // skip if browser not support Shadow DOM natively
  22332. if (!document.createElement('div').createShadowRoot) {
  22333. // Fix for "no exceptations" warnings
  22334. expect(true).toBe(true);
  22335. return;
  22336. }
  22337. var hotTable = document.createElement('hot-table');
  22338. var outsideDiv = document.createElement('div');
  22339. expect(Handsontable.dom.isChildOfWebComponentTable(hotTable)).toBe(true);
  22340. expect(Handsontable.dom.isChildOfWebComponentTable(outsideDiv)).toBe(false);
  22341. var hotTableDiv = document.createElement('div');
  22342. hotTable.appendChild(hotTableDiv);
  22343. expect(Handsontable.dom.isChildOfWebComponentTable(hotTableDiv)).toBe(true);
  22344. var fragment = document.createDocumentFragment();
  22345. expect(Handsontable.dom.isChildOfWebComponentTable(fragment)).toBe(false);
  22346. var myElement = document.createElement('my-element');
  22347. expect(Handsontable.dom.isChildOfWebComponentTable(myElement)).toBe(false);
  22348. var shadowRoot = myElement.createShadowRoot();
  22349. var insideDiv = shadowRoot.appendChild(document.createElement('div'));
  22350. hotTable.createShadowRoot().appendChild(myElement);
  22351. expect(Handsontable.dom.isChildOfWebComponentTable(myElement)).toBe(true);
  22352. expect(Handsontable.dom.isChildOfWebComponentTable(insideDiv)).toBe(true);
  22353. });
  22354. });
  22355. //
  22356. // Handsontable.dom.polymerWrap
  22357. //
  22358. describe('polymerWrap', function () {
  22359. it('should wrap element into polymer wrapper if exists', function () {
  22360. expect(Handsontable.dom.polymerWrap(1)).toBe(1);
  22361. window.wrap = function () {
  22362. return 'wrapped';
  22363. };
  22364. window.Polymer = {};
  22365. expect(Handsontable.dom.polymerWrap(1)).toBe('wrapped');
  22366. // Test https://github.com/handsontable/handsontable/issues/2283
  22367. window.wrap = document.createElement('div');
  22368. expect(Handsontable.dom.polymerWrap(1)).toBe(1);
  22369. delete window.wrap;
  22370. delete window.Polymer;
  22371. });
  22372. });
  22373. //
  22374. // Handsontable.dom.polymerUnwrap
  22375. //
  22376. describe('polymerUnwrap', function () {
  22377. it('should unwrap element from polymer wrapper if exists', function () {
  22378. expect(Handsontable.dom.polymerUnwrap('wrapped')).toBe('wrapped');
  22379. window.unwrap = function () {
  22380. return 1;
  22381. };
  22382. window.Polymer = {};
  22383. expect(Handsontable.dom.polymerUnwrap('wrapped')).toBe(1);
  22384. window.unwrap = document.createElement('div');
  22385. expect(Handsontable.dom.polymerUnwrap('wrapped')).toBe('wrapped');
  22386. delete window.unwrap;
  22387. delete window.Polymer;
  22388. });
  22389. });
  22390. //
  22391. // Handsontable.dom.addClass
  22392. //
  22393. describe('addClass', function () {
  22394. it('should add class names as string to an element', function () {
  22395. var element = document.createElement('div');
  22396. expect(element.className).toBe('');
  22397. Handsontable.dom.addClass(element, 'test');
  22398. expect(element.className).toBe('test');
  22399. Handsontable.dom.addClass(element, 'test test1 test2');
  22400. expect(element.className).toBe('test test1 test2');
  22401. Handsontable.dom.addClass(element, 'test3');
  22402. expect(element.className).toBe('test test1 test2 test3');
  22403. Handsontable.dom.addClass(element, '');
  22404. expect(element.className).toBe('test test1 test2 test3');
  22405. });
  22406. it('should add class names as array to an element', function () {
  22407. var element = document.createElement('div');
  22408. expect(element.className).toBe('');
  22409. Handsontable.dom.addClass(element, ['test']);
  22410. expect(element.className).toBe('test');
  22411. Handsontable.dom.addClass(element, ['test1', 'test2', 'test3']);
  22412. expect(element.className).toBe('test test1 test2 test3');
  22413. Handsontable.dom.addClass(element, 'test4');
  22414. expect(element.className).toBe('test test1 test2 test3 test4');
  22415. Handsontable.dom.addClass(element, '');
  22416. expect(element.className).toBe('test test1 test2 test3 test4');
  22417. });
  22418. });
  22419. //
  22420. // Handsontable.dom.removeClass
  22421. //
  22422. describe('removeClass', function () {
  22423. it('should remove class names as string from an element', function () {
  22424. var element = document.createElement('div');
  22425. element.className = 'test test1 test2 test3 test4';
  22426. Handsontable.dom.removeClass(element, 'not-exists');
  22427. expect(element.className).toBe('test test1 test2 test3 test4');
  22428. Handsontable.dom.removeClass(element, 'test');
  22429. expect(element.className).toBe('test1 test2 test3 test4');
  22430. Handsontable.dom.removeClass(element, 'test test1 test4');
  22431. expect(element.className).toBe('test2 test3');
  22432. Handsontable.dom.removeClass(element, '');
  22433. expect(element.className).toBe('test2 test3');
  22434. });
  22435. it('should remove class names as array from an element', function () {
  22436. var element = document.createElement('div');
  22437. element.className = 'test test1 test2 test3 test4';
  22438. Handsontable.dom.removeClass(element, ['not-exists']);
  22439. expect(element.className).toBe('test test1 test2 test3 test4');
  22440. Handsontable.dom.removeClass(element, ['test']);
  22441. expect(element.className).toBe('test1 test2 test3 test4');
  22442. Handsontable.dom.removeClass(element, ['test', 'test1', 'test4']);
  22443. expect(element.className).toBe('test2 test3');
  22444. Handsontable.dom.removeClass(element, ['test', '', '']);
  22445. expect(element.className).toBe('test2 test3');
  22446. });
  22447. });
  22448. //
  22449. // Handsontable.dom.hasClass
  22450. //
  22451. describe('hasClass', function () {
  22452. it('should checks if an element has passed class name', function () {
  22453. var element = document.createElement('div');
  22454. element.className = 'test test1 test2 test3 test4';
  22455. expect(Handsontable.dom.hasClass(element, 'not-exists')).toBe(false);
  22456. expect(Handsontable.dom.hasClass(element, 'test3')).toBe(true);
  22457. expect(Handsontable.dom.hasClass(element, 'test')).toBe(true);
  22458. expect(Handsontable.dom.hasClass(element, '')).toBe(false);
  22459. });
  22460. });
  22461. });
  22462. /***/ }),
  22463. /* 183 */
  22464. /***/ (function(module, exports, __webpack_require__) {
  22465. "use strict";
  22466. describe('FillHandle', function () {
  22467. var id = 'testContainer';
  22468. beforeEach(function () {
  22469. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  22470. });
  22471. afterEach(function () {
  22472. if (this.$container) {
  22473. destroy();
  22474. this.$container.remove();
  22475. }
  22476. });
  22477. it('should appear when fillHandle equals true', function () {
  22478. handsontable({
  22479. fillHandle: true
  22480. });
  22481. selectCell(2, 2);
  22482. expect(isFillHandleVisible()).toBe(true);
  22483. });
  22484. it('should appear when fillHandle is enabled as `string` value', function () {
  22485. handsontable({
  22486. fillHandle: 'horizontal'
  22487. });
  22488. selectCell(2, 2);
  22489. expect(isFillHandleVisible()).toBe(true);
  22490. });
  22491. it('should not change cell value (drag vertically when fillHandle option is set to `horizontal`)', function () {
  22492. handsontable({
  22493. data: [[1, 2, 3, 4, 5, 6], [7, 8, 9, 1, 2, 3], [4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6]],
  22494. fillHandle: 'horizontal'
  22495. });
  22496. selectCell(0, 0);
  22497. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22498. this.$container.find('tbody tr:eq(1) td:eq(0)').simulate('mouseover').simulate('mouseup');
  22499. expect(getDataAtCell(1, 0)).toEqual(7);
  22500. });
  22501. it('should not change cell value (drag horizontally when fillHandle option is set to `vertical`)', function () {
  22502. handsontable({
  22503. data: [[1, 2, 3, 4, 5, 6], [7, 8, 9, 1, 2, 3], [4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6]],
  22504. fillHandle: 'vertical'
  22505. });
  22506. selectCell(0, 0);
  22507. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22508. this.$container.find('tbody tr:eq(0) td:eq(1)').simulate('mouseover').simulate('mouseup');
  22509. expect(getDataAtCell(0, 1)).toEqual(2);
  22510. });
  22511. it('should work properly when fillHandle option is set to object with property `direction` set to `vertical`)', function () {
  22512. handsontable({
  22513. data: [[1, 2, 3, 4, 5, 6], [7, 8, 9, 1, 2, 3], [4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6]],
  22514. fillHandle: {
  22515. direction: 'vertical'
  22516. }
  22517. });
  22518. selectCell(0, 0);
  22519. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22520. this.$container.find('tbody tr:eq(0) td:eq(1)').simulate('mouseover').simulate('mouseup');
  22521. expect(getDataAtCell(0, 1)).toEqual(2);
  22522. selectCell(0, 0);
  22523. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22524. this.$container.find('tbody tr:eq(1) td:eq(0)').simulate('mouseover').simulate('mouseup');
  22525. expect(getDataAtCell(1, 0)).toEqual(1);
  22526. });
  22527. it('should work properly when fillHandle option is set to object with property `direction` set to `horizontal`)', function () {
  22528. handsontable({
  22529. data: [[1, 2, 3, 4, 5, 6], [7, 8, 9, 1, 2, 3], [4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6]],
  22530. fillHandle: {
  22531. direction: 'horizontal'
  22532. }
  22533. });
  22534. selectCell(0, 0);
  22535. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22536. this.$container.find('tbody tr:eq(0) td:eq(1)').simulate('mouseover').simulate('mouseup');
  22537. expect(getDataAtCell(0, 1)).toEqual(1);
  22538. selectCell(0, 0);
  22539. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22540. this.$container.find('tbody tr:eq(1) td:eq(0)').simulate('mouseover').simulate('mouseup');
  22541. expect(getDataAtCell(1, 0)).toEqual(7);
  22542. });
  22543. it('should not change cell value (drag when fillHandle is set to `false`)', function () {
  22544. handsontable({
  22545. data: [[1, 2, 3, 4, 5, 6], [7, 8, 9, 1, 2, 3], [4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6]],
  22546. fillHandle: false
  22547. });
  22548. // checking drag vertically - should not change cell value
  22549. selectCell(0, 0);
  22550. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22551. this.$container.find('tbody tr:eq(0) td:eq(1)').simulate('mouseover').simulate('mouseup');
  22552. expect(getDataAtCell(0, 1)).toEqual(2);
  22553. // checking drag horizontally - should not change cell value
  22554. selectCell(0, 0);
  22555. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22556. this.$container.find('tbody tr:eq(0) td:eq(1)').simulate('mouseover').simulate('mouseup');
  22557. expect(getDataAtCell(0, 1)).toEqual(2);
  22558. });
  22559. it('should work properly when using updateSettings', function () {
  22560. var hot = handsontable({
  22561. data: [[1, 2, 3, 4, 5, 6], [7, 8, 9, 1, 2, 3], [4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6]],
  22562. fillHandle: 'horizontal'
  22563. });
  22564. updateSettings({ fillHandle: 'vertical' });
  22565. // checking drag vertically - should change cell value
  22566. selectCell(0, 0);
  22567. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22568. this.$container.find('tbody tr:eq(0) td:eq(1)').simulate('mouseover').simulate('mouseup');
  22569. expect(getDataAtCell(0, 1)).toEqual(2);
  22570. updateSettings({ fillHandle: false });
  22571. // checking drag vertically - should not change cell value
  22572. selectCell(0, 1);
  22573. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22574. this.$container.find('tbody tr:eq(1) td:eq(1)').simulate('mouseover').simulate('mouseup');
  22575. expect(getDataAtCell(1, 1)).toEqual(8);
  22576. // checking drag horizontally - should not change cell value
  22577. selectCell(0, 1);
  22578. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22579. this.$container.find('tbody tr:eq(0) td:eq(2)').simulate('mouseover').simulate('mouseup');
  22580. expect(getDataAtCell(0, 2)).toEqual(3);
  22581. });
  22582. it('should appear when fillHandle is enabled as `object` value', function () {
  22583. handsontable({
  22584. fillHandle: {
  22585. allowInsertRow: true
  22586. }
  22587. });
  22588. selectCell(2, 2);
  22589. expect(isFillHandleVisible()).toBe(true);
  22590. });
  22591. it('should not appear when fillHandle equals false', function () {
  22592. handsontable({
  22593. fillHandle: false
  22594. });
  22595. selectCell(2, 2);
  22596. expect(isFillHandleVisible()).toBe(false);
  22597. });
  22598. it('should disappear when beginediting is triggered', function () {
  22599. handsontable({
  22600. fillHandle: true
  22601. });
  22602. selectCell(2, 2);
  22603. keyDown('enter');
  22604. expect(isFillHandleVisible()).toBe(false);
  22605. });
  22606. it('should appear when finishediting is triggered', function () {
  22607. handsontable({
  22608. fillHandle: true
  22609. });
  22610. selectCell(2, 2);
  22611. keyDown('enter');
  22612. keyDown('enter');
  22613. expect(isFillHandleVisible()).toBe(true);
  22614. });
  22615. it('should not appear when fillHandle equals false and finishediting is triggered', function () {
  22616. handsontable({
  22617. fillHandle: false
  22618. });
  22619. selectCell(2, 2);
  22620. keyDown('enter');
  22621. keyDown('enter');
  22622. expect(isFillHandleVisible()).toBe(false);
  22623. });
  22624. it('should appear when editor is discarded using the ESC key', function () {
  22625. handsontable({
  22626. fillHandle: true
  22627. });
  22628. selectCell(2, 2);
  22629. keyDown('enter');
  22630. keyDown('esc');
  22631. expect(isFillHandleVisible()).toBe(true);
  22632. });
  22633. it('should add custom value after autofill', function () {
  22634. handsontable({
  22635. data: [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22636. beforeAutofill: function beforeAutofill(start, end, data) {
  22637. data[0][0] = 'test';
  22638. }
  22639. });
  22640. selectCell(0, 0);
  22641. this.$container.find('.wtBorder.corner').simulate('mousedown');
  22642. this.$container.find('tr:eq(1) td:eq(0)').simulate('mouseover');
  22643. this.$container.find('tr:eq(2) td:eq(0)').simulate('mouseover');
  22644. this.$container.find('.wtBorder.corner').simulate('mouseup');
  22645. expect(getSelected()).toEqual([0, 0, 2, 0]);
  22646. expect(getDataAtCell(1, 0)).toEqual('test');
  22647. });
  22648. it('should use correct cell coordinates also when Handsontable is used inside a TABLE (#355)', function () {
  22649. var $table = $('<table><tr><td></td></tr></table>').appendTo('body');
  22650. this.$container.appendTo($table.find('td'));
  22651. var ev;
  22652. handsontable({
  22653. data: [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22654. beforeAutofill: function beforeAutofill(start, end, data) {
  22655. data[0][0] = 'test';
  22656. }
  22657. });
  22658. selectCell(1, 1);
  22659. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22660. this.$container.find('tr:eq(1) td:eq(0)').simulate('mouseover');
  22661. this.$container.find('tr:eq(2) td:eq(0)').simulate('mouseover');
  22662. this.$container.find('tr:eq(2) td:eq(0)').simulate('mouseup');
  22663. expect(getSelected()).toEqual([1, 1, 2, 1]);
  22664. expect(getDataAtCell(2, 1)).toEqual('test');
  22665. document.body.removeChild($table[0]);
  22666. });
  22667. it('should fill cells below until the end of content in the neighbouring column with current cell\'s data', function () {
  22668. var hot = handsontable({
  22669. data: [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, null, null, null, null], [1, 2, null, null, null, null]]
  22670. });
  22671. selectCell(1, 3);
  22672. var fillHandle = this.$container.find('.wtBorder.current.corner')[0];
  22673. mouseDoubleClick(fillHandle);
  22674. expect(getDataAtCell(2, 3)).toEqual(null);
  22675. expect(getDataAtCell(3, 3)).toEqual(null);
  22676. selectCell(1, 2);
  22677. mouseDoubleClick(fillHandle);
  22678. expect(getDataAtCell(2, 2)).toEqual(3);
  22679. expect(getDataAtCell(3, 2)).toEqual(3);
  22680. });
  22681. it('should fill cells below until the end of content in the neighbouring column with the currently selected area\'s data', function () {
  22682. var hot = handsontable({
  22683. data: [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, null, null, null, null], [1, 2, null, null, null, null]]
  22684. });
  22685. selectCell(1, 3, 1, 4);
  22686. var fillHandle = this.$container.find('.wtBorder.area.corner')[0];
  22687. mouseDoubleClick(fillHandle);
  22688. expect(getDataAtCell(2, 3)).toEqual(null);
  22689. expect(getDataAtCell(3, 3)).toEqual(null);
  22690. expect(getDataAtCell(2, 4)).toEqual(null);
  22691. expect(getDataAtCell(3, 4)).toEqual(null);
  22692. selectCell(1, 2, 1, 3);
  22693. mouseDoubleClick(fillHandle);
  22694. expect(getDataAtCell(2, 2)).toEqual(3);
  22695. expect(getDataAtCell(3, 2)).toEqual(3);
  22696. expect(getDataAtCell(2, 3)).toEqual(4);
  22697. expect(getDataAtCell(3, 3)).toEqual(4);
  22698. });
  22699. it('should add new row after dragging the handle to the last table row', function (done) {
  22700. var hot = handsontable({
  22701. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]
  22702. });
  22703. selectCell(0, 2);
  22704. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22705. this.$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22706. expect(hot.countRows()).toBe(4);
  22707. setTimeout(function () {
  22708. expect(hot.countRows()).toBe(5);
  22709. spec().$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22710. }, 300);
  22711. setTimeout(function () {
  22712. expect(hot.countRows()).toBe(6);
  22713. done();
  22714. }, 600);
  22715. });
  22716. it('should add new row after dragging the handle to the last table row (autoInsertRow as true)', function (done) {
  22717. var hot = handsontable({
  22718. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22719. fillHandle: {
  22720. autoInsertRow: true
  22721. }
  22722. });
  22723. selectCell(0, 2);
  22724. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22725. this.$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22726. expect(hot.countRows()).toBe(4);
  22727. setTimeout(function () {
  22728. expect(hot.countRows()).toBe(5);
  22729. spec().$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22730. }, 300);
  22731. setTimeout(function () {
  22732. expect(hot.countRows()).toBe(6);
  22733. done();
  22734. }, 600);
  22735. });
  22736. it('should add new row after dragging the handle to the last table row (autoInsertRow as true, vertical)', function (done) {
  22737. var hot = handsontable({
  22738. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22739. fillHandle: {
  22740. direction: 'vertical',
  22741. autoInsertRow: true
  22742. }
  22743. });
  22744. selectCell(0, 2);
  22745. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22746. this.$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22747. expect(hot.countRows()).toBe(4);
  22748. setTimeout(function () {
  22749. expect(hot.countRows()).toBe(5);
  22750. spec().$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22751. }, 300);
  22752. setTimeout(function () {
  22753. expect(hot.countRows()).toBe(6);
  22754. done();
  22755. }, 600);
  22756. });
  22757. it('should not add new row after dragging the handle to the last table row (autoInsertRow as true, horizontal)', function (done) {
  22758. var hot = handsontable({
  22759. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22760. fillHandle: {
  22761. direction: 'horizontal',
  22762. autoInsertRow: true
  22763. }
  22764. });
  22765. selectCell(0, 2);
  22766. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22767. this.$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22768. expect(hot.countRows()).toBe(4);
  22769. setTimeout(function () {
  22770. expect(hot.countRows()).toBe(4);
  22771. spec().$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22772. }, 300);
  22773. setTimeout(function () {
  22774. expect(hot.countRows()).toBe(4);
  22775. done();
  22776. }, 600);
  22777. });
  22778. it('should not add new row after dragging the handle below the viewport when `autoInsertRow` is disabled', function (done) {
  22779. var hot = handsontable({
  22780. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22781. fillHandle: {
  22782. autoInsertRow: false
  22783. }
  22784. });
  22785. selectCell(0, 2);
  22786. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22787. var ev = {};
  22788. var $lastRow = this.$container.find('tr:last-child td:eq(2)');
  22789. expect(hot.countRows()).toBe(4);
  22790. ev.clientX = $lastRow.offset().left / 2;
  22791. ev.clientY = $lastRow.offset().top + 50;
  22792. $(document.documentElement).simulate('mousemove', ev);
  22793. setTimeout(function () {
  22794. expect(hot.countRows()).toBe(4);
  22795. ev.clientY = $lastRow.offset().top + 150;
  22796. $(document.documentElement).simulate('mousemove', ev);
  22797. }, 300);
  22798. setTimeout(function () {
  22799. expect(hot.countRows()).toBe(4);
  22800. done();
  22801. }, 600);
  22802. });
  22803. it('should not add new rows if the current number of rows reaches the maxRows setting', function (done) {
  22804. var hot = handsontable({
  22805. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22806. maxRows: 5
  22807. });
  22808. selectCell(0, 2);
  22809. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22810. this.$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22811. expect(hot.countRows()).toBe(4);
  22812. setTimeout(function () {
  22813. expect(hot.countRows()).toBe(5);
  22814. spec().$container.find('tr:last-child td:eq(2)').simulate('mouseover');
  22815. }, 200);
  22816. setTimeout(function () {
  22817. expect(hot.countRows()).toBe(5);
  22818. done();
  22819. }, 400);
  22820. });
  22821. it('should add new row after dragging the handle below the viewport', function (done) {
  22822. var hot = handsontable({
  22823. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]
  22824. });
  22825. selectCell(0, 2);
  22826. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22827. var ev = {};
  22828. var $lastRow = this.$container.find('tr:last-child td:eq(2)');
  22829. expect(hot.countRows()).toBe(4);
  22830. ev.clientX = $lastRow.offset().left / 2;
  22831. ev.clientY = $lastRow.offset().top + 50;
  22832. $(document.documentElement).simulate('mousemove', ev);
  22833. setTimeout(function () {
  22834. expect(hot.countRows()).toBe(5);
  22835. ev.clientY = $lastRow.offset().top + 150;
  22836. $(document.documentElement).simulate('mousemove', ev);
  22837. }, 300);
  22838. setTimeout(function () {
  22839. expect(hot.countRows()).toBe(6);
  22840. done();
  22841. }, 600);
  22842. });
  22843. it('should fill cells when dragging the handle to the headers', function () {
  22844. var hot = handsontable({
  22845. data: [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 7, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22846. colHeaders: true,
  22847. rowHeaders: true
  22848. });
  22849. // col headers:
  22850. selectCell(2, 2);
  22851. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22852. var errors = 0;
  22853. try {
  22854. this.$container.find('thead tr:first-child th:eq(2)').simulate('mouseover').simulate('mouseup');
  22855. } catch (err) {
  22856. errors++;
  22857. }
  22858. expect(errors).toEqual(0);
  22859. expect(getDataAtCell(1, 2)).toEqual(7);
  22860. expect(getDataAtCell(0, 2)).toEqual(7);
  22861. expect($('.fill').filter(function () {
  22862. return $(this).css('display') !== 'none';
  22863. }).length).toEqual(0); // check if fill selection is refreshed
  22864. // row headers:
  22865. selectCell(2, 2);
  22866. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22867. errors = 0;
  22868. try {
  22869. this.$container.find('tbody tr:nth(2) th:first-child').simulate('mouseover').simulate('mouseup');
  22870. } catch (err) {
  22871. errors++;
  22872. }
  22873. expect(errors).toEqual(0);
  22874. expect(getDataAtCell(2, 1)).toEqual(7);
  22875. expect(getDataAtCell(2, 0)).toEqual(7);
  22876. expect($('.fill').filter(function () {
  22877. return $(this).css('display') !== 'none';
  22878. }).length).toEqual(0); // check if fill selection is refreshed
  22879. });
  22880. it('should not add a new row if dragging from the last row upwards or sideways', function (done) {
  22881. var mouseOverSpy = jasmine.createSpy('mouseOverSpy');
  22882. var hot = handsontable({
  22883. data: [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22884. afterOnCellMouseOver: mouseOverSpy
  22885. });
  22886. selectCell(3, 2);
  22887. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22888. this.$container.find('tr:nth-child(3) td:eq(2)').simulate('mouseover');
  22889. setTimeout(function () {
  22890. expect(hot.countRows()).toBe(4);
  22891. selectCell(3, 2);
  22892. spec().$container.find('.wtBorder.current.corner').simulate('mousedown');
  22893. spec().$container.find('tr:nth-child(4) td:eq(3)').simulate('mouseover');
  22894. }, 300);
  22895. setTimeout(function () {
  22896. expect(hot.countRows()).toBe(4);
  22897. selectCell(3, 2);
  22898. spec().$container.find('.wtBorder.current.corner').simulate('mousedown');
  22899. spec().$container.find('tr:nth-child(4) td:eq(1)').simulate('mouseover');
  22900. }, 500);
  22901. setTimeout(function () {
  22902. expect(hot.countRows()).toBe(4);
  22903. done();
  22904. }, 700);
  22905. });
  22906. it('should add new row after dragging the handle below the viewport', function (done) {
  22907. var hot = handsontable({
  22908. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]
  22909. });
  22910. selectCell(0, 2);
  22911. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22912. var ev = {};
  22913. var $lastRow = this.$container.find('tr:last-child td:eq(2)');
  22914. expect(hot.countRows()).toBe(4);
  22915. ev.clientX = $lastRow.offset().left / 2;
  22916. ev.clientY = $lastRow.offset().top + 50;
  22917. $(document.documentElement).simulate('mousemove', ev);
  22918. setTimeout(function () {
  22919. expect(hot.countRows()).toBe(5);
  22920. ev.clientY = $lastRow.offset().top + 150;
  22921. $(document.documentElement).simulate('mousemove', ev);
  22922. }, 300);
  22923. setTimeout(function () {
  22924. expect(hot.countRows()).toBe(6);
  22925. done();
  22926. }, 600);
  22927. });
  22928. it('should not add new row after dragging the handle below the viewport (direction is set to horizontal)', function (done) {
  22929. var hot = handsontable({
  22930. data: [[1, 2, 'test', 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
  22931. fillHandle: {
  22932. direction: 'horizontal',
  22933. autoInsertRow: true
  22934. }
  22935. });
  22936. selectCell(0, 2);
  22937. this.$container.find('.wtBorder.current.corner').simulate('mousedown');
  22938. var ev = {};
  22939. var $lastRow = this.$container.find('tr:last-child td:eq(2)');
  22940. expect(hot.countRows()).toBe(4);
  22941. ev.clientX = $lastRow.offset().left / 2;
  22942. ev.clientY = $lastRow.offset().top + 50;
  22943. $(document.documentElement).simulate('mousemove', ev);
  22944. setTimeout(function () {
  22945. expect(hot.countRows()).toBe(4);
  22946. done();
  22947. }, 300);
  22948. });
  22949. describe('should works properly when two or more instances of Handsontable was initialized with other settings (#3257)', function () {
  22950. var getData;
  22951. var $container1;
  22952. var $container2;
  22953. beforeAll(function () {
  22954. getData = function getData() {
  22955. return [[1, 2, 3, 4, 5, 6], [7, 8, 9, 1, 2, 3], [4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6]];
  22956. };
  22957. $container1 = $('<div id="hot1"></div>').appendTo('body').handsontable({
  22958. data: getData(),
  22959. fillHandle: true
  22960. });
  22961. $container2 = $('<div id="hot2"></div>').appendTo('body').handsontable({
  22962. data: getData(),
  22963. fillHandle: 'horizontal'
  22964. });
  22965. });
  22966. it('checking drag vertically on 1. instance of Handsontable - should change cell value', function () {
  22967. $container1.handsontable('selectCell', 0, 0);
  22968. $container1.find('.wtBorder.current.corner').simulate('mousedown');
  22969. $container1.find('tbody tr:eq(1) td:eq(0)').simulate('mouseover').simulate('mouseup');
  22970. expect($container1.handsontable('getDataAtCell', 1, 0)).toEqual(1);
  22971. });
  22972. describe('-> updating settings on 2. instance of Handsontable', function () {
  22973. beforeAll(function () {
  22974. $container2.handsontable('updateSettings', { fillHandle: 'vertical' });
  22975. });
  22976. it('checking drag vertically on 2. instance of Handsontable - should change cell value', function () {
  22977. $container2.handsontable('selectCell', 0, 2);
  22978. $container2.find('.wtBorder.current.corner').simulate('mousedown');
  22979. $container2.find('tbody tr:eq(1) td:eq(2)').simulate('mouseover').simulate('mouseup');
  22980. expect($container2.handsontable('getDataAtCell', 1, 2)).toEqual(3);
  22981. });
  22982. });
  22983. afterAll(function () {
  22984. // destroing containers
  22985. $container1.handsontable('destroy');
  22986. $container1.remove();
  22987. $container2.handsontable('destroy');
  22988. $container2.remove();
  22989. });
  22990. });
  22991. });
  22992. /***/ }),
  22993. /* 184 */
  22994. /***/ (function(module, exports, __webpack_require__) {
  22995. "use strict";
  22996. describe('Performance', function () {
  22997. var id = 'testContainer';
  22998. // this is a test suite to test if there are no redundant operations
  22999. beforeEach(function () {
  23000. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23001. });
  23002. afterEach(function () {
  23003. if (this.$container) {
  23004. destroy();
  23005. this.$container.remove();
  23006. }
  23007. });
  23008. it('should call renderer once for one cell (fixed column width)', function () {
  23009. var count = 0;
  23010. handsontable({
  23011. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23012. colWidths: 100,
  23013. rowHeights: 23,
  23014. renderer: function renderer() {
  23015. Handsontable.renderers.TextRenderer.apply(this, arguments);
  23016. count++;
  23017. }
  23018. });
  23019. expect(count).toEqual(1); // only for master table
  23020. });
  23021. it('should call renderer twice for one cell (auto column width)', function () {
  23022. var count = 0;
  23023. var hot = handsontable({
  23024. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23025. rowHeights: 23,
  23026. renderer: function renderer() {
  23027. Handsontable.renderers.TextRenderer.apply(this, arguments);
  23028. count++;
  23029. }
  23030. });
  23031. expect(count).toEqual(2); // 1 for autoColumnSize, 1 for actual cell render
  23032. });
  23033. it('should call renderer twice for one cell (auto row height)', function () {
  23034. var count = 0;
  23035. var hot = handsontable({
  23036. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23037. colWidths: 50,
  23038. renderer: function renderer() {
  23039. Handsontable.renderers.TextRenderer.apply(this, arguments);
  23040. count++;
  23041. }
  23042. });
  23043. expect(count).toEqual(1); // 1 for actual cell render (colWidths prevent autoColumnSize to enable)
  23044. });
  23045. it('should call renderer triple times for one cell (auto row height, auto column width)', function () {
  23046. var count = 0;
  23047. var hot = handsontable({
  23048. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23049. autoRowSize: true,
  23050. autoColumnSize: true,
  23051. renderer: function renderer() {
  23052. Handsontable.renderers.TextRenderer.apply(this, arguments);
  23053. count++;
  23054. }
  23055. });
  23056. expect(count).toEqual(3); // 1 for autoColumnSize, 1 for autoRowSize, 1 for actual cell render
  23057. });
  23058. it('should call getCellMeta minimum number of times for one cell (auto column width, without overlays)', function () {
  23059. var count = 0;
  23060. handsontable({
  23061. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23062. rowHeights: 23,
  23063. beforeGetCellMeta: function beforeGetCellMeta() {
  23064. count++;
  23065. }
  23066. });
  23067. expect(count).toEqual(7);
  23068. });
  23069. it('should call getCellMeta minimum number of times for one cell (auto row height, without overlays)', function () {
  23070. var count = 0;
  23071. handsontable({
  23072. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23073. colWidths: 50,
  23074. beforeGetCellMeta: function beforeGetCellMeta() {
  23075. count++;
  23076. }
  23077. });
  23078. expect(count).toEqual(5);
  23079. });
  23080. it('should call getCellMeta minimum number of times for one cell (auto column width, with left overlay)', function () {
  23081. var count = 0;
  23082. handsontable({
  23083. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23084. colHeaders: true,
  23085. rowHeights: 23,
  23086. beforeGetCellMeta: function beforeGetCellMeta() {
  23087. count++;
  23088. }
  23089. });
  23090. expect(count).toEqual(8);
  23091. });
  23092. it('should call getCellMeta minimum number of times for one cell (auto row height, with left overlay)', function () {
  23093. var count = 0;
  23094. handsontable({
  23095. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23096. colHeaders: true,
  23097. colWidths: 50,
  23098. beforeGetCellMeta: function beforeGetCellMeta() {
  23099. count++;
  23100. }
  23101. });
  23102. expect(count).toEqual(6);
  23103. });
  23104. it('should call getCellMeta minimum number of times for one cell (auto column width, with top overlay)', function () {
  23105. var count = 0;
  23106. handsontable({
  23107. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23108. rowHeaders: true,
  23109. rowHeights: 23,
  23110. beforeGetCellMeta: function beforeGetCellMeta() {
  23111. count++;
  23112. }
  23113. });
  23114. expect(count).toEqual(7);
  23115. });
  23116. it('should call getCellMeta minimum number of times for one cell (auto row height, with top overlay)', function () {
  23117. var count = 0;
  23118. handsontable({
  23119. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23120. rowHeaders: true,
  23121. colWidths: 50,
  23122. beforeGetCellMeta: function beforeGetCellMeta() {
  23123. count++;
  23124. }
  23125. });
  23126. expect(count).toEqual(5);
  23127. });
  23128. it('should call getCellMeta minimum number of times for one cell (auto column width, with all overlays)', function () {
  23129. var count = 0;
  23130. handsontable({
  23131. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23132. colHeaders: true,
  23133. rowHeaders: true,
  23134. rowHeights: 23,
  23135. beforeGetCellMeta: function beforeGetCellMeta() {
  23136. count++;
  23137. }
  23138. });
  23139. expect(count).toEqual(8);
  23140. });
  23141. it('should call getCellMeta minimum number of times for one cell (auto row height, with all overlays)', function () {
  23142. var count = 0;
  23143. handsontable({
  23144. data: Handsontable.helper.createSpreadsheetData(1, 1),
  23145. colHeaders: true,
  23146. rowHeaders: true,
  23147. colWidths: 50,
  23148. beforeGetCellMeta: function beforeGetCellMeta() {
  23149. count++;
  23150. }
  23151. });
  23152. expect(count).toEqual(6);
  23153. });
  23154. it('should call renderer twice for each cell (auto column width)', function () {
  23155. var count = 0;
  23156. handsontable({
  23157. data: Handsontable.helper.createSpreadsheetData(4, 4),
  23158. rowHeights: 23,
  23159. autoColumnSize: true,
  23160. renderer: function renderer() {
  23161. Handsontable.renderers.TextRenderer.apply(this, arguments);
  23162. count++;
  23163. }
  23164. });
  23165. expect(count).toEqual(28);
  23166. });
  23167. it('should call renderer twice for each cell (auto row height)', function () {
  23168. var count = 0;
  23169. handsontable({
  23170. data: Handsontable.helper.createSpreadsheetData(4, 4),
  23171. colWidths: 50,
  23172. autoRowSize: true,
  23173. renderer: function renderer() {
  23174. Handsontable.renderers.TextRenderer.apply(this, arguments);
  23175. count++;
  23176. }
  23177. });
  23178. expect(count).toEqual(28); // 16 in main table and 4 rows for autoRowSize
  23179. });
  23180. it('should call renderer twice for each cell (auto row height, auto column width)', function () {
  23181. var count = 0;
  23182. handsontable({
  23183. data: Handsontable.helper.createSpreadsheetData(4, 4),
  23184. autoRowSize: true,
  23185. autoColumnSize: true,
  23186. renderer: function renderer() {
  23187. Handsontable.renderers.TextRenderer.apply(this, arguments);
  23188. count++;
  23189. }
  23190. });
  23191. expect(count).toEqual(40); // 16x2 in main table, 4 rows for autoRowSize and 4 cols for autoColumnSize
  23192. });
  23193. });
  23194. /***/ }),
  23195. /* 185 */
  23196. /***/ (function(module, exports, __webpack_require__) {
  23197. "use strict";
  23198. describe('PluginHooks', function () {
  23199. var id = 'testContainer';
  23200. beforeEach(function () {
  23201. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23202. });
  23203. afterEach(function () {
  23204. if (this.$container) {
  23205. destroy();
  23206. this.$container.remove();
  23207. }
  23208. });
  23209. it('should add a many local hooks at init (as array)', function () {
  23210. var handler1 = jasmine.createSpy('handler1');
  23211. var handler2 = jasmine.createSpy('handler2');
  23212. var handler3 = jasmine.createSpy('handler3');
  23213. handsontable({
  23214. afterInit: [handler1, handler2, handler3]
  23215. });
  23216. expect(handler1).toHaveBeenCalled();
  23217. expect(handler2).toHaveBeenCalled();
  23218. expect(handler3).toHaveBeenCalled();
  23219. });
  23220. it('should remove a global hook', function () {
  23221. var test = 0,
  23222. hook = function hook() {
  23223. test = 5;
  23224. };
  23225. Handsontable.hooks.add('afterInit', hook);
  23226. Handsontable.hooks.remove('afterInit', hook);
  23227. handsontable();
  23228. expect(test).toEqual(0);
  23229. });
  23230. it('should remove a local hook', function () {
  23231. var test = 0,
  23232. hook = function hook() {
  23233. test = 5;
  23234. };
  23235. handsontable();
  23236. getInstance().addHook('afterInit', hook);
  23237. getInstance().removeHook('afterInit', hook);
  23238. expect(test).toEqual(0);
  23239. });
  23240. it('should run global hook', function () {
  23241. var test = 0;
  23242. Handsontable.hooks.add('afterInit', function () {
  23243. test = 5;
  23244. });
  23245. handsontable();
  23246. expect(test).toEqual(5);
  23247. });
  23248. it('should run local hook', function () {
  23249. var test = 0;
  23250. handsontable();
  23251. getInstance().addHook('myHook', function () {
  23252. test += 5;
  23253. });
  23254. getInstance().runHooks('myHook');
  23255. getInstance().runHooks('myHook');
  23256. expect(test).toEqual(10);
  23257. });
  23258. it('should run local hook once', function () {
  23259. var test = 0;
  23260. handsontable();
  23261. getInstance().addHookOnce('myHook', function () {
  23262. test += 5;
  23263. });
  23264. getInstance().runHooks('myHook');
  23265. getInstance().runHooks('myHook');
  23266. expect(test).toEqual(5);
  23267. });
  23268. it('should run all hooks', function () {
  23269. var test = 0;
  23270. Handsontable.hooks.add('afterInit', function () {
  23271. test += 5;
  23272. });
  23273. handsontable({
  23274. afterInit: function afterInit() {
  23275. test += 5;
  23276. }
  23277. });
  23278. expect(test).toEqual(10);
  23279. });
  23280. it('list of all avaliable plugin hooks should be exposed as a public method', function () {
  23281. var hooks = Handsontable.hooks.getRegistered(); // this is used in demo/callbacks.html
  23282. expect(hooks.indexOf('beforeInit')).toBeGreaterThan(-1);
  23283. });
  23284. it('should add a local hook with addHooks method', function () {
  23285. var hot1 = handsontable();
  23286. var test = 0;
  23287. hot1.addHook('myHook', function () {
  23288. test += 5;
  23289. });
  23290. hot1.runHooks('myHook');
  23291. expect(test).toEqual(5);
  23292. });
  23293. it('should remove a local hook with removeHook method', function () {
  23294. var hot1 = handsontable();
  23295. var test = 0;
  23296. var handler = function handler() {
  23297. test += 5;
  23298. };
  23299. hot1.addHook('myHook', handler);
  23300. hot1.runHooks('myHook');
  23301. hot1.runHooks('myHook');
  23302. expect(test).toEqual(10);
  23303. hot1.removeHook('myHook', handler);
  23304. hot1.runHooks('myHook');
  23305. expect(test).toEqual(10);
  23306. });
  23307. it('should add a local hook with addHookOnce method and run it just once', function () {
  23308. var hot1 = handsontable();
  23309. var test = 0;
  23310. var handler = function handler() {
  23311. test += 5;
  23312. };
  23313. hot1.addHookOnce('myHook', handler);
  23314. hot1.runHooks('myHook');
  23315. hot1.runHooks('myHook');
  23316. expect(test).toEqual(5);
  23317. });
  23318. it('should run hook with runHooks and return value', function () {
  23319. var hot = handsontable();
  23320. var handler = function handler() {
  23321. return 5;
  23322. };
  23323. hot.addHook('myHook', handler);
  23324. expect(hot.runHooks('myHook')).toEqual(5);
  23325. });
  23326. it('should run two "once" hooks in desired order', function () {
  23327. var hot = handsontable();
  23328. var arr = [];
  23329. hot.addHookOnce('myHook', function () {
  23330. arr.push(1);
  23331. });
  23332. hot.addHookOnce('myHook', function () {
  23333. arr.push(2);
  23334. });
  23335. hot.runHooks('myHook');
  23336. expect(arr).toEqual([1, 2]);
  23337. });
  23338. it('should execute two "once" hooks in desired order', function () {
  23339. var hot = handsontable();
  23340. var str = 'a';
  23341. hot.addHookOnce('myHook', function (str) {
  23342. return str + 'b';
  23343. });
  23344. hot.addHookOnce('myHook', function (str) {
  23345. return str + 'c';
  23346. });
  23347. expect(hot.runHooks('myHook', str)).toEqual('abc');
  23348. });
  23349. it('adding same hook twice should register it only once (without an error)', function () {
  23350. var i = 0;
  23351. var fn = function fn() {
  23352. i++;
  23353. };
  23354. var hot = handsontable({
  23355. afterOnCellMouseOver: fn
  23356. });
  23357. hot.getInstance().updateSettings({ afterOnCellMouseOver: fn });
  23358. hot.runHooks('afterOnCellMouseOver');
  23359. expect(i).toEqual(1);
  23360. });
  23361. it('should mark the hook callbacks added with Handsontable initialization', function () {
  23362. var fn = function fn() {};
  23363. var fn2 = function fn2() {};
  23364. var hot = handsontable({
  23365. afterChange: fn
  23366. });
  23367. hot.addHook('afterChange', fn2);
  23368. expect(fn.initialHook).toEqual(true);
  23369. expect(fn2.initialHook).toEqual(void 0);
  23370. });
  23371. it('should mark the hook callbacks added using the updateSettings method', function () {
  23372. var fn = function fn() {};
  23373. var fn2 = function fn2() {};
  23374. var hot = handsontable();
  23375. hot.updateSettings({
  23376. afterChange: fn
  23377. });
  23378. hot.addHook('afterChange', fn2);
  23379. expect(fn.initialHook).toEqual(true);
  23380. expect(fn2.initialHook).toEqual(void 0);
  23381. });
  23382. it('should replace the existing hook callbacks, if they\'re updated using the updateSettings method (when there was a hook ' + 'already declared in the initialization)', function () {
  23383. var fn = function fn() {};
  23384. var fn2 = function fn2() {};
  23385. var hot = handsontable({
  23386. afterGetCellMeta: fn
  23387. });
  23388. var initialCallbackCount = hot.pluginHookBucket.afterGetCellMeta.length;
  23389. hot.updateSettings({
  23390. afterGetCellMeta: function afterGetCellMeta() {
  23391. var a = 'another function';
  23392. }
  23393. });
  23394. hot.updateSettings({
  23395. afterGetCellMeta: function afterGetCellMeta() {
  23396. var a = 'yet another function';
  23397. }
  23398. });
  23399. hot.updateSettings({
  23400. afterGetCellMeta: fn2
  23401. });
  23402. expect(hot.pluginHookBucket.afterGetCellMeta.length).toEqual(initialCallbackCount);
  23403. });
  23404. it('should replace the existing hook callbacks, if they\'re updated using the updateSettings method', function () {
  23405. var fn = function fn() {};
  23406. var fn2 = function fn2() {};
  23407. var hot = handsontable();
  23408. hot.addHook('afterGetCellMeta', function () {
  23409. return 'doesn\'t matter 1';
  23410. });
  23411. hot.addHook('afterGetCellMeta', function () {
  23412. return 'doesn\'t matter 2';
  23413. });
  23414. hot.addHook('afterGetCellMeta', function () {
  23415. return 'doesn\'t matter 3';
  23416. });
  23417. hot.updateSettings({
  23418. afterGetCellMeta: fn
  23419. });
  23420. var initialCallbackCount = hot.pluginHookBucket.afterGetCellMeta.length;
  23421. hot.updateSettings({
  23422. afterGetCellMeta: function afterGetCellMeta() {
  23423. var a = 'another function';
  23424. }
  23425. });
  23426. hot.updateSettings({
  23427. afterGetCellMeta: function afterGetCellMeta() {
  23428. var a = 'yet another function';
  23429. }
  23430. });
  23431. hot.updateSettings({
  23432. afterGetCellMeta: fn2
  23433. });
  23434. expect(hot.pluginHookBucket.afterGetCellMeta.length).toEqual(initialCallbackCount);
  23435. });
  23436. it('should NOT replace existing hook callbacks, if the\'re added using the addHook method', function () {
  23437. var fn = function fn() {};
  23438. var fn2 = function fn2() {};
  23439. var hot = handsontable();
  23440. hot.updateSettings({
  23441. afterGetCellMeta: fn
  23442. });
  23443. var initialCallbackCount = hot.pluginHookBucket.afterGetCellMeta.length;
  23444. hot.addHook('afterGetCellMeta', function () {
  23445. var a = 'another function';
  23446. });
  23447. hot.addHook('afterGetCellMeta', function () {
  23448. var a = 'yet another function';
  23449. });
  23450. hot.addHook('afterGetCellMeta', fn2);
  23451. // should not add this one, as it's a duplicate
  23452. hot.addHook('afterGetCellMeta', fn);
  23453. expect(hot.pluginHookBucket.afterGetCellMeta.length).toEqual(initialCallbackCount + 3);
  23454. });
  23455. describe('controlling handler queue execution', function () {
  23456. it('should execute all handlers if none of them hasn\'t skipped', function () {
  23457. var handler1 = jasmine.createSpy('handler1');
  23458. var handler2 = jasmine.createSpy('handler2');
  23459. var handler3 = jasmine.createSpy('handler3');
  23460. var hot = handsontable();
  23461. hot.addHook('fakeEvent', handler1);
  23462. hot.addHook('fakeEvent', handler2);
  23463. hot.addHook('fakeEvent', handler3);
  23464. expect(handler1).not.toHaveBeenCalled();
  23465. expect(handler2).not.toHaveBeenCalled();
  23466. expect(handler3).not.toHaveBeenCalled();
  23467. hot.runHooks('fakeEvent');
  23468. expect(handler1).toHaveBeenCalled();
  23469. expect(handler2).toHaveBeenCalled();
  23470. expect(handler3).toHaveBeenCalled();
  23471. });
  23472. });
  23473. });
  23474. /***/ }),
  23475. /* 186 */
  23476. /***/ (function(module, exports, __webpack_require__) {
  23477. "use strict";
  23478. describe('RowHeader', function () {
  23479. var id = 'testContainer';
  23480. beforeEach(function () {
  23481. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23482. });
  23483. afterEach(function () {
  23484. if (this.$container) {
  23485. destroy();
  23486. this.$container.remove();
  23487. }
  23488. });
  23489. it('should not show row headers by default', function () {
  23490. var that = this;
  23491. handsontable();
  23492. expect(that.$container.find('tbody th').length).toEqual(0);
  23493. });
  23494. it('should show row headers if true', function () {
  23495. var that = this;
  23496. handsontable({
  23497. rowHeaders: true
  23498. });
  23499. expect(that.$container.find('tbody th').length).toBeGreaterThan(0);
  23500. });
  23501. it('should show row headers numbered 1-10 by default', function () {
  23502. var that = this;
  23503. var startRows = 5;
  23504. handsontable({
  23505. startRows: startRows,
  23506. rowHeaders: true
  23507. });
  23508. var ths = getLeftClone().find('tbody th');
  23509. expect(ths.length).toEqual(startRows);
  23510. expect($.trim(ths.eq(0).text())).toEqual('1');
  23511. expect($.trim(ths.eq(1).text())).toEqual('2');
  23512. expect($.trim(ths.eq(2).text())).toEqual('3');
  23513. expect($.trim(ths.eq(3).text())).toEqual('4');
  23514. expect($.trim(ths.eq(4).text())).toEqual('5');
  23515. });
  23516. it('should show row headers with custom label', function () {
  23517. var that = this;
  23518. var startRows = 5;
  23519. handsontable({
  23520. startRows: startRows,
  23521. rowHeaders: ['First', 'Second', 'Third']
  23522. });
  23523. var ths = getLeftClone().find('tbody th');
  23524. expect(ths.length).toEqual(startRows);
  23525. expect($.trim(ths.eq(0).text())).toEqual('First');
  23526. expect($.trim(ths.eq(1).text())).toEqual('Second');
  23527. expect($.trim(ths.eq(2).text())).toEqual('Third');
  23528. expect($.trim(ths.eq(3).text())).toEqual('4');
  23529. expect($.trim(ths.eq(4).text())).toEqual('5');
  23530. });
  23531. it('should not show row headers if false', function () {
  23532. var that = this;
  23533. handsontable({
  23534. rowHeaders: false
  23535. });
  23536. expect(getLeftClone().find('tbody th').length).toEqual(0);
  23537. });
  23538. it('should hide rows headers after updateSetting', function () {
  23539. var hot = handsontable({
  23540. startRows: 5,
  23541. rowHeaders: true
  23542. });
  23543. expect(getHtCore().find('tbody th').length).toEqual(5);
  23544. expect(getLeftClone().find('tbody th').length).toEqual(5);
  23545. hot.updateSettings({
  23546. rowHeaders: false
  23547. });
  23548. expect(getHtCore().find('tbody th').length).toEqual(0);
  23549. });
  23550. it('should show rows headers after updateSettings', function () {
  23551. var hot = handsontable({
  23552. startRows: 5,
  23553. rowHeaders: false
  23554. });
  23555. expect(getHtCore().find('tbody th').length).toEqual(0);
  23556. expect(getLeftClone().find('tbody th').length).toEqual(0);
  23557. hot.updateSettings({
  23558. rowHeaders: true
  23559. });
  23560. expect(getHtCore().find('tbody th').length).toEqual(5);
  23561. expect(getLeftClone().find('tbody th').length).toEqual(5);
  23562. });
  23563. it('should show/hide rows headers after multiple updateSettings', function () {
  23564. var hot = handsontable({
  23565. startRows: 5,
  23566. rowHeaders: false
  23567. });
  23568. expect(getHtCore().find('tbody th').length).toEqual(0);
  23569. expect(getLeftClone().find('tbody th').length).toEqual(0);
  23570. hot.updateSettings({
  23571. rowHeaders: true
  23572. });
  23573. expect(getHtCore().find('tbody th').length).toEqual(5);
  23574. expect(getLeftClone().width()).toBeGreaterThan(0);
  23575. hot.updateSettings({
  23576. rowHeaders: false
  23577. });
  23578. expect(getHtCore().find('tbody th').length).toEqual(0);
  23579. expect(getLeftClone().width()).toEqual(0);
  23580. hot.updateSettings({
  23581. rowHeaders: true
  23582. });
  23583. expect(getHtCore().find('tbody th').length).toEqual(5);
  23584. expect(getLeftClone().width()).toBeGreaterThan(0);
  23585. });
  23586. it('should show new rows headers after updateSettings', function () {
  23587. var hot = handsontable({
  23588. startCols: 3,
  23589. rowHeaders: ['A', 'B', 'C']
  23590. });
  23591. var leftClone = getLeftClone();
  23592. expect(leftClone.find('tbody tr:eq(0) th:eq(0)').text()).toEqual('A');
  23593. expect(leftClone.find('tbody tr:eq(1) th:eq(0)').text()).toEqual('B');
  23594. expect(leftClone.find('tbody tr:eq(2) th:eq(0)').text()).toEqual('C');
  23595. hot.updateSettings({
  23596. rowHeaders: ['X', 'Y', 'Z']
  23597. });
  23598. expect(leftClone.find('tbody tr:eq(0) th:eq(0)').text()).toEqual('X');
  23599. expect(leftClone.find('tbody tr:eq(1) th:eq(0)').text()).toEqual('Y');
  23600. expect(leftClone.find('tbody tr:eq(2) th:eq(0)').text()).toEqual('Z');
  23601. });
  23602. it('should allow defining custom row header width using the rowHeaderWidth config option', function () {
  23603. var hot = handsontable({
  23604. startCols: 3,
  23605. rowHeaders: true,
  23606. rowHeaderWidth: 150
  23607. });
  23608. expect(this.$container.find('th').eq(0).outerWidth()).toEqual(150);
  23609. expect(this.$container.find('col').first().css('width')).toEqual('150px');
  23610. });
  23611. it('should allow defining custom column header heights using the columnHeaderHeight config option, when multiple column header levels are defined', function () {
  23612. var hot = handsontable({
  23613. startCols: 3,
  23614. rowHeaders: true,
  23615. rowHeaderWidth: [66, 96],
  23616. afterGetRowHeaderRenderers: function afterGetRowHeaderRenderers(array) {
  23617. array.push(function (index, TH) {
  23618. TH.innerHTML = '';
  23619. var div = document.createElement('div');
  23620. var span = document.createElement('span');
  23621. div.className = 'relative';
  23622. span.className = 'rowHeader';
  23623. span.innerText = index;
  23624. div.appendChild(span);
  23625. TH.appendChild(div);
  23626. });
  23627. return array;
  23628. }
  23629. });
  23630. hot.render();
  23631. expect(this.$container.find('.handsontable.ht_clone_left tr:nth-child(1) th:nth-child(1)').outerWidth()).toEqual(66);
  23632. expect(this.$container.find('.handsontable.ht_clone_left tr:nth-child(1) th:nth-child(2)').outerWidth()).toEqual(96);
  23633. expect(this.$container.find('col').first().css('width')).toEqual('66px');
  23634. expect(this.$container.find('col').eq(1).css('width')).toEqual('96px');
  23635. });
  23636. });
  23637. /***/ }),
  23638. /* 187 */
  23639. /***/ (function(module, exports, __webpack_require__) {
  23640. "use strict";
  23641. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  23642. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  23643. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  23644. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  23645. function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
  23646. describe('cellTypes', function () {
  23647. var id = 'testContainer';
  23648. var _Handsontable$cellTyp = Handsontable.cellTypes,
  23649. registerCellType = _Handsontable$cellTyp.registerCellType,
  23650. getCellType = _Handsontable$cellTyp.getCellType;
  23651. var _Handsontable$editors = Handsontable.editors,
  23652. registerEditor = _Handsontable$editors.registerEditor,
  23653. getEditor = _Handsontable$editors.getEditor,
  23654. BaseEditor = _Handsontable$editors.BaseEditor;
  23655. var _Handsontable$rendere = Handsontable.renderers,
  23656. registerRenderer = _Handsontable$rendere.registerRenderer,
  23657. getRenderer = _Handsontable$rendere.getRenderer;
  23658. var _Handsontable$validat = Handsontable.validators,
  23659. registerValidator = _Handsontable$validat.registerValidator,
  23660. getValidator = _Handsontable$validat.getValidator;
  23661. beforeEach(function () {
  23662. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23663. });
  23664. afterEach(function () {
  23665. if (this.$container) {
  23666. destroy();
  23667. this.$container.remove();
  23668. }
  23669. });
  23670. it('should register custom cell type (with custom editor, renderer and validator)', _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
  23671. var MyEditor, onAfterValidate, hot;
  23672. return regeneratorRuntime.wrap(function _callee$(_context) {
  23673. while (1) {
  23674. switch (_context.prev = _context.next) {
  23675. case 0:
  23676. MyEditor = function (_BaseEditor) {
  23677. _inherits(MyEditor, _BaseEditor);
  23678. function MyEditor() {
  23679. _classCallCheck(this, MyEditor);
  23680. return _possibleConstructorReturn(this, (MyEditor.__proto__ || Object.getPrototypeOf(MyEditor)).apply(this, arguments));
  23681. }
  23682. _createClass(MyEditor, [{
  23683. key: 'init',
  23684. value: function init() {
  23685. this.TEXTAREA = document.createElement('TEXTAREA');
  23686. this.TEXTAREA_PARENT = document.createElement('DIV');
  23687. this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);
  23688. this.instance.rootElement.appendChild(this.TEXTAREA_PARENT);
  23689. }
  23690. }, {
  23691. key: 'getValue',
  23692. value: function getValue() {
  23693. return '**' + this.TEXTAREA.value + '**';
  23694. }
  23695. }, {
  23696. key: 'setValue',
  23697. value: function setValue(value) {
  23698. this.TEXTAREA.value = value;
  23699. }
  23700. }, {
  23701. key: 'open',
  23702. value: function open() {}
  23703. }, {
  23704. key: 'close',
  23705. value: function close() {}
  23706. }, {
  23707. key: 'focus',
  23708. value: function focus() {
  23709. this.TEXTAREA.focus();
  23710. }
  23711. }]);
  23712. return MyEditor;
  23713. }(BaseEditor);
  23714. registerCellType('myCellType', {
  23715. editor: MyEditor,
  23716. renderer: function renderer(hot, td, row, col, prop, value, cellProperties) {
  23717. td.innerHTML = '--' + value + '--';
  23718. },
  23719. validator: function validator(value, cb) {
  23720. cb(value === 10);
  23721. }
  23722. });
  23723. onAfterValidate = jasmine.createSpy('onAfterValidate');
  23724. hot = handsontable({
  23725. data: [[1, 6, 10]],
  23726. columns: [{
  23727. type: 'myCellType'
  23728. }],
  23729. afterValidate: onAfterValidate
  23730. });
  23731. hot.setDataAtCell(1, 0, 10);
  23732. _context.next = 7;
  23733. return sleep(100);
  23734. case 7:
  23735. expect(onAfterValidate).toHaveBeenCalledWith(true, 10, 1, 0, undefined, undefined);
  23736. expect(getCell(1, 0).innerHTML).toBe('--10--');
  23737. selectCell(0, 0);
  23738. keyDown('enter');
  23739. document.activeElement.value = 'hello';
  23740. destroyEditor();
  23741. _context.next = 15;
  23742. return sleep(100);
  23743. case 15:
  23744. expect(onAfterValidate).toHaveBeenCalledWith(false, '**hello**', 0, 0, 'edit', undefined);
  23745. expect(getCell(0, 0).innerHTML).toBe('--**hello**--');
  23746. case 17:
  23747. case 'end':
  23748. return _context.stop();
  23749. }
  23750. }
  23751. }, _callee, undefined);
  23752. })));
  23753. it('should retrieve predefined cell types by its names', function () {
  23754. var _Handsontable = Handsontable,
  23755. editors = _Handsontable.editors,
  23756. renderers = _Handsontable.renderers,
  23757. validators = _Handsontable.validators;
  23758. expect(getCellType('autocomplete').editor).toBe(editors.AutocompleteEditor);
  23759. expect(getCellType('autocomplete').renderer).toBe(renderers.AutocompleteRenderer);
  23760. expect(getCellType('autocomplete').validator).toBe(validators.AutocompleteValidator);
  23761. expect(getCellType('checkbox').editor).toBe(editors.CheckboxEditor);
  23762. expect(getCellType('checkbox').renderer).toBe(renderers.CheckboxRenderer);
  23763. expect(getCellType('checkbox').validator).not.toBeDefined();
  23764. expect(getCellType('date').editor).toBe(editors.DateEditor);
  23765. expect(getCellType('date').renderer).toBe(renderers.AutocompleteRenderer);
  23766. expect(getCellType('date').validator).toBe(validators.DateValidator);
  23767. expect(getCellType('dropdown').editor).toBe(editors.DropdownEditor);
  23768. expect(getCellType('dropdown').renderer).toBe(renderers.AutocompleteRenderer);
  23769. expect(getCellType('dropdown').validator).toBe(validators.AutocompleteValidator);
  23770. expect(getCellType('handsontable').editor).toBe(editors.HandsontableEditor);
  23771. expect(getCellType('handsontable').renderer).toBe(renderers.AutocompleteRenderer);
  23772. expect(getCellType('handsontable').validator).not.toBeDefined();
  23773. expect(getCellType('numeric').editor).toBe(editors.NumericEditor);
  23774. expect(getCellType('numeric').renderer).toBe(renderers.NumericRenderer);
  23775. expect(getCellType('numeric').validator).toBe(validators.NumericValidator);
  23776. expect(getCellType('numeric').dataType).toBe('number');
  23777. expect(getCellType('password').editor).toBe(editors.PasswordEditor);
  23778. expect(getCellType('password').renderer).toBe(renderers.PasswordRenderer);
  23779. expect(getCellType('password').validator).not.toBeDefined();
  23780. expect(getCellType('password').copyable).toBe(false);
  23781. expect(getCellType('text').editor).toBe(editors.TextEditor);
  23782. expect(getCellType('text').renderer).toBe(renderers.TextRenderer);
  23783. expect(getCellType('text').validator).not.toBeDefined();
  23784. expect(getCellType('time').editor).toBe(editors.TextEditor);
  23785. expect(getCellType('time').renderer).toBe(renderers.TextRenderer);
  23786. expect(getCellType('time').validator).toBe(validators.TimeValidator);
  23787. });
  23788. it('should register custom cell type into renderers, editors and validators', function () {
  23789. var MyEditor = function MyEditor() {
  23790. _classCallCheck(this, MyEditor);
  23791. };
  23792. function myRenderer() {}
  23793. function myValidator() {}
  23794. registerCellType('myCellType', {
  23795. editor: MyEditor,
  23796. renderer: myRenderer,
  23797. validator: myValidator
  23798. });
  23799. expect(getEditor('myCellType')).toBe(MyEditor);
  23800. expect(getRenderer('myCellType')).toBe(myRenderer);
  23801. expect(getValidator('myCellType')).toBe(myValidator);
  23802. });
  23803. it('should overwrite cell types under the same name', function () {
  23804. var MyEditor = function MyEditor() {
  23805. _classCallCheck(this, MyEditor);
  23806. };
  23807. function myRenderer() {}
  23808. function myValidator() {}
  23809. registerCellType('myCellType', {
  23810. editor: MyEditor,
  23811. renderer: myRenderer,
  23812. validator: myValidator
  23813. });
  23814. expect(getEditor('myCellType')).toBe(MyEditor);
  23815. expect(getRenderer('myCellType')).toBe(myRenderer);
  23816. expect(getValidator('myCellType')).toBe(myValidator);
  23817. function myRenderer2() {}
  23818. function myValidator2() {}
  23819. registerCellType('myCellType', {
  23820. renderer: myRenderer2,
  23821. validator: myValidator2
  23822. });
  23823. expect(getEditor('myCellType')).toBe(MyEditor);
  23824. expect(getRenderer('myCellType')).toBe(myRenderer2);
  23825. expect(getValidator('myCellType')).toBe(myValidator2);
  23826. });
  23827. it('should retrieve custom cell type by its names', function () {
  23828. var MyEditor = function MyEditor() {
  23829. _classCallCheck(this, MyEditor);
  23830. };
  23831. function myRenderer() {}
  23832. function myValidator() {}
  23833. registerCellType('myCellType', {
  23834. editor: MyEditor,
  23835. renderer: myRenderer,
  23836. validator: myValidator
  23837. });
  23838. expect(getCellType('myCellType').editor).toBe(MyEditor);
  23839. expect(getCellType('myCellType').renderer).toBe(myRenderer);
  23840. expect(getCellType('myCellType').validator).toBe(myValidator);
  23841. });
  23842. });
  23843. /***/ }),
  23844. /* 188 */
  23845. /***/ (function(module, exports, __webpack_require__) {
  23846. "use strict";
  23847. describe('Core.colToProp', function () {
  23848. var id = 'testContainer';
  23849. beforeEach(function () {
  23850. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23851. });
  23852. afterEach(function () {
  23853. if (this.$container) {
  23854. destroy();
  23855. this.$container.remove();
  23856. }
  23857. });
  23858. it('should return the property name for the provided column number', function () {
  23859. var hot = handsontable({
  23860. data: [{
  23861. id: 1,
  23862. firstName: 'Tobias',
  23863. lastName: 'Forge'
  23864. }]
  23865. });
  23866. expect(colToProp(0)).toBe('id');
  23867. expect(colToProp(1)).toBe('firstName');
  23868. expect(colToProp(2)).toBe('lastName');
  23869. });
  23870. it('it should return the provided property name, when the user passes a property name as a column number', function () {
  23871. var hot = handsontable({
  23872. data: [{
  23873. id: 1,
  23874. sort: true,
  23875. length: 2
  23876. }]
  23877. });
  23878. expect(colToProp('id')).toBe('id');
  23879. expect(colToProp('sort')).toBe('sort');
  23880. expect(colToProp('length')).toBe('length');
  23881. });
  23882. });
  23883. /***/ }),
  23884. /* 189 */
  23885. /***/ (function(module, exports, __webpack_require__) {
  23886. "use strict";
  23887. describe('Core.countSourceCols', function () {
  23888. var id = 'testContainer';
  23889. beforeEach(function () {
  23890. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23891. });
  23892. afterEach(function () {
  23893. if (this.$container) {
  23894. destroy();
  23895. this.$container.remove();
  23896. }
  23897. });
  23898. it('should return properly index from ', function () {
  23899. var hot = handsontable({
  23900. data: [['', '', '', '', '', '', '', '', '', '', '', '', '', '', '']],
  23901. columns: function columns(column) {
  23902. return [1, 5, 9].indexOf(column) > -1 ? {} : null;
  23903. }
  23904. });
  23905. expect(hot.countSourceCols()).toBe(15);
  23906. });
  23907. });
  23908. /***/ }),
  23909. /* 190 */
  23910. /***/ (function(module, exports, __webpack_require__) {
  23911. "use strict";
  23912. describe('Core.getCellMetaAtRow', function () {
  23913. var id = 'testContainer';
  23914. beforeEach(function () {
  23915. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23916. });
  23917. afterEach(function () {
  23918. if (this.$container) {
  23919. destroy();
  23920. this.$container.remove();
  23921. }
  23922. });
  23923. it('should return a row of cell meta in a form of an array', function () {
  23924. handsontable();
  23925. var rowOfMeta = getCellMetaAtRow(0);
  23926. expect(rowOfMeta.length).toBe(5);
  23927. expect(rowOfMeta[0].row).toBe(0);
  23928. expect(rowOfMeta[1].row).toBe(0);
  23929. expect(rowOfMeta[2].row).toBe(0);
  23930. expect(rowOfMeta[3].row).toBe(0);
  23931. expect(rowOfMeta[4].row).toBe(0);
  23932. expect(rowOfMeta[0].col).toBe(0);
  23933. expect(rowOfMeta[1].col).toBe(1);
  23934. expect(rowOfMeta[2].col).toBe(2);
  23935. expect(rowOfMeta[3].col).toBe(3);
  23936. expect(rowOfMeta[4].col).toBe(4);
  23937. expect(rowOfMeta[0].prop).toBe(0);
  23938. expect(rowOfMeta[1].prop).toBe(1);
  23939. expect(rowOfMeta[2].prop).toBe(2);
  23940. expect(rowOfMeta[3].prop).toBe(3);
  23941. expect(rowOfMeta[4].prop).toBe(4);
  23942. });
  23943. });
  23944. /***/ }),
  23945. /* 191 */
  23946. /***/ (function(module, exports, __webpack_require__) {
  23947. "use strict";
  23948. describe('Core.getCellsMeta', function () {
  23949. var id = 'testContainer';
  23950. beforeEach(function () {
  23951. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23952. });
  23953. afterEach(function () {
  23954. if (this.$container) {
  23955. destroy();
  23956. this.$container.remove();
  23957. }
  23958. });
  23959. it('should return all initialized cells meta as flatten array', function () {
  23960. handsontable();
  23961. var metas = getCellsMeta();
  23962. expect(metas.length).toBe(25); // default data size
  23963. expect(metas[0].row).toBe(0);
  23964. expect(metas[0].col).toBe(0);
  23965. expect(metas[0].prop).toBe(0);
  23966. expect(metas[19].row).toBe(3);
  23967. expect(metas[19].col).toBe(4);
  23968. expect(metas[19].prop).toBe(4);
  23969. });
  23970. });
  23971. /***/ }),
  23972. /* 192 */
  23973. /***/ (function(module, exports, __webpack_require__) {
  23974. "use strict";
  23975. describe('Core.getCopyableData', function () {
  23976. var id = 'testContainer';
  23977. beforeEach(function () {
  23978. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  23979. });
  23980. afterEach(function () {
  23981. if (this.$container) {
  23982. destroy();
  23983. this.$container.remove();
  23984. }
  23985. });
  23986. it('should return copyable data when `copyable` option is enabled', function () {
  23987. handsontable({
  23988. data: Handsontable.helper.createSpreadsheetData(10, 10),
  23989. copyable: true
  23990. });
  23991. expect(getCopyableData(0, 0)).toBe('A1');
  23992. expect(getCopyableData(1, 1)).toBe('B2');
  23993. expect(getCopyableData(5, 1)).toBe('B6');
  23994. expect(getCopyableData(8, 9)).toBe('J9');
  23995. });
  23996. it('should return empty string as copyable data when `copyable` option is disabled', function () {
  23997. handsontable({
  23998. data: Handsontable.helper.createSpreadsheetData(10, 10),
  23999. copyable: false
  24000. });
  24001. expect(getCopyableData(0, 0)).toBe('');
  24002. expect(getCopyableData(1, 1)).toBe('');
  24003. expect(getCopyableData(5, 1)).toBe('');
  24004. expect(getCopyableData(8, 9)).toBe('');
  24005. });
  24006. });
  24007. /***/ }),
  24008. /* 193 */
  24009. /***/ (function(module, exports, __webpack_require__) {
  24010. "use strict";
  24011. describe('Core.getCopyableText', function () {
  24012. var id = 'testContainer';
  24013. beforeEach(function () {
  24014. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24015. });
  24016. afterEach(function () {
  24017. if (this.$container) {
  24018. destroy();
  24019. this.$container.remove();
  24020. }
  24021. });
  24022. it('should return copyable string when `copyable` option is enabled', function () {
  24023. handsontable({
  24024. data: Handsontable.helper.createSpreadsheetData(5, 5),
  24025. copyable: true
  24026. });
  24027. expect(getCopyableText(0, 0)).toBe('A1');
  24028. expect(getCopyableText(0, 0, 1, 2)).toBe('A1\tB1\tC1\nA2\tB2\tC2');
  24029. });
  24030. it('should return empty string as copyable data when `copyable` option is disabled', function () {
  24031. handsontable({
  24032. data: Handsontable.helper.createSpreadsheetData(5, 5),
  24033. copyable: false
  24034. });
  24035. expect(getCopyableText(0, 0)).toBe('');
  24036. expect(getCopyableText(0, 0, 1, 2)).toBe('\t\t\n\t\t');
  24037. });
  24038. });
  24039. /***/ }),
  24040. /* 194 */
  24041. /***/ (function(module, exports, __webpack_require__) {
  24042. "use strict";
  24043. describe('Core.getSourceDataArray', function () {
  24044. var id = 'testContainer';
  24045. beforeEach(function () {
  24046. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24047. });
  24048. afterEach(function () {
  24049. if (this.$container) {
  24050. destroy();
  24051. this.$container.remove();
  24052. }
  24053. });
  24054. it('should return data as an array when provided data was an array of arrays', function () {
  24055. handsontable({
  24056. data: [[1, 2, 3], ['a', 'b', 'c']],
  24057. copyable: true
  24058. });
  24059. expect(getSourceDataArray()).toEqual([[1, 2, 3], ['a', 'b', 'c']]);
  24060. expect(getSourceDataArray(0, 1, 1, 2)).toEqual([[2, 3], ['b', 'c']]);
  24061. });
  24062. it('should return data as an array when provided data was an array of objects', function () {
  24063. handsontable({
  24064. data: [{ a: 1, b: 2, c: 3 }, { a: 'a', b: 'b', c: 'c' }],
  24065. copyable: true
  24066. });
  24067. expect(getSourceDataArray()).toEqual([[1, 2, 3], ['a', 'b', 'c']]);
  24068. expect(getSourceDataArray(0, 1, 1, 2)).toEqual([[2, 3], ['b', 'c']]);
  24069. });
  24070. });
  24071. /***/ }),
  24072. /* 195 */
  24073. /***/ (function(module, exports, __webpack_require__) {
  24074. "use strict";
  24075. describe('Core.getSourceDataAtCell', function () {
  24076. var id = 'testContainer';
  24077. beforeEach(function () {
  24078. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24079. });
  24080. afterEach(function () {
  24081. if (this.$container) {
  24082. destroy();
  24083. this.$container.remove();
  24084. }
  24085. });
  24086. it('should return null when is call without arguments', function () {
  24087. handsontable({
  24088. data: [[1, 2, 3], ['a', 'b', 'c']]
  24089. });
  24090. expect(getSourceDataAtCell()).toBeNull();
  24091. });
  24092. it('should return cell value when provided data was an array of arrays', function () {
  24093. handsontable({
  24094. data: [[1, 2, 3], ['a', 'b', 'c']]
  24095. });
  24096. expect(getSourceDataAtCell(1, 1)).toEqual('b');
  24097. });
  24098. it('should return cell value when provided data was an array of objects', function () {
  24099. handsontable({
  24100. data: [{ a: 1, b: 2, c: 3 }, { a: 'a', b: 'b', c: 'c' }],
  24101. copyable: true
  24102. });
  24103. expect(getSourceDataAtCell(1, 'b')).toEqual('b');
  24104. });
  24105. it('should return cell value when provided data was an array of objects (nested structure)', function () {
  24106. handsontable({
  24107. data: [{ a: 1, b: { a: 21, b: 22 }, c: 3 }, { a: 'a', b: { a: 'ba', b: 'bb' }, c: 'c' }],
  24108. columns: [{ data: 'a' }, { data: 'b.a' }, { data: 'b.b' }, { data: 'c' }]
  24109. });
  24110. expect(getSourceDataAtCell(1, 'b.b')).toEqual('bb');
  24111. });
  24112. it('should return cell value when data is provided by dataSchema', function () {
  24113. handsontable({
  24114. data: [model({ id: 1, name: 'Ted Right', address: '' }), model({ id: 2, name: 'Frank Honest', address: '' }), model({ id: 3, name: 'Joan Well', address: '' }), model({ id: 4, name: 'Gail Polite', address: '' }), model({ id: 5, name: 'Michael Fair', address: '' })],
  24115. dataSchema: model,
  24116. columns: [{ data: property('id') }, { data: property('name') }, { data: property('address') }]
  24117. });
  24118. function model(opts) {
  24119. var _pub = {},
  24120. _priv = {
  24121. id: undefined,
  24122. name: undefined,
  24123. address: undefined
  24124. };
  24125. for (var i in opts) {
  24126. if (Object.prototype.hasOwnProperty.call(opts, i)) {
  24127. _priv[i] = opts[i];
  24128. }
  24129. }
  24130. _pub.attr = function (attr, val) {
  24131. if (typeof val === 'undefined') {
  24132. return _priv[attr];
  24133. }
  24134. _priv[attr] = val;
  24135. return _pub;
  24136. };
  24137. return _pub;
  24138. }
  24139. function property(attr) {
  24140. return function (row, value) {
  24141. return row.attr(attr, value);
  24142. };
  24143. }
  24144. expect(getSourceDataAtCell(1, 1)).toEqual('Frank Honest');
  24145. });
  24146. describe('`modifyRowData` hook', function () {
  24147. it('should be possible to change data for row on the fly ', function () {
  24148. handsontable({
  24149. data: [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]],
  24150. modifyRowData: function modifyRowData(row) {
  24151. var newDataset = [];
  24152. if (row === 1) {
  24153. newDataset.push('2016', 0, 0, 0, 0);
  24154. }
  24155. return newDataset.length ? newDataset : void 0;
  24156. }
  24157. });
  24158. expect(getSourceDataAtCell(1, 0)).toEqual('2016');
  24159. });
  24160. });
  24161. });
  24162. /***/ }),
  24163. /* 196 */
  24164. /***/ (function(module, exports, __webpack_require__) {
  24165. "use strict";
  24166. describe('Core.propToCol', function () {
  24167. var id = 'testContainer';
  24168. beforeEach(function () {
  24169. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24170. });
  24171. afterEach(function () {
  24172. if (this.$container) {
  24173. destroy();
  24174. this.$container.remove();
  24175. }
  24176. });
  24177. it('should return valid index for newly added column when manualColumnMove is enabled', function () {
  24178. var hot = handsontable({
  24179. data: Handsontable.helper.createSpreadsheetData(10, 10),
  24180. manualColumnMove: true
  24181. });
  24182. hot.alter('insert_col', 5);
  24183. expect(propToCol(0)).toBe(0);
  24184. expect(propToCol(10)).toBe(10);
  24185. });
  24186. });
  24187. /***/ }),
  24188. /* 197 */
  24189. /***/ (function(module, exports, __webpack_require__) {
  24190. "use strict";
  24191. describe('Core.setCellMeta', function () {
  24192. var id = 'testContainer';
  24193. beforeEach(function () {
  24194. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24195. });
  24196. afterEach(function () {
  24197. if (this.$container) {
  24198. destroy();
  24199. this.$container.remove();
  24200. }
  24201. });
  24202. it('should set correct meta className for cell', function () {
  24203. var className = 'htCenter htMiddle';
  24204. handsontable({
  24205. afterCellMetaReset: function afterCellMetaReset() {
  24206. this.setCellMeta(0, 0, 'className', className);
  24207. }
  24208. });
  24209. var cellMeta = getCellMeta(0, 0);
  24210. expect(cellMeta.className).not.toBeUndefined();
  24211. expect(cellMeta.className).toEqual(className);
  24212. });
  24213. it('should set correct meta className for non existed cell', function () {
  24214. var className = 'htCenter htMiddle';
  24215. handsontable({
  24216. data: Handsontable.helper.createSpreadsheetData(5, 5),
  24217. afterCellMetaReset: function afterCellMetaReset() {
  24218. this.setCellMeta(100, 100, 'className', className);
  24219. }
  24220. });
  24221. var cellMeta = getCellMeta(100, 100);
  24222. expect(cellMeta.className).not.toBeUndefined();
  24223. expect(cellMeta.className).toEqual(className);
  24224. });
  24225. it('should set correct meta classNames for cells using cell in configuration', function () {
  24226. var classNames = ['htCenter htTop', 'htRight htBottom'];
  24227. handsontable({
  24228. cell: [{ row: 0, col: 0, className: classNames[0] }, { row: 1, col: 1, className: classNames[1] }]
  24229. });
  24230. expect(this.$container.find('tbody tr:eq(0) td:eq(0)')[0].className).toEqual(classNames[0]);
  24231. expect(this.$container.find('tbody tr:eq(1) td:eq(1)')[0].className).toEqual(classNames[1]);
  24232. });
  24233. it('should change cell meta data with updateSettings when the cell option is defined', function () {
  24234. var classNames = ['htCenter htTop', 'htRight htBottom'];
  24235. handsontable({
  24236. cell: [{ row: 0, col: 0, className: classNames[0] }, { row: 1, col: 1, className: classNames[1] }]
  24237. });
  24238. expect(this.$container.find('tbody tr:eq(0) td:eq(0)')[0].className).toEqual(classNames[0]);
  24239. expect(this.$container.find('tbody tr:eq(1) td:eq(1)')[0].className).toEqual(classNames[1]);
  24240. updateSettings({
  24241. cell: []
  24242. });
  24243. expect(this.$container.find('tbody tr:eq(0) td:eq(0)')[0].className).toEqual('');
  24244. expect(this.$container.find('tbody tr:eq(1) td:eq(1)')[0].className).toEqual('');
  24245. updateSettings({
  24246. cell: [{ row: 0, col: 0, className: classNames[1] }, { row: 1, col: 1, className: classNames[0] }]
  24247. });
  24248. expect(this.$container.find('tbody tr:eq(0) td:eq(0)')[0].className).toEqual(classNames[1]);
  24249. expect(this.$container.find('tbody tr:eq(1) td:eq(1)')[0].className).toEqual(classNames[0]);
  24250. });
  24251. it('should call afterSetCellMeta plugin hook', function () {
  24252. var className = 'htCenter htMiddle';
  24253. var res = {};
  24254. handsontable({
  24255. afterCellMetaReset: function afterCellMetaReset() {
  24256. this.setCellMeta(0, 1, 'className', className);
  24257. },
  24258. afterSetCellMeta: function afterSetCellMeta(row, col, key, val) {
  24259. res.row = row;
  24260. res.col = col;
  24261. res.key = key;
  24262. res.val = val;
  24263. }
  24264. });
  24265. expect(res.row).toEqual(0);
  24266. expect(res.col).toEqual(1);
  24267. expect(res.key).toEqual('className');
  24268. expect(res.val).toEqual(className);
  24269. });
  24270. });
  24271. /***/ }),
  24272. /* 198 */
  24273. /***/ (function(module, exports, __webpack_require__) {
  24274. "use strict";
  24275. describe('Core.spliceCellsMeta', function () {
  24276. var id = 'testContainer';
  24277. beforeEach(function () {
  24278. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24279. });
  24280. afterEach(function () {
  24281. if (this.$container) {
  24282. destroy();
  24283. this.$container.remove();
  24284. }
  24285. });
  24286. it('should splice the cell meta array analogously to the native `splice` method', function () {
  24287. handsontable();
  24288. var allMeta = getCellsMeta();
  24289. expect(allMeta.length).toBe(25);
  24290. spliceCellsMeta(3, 1);
  24291. allMeta = getCellsMeta();
  24292. expect(allMeta.length).toBe(20);
  24293. var metaAtRow = getCellMetaAtRow(2);
  24294. expect(metaAtRow[0].row).toEqual(2);
  24295. metaAtRow = getCellMetaAtRow(3);
  24296. expect(metaAtRow[0].row).toEqual(4);
  24297. });
  24298. });
  24299. /***/ }),
  24300. /* 199 */
  24301. /***/ (function(module, exports, __webpack_require__) {
  24302. "use strict";
  24303. describe('Core.spliceCol', function () {
  24304. var id = 'testContainer';
  24305. beforeEach(function () {
  24306. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24307. });
  24308. afterEach(function () {
  24309. if (this.$container) {
  24310. destroy();
  24311. this.$container.remove();
  24312. }
  24313. });
  24314. it('should remove from the second column three rows starting from the beginning', function () {
  24315. var hot = handsontable({
  24316. data: Handsontable.helper.createSpreadsheetData(5, 5)
  24317. });
  24318. var removedData = hot.spliceCol(1, 0, 3);
  24319. expect(removedData).toEqual(['B1', 'B2', 'B3']);
  24320. expect(hot.getDataAtRow(0)).toEqual(['A1', 'B4', 'C1', 'D1', 'E1']);
  24321. expect(hot.getDataAtRow(1)).toEqual(['A2', 'B5', 'C2', 'D2', 'E2']);
  24322. expect(hot.getDataAtRow(2)).toEqual(['A3', null, 'C3', 'D3', 'E3']);
  24323. expect(hot.getDataAtRow(3)).toEqual(['A4', null, 'C4', 'D4', 'E4']);
  24324. expect(hot.getDataAtRow(4)).toEqual(['A5', null, 'C5', 'D5', 'E5']);
  24325. });
  24326. it('should remove from the third column three rows starting from the second row', function () {
  24327. var hot = handsontable({
  24328. data: Handsontable.helper.createSpreadsheetData(5, 5)
  24329. });
  24330. var removedData = hot.spliceCol(2, 1, 3);
  24331. expect(removedData).toEqual(['C2', 'C3', 'C4']);
  24332. expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1']);
  24333. expect(hot.getDataAtRow(1)).toEqual(['A2', 'B2', 'C5', 'D2', 'E2']);
  24334. expect(hot.getDataAtRow(2)).toEqual(['A3', 'B3', null, 'D3', 'E3']);
  24335. expect(hot.getDataAtRow(3)).toEqual(['A4', 'B4', null, 'D4', 'E4']);
  24336. expect(hot.getDataAtRow(4)).toEqual(['A5', 'B5', null, 'D5', 'E5']);
  24337. });
  24338. it('should replace and append new rows in the second column starting from the second row', function () {
  24339. var hot = handsontable({
  24340. data: Handsontable.helper.createSpreadsheetData(5, 5)
  24341. });
  24342. var removedData = hot.spliceCol(1, 1, 3, 'X1', 'X2', 'X3', 'X4', 'X5');
  24343. expect(removedData).toEqual(['B2', 'B3', 'B4']);
  24344. expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1']);
  24345. expect(hot.getDataAtRow(1)).toEqual(['A2', 'X1', 'C2', 'D2', 'E2']);
  24346. expect(hot.getDataAtRow(2)).toEqual(['A3', 'X2', 'C3', 'D3', 'E3']);
  24347. expect(hot.getDataAtRow(3)).toEqual(['A4', 'X3', 'C4', 'D4', 'E4']);
  24348. expect(hot.getDataAtRow(4)).toEqual(['A5', 'X4', 'C5', 'D5', 'E5']);
  24349. expect(hot.getDataAtRow(5)).toEqual([null, 'X5', null, null, null]);
  24350. expect(hot.getDataAtRow(6)).toEqual([null, 'B5', null, null, null]);
  24351. });
  24352. it('should trigger beforeChange and afterChange hook with proper arguments', function () {
  24353. var spyAfter = jasmine.createSpy('after');
  24354. var spyBefore = jasmine.createSpy('before');
  24355. var hot = handsontable({
  24356. data: Handsontable.helper.createSpreadsheetData(5, 5),
  24357. beforeChange: spyBefore,
  24358. afterChange: spyAfter
  24359. });
  24360. hot.spliceCol(2, 1, 3, 'X1');
  24361. expect(spyBefore.calls.argsFor(0)[0]).toEqual([[1, 2, 'C2', 'X1'], [2, 2, 'C3', 'C5'], [3, 2, 'C4', null], [4, 2, 'C5', null], [5, 2, null, null]]);
  24362. expect(spyBefore.calls.argsFor(0)[1]).toBe('spliceCol');
  24363. expect(spyAfter.calls.argsFor(1)[0]).toEqual([[1, 2, 'C2', 'X1'], [2, 2, 'C3', 'C5'], [3, 2, 'C4', null], [4, 2, 'C5', null], [5, 2, null, null]]);
  24364. expect(spyAfter.calls.argsFor(1)[1]).toBe('spliceCol');
  24365. });
  24366. it('should trigger beforeCreateRow and afterCreateRow hook with proper arguments', function () {
  24367. var spyAfter = jasmine.createSpy('after');
  24368. var spyBefore = jasmine.createSpy('before');
  24369. var hot = handsontable({
  24370. data: Handsontable.helper.createSpreadsheetData(5, 5),
  24371. beforeCreateRow: spyBefore,
  24372. afterCreateRow: spyAfter
  24373. });
  24374. hot.spliceCol(2, 1, 3, 'X1', 'X2', 'X3', 'X4');
  24375. expect(spyBefore).toHaveBeenCalledWith(5, 1, 'spliceCol', undefined, undefined, undefined);
  24376. expect(spyAfter).toHaveBeenCalledWith(5, 1, 'spliceCol', undefined, undefined, undefined);
  24377. });
  24378. });
  24379. /***/ }),
  24380. /* 200 */
  24381. /***/ (function(module, exports, __webpack_require__) {
  24382. "use strict";
  24383. describe('Core.spliceRow', function () {
  24384. var id = 'testContainer';
  24385. beforeEach(function () {
  24386. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24387. });
  24388. afterEach(function () {
  24389. if (this.$container) {
  24390. destroy();
  24391. this.$container.remove();
  24392. }
  24393. });
  24394. it('should remove from the second row three columns starting from the beginning', function () {
  24395. var hot = handsontable({
  24396. data: Handsontable.helper.createSpreadsheetData(5, 5)
  24397. });
  24398. var removedData = hot.spliceRow(1, 0, 3);
  24399. expect(removedData).toEqual(['A2', 'B2', 'C2']);
  24400. expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1']);
  24401. expect(hot.getDataAtRow(1)).toEqual(['D2', 'E2', null, null, null]);
  24402. expect(hot.getDataAtRow(2)).toEqual(['A3', 'B3', 'C3', 'D3', 'E3']);
  24403. expect(hot.getDataAtRow(3)).toEqual(['A4', 'B4', 'C4', 'D4', 'E4']);
  24404. expect(hot.getDataAtRow(4)).toEqual(['A5', 'B5', 'C5', 'D5', 'E5']);
  24405. });
  24406. it('should remove from the third row three columns starting from the second column', function () {
  24407. var hot = handsontable({
  24408. data: Handsontable.helper.createSpreadsheetData(5, 5)
  24409. });
  24410. var removedData = hot.spliceRow(2, 1, 3);
  24411. expect(removedData).toEqual(['B3', 'C3', 'D3']);
  24412. expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1']);
  24413. expect(hot.getDataAtRow(1)).toEqual(['A2', 'B2', 'C2', 'D2', 'E2']);
  24414. expect(hot.getDataAtRow(2)).toEqual(['A3', 'E3', null, null, null]);
  24415. expect(hot.getDataAtRow(3)).toEqual(['A4', 'B4', 'C4', 'D4', 'E4']);
  24416. expect(hot.getDataAtRow(4)).toEqual(['A5', 'B5', 'C5', 'D5', 'E5']);
  24417. });
  24418. it('should replace and append new columns in the second row starting from the second column', function () {
  24419. var hot = handsontable({
  24420. data: Handsontable.helper.createSpreadsheetData(5, 5)
  24421. });
  24422. var removedData = hot.spliceRow(1, 1, 3, 'X1', 'X2', 'X3', 'X4', 'X5');
  24423. expect(removedData).toEqual(['B2', 'C2', 'D2']);
  24424. expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', null, null]);
  24425. expect(hot.getDataAtRow(1)).toEqual(['A2', 'X1', 'X2', 'X3', 'X4', 'X5', 'E2']);
  24426. expect(hot.getDataAtRow(2)).toEqual(['A3', 'B3', 'C3', 'D3', 'E3', null, null]);
  24427. expect(hot.getDataAtRow(3)).toEqual(['A4', 'B4', 'C4', 'D4', 'E4', null, null]);
  24428. expect(hot.getDataAtRow(4)).toEqual(['A5', 'B5', 'C5', 'D5', 'E5', null, null]);
  24429. });
  24430. it('should trigger beforeChange and afterChange hook with proper arguments', function () {
  24431. var spyAfter = jasmine.createSpy('after');
  24432. var spyBefore = jasmine.createSpy('before');
  24433. var hot = handsontable({
  24434. data: Handsontable.helper.createSpreadsheetData(5, 5),
  24435. beforeChange: spyBefore,
  24436. afterChange: spyAfter
  24437. });
  24438. hot.spliceRow(2, 1, 3, 'X1');
  24439. expect(spyBefore.calls.argsFor(0)[0]).toEqual([[2, 1, 'B3', 'X1'], [2, 2, 'C3', 'E3'], [2, 3, 'D3', null], [2, 4, 'E3', null], [2, 5, undefined, null]]);
  24440. expect(spyBefore.calls.argsFor(0)[1]).toBe('spliceRow');
  24441. expect(spyAfter.calls.argsFor(1)[0]).toEqual([[2, 1, 'B3', 'X1'], [2, 2, 'C3', 'E3'], [2, 3, 'D3', null], [2, 4, 'E3', null], [2, 5, undefined, null]]);
  24442. expect(spyAfter.calls.argsFor(1)[1]).toBe('spliceRow');
  24443. });
  24444. it('should trigger beforeCreateCol and afterCreateCol hook with proper arguments', function () {
  24445. var spyAfter = jasmine.createSpy('after');
  24446. var spyBefore = jasmine.createSpy('before');
  24447. var hot = handsontable({
  24448. data: Handsontable.helper.createSpreadsheetData(5, 5),
  24449. beforeCreateCol: spyBefore,
  24450. afterCreateCol: spyAfter
  24451. });
  24452. hot.spliceRow(2, 1, 3, 'X1', 'X2', 'X3', 'X4');
  24453. expect(spyBefore).toHaveBeenCalledWith(5, 1, 'spliceRow', undefined, undefined, undefined);
  24454. expect(spyAfter).toHaveBeenCalledWith(5, 1, 'spliceRow', undefined, undefined, undefined);
  24455. });
  24456. });
  24457. /***/ }),
  24458. /* 201 */
  24459. /***/ (function(module, exports, __webpack_require__) {
  24460. "use strict";
  24461. describe('Core.toPhysicalColumn', function () {
  24462. var id = 'testContainer';
  24463. beforeEach(function () {
  24464. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24465. });
  24466. afterEach(function () {
  24467. if (this.$container) {
  24468. destroy();
  24469. this.$container.remove();
  24470. }
  24471. });
  24472. it('should return valid physical row index', function () {
  24473. var hot = handsontable({
  24474. data: Handsontable.helper.createSpreadsheetData(10, 10),
  24475. modifyCol: function modifyCol(column) {
  24476. return column + 3;
  24477. }
  24478. });
  24479. expect(hot.toPhysicalColumn(0)).toBe(3);
  24480. expect(hot.toPhysicalColumn(1)).toBe(4);
  24481. expect(hot.toPhysicalColumn(2)).toBe(5);
  24482. });
  24483. });
  24484. /***/ }),
  24485. /* 202 */
  24486. /***/ (function(module, exports, __webpack_require__) {
  24487. "use strict";
  24488. describe('Core.toPhysicalRow', function () {
  24489. var id = 'testContainer';
  24490. beforeEach(function () {
  24491. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24492. });
  24493. afterEach(function () {
  24494. if (this.$container) {
  24495. destroy();
  24496. this.$container.remove();
  24497. }
  24498. });
  24499. it('should return valid physical row index', function () {
  24500. var hot = handsontable({
  24501. data: Handsontable.helper.createSpreadsheetData(10, 10),
  24502. modifyRow: function modifyRow(row) {
  24503. return row + 3;
  24504. }
  24505. });
  24506. expect(hot.toPhysicalRow(0)).toBe(3);
  24507. expect(hot.toPhysicalRow(1)).toBe(4);
  24508. expect(hot.toPhysicalRow(2)).toBe(5);
  24509. });
  24510. });
  24511. /***/ }),
  24512. /* 203 */
  24513. /***/ (function(module, exports, __webpack_require__) {
  24514. "use strict";
  24515. describe('Core.toVisualColumn', function () {
  24516. var id = 'testContainer';
  24517. beforeEach(function () {
  24518. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24519. });
  24520. afterEach(function () {
  24521. if (this.$container) {
  24522. destroy();
  24523. this.$container.remove();
  24524. }
  24525. });
  24526. it('should return valid visual row index', function () {
  24527. var hot = handsontable({
  24528. data: Handsontable.helper.createSpreadsheetData(10, 10),
  24529. unmodifyCol: function unmodifyCol(column) {
  24530. return column + 3;
  24531. }
  24532. });
  24533. expect(hot.toVisualColumn(0)).toBe(3);
  24534. expect(hot.toVisualColumn(1)).toBe(4);
  24535. expect(hot.toVisualColumn(2)).toBe(5);
  24536. });
  24537. });
  24538. /***/ }),
  24539. /* 204 */
  24540. /***/ (function(module, exports, __webpack_require__) {
  24541. "use strict";
  24542. describe('Core.toVisualRow', function () {
  24543. var id = 'testContainer';
  24544. beforeEach(function () {
  24545. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  24546. });
  24547. afterEach(function () {
  24548. if (this.$container) {
  24549. destroy();
  24550. this.$container.remove();
  24551. }
  24552. });
  24553. it('should return valid visual row index', function () {
  24554. var hot = handsontable({
  24555. data: Handsontable.helper.createSpreadsheetData(10, 10),
  24556. unmodifyRow: function unmodifyRow(row) {
  24557. return row + 3;
  24558. }
  24559. });
  24560. expect(hot.toVisualRow(0)).toBe(3);
  24561. expect(hot.toVisualRow(1)).toBe(4);
  24562. expect(hot.toVisualRow(2)).toBe(5);
  24563. });
  24564. });
  24565. /***/ }),
  24566. /* 205 */
  24567. /***/ (function(module, exports, __webpack_require__) {
  24568. "use strict";
  24569. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  24570. describe('AutocompleteEditor', function () {
  24571. var id = 'testContainer';
  24572. var choices = ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white', 'purple', 'lime', 'olive', 'cyan'];
  24573. var hot;
  24574. beforeEach(function () {
  24575. this.$container = $('<div id="' + id + '" style="width: 300px; height: 200px; overflow: auto"></div>').appendTo('body');
  24576. });
  24577. afterEach(function () {
  24578. if (hot) {
  24579. hot = null;
  24580. }
  24581. if (this.$container) {
  24582. destroy();
  24583. this.$container.remove();
  24584. }
  24585. });
  24586. describe('open editor', function () {
  24587. it('should display editor (after hitting ENTER)', function () {
  24588. handsontable({
  24589. columns: [{
  24590. editor: 'autocomplete',
  24591. source: choices
  24592. }]
  24593. });
  24594. selectCell(0, 0);
  24595. var editor = $('.autocompleteEditor');
  24596. expect(editor.is(':visible')).toBe(false);
  24597. keyDownUp('enter');
  24598. expect(editor.is(':visible')).toBe(true);
  24599. });
  24600. it('should display editor (after hitting F2)', function () {
  24601. handsontable({
  24602. columns: [{
  24603. editor: 'autocomplete',
  24604. source: choices
  24605. }]
  24606. });
  24607. selectCell(0, 0);
  24608. var editor = $('.autocompleteEditor');
  24609. expect(editor.is(':visible')).toBe(false);
  24610. keyDownUp('f2');
  24611. expect(editor.is(':visible')).toBe(true);
  24612. });
  24613. it('should display editor (after doubleclicking)', function () {
  24614. handsontable({
  24615. columns: [{
  24616. editor: 'autocomplete',
  24617. source: choices
  24618. }]
  24619. });
  24620. selectCell(0, 0);
  24621. var editor = $('.autocompleteEditor');
  24622. expect(editor.is(':visible')).toBe(false);
  24623. mouseDoubleClick($(getCell(0, 0)));
  24624. expect(editor.is(':visible')).toBe(true);
  24625. });
  24626. // see https://github.com/handsontable/handsontable/issues/3380
  24627. it('should not throw error while selecting the next cell by hitting enter key', function () {
  24628. var spy = jasmine.createSpyObj('error', ['test']);
  24629. var prevError = window.onerror;
  24630. window.onerror = function (messageOrEvent, source, lineno, colno, error) {
  24631. spy.test();
  24632. };
  24633. handsontable({
  24634. columns: [{
  24635. editor: 'autocomplete',
  24636. source: choices
  24637. }]
  24638. });
  24639. selectCell(0, 0);
  24640. keyDownUp('enter');
  24641. keyDownUp('enter');
  24642. keyDownUp('enter');
  24643. expect(spy.test.calls.count()).toBe(0);
  24644. window.onerror = prevError;
  24645. });
  24646. });
  24647. describe('choices', function () {
  24648. it('should display given choices (array)', function (done) {
  24649. handsontable({
  24650. columns: [{
  24651. editor: 'autocomplete',
  24652. source: choices
  24653. }]
  24654. });
  24655. selectCell(0, 0);
  24656. var editor = $('.autocompleteEditor');
  24657. keyDownUp('enter');
  24658. setTimeout(function () {
  24659. expect(editor.find('tbody td:eq(0)').text()).toEqual(choices[0]);
  24660. expect(editor.find('tbody td:eq(1)').text()).toEqual(choices[1]);
  24661. expect(editor.find('tbody td:eq(2)').text()).toEqual(choices[2]);
  24662. expect(editor.find('tbody td:eq(3)').text()).toEqual(choices[3]);
  24663. expect(editor.find('tbody td:eq(4)').text()).toEqual(choices[4]);
  24664. done();
  24665. }, 100);
  24666. });
  24667. it('should call source function with context set as cellProperties', function (done) {
  24668. var source = jasmine.createSpy('source');
  24669. var context;
  24670. source.and.callFake(function (query, process) {
  24671. process(choices);
  24672. context = this;
  24673. });
  24674. var hot = handsontable({
  24675. columns: [{
  24676. editor: 'autocomplete',
  24677. source: source
  24678. }]
  24679. });
  24680. selectCell(0, 0);
  24681. source.calls.reset();
  24682. keyDownUp('enter');
  24683. setTimeout(function () {
  24684. expect(context.instance).toBe(hot);
  24685. expect(context.row).toBe(0);
  24686. expect(context.col).toBe(0);
  24687. done();
  24688. }, 200);
  24689. });
  24690. it('should display given choices (sync function)', function (done) {
  24691. var syncSources = jasmine.createSpy('syncSources');
  24692. syncSources.and.callFake(function (query, process) {
  24693. process(choices);
  24694. });
  24695. handsontable({
  24696. columns: [{
  24697. editor: 'autocomplete',
  24698. source: syncSources
  24699. }]
  24700. });
  24701. selectCell(0, 0);
  24702. var editor = $('.autocompleteEditor');
  24703. syncSources.calls.reset();
  24704. keyDownUp('enter');
  24705. setTimeout(function () {
  24706. expect(editor.find('tbody td:eq(0)').text()).toEqual(choices[0]);
  24707. expect(editor.find('tbody td:eq(1)').text()).toEqual(choices[1]);
  24708. expect(editor.find('tbody td:eq(2)').text()).toEqual(choices[2]);
  24709. expect(editor.find('tbody td:eq(3)').text()).toEqual(choices[3]);
  24710. expect(editor.find('tbody td:eq(4)').text()).toEqual(choices[4]);
  24711. done();
  24712. }, 200);
  24713. });
  24714. it('should display given choices (async function)', function (done) {
  24715. var asyncSources = jasmine.createSpy('asyncSources');
  24716. asyncSources.and.callFake(function (process) {
  24717. process(choices);
  24718. });
  24719. handsontable({
  24720. columns: [{
  24721. editor: 'autocomplete',
  24722. source: function source(query, process) {
  24723. setTimeout(function () {
  24724. asyncSources(process);
  24725. }, 0);
  24726. }
  24727. }]
  24728. });
  24729. selectCell(0, 0);
  24730. var editor = $('.autocompleteEditor');
  24731. keyDownUp('enter');
  24732. setTimeout(function () {
  24733. expect(asyncSources.calls.count()).toEqual(1);
  24734. expect(editor.find('tbody td:eq(0)').text()).toEqual(choices[0]);
  24735. expect(editor.find('tbody td:eq(1)').text()).toEqual(choices[1]);
  24736. expect(editor.find('tbody td:eq(2)').text()).toEqual(choices[2]);
  24737. expect(editor.find('tbody td:eq(3)').text()).toEqual(choices[3]);
  24738. expect(editor.find('tbody td:eq(4)').text()).toEqual(choices[4]);
  24739. done();
  24740. }, 200);
  24741. });
  24742. it('should NOT update choices list, after cursor leaves and enters the list (#1330)', function (done) {
  24743. spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'updateChoicesList').and.callThrough();
  24744. var updateChoicesList = Handsontable.editors.AutocompleteEditor.prototype.updateChoicesList;
  24745. var hot = handsontable({
  24746. columns: [{
  24747. editor: 'autocomplete',
  24748. source: choices
  24749. }]
  24750. });
  24751. selectCell(0, 0);
  24752. var editor = hot.getActiveEditor();
  24753. keyDownUp('enter');
  24754. setTimeout(function () {
  24755. updateChoicesList.calls.reset();
  24756. $(editor.htContainer).find('.htCore tr:eq(0) td:eq(0)').mouseenter();
  24757. $(editor.htContainer).find('.htCore tr:eq(0) td:eq(0)').mouseleave();
  24758. $(editor.htContainer).find('.htCore tr:eq(0) td:eq(0)').mouseenter();
  24759. }, 200);
  24760. setTimeout(function () {
  24761. expect(updateChoicesList).not.toHaveBeenCalled();
  24762. done();
  24763. }, 300);
  24764. });
  24765. it('should update choices list exactly once after a key is pressed (#1330)', function (done) {
  24766. spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'updateChoicesList').and.callThrough();
  24767. var updateChoicesList = Handsontable.editors.AutocompleteEditor.prototype.updateChoicesList;
  24768. var hot = handsontable({
  24769. columns: [{
  24770. editor: 'autocomplete',
  24771. source: choices
  24772. }]
  24773. });
  24774. selectCell(0, 0);
  24775. var editor = hot.getActiveEditor();
  24776. updateChoicesList.calls.reset();
  24777. keyDownUp('enter');
  24778. setTimeout(function () {
  24779. updateChoicesList.calls.reset();
  24780. editor.TEXTAREA.value = 'red';
  24781. $(editor.TEXTAREA).simulate('keydown', {
  24782. keyCode: 'd'.charCodeAt(0)
  24783. });
  24784. }, 200);
  24785. setTimeout(function () {
  24786. expect(updateChoicesList.calls.count()).toEqual(1);
  24787. done();
  24788. }, 100);
  24789. });
  24790. it('should not initialize the dropdown with unneeded scrollbars (scrollbar causing a scrollbar issue)', function (done) {
  24791. spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'updateChoicesList').and.callThrough();
  24792. var updateChoicesList = Handsontable.editors.AutocompleteEditor.prototype.updateChoicesList;
  24793. var hot = handsontable({
  24794. data: [['blue'], [], [], []],
  24795. columns: [{
  24796. editor: 'autocomplete',
  24797. source: choices
  24798. }]
  24799. });
  24800. selectCell(0, 0);
  24801. var editor = hot.getActiveEditor();
  24802. updateChoicesList.calls.reset();
  24803. keyDownUp('enter');
  24804. setTimeout(function () {
  24805. expect(editor.htContainer.scrollWidth).toEqual(editor.htContainer.clientWidth);
  24806. done();
  24807. }, 200);
  24808. });
  24809. it('autocomplete list should have textarea dimensions', function (done) {
  24810. var syncSources = jasmine.createSpy('syncSources');
  24811. syncSources.and.callFake(function (query, process) {
  24812. process(choices);
  24813. });
  24814. handsontable({
  24815. colWidths: [200],
  24816. columns: [{
  24817. editor: 'autocomplete',
  24818. source: syncSources
  24819. }]
  24820. });
  24821. selectCell(0, 0);
  24822. var editor = $('.handsontableInputHolder');
  24823. syncSources.calls.reset();
  24824. keyDownUp('enter');
  24825. setTimeout(function () {
  24826. // -2 for transparent borders
  24827. expect(editor.find('.autocompleteEditor .htCore td').width()).toEqual(editor.find('.handsontableInput').width() - 2);
  24828. expect(editor.find('.autocompleteEditor .htCore td').width()).toBeGreaterThan(187);
  24829. done();
  24830. }, 200);
  24831. });
  24832. it('autocomplete list should have the suggestion table dimensions, when trimDropdown option is set to false', function (done) {
  24833. var syncSources = jasmine.createSpy('syncSources');
  24834. syncSources.and.callFake(function (query, process) {
  24835. process(['long text', 'even longer text', 'extremely long text in the suggestion list', 'short text', 'text', 'another', 'yellow', 'black']);
  24836. });
  24837. var hot = handsontable({
  24838. colWidths: [200],
  24839. columns: [{
  24840. editor: 'autocomplete',
  24841. source: syncSources
  24842. }],
  24843. trimDropdown: false
  24844. });
  24845. selectCell(0, 0);
  24846. var editor = $('.handsontableInputHolder');
  24847. syncSources.calls.reset();
  24848. keyDownUp('enter');
  24849. setTimeout(function () {
  24850. expect(editor.find('.autocompleteEditor .htCore td').eq(0).width()).toBeGreaterThan(editor.find('.handsontableInput').width());
  24851. done();
  24852. }, 200);
  24853. });
  24854. it('autocomplete textarea should have cell dimensions (after render)', function (done) {
  24855. var data = [['a', 'b'], ['c', 'd']];
  24856. hot = handsontable({
  24857. data: data,
  24858. minRows: 4,
  24859. minCols: 4,
  24860. minSpareRows: 4,
  24861. minSpareCols: 4,
  24862. cells: function cells() {
  24863. return {
  24864. type: Handsontable.AutocompleteCell
  24865. };
  24866. }
  24867. });
  24868. selectCell(1, 1);
  24869. keyDownUp('enter');
  24870. data[1][1] = 'dddddddddddddddddddd';
  24871. render();
  24872. setTimeout(function () {
  24873. var $td = spec().$container.find('.htCore tbody tr:eq(1) td:eq(1)');
  24874. expect(autocompleteEditor().width()).toEqual($td.width());
  24875. done();
  24876. }, 10);
  24877. });
  24878. it('should invoke beginEditing only once after dobleclicking on a cell (#1011)', function () {
  24879. var hot = handsontable({
  24880. columns: [{}, {}, {
  24881. type: 'autocomplete',
  24882. source: choices
  24883. }]
  24884. });
  24885. selectCell(0, 2);
  24886. spyOn(hot.getActiveEditor(), 'beginEditing');
  24887. expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(0);
  24888. mouseDoubleClick(getCell(0, 2));
  24889. expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(1);
  24890. mouseDoubleClick(getCell(1, 2));
  24891. expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(2);
  24892. mouseDoubleClick(getCell(2, 2));
  24893. expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(3);
  24894. });
  24895. it('should not display all the choices from a long source list and not leave any unused space in the dropdown (YouTrack: #HOT-32)', function (done) {
  24896. var hot = handsontable({
  24897. columns: [{
  24898. type: 'autocomplete',
  24899. source: ['Acura', 'Audi', 'BMW', 'Buick', 'Cadillac', 'Chevrolet', 'Chrysler', 'Citroen', 'Dodge', 'Eagle', 'Ferrari', 'Ford', 'General Motors', 'GMC', 'Honda', 'Hummer', 'Hyundai', 'Infiniti', 'Isuzu', 'Jaguar', 'Jeep', 'Kia', 'Lamborghini', 'Land Rover', 'Lexus', 'Lincoln', 'Lotus', 'Mazda', 'Mercedes-Benz', 'Mercury', 'Mitsubishi', 'Nissan', 'Oldsmobile', 'Peugeot', 'Pontiac', 'Porsche', 'Regal', 'Renault', 'Saab', 'Saturn', 'Seat', 'Skoda', 'Subaru', 'Suzuki', 'Toyota', 'Volkswagen', 'Volvo']
  24900. }]
  24901. });
  24902. selectCell(0, 0);
  24903. keyDownUp('enter');
  24904. var $autocomplete = autocomplete();
  24905. var $autocompleteHolder = $autocomplete.find('.ht_master .wtHolder').first();
  24906. setTimeout(function () {
  24907. expect($autocomplete.find('td').first().text()).toEqual('Acura');
  24908. $autocompleteHolder.scrollTop($autocompleteHolder[0].scrollHeight);
  24909. }, 100);
  24910. setTimeout(function () {
  24911. expect($autocomplete.find('td').last().text()).toEqual('Volvo');
  24912. done();
  24913. }, 200);
  24914. });
  24915. it('should display the choices, regardless if they\'re declared as string or numeric', function (done) {
  24916. handsontable({
  24917. columns: [{
  24918. editor: 'autocomplete',
  24919. source: ['1', '2', 3, '4', 5, 6]
  24920. }]
  24921. });
  24922. selectCell(0, 0);
  24923. var editor = $('.autocompleteEditor');
  24924. keyDownUp('enter');
  24925. setTimeout(function () {
  24926. expect(editor.find('tbody td:eq(0)').text()).toEqual('1');
  24927. expect(editor.find('tbody td:eq(1)').text()).toEqual('2');
  24928. expect(editor.find('tbody td:eq(2)').text()).toEqual('3');
  24929. expect(editor.find('tbody td:eq(3)').text()).toEqual('4');
  24930. expect(editor.find('tbody td:eq(4)').text()).toEqual('5');
  24931. expect(editor.find('tbody td:eq(5)').text()).toEqual('6');
  24932. done();
  24933. }, 100);
  24934. });
  24935. it('should display the choices, regardless if they\'re declared as string or numeric, when data is present', function (done) {
  24936. handsontable({
  24937. data: Handsontable.helper.createSpreadsheetData(10, 1),
  24938. columns: [{
  24939. editor: 'autocomplete',
  24940. source: ['1', '2', 3, '4', 5, 6]
  24941. }]
  24942. });
  24943. selectCell(0, 0);
  24944. keyDownUp('backspace');
  24945. var editor = $('.autocompleteEditor');
  24946. keyDownUp('enter');
  24947. setTimeout(function () {
  24948. expect(editor.find('tbody td:eq(0)').text()).toEqual('1');
  24949. expect(editor.find('tbody td:eq(1)').text()).toEqual('2');
  24950. expect(editor.find('tbody td:eq(2)').text()).toEqual('3');
  24951. expect(editor.find('tbody td:eq(3)').text()).toEqual('4');
  24952. expect(editor.find('tbody td:eq(4)').text()).toEqual('5');
  24953. expect(editor.find('tbody td:eq(5)').text()).toEqual('6');
  24954. done();
  24955. }, 100);
  24956. });
  24957. it('should display the dropdown above the editor, when there is not enough space below the cell AND there is more space above the cell', function (done) {
  24958. var hot = handsontable({
  24959. data: Handsontable.helper.createSpreadsheetData(30, 30),
  24960. columns: [{
  24961. editor: 'autocomplete',
  24962. source: choices
  24963. }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  24964. width: 400,
  24965. height: 400
  24966. });
  24967. setDataAtCell(29, 0, '');
  24968. selectCell(29, 0);
  24969. mouseDoubleClick($(getCell(29, 0)));
  24970. setTimeout(function () {
  24971. var autocompleteEditor = $('.autocompleteEditor');
  24972. expect(autocompleteEditor.css('position')).toEqual('absolute');
  24973. expect(autocompleteEditor.css('top')).toEqual(-1 * autocompleteEditor.height() + 'px');
  24974. done();
  24975. }, 200);
  24976. });
  24977. it('should flip the dropdown upwards when there is no more room left below the cell after filtering the choice list', function (done) {
  24978. var hot = handsontable({
  24979. data: Handsontable.helper.createSpreadsheetData(30, 30),
  24980. columns: [{
  24981. editor: 'autocomplete',
  24982. source: choices
  24983. }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  24984. width: 400,
  24985. height: 400
  24986. });
  24987. setDataAtCell(26, 0, 'b');
  24988. selectCell(26, 0);
  24989. hot.view.wt.wtTable.holder.scrollTop = 999;
  24990. mouseDoubleClick($(getCell(26, 0)));
  24991. var autocompleteEditor = $('.autocompleteEditor');
  24992. setTimeout(function () {
  24993. expect(autocompleteEditor.css('position')).toEqual('relative');
  24994. autocompleteEditor.siblings('textarea').first().val('');
  24995. keyDownUp('backspace');
  24996. }, 20);
  24997. setTimeout(function () {
  24998. expect(autocompleteEditor.css('position')).toEqual('absolute');
  24999. expect(autocompleteEditor.css('top')).toEqual(-1 * autocompleteEditor.height() + 'px');
  25000. done();
  25001. }, 100);
  25002. });
  25003. });
  25004. describe('closing editor', function () {
  25005. it('should destroy editor when value change with mouse click on suggestion', function (done) {
  25006. var syncSources = jasmine.createSpy('syncSources');
  25007. syncSources.and.callFake(function (query, process) {
  25008. process(choices);
  25009. });
  25010. handsontable({
  25011. columns: [{
  25012. editor: 'autocomplete',
  25013. source: syncSources
  25014. }]
  25015. });
  25016. selectCell(0, 0);
  25017. keyDownUp('enter');
  25018. setTimeout(function () {
  25019. autocomplete().find('tbody td:eq(3)').simulate('mousedown');
  25020. expect(getDataAtCell(0, 0)).toEqual('green');
  25021. done();
  25022. }, 200);
  25023. });
  25024. it('should not change value type from `numeric` to `string` after mouse click suggestion - ' + 'test no. 1 #4143', function (done) {
  25025. handsontable({
  25026. columns: [{
  25027. editor: 'autocomplete',
  25028. source: [1, 2, 3, 4, 5, 11, 14]
  25029. }]
  25030. });
  25031. selectCell(0, 0);
  25032. keyDownUp('enter');
  25033. setTimeout(function () {
  25034. autocomplete().find('tbody td:eq(0)').simulate('mousedown');
  25035. expect(_typeof(getDataAtCell(0, 0))).toEqual('number');
  25036. done();
  25037. }, 200);
  25038. });
  25039. it('should not change value type from `numeric` to `string` after mouse click on suggestion - ' + 'test no. 2 #4143', function (done) {
  25040. var syncSources = jasmine.createSpy('syncSources');
  25041. var source = [1, 2, 3, 4, 5, 11, 14];
  25042. syncSources.and.callFake(function (query, process) {
  25043. process(source);
  25044. });
  25045. handsontable({
  25046. columns: [{
  25047. editor: 'autocomplete',
  25048. source: syncSources
  25049. }]
  25050. });
  25051. selectCell(0, 0);
  25052. keyDownUp('enter');
  25053. setTimeout(function () {
  25054. autocomplete().find('tbody td:eq(0)').simulate('mousedown');
  25055. expect(_typeof(getDataAtCell(0, 0))).toEqual('number');
  25056. done();
  25057. }, 200);
  25058. });
  25059. it('should call `afterChange` hook with proper value types - test no. 1 #4143', function (done) {
  25060. var changesInside = void 0;
  25061. var sourceInside = void 0;
  25062. var afterChange = function afterChange(changes, source) {
  25063. if (source !== 'loadData') {
  25064. changesInside = changes;
  25065. sourceInside = source;
  25066. }
  25067. };
  25068. handsontable({
  25069. columns: [{
  25070. editor: 'autocomplete',
  25071. source: [1, 2, 3, 4, 5, 11, 14]
  25072. }],
  25073. afterChange: afterChange
  25074. });
  25075. selectCell(0, 0);
  25076. keyDownUp('enter');
  25077. setTimeout(function () {
  25078. autocomplete().find('tbody td:eq(1)').simulate('mousedown');
  25079. expect(changesInside[0]).toEqual([0, 0, null, 2]);
  25080. done();
  25081. }, 200);
  25082. });
  25083. it('should call `afterChange` hook with proper value types - test no. 2 #4143', function (done) {
  25084. var changesInside = void 0;
  25085. var sourceInside = void 0;
  25086. var afterChange = function afterChange(changes, source) {
  25087. if (source !== 'loadData') {
  25088. changesInside = changes;
  25089. sourceInside = source;
  25090. }
  25091. };
  25092. var syncSources = jasmine.createSpy('syncSources');
  25093. var source = [1, 2, 3, 4, 5, 11, 14];
  25094. syncSources.and.callFake(function (query, process) {
  25095. process(source);
  25096. });
  25097. handsontable({
  25098. columns: [{
  25099. editor: 'autocomplete',
  25100. source: syncSources
  25101. }],
  25102. afterChange: afterChange
  25103. });
  25104. selectCell(0, 0);
  25105. keyDownUp('enter');
  25106. setTimeout(function () {
  25107. autocomplete().find('tbody td:eq(1)').simulate('mousedown');
  25108. expect(changesInside[0]).toEqual([0, 0, null, 2]);
  25109. done();
  25110. }, 200);
  25111. });
  25112. it('should not change value type from `numeric` to `string` when written down value from set of suggestions #4143', function (done) {
  25113. var syncSources = jasmine.createSpy('syncSources');
  25114. var source = [1, 2, 3, 4, 5, 11, 14];
  25115. syncSources.and.callFake(function (query, process) {
  25116. process(source);
  25117. });
  25118. handsontable({
  25119. columns: [{
  25120. editor: 'autocomplete',
  25121. source: syncSources
  25122. }]
  25123. });
  25124. selectCell(0, 0);
  25125. keyDownUp('enter');
  25126. keyDownUp('backspace');
  25127. document.activeElement.value = '1';
  25128. $(document.activeElement).simulate('keyup');
  25129. setTimeout(function () {
  25130. keyDownUp('enter');
  25131. expect(getDataAtCell(0, 0)).toEqual(1);
  25132. done();
  25133. }, 200);
  25134. });
  25135. it('should destroy editor when value change with Enter on suggestion', function (done) {
  25136. var syncSources = jasmine.createSpy('syncSources');
  25137. syncSources.and.callFake(function (query, process) {
  25138. process(choices);
  25139. });
  25140. handsontable({
  25141. columns: [{
  25142. editor: 'autocomplete',
  25143. source: syncSources
  25144. }]
  25145. });
  25146. selectCell(0, 0);
  25147. keyDownUp('enter');
  25148. setTimeout(function () {
  25149. keyDownUp('arrow_down');
  25150. keyDownUp('arrow_down');
  25151. keyDownUp('arrow_down');
  25152. keyDownUp('arrow_down');
  25153. keyDownUp('enter');
  25154. expect(getDataAtCell(0, 0)).toEqual('green');
  25155. done();
  25156. }, 200);
  25157. });
  25158. it('should destroy editor when pressed Enter then Esc', function (done) {
  25159. var syncSources = jasmine.createSpy('syncSources');
  25160. syncSources.and.callFake(function (query, process) {
  25161. process(choices);
  25162. });
  25163. handsontable({
  25164. columns: [{
  25165. editor: 'autocomplete',
  25166. source: syncSources
  25167. }]
  25168. });
  25169. selectCell(0, 0);
  25170. keyDownUp('enter');
  25171. setTimeout(function () {
  25172. expect(autocompleteEditor().is(':visible')).toBe(true);
  25173. keyDownUp('esc');
  25174. expect(autocompleteEditor().is(':visible')).toBe(false);
  25175. done();
  25176. }, 200);
  25177. });
  25178. it('should destroy editor when mouse double clicked then Esc', function (done) {
  25179. var syncSources = jasmine.createSpy('syncSources');
  25180. syncSources.and.callFake(function (query, process) {
  25181. process(choices);
  25182. });
  25183. handsontable({
  25184. columns: [{
  25185. editor: 'autocomplete',
  25186. source: syncSources
  25187. }]
  25188. });
  25189. selectCell(0, 0);
  25190. mouseDoubleClick(getCell(0, 0));
  25191. setTimeout(function () {
  25192. expect(autocompleteEditor().is(':visible')).toBe(true);
  25193. keyDownUp('esc');
  25194. expect(autocompleteEditor().is(':visible')).toBe(false);
  25195. done();
  25196. }, 200);
  25197. });
  25198. it('cancel editing (Esc) should restore the previous value', function (done) {
  25199. var syncSources = jasmine.createSpy('syncSources');
  25200. syncSources.and.callFake(function (query, process) {
  25201. process(choices);
  25202. });
  25203. handsontable({
  25204. columns: [{
  25205. editor: 'autocomplete',
  25206. source: syncSources
  25207. }]
  25208. });
  25209. setDataAtCell(0, 0, 'black');
  25210. selectCell(0, 0);
  25211. keyDownUp('enter');
  25212. setTimeout(function () {
  25213. autocomplete().siblings('.handsontableInput').val('ye');
  25214. keyDownUp(69); // e
  25215. keyDownUp('esc');
  25216. expect(getDataAtCell(0, 0)).toEqual('black');
  25217. done();
  25218. }, 200);
  25219. });
  25220. it('should destroy editor when clicked outside the table', function (done) {
  25221. var syncSources = jasmine.createSpy('syncSources');
  25222. syncSources.and.callFake(function (query, process) {
  25223. process(choices);
  25224. });
  25225. handsontable({
  25226. columns: [{
  25227. editor: 'autocomplete',
  25228. source: syncSources
  25229. }]
  25230. });
  25231. selectCell(0, 0);
  25232. mouseDoubleClick(getCell(0, 0));
  25233. setTimeout(function () {
  25234. expect(autocompleteEditor().is(':visible')).toBe(true);
  25235. $('body').simulate('mousedown');
  25236. expect(autocompleteEditor().is(':visible')).toBe(false);
  25237. done();
  25238. }, 200);
  25239. });
  25240. it('should show fillHandle element again after close editor', function (done) {
  25241. var syncSources = jasmine.createSpy('syncSources');
  25242. syncSources.plan = function (query, process) {
  25243. process(choices.filter(function (choice) {
  25244. return choice.indexOf(query) != -1;
  25245. }));
  25246. };
  25247. var hot = handsontable({
  25248. columns: [{
  25249. type: 'autocomplete',
  25250. source: syncSources,
  25251. strict: false
  25252. }, {}]
  25253. });
  25254. selectCell(1, 0);
  25255. keyDownUp('x'); // Trigger quick edit mode
  25256. keyDownUp('enter');
  25257. setTimeout(function () {
  25258. expect($('#testContainer.handsontable > .handsontable .wtBorder.current.corner:visible').length).toEqual(1);
  25259. done();
  25260. }, 200);
  25261. });
  25262. });
  25263. describe('non strict mode', function () {
  25264. it('should allow any value in non strict mode (close editor with ENTER)', function (done) {
  25265. var syncSources = jasmine.createSpy('syncSources');
  25266. syncSources.and.callFake(function (query, process) {
  25267. process(choices);
  25268. });
  25269. handsontable({
  25270. columns: [{
  25271. editor: 'autocomplete',
  25272. source: syncSources
  25273. }]
  25274. });
  25275. selectCell(0, 0);
  25276. keyDownUp('enter');
  25277. setTimeout(function () {
  25278. var editor = $('.handsontableInput');
  25279. editor.val('foo');
  25280. keyDownUp('enter');
  25281. expect(getDataAtCell(0, 0)).toEqual('foo');
  25282. done();
  25283. }, 200);
  25284. });
  25285. it('should allow any value in non strict mode (close editor by clicking on table)', function (done) {
  25286. var syncSources = jasmine.createSpy('syncSources');
  25287. syncSources.and.callFake(function (query, process) {
  25288. process(choices);
  25289. });
  25290. handsontable({
  25291. columns: [{
  25292. editor: 'autocomplete',
  25293. source: syncSources
  25294. }]
  25295. });
  25296. selectCell(0, 0);
  25297. keyDownUp('enter');
  25298. setTimeout(function () {
  25299. var editor = $('.handsontableInput');
  25300. editor.val('foo');
  25301. spec().$container.find('tbody tr:eq(1) td:eq(0)').simulate('mousedown');
  25302. expect(getDataAtCell(0, 0)).toEqual('foo');
  25303. done();
  25304. }, 200);
  25305. });
  25306. it('should save the value from textarea after hitting ENTER', function (done) {
  25307. var syncSources = jasmine.createSpy('syncSources');
  25308. syncSources.and.callFake(function (query, process) {
  25309. process(choices.filter(function (choice) {
  25310. return choice.indexOf(query) != -1;
  25311. }));
  25312. });
  25313. hot = handsontable({
  25314. columns: [{
  25315. editor: 'autocomplete',
  25316. source: syncSources
  25317. }]
  25318. });
  25319. selectCell(0, 0);
  25320. var editorInput = $('.handsontableInput');
  25321. expect(getDataAtCell(0, 0)).toBeNull();
  25322. keyDownUp('enter');
  25323. setTimeout(function () {
  25324. syncSources.calls.reset();
  25325. editorInput.val('b');
  25326. keyDownUp('b'.charCodeAt(0));
  25327. }, 200);
  25328. setTimeout(function () {
  25329. var ac = hot.getActiveEditor();
  25330. var innerHot = ac.htEditor;
  25331. expect(innerHot.getData()).toEqual([['blue'], ['black']]);
  25332. var selected = innerHot.getSelected();
  25333. expect(selected).toBeUndefined();
  25334. keyDownUp('enter');
  25335. expect(getDataAtCell(0, 0)).toEqual('b');
  25336. done();
  25337. }, 400);
  25338. });
  25339. });
  25340. describe('strict mode', function () {
  25341. it('strict mode should NOT use value if it DOES NOT match the list (sync reponse is empty)', function (done) {
  25342. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  25343. var onAfterChange = jasmine.createSpy('onAfterChange');
  25344. var syncSources = jasmine.createSpy('syncSources');
  25345. syncSources.and.callFake(function (query, process) {
  25346. process([]); // hardcoded empty result
  25347. });
  25348. handsontable({
  25349. data: [['one', 'two'], ['three', 'four']],
  25350. columns: [{
  25351. type: 'autocomplete',
  25352. source: syncSources,
  25353. allowInvalid: false,
  25354. strict: true
  25355. }, {}],
  25356. afterValidate: onAfterValidate,
  25357. afterChange: onAfterChange
  25358. });
  25359. setDataAtCell(0, 0, 'unexistent');
  25360. setTimeout(function () {
  25361. expect(getData()).toEqual([['one', 'two'], ['three', 'four']]);
  25362. expect(syncSources.calls.count()).toEqual(1);
  25363. expect(onAfterValidate.calls.count()).toEqual(1);
  25364. expect(onAfterChange.calls.count()).toEqual(1); // 1 for loadData (it is not called after failed edit)
  25365. done();
  25366. }, 200);
  25367. });
  25368. it('strict mode should use value if it DOES match the list (sync reponse is not empty)', function (done) {
  25369. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  25370. var onAfterChange = jasmine.createSpy('onAfterChange');
  25371. var syncSources = jasmine.createSpy('asyncSources');
  25372. syncSources.and.callFake(function (query, process) {
  25373. process(choices); // hardcoded empty result
  25374. });
  25375. handsontable({
  25376. data: [['one', 'two'], ['three', 'four']],
  25377. columns: [{
  25378. type: 'autocomplete',
  25379. source: syncSources,
  25380. allowInvalid: false,
  25381. strict: true
  25382. }, {}],
  25383. afterValidate: onAfterValidate,
  25384. afterChange: onAfterChange
  25385. });
  25386. setDataAtCell(0, 0, 'yellow');
  25387. setTimeout(function () {
  25388. expect(getData()).toEqual([['yellow', 'two'], ['three', 'four']]);
  25389. expect(syncSources.calls.count()).toEqual(1);
  25390. expect(onAfterValidate.calls.count()).toEqual(1);
  25391. expect(onAfterChange.calls.count()).toEqual(2); // 1 for loadData and 1 for setDataAtCell
  25392. done();
  25393. }, 200);
  25394. });
  25395. it('strict mode should NOT use value if it DOES NOT match the list (async reponse is empty)', function (done) {
  25396. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  25397. var onAfterChange = jasmine.createSpy('onAfterChange');
  25398. var asyncSources = jasmine.createSpy('asyncSources');
  25399. asyncSources.and.callFake(function (query, process) {
  25400. setTimeout(function () {
  25401. process([]); // hardcoded empty result
  25402. });
  25403. });
  25404. handsontable({
  25405. data: [['one', 'two'], ['three', 'four']],
  25406. columns: [{
  25407. type: 'autocomplete',
  25408. source: asyncSources,
  25409. allowInvalid: false,
  25410. strict: true
  25411. }, {}],
  25412. afterValidate: onAfterValidate,
  25413. afterChange: onAfterChange
  25414. });
  25415. setDataAtCell(0, 0, 'unexistent');
  25416. setTimeout(function () {
  25417. expect(getData()).toEqual([['one', 'two'], ['three', 'four']]);
  25418. expect(asyncSources.calls.count()).toEqual(1);
  25419. expect(onAfterValidate.calls.count()).toEqual(1);
  25420. expect(onAfterChange.calls.count()).toEqual(1); // 1 for loadData (it is not called after failed edit)
  25421. done();
  25422. }, 200);
  25423. });
  25424. it('strict mode should use value if it DOES match the list (async reponse is not empty)', function (done) {
  25425. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  25426. var onAfterChange = jasmine.createSpy('onAfterChange');
  25427. var asyncSources = jasmine.createSpy('asyncSources');
  25428. asyncSources.and.callFake(function (query, process) {
  25429. setTimeout(function () {
  25430. process(choices); // hardcoded empty result
  25431. });
  25432. });
  25433. handsontable({
  25434. data: [['one', 'two'], ['three', 'four']],
  25435. columns: [{
  25436. type: 'autocomplete',
  25437. source: asyncSources,
  25438. allowInvalid: false,
  25439. strict: true
  25440. }, {}],
  25441. afterValidate: onAfterValidate,
  25442. afterChange: onAfterChange
  25443. });
  25444. setDataAtCell(0, 0, 'yellow');
  25445. setTimeout(function () {
  25446. expect(getData()).toEqual([['yellow', 'two'], ['three', 'four']]);
  25447. expect(asyncSources.calls.count()).toEqual(1);
  25448. expect(onAfterValidate.calls.count()).toEqual(1);
  25449. expect(onAfterChange.calls.count()).toEqual(2); // 1 for loadData and 1 for setDataAtCell
  25450. done();
  25451. }, 200);
  25452. });
  25453. it('strict mode mark value as invalid if it DOES NOT match the list (sync reponse is empty)', function (done) {
  25454. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  25455. var onAfterChange = jasmine.createSpy('onAfterChange');
  25456. var syncSources = jasmine.createSpy('syncSources');
  25457. syncSources.and.callFake(function (query, process) {
  25458. process([]); // hardcoded empty result
  25459. });
  25460. handsontable({
  25461. data: [['one', 'two'], ['three', 'four']],
  25462. columns: [{
  25463. type: 'autocomplete',
  25464. source: syncSources,
  25465. allowInvalid: true,
  25466. strict: true
  25467. }, {}],
  25468. afterValidate: onAfterValidate,
  25469. afterChange: onAfterChange
  25470. });
  25471. expect(getCellMeta(0, 0).valid).not.toBe(false);
  25472. expect($(getCell(0, 0)).hasClass('htInvalid')).toBe(false);
  25473. setDataAtCell(0, 0, 'unexistent');
  25474. setTimeout(function () {
  25475. expect(getData()).toEqual([['unexistent', 'two'], ['three', 'four']]);
  25476. expect(getCellMeta(0, 0).valid).toBe(false);
  25477. expect($(getCell(0, 0)).hasClass('htInvalid')).toBe(true);
  25478. done();
  25479. }, 200);
  25480. });
  25481. it('should select the best matching option after hitting ENTER', function (done) {
  25482. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  25483. var syncSources = jasmine.createSpy('syncSources');
  25484. syncSources.and.callFake(function (query, process) {
  25485. process(choices.filter(function (choice) {
  25486. return choice.indexOf(query) != -1;
  25487. }));
  25488. });
  25489. hot = handsontable({
  25490. columns: [{
  25491. editor: 'autocomplete',
  25492. source: syncSources,
  25493. strict: true
  25494. }],
  25495. afterValidate: onAfterValidate
  25496. });
  25497. selectCell(0, 0);
  25498. var editorInput = $('.handsontableInput');
  25499. expect(getDataAtCell(0, 0)).toBeNull();
  25500. keyDownUp('enter');
  25501. setTimeout(function () {
  25502. syncSources.calls.reset();
  25503. editorInput.val('b');
  25504. keyDownUp('b'.charCodeAt(0));
  25505. }, 200);
  25506. setTimeout(function () {
  25507. var ac = hot.getActiveEditor();
  25508. var innerHot = ac.htEditor;
  25509. expect(innerHot.getData()).toEqual([['blue'], ['black']]);
  25510. var selected = innerHot.getSelected();
  25511. var selectedData = innerHot.getDataAtCell(selected[0], selected[1]);
  25512. expect(selectedData).toEqual('blue');
  25513. onAfterValidate.calls.reset();
  25514. keyDownUp('enter');
  25515. }, 400);
  25516. setTimeout(function () {
  25517. expect(getDataAtCell(0, 0)).toEqual('blue');
  25518. done();
  25519. }, 600);
  25520. });
  25521. it('should select the best matching option after hitting TAB', function (done) {
  25522. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  25523. var syncSources = jasmine.createSpy('syncSources');
  25524. syncSources.and.callFake(function (query, process) {
  25525. process(choices.filter(function (choice) {
  25526. return choice.indexOf(query) != -1;
  25527. }));
  25528. });
  25529. hot = handsontable({
  25530. columns: [{
  25531. editor: 'autocomplete',
  25532. source: syncSources,
  25533. strict: true
  25534. }],
  25535. afterValidate: onAfterValidate
  25536. });
  25537. selectCell(0, 0);
  25538. var editorInput = $('.handsontableInput');
  25539. expect(getDataAtCell(0, 0)).toBeNull();
  25540. keyDownUp('enter');
  25541. setTimeout(function () {
  25542. syncSources.calls.reset();
  25543. editorInput.val('b');
  25544. keyDownUp('b'.charCodeAt(0));
  25545. }, 200);
  25546. setTimeout(function () {
  25547. var ac = hot.getActiveEditor();
  25548. var innerHot = ac.htEditor;
  25549. expect(innerHot.getData()).toEqual([['blue'], ['black']]);
  25550. var selected = innerHot.getSelected();
  25551. var selectedData = innerHot.getDataAtCell(selected[0], selected[1]);
  25552. expect(selectedData).toEqual('blue');
  25553. onAfterValidate.calls.reset();
  25554. keyDownUp('tab');
  25555. }, 400);
  25556. setTimeout(function () {
  25557. expect(getDataAtCell(0, 0)).toEqual('blue');
  25558. done();
  25559. }, 600);
  25560. });
  25561. it('should mark list item corresponding to current cell value as selected', function (done) {
  25562. var syncSources = jasmine.createSpy('syncSources');
  25563. syncSources.and.callFake(function (query, process) {
  25564. process(['red', 'dark-yellow', 'yellow', 'light-yellow', 'black']);
  25565. });
  25566. handsontable({
  25567. columns: [{
  25568. editor: 'autocomplete',
  25569. source: syncSources,
  25570. strict: true
  25571. }],
  25572. data: [['yellow'], ['red'], ['blue']]
  25573. });
  25574. selectCell(0, 0);
  25575. keyDownUp('enter');
  25576. setTimeout(function () {
  25577. expect(autocomplete().find('.current').text()).toEqual(getDataAtCell(0, 0));
  25578. done();
  25579. }, 200);
  25580. });
  25581. });
  25582. describe('filtering', function () {
  25583. it('typing in textarea should filter the lookup list', function (done) {
  25584. var syncSources = jasmine.createSpy('syncSources');
  25585. syncSources.and.callFake(function (query, process) {
  25586. process(choices.filter(function (choice) {
  25587. return choice.indexOf(query) != -1;
  25588. }));
  25589. });
  25590. hot = handsontable({
  25591. columns: [{
  25592. editor: 'autocomplete',
  25593. source: syncSources
  25594. }]
  25595. });
  25596. selectCell(0, 0);
  25597. var editorInput = $('.handsontableInput');
  25598. expect(getDataAtCell(0, 0)).toBeNull();
  25599. keyDownUp('enter');
  25600. setTimeout(function () {
  25601. syncSources.calls.reset();
  25602. editorInput.val('e');
  25603. keyDownUp(69); // e
  25604. }, 200);
  25605. setTimeout(function () {
  25606. var ac = hot.getActiveEditor();
  25607. var innerHot = ac.htEditor;
  25608. expect(innerHot.getData()).toEqual([['red'], ['yellow'], ['green'], ['blue'], ['lime'], ['white'], ['olive'], ['orange'], ['purple']]);
  25609. syncSources.calls.reset();
  25610. editorInput.val('ed');
  25611. keyDownUp(68); // d
  25612. }, 400);
  25613. setTimeout(function () {
  25614. var ac = hot.getActiveEditor();
  25615. var innerHot = ac.htEditor;
  25616. expect(innerHot.getData()).toEqual([['red']]);
  25617. done();
  25618. }, 600);
  25619. });
  25620. it('default filtering should be case insensitive', function (done) {
  25621. hot = handsontable({
  25622. columns: [{
  25623. editor: 'autocomplete',
  25624. source: choices
  25625. }]
  25626. });
  25627. selectCell(0, 0);
  25628. var editorInput = $('.handsontableInput');
  25629. expect(getDataAtCell(0, 0)).toBeNull();
  25630. keyDownUp('enter');
  25631. editorInput.val('e');
  25632. keyDownUp(69); // e
  25633. setTimeout(function () {
  25634. var ac = hot.getActiveEditor();
  25635. var innerHot = ac.htEditor;
  25636. expect(innerHot.getData()).toEqual([['red'], ['yellow'], ['green'], ['blue'], ['lime'], ['white'], ['olive'], ['orange'], ['purple']]);
  25637. editorInput.val('e');
  25638. keyDownUp(69); // E (same as 'e')
  25639. }, 50);
  25640. setTimeout(function () {
  25641. var ac = hot.getActiveEditor();
  25642. var innerHot = ac.htEditor;
  25643. expect(innerHot.getData()).toEqual([['red'], ['yellow'], ['green'], ['blue'], ['lime'], ['white'], ['olive'], ['orange'], ['purple']]);
  25644. done();
  25645. }, 100);
  25646. });
  25647. it('default filtering should be case sensitive when filteringCaseSensitive is false', function (done) {
  25648. hot = handsontable({
  25649. columns: [{
  25650. editor: 'autocomplete',
  25651. source: choices,
  25652. filteringCaseSensitive: true
  25653. }]
  25654. });
  25655. selectCell(0, 0);
  25656. var editorInput = $('.handsontableInput');
  25657. expect(getDataAtCell(0, 0)).toBeNull();
  25658. keyDownUp('enter');
  25659. editorInput.val('e');
  25660. keyDownUp(69); // e
  25661. setTimeout(function () {
  25662. var ac = hot.getActiveEditor();
  25663. var innerHot = ac.htEditor;
  25664. expect(innerHot.getData()).toEqual([['red'], ['yellow'], ['green'], ['blue'], ['lime'], ['white'], ['olive'], ['orange'], ['purple']]);
  25665. editorInput.val('E');
  25666. keyDownUp(69); // E (same as 'e')
  25667. }, 50);
  25668. setTimeout(function () {
  25669. var ac = hot.getActiveEditor();
  25670. var innerHot = ac.htEditor;
  25671. expect(innerHot.getData()).toEqual([]);
  25672. expect(innerHot.getSourceData()).toEqual([]);
  25673. done();
  25674. }, 200);
  25675. });
  25676. it('typing in textarea should NOT filter the lookup list when filtering is disabled', function (done) {
  25677. hot = handsontable({
  25678. columns: [{
  25679. editor: 'autocomplete',
  25680. source: choices,
  25681. filter: false
  25682. }]
  25683. });
  25684. selectCell(0, 0);
  25685. var editorInput = $('.handsontableInput');
  25686. expect(getDataAtCell(0, 0)).toBeNull();
  25687. keyDownUp('enter');
  25688. setTimeout(function () {
  25689. editorInput.val('e');
  25690. keyDownUp('e'.charCodeAt(0)); // e
  25691. }, 20);
  25692. setTimeout(function () {
  25693. var ac = hot.getActiveEditor();
  25694. var innerHot = ac.htEditor;
  25695. expect(innerHot.getData()).toEqual(Handsontable.helper.pivot([choices]));
  25696. editorInput.val('ed');
  25697. keyDownUp('d'.charCodeAt(0)); // d
  25698. }, 40);
  25699. setTimeout(function () {
  25700. var ac = hot.getActiveEditor();
  25701. var innerHot = ac.htEditor;
  25702. expect(innerHot.getData()).toEqual(Handsontable.helper.pivot([choices]));
  25703. done();
  25704. }, 60);
  25705. });
  25706. it('typing in textarea should highlight the matching phrase', function (done) {
  25707. var choices = ['Male', 'Female'];
  25708. var syncSources = jasmine.createSpy('syncSources');
  25709. syncSources.and.callFake(function (query, process) {
  25710. process(choices.filter(function (choice) {
  25711. return choice.search(new RegExp(query, 'i')) != -1;
  25712. }));
  25713. });
  25714. hot = handsontable({
  25715. columns: [{
  25716. editor: 'autocomplete',
  25717. source: syncSources,
  25718. filter: false
  25719. }]
  25720. });
  25721. selectCell(0, 0);
  25722. var editorInput = $('.handsontableInput');
  25723. expect(getDataAtCell(0, 0)).toBeNull();
  25724. keyDownUp('enter');
  25725. setTimeout(function () {
  25726. syncSources.calls.reset();
  25727. editorInput.val('Male');
  25728. keyDownUp(69); // e
  25729. }, 200);
  25730. setTimeout(function () {
  25731. var ac = hot.getActiveEditor();
  25732. var innerHot = ac.htEditor;
  25733. var autocompleteList = $(innerHot.rootElement);
  25734. expect(autocompleteList.find('td:eq(0)').html()).toMatch(/<(strong|STRONG)>Male<\/(strong|STRONG)>/); // IE8 makes the tag names UPPERCASE
  25735. expect(autocompleteList.find('td:eq(1)').html()).toMatch(/Fe<(strong|STRONG)>male<\/(strong|STRONG)>/);
  25736. done();
  25737. }, 400);
  25738. });
  25739. it('text in textarea should not be interpreted as regexp', function (done) {
  25740. spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'queryChoices').and.callThrough();
  25741. var queryChoices = Handsontable.editors.AutocompleteEditor.prototype.queryChoices;
  25742. hot = handsontable({
  25743. columns: [{
  25744. editor: 'autocomplete',
  25745. source: choices
  25746. }]
  25747. });
  25748. selectCell(0, 0);
  25749. var editorInput = $('.handsontableInput');
  25750. expect(getDataAtCell(0, 0)).toBeNull();
  25751. keyDownUp('enter');
  25752. setTimeout(function () {
  25753. queryChoices.calls.reset();
  25754. editorInput.val('yellow|red');
  25755. keyDownUp('d'.charCodeAt(0));
  25756. }, 200);
  25757. setTimeout(function () {
  25758. var ac = hot.getActiveEditor();
  25759. var innerHot = ac.htEditor;
  25760. expect(innerHot.getData().length).toEqual(0);
  25761. done();
  25762. }, 400);
  25763. });
  25764. it('text in textarea should not be interpreted as regexp when highlighting the matching phrase', function (done) {
  25765. var choices = ['Male', 'Female'];
  25766. var syncSources = jasmine.createSpy('syncSources');
  25767. syncSources.and.callFake(function (query, process) {
  25768. process(choices.filter(function (choice) {
  25769. return choice.search(new RegExp(query, 'i')) != -1;
  25770. }));
  25771. });
  25772. hot = handsontable({
  25773. columns: [{
  25774. editor: 'autocomplete',
  25775. source: syncSources,
  25776. filter: false
  25777. }]
  25778. });
  25779. selectCell(0, 0);
  25780. var editorInput = $('.handsontableInput');
  25781. expect(getDataAtCell(0, 0)).toBeNull();
  25782. keyDownUp('enter');
  25783. setTimeout(function () {
  25784. syncSources.calls.reset();
  25785. editorInput.val('M|F');
  25786. keyDownUp('F'.charCodeAt(0));
  25787. }, 200);
  25788. setTimeout(function () {
  25789. var ac = hot.getActiveEditor();
  25790. var innerHot = ac.htEditor;
  25791. var autocompleteList = $(innerHot.rootElement);
  25792. expect(autocompleteList.find('td:eq(0)').html()).toEqual('Male');
  25793. expect(autocompleteList.find('td:eq(1)').html()).toEqual('Female');
  25794. done();
  25795. }, 400);
  25796. });
  25797. it('should allow any value if filter === false and allowInvalid === true', function (done) {
  25798. spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'queryChoices').and.callThrough();
  25799. var queryChoices = Handsontable.editors.AutocompleteEditor.prototype.queryChoices;
  25800. handsontable({
  25801. columns: [{
  25802. editor: 'autocomplete',
  25803. source: choices,
  25804. filter: false,
  25805. strict: true,
  25806. allowInvalid: true
  25807. }]
  25808. });
  25809. selectCell(0, 0);
  25810. var editorInput = $('.handsontableInput');
  25811. expect(getDataAtCell(0, 0)).toBeNull();
  25812. keyDownUp('enter');
  25813. setTimeout(function () {
  25814. queryChoices.calls.reset();
  25815. editorInput.val('foobar');
  25816. keyDownUp(82); // r
  25817. }, 200);
  25818. setTimeout(function () {
  25819. keyDownUp(Handsontable.helper.KEY_CODES.ENTER);
  25820. expect(getDataAtCell(0, 0)).toEqual('foobar');
  25821. done();
  25822. }, 400);
  25823. });
  25824. it('typing in textarea should highlight best choice, if strict === true', function (done) {
  25825. var choices = ['Male', 'Female'];
  25826. var syncSources = jasmine.createSpy('syncSources');
  25827. syncSources.and.callFake(function (query, process) {
  25828. process(choices.filter(function (choice) {
  25829. return choice.search(new RegExp(query, 'i')) != -1;
  25830. }));
  25831. });
  25832. var hot = handsontable({
  25833. columns: [{
  25834. editor: 'autocomplete',
  25835. source: syncSources,
  25836. filter: false,
  25837. strict: true
  25838. }]
  25839. });
  25840. selectCell(0, 0);
  25841. var editorInput = $('.handsontableInput');
  25842. expect(getDataAtCell(0, 0)).toBeNull();
  25843. keyDownUp('enter');
  25844. setTimeout(function () {
  25845. syncSources.calls.reset();
  25846. editorInput.val('e');
  25847. keyDownUp(69); // e
  25848. }, 200);
  25849. setTimeout(function () {
  25850. var ac = hot.getActiveEditor();
  25851. var innerHot = ac.htEditor;
  25852. expect(innerHot.getSelected()).toEqual([1, 0, 1, 0]);
  25853. done();
  25854. }, 400);
  25855. });
  25856. });
  25857. it('should restore the old value when hovered over a autocomplete menu item and then clicked outside of the table', function (done) {
  25858. var syncSources = jasmine.createSpy('syncSources');
  25859. syncSources.and.callFake(function (query, process) {
  25860. process(choices);
  25861. });
  25862. handsontable({
  25863. columns: [{
  25864. editor: 'autocomplete',
  25865. source: syncSources
  25866. }]
  25867. });
  25868. selectCell(0, 0);
  25869. expect(getDataAtCell(0, 0)).toBeNull();
  25870. keyDownUp('enter');
  25871. setTimeout(function () {
  25872. autocomplete().find('tbody td:eq(1)').simulate('mouseenter');
  25873. autocomplete().find('tbody td:eq(1)').simulate('mouseleave');
  25874. spec().$container.simulate('mousedown');
  25875. expect(getDataAtCell(0, 0)).toBeNull();
  25876. done();
  25877. }, 200);
  25878. });
  25879. it('should be able to use empty value ("")', function (done) {
  25880. var syncSources = jasmine.createSpy('syncSources');
  25881. syncSources.and.callFake(function (query, process) {
  25882. process(['', 'BMW', 'Bentley']);
  25883. });
  25884. handsontable({
  25885. data: [['one', 'two'], ['three', 'four']],
  25886. columns: [{
  25887. editor: 'autocomplete',
  25888. source: syncSources,
  25889. filter: false
  25890. }]
  25891. });
  25892. selectCell(0, 0);
  25893. keyDownUp('enter');
  25894. setTimeout(function () {
  25895. expect(getDataAtCell(0, 0)).toEqual('one');
  25896. autocomplete().find('tbody td:eq(0)').simulate('mousedown');
  25897. expect(getDataAtCell(0, 0)).toEqual('');
  25898. done();
  25899. }, 200);
  25900. });
  25901. describe('allow html mode', function () {
  25902. it('should allow inject html items (async mode)', function (done) {
  25903. hot = handsontable({
  25904. columns: [{
  25905. type: 'autocomplete',
  25906. source: function source(query, cb) {
  25907. cb(['<b>foo <span>zip</span></b>', '<i>bar</i>', '<strong>baz</strong>']);
  25908. },
  25909. allowHtml: true
  25910. }]
  25911. });
  25912. selectCell(0, 0);
  25913. var editorInput = $('.handsontableInput');
  25914. expect(getDataAtCell(0, 0)).toBeNull();
  25915. keyDownUp('enter');
  25916. setTimeout(function () {
  25917. editorInput.val('b');
  25918. keyDownUp('b'.charCodeAt(0));
  25919. }, 200);
  25920. setTimeout(function () {
  25921. var ac = hot.getActiveEditor();
  25922. var innerHot = ac.htEditor;
  25923. expect(innerHot.getData()).toEqual([['<i>bar</i>'], ['<strong>baz</strong>']]);
  25924. editorInput.val('bar');
  25925. keyDownUp('a'.charCodeAt(0));
  25926. keyDownUp('r'.charCodeAt(0));
  25927. }, 400);
  25928. setTimeout(function () {
  25929. var ac = hot.getActiveEditor();
  25930. var innerHot = ac.htEditor;
  25931. expect(innerHot.getData()).toEqual([['<i>bar</i>']]);
  25932. keyDownUp('arrow_down');
  25933. keyDownUp('enter');
  25934. }, 600);
  25935. setTimeout(function () {
  25936. expect(getCell(0, 0).querySelector('i').textContent).toBe('bar');
  25937. done();
  25938. }, 700);
  25939. });
  25940. it('should allow inject html items (sync mode)', function (done) {
  25941. hot = handsontable({
  25942. columns: [{
  25943. type: 'autocomplete',
  25944. source: ['<b>foo <span>zip</span></b>', '<i>bar</i>', '<strong>baz</strong>'],
  25945. allowHtml: true
  25946. }]
  25947. });
  25948. selectCell(0, 0);
  25949. var editorInput = $('.handsontableInput');
  25950. expect(getDataAtCell(0, 0)).toBeNull();
  25951. keyDownUp('enter');
  25952. setTimeout(function () {
  25953. editorInput.val('b');
  25954. keyDownUp('b'.charCodeAt(0));
  25955. }, 200);
  25956. setTimeout(function () {
  25957. var ac = hot.getActiveEditor();
  25958. var innerHot = ac.htEditor;
  25959. expect(innerHot.getData()).toEqual([['<i>bar</i>'], ['<strong>baz</strong>']]);
  25960. editorInput.val('bar');
  25961. keyDownUp('a'.charCodeAt(0));
  25962. keyDownUp('r'.charCodeAt(0));
  25963. }, 400);
  25964. setTimeout(function () {
  25965. var ac = hot.getActiveEditor();
  25966. var innerHot = ac.htEditor;
  25967. expect(innerHot.getData()).toEqual([['<i>bar</i>']]);
  25968. keyDownUp('arrow_down');
  25969. keyDownUp('enter');
  25970. }, 600);
  25971. setTimeout(function () {
  25972. expect(getCell(0, 0).querySelector('i').textContent).toBe('bar');
  25973. done();
  25974. }, 700);
  25975. });
  25976. });
  25977. describe('disallow html mode', function () {
  25978. it('should be disabled by default', function () {
  25979. hot = handsontable({
  25980. columns: [{
  25981. type: 'autocomplete',
  25982. source: function source(query, cb) {
  25983. cb(['<b>foo <span>zip</span></b>', '<i>bar</i>', '<strong>baz</strong>']);
  25984. },
  25985. allowHtml: false
  25986. }]
  25987. });
  25988. expect(hot.getCellMeta(0, 0).allowHtml).toBeFalsy();
  25989. });
  25990. it('should strip html from strings provided in source (async mode)', function (done) {
  25991. hot = handsontable({
  25992. columns: [{
  25993. type: 'autocomplete',
  25994. source: function source(query, cb) {
  25995. cb(['<b>foo <span>zip</span></b>', '<i>bar</i>', '<strong>baz</strong>']);
  25996. },
  25997. allowHtml: false
  25998. }]
  25999. });
  26000. selectCell(0, 0);
  26001. var editorInput = $('.handsontableInput');
  26002. expect(getDataAtCell(0, 0)).toBeNull();
  26003. keyDownUp('enter');
  26004. setTimeout(function () {
  26005. editorInput.val('b');
  26006. keyDownUp('b'.charCodeAt(0));
  26007. }, 200);
  26008. setTimeout(function () {
  26009. var ac = hot.getActiveEditor();
  26010. var innerHot = ac.htEditor;
  26011. expect(innerHot.getData()).toEqual([['bar'], ['baz']]);
  26012. editorInput.val('bar');
  26013. keyDownUp('a'.charCodeAt(0));
  26014. keyDownUp('r'.charCodeAt(0));
  26015. }, 400);
  26016. setTimeout(function () {
  26017. var ac = hot.getActiveEditor();
  26018. var innerHot = ac.htEditor;
  26019. expect(innerHot.getData()).toEqual([['bar']]);
  26020. keyDownUp('arrow_down');
  26021. keyDownUp('enter');
  26022. }, 600);
  26023. setTimeout(function () {
  26024. expect(getCell(0, 0).querySelector('i')).toBeNull();
  26025. expect(getCell(0, 0).textContent).toMatch('bar');
  26026. done();
  26027. }, 700);
  26028. });
  26029. it('should strip html from strings provided in source (sync mode)', function (done) {
  26030. hot = handsontable({
  26031. columns: [{
  26032. type: 'autocomplete',
  26033. source: ['<b>foo <span>zip</span></b>', '<i>bar</i>', '<strong>baz</strong>'],
  26034. allowHtml: false
  26035. }]
  26036. });
  26037. selectCell(0, 0);
  26038. var editorInput = $('.handsontableInput');
  26039. expect(getDataAtCell(0, 0)).toBeNull();
  26040. keyDownUp('enter');
  26041. setTimeout(function () {
  26042. editorInput.val('b');
  26043. keyDownUp('b'.charCodeAt(0));
  26044. }, 200);
  26045. setTimeout(function () {
  26046. var ac = hot.getActiveEditor();
  26047. var innerHot = ac.htEditor;
  26048. expect(innerHot.getData()).toEqual([['bar'], ['baz']]);
  26049. editorInput.val('bar');
  26050. keyDownUp('a'.charCodeAt(0));
  26051. keyDownUp('r'.charCodeAt(0));
  26052. }, 400);
  26053. setTimeout(function () {
  26054. var ac = hot.getActiveEditor();
  26055. var innerHot = ac.htEditor;
  26056. expect(innerHot.getData()).toEqual([['bar']]);
  26057. keyDownUp('arrow_down');
  26058. keyDownUp('enter');
  26059. }, 600);
  26060. setTimeout(function () {
  26061. expect(getCell(0, 0).querySelector('i')).toBeNull();
  26062. expect(getCell(0, 0).textContent).toMatch('bar');
  26063. done();
  26064. }, 700);
  26065. });
  26066. });
  26067. describe('Autocomplete helper functions:', function () {
  26068. describe('sortByRelevance', function () {
  26069. it('should sort the provided array, so items more relevant to the provided value are listed first', function () {
  26070. var choices = ['Wayne', // 0
  26071. 'Draven', // 1
  26072. 'Banner', // 2
  26073. 'Stark', // 3
  26074. 'Parker', // 4
  26075. 'Kent', // 5
  26076. 'Gordon', // 6
  26077. 'Kyle', // 7
  26078. 'Simmons' // 8
  26079. ];
  26080. var value = 'a';
  26081. var sorted = Handsontable.editors.AutocompleteEditor.sortByRelevance(value, choices);
  26082. expect(sorted).toEqual([0, 2, 4, 3, 1]);
  26083. value = 'o';
  26084. sorted = Handsontable.editors.AutocompleteEditor.sortByRelevance(value, choices);
  26085. expect(sorted).toEqual([6, 8]);
  26086. value = 'er';
  26087. sorted = Handsontable.editors.AutocompleteEditor.sortByRelevance(value, choices);
  26088. expect(sorted).toEqual([2, 4]);
  26089. });
  26090. });
  26091. });
  26092. it('should not modify the suggestion lists\' order, when the sortByRelevance option is set to false', function (done) {
  26093. var choices = ['Wayne', 'Draven', 'Banner', 'Stark', 'Parker', 'Kent', 'Gordon', 'Kyle', 'Simmons'];
  26094. var hot = handsontable({
  26095. columns: [{
  26096. editor: 'autocomplete',
  26097. source: choices,
  26098. sortByRelevance: false
  26099. }]
  26100. });
  26101. selectCell(0, 0);
  26102. keyDownUp('enter');
  26103. var $editorInput = $('.handsontableInput');
  26104. $editorInput.val('a');
  26105. keyDownUp('a'.charCodeAt(0));
  26106. Handsontable.dom.setCaretPosition($editorInput[0], 1);
  26107. setTimeout(function () {
  26108. var dropdownList = $('.autocompleteEditor tbody').first();
  26109. var listLength = dropdownList.find('tr').size();
  26110. expect(listLength).toBe(9);
  26111. for (var i = 1; i <= listLength; i++) {
  26112. expect(dropdownList.find('tr:nth-child(' + i + ') td').text()).toEqual(choices[i - 1]);
  26113. }
  26114. done();
  26115. }, 30);
  26116. });
  26117. it('should fire one afterChange event when value is changed', function (done) {
  26118. var onAfterChange = jasmine.createSpy('onAfterChange');
  26119. var syncSources = jasmine.createSpy('syncSources');
  26120. syncSources.and.callFake(function (query, process) {
  26121. process(choices);
  26122. });
  26123. handsontable({
  26124. columns: [{
  26125. editor: 'autocomplete',
  26126. source: syncSources
  26127. }],
  26128. afterChange: onAfterChange
  26129. });
  26130. selectCell(0, 0);
  26131. keyDownUp('enter');
  26132. setTimeout(function () {
  26133. onAfterChange.calls.reset();
  26134. autocomplete().find('tbody td:eq(1)').simulate('mousedown');
  26135. expect(getDataAtCell(0, 0)).toEqual('red');
  26136. expect(onAfterChange.calls.count()).toEqual(1);
  26137. expect(onAfterChange).toHaveBeenCalledWith([[0, 0, null, 'red']], 'edit', undefined, undefined, undefined, undefined);
  26138. done();
  26139. }, 200);
  26140. });
  26141. it('should not affect other cell values after clicking on autocomplete cell (#1021)', function (done) {
  26142. var syncSources = jasmine.createSpy('syncSources');
  26143. syncSources.and.callFake(function (query, process) {
  26144. process(choices);
  26145. });
  26146. handsontable({
  26147. columns: [{}, {}, {
  26148. editor: 'autocomplete',
  26149. source: syncSources
  26150. }, {}],
  26151. data: [[null, null, 'yellow', null], [null, null, 'red', null], [null, null, 'blue', null]]
  26152. });
  26153. expect($(getCell(0, 2)).text()).toMatch('yellow');
  26154. mouseDoubleClick(getCell(0, 2));
  26155. expect($(getCell(1, 2)).text()).toMatch('red');
  26156. mouseDoubleClick(getCell(1, 2));
  26157. expect($(getCell(2, 2)).text()).toMatch('blue');
  26158. mouseDoubleClick(getCell(2, 2));
  26159. setTimeout(function () {
  26160. expect(getDataAtCol(2)).toEqual(['yellow', 'red', 'blue']);
  26161. done();
  26162. }, 200);
  26163. });
  26164. it('should handle editor if cell data is a function', function (done) {
  26165. spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'updateChoicesList').and.callThrough();
  26166. var updateChoicesList = Handsontable.editors.AutocompleteEditor.prototype.updateChoicesList;
  26167. var afterValidateCallback = jasmine.createSpy('afterValidateCallbak');
  26168. var hot = handsontable({
  26169. data: [new Model({
  26170. id: 1,
  26171. name: 'Ted Right',
  26172. address: ''
  26173. }), new Model({
  26174. id: 2,
  26175. name: 'Frank Honest',
  26176. address: ''
  26177. }), new Model({
  26178. id: 3,
  26179. name: 'Joan Well',
  26180. address: ''
  26181. })],
  26182. dataSchema: Model,
  26183. colHeaders: ['ID', 'Name', 'Address'],
  26184. columns: [{
  26185. data: createAccessorForProperty('id'),
  26186. type: 'autocomplete',
  26187. source: ['1', '2', '3'],
  26188. filter: false,
  26189. strict: true
  26190. }, {
  26191. data: createAccessorForProperty('name')
  26192. }, {
  26193. data: createAccessorForProperty('address')
  26194. }],
  26195. minSpareRows: 1,
  26196. afterValidate: afterValidateCallback
  26197. });
  26198. selectCell(0, 0);
  26199. expect(hot.getActiveEditor().isOpened()).toBe(false);
  26200. keyDownUp('enter');
  26201. setTimeout(function () {
  26202. expect(hot.getActiveEditor().isOpened()).toBe(true);
  26203. afterValidateCallback.calls.reset();
  26204. $(hot.getActiveEditor().htContainer).find('tr:eq(1) td:eq(0)').simulate('mousedown');
  26205. }, 200);
  26206. setTimeout(function () {
  26207. expect(getDataAtCell(0, 0)).toEqual('2');
  26208. done();
  26209. }, 400);
  26210. });
  26211. it('should not call the `source` has been selected', function () {
  26212. var syncSources = jasmine.createSpy('syncSources');
  26213. syncSources.and.callFake(function (query, process) {
  26214. process([]); // hardcoded empty result
  26215. });
  26216. handsontable({
  26217. data: [['one', 'two'], ['three', 'four']],
  26218. columns: [{
  26219. type: 'autocomplete',
  26220. source: syncSources,
  26221. allowInvalid: false,
  26222. strict: true
  26223. }, {}],
  26224. cells: function cells(row, col) {
  26225. var cellProperties = {};
  26226. if (row === 0 && col === 0) {
  26227. cellProperties.readOnly = true;
  26228. }
  26229. return cellProperties;
  26230. }
  26231. });
  26232. expect(getCellMeta(0, 0).readOnly).toBe(true);
  26233. expect(syncSources).not.toHaveBeenCalled();
  26234. selectCell(0, 0);
  26235. expect(syncSources).not.toHaveBeenCalled();
  26236. expect(getCellMeta(1, 0).readOnly).toBeFalsy();
  26237. selectCell(1, 0);
  26238. expect(syncSources).not.toHaveBeenCalled();
  26239. });
  26240. it('should not call the `source` method if cell is read only and the arrow has been clicked', function (done) {
  26241. var syncSources = jasmine.createSpy('syncSources');
  26242. syncSources.and.callFake(function (query, process) {
  26243. process([]); // hardcoded empty result
  26244. });
  26245. handsontable({
  26246. data: [['one', 'two'], ['three', 'four']],
  26247. columns: [{
  26248. type: 'autocomplete',
  26249. source: syncSources,
  26250. allowInvalid: false,
  26251. strict: true
  26252. }, {}],
  26253. cells: function cells(row, col) {
  26254. var cellProperties = {};
  26255. if (row === 0 && col === 0) {
  26256. cellProperties.readOnly = true;
  26257. }
  26258. return cellProperties;
  26259. }
  26260. });
  26261. expect(getCellMeta(0, 0).readOnly).toBe(true);
  26262. expect(syncSources).not.toHaveBeenCalled();
  26263. selectCell(0, 0);
  26264. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  26265. setTimeout(function () {
  26266. expect(syncSources).not.toHaveBeenCalled();
  26267. syncSources.calls.reset();
  26268. expect(getCellMeta(1, 0).readOnly).toBeFalsy();
  26269. selectCell(1, 0);
  26270. $(getCell(1, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  26271. }, 100);
  26272. setTimeout(function () {
  26273. expect(syncSources).toHaveBeenCalled();
  26274. expect(syncSources.calls.count()).toEqual(1);
  26275. done();
  26276. }, 200);
  26277. });
  26278. it('should add a scrollbar to the autocomplete dropdown, only if number of displayed choices exceeds 10', function (done) {
  26279. var hot = handsontable({
  26280. data: [['', 'two', 'three'], ['four', 'five', 'six']],
  26281. columns: [{
  26282. type: 'autocomplete',
  26283. source: choices,
  26284. allowInvalid: false,
  26285. strict: false
  26286. }, {}, {}]
  26287. });
  26288. this.$container.css({
  26289. height: 600
  26290. });
  26291. expect(choices.length).toBeGreaterThan(10);
  26292. selectCell(0, 0);
  26293. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  26294. var dropdown = hot.getActiveEditor().htContainer;
  26295. var dropdownHolder = hot.getActiveEditor().htEditor.view.wt.wtTable.holder;
  26296. setTimeout(function () {
  26297. expect(dropdownHolder.scrollHeight).toBeGreaterThan(dropdownHolder.clientHeight);
  26298. keyDownUp('esc');
  26299. hot.getSettings().columns[0].source = hot.getSettings().columns[0].source.slice(0).splice(3);
  26300. hot.updateSettings({});
  26301. selectCell(0, 0);
  26302. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  26303. }, 30);
  26304. setTimeout(function () {
  26305. expect(dropdownHolder.scrollHeight > dropdownHolder.clientHeight).toBe(false);
  26306. done();
  26307. }, 60);
  26308. });
  26309. it('should not close editor on scrolling', function (done) {
  26310. var hot = handsontable({
  26311. data: [['', 'two', 'three'], ['four', 'five', 'six']],
  26312. columns: [{
  26313. type: 'autocomplete',
  26314. source: choices,
  26315. allowInvalid: false,
  26316. strict: false
  26317. }, {}, {}]
  26318. });
  26319. expect(choices.length).toBeGreaterThan(10);
  26320. selectCell(0, 0);
  26321. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  26322. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mouseup');
  26323. var dropdown = hot.getActiveEditor().htContainer;
  26324. hot.view.wt.wtOverlays.topOverlay.scrollTo(1);
  26325. setTimeout(function () {
  26326. expect($(dropdown).is(':visible')).toBe(true);
  26327. selectCell(0, 0);
  26328. }, 30);
  26329. setTimeout(function () {
  26330. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  26331. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mouseup');
  26332. hot.view.wt.wtOverlays.topOverlay.scrollTo(3);
  26333. }, 80);
  26334. setTimeout(function () {
  26335. expect($(dropdown).is(':visible')).toBe(true);
  26336. done();
  26337. }, 120);
  26338. });
  26339. it('should keep textarea caret position, after moving the selection to the suggestion list (pressing down arrow)', function (done) {
  26340. var syncSources = jasmine.createSpy('syncSources');
  26341. syncSources.and.callFake(function (query, process) {
  26342. process(choices.filter(function (choice) {
  26343. return choice.indexOf(query) != -1;
  26344. }));
  26345. });
  26346. handsontable({
  26347. columns: [{
  26348. type: 'autocomplete',
  26349. source: syncSources,
  26350. strict: false
  26351. }]
  26352. });
  26353. selectCell(0, 0);
  26354. keyDownUp('enter');
  26355. var $editorInput = $('.handsontableInput');
  26356. $editorInput.val('an');
  26357. keyDownUp(65); // a
  26358. keyDownUp(78); // n
  26359. Handsontable.dom.setCaretPosition($editorInput[0], 1);
  26360. setTimeout(function () {
  26361. keyDownUp('arrow_down');
  26362. expect(Handsontable.dom.getCaretPosition($editorInput[0])).toEqual(1);
  26363. keyDownUp('arrow_down');
  26364. expect(Handsontable.dom.getCaretPosition($editorInput[0])).toEqual(1);
  26365. done();
  26366. }, 200);
  26367. });
  26368. it('should keep textarea selection, after moving the selection to the suggestion list (pressing down arrow)', function (done) {
  26369. var syncSources = jasmine.createSpy('syncSources');
  26370. syncSources.and.callFake(function (query, process) {
  26371. process(choices.filter(function (choice) {
  26372. return choice.indexOf(query) != -1;
  26373. }));
  26374. });
  26375. handsontable({
  26376. columns: [{
  26377. type: 'autocomplete',
  26378. source: syncSources,
  26379. strict: false
  26380. }]
  26381. });
  26382. selectCell(0, 0);
  26383. keyDownUp('enter');
  26384. var $editorInput = $('.handsontableInput');
  26385. $editorInput.val('an');
  26386. keyDownUp(65); // a
  26387. keyDownUp(78); // n
  26388. Handsontable.dom.setCaretPosition($editorInput[0], 1, 2);
  26389. setTimeout(function () {
  26390. keyDownUp('arrow_down');
  26391. expect(Handsontable.dom.getCaretPosition($editorInput[0])).toEqual(1);
  26392. expect(Handsontable.dom.getSelectionEndPosition($editorInput[0])).toEqual(2);
  26393. keyDownUp('arrow_down');
  26394. expect(Handsontable.dom.getCaretPosition($editorInput[0])).toEqual(1);
  26395. expect(Handsontable.dom.getSelectionEndPosition($editorInput[0])).toEqual(2);
  26396. done();
  26397. }, 200);
  26398. });
  26399. it('should jump to the sibling cell, after pressing up key in quick edit mode', function (done) {
  26400. var syncSources = jasmine.createSpy('syncSources');
  26401. syncSources.and.callFake(function (query, process) {
  26402. process(choices.filter(function (choice) {
  26403. return choice.indexOf(query) != -1;
  26404. }));
  26405. });
  26406. handsontable({
  26407. columns: [{
  26408. type: 'autocomplete',
  26409. source: syncSources,
  26410. strict: false
  26411. }, {}]
  26412. });
  26413. selectCell(1, 0);
  26414. keyDownUp('x'); // trigger quick edit mode
  26415. var $editorInput = $('.handsontableInput');
  26416. $editorInput.val('an');
  26417. keyDownUp(65); // a
  26418. keyDownUp(78); // n
  26419. setTimeout(function () {
  26420. keyDownUp('arrow_up');
  26421. expect(getSelected()).toEqual([0, 0, 0, 0]);
  26422. done();
  26423. }, 200);
  26424. });
  26425. it('should jump to the next cell, after pressing right key in quick edit mode', function (done) {
  26426. var syncSources = jasmine.createSpy('syncSources');
  26427. syncSources.plan = function (query, process) {
  26428. process(choices.filter(function (choice) {
  26429. return choice.indexOf(query) != -1;
  26430. }));
  26431. };
  26432. handsontable({
  26433. columns: [{
  26434. type: 'autocomplete',
  26435. source: syncSources,
  26436. strict: false
  26437. }, {}]
  26438. });
  26439. selectCell(1, 0);
  26440. keyDownUp('x'); // trigger quick edit mode
  26441. var $editorInput = $('.handsontableInput');
  26442. $editorInput.val('an');
  26443. keyDownUp(65); // a
  26444. keyDownUp(78); // n
  26445. setTimeout(function () {
  26446. keyDownUp('arrow_right');
  26447. expect(getSelected()).toEqual([1, 1, 1, 1]);
  26448. done();
  26449. }, 200);
  26450. });
  26451. it('should jump to the next cell, after pressing left key in quick edit mode', function (done) {
  26452. var syncSources = jasmine.createSpy('syncSources');
  26453. syncSources.and.callFake(function (query, process) {
  26454. process(choices.filter(function (choice) {
  26455. return choice.indexOf(query) != -1;
  26456. }));
  26457. });
  26458. handsontable({
  26459. columns: [{}, {
  26460. type: 'autocomplete',
  26461. source: syncSources,
  26462. strict: false
  26463. }]
  26464. });
  26465. selectCell(1, 1);
  26466. keyDownUp('x'); // trigger quick edit mode
  26467. var $editorInput = $('.handsontableInput');
  26468. $editorInput.val('an');
  26469. keyDownUp(65); // a
  26470. keyDownUp(78); // n
  26471. // put caret on the end of the text to ensure that editor will be closed after hit left arrow key
  26472. Handsontable.dom.setCaretPosition($editorInput[0], 2, 2);
  26473. setTimeout(function () {
  26474. keyDownUp('arrow_left');
  26475. expect(getSelected()).toEqual([1, 0, 1, 0]);
  26476. done();
  26477. }, 200);
  26478. });
  26479. it('should jump to the next cell, after pressing down key in quick edit mode', function (done) {
  26480. var syncSources = jasmine.createSpy('syncSources');
  26481. syncSources.and.callFake(function (query, process) {
  26482. process(choices.filter(function (choice) {
  26483. return choice.indexOf(query) != -1;
  26484. }));
  26485. });
  26486. handsontable({
  26487. columns: [{
  26488. type: 'autocomplete',
  26489. source: syncSources,
  26490. strict: false
  26491. }, {}]
  26492. });
  26493. selectCell(1, 0);
  26494. keyDownUp('x'); // trigger quick edit mode
  26495. var $editorInput = $('.handsontableInput');
  26496. $editorInput.val('an');
  26497. keyDownUp(65); // a
  26498. keyDownUp(78); // n
  26499. setTimeout(function () {
  26500. keyDownUp('arrow_down');
  26501. expect(getSelected()).toEqual([1, 0, 1, 0]);
  26502. done();
  26503. }, 200);
  26504. });
  26505. it('should jump to the next cell, after pressing down key in quick edit mode when no matching option list found', function (done) {
  26506. var syncSources = jasmine.createSpy('syncSources');
  26507. syncSources.and.callFake(function (query, process) {
  26508. process(choices.filter(function (choice) {
  26509. return choice.indexOf(query) != -1;
  26510. }));
  26511. });
  26512. handsontable({
  26513. columns: [{
  26514. type: 'autocomplete',
  26515. source: syncSources,
  26516. strict: false
  26517. }, {}]
  26518. });
  26519. selectCell(1, 0);
  26520. keyDownUp('x'); // trigger quick edit mode
  26521. var $editorInput = $('.handsontableInput');
  26522. $editorInput.val('anananan');
  26523. keyDownUp(65); // a
  26524. keyDownUp(78); // n
  26525. keyDownUp(65); // a
  26526. keyDownUp(78); // n
  26527. keyDownUp(65); // a
  26528. keyDownUp(78); // n
  26529. keyDownUp(65); // a
  26530. keyDownUp(78); // n
  26531. setTimeout(function () {
  26532. keyDownUp('arrow_down');
  26533. expect(getSelected()).toEqual([2, 0, 2, 0]);
  26534. done();
  26535. }, 200);
  26536. });
  26537. it('should not jump to the next cell, after pressing down key in quick edit mode when options list was opened', function (done) {
  26538. var syncSources = jasmine.createSpy('syncSources');
  26539. syncSources.and.callFake(function (query, process) {
  26540. process(choices.filter(function (choice) {
  26541. return choice.indexOf(query) != -1;
  26542. }));
  26543. });
  26544. handsontable({
  26545. columns: [{
  26546. type: 'autocomplete',
  26547. source: syncSources,
  26548. strict: false
  26549. }, {}]
  26550. });
  26551. selectCell(1, 0);
  26552. keyDownUp('x'); // trigger quick edit mode
  26553. var $editorInput = $('.handsontableInput');
  26554. $editorInput.val('an');
  26555. keyDownUp(65); // a
  26556. keyDownUp(78); // n
  26557. setTimeout(function () {
  26558. keyDownUp('arrow_down');
  26559. expect(getSelected()).toEqual([1, 0, 1, 0]);
  26560. done();
  26561. }, 200);
  26562. });
  26563. it('should select option in opened editor after pressing down key in quick edit mode', function (done) {
  26564. var syncSources = jasmine.createSpy('syncSources');
  26565. syncSources.and.callFake(function (query, process) {
  26566. process(choices.filter(function (choice) {
  26567. return choice.indexOf(query) != -1;
  26568. }));
  26569. });
  26570. var hot = handsontable({
  26571. columns: [{
  26572. type: 'autocomplete',
  26573. source: syncSources,
  26574. strict: false
  26575. }, {}]
  26576. });
  26577. selectCell(1, 0);
  26578. keyDownUp('x'); // Trigger quick edit mode
  26579. setTimeout(function () {
  26580. keyDownUp('arrow_down');
  26581. expect(hot.getActiveEditor().htEditor.getSelected()).toEqual([0, 0, 0, 0]);
  26582. keyDownUp('arrow_down');
  26583. expect(hot.getActiveEditor().htEditor.getSelected()).toEqual([1, 0, 1, 0]);
  26584. keyDownUp('arrow_down');
  26585. expect(hot.getActiveEditor().htEditor.getSelected()).toEqual([2, 0, 2, 0]);
  26586. done();
  26587. }, 200);
  26588. });
  26589. it('should select option in opened editor after pressing up key in quick edit mode', function (done) {
  26590. var syncSources = jasmine.createSpy('syncSources');
  26591. syncSources.and.callFake(function (query, process) {
  26592. process(choices.filter(function (choice) {
  26593. return choice.indexOf(query) != -1;
  26594. }));
  26595. });
  26596. var hot = handsontable({
  26597. columns: [{
  26598. type: 'autocomplete',
  26599. source: syncSources,
  26600. strict: false
  26601. }, {}]
  26602. });
  26603. selectCell(1, 0);
  26604. keyDownUp('x'); // Trigger quick edit mode
  26605. setTimeout(function () {
  26606. hot.getActiveEditor().htEditor.selectCell(2, 0);
  26607. expect(hot.getActiveEditor().htEditor.getSelected()).toEqual([2, 0, 2, 0]);
  26608. keyDownUp('arrow_up');
  26609. expect(hot.getActiveEditor().htEditor.getSelected()).toEqual([1, 0, 1, 0]);
  26610. keyDownUp('arrow_up');
  26611. expect(hot.getActiveEditor().htEditor.getSelected()).toEqual([0, 0, 0, 0]);
  26612. keyDownUp('arrow_up');
  26613. expect(hot.getActiveEditor().htEditor.getSelected()).toEqual([0, 0, 0, 0]);
  26614. done();
  26615. }, 200);
  26616. });
  26617. it('should not close editor in quick edit mode after pressing down key when last option is selected', function (done) {
  26618. var syncSources = jasmine.createSpy('syncSources');
  26619. syncSources.and.callFake(function (query, process) {
  26620. process(choices.filter(function (choice) {
  26621. return choice.indexOf(query) != -1;
  26622. }));
  26623. });
  26624. var hot = handsontable({
  26625. columns: [{
  26626. type: 'autocomplete',
  26627. source: syncSources,
  26628. strict: false
  26629. }, {}]
  26630. });
  26631. selectCell(1, 0);
  26632. keyDownUp('x'); // Trigger quick edit mode
  26633. setTimeout(function () {
  26634. hot.getActiveEditor().htEditor.selectCell(7, 0);
  26635. hot.listen();
  26636. keyDownUp('arrow_down');
  26637. keyDownUp('arrow_down');
  26638. keyDownUp('arrow_down');
  26639. keyDownUp('arrow_down');
  26640. keyDownUp('arrow_down');
  26641. expect(hot.getActiveEditor().isOpened()).toBe(true);
  26642. done();
  26643. }, 200);
  26644. });
  26645. it('should close editor in quick edit mode after pressing up key when no option is selected', function (done) {
  26646. var syncSources = jasmine.createSpy('syncSources');
  26647. syncSources.and.callFake(function (query, process) {
  26648. process(choices.filter(function (choice) {
  26649. return choice.indexOf(query) != -1;
  26650. }));
  26651. });
  26652. var hot = handsontable({
  26653. columns: [{
  26654. type: 'autocomplete',
  26655. source: syncSources,
  26656. strict: false
  26657. }, {}]
  26658. });
  26659. selectCell(1, 0);
  26660. keyDownUp('x'); // Trigger quick edit mode
  26661. setTimeout(function () {
  26662. hot.getActiveEditor().htEditor.selectCell(1, 0);
  26663. hot.listen();
  26664. keyDownUp('arrow_up');
  26665. keyDownUp('arrow_up');
  26666. keyDownUp('arrow_up');
  26667. expect(getSelected()).toEqual([0, 0, 0, 0]);
  26668. done();
  26669. }, 200);
  26670. });
  26671. });
  26672. /***/ }),
  26673. /* 206 */
  26674. /***/ (function(module, exports, __webpack_require__) {
  26675. "use strict";
  26676. describe('BaseEditor', function () {
  26677. var id = 'testContainer';
  26678. beforeEach(function () {
  26679. this.$container = $('<div id="' + id + '" style="width: 300px; height: 200px; overflow: auto"></div>').appendTo('body');
  26680. });
  26681. afterEach(function () {
  26682. if (this.$container) {
  26683. destroy();
  26684. this.$container.remove();
  26685. }
  26686. });
  26687. describe('ctrl + enter when editor is active', function () {
  26688. it('should populate value from the currently active cell to every cell in the selected range', function () {
  26689. var hot = handsontable({
  26690. data: Handsontable.helper.createSpreadsheetData(6, 6)
  26691. });
  26692. selectCell(1, 1, 2, 2);
  26693. expect(getDataAtCell(1, 1)).toEqual('B2');
  26694. expect(getDataAtCell(2, 2)).toEqual('C3');
  26695. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  26696. keyDown('ctrl+enter');
  26697. expect(getDataAtCell(1, 1)).toEqual('B2');
  26698. expect(getDataAtCell(1, 2)).toEqual('B2');
  26699. expect(getDataAtCell(2, 1)).toEqual('B2');
  26700. expect(getDataAtCell(2, 2)).toEqual('B2');
  26701. loadData(Handsontable.helper.createSpreadsheetData(6, 6));
  26702. selectCell(1, 2, 2, 1);
  26703. expect(getDataAtCell(1, 2)).toEqual('C2');
  26704. expect(getDataAtCell(2, 1)).toEqual('B3');
  26705. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  26706. keyDown('ctrl+enter');
  26707. expect(getDataAtCell(1, 1)).toEqual('C2');
  26708. expect(getDataAtCell(1, 2)).toEqual('C2');
  26709. expect(getDataAtCell(2, 1)).toEqual('C2');
  26710. expect(getDataAtCell(2, 2)).toEqual('C2');
  26711. loadData(Handsontable.helper.createSpreadsheetData(6, 6));
  26712. selectCell(2, 2, 1, 1);
  26713. expect(getDataAtCell(2, 2)).toEqual('C3');
  26714. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  26715. keyDown('ctrl+enter');
  26716. expect(getDataAtCell(1, 1)).toEqual('C3');
  26717. expect(getDataAtCell(1, 2)).toEqual('C3');
  26718. expect(getDataAtCell(2, 1)).toEqual('C3');
  26719. expect(getDataAtCell(2, 2)).toEqual('C3');
  26720. loadData(Handsontable.helper.createSpreadsheetData(6, 6));
  26721. selectCell(2, 1, 1, 2);
  26722. expect(getDataAtCell(2, 1)).toEqual('B3');
  26723. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  26724. keyDown('ctrl+enter');
  26725. expect(getDataAtCell(1, 1)).toEqual('B3');
  26726. expect(getDataAtCell(1, 2)).toEqual('B3');
  26727. expect(getDataAtCell(2, 1)).toEqual('B3');
  26728. expect(getDataAtCell(2, 2)).toEqual('B3');
  26729. });
  26730. });
  26731. it('should exported all editors into Handsontable.editors object', function () {
  26732. expect(Handsontable.editors.AutocompleteEditor).toBeDefined();
  26733. expect(Handsontable.editors.BaseEditor).toBeDefined();
  26734. expect(Handsontable.editors.CheckboxEditor).toBeDefined();
  26735. expect(Handsontable.editors.DateEditor).toBeDefined();
  26736. expect(Handsontable.editors.DropdownEditor).toBeDefined();
  26737. expect(Handsontable.editors.HandsontableEditor).toBeDefined();
  26738. expect(Handsontable.editors.MobileEditor).toBeDefined();
  26739. expect(Handsontable.editors.NumericEditor).toBeDefined();
  26740. expect(Handsontable.editors.PasswordEditor).toBeDefined();
  26741. expect(Handsontable.editors.SelectEditor).toBeDefined();
  26742. expect(Handsontable.editors.TextEditor).toBeDefined();
  26743. });
  26744. });
  26745. /***/ }),
  26746. /* 207 */
  26747. /***/ (function(module, exports, __webpack_require__) {
  26748. "use strict";
  26749. describe('DateEditor', function () {
  26750. var id = 'testContainer';
  26751. beforeEach(function () {
  26752. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  26753. });
  26754. afterEach(function () {
  26755. if (this.$container) {
  26756. destroy();
  26757. this.$container.remove();
  26758. }
  26759. });
  26760. function getDates() {
  26761. return [['01/14/2006'], ['12/01/2008'], ['11/19/2011'], ['02/02/2004'], ['07/24/2011']];
  26762. }
  26763. it('should display Pikday calendar', function () {
  26764. handsontable({
  26765. data: getDates(),
  26766. columns: [{
  26767. type: 'date'
  26768. }]
  26769. });
  26770. expect($('.pika-single').is(':visible')).toBe(false);
  26771. selectCell(0, 0);
  26772. keyDown('enter');
  26773. expect($('.pika-single').is(':visible')).toBe(true);
  26774. });
  26775. it('should pass date picker config object to Pikday', function () {
  26776. var onOpenSpy = jasmine.createSpy('open');
  26777. var onCloseSpy = jasmine.createSpy('close');
  26778. var hot = handsontable({
  26779. data: getDates(),
  26780. columns: [{
  26781. type: 'date',
  26782. datePickerConfig: {
  26783. firstDay: 1,
  26784. field: 'field', // read only - shouldn't overwrite
  26785. trigger: 'trigger', // read only - shouldn't overwrite
  26786. container: 'container', // read only - shouldn't overwrite
  26787. bound: true, // read only - shouldn't overwrite
  26788. i18n: {
  26789. previousMonth: 'Poprzedni',
  26790. nextMonth: 'Następny',
  26791. months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
  26792. weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
  26793. weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
  26794. },
  26795. onOpen: onOpenSpy,
  26796. onClose: onCloseSpy
  26797. }
  26798. }]
  26799. });
  26800. selectCell(0, 0);
  26801. keyDown('enter');
  26802. keyDown('esc');
  26803. var config = hot.getActiveEditor().$datePicker.config();
  26804. expect(config.field instanceof HTMLElement).toBe(true);
  26805. expect(config.trigger instanceof HTMLElement).toBe(true);
  26806. expect(config.container instanceof HTMLElement).toBe(true);
  26807. expect(config.bound).toBe(false);
  26808. expect(config.firstDay).toBe(1);
  26809. expect(config.i18n.previousMonth).toBe('Poprzedni');
  26810. expect(config.i18n.nextMonth).toBe('Następny');
  26811. expect(onOpenSpy).toHaveBeenCalled();
  26812. expect(onCloseSpy).toHaveBeenCalled();
  26813. });
  26814. it('should remove any HTML connected with Pikaday Calendar', function () {
  26815. handsontable({
  26816. data: getDates(),
  26817. columns: [{
  26818. type: 'date'
  26819. }]
  26820. });
  26821. expect($('.pika-single').length).toBe(0);
  26822. selectCell(0, 0);
  26823. keyDown('enter');
  26824. expect($('.pika-single').length).toBe(1);
  26825. destroy();
  26826. expect($('.pika-single').length).toBe(0);
  26827. });
  26828. it('should select date corresponding to cell value', function () {
  26829. handsontable({
  26830. data: getDates(),
  26831. columns: [{
  26832. type: 'date',
  26833. dateFormat: 'MM/DD/YYYY'
  26834. }]
  26835. });
  26836. selectCell(0, 0);
  26837. keyDown('enter');
  26838. var date = new Date(getDates()[0][0]);
  26839. expect($('.pika-single').find('.pika-select-year').find(':selected').val()).toMatch(date.getFullYear().toString());
  26840. expect($('.pika-single').find('.pika-select-month').find(':selected').val()).toMatch(date.getMonth().toString());
  26841. expect($('.pika-single').find('.pika-table .is-selected').text()).toMatch(date.getDate().toString());
  26842. });
  26843. it('should save new date after clicked on calendar', function (done) {
  26844. handsontable({
  26845. data: getDates(),
  26846. columns: [{
  26847. type: 'date',
  26848. dateFormat: 'MM/DD/YYYY'
  26849. }]
  26850. });
  26851. selectCell(0, 0);
  26852. expect(getDataAtCell(0, 0)).toMatch('01/14/2006');
  26853. keyDown('enter');
  26854. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(0) td:eq(0) button'));
  26855. setTimeout(function () {
  26856. expect(getDataAtCell(0, 0)).toMatch('01/01/2006');
  26857. done();
  26858. }, 150);
  26859. });
  26860. it('should display fill handle after selected date on calendar', function (done) {
  26861. handsontable({
  26862. data: getDates(),
  26863. columns: [{
  26864. type: 'date',
  26865. dateFormat: 'MM/DD/YYYY'
  26866. }]
  26867. });
  26868. selectCell(0, 0);
  26869. expect(getDataAtCell(0, 0)).toMatch('01/14/2006');
  26870. keyDown('enter');
  26871. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(0) td:eq(0) button'));
  26872. setTimeout(function () {
  26873. expect(getDataAtCell(0, 0)).toMatch('01/01/2006');
  26874. expect($('.htBorders .current.corner').is(':visible')).toBe(true);
  26875. done();
  26876. }, 150);
  26877. });
  26878. it('should setup in settings and display defaultDate on calendar', function (done) {
  26879. handsontable({
  26880. data: getDates(),
  26881. minSpareRows: 1,
  26882. columns: [{
  26883. type: 'date',
  26884. dateFormat: 'MM/DD/YYYY',
  26885. defaultDate: '01/01/1900'
  26886. }]
  26887. });
  26888. selectCell(5, 0);
  26889. expect(getDataAtCell(5, 0)).toBe(null);
  26890. keyDown('enter');
  26891. var date = new Date('01/01/1900');
  26892. expect($('.pika-single').find('.pika-select-year').find(':selected').val()).toMatch(date.getFullYear().toString());
  26893. expect($('.pika-single').find('.pika-select-month').find(':selected').val()).toMatch(date.getMonth().toString());
  26894. expect($('.pika-single').find('.pika-table .is-selected').text()).toMatch(date.getDate().toString());
  26895. keyDown('enter');
  26896. setTimeout(function () {
  26897. expect(getDataAtCell(5, 0)).toMatch('01/01/1900');
  26898. done();
  26899. }, 150);
  26900. });
  26901. it('should close calendar after picking new date', function () {
  26902. handsontable({
  26903. data: getDates(),
  26904. columns: [{
  26905. type: 'date',
  26906. dateFormat: 'MM/DD/YYYY'
  26907. }]
  26908. });
  26909. selectCell(0, 0);
  26910. keyDown('enter');
  26911. expect($('.pika-single').is(':visible')).toBe(true);
  26912. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(0) td:eq(0) button'));
  26913. expect($('.pika-single').is(':visible')).toBe(false);
  26914. });
  26915. it('should enable to input any value in textarea', function (done) {
  26916. var hot = handsontable({
  26917. data: getDates(),
  26918. columns: [{
  26919. type: 'date'
  26920. }]
  26921. });
  26922. selectCell(0, 0);
  26923. var editor = hot.getActiveEditor();
  26924. editor.beginEditing();
  26925. expect(editor.isOpened()).toBe(true);
  26926. editor.TEXTAREA.value = 'foo';
  26927. keyDownUp('o'.charCodeAt(0));
  26928. expect(editor.getValue()).toEqual('foo');
  26929. editor.finishEditing();
  26930. setTimeout(function () {
  26931. expect(getDataAtCell(0, 0)).toEqual('foo');
  26932. done();
  26933. }, 30);
  26934. });
  26935. it('should restore original when edited and pressed ESC ', function (done) {
  26936. var hot = handsontable({
  26937. data: getDates(),
  26938. columns: [{
  26939. type: 'date'
  26940. }]
  26941. });
  26942. selectCell(0, 0);
  26943. var editor = hot.getActiveEditor();
  26944. editor.beginEditing();
  26945. expect(editor.isOpened()).toBe(true);
  26946. editor.TEXTAREA.value = 'foo';
  26947. expect(editor.getValue()).toEqual('foo');
  26948. keyDownUp(Handsontable.helper.KEY_CODES.ESCAPE); // cancel editing
  26949. editor.finishEditing();
  26950. setTimeout(function () {
  26951. expect(getDataAtCell(0, 0)).toEqual('01/14/2006');
  26952. done();
  26953. }, 30);
  26954. });
  26955. it('should display a calendar based on a current date, even if a date in a wrong format was entered previously', function (done) {
  26956. var hot = handsontable({
  26957. data: Handsontable.helper.createSpreadsheetData(5, 2),
  26958. columns: [{ type: 'date' }, { type: 'date', dateFormat: 'YYYY-MM-DD' }],
  26959. minSpareRows: 1
  26960. });
  26961. setDataAtCell(4, 1, '15-11-11');
  26962. setTimeout(function () {
  26963. selectCell(5, 1);
  26964. keyDown('enter');
  26965. expect($('.pika-single').is(':visible')).toBe(true);
  26966. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(3) td:eq(3) button'));
  26967. }, 150);
  26968. setTimeout(function () {
  26969. var resultDate = getDataAtCell(5, 1);
  26970. expect(moment(resultDate).year()).toEqual(moment().year());
  26971. expect(moment(resultDate).month()).toEqual(moment().month());
  26972. done();
  26973. }, 300);
  26974. });
  26975. it('should display Pikaday Calendar bottom of the selected cell', function () {
  26976. var hot = handsontable({
  26977. data: Handsontable.helper.createSpreadsheetData(5, 2),
  26978. columns: [{ type: 'date' }, { type: 'date' }]
  26979. }),
  26980. cellOffset,
  26981. datePickerOffset;
  26982. selectCell(1, 1);
  26983. keyDown('enter');
  26984. cellOffset = $(hot.getActiveEditor().TD).offset();
  26985. datePickerOffset = $('.pika-single').offset();
  26986. // 23 is a height of the editor cell
  26987. expect(cellOffset.top + 23).toBeCloseTo(datePickerOffset.top, 0);
  26988. expect(cellOffset.left).toBeCloseTo(datePickerOffset.left, 0);
  26989. });
  26990. it('should display Pikaday Calendar bottom of the selected cell when table have scrolls', function () {
  26991. var container = $('#testContainer');
  26992. container[0].style.height = '300px';
  26993. container[0].style.width = '200px';
  26994. container[0].style.overflow = 'hidden';
  26995. var hot = handsontable({
  26996. data: Handsontable.helper.createSpreadsheetData(30, 10),
  26997. colWidths: 60,
  26998. columns: [{ type: 'date' }, { type: 'date' }, { type: 'date' }, { type: 'date' }, { type: 'date' }, { type: 'date' }, { type: 'date' }]
  26999. }),
  27000. cellOffset,
  27001. datePickerOffset;
  27002. selectCell(20, 6);
  27003. keyDown('enter');
  27004. cellOffset = $(hot.getActiveEditor().TD).offset();
  27005. datePickerOffset = $('.pika-single').offset();
  27006. expect(cellOffset.top + 23).toBeCloseTo(datePickerOffset.top, 0);
  27007. expect(cellOffset.left).toBeCloseTo(datePickerOffset.left, 0);
  27008. });
  27009. it('should not modify the edited date and time, when opening the editor', function () {
  27010. var hot = handsontable({
  27011. data: [['02/02/2015 8:00 AM']],
  27012. columns: [{
  27013. type: 'date',
  27014. dateFormat: 'MM/DD/YYYY h:mm A',
  27015. correctFormat: true,
  27016. defaultDate: '01/01/1900',
  27017. allowEmpty: false
  27018. }]
  27019. }),
  27020. editor,
  27021. cellValue;
  27022. // setDataAtCell(0, 0, '02/02/2015 8:00 AM');
  27023. cellValue = getDataAtCell(0, 0);
  27024. selectCell(0, 0);
  27025. keyDown('enter');
  27026. editor = hot.getActiveEditor();
  27027. expect(editor.TEXTAREA.value).toEqual(cellValue);
  27028. });
  27029. });
  27030. /***/ }),
  27031. /* 208 */
  27032. /***/ (function(module, exports, __webpack_require__) {
  27033. "use strict";
  27034. describe('DropdownEditor', function () {
  27035. var id = 'testContainer';
  27036. var choices = ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white', 'purple', 'lime', 'olive', 'cyan'];
  27037. var hot;
  27038. beforeEach(function () {
  27039. this.$container = $('<div id="' + id + '" style="width: 300px; height: 200px; overflow: auto"></div>').appendTo('body');
  27040. });
  27041. afterEach(function () {
  27042. if (hot) {
  27043. hot = null;
  27044. }
  27045. if (this.$container) {
  27046. destroy();
  27047. this.$container.remove();
  27048. }
  27049. });
  27050. describe('open editor', function () {
  27051. // see https://github.com/handsontable/handsontable/issues/3380
  27052. it('should not throw error while selecting the next cell by hitting enter key', function () {
  27053. var spy = jasmine.createSpyObj('error', ['test']);
  27054. var prevError = window.onerror;
  27055. window.onerror = function (messageOrEvent, source, lineno, colno, error) {
  27056. spy.test();
  27057. };
  27058. handsontable({
  27059. columns: [{
  27060. editor: 'dropdown',
  27061. source: choices
  27062. }]
  27063. });
  27064. selectCell(0, 0);
  27065. keyDownUp('enter');
  27066. keyDownUp('enter');
  27067. keyDownUp('enter');
  27068. expect(spy.test.calls.count()).toBe(0);
  27069. window.onerror = prevError;
  27070. });
  27071. });
  27072. describe('closing the editor', function () {
  27073. it('should not close editor on scrolling', function (done) {
  27074. hot = handsontable({
  27075. data: [['', 'two', 'three'], ['four', 'five', 'six']],
  27076. columns: [{
  27077. type: 'dropdown',
  27078. source: choices
  27079. }, {}, {}]
  27080. });
  27081. selectCell(0, 0);
  27082. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  27083. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mouseup');
  27084. hot.view.wt.wtOverlays.topOverlay.scrollTo(1);
  27085. var dropdown = hot.getActiveEditor();
  27086. setTimeout(function () {
  27087. expect($(dropdown.htContainer).is(':visible')).toBe(true);
  27088. selectCell(0, 0);
  27089. }, 30);
  27090. setTimeout(function () {
  27091. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  27092. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mouseup');
  27093. hot.view.wt.wtOverlays.topOverlay.scrollTo(3);
  27094. }, 150);
  27095. setTimeout(function () {
  27096. expect($(dropdown.htContainer).is(':visible')).toBe(true);
  27097. done();
  27098. }, 200);
  27099. });
  27100. });
  27101. it('should mark all invalid values as invalid, after pasting them into dropdown-type cells', function (done) {
  27102. hot = handsontable({
  27103. data: [['', 'two', 'three'], ['four', 'five', 'six']],
  27104. columns: [{
  27105. type: 'dropdown',
  27106. source: choices
  27107. }, {}, {}]
  27108. });
  27109. populateFromArray(0, 0, [['invalid'], ['input']], null, null, 'paste');
  27110. setTimeout(function () {
  27111. expect(Handsontable.dom.hasClass(getCell(0, 0), 'htInvalid')).toBe(true);
  27112. expect(Handsontable.dom.hasClass(getCell(1, 0), 'htInvalid')).toBe(true);
  27113. done();
  27114. }, 40);
  27115. });
  27116. });
  27117. /***/ }),
  27118. /* 209 */
  27119. /***/ (function(module, exports, __webpack_require__) {
  27120. "use strict";
  27121. describe('HandsontableEditor', function () {
  27122. var id = 'testContainer';
  27123. beforeEach(function () {
  27124. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  27125. });
  27126. afterEach(function () {
  27127. if (this.$container) {
  27128. destroy();
  27129. this.$container.remove();
  27130. }
  27131. });
  27132. function getManufacturerData() {
  27133. return [{ name: 'BMW', country: 'Germany', owner: 'Bayerische Motoren Werke AG' }, { name: 'Chrysler', country: 'USA', owner: 'Chrysler Group LLC' }, { name: 'Nissan', country: 'Japan', owner: 'Nissan Motor Company Ltd' }, { name: 'Suzuki', country: 'Japan', owner: 'Suzuki Motor Corporation' }, { name: 'Toyota', country: 'Japan', owner: 'Toyota Motor Corporation' }, { name: 'Volvo', country: 'Sweden', owner: 'Zhejiang Geely Holding Group' }];
  27134. }
  27135. it('should create an editor that is a Handsontable instance', function () {
  27136. handsontable({
  27137. columns: [{
  27138. type: 'handsontable',
  27139. handsontable: {
  27140. colHeaders: ['Marque', 'Country', 'Parent company'],
  27141. data: getManufacturerData()
  27142. }
  27143. }]
  27144. });
  27145. selectCell(2, 0);
  27146. keyDownUp('enter');
  27147. expect(this.$container.find('.handsontableEditor:visible').length).toEqual(1);
  27148. });
  27149. it('should destroy the editor when Esc is pressed', function () {
  27150. handsontable({
  27151. columns: [{
  27152. type: 'handsontable',
  27153. handsontable: {
  27154. colHeaders: ['Marque', 'Country', 'Parent company'],
  27155. data: getManufacturerData()
  27156. }
  27157. }]
  27158. });
  27159. selectCell(2, 0);
  27160. keyDownUp('enter');
  27161. keyDownUp('esc');
  27162. expect(this.$container.find('.handsontableEditor:visible').length).toEqual(0);
  27163. });
  27164. // see https://github.com/handsontable/handsontable/issues/3380
  27165. it('should not throw error while selecting the next cell by hitting enter key', function () {
  27166. var spy = jasmine.createSpyObj('error', ['test']);
  27167. var prevError = window.onerror;
  27168. window.onerror = function (messageOrEvent, source, lineno, colno, error) {
  27169. spy.test();
  27170. };
  27171. handsontable({
  27172. columns: [{
  27173. type: 'handsontable',
  27174. handsontable: {
  27175. data: [['Marque'], ['Country'], ['Parent company']]
  27176. }
  27177. }]
  27178. });
  27179. selectCell(0, 0);
  27180. keyDownUp('enter');
  27181. keyDownUp('enter');
  27182. keyDownUp('enter');
  27183. expect(spy.test.calls.count()).toBe(0);
  27184. window.onerror = prevError;
  27185. });
  27186. it('Enter pressed in nested HT should set the value and hide the editor', function () {
  27187. handsontable({
  27188. columns: [{
  27189. type: 'handsontable',
  27190. handsontable: {
  27191. colHeaders: ['Marque', 'Country', 'Parent company'],
  27192. data: getManufacturerData()
  27193. }
  27194. }]
  27195. });
  27196. selectCell(2, 0);
  27197. keyDownUp('enter');
  27198. keyDownUp('arrow_down');
  27199. keyDownUp('enter');
  27200. expect(this.$container.find('.handsontableEditor:visible').length).toEqual(0);
  27201. expect(getDataAtCell(2, 0)).toEqual('BMW');
  27202. });
  27203. it('should keep focus on textarea after arrow is pressed', function () {
  27204. var hot = handsontable({
  27205. columns: [{
  27206. type: 'handsontable',
  27207. handsontable: {
  27208. colHeaders: ['Marque', 'Country', 'Parent company'],
  27209. data: getManufacturerData()
  27210. }
  27211. }]
  27212. });
  27213. selectCell(2, 0);
  27214. keyDownUp('enter');
  27215. keyDownUp('arrow_down');
  27216. expect(document.activeElement).toEqual(hot.getActiveEditor().TEXTAREA);
  27217. });
  27218. it('should focus the TD after HT editor is prepared and destroyed', function () {
  27219. handsontable({
  27220. columns: [{
  27221. type: 'handsontable',
  27222. handsontable: {
  27223. colHeaders: ['Marque', 'Country', 'Parent company'],
  27224. data: getManufacturerData()
  27225. }
  27226. }]
  27227. });
  27228. selectCell(2, 0);
  27229. keyDownUp('arrow_down');
  27230. keyDownUp('arrow_down');
  27231. expect(getSelected()).toEqual([4, 0, 4, 0]);
  27232. });
  27233. it('should focus the TD after HT editor is prepared, finished (by keyboard) and destroyed', function () {
  27234. var selections = [];
  27235. handsontable({
  27236. columns: [{
  27237. type: 'handsontable',
  27238. handsontable: {
  27239. colHeaders: ['Marque', 'Country', 'Parent company'],
  27240. data: getManufacturerData(),
  27241. afterSelection: function afterSelection() {
  27242. selections.push(['inner', arguments[0]]); // arguments[0] is selection start row
  27243. }
  27244. }
  27245. }],
  27246. afterSelection: function afterSelection() {
  27247. selections.push(['outer', arguments[0]]); // arguments[0] is selection start row
  27248. }
  27249. });
  27250. expect(selections.length).toBe(0);
  27251. selectCell(1, 0);
  27252. expect(selections[0]).toEqual(['outer', 1]);
  27253. keyDownUp('arrow_down');
  27254. expect(selections[1]).toEqual(['outer', 2]);
  27255. keyDownUp('enter');
  27256. keyDownUp('arrow_down');
  27257. expect(selections[2]).toEqual(['inner', 0]);
  27258. keyDownUp('esc');
  27259. keyDownUp('arrow_down');
  27260. expect(selections[3]).toEqual(['outer', 3]);
  27261. expect(selections.length).toBe(4);
  27262. });
  27263. describe('strict mode', function () {
  27264. it('should open editor and select cell (0, 0) in inner HOT', function () {
  27265. var hot = handsontable({
  27266. columns: [{
  27267. type: 'handsontable',
  27268. handsontable: {
  27269. colHeaders: ['Marque', 'Country', 'Parent company'],
  27270. data: getManufacturerData()
  27271. },
  27272. strict: true
  27273. }]
  27274. });
  27275. selectCell(2, 0);
  27276. keyDownUp('enter');
  27277. var ht = hot.getActiveEditor();
  27278. var innerHot = ht.htEditor;
  27279. expect(innerHot.getSelected()).toEqual([0, 0, 0, 0]);
  27280. });
  27281. it('should hide textarea', function () {
  27282. var hot = handsontable({
  27283. columns: [{
  27284. type: 'handsontable',
  27285. handsontable: {
  27286. colHeaders: ['Marque', 'Country', 'Parent company'],
  27287. data: getManufacturerData()
  27288. },
  27289. strict: true
  27290. }]
  27291. });
  27292. selectCell(2, 0);
  27293. keyDownUp('enter');
  27294. expect(hot.getActiveEditor().TEXTAREA.style.visibility).toEqual('hidden');
  27295. });
  27296. });
  27297. describe('non strict mode', function () {
  27298. it('should open editor and DO NOT select any cell in inner HOT', function () {
  27299. var hot = handsontable({
  27300. columns: [{
  27301. type: 'handsontable',
  27302. handsontable: {
  27303. colHeaders: ['Marque', 'Country', 'Parent company'],
  27304. data: getManufacturerData()
  27305. }
  27306. }]
  27307. });
  27308. selectCell(2, 0);
  27309. keyDownUp('enter');
  27310. var ht = hot.getActiveEditor();
  27311. var innerHot = ht.htEditor;
  27312. expect(innerHot.getSelected()).toBeUndefined();
  27313. });
  27314. it('should show textarea', function () {
  27315. var hot = handsontable({
  27316. columns: [{
  27317. type: 'handsontable',
  27318. handsontable: {
  27319. colHeaders: ['Marque', 'Country', 'Parent company'],
  27320. data: getManufacturerData()
  27321. }
  27322. }]
  27323. });
  27324. selectCell(2, 0);
  27325. keyDownUp('enter');
  27326. expect(hot.getActiveEditor().TEXTAREA.style.visibility).toEqual('visible');
  27327. });
  27328. });
  27329. });
  27330. /***/ }),
  27331. /* 210 */
  27332. /***/ (function(module, exports, __webpack_require__) {
  27333. "use strict";
  27334. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  27335. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  27336. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  27337. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  27338. describe('editors', function () {
  27339. var id = 'testContainer';
  27340. var _Handsontable$editors = Handsontable.editors,
  27341. registerEditor = _Handsontable$editors.registerEditor,
  27342. getEditor = _Handsontable$editors.getEditor;
  27343. beforeEach(function () {
  27344. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  27345. });
  27346. afterEach(function () {
  27347. if (this.$container) {
  27348. destroy();
  27349. this.$container.remove();
  27350. }
  27351. });
  27352. it('should register custom editor', function () {
  27353. var MyEditor = function (_Handsontable$editors2) {
  27354. _inherits(MyEditor, _Handsontable$editors2);
  27355. function MyEditor() {
  27356. _classCallCheck(this, MyEditor);
  27357. return _possibleConstructorReturn(this, (MyEditor.__proto__ || Object.getPrototypeOf(MyEditor)).apply(this, arguments));
  27358. }
  27359. _createClass(MyEditor, [{
  27360. key: 'init',
  27361. value: function init() {
  27362. this.TEXTAREA = document.createElement('TEXTAREA');
  27363. this.TEXTAREA_PARENT = document.createElement('DIV');
  27364. this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);
  27365. this.instance.rootElement.appendChild(this.TEXTAREA_PARENT);
  27366. }
  27367. }, {
  27368. key: 'getValue',
  27369. value: function getValue() {
  27370. return '--' + this.TEXTAREA.value + '--';
  27371. }
  27372. }, {
  27373. key: 'setValue',
  27374. value: function setValue(value) {
  27375. this.TEXTAREA.value = value;
  27376. }
  27377. }, {
  27378. key: 'open',
  27379. value: function open() {}
  27380. }, {
  27381. key: 'close',
  27382. value: function close() {}
  27383. }, {
  27384. key: 'focus',
  27385. value: function focus() {
  27386. this.TEXTAREA.focus();
  27387. }
  27388. }]);
  27389. return MyEditor;
  27390. }(Handsontable.editors.BaseEditor);
  27391. registerEditor('myEditor', MyEditor);
  27392. var hot = handsontable({
  27393. data: [[1, 6, 10]],
  27394. columns: [{
  27395. editor: 'myEditor'
  27396. }]
  27397. });
  27398. selectCell(0, 0);
  27399. keyDown('enter');
  27400. document.activeElement.value = 'hello';
  27401. destroyEditor();
  27402. expect(getDataAtCell(0, 0)).toBe('--hello--');
  27403. });
  27404. it('should retrieve predefined editors by its names', function () {
  27405. expect(getEditor('autocomplete')).toBeFunction();
  27406. expect(getEditor('base')).toBeFunction();
  27407. expect(getEditor('checkbox')).toBeFunction();
  27408. expect(getEditor('date')).toBeFunction();
  27409. expect(getEditor('dropdown')).toBeFunction();
  27410. expect(getEditor('handsontable')).toBeFunction();
  27411. expect(getEditor('mobile')).toBeFunction();
  27412. expect(getEditor('numeric')).toBeFunction();
  27413. expect(getEditor('password')).toBeFunction();
  27414. expect(getEditor('select')).toBeFunction();
  27415. expect(getEditor('text')).toBeFunction();
  27416. });
  27417. it('should retrieve custom editor by its names', function () {
  27418. var MyEditor = function MyEditor() {
  27419. _classCallCheck(this, MyEditor);
  27420. };
  27421. registerEditor('myEditor', MyEditor);
  27422. expect(getEditor('myEditor')).toBe(MyEditor);
  27423. });
  27424. });
  27425. /***/ }),
  27426. /* 211 */
  27427. /***/ (function(module, exports, __webpack_require__) {
  27428. "use strict";
  27429. describe('noEditor', function () {
  27430. var id = 'testContainer';
  27431. beforeEach(function () {
  27432. this.$container = $('<div id="' + id + '" style="width: 300px; height: 200px; overflow: auto"></div>').appendTo('body');
  27433. });
  27434. afterEach(function () {
  27435. if (this.$container) {
  27436. destroy();
  27437. this.$container.remove();
  27438. }
  27439. });
  27440. it('shouldn\'t begin editing when enterBeginsEditing equals true', function () {
  27441. var selection;
  27442. handsontable({
  27443. enterBeginsEditing: true,
  27444. editor: false
  27445. });
  27446. selectCell(2, 2);
  27447. keyDown('enter');
  27448. selection = getSelected();
  27449. expect(selection).toEqual([2, 2, 2, 2]);
  27450. expect(isEditorVisible()).toEqual(false);
  27451. });
  27452. it('shouldn\'t move down after editing', function () {
  27453. var selection;
  27454. handsontable({
  27455. editor: false
  27456. });
  27457. selectCell(2, 2);
  27458. keyDown('enter');
  27459. keyDown('enter');
  27460. selection = getSelected();
  27461. expect(selection).toEqual([2, 2, 2, 2]);
  27462. });
  27463. it('shouldn\'t move down when enterBeginsEditing equals false', function () {
  27464. var selection;
  27465. handsontable({
  27466. enterBeginsEditing: false,
  27467. editor: false
  27468. });
  27469. selectCell(2, 2);
  27470. keyDown('enter');
  27471. selection = getSelected();
  27472. expect(selection).toEqual([3, 2, 3, 2]);
  27473. expect(isEditorVisible()).toEqual(false);
  27474. });
  27475. it('shouldn\'t render any value in editor', function () {
  27476. handsontable({
  27477. editor: false
  27478. });
  27479. setDataAtCell(2, 2, 'string');
  27480. selectCell(2, 2);
  27481. keyDown('enter');
  27482. expect(keyProxy().length).toEqual(0);
  27483. });
  27484. it('shouldn\'t open editor after hitting F2', function () {
  27485. handsontable({
  27486. editor: false
  27487. });
  27488. selectCell(2, 2);
  27489. expect(isEditorVisible()).toEqual(false);
  27490. keyDown('f2');
  27491. expect(isEditorVisible()).toEqual(false);
  27492. });
  27493. it('shouldn\'t open editor after hitting CapsLock', function () {
  27494. handsontable({
  27495. editor: false
  27496. });
  27497. selectCell(2, 2);
  27498. expect(isEditorVisible()).toEqual(false);
  27499. keyDown(Handsontable.helper.KEY_CODES.CAPS_LOCK);
  27500. expect(isEditorVisible()).toEqual(false);
  27501. });
  27502. it('shouldn\'t open editor after double clicking on a cell', function (done) {
  27503. var hot = handsontable({
  27504. data: Handsontable.helper.createSpreadsheetData(5, 2),
  27505. editor: false
  27506. });
  27507. var cell = $(getCell(0, 0));
  27508. var clicks = 0;
  27509. window.scrollTo(0, cell.offset().top);
  27510. setTimeout(function () {
  27511. mouseDown(cell);
  27512. mouseUp(cell);
  27513. clicks++;
  27514. }, 0);
  27515. setTimeout(function () {
  27516. mouseDown(cell);
  27517. mouseUp(cell);
  27518. clicks++;
  27519. }, 100);
  27520. setTimeout(function () {
  27521. expect(clicks).toBe(2);
  27522. expect(hot.getActiveEditor()).toBe(undefined);
  27523. expect(isEditorVisible()).toBe(false);
  27524. done();
  27525. }, 200);
  27526. });
  27527. it('should not open editor after pressing a printable character', function () {
  27528. handsontable({
  27529. data: Handsontable.helper.createSpreadsheetData(3, 3),
  27530. editor: false
  27531. });
  27532. selectCell(0, 0);
  27533. expect(isEditorVisible()).toBe(false);
  27534. this.$container.simulate('keydown', { keyCode: 'a'.charCodeAt(0) });
  27535. expect(isEditorVisible()).toBe(false);
  27536. });
  27537. it('should not open editor after pressing a printable character with shift key', function () {
  27538. handsontable({
  27539. data: Handsontable.helper.createSpreadsheetData(3, 3),
  27540. editor: false
  27541. });
  27542. selectCell(0, 0);
  27543. expect(isEditorVisible()).toBe(false);
  27544. this.$container.simulate('keydown', { keyCode: 'a'.charCodeAt(0), shiftKey: true });
  27545. expect(isEditorVisible()).toBe(false);
  27546. });
  27547. it('should not not open editor after hitting ALT', function () {
  27548. handsontable({
  27549. data: Handsontable.helper.createSpreadsheetData(4, 4),
  27550. editor: false
  27551. });
  27552. expect(getDataAtCell(0, 0)).toEqual('A1');
  27553. selectCell(0, 0);
  27554. keyDown(Handsontable.helper.KEY_CODES.ALT);
  27555. expect(isEditorVisible()).toBe(false);
  27556. });
  27557. });
  27558. /***/ }),
  27559. /* 212 */
  27560. /***/ (function(module, exports, __webpack_require__) {
  27561. "use strict";
  27562. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  27563. describe('NumericEditor', function () {
  27564. var id = 'testContainer';
  27565. beforeEach(function () {
  27566. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  27567. });
  27568. afterEach(function () {
  27569. if (this.$container) {
  27570. destroy();
  27571. this.$container.remove();
  27572. }
  27573. });
  27574. var arrayOfObjects = function arrayOfObjects() {
  27575. return [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }, { id: 6, name: 'Chuck', lastName: 'Jackson' }, { id: 7, name: 'Meg', lastName: 'Jansen' }, { id: 8, name: 'Rob', lastName: 'Norris' }, { id: 9, name: 'Sean', lastName: 'O\'Hara' }, { id: 10, name: 'Eve', lastName: 'Branson' }];
  27576. };
  27577. it('should convert numeric value to number (object data source)', function (done) {
  27578. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27579. handsontable({
  27580. data: arrayOfObjects(),
  27581. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  27582. afterValidate: onAfterValidate
  27583. });
  27584. selectCell(2, 0);
  27585. keyDown('enter');
  27586. document.activeElement.value = '999';
  27587. destroyEditor();
  27588. setTimeout(function () {
  27589. expect(_typeof(getDataAtCell(2, 0))).toEqual('number');
  27590. expect(getDataAtCell(2, 0)).toEqual(999);
  27591. done();
  27592. }, 100);
  27593. });
  27594. it('should apply changes to editor after validation', function (done) {
  27595. handsontable({
  27596. data: arrayOfObjects(),
  27597. columns: [{ data: 'id', type: 'numeric' }]
  27598. });
  27599. selectCell(0, 0);
  27600. keyDown('delete');
  27601. setTimeout(function () {
  27602. expect(getActiveEditor().originalValue).toEqual('');
  27603. done();
  27604. }, 100);
  27605. });
  27606. it('should allow custom validator', function (done) {
  27607. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27608. handsontable({
  27609. data: arrayOfObjects(),
  27610. allowInvalid: false,
  27611. columns: [{
  27612. data: 'id',
  27613. type: 'numeric',
  27614. validator: function validator(val, cb) {
  27615. cb(parseInt(val, 10) > 100);
  27616. }
  27617. }, { data: 'name' }, { data: 'lastName' }],
  27618. afterValidate: onAfterValidate
  27619. });
  27620. selectCell(2, 0);
  27621. keyDown('enter');
  27622. document.activeElement.value = '99';
  27623. destroyEditor();
  27624. setTimeout(function () {
  27625. expect(getDataAtCell(2, 0)).not.toEqual(99); // should be ignored
  27626. document.activeElement.value = '999';
  27627. onAfterValidate.calls.reset();
  27628. destroyEditor();
  27629. }, 100);
  27630. setTimeout(function () {
  27631. expect(getDataAtCell(2, 0)).toEqual(999);
  27632. done();
  27633. }, 200);
  27634. });
  27635. it('should convert string in format \'XX.XX\' to a float with the same value', function (done) {
  27636. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27637. handsontable({
  27638. data: arrayOfObjects(),
  27639. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  27640. afterValidate: onAfterValidate
  27641. });
  27642. selectCell(2, 0);
  27643. keyDown('enter');
  27644. document.activeElement.value = '99.99';
  27645. onAfterValidate.calls.reset();
  27646. destroyEditor();
  27647. setTimeout(function () {
  27648. expect(getDataAtCell(2, 0)).toEqual(parseFloat(99.99));
  27649. done();
  27650. }, 100);
  27651. });
  27652. it('should convert string in format \'XX.XX\' to a float when passing float without leading zero', function (done) {
  27653. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27654. handsontable({
  27655. data: arrayOfObjects(),
  27656. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  27657. afterValidate: onAfterValidate
  27658. });
  27659. selectCell(2, 0);
  27660. keyDown('enter');
  27661. document.activeElement.value = '.74';
  27662. onAfterValidate.calls.reset();
  27663. destroyEditor();
  27664. setTimeout(function () {
  27665. expect(getDataAtCell(2, 0)).toEqual(parseFloat(0.74));
  27666. done();
  27667. }, 100);
  27668. });
  27669. it('should convert string in format \'XX,XX\' (with comma as separator) to a float with the same value if the numeric locale ' + 'specifies comma as the precision delimiter (language=de)', function (done) {
  27670. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27671. handsontable({
  27672. data: arrayOfObjects(),
  27673. columns: [{ data: 'id', type: 'numeric', language: 'de-DE' }, { data: 'name' }, { data: 'lastName' }],
  27674. afterValidate: onAfterValidate
  27675. });
  27676. selectCell(2, 0);
  27677. keyDown('enter');
  27678. document.activeElement.value = '99,99';
  27679. onAfterValidate.calls.reset();
  27680. destroyEditor();
  27681. setTimeout(function () {
  27682. expect(getDataAtCell(2, 0)).toEqual(parseFloat(99.99));
  27683. done();
  27684. }, 100);
  27685. });
  27686. it('should display a string in a format \'$X,XXX.XX\' when using language=en, appropriate format in column settings and \'XXXX.XX\' as ' + 'an input string', function (done) {
  27687. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27688. handsontable({
  27689. data: arrayOfObjects(),
  27690. columns: [{ data: 'id', type: 'numeric', format: '$0,0.00', language: 'en-US' }, { data: 'name' }, { data: 'lastName' }],
  27691. afterValidate: onAfterValidate
  27692. });
  27693. selectCell(2, 0);
  27694. keyDown('enter');
  27695. document.activeElement.value = '2456.22';
  27696. onAfterValidate.calls.reset();
  27697. destroyEditor();
  27698. setTimeout(function () {
  27699. expect(getCell(2, 0).innerHTML).toEqual('$2,456.22');
  27700. done();
  27701. }, 100);
  27702. });
  27703. it('should display a string in a format \'X.XXX,XX €\' when using language=de, appropriate format in column settings and \'XXXX,XX\' as an ' + 'input string (that comes from manual input)', function (done) {
  27704. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27705. handsontable({
  27706. data: arrayOfObjects(),
  27707. columns: [{ data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE' }, { data: 'name' }, { data: 'lastName' }],
  27708. afterValidate: onAfterValidate
  27709. });
  27710. selectCell(2, 0);
  27711. keyDown('enter');
  27712. document.activeElement.value = '2456,22';
  27713. onAfterValidate.calls.reset();
  27714. destroyEditor();
  27715. setTimeout(function () {
  27716. expect(getCell(2, 0).innerHTML).toEqual('2.456,22 €');
  27717. done();
  27718. }, 100);
  27719. });
  27720. it('should display a string in a format \'X.XXX,XX €\' when using language=de, appropriate format in column settings and \'XXXX.XX\' as an ' + 'input string (that comes from paste)', function (done) {
  27721. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27722. handsontable({
  27723. data: arrayOfObjects(),
  27724. columns: [{ data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE' }, { data: 'name' }, { data: 'lastName' }],
  27725. afterValidate: onAfterValidate
  27726. });
  27727. selectCell(2, 0);
  27728. keyDown('enter');
  27729. document.activeElement.value = '2456.22';
  27730. onAfterValidate.calls.reset();
  27731. destroyEditor();
  27732. setTimeout(function () {
  27733. expect(getCell(2, 0).innerHTML).toEqual('2.456,22 €');
  27734. done();
  27735. }, 100);
  27736. });
  27737. it('should not validate input values in different formats than \'XX.XX\' and \'XX,XX\'', function (done) {
  27738. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27739. handsontable({
  27740. data: arrayOfObjects(),
  27741. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  27742. afterValidate: onAfterValidate
  27743. });
  27744. selectCell(2, 0);
  27745. function manuallySetValueTo(val) {
  27746. keyDown('enter');
  27747. document.activeElement.value = val;
  27748. onAfterValidate.calls.reset();
  27749. destroyEditor();
  27750. }
  27751. manuallySetValueTo('22.22');
  27752. setTimeout(function () {
  27753. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(false); // should validate alright
  27754. manuallySetValueTo('2,000,000.22');
  27755. }, 100);
  27756. setTimeout(function () {
  27757. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(true);
  27758. manuallySetValueTo('11,11');
  27759. }, 200);
  27760. setTimeout(function () {
  27761. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(false); // should validate alright
  27762. manuallySetValueTo('one thounsand');
  27763. }, 300);
  27764. setTimeout(function () {
  27765. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(true);
  27766. manuallySetValueTo('99d99');
  27767. }, 400);
  27768. setTimeout(function () {
  27769. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(true);
  27770. done();
  27771. }, 500);
  27772. });
  27773. it('should paste formatted data if source cell has format', function (done) {
  27774. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27775. handsontable({
  27776. data: arrayOfObjects(),
  27777. columns: [{ data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE' }, { data: 'name' }, { data: 'lastName' }],
  27778. afterValidate: onAfterValidate
  27779. });
  27780. selectCell(2, 0);
  27781. keyDown('enter');
  27782. document.activeElement.value = '€123,00';
  27783. onAfterValidate.calls.reset();
  27784. destroyEditor();
  27785. setTimeout(function () {
  27786. expect(getCell(2, 0).innerHTML).toEqual('123,00 €');
  27787. done();
  27788. }, 100);
  27789. });
  27790. it('should display a string in a format \'X XXX,XX €\' when using language=de, appropriate format in column settings and \'XXXX,XX\' as an ' + 'input string and ignore not needed zeros at the end', function (done) {
  27791. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  27792. handsontable({
  27793. data: [{ id: 1, name: 'Ted', lastName: 'Right', money: 0 }, { id: 2, name: 'Frank', lastName: 'Honest', money: 0 }, { id: 3, name: 'Joan', lastName: 'Well', money: 0 }, { id: 4, name: 'Sid', lastName: 'Strong', money: 0 }, { id: 5, name: 'Jane', lastName: 'Neat', money: 0 }, { id: 6, name: 'Chuck', lastName: 'Jackson', money: 0 }, { id: 7, name: 'Meg', lastName: 'Jansen', money: 0 }, { id: 8, name: 'Rob', lastName: 'Norris', money: 0 }, { id: 9, name: 'Sean', lastName: 'O\'Hara', money: 0 }, { id: 10, name: 'Eve', lastName: 'Branson', money: 0 }],
  27794. columns: [{ data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE' }, { data: 'name' }, { data: 'lastName' }, { data: 'money', type: 'numeric', format: '$0,0.00', language: 'en-US' }],
  27795. afterValidate: onAfterValidate
  27796. });
  27797. selectCell(2, 0);
  27798. function manuallySetValueTo(val) {
  27799. keyDown('enter');
  27800. document.activeElement.value = val;
  27801. onAfterValidate.calls.reset();
  27802. destroyEditor();
  27803. }
  27804. manuallySetValueTo('2456,220');
  27805. setTimeout(function () {
  27806. expect(getCell(2, 0).innerHTML).toEqual('2.456,22 €');
  27807. deselectCell();
  27808. selectCell(2, 3);
  27809. manuallySetValueTo('2456.220');
  27810. }, 100);
  27811. setTimeout(function () {
  27812. expect(getCell(2, 3).innerHTML).toEqual('$2,456.22');
  27813. done();
  27814. }, 200);
  27815. });
  27816. it('should mark text as invalid without removing', function (done) {
  27817. var hot = handsontable({
  27818. data: arrayOfObjects(),
  27819. columns: [{ data: 'id', type: 'numeric', format: '0,0.00' }, { data: 'name' }, { data: 'lastName' }]
  27820. });
  27821. hot.setDataAtCell(0, 0, 'abc');
  27822. setTimeout(function () {
  27823. expect(hot.getDataAtCell(0, 0)).toEqual('abc');
  27824. done();
  27825. }, 200);
  27826. });
  27827. it('should not throw error on closing editor when column data is defined as \'length\'', function () {
  27828. hot = handsontable({
  27829. data: [{ length: 4 }, { length: 5 }],
  27830. columns: [{
  27831. data: 'length', type: 'numeric'
  27832. }, {}, {}]
  27833. });
  27834. selectCell(1, 0);
  27835. keyDown('enter');
  27836. document.activeElement.value = '999';
  27837. expect(function () {
  27838. destroyEditor();
  27839. }).not.toThrow();
  27840. });
  27841. describe('Cell corner is showed properly when changing focused cells #3877', function () {
  27842. var isFocusedCellDisplayingCornerTest = function isFocusedCellDisplayingCornerTest(settings) {
  27843. var moveFromRow = settings.moveFromRow;
  27844. var moveFromCol = settings.moveFromCol;
  27845. var moveToRow = settings.moveToRow;
  27846. var moveToCol = settings.moveToCol;
  27847. var doneFunc = settings.doneFunc;
  27848. var $corner = settings.$container.find('.wtBorder.current.corner');
  27849. selectCell(moveFromRow, moveFromCol);
  27850. keyDown('enter');
  27851. selectCell(moveToRow, moveToCol);
  27852. setTimeout(function () {
  27853. expect($corner.css('display')).toEqual('block');
  27854. doneFunc();
  27855. }, 100);
  27856. };
  27857. it('Moving from numeric editor to text editor', function (done) {
  27858. handsontable({
  27859. data: [{ id: 1, name: 'Ted', lastName: 'Right', money: 0 }],
  27860. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }, { data: 'money', type: 'numeric', format: '$0,0.00', language: 'en-US' }]
  27861. });
  27862. isFocusedCellDisplayingCornerTest({
  27863. moveFromRow: 0,
  27864. moveFromCol: 3,
  27865. moveToRow: 0,
  27866. moveToCol: 0,
  27867. $container: this.$container,
  27868. doneFunc: done
  27869. });
  27870. });
  27871. it('Moving from text editor to numeric editor', function (done) {
  27872. handsontable({
  27873. data: [{ id: 1, name: 'Ted', lastName: 'Right', money: 0 }],
  27874. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }, { data: 'money', type: 'numeric', format: '$0,0.00', language: 'en-US' }]
  27875. });
  27876. isFocusedCellDisplayingCornerTest({
  27877. moveFromRow: 0,
  27878. moveFromCol: 1,
  27879. moveToRow: 0,
  27880. moveToCol: 3,
  27881. $container: this.$container,
  27882. doneFunc: done
  27883. });
  27884. });
  27885. });
  27886. });
  27887. /***/ }),
  27888. /* 213 */
  27889. /***/ (function(module, exports, __webpack_require__) {
  27890. "use strict";
  27891. describe('PasswordEditor', function () {
  27892. var id = 'testContainer';
  27893. beforeEach(function () {
  27894. this.$container = $('<div id="' + id + '" style="width: 300px; height: 300px;"></div>').appendTo('body');
  27895. });
  27896. afterEach(function () {
  27897. if (this.$container) {
  27898. destroy();
  27899. this.$container.remove();
  27900. }
  27901. });
  27902. it('should display editor as password field', function () {
  27903. handsontable({
  27904. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  27905. columns: [{
  27906. editor: Handsontable.editors.PasswordEditor
  27907. }]
  27908. });
  27909. selectCell(0, 0);
  27910. keyDown('enter');
  27911. var editor = $('.handsontableInput');
  27912. expect(editor.is(':visible')).toBe(true);
  27913. expect(editor.is(':password')).toBe(true);
  27914. });
  27915. it('should set passwordEditor using \'password\' alias', function () {
  27916. handsontable({
  27917. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  27918. columns: [{
  27919. editor: 'password'
  27920. }]
  27921. });
  27922. selectCell(0, 0);
  27923. keyDown('enter');
  27924. var editor = $('.handsontableInput');
  27925. expect(editor.is(':visible')).toBe(true);
  27926. expect(editor.is(':password')).toBe(true);
  27927. });
  27928. it('should set passwordEditor using column type \'password\' ', function () {
  27929. handsontable({
  27930. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  27931. columns: [{
  27932. type: 'password'
  27933. }]
  27934. });
  27935. selectCell(0, 0);
  27936. keyDown('enter');
  27937. var editorHolder = $('.handsontableInputHolder');
  27938. var editor = editorHolder.find('.handsontableInput');
  27939. expect(editorHolder.is(':visible')).toBe(true);
  27940. expect(editor.is(':password')).toBe(true);
  27941. });
  27942. it('should save values typed in passwordEditor', function () {
  27943. handsontable({
  27944. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  27945. columns: [{
  27946. editor: 'password'
  27947. }]
  27948. });
  27949. selectCell(0, 0);
  27950. expect(getDataAtCell(0, 0)).toMatch('Joe');
  27951. expect(getRenderedValue(0, 0)).toMatch('Joe');
  27952. keyDown('enter');
  27953. var editorHolder = $('.handsontableInputHolder');
  27954. var editor = editorHolder.find('.handsontableInput');
  27955. expect(editorHolder.is(':visible')).toBe(true);
  27956. editor.val('Edgar');
  27957. selectCell(1, 0); // closes editor and saves current value
  27958. expect(editorHolder.is(':visible')).toBe(false);
  27959. expect(getDataAtCell(0, 0)).toMatch('Edgar');
  27960. expect(getRenderedValue(0, 0)).toMatch('Edgar');
  27961. });
  27962. });
  27963. /***/ }),
  27964. /* 214 */
  27965. /***/ (function(module, exports, __webpack_require__) {
  27966. "use strict";
  27967. describe('SelectEditor', function () {
  27968. var id = 'testContainer';
  27969. beforeEach(function () {
  27970. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  27971. });
  27972. afterEach(function () {
  27973. if (this.$container) {
  27974. destroy();
  27975. this.$container.remove();
  27976. }
  27977. });
  27978. it('should display select', function () {
  27979. handsontable({
  27980. columns: [{
  27981. editor: 'select'
  27982. }]
  27983. });
  27984. selectCell(0, 0);
  27985. var editor = $('.htSelectEditor');
  27986. expect(editor.length).toEqual(1);
  27987. expect(editor.is('select')).toBe(true);
  27988. expect(editor.is(':visible')).toBe(false);
  27989. keyDown('enter');
  27990. expect(editor.is(':visible')).toBe(true);
  27991. expect(editor.offset()).toEqual($(getCell(0, 0)).offset());
  27992. });
  27993. it('should display and correctly reposition select editor while scrolling', function (done) {
  27994. var hot = handsontable({
  27995. width: 200,
  27996. height: 200,
  27997. data: Handsontable.helper.createSpreadsheetData(100, 100),
  27998. columns: [{
  27999. editor: 'select'
  28000. }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { editor: 'select' }]
  28001. });
  28002. var mainHolder = hot.view.wt.wtTable.holder;
  28003. selectCell(0, 0);
  28004. keyDown('enter');
  28005. keyUp('enter');
  28006. mainHolder.scrollTop = 10;
  28007. mainHolder.scrollLeft = 20;
  28008. var editor = $('.htSelectEditor');
  28009. setTimeout(function () {
  28010. expect(editor.css('top')).toEqual('-10px');
  28011. expect(editor.css('left')).toEqual('-20px');
  28012. done();
  28013. }, 200);
  28014. });
  28015. it('should populate select with given options (array)', function () {
  28016. var options = ['Misubishi', 'Chevrolet', 'Lamborgini'];
  28017. handsontable({
  28018. columns: [{
  28019. editor: 'select',
  28020. selectOptions: options
  28021. }]
  28022. });
  28023. selectCell(0, 0);
  28024. var editor = $('.htSelectEditor');
  28025. keyDown('enter');
  28026. var $options = editor.find('option');
  28027. expect($options.length).toEqual(options.length);
  28028. expect($options.eq(0).val()).toMatch(options[0]);
  28029. expect($options.eq(0).html()).toMatch(options[0]);
  28030. expect($options.eq(1).val()).toMatch(options[1]);
  28031. expect($options.eq(1).html()).toMatch(options[1]);
  28032. expect($options.eq(2).val()).toMatch(options[2]);
  28033. expect($options.eq(2).html()).toMatch(options[2]);
  28034. });
  28035. it('should populate select with given options (object)', function () {
  28036. var options = {
  28037. mit: 'Misubishi',
  28038. che: 'Chevrolet',
  28039. lam: 'Lamborgini'
  28040. };
  28041. handsontable({
  28042. columns: [{
  28043. editor: 'select',
  28044. selectOptions: options
  28045. }]
  28046. });
  28047. selectCell(0, 0);
  28048. var editor = $('.htSelectEditor');
  28049. keyDown('enter');
  28050. var $options = editor.find('option');
  28051. expect($options.eq(0).val()).toMatch('mit');
  28052. expect($options.eq(0).html()).toMatch(options.mit);
  28053. expect($options.eq(1).val()).toMatch('che');
  28054. expect($options.eq(1).html()).toMatch(options.che);
  28055. expect($options.eq(2).val()).toMatch('lam');
  28056. expect($options.eq(2).html()).toMatch(options.lam);
  28057. });
  28058. it('should populate select with given options (function:array)', function () {
  28059. var options = function options() {
  28060. return ['Misubishi', 'Chevrolet', 'Lamborgini'];
  28061. };
  28062. handsontable({
  28063. columns: [{
  28064. editor: 'select',
  28065. selectOptions: options
  28066. }]
  28067. });
  28068. selectCell(0, 0);
  28069. var editor = $('.htSelectEditor');
  28070. keyDown('enter');
  28071. var $options = editor.find('option');
  28072. expect($options.length).toEqual(options().length);
  28073. expect($options.eq(0).val()).toMatch(options()[0]);
  28074. expect($options.eq(0).html()).toMatch(options()[0]);
  28075. expect($options.eq(1).val()).toMatch(options()[1]);
  28076. expect($options.eq(1).html()).toMatch(options()[1]);
  28077. expect($options.eq(2).val()).toMatch(options()[2]);
  28078. expect($options.eq(2).html()).toMatch(options()[2]);
  28079. });
  28080. it('should populate select with given options (function:object)', function () {
  28081. var options = function options() {
  28082. return {
  28083. mit: 'Misubishi',
  28084. che: 'Chevrolet',
  28085. lam: 'Lamborgini'
  28086. };
  28087. };
  28088. handsontable({
  28089. columns: [{
  28090. editor: 'select',
  28091. selectOptions: options
  28092. }]
  28093. });
  28094. selectCell(0, 0);
  28095. var editor = $('.htSelectEditor');
  28096. keyDown('enter');
  28097. var $options = editor.find('option');
  28098. expect($options.eq(0).val()).toMatch('mit');
  28099. expect($options.eq(0).html()).toMatch(options().mit);
  28100. expect($options.eq(1).val()).toMatch('che');
  28101. expect($options.eq(1).html()).toMatch(options().che);
  28102. expect($options.eq(2).val()).toMatch('lam');
  28103. expect($options.eq(2).html()).toMatch(options().lam);
  28104. });
  28105. it('should mark option matching cell value as selected', function () {
  28106. var options = ['Misubishi', 'Chevrolet', 'Lamborgini'];
  28107. handsontable({
  28108. data: [['Misubishi'], ['Lamborgini'], ['Chevrolet']],
  28109. columns: [{
  28110. editor: 'select',
  28111. selectOptions: options
  28112. }]
  28113. });
  28114. selectCell(0, 0);
  28115. var editor = $('.htSelectEditor');
  28116. keyDown('enter');
  28117. expect(editor.find('option:selected').text()).toEqual(getDataAtCell(0, 0));
  28118. keyDown('enter');
  28119. selectCell(1, 0);
  28120. keyDown('enter');
  28121. expect(editor.find('option:selected').text()).toEqual(getDataAtCell(1, 0));
  28122. keyDown('enter');
  28123. selectCell(2, 0);
  28124. keyDown('enter');
  28125. expect(editor.find('option:selected').text()).toEqual(getDataAtCell(2, 0));
  28126. keyDown('enter');
  28127. });
  28128. it('should not prevent the default event action when select is clicked', function () {
  28129. var options = function options() {
  28130. return ['Misubishi', 'Chevrolet', 'Lamborgini'];
  28131. };
  28132. handsontable({
  28133. columns: [{
  28134. editor: 'select',
  28135. selectOptions: options
  28136. }]
  28137. });
  28138. selectCell(0, 0);
  28139. var editor = $('.htSelectEditor');
  28140. keyDown('enter');
  28141. var select = editor.find('select');
  28142. var selectMouseDownListener = jasmine.createSpy('selectMouseDownListener');
  28143. $('body').on('mousedown', selectMouseDownListener);
  28144. editor.mousedown();
  28145. expect(selectMouseDownListener.calls.count()).toEqual(1);
  28146. var event = selectMouseDownListener.calls.argsFor(0)[0];
  28147. expect(event).toBeDefined();
  28148. expect(event.isDefaultPrevented()).toBe(false);
  28149. });
  28150. });
  28151. /***/ }),
  28152. /* 215 */
  28153. /***/ (function(module, exports, __webpack_require__) {
  28154. "use strict";
  28155. describe('TextEditor', function () {
  28156. var id = 'testContainer';
  28157. beforeEach(function () {
  28158. this.$container = $('<div id="' + id + '" style="width: 300px; height: 200px; overflow: hidden;"></div>').appendTo('body');
  28159. });
  28160. afterEach(function () {
  28161. if (this.$container) {
  28162. destroy();
  28163. this.$container.remove();
  28164. }
  28165. });
  28166. it('should begin editing when enterBeginsEditing equals true', function () {
  28167. handsontable({
  28168. enterBeginsEditing: true,
  28169. editor: 'text'
  28170. });
  28171. selectCell(2, 2);
  28172. keyDown('enter');
  28173. var selection = getSelected();
  28174. expect(selection).toEqual([2, 2, 2, 2]);
  28175. expect(isEditorVisible()).toEqual(true);
  28176. });
  28177. it('should move down after editing', function () {
  28178. handsontable({
  28179. editor: 'text'
  28180. });
  28181. selectCell(2, 2);
  28182. keyDown('enter');
  28183. keyDown('enter');
  28184. var selection = getSelected();
  28185. expect(selection).toEqual([3, 2, 3, 2]);
  28186. });
  28187. it('should move down when enterBeginsEditing equals false', function () {
  28188. handsontable({
  28189. enterBeginsEditing: false
  28190. });
  28191. selectCell(2, 2);
  28192. keyDown('enter');
  28193. var selection = getSelected();
  28194. expect(selection).toEqual([3, 2, 3, 2]);
  28195. expect(isEditorVisible()).toEqual(false);
  28196. });
  28197. it('should render string in textarea', function () {
  28198. handsontable();
  28199. setDataAtCell(2, 2, 'string');
  28200. selectCell(2, 2);
  28201. keyDown('enter');
  28202. expect(keyProxy().val()).toEqual('string');
  28203. });
  28204. it('should render textarea editor in specified size at cell 0, 0 without headers', function (done) {
  28205. var hot = handsontable();
  28206. selectCell(0, 0);
  28207. keyDown('enter');
  28208. setTimeout(function () {
  28209. expect(hot.getActiveEditor().TEXTAREA.style.height).toBe('23px');
  28210. expect(hot.getActiveEditor().TEXTAREA.style.width).toBe('40px');
  28211. done();
  28212. }, 200);
  28213. });
  28214. it('should render textarea editor in specified size at cell 1, 0 without headers', function (done) {
  28215. var hot = handsontable();
  28216. selectCell(1, 1);
  28217. keyDown('enter');
  28218. setTimeout(function () {
  28219. expect(hot.getActiveEditor().TEXTAREA.style.height).toBe('23px');
  28220. done();
  28221. }, 200);
  28222. });
  28223. it('should render textarea editor in specified size at cell 0, 0 with headers', function (done) {
  28224. var hot = handsontable({
  28225. rowHeaders: true,
  28226. colHeaders: true
  28227. });
  28228. selectCell(0, 0);
  28229. keyDown('enter');
  28230. setTimeout(function () {
  28231. expect(hot.getActiveEditor().TEXTAREA.style.height).toBe('23px');
  28232. expect(hot.getActiveEditor().TEXTAREA.style.width).toBe('40px');
  28233. expect(hot.getActiveEditor().textareaParentStyle.top).toBe('26px');
  28234. done();
  28235. }, 200);
  28236. });
  28237. it('should render textarea editor in specified size at cell 0, 0 with headers defined in columns', function (done) {
  28238. var hot = handsontable({
  28239. data: Handsontable.helper.createSpreadsheetObjectData(10, 10),
  28240. columns: [{
  28241. data: 'prop0',
  28242. title: 'Prop 0'
  28243. }, {
  28244. data: 'prop1',
  28245. title: 'Prop 1'
  28246. }, {
  28247. data: 'prop2',
  28248. title: 'Prop 2'
  28249. }, {
  28250. data: 'prop3',
  28251. title: 'Prop 3'
  28252. }]
  28253. });
  28254. selectCell(0, 0);
  28255. keyDown('enter');
  28256. setTimeout(function () {
  28257. expect(hot.getActiveEditor().TEXTAREA.style.height).toBe('23px');
  28258. expect(parseInt(hot.getActiveEditor().TEXTAREA.style.width, 10)).toBeAroundValue(50, 4);
  28259. expect(hot.getActiveEditor().textareaParentStyle.top).toBe('26px');
  28260. done();
  28261. }, 200);
  28262. });
  28263. it('should hide whole editor when it is higher then header', function (done) {
  28264. var hot = handsontable({
  28265. data: Handsontable.helper.createSpreadsheetData(50, 50),
  28266. rowHeaders: true,
  28267. colHeaders: true
  28268. });
  28269. setDataAtCell(2, 2, 'string\nstring\nstring');
  28270. selectCell(2, 2);
  28271. keyDown('enter');
  28272. keyUp('enter');
  28273. var mainHolder = hot.view.wt.wtTable.holder;
  28274. mainHolder.scrollTop = 150;
  28275. mainHolder.scrollLeft = 150;
  28276. setTimeout(function () {
  28277. expect(parseInt(hot.getActiveEditor().textareaParentStyle.top, 10)).toBeAroundValue(-77);
  28278. expect(parseInt(hot.getActiveEditor().textareaParentStyle.left, 10)).toBeAroundValue(-1);
  28279. done();
  28280. }, 200);
  28281. });
  28282. it('should hide editor when quick navigation by click scrollbar was triggered', function (done) {
  28283. var hot = handsontable({
  28284. data: Handsontable.helper.createSpreadsheetData(50, 50),
  28285. rowHeaders: true,
  28286. colHeaders: true
  28287. });
  28288. setDataAtCell(2, 2, 'string\nstring\nstring');
  28289. selectCell(2, 2);
  28290. keyDown('enter');
  28291. keyUp('enter');
  28292. hot.scrollViewportTo(49);
  28293. setTimeout(function () {
  28294. expect(hot.getActiveEditor().textareaParentStyle.display).toBe('none');
  28295. done();
  28296. }, 100);
  28297. });
  28298. it('should render textarea editor in specified height (single line)', function (done) {
  28299. var hot = handsontable(),
  28300. editorHeight;
  28301. setDataAtCell(2, 2, 'first line');
  28302. selectCell(2, 2);
  28303. keyDown('enter');
  28304. setTimeout(function () {
  28305. expect(hot.getActiveEditor().TEXTAREA.style.height).toBe('23px');
  28306. done();
  28307. }, 200);
  28308. });
  28309. it('should render textarea editor in specified height (multi line)', function (done) {
  28310. var hot = handsontable(),
  28311. editorHeight;
  28312. setDataAtCell(2, 2, 'first line\n second line\n third line...');
  28313. selectCell(2, 2);
  28314. keyDown('enter');
  28315. setTimeout(function () {
  28316. expect(hot.getActiveEditor().TEXTAREA.style.height).toBe('64px');
  28317. done();
  28318. }, 200);
  28319. });
  28320. it('should render number in textarea', function () {
  28321. handsontable();
  28322. setDataAtCell(2, 2, 13);
  28323. selectCell(2, 2);
  28324. keyDown('enter');
  28325. expect(keyProxy().val()).toEqual('13');
  28326. });
  28327. it('should render boolean true in textarea', function () {
  28328. handsontable();
  28329. setDataAtCell(2, 2, true);
  28330. selectCell(2, 2);
  28331. keyDown('enter');
  28332. expect(keyProxy().val()).toEqual('true');
  28333. });
  28334. it('should render boolean false in textarea', function () {
  28335. handsontable();
  28336. setDataAtCell(2, 2, false);
  28337. selectCell(2, 2);
  28338. keyDown('enter');
  28339. expect(keyProxy().val()).toEqual('false');
  28340. });
  28341. it('should render null in textarea', function () {
  28342. handsontable();
  28343. setDataAtCell(2, 2, null);
  28344. selectCell(2, 2);
  28345. keyDown('enter');
  28346. expect(keyProxy().val()).toEqual('');
  28347. });
  28348. it('should render undefined in textarea', function () {
  28349. handsontable();
  28350. setDataAtCell(2, 2, void 0);
  28351. selectCell(2, 2);
  28352. keyDown('enter');
  28353. expect(keyProxy().val()).toEqual('');
  28354. });
  28355. it('should render nested object value in textarea', function () {
  28356. handsontable({
  28357. data: [{
  28358. name: {
  28359. first: 'Tom',
  28360. last: 'Kowalski',
  28361. obj: {}
  28362. }
  28363. }, {
  28364. name: {
  28365. first: 'John',
  28366. last: 'Cage',
  28367. obj: {
  28368. foo: 'bar'
  28369. }
  28370. }
  28371. }],
  28372. columns: [{
  28373. data: 'name.last'
  28374. }, {
  28375. data: 'name.obj.foo'
  28376. }]
  28377. });
  28378. selectCell(0, 0);
  28379. keyDown('enter');
  28380. expect(keyProxy().val()).toEqual('Kowalski');
  28381. selectCell(1, 1);
  28382. keyDown('enter');
  28383. expect(keyProxy().val()).toEqual('bar');
  28384. });
  28385. it('should render nested object value in textarea after change rows order', function () {
  28386. var hot = handsontable({
  28387. data: [{
  28388. name: {
  28389. first: 'Tom',
  28390. last: 'Kowalski',
  28391. obj: {}
  28392. }
  28393. }, {
  28394. name: {
  28395. first: 'John',
  28396. last: 'Cage',
  28397. obj: {
  28398. foo: 'bar'
  28399. }
  28400. }
  28401. }],
  28402. columns: [{
  28403. data: 'name.last'
  28404. }, {
  28405. data: 'name.obj.foo'
  28406. }],
  28407. manualRowMove: true
  28408. });
  28409. hot.getPlugin('manualRowMove').moveRow(1, 0);
  28410. hot.render();
  28411. selectCell(0, 0);
  28412. keyDown('enter');
  28413. expect(keyProxy().val()).toEqual('Cage');
  28414. keyDown('enter');
  28415. expect(hot.getDataAtCell(0, 0)).toEqual('Cage');
  28416. selectCell(1, 1);
  28417. keyDown('enter');
  28418. expect(keyProxy().val()).toEqual('');
  28419. keyDown('enter');
  28420. expect(hot.getDataAtCell(1, 1)).toEqual('');
  28421. });
  28422. it('should render nested object value in textarea after change columns order', function () {
  28423. var hot = handsontable({
  28424. data: [{
  28425. name: {
  28426. first: 'Tom',
  28427. last: 'Kowalski',
  28428. obj: {}
  28429. }
  28430. }, {
  28431. name: {
  28432. first: 'John',
  28433. last: 'Cage',
  28434. obj: {
  28435. foo: 'bar'
  28436. }
  28437. }
  28438. }],
  28439. columns: [{
  28440. data: 'name.last'
  28441. }, {
  28442. data: 'name.obj.foo'
  28443. }],
  28444. manualColumnMove: true
  28445. });
  28446. hot.getPlugin('manualColumnMove').moveColumn(1, 0);
  28447. hot.render();
  28448. selectCell(0, 0);
  28449. keyDown('enter');
  28450. expect(keyProxy().val()).toEqual('');
  28451. keyDown('enter');
  28452. expect(hot.getDataAtCell(0, 0)).toEqual('');
  28453. selectCell(1, 1);
  28454. keyDown('enter');
  28455. expect(keyProxy().val()).toEqual('Cage');
  28456. keyDown('enter');
  28457. expect(hot.getDataAtCell(1, 1)).toEqual('Cage');
  28458. });
  28459. it('should render array value defined by columns settings in textarea', function () {
  28460. handsontable({
  28461. data: [['', 'Kia'], ['2012', 10], ['2013', 10]],
  28462. columns: [{
  28463. data: '1'
  28464. }, {
  28465. data: '0'
  28466. }]
  28467. });
  28468. selectCell(0, 0);
  28469. keyDown('enter');
  28470. expect(keyProxy().val()).toEqual('Kia');
  28471. selectCell(1, 1);
  28472. keyDown('enter');
  28473. expect(keyProxy().val()).toEqual('2012');
  28474. });
  28475. it('should open editor after hitting F2', function () {
  28476. handsontable();
  28477. selectCell(2, 2);
  28478. var editor = $('.handsontableInput');
  28479. expect(isEditorVisible()).toEqual(false);
  28480. keyDown('f2');
  28481. expect(isEditorVisible()).toEqual(true);
  28482. });
  28483. it('should close editor after hitting ESC', function () {
  28484. handsontable();
  28485. selectCell(2, 2);
  28486. var editor = $('.handsontableInput');
  28487. expect(isEditorVisible()).toEqual(false);
  28488. keyDown('f2');
  28489. expect(isEditorVisible()).toEqual(true);
  28490. keyDown('esc');
  28491. expect(isEditorVisible()).toEqual(false);
  28492. });
  28493. it('should NOT open editor after hitting CapsLock', function () {
  28494. handsontable();
  28495. selectCell(2, 2);
  28496. var editor = $('.handsontableInput');
  28497. expect(isEditorVisible()).toEqual(false);
  28498. keyDown(Handsontable.helper.KEY_CODES.CAPS_LOCK);
  28499. expect(isEditorVisible()).toEqual(false);
  28500. });
  28501. it('should open editor after cancelling edit and beginning it again', function () {
  28502. handsontable();
  28503. selectCell(2, 2);
  28504. expect(isEditorVisible()).toEqual(false);
  28505. keyDown('f2');
  28506. expect(isEditorVisible()).toEqual(true);
  28507. keyDown('esc');
  28508. expect(isEditorVisible()).toEqual(false);
  28509. keyDown('f2');
  28510. expect(isEditorVisible()).toEqual(true);
  28511. });
  28512. it('loadData should not destroy editor', function () {
  28513. handsontable();
  28514. selectCell(2, 2);
  28515. keyDown('f2');
  28516. loadData(getData());
  28517. expect(isEditorVisible()).toEqual(true);
  28518. });
  28519. it('updateSettings should not destroy editor', function () {
  28520. handsontable();
  28521. selectCell(2, 2);
  28522. keyDown('f2');
  28523. updateSettings({
  28524. data: getData()
  28525. });
  28526. expect(isEditorVisible()).toEqual(true);
  28527. });
  28528. it('textarea should have cell dimensions (after render)', function () {
  28529. var data = [['a', 'b'], ['c', 'd']];
  28530. var hot = handsontable({
  28531. data: data,
  28532. minRows: 4,
  28533. minCols: 4,
  28534. minSpareRows: 4,
  28535. minSpareCols: 4,
  28536. enterMoves: false
  28537. });
  28538. selectCell(1, 1);
  28539. var $td = getHtCore().find('tbody tr:eq(1) td:eq(1)');
  28540. var editor = hot.getActiveEditor();
  28541. keyDownUp('enter');
  28542. expect(keyProxy().width()).toEqual($td.width());
  28543. keyDownUp('enter');
  28544. data[1][1] = 'dddddddddddddddddddd';
  28545. render();
  28546. keyDownUp('enter');
  28547. expect(keyProxy().width()).toEqual($td.width());
  28548. });
  28549. it('global shortcuts (like CTRL+A) should be blocked when cell is being edited', function () {
  28550. handsontable();
  28551. selectCell(2, 2);
  28552. keyDownUp('enter');
  28553. keyDown(65, {
  28554. ctrlKey: true
  28555. }); // CTRL+A should NOT select all table when cell is edited
  28556. var selection = getSelected();
  28557. expect(selection).toEqual([2, 2, 2, 2]);
  28558. expect(isEditorVisible()).toEqual(true);
  28559. });
  28560. it('should open editor after double clicking on a cell', function (done) {
  28561. var hot = handsontable({
  28562. data: Handsontable.helper.createSpreadsheetData(5, 2)
  28563. });
  28564. var cell = $(getCell(0, 0));
  28565. var clicks = 0;
  28566. window.scrollTo(0, cell.offset().top);
  28567. setTimeout(function () {
  28568. mouseDown(cell);
  28569. mouseUp(cell);
  28570. clicks++;
  28571. }, 0);
  28572. setTimeout(function () {
  28573. mouseDown(cell);
  28574. mouseUp(cell);
  28575. clicks++;
  28576. }, 100);
  28577. setTimeout(function () {
  28578. var editor = hot.getActiveEditor();
  28579. expect(clicks).toBe(2);
  28580. expect(editor.isOpened()).toBe(true);
  28581. expect(editor.isInFullEditMode()).toBe(true);
  28582. done();
  28583. }, 200);
  28584. });
  28585. it('should call editor focus() method after opening an editor', function () {
  28586. var hot = handsontable();
  28587. selectCell(2, 2);
  28588. var editor = hot.getActiveEditor();
  28589. spyOn(editor, 'focus');
  28590. expect(editor.isOpened()).toEqual(false);
  28591. expect(editor.focus).not.toHaveBeenCalled();
  28592. keyDown('f2');
  28593. expect(editor.isOpened()).toEqual(true);
  28594. expect(editor.focus).toHaveBeenCalled();
  28595. });
  28596. it('editor size should not exceed the viewport after text edit', function () {
  28597. handsontable({
  28598. data: Handsontable.helper.createSpreadsheetData(10, 5),
  28599. width: 200,
  28600. height: 200
  28601. });
  28602. selectCell(2, 2);
  28603. keyDown('enter');
  28604. expect(isEditorVisible()).toEqual(true);
  28605. document.activeElement.value = 'Very very very very very very very very very very very very very very very very very long text';
  28606. keyDownUp(32); // space - trigger textarea resize
  28607. var $textarea = $(document.activeElement);
  28608. var $wtHider = this.$container.find('.wtHider');
  28609. expect($textarea.offset().left + $textarea.outerWidth()).not.toBeGreaterThan($wtHider.offset().left + this.$container.outerWidth());
  28610. expect($textarea.offset().top + $textarea.outerHeight()).not.toBeGreaterThan($wtHider.offset().top + $wtHider.outerHeight());
  28611. });
  28612. it('should open editor after selecting cell in another table and hitting enter', function () {
  28613. this.$container2 = $('<div id="' + id + '-2"></div>').appendTo('body');
  28614. var hot1 = handsontable();
  28615. var hot2 = handsontable2.call(this);
  28616. this.$container.find('tbody tr:eq(0) td:eq(0)').simulate('mousedown');
  28617. this.$container.find('tbody tr:eq(0) td:eq(0)').simulate('mouseup');
  28618. // Open editor in HOT1
  28619. keyDown('enter');
  28620. var editor = $('.handsontableInputHolder');
  28621. expect(editor.is(':visible')).toBe(true);
  28622. // Close editor in HOT1
  28623. keyDown('enter');
  28624. expect(editor.is(':visible')).toBe(false);
  28625. this.$container2.find('tbody tr:eq(0) td:eq(0)').simulate('mousedown');
  28626. this.$container2.find('tbody tr:eq(0) td:eq(0)').simulate('mouseup');
  28627. expect(hot1.getSelected()).toBeUndefined();
  28628. expect(hot2.getSelected()).toEqual([0, 0, 0, 0]);
  28629. // Open editor in HOT2
  28630. keyDown('enter');
  28631. editor = $('.handsontableInputHolder');
  28632. expect(editor.is(':visible')).toBe(true);
  28633. this.$container2.handsontable('destroy');
  28634. this.$container2.remove();
  28635. function handsontable2(options) {
  28636. var container = this.$container2;
  28637. container.handsontable(options);
  28638. container[0].focus(); // otherwise TextEditor tests do not pass in IE8
  28639. return container.data('handsontable');
  28640. }
  28641. });
  28642. it('should open editor after pressing a printable character', function () {
  28643. var hot = handsontable({
  28644. data: Handsontable.helper.createSpreadsheetData(3, 3)
  28645. });
  28646. selectCell(0, 0);
  28647. var editorHolder = $('.handsontableInputHolder');
  28648. // var editorInput = editorHolder.find('.handsontableInput');
  28649. expect(editorHolder.is(':visible')).toBe(false);
  28650. // var keyboardEvent = $.Event('keydown', {
  28651. // keyCode: 'a'.charCodeAt(0)
  28652. // });
  28653. // this.$container.trigger(keyboardEvent);
  28654. this.$container.simulate('keydown', {
  28655. keyCode: 'a'.charCodeAt(0)
  28656. });
  28657. expect(editorHolder.is(':visible')).toBe(true);
  28658. });
  28659. it('should open editor after pressing a printable character with shift key', function () {
  28660. var hot = handsontable({
  28661. data: Handsontable.helper.createSpreadsheetData(3, 3)
  28662. });
  28663. selectCell(0, 0);
  28664. var editorHolder = $('.handsontableInputHolder');
  28665. expect(editorHolder.is(':visible')).toBe(false);
  28666. /**
  28667. * To reliably mimic SHIFT+SOME_KEY combination we have to trigger two events.
  28668. * First we need to trigger keydown event with SHIFT keyCode (16)
  28669. * and then trigger a keydown event with keyCode of SOME_KEY and shiftKey property set to true
  28670. */
  28671. // var shiftKeyboardEvent = $.Event('keydown', {
  28672. // keyCode: 16, //shift
  28673. // shiftKey: true
  28674. // });
  28675. //
  28676. // var keyboardEvent = $.Event('keydown', {
  28677. // keyCode: 'a'.charCodeAt(0),
  28678. // shiftKey: true
  28679. // });
  28680. this.$container.simulate('keydown', {
  28681. keyCode: 'a'.charCodeAt(0),
  28682. shiftKey: true
  28683. });
  28684. // this.$container.trigger(shiftKeyboardEvent);
  28685. // this.$container.trigger(keyboardEvent);
  28686. expect(editorHolder.is(':visible')).toBe(true);
  28687. });
  28688. it('should be able to open editor after clearing cell data with DELETE', function () {
  28689. var hot = handsontable({
  28690. data: Handsontable.helper.createSpreadsheetData(3, 3)
  28691. });
  28692. selectCell(0, 0);
  28693. var editorHolder = $('.handsontableInputHolder');
  28694. expect(editorHolder.is(':visible')).toBe(false);
  28695. this.$container.simulate('keydown', {
  28696. keyCode: 46
  28697. });
  28698. this.$container.simulate('keydown', {
  28699. keyCode: 'a'.charCodeAt(0)
  28700. });
  28701. expect(editorHolder.is(':visible')).toBe(true);
  28702. });
  28703. it('should be able to open editor after clearing cell data with BACKSPACE', function () {
  28704. var hot = handsontable({
  28705. data: Handsontable.helper.createSpreadsheetData(3, 3)
  28706. });
  28707. selectCell(0, 0);
  28708. var editorHolder = $('.handsontableInputHolder');
  28709. expect(editorHolder.is(':visible')).toBe(false);
  28710. this.$container.simulate('keydown', {
  28711. keyCode: 8 // backspace
  28712. });
  28713. this.$container.simulate('keydown', {
  28714. keyCode: 'a'.charCodeAt(0)
  28715. });
  28716. expect(editorHolder.is(':visible')).toBe(true);
  28717. });
  28718. it('should scroll editor to a cell, if trying to edit cell that is outside of the viewport', function () {
  28719. var hot = handsontable({
  28720. data: Handsontable.helper.createSpreadsheetData(20, 20),
  28721. width: 100,
  28722. height: 50
  28723. });
  28724. selectCell(0, 0);
  28725. expect(getCell(0, 0)).not.toBeNull();
  28726. expect(getCell(19, 19)).toBeNull();
  28727. hot.view.scrollViewport({ row: 19, col: 19 });
  28728. hot.render();
  28729. expect(getCell(0, 0)).toBeNull();
  28730. expect(getCell(19, 19)).not.toBeNull();
  28731. keyDown('enter');
  28732. expect(getCell(0, 0)).not.toBeNull();
  28733. expect(getCell(19, 19)).toBeNull();
  28734. });
  28735. it('should open empty editor after clearing cell value width BACKSPACE', function () {
  28736. var hot = handsontable({
  28737. data: Handsontable.helper.createSpreadsheetData(4, 4)
  28738. });
  28739. expect(getDataAtCell(0, 0)).toEqual('A1');
  28740. selectCell(0, 0);
  28741. keyDown(Handsontable.helper.KEY_CODES.BACKSPACE);
  28742. expect(getDataAtCell(0, 0)).toEqual('');
  28743. expect(hot.getActiveEditor().isOpened()).toBe(false);
  28744. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28745. expect(hot.getActiveEditor().isOpened()).toBe(true);
  28746. expect(hot.getActiveEditor().getValue()).toEqual('');
  28747. });
  28748. it('should open empty editor after clearing cell value width DELETE', function () {
  28749. var hot = handsontable({
  28750. data: Handsontable.helper.createSpreadsheetData(4, 4)
  28751. });
  28752. expect(getDataAtCell(0, 0)).toEqual('A1');
  28753. selectCell(0, 0);
  28754. keyDown(Handsontable.helper.KEY_CODES.DELETE);
  28755. expect(getDataAtCell(0, 0)).toEqual('');
  28756. expect(hot.getActiveEditor().isOpened()).toBe(false);
  28757. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28758. expect(hot.getActiveEditor().isOpened()).toBe(true);
  28759. expect(hot.getActiveEditor().getValue()).toEqual('');
  28760. });
  28761. it('should not open editor after hitting ALT (#1239)', function () {
  28762. var hot = handsontable({
  28763. data: Handsontable.helper.createSpreadsheetData(4, 4)
  28764. });
  28765. expect(getDataAtCell(0, 0)).toEqual('A1');
  28766. selectCell(0, 0);
  28767. keyDown(Handsontable.helper.KEY_CODES.ALT);
  28768. expect(hot.getActiveEditor().isOpened()).toBe(false);
  28769. });
  28770. it('should open editor at the same coordinates as the edited cell', function () {
  28771. var hot = handsontable({
  28772. data: Handsontable.helper.createSpreadsheetData(16, 8),
  28773. fixedColumnsLeft: 2,
  28774. fixedRowsTop: 2
  28775. });
  28776. var mainHolder = hot.view.wt.wtTable.holder;
  28777. // corner
  28778. selectCell(1, 1);
  28779. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28780. var $inputHolder = $('.handsontableInputHolder');
  28781. expect($(getCell(1, 1)).offset().left).toEqual($inputHolder.offset().left + 1);
  28782. expect($(getCell(1, 1)).offset().top).toEqual($inputHolder.offset().top + 1);
  28783. // top
  28784. selectCell(1, 4);
  28785. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28786. expect($(getCell(1, 4)).offset().left).toEqual($inputHolder.offset().left + 1);
  28787. expect($(getCell(1, 4)).offset().top).toEqual($inputHolder.offset().top + 1);
  28788. // left
  28789. selectCell(4, 1);
  28790. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28791. expect($(getCell(4, 1)).offset().left).toEqual($inputHolder.offset().left + 1);
  28792. expect($(getCell(4, 1)).offset().top).toEqual($inputHolder.offset().top + 1);
  28793. // non-fixed
  28794. selectCell(4, 4);
  28795. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28796. expect($(getCell(4, 4)).offset().left).toEqual($inputHolder.offset().left + 1);
  28797. expect($(getCell(4, 4)).offset().top).toEqual($inputHolder.offset().top + 1);
  28798. $(mainHolder).scrollTop(1000);
  28799. });
  28800. it('should open editor at the same coordinates as the edited cell after the table had been scrolled (corner)', function () {
  28801. var hot = handsontable({
  28802. data: Handsontable.helper.createSpreadsheetData(16, 8),
  28803. fixedColumnsLeft: 2,
  28804. fixedRowsTop: 2
  28805. });
  28806. var $holder = $(hot.view.wt.wtTable.holder);
  28807. $holder.scrollTop(100);
  28808. $holder.scrollLeft(100);
  28809. hot.render();
  28810. // corner
  28811. selectCell(1, 1);
  28812. var currentCell = hot.getCell(1, 1, true);
  28813. var left = $(currentCell).offset().left;
  28814. var top = $(currentCell).offset().top;
  28815. var $inputHolder = $('.handsontableInputHolder');
  28816. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28817. expect(left).toEqual($inputHolder.offset().left + 1);
  28818. expect(top).toEqual($inputHolder.offset().top + 1);
  28819. });
  28820. it('should open editor at the same coordinates as the edited cell after the table had been scrolled (top)', function (done) {
  28821. var hot = handsontable({
  28822. data: Handsontable.helper.createSpreadsheetData(50, 50),
  28823. fixedColumnsLeft: 2,
  28824. fixedRowsTop: 2
  28825. });
  28826. var $holder = $(hot.view.wt.wtTable.holder);
  28827. $holder[0].scrollTop = 500;
  28828. setTimeout(function () {
  28829. $holder[0].scrollLeft = 500;
  28830. }, 100);
  28831. setTimeout(function () {
  28832. // top
  28833. selectCell(1, 6);
  28834. }, 200);
  28835. setTimeout(function () {
  28836. var currentCell = hot.getCell(1, 6, true);
  28837. var left = $(currentCell).offset().left;
  28838. var top = $(currentCell).offset().top;
  28839. var $inputHolder = $('.handsontableInputHolder');
  28840. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28841. expect(left).toEqual($inputHolder.offset().left + 1);
  28842. expect(top).toEqual($inputHolder.offset().top + 1);
  28843. done();
  28844. }, 300);
  28845. });
  28846. it('should open editor at the same coordinates as the edited cell after the table had been scrolled (left)', function () {
  28847. var hot = handsontable({
  28848. data: Handsontable.helper.createSpreadsheetData(50, 50),
  28849. fixedColumnsLeft: 2,
  28850. fixedRowsTop: 2
  28851. });
  28852. var $holder = $(hot.view.wt.wtTable.holder);
  28853. $holder.scrollTop(500);
  28854. $holder.scrollLeft(500);
  28855. hot.render();
  28856. // left
  28857. selectCell(6, 1);
  28858. var currentCell = hot.getCell(6, 1, true);
  28859. var left = $(currentCell).offset().left;
  28860. var top = $(currentCell).offset().top;
  28861. var $inputHolder = $('.handsontableInputHolder');
  28862. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28863. expect(left).toEqual($inputHolder.offset().left + 1);
  28864. expect(top).toEqual($inputHolder.offset().top + 1);
  28865. });
  28866. it('should open editor at the same coordinates as the edited cell after the table had been scrolled (non-fixed)', function () {
  28867. var hot = handsontable({
  28868. data: Handsontable.helper.createSpreadsheetData(50, 50),
  28869. fixedColumnsLeft: 2,
  28870. fixedRowsTop: 2
  28871. });
  28872. var $holder = $(hot.view.wt.wtTable.holder);
  28873. $holder.scrollTop(500);
  28874. $holder.scrollLeft(500);
  28875. hot.render();
  28876. // non-fixed
  28877. selectCell(7, 7);
  28878. var currentCell = hot.getCell(7, 7, true);
  28879. var left = $(currentCell).offset().left;
  28880. var top = $(currentCell).offset().top;
  28881. var $inputHolder = $('.handsontableInputHolder');
  28882. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28883. expect(left).toEqual($inputHolder.offset().left + 1);
  28884. expect(top).toEqual($inputHolder.offset().top + 1);
  28885. });
  28886. it('should display editor with the proper size, when the edited column is beyond the tables container', function () {
  28887. this.$container.css('overflow', '');
  28888. var hot = handsontable({
  28889. data: Handsontable.helper.createSpreadsheetData(3, 9)
  28890. });
  28891. selectCell(0, 7);
  28892. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28893. expect(Handsontable.dom.outerWidth(hot.getActiveEditor().TEXTAREA)).toBeAroundValue(Handsontable.dom.outerWidth(hot.getCell(0, 7)));
  28894. });
  28895. it('should display editor with the proper size, when editing a last row after the table is scrolled to the bottom', function () {
  28896. var hot = handsontable({
  28897. data: Handsontable.helper.createSpreadsheetData(3, 8),
  28898. minSpareRows: 1,
  28899. height: 100
  28900. });
  28901. selectCell(0, 2);
  28902. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28903. var regularHeight = Handsontable.dom.outerHeight(hot.getActiveEditor().TEXTAREA);
  28904. selectCell(3, 2);
  28905. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28906. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28907. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28908. // lame check, needs investigating why sometimes it leaves 2px error
  28909. if (Handsontable.dom.outerHeight(hot.getActiveEditor().TEXTAREA) == regularHeight) {
  28910. expect(Handsontable.dom.outerHeight(hot.getActiveEditor().TEXTAREA)).toEqual(regularHeight);
  28911. } else {
  28912. expect(Handsontable.dom.outerHeight(hot.getActiveEditor().TEXTAREA)).toEqual(regularHeight - 2);
  28913. }
  28914. });
  28915. it('should render the text without trimming out the whitespace, if trimWhitespace is set to false', function () {
  28916. this.$container.css('overflow', '');
  28917. var hot = handsontable({
  28918. data: Handsontable.helper.createSpreadsheetData(3, 9),
  28919. trimWhitespace: false
  28920. });
  28921. selectCell(0, 2);
  28922. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28923. hot.getActiveEditor().TEXTAREA.value = ' test of whitespace ';
  28924. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28925. expect(getDataAtCell(0, 2).length).toEqual(37);
  28926. });
  28927. it('should insert new line on caret position when pressing ALT + ENTER', function () {
  28928. var data = [['Maserati', 'Mazda'], ['Honda', 'Mini']];
  28929. var hot = handsontable({
  28930. data: data
  28931. });
  28932. selectCell(0, 0);
  28933. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28934. var $editorInput = $('.handsontableInput');
  28935. Handsontable.dom.setCaretPosition($editorInput[0], 2);
  28936. $editorInput.simulate('keydown', {
  28937. altKey: true,
  28938. keyCode: Handsontable.helper.KEY_CODES.ENTER
  28939. });
  28940. expect(hot.getActiveEditor().TEXTAREA.value).toEqual('Ma\nserati');
  28941. });
  28942. it('should be displayed and resized properly, so it doesn\'t exceed the viewport dimensions', function () {
  28943. var data = [['', '', '', '', ''], ['', 'The Dude abides. I don\'t know about you but I take comfort in that. It\'s good knowin\' he\'s out there. The ' + 'Dude. Takin\' \'er easy for all us sinners. Shoosh. I sure hope he makes the finals.', '', '', ''], ['', '', '', '', '']];
  28944. var hot = handsontable({
  28945. data: data,
  28946. colWidths: 40,
  28947. width: 300,
  28948. height: 200,
  28949. minSpareRows: 20,
  28950. minSpareCols: 20
  28951. });
  28952. selectCell(1, 1);
  28953. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28954. var $editorInput = $('.handsontableInput');
  28955. var $editedCell = $(hot.getCell(1, 1));
  28956. expect($editorInput.outerWidth()).toEqual(hot.view.wt.wtTable.holder.clientWidth - $editedCell.position().left + 1);
  28957. hot.view.wt.scrollHorizontal(3);
  28958. hot.render();
  28959. expect($editorInput.width() + $editorInput.offset().left).toBeLessThan(hot.view.wt.wtTable.holder.clientWidth);
  28960. });
  28961. it('should resize editor to properly size after focus', function (done) {
  28962. var data = [['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', 'sadiasdoadoajdoasjdoij doi ajdoiasjdasoidasoid'], ['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', '', '', '', '']];
  28963. var hot = handsontable({
  28964. data: data,
  28965. colWidths: 40,
  28966. rowHeights: 25,
  28967. width: 500,
  28968. height: 220
  28969. });
  28970. selectCell(4, 10);
  28971. keyDown(Handsontable.helper.KEY_CODES.ENTER);
  28972. var $editorInput = $('.handsontableInput');
  28973. setTimeout(function () {
  28974. expect([105, 119]).toEqual(jasmine.arrayContaining([$editorInput.height()]));
  28975. done();
  28976. }, 150);
  28977. });
  28978. });
  28979. /***/ }),
  28980. /* 216 */
  28981. /***/ (function(module, exports, __webpack_require__) {
  28982. "use strict";
  28983. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  28984. __webpack_require__(85);
  28985. __webpack_require__(102);
  28986. __webpack_require__(111);
  28987. __webpack_require__(112);
  28988. __webpack_require__(96);
  28989. __webpack_require__(110);
  28990. __webpack_require__(93);
  28991. __webpack_require__(94);
  28992. __webpack_require__(95);
  28993. __webpack_require__(84);
  28994. __webpack_require__(107);
  28995. __webpack_require__(105);
  28996. __webpack_require__(103);
  28997. __webpack_require__(108);
  28998. __webpack_require__(109);
  28999. __webpack_require__(104);
  29000. __webpack_require__(106);
  29001. __webpack_require__(97);
  29002. __webpack_require__(98);
  29003. __webpack_require__(99);
  29004. __webpack_require__(101);
  29005. __webpack_require__(100);
  29006. __webpack_require__(82);
  29007. __webpack_require__(83);
  29008. __webpack_require__(78);
  29009. __webpack_require__(81);
  29010. __webpack_require__(80);
  29011. __webpack_require__(79);
  29012. __webpack_require__(51);
  29013. __webpack_require__(87);
  29014. __webpack_require__(88);
  29015. __webpack_require__(90);
  29016. __webpack_require__(89);
  29017. __webpack_require__(86);
  29018. __webpack_require__(92);
  29019. __webpack_require__(91);
  29020. __webpack_require__(113);
  29021. __webpack_require__(116);
  29022. __webpack_require__(114);
  29023. __webpack_require__(115);
  29024. __webpack_require__(118);
  29025. __webpack_require__(117);
  29026. __webpack_require__(120);
  29027. __webpack_require__(119);
  29028. __webpack_require__(122);
  29029. __webpack_require__(121).install();
  29030. var regExp = new RegExp( false ? __ENV_ARGS__.testPathPattern : '.*', 'i');
  29031. [__webpack_require__(124), __webpack_require__(123)].forEach(function (req) {
  29032. req.keys().forEach(function (key) {
  29033. if (regExp.test(key)) {
  29034. req(key);
  29035. }
  29036. });
  29037. });
  29038. __webpack_require__(75);
  29039. /***/ }),
  29040. /* 217 */
  29041. /***/ (function(module, exports, __webpack_require__) {
  29042. "use strict";
  29043. describe('Public API', function () {
  29044. var id = 'testContainer';
  29045. beforeEach(function () {
  29046. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  29047. });
  29048. afterEach(function () {
  29049. if (this.$container) {
  29050. destroy();
  29051. this.$container.remove();
  29052. }
  29053. });
  29054. describe('Plugins', function () {
  29055. it('should expose static method for registering external plugins', function () {
  29056. expect(Handsontable.plugins.registerPlugin).toBeFunction();
  29057. });
  29058. it('should expose BasePlugin class', function () {
  29059. expect(Handsontable.plugins.BasePlugin).toBeFunction();
  29060. });
  29061. it('should expose all registered plugin classes', function () {
  29062. expect(Handsontable.plugins.AutoColumnSize).toBeFunction();
  29063. expect(Handsontable.plugins.AutoRowSize).toBeFunction();
  29064. expect(Handsontable.plugins.ColumnSorting).toBeFunction();
  29065. expect(Handsontable.plugins.Comments).toBeFunction();
  29066. expect(Handsontable.plugins.ContextMenu).toBeFunction();
  29067. expect(Handsontable.plugins.ContextMenuCopyPaste).toBeFunction();
  29068. expect(Handsontable.plugins.DragToScroll).toBeFunction();
  29069. expect(Handsontable.plugins.ManualColumnFreeze).toBeFunction();
  29070. expect(Handsontable.plugins.ManualColumnResize).toBeFunction();
  29071. expect(Handsontable.plugins.ManualRowResize).toBeFunction();
  29072. expect(Handsontable.plugins.MultipleSelectionHandles).toBeFunction();
  29073. expect(Handsontable.plugins.TouchScroll).toBeFunction();
  29074. });
  29075. });
  29076. describe('Editors', function () {
  29077. it('should expose static method for registering external editors', function () {
  29078. expect(Handsontable.editors.registerEditor).toBeFunction();
  29079. });
  29080. it('should expose static method for retrieving registered editors', function () {
  29081. expect(Handsontable.editors.getEditor).toBeFunction();
  29082. });
  29083. it('should expose BaseEditor class', function () {
  29084. expect(Handsontable.editors.BaseEditor).toBeFunction();
  29085. });
  29086. it('should expose all registered editor classes', function () {
  29087. expect(Handsontable.editors.AutocompleteEditor).toBeFunction();
  29088. expect(Handsontable.editors.CheckboxEditor).toBeFunction();
  29089. expect(Handsontable.editors.DateEditor).toBeFunction();
  29090. expect(Handsontable.editors.DropdownEditor).toBeFunction();
  29091. expect(Handsontable.editors.HandsontableEditor).toBeFunction();
  29092. expect(Handsontable.editors.MobileEditor).toBeFunction();
  29093. expect(Handsontable.editors.NumericEditor).toBeFunction();
  29094. expect(Handsontable.editors.PasswordEditor).toBeFunction();
  29095. expect(Handsontable.editors.SelectEditor).toBeFunction();
  29096. expect(Handsontable.editors.TextEditor).toBeFunction();
  29097. });
  29098. });
  29099. describe('Renderers', function () {
  29100. it('should expose static method for registering external renderers', function () {
  29101. expect(Handsontable.renderers.registerRenderer).toBeFunction();
  29102. });
  29103. it('should expose static method for retrieving registered renderers', function () {
  29104. expect(Handsontable.renderers.getRenderer).toBeFunction();
  29105. });
  29106. it('should expose BaseRenderer class', function () {
  29107. expect(Handsontable.renderers.BaseRenderer).toBeFunction();
  29108. });
  29109. it('should expose all registered renderer functions', function () {
  29110. expect(Handsontable.renderers.AutocompleteRenderer).toBeFunction();
  29111. expect(Handsontable.renderers.CheckboxRenderer).toBeFunction();
  29112. expect(Handsontable.renderers.HtmlRenderer).toBeFunction();
  29113. expect(Handsontable.renderers.NumericRenderer).toBeFunction();
  29114. expect(Handsontable.renderers.PasswordRenderer).toBeFunction();
  29115. expect(Handsontable.renderers.TextRenderer).toBeFunction();
  29116. });
  29117. });
  29118. describe('Validators', function () {
  29119. it('should expose static method for registering external validators', function () {
  29120. expect(Handsontable.validators.registerValidator).toBeFunction();
  29121. });
  29122. it('should expose static method for retrieving registered validators', function () {
  29123. expect(Handsontable.validators.getValidator).toBeFunction();
  29124. });
  29125. it('should expose all registered validator functions', function () {
  29126. expect(Handsontable.validators.AutocompleteValidator).toBeFunction();
  29127. expect(Handsontable.validators.DateValidator).toBeFunction();
  29128. expect(Handsontable.validators.NumericValidator).toBeFunction();
  29129. expect(Handsontable.validators.TimeValidator).toBeFunction();
  29130. });
  29131. });
  29132. describe('CellTypes', function () {
  29133. it('should expose static method for registering external cell types', function () {
  29134. expect(Handsontable.cellTypes.registerCellType).toBeFunction();
  29135. });
  29136. it('should expose static method for retrieving registered cell types', function () {
  29137. expect(Handsontable.cellTypes.getCellType).toBeFunction();
  29138. });
  29139. it('should expose all registered cell type objects', function () {
  29140. expect(Handsontable.cellTypes.autocomplete.editor).toBe(Handsontable.editors.AutocompleteEditor);
  29141. expect(Handsontable.cellTypes.autocomplete.renderer).toBe(Handsontable.renderers.AutocompleteRenderer);
  29142. expect(Handsontable.cellTypes.autocomplete.validator).toBe(Handsontable.validators.AutocompleteValidator);
  29143. expect(Handsontable.cellTypes.checkbox.editor).toBe(Handsontable.editors.CheckboxEditor);
  29144. expect(Handsontable.cellTypes.checkbox.renderer).toBe(Handsontable.renderers.CheckboxRenderer);
  29145. expect(Handsontable.cellTypes.checkbox.validator).not.toBeDefined();
  29146. expect(Handsontable.cellTypes.date.editor).toBe(Handsontable.editors.DateEditor);
  29147. expect(Handsontable.cellTypes.date.renderer).toBe(Handsontable.renderers.AutocompleteRenderer);
  29148. expect(Handsontable.cellTypes.date.validator).toBe(Handsontable.validators.DateValidator);
  29149. expect(Handsontable.cellTypes.dropdown.editor).toBe(Handsontable.editors.DropdownEditor);
  29150. expect(Handsontable.cellTypes.dropdown.renderer).toBe(Handsontable.renderers.AutocompleteRenderer);
  29151. expect(Handsontable.cellTypes.dropdown.validator).toBe(Handsontable.validators.AutocompleteValidator);
  29152. expect(Handsontable.cellTypes.handsontable.editor).toBe(Handsontable.editors.HandsontableEditor);
  29153. expect(Handsontable.cellTypes.handsontable.renderer).toBe(Handsontable.renderers.AutocompleteRenderer);
  29154. expect(Handsontable.cellTypes.handsontable.validator).not.toBeDefined();
  29155. expect(Handsontable.cellTypes.numeric.editor).toBe(Handsontable.editors.NumericEditor);
  29156. expect(Handsontable.cellTypes.numeric.renderer).toBe(Handsontable.renderers.NumericRenderer);
  29157. expect(Handsontable.cellTypes.numeric.validator).toBe(Handsontable.validators.NumericValidator);
  29158. expect(Handsontable.cellTypes.password.editor).toBe(Handsontable.editors.PasswordEditor);
  29159. expect(Handsontable.cellTypes.password.renderer).toBe(Handsontable.renderers.PasswordRenderer);
  29160. expect(Handsontable.cellTypes.password.validator).not.toBeDefined();
  29161. expect(Handsontable.cellTypes.text.editor).toBe(Handsontable.editors.TextEditor);
  29162. expect(Handsontable.cellTypes.text.renderer).toBe(Handsontable.renderers.TextRenderer);
  29163. expect(Handsontable.cellTypes.text.validator).not.toBeDefined();
  29164. expect(Handsontable.cellTypes.time.editor).toBe(Handsontable.editors.TextEditor);
  29165. expect(Handsontable.cellTypes.time.renderer).toBe(Handsontable.renderers.TextRenderer);
  29166. expect(Handsontable.cellTypes.time.validator).toBe(Handsontable.validators.TimeValidator);
  29167. });
  29168. });
  29169. });
  29170. /***/ }),
  29171. /* 218 */
  29172. /***/ (function(module, exports, __webpack_require__) {
  29173. "use strict";
  29174. describe('AutocompleteRenderer', function () {
  29175. var id = 'testContainer';
  29176. beforeEach(function () {
  29177. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  29178. });
  29179. afterEach(function () {
  29180. if (this.$container) {
  29181. destroy();
  29182. this.$container.remove();
  29183. }
  29184. });
  29185. it('should contain down arrow glyph', function (done) {
  29186. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  29187. handsontable({
  29188. type: 'autocomplete',
  29189. afterValidate: onAfterValidate
  29190. });
  29191. setDataAtCell(2, 2, 'string');
  29192. setTimeout(function () {
  29193. var html = getCell(2, 2).innerHTML;
  29194. expect(html).toContain('string');
  29195. expect(html).toContain('\u25BC');
  29196. done();
  29197. }, 100);
  29198. });
  29199. it('should open cell editor after clicking on arrow glyph', function () {
  29200. var hot = handsontable({
  29201. type: 'autocomplete'
  29202. });
  29203. selectCell(0, 0);
  29204. expect(hot.getActiveEditor().isOpened()).toBe(false);
  29205. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  29206. expect(hot.getActiveEditor().isOpened()).toBe(true);
  29207. });
  29208. it('should open cell editor after clicking on arrow glyph, after the table has been destroyed and reinitialized (#1367)', function () {
  29209. var hot = handsontable({
  29210. type: 'autocomplete'
  29211. });
  29212. destroy();
  29213. hot = handsontable({
  29214. type: 'autocomplete'
  29215. });
  29216. selectCell(0, 0);
  29217. expect(hot.getActiveEditor().isOpened()).toBe(false);
  29218. $(getCell(0, 0)).find('.htAutocompleteArrow').simulate('mousedown');
  29219. expect(hot.getActiveEditor().isOpened()).toBe(true);
  29220. });
  29221. });
  29222. /***/ }),
  29223. /* 219 */
  29224. /***/ (function(module, exports, __webpack_require__) {
  29225. "use strict";
  29226. describe('CellDecorator', function () {
  29227. var id = 'testContainer';
  29228. beforeEach(function () {
  29229. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  29230. });
  29231. afterEach(function () {
  29232. if (this.$container) {
  29233. destroy();
  29234. this.$container.remove();
  29235. }
  29236. });
  29237. var arrayOfObjects = function arrayOfObjects() {
  29238. return [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }];
  29239. };
  29240. it('should add an appropriate class name to every cell, if wordWrap=false is set to the whole table', function () {
  29241. var hot = handsontable({
  29242. data: arrayOfObjects(),
  29243. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }],
  29244. wordWrap: false
  29245. });
  29246. var cols = countCols(),
  29247. rows = countRows();
  29248. for (var i = 0; i < cols; i++) {
  29249. for (var j = 0; j < rows; j++) {
  29250. expect($(getCell(i, j)).hasClass(hot.getSettings().noWordWrapClassName)).toBe(true);
  29251. }
  29252. }
  29253. });
  29254. it('should add an appropriate class name to every cell in a column, if wordWrap=false is set to the column settings', function () {
  29255. var hot = handsontable({
  29256. data: arrayOfObjects(),
  29257. columns: [{ data: 'id' }, { data: 'name', wordWrap: false }, { data: 'lastName' }]
  29258. });
  29259. var rows = countRows();
  29260. for (var i = 0; i < rows; i++) {
  29261. expect($(getCell(i, 1)).hasClass(hot.getSettings().noWordWrapClassName)).toBe(true);
  29262. }
  29263. for (var _i = 0; _i < rows; _i++) {
  29264. expect($(getCell(_i, 0)).hasClass(hot.getSettings().noWordWrapClassName)).toBe(false); // no class added to other columns
  29265. expect($(getCell(_i, 2)).hasClass(hot.getSettings().noWordWrapClassName)).toBe(false);
  29266. }
  29267. });
  29268. it('should add an appropriate class to a cell, if wordWrap=false is set to a single cell', function () {
  29269. var hot = handsontable({
  29270. data: arrayOfObjects(),
  29271. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }]
  29272. });
  29273. expect($(getCell(1, 1)).hasClass(hot.getSettings().noWordWrapClassName)).toBe(false);
  29274. getCellMeta(1, 1).wordWrap = false;
  29275. render();
  29276. expect($(getCell(1, 1)).hasClass(hot.getSettings().noWordWrapClassName)).toBe(true);
  29277. });
  29278. it('should set "white-space" css parameter to "nowrap" if htNoWrap class is added to a cell', function () {
  29279. var hot = handsontable({
  29280. data: arrayOfObjects(),
  29281. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }]
  29282. });
  29283. expect(window.getComputedStyle(getCell(1, 1)).whiteSpace).not.toEqual('nowrap');
  29284. getCellMeta(1, 1).wordWrap = false;
  29285. render();
  29286. expect(window.getComputedStyle(getCell(1, 1)).whiteSpace).toEqual('nowrap');
  29287. });
  29288. it('should not add cell `htInvalid` class when trying to add not proper value', function (done) {
  29289. var hot = handsontable({
  29290. data: arrayOfObjects(),
  29291. columns: [{ data: 'id' }, { data: 'name' }, { data: 'salary', type: 'numeric', allowInvalid: false }]
  29292. });
  29293. setDataAtCell(0, 2, 'non-numeric value');
  29294. setTimeout(function () {
  29295. expect($(getCell(0, 2)).hasClass(hot.getSettings().invalidCellClassName)).toBe(false);
  29296. done();
  29297. }, 200);
  29298. });
  29299. });
  29300. /***/ }),
  29301. /* 220 */
  29302. /***/ (function(module, exports, __webpack_require__) {
  29303. "use strict";
  29304. describe('CheckboxRenderer', function () {
  29305. var id = 'testContainer';
  29306. beforeEach(function () {
  29307. this.$container = $('<div id="' + id + '" style="width: 300px; height: 200px;"></div>').appendTo('body');
  29308. });
  29309. afterEach(function () {
  29310. if (this.$container) {
  29311. destroy();
  29312. this.$container.remove();
  29313. }
  29314. });
  29315. it('should render values as checkboxes', function () {
  29316. handsontable({
  29317. data: [[true], [false], [true]],
  29318. columns: [{ type: 'checkbox' }]
  29319. });
  29320. expect($(getRenderedValue(0, 0)).is(':checkbox')).toBe(true);
  29321. expect($(getRenderedValue(1, 0)).is(':checkbox')).toBe(true);
  29322. expect($(getRenderedValue(2, 0)).is(':checkbox')).toBe(true);
  29323. });
  29324. it('should render check checkboxes for cell which value is true', function () {
  29325. handsontable({
  29326. data: [[true], [false], [true]],
  29327. columns: [{ type: 'checkbox' }]
  29328. });
  29329. expect($(getRenderedContent(0, 0)).prop('checked')).toBe(true);
  29330. expect($(getRenderedContent(1, 0)).prop('checked')).toBe(false);
  29331. expect($(getRenderedContent(2, 0)).prop('checked')).toBe(true);
  29332. });
  29333. it('should use templates to check appropriate checkboxes', function () {
  29334. handsontable({
  29335. data: [['yes'], ['no'], ['yes']],
  29336. columns: [{
  29337. type: 'checkbox',
  29338. checkedTemplate: 'yes',
  29339. uncheckedTemplate: 'no'
  29340. }]
  29341. });
  29342. expect($(getRenderedContent(0, 0)).prop('checked')).toBe(true);
  29343. expect($(getRenderedContent(1, 0)).prop('checked')).toBe(false);
  29344. expect($(getRenderedContent(2, 0)).prop('checked')).toBe(true);
  29345. });
  29346. it('should select cell after checkbox click', function () {
  29347. var hot = handsontable({
  29348. data: [[true], [false], [true]],
  29349. columns: [{ type: 'checkbox' }]
  29350. });
  29351. hot.selectCell(0, 0);
  29352. this.$container.find(':checkbox').eq(2).simulate('mousedown');
  29353. expect(hot.getSelected()).toEqual([2, 0, 2, 0]);
  29354. });
  29355. it('should select cell after label click', function () {
  29356. var hot = handsontable({
  29357. data: [[true], [false], [true]],
  29358. columns: [{ type: 'checkbox', label: { position: 'before', value: 'Sure? ' } }]
  29359. });
  29360. hot.selectCell(0, 0);
  29361. this.$container.find('td label').eq(2).simulate('mousedown');
  29362. expect(hot.getSelected()).toEqual([2, 0, 2, 0]);
  29363. });
  29364. it('should reverse selection in checkboxes', function () {
  29365. handsontable({
  29366. data: [[true], [false], [true]],
  29367. columns: [{ type: 'checkbox' }]
  29368. });
  29369. this.$container.find(':checkbox').eq(0).simulate('click');
  29370. this.$container.find(':checkbox').eq(1).simulate('click');
  29371. this.$container.find(':checkbox').eq(2).simulate('click');
  29372. expect(getData()).toEqual([[false], [true], [false]]);
  29373. });
  29374. it('shouldn\'t uncheck checkboxes', function () {
  29375. handsontable({
  29376. data: [[true], [true], [true]],
  29377. columns: [{ type: 'checkbox', readOnly: true }]
  29378. });
  29379. this.$container.find(':checkbox').trigger('click');
  29380. expect(getData()).toEqual([[true], [true], [true]]);
  29381. });
  29382. it('should check single box after hitting space', function () {
  29383. handsontable({
  29384. data: [[true], [true], [true]],
  29385. columns: [{ type: 'checkbox' }]
  29386. });
  29387. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29388. addHook('afterChange', afterChangeCallback);
  29389. var checkboxes = this.$container.find(':checkbox');
  29390. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29391. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29392. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29393. expect(getData()).toEqual([[true], [true], [true]]);
  29394. selectCell(0, 0);
  29395. // this.$container.find(':checkbox').eq(0).simulate('click');
  29396. // this.$container.simulate('keydown',{
  29397. // keyCode: 32
  29398. // });
  29399. keyDown('space');
  29400. checkboxes = this.$container.find(':checkbox');
  29401. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29402. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29403. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29404. expect(getData()).toEqual([[false], [true], [true]]);
  29405. expect(afterChangeCallback.calls.count()).toEqual(1);
  29406. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
  29407. });
  29408. it('should not check single box after hitting space, if cell is readOnly', function () {
  29409. handsontable({
  29410. data: [[true], [true], [true]],
  29411. columns: [{ type: 'checkbox', readOnly: true }]
  29412. });
  29413. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29414. addHook('afterChange', afterChangeCallback);
  29415. var checkboxes = this.$container.find(':checkbox');
  29416. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29417. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29418. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29419. expect(getData()).toEqual([[true], [true], [true]]);
  29420. selectCell(0, 0);
  29421. keyDown('space');
  29422. checkboxes = this.$container.find(':checkbox');
  29423. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29424. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29425. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29426. expect(getData()).toEqual([[true], [true], [true]]);
  29427. expect(afterChangeCallback).not.toHaveBeenCalled();
  29428. });
  29429. it('should not check single box after hitting space, if last column is readOnly (#3562)', function () {
  29430. handsontable({
  29431. data: [[true, true], [false, false], [true, true]],
  29432. columns: [{ type: 'checkbox' }, { type: 'checkbox', readOnly: true }]
  29433. });
  29434. selectCell(0, 0);
  29435. keyDown('space');
  29436. selectCell(0, 1);
  29437. keyDown('space');
  29438. selectCell(1, 0);
  29439. keyDown('space');
  29440. selectCell(1, 1);
  29441. keyDown('space');
  29442. var checkboxes = this.$container.find(':checkbox');
  29443. // column 0
  29444. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29445. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29446. expect(checkboxes.eq(4).prop('checked')).toBe(true);
  29447. // column 1
  29448. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29449. expect(checkboxes.eq(3).prop('checked')).toBe(false);
  29450. expect(checkboxes.eq(5).prop('checked')).toBe(true);
  29451. expect(getData()).toEqual([[false, true], [true, false], [true, true]]);
  29452. });
  29453. it('should change checkboxes values properly when data contains null or/and undefined', function () {
  29454. handsontable({
  29455. data: [[null], [undefined]],
  29456. colHeaders: true,
  29457. columns: [{
  29458. type: 'checkbox'
  29459. }]
  29460. });
  29461. selectCell(0, 0, 1, 0);
  29462. keyDown('space');
  29463. expect(getDataAtCol(0)).toEqual([true, true]);
  29464. selectCell(0, 0, 1, 0);
  29465. keyDown('space');
  29466. expect(getDataAtCol(0)).toEqual([false, false]);
  29467. });
  29468. it('should change checkboxes values for cells below the viewport (hot initialized by startRows) #4037', function () {
  29469. handsontable({
  29470. startRows: 200,
  29471. colHeaders: true,
  29472. columns: [{
  29473. type: 'checkbox'
  29474. }]
  29475. });
  29476. selectCell(0, 0, 199, 0);
  29477. keyDown('space');
  29478. expect(getDataAtCell(199, 0)).toEqual(true);
  29479. });
  29480. it('should reverse checkboxes state after hitting space, when multiple cells are selected', function () {
  29481. var hot = handsontable({
  29482. data: [[true], [false], [true]],
  29483. columns: [{ type: 'checkbox' }]
  29484. });
  29485. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29486. addHook('afterChange', afterChangeCallback);
  29487. var checkboxes = this.$container.find(':checkbox');
  29488. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29489. expect(checkboxes.eq(1).prop('checked')).toBe(false);
  29490. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29491. expect(getData()).toEqual([[true], [false], [true]]);
  29492. selectCell(0, 0, 2, 0);
  29493. keyDown('space');
  29494. checkboxes = this.$container.find(':checkbox');
  29495. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29496. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29497. expect(checkboxes.eq(2).prop('checked')).toBe(false);
  29498. expect(getData()).toEqual([[false], [true], [false]]);
  29499. expect(afterChangeCallback.calls.count()).toEqual(1);
  29500. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false], [1, 0, false, true], [2, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
  29501. });
  29502. it('should reverse checkboxes state after hitting space, when multiple cells are selected and selStart > selEnd', function () {
  29503. handsontable({
  29504. data: [[true], [false], [true]],
  29505. columns: [{ type: 'checkbox' }]
  29506. });
  29507. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29508. addHook('afterChange', afterChangeCallback);
  29509. var checkboxes = this.$container.find(':checkbox');
  29510. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29511. expect(checkboxes.eq(1).prop('checked')).toBe(false);
  29512. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29513. expect(getData()).toEqual([[true], [false], [true]]);
  29514. selectCell(2, 0, 0, 0); // selStart = [2,0], selEnd = [0,0]
  29515. keyDown('space');
  29516. checkboxes = this.$container.find(':checkbox');
  29517. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29518. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29519. expect(checkboxes.eq(2).prop('checked')).toBe(false);
  29520. expect(getData()).toEqual([[false], [true], [false]]);
  29521. expect(afterChangeCallback.calls.count()).toEqual(1);
  29522. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false], [1, 0, false, true], [2, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
  29523. });
  29524. it('should open cell editors of cell that does not have checkboxRenderer (#1199)', function () {
  29525. var hot = handsontable({
  29526. data: [[true, 'B0'], [true, 'B1'], [true, 'B2']],
  29527. columns: [{ type: 'checkbox' }, { type: 'text' }]
  29528. });
  29529. selectCell(0, 1);
  29530. expect(hot.getActiveEditor().isOpened()).toBe(false);
  29531. keyDown('space');
  29532. expect(hot.getActiveEditor().isOpened()).toBe(true);
  29533. });
  29534. it('double click on checkbox cell should invert the value', function () {
  29535. handsontable({
  29536. data: [[true], [false], [true]],
  29537. columns: [{ type: 'checkbox' }]
  29538. });
  29539. selectCell(0, 0);
  29540. mouseDoubleClick(getCell(0, 0));
  29541. expect(getDataAtCell(0, 0)).toBe(false);
  29542. mouseDoubleClick(getCell(0, 0));
  29543. expect(getDataAtCell(0, 0)).toBe(true);
  29544. mouseDoubleClick(getCell(0, 0));
  29545. expect(getDataAtCell(0, 0)).toBe(false);
  29546. });
  29547. it('should change checkbox state from checked to unchecked after hitting ENTER', function () {
  29548. handsontable({
  29549. data: [[true], [true], [true]],
  29550. columns: [{ type: 'checkbox' }]
  29551. });
  29552. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29553. addHook('afterChange', afterChangeCallback);
  29554. var checkboxes = this.$container.find(':checkbox');
  29555. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29556. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29557. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29558. expect(getData()).toEqual([[true], [true], [true]]);
  29559. selectCell(0, 0);
  29560. keyDown('enter');
  29561. checkboxes = this.$container.find(':checkbox');
  29562. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29563. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29564. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29565. expect(getData()).toEqual([[false], [true], [true]]);
  29566. expect(afterChangeCallback.calls.count()).toEqual(1);
  29567. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
  29568. });
  29569. it('should change checkbox state from checked to unchecked after hitting ENTER using custom check/uncheck templates', function () {
  29570. handsontable({
  29571. data: [['yes'], ['yes'], ['no']],
  29572. columns: [{
  29573. type: 'checkbox',
  29574. checkedTemplate: 'yes',
  29575. uncheckedTemplate: 'no'
  29576. }]
  29577. });
  29578. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29579. addHook('afterChange', afterChangeCallback);
  29580. var checkboxes = this.$container.find(':checkbox');
  29581. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29582. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29583. expect(checkboxes.eq(2).prop('checked')).toBe(false);
  29584. expect(getData()).toEqual([['yes'], ['yes'], ['no']]);
  29585. selectCell(0, 0);
  29586. keyDown('enter');
  29587. checkboxes = this.$container.find(':checkbox');
  29588. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29589. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29590. expect(checkboxes.eq(2).prop('checked')).toBe(false);
  29591. expect(getData()).toEqual([['no'], ['yes'], ['no']]);
  29592. expect(afterChangeCallback.calls.count()).toEqual(1);
  29593. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 'yes', 'no']], 'edit', undefined, undefined, undefined, undefined);
  29594. });
  29595. it('should change checkbox state from checked to unchecked after hitting ENTER using custom check/uncheck templates in numeric format', function () {
  29596. handsontable({
  29597. data: [[1], [1], [0]],
  29598. columns: [{
  29599. type: 'checkbox',
  29600. checkedTemplate: 1,
  29601. uncheckedTemplate: 0
  29602. }]
  29603. });
  29604. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29605. addHook('afterChange', afterChangeCallback);
  29606. var checkboxes = this.$container.find(':checkbox');
  29607. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29608. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29609. expect(checkboxes.eq(2).prop('checked')).toBe(false);
  29610. expect(getData()).toEqual([[1], [1], [0]]);
  29611. selectCell(0, 0);
  29612. keyDown('enter');
  29613. checkboxes = this.$container.find(':checkbox');
  29614. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29615. expect(checkboxes.eq(1).prop('checked')).toBe(true);
  29616. expect(checkboxes.eq(2).prop('checked')).toBe(false);
  29617. expect(getData()).toEqual([[0], [1], [0]]);
  29618. expect(afterChangeCallback.calls.count()).toEqual(1);
  29619. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 1, 0]], 'edit', undefined, undefined, undefined, undefined);
  29620. });
  29621. it('should change checkbox state to unchecked after hitting DELETE', function () {
  29622. handsontable({
  29623. data: [[true], [false], [true]],
  29624. columns: [{ type: 'checkbox' }]
  29625. });
  29626. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29627. addHook('afterChange', afterChangeCallback);
  29628. var checkboxes = this.$container.find(':checkbox');
  29629. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29630. expect(checkboxes.eq(1).prop('checked')).toBe(false);
  29631. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29632. expect(getData()).toEqual([[true], [false], [true]]);
  29633. selectCell(0, 0);
  29634. keyDown('delete');
  29635. selectCell(0, 1);
  29636. keyDown('delete');
  29637. checkboxes = this.$container.find(':checkbox');
  29638. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29639. expect(checkboxes.eq(1).prop('checked')).toBe(false);
  29640. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29641. expect(getData()).toEqual([[false], [false], [true]]);
  29642. expect(afterChangeCallback.calls.count()).toEqual(2);
  29643. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
  29644. });
  29645. it('should change checkbox notte to unchecked after hitting BACKSPACE', function () {
  29646. handsontable({
  29647. data: [[true], [false], [true]],
  29648. columns: [{ type: 'checkbox' }]
  29649. });
  29650. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29651. addHook('afterChange', afterChangeCallback);
  29652. var checkboxes = this.$container.find(':checkbox');
  29653. expect(checkboxes.eq(0).prop('checked')).toBe(true);
  29654. expect(checkboxes.eq(1).prop('checked')).toBe(false);
  29655. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29656. expect(getData()).toEqual([[true], [false], [true]]);
  29657. selectCell(0, 0);
  29658. keyDown('backspace');
  29659. selectCell(0, 1);
  29660. keyDown('backspace');
  29661. checkboxes = this.$container.find(':checkbox');
  29662. expect(checkboxes.eq(0).prop('checked')).toBe(false);
  29663. expect(checkboxes.eq(1).prop('checked')).toBe(false);
  29664. expect(checkboxes.eq(2).prop('checked')).toBe(true);
  29665. expect(getData()).toEqual([[false], [false], [true]]);
  29666. expect(afterChangeCallback.calls.count()).toEqual(2);
  29667. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
  29668. });
  29669. it('should change notkbox state to unchecked after hitting DELETE (from #bad-value# state)', function () {
  29670. handsontable({
  29671. data: [['foo'], ['bar']],
  29672. columns: [{ type: 'checkbox' }]
  29673. });
  29674. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29675. addHook('afterChange', afterChangeCallback);
  29676. expect(getDataAtCell(0, 0)).toBe('foo');
  29677. expect(getDataAtCell(1, 0)).toBe('bar');
  29678. selectCell(0, 0);
  29679. keyDown('delete');
  29680. selectCell(1, 0);
  29681. keyDown('delete');
  29682. expect(getDataAtCell(0, 0)).toBe(false);
  29683. expect(getDataAtCell(1, 0)).toBe(false);
  29684. expect(getData()).toEqual([[false], [false]]);
  29685. expect(afterChangeCallback.calls.count()).toEqual(2);
  29686. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 'foo', false]], 'edit', undefined, undefined, undefined, undefined);
  29687. });
  29688. it('should change checkbox note to unchecked after hitting BACKSPACE (from #bad-value# state)', function () {
  29689. handsontable({
  29690. data: [['foo'], ['bar']],
  29691. columns: [{ type: 'checkbox' }]
  29692. });
  29693. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29694. addHook('afterChange', afterChangeCallback);
  29695. expect(getDataAtCell(0, 0)).toBe('foo');
  29696. expect(getDataAtCell(1, 0)).toBe('bar');
  29697. selectCell(0, 0);
  29698. keyDown('backspace');
  29699. selectCell(1, 0);
  29700. keyDown('backspace');
  29701. expect(getDataAtCell(0, 0)).toBe(false);
  29702. expect(getDataAtCell(1, 0)).toBe(false);
  29703. expect(getData()).toEqual([[false], [false]]);
  29704. expect(afterChangeCallback.calls.count()).toEqual(2);
  29705. expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 'foo', false]], 'edit', undefined, undefined, undefined, undefined);
  29706. });
  29707. it('shouldn\'t change checkbo notate after hitting other keys then DELETE or BACKSPACE (from #bad-value# state)', function () {
  29708. handsontable({
  29709. data: [['foo'], ['bar']],
  29710. columns: [{ type: 'checkbox' }]
  29711. });
  29712. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29713. addHook('afterChange', afterChangeCallback);
  29714. expect(getDataAtCell(0, 0)).toBe('foo');
  29715. selectCell(0, 0);
  29716. keyDown('space');
  29717. selectCell(0, 0);
  29718. keyDown('c');
  29719. expect(getDataAtCell(0, 0)).toBe('foo');
  29720. expect(getData()).toEqual([['foo'], ['bar']]);
  29721. expect(afterChangeCallback.calls.count()).toEqual(0);
  29722. });
  29723. it('should not change checkbox state after hitting other keys then SPACE, ENTER, DELETE or BACKSPACE', function () {
  29724. handsontable({
  29725. data: [[false], [true], [true]],
  29726. columns: [{ type: 'checkbox' }]
  29727. });
  29728. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29729. addHook('afterChange', afterChangeCallback);
  29730. selectCell(0, 0);
  29731. keyDown('space');
  29732. expect(getDataAtCell(0, 0)).toBe(true);
  29733. selectCell(0, 0);
  29734. keyDown('c');
  29735. expect(getDataAtCell(0, 0)).toBe(true);
  29736. expect(afterChangeCallback.calls.count()).toEqual(1);
  29737. });
  29738. it('should add label on the beginning of a checkbox element', function () {
  29739. handsontable({
  29740. data: [{ checked: true, label: 'myLabel' }, { checked: false, label: 'myLabel' }],
  29741. columns: [{ type: 'checkbox', data: 'checked', label: { position: 'before', property: 'label' } }]
  29742. });
  29743. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29744. addHook('afterChange', afterChangeCallback);
  29745. selectCell(0, 0);
  29746. keyDown('space');
  29747. expect(getDataAtCell(0, 0)).toBe(false);
  29748. expect(getDataAtCell(1, 0)).toBe(false);
  29749. expect(afterChangeCallback.calls.count()).toEqual(1);
  29750. expect(getCell(0, 0).querySelector('label').firstChild.textContent).toEqual('myLabel');
  29751. });
  29752. it('should add label on the end of a checkbox element', function () {
  29753. handsontable({
  29754. data: [{ checked: true, label: 'myLabel' }, { checked: false, label: 'myLabel' }],
  29755. columns: [{ type: 'checkbox', data: 'checked', label: { position: 'after', property: 'label' } }]
  29756. });
  29757. var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
  29758. addHook('afterChange', afterChangeCallback);
  29759. selectCell(0, 0);
  29760. keyDown('space');
  29761. expect(getDataAtCell(0, 0)).toBe(false);
  29762. expect(getDataAtCell(1, 0)).toBe(false);
  29763. expect(afterChangeCallback.calls.count()).toEqual(1);
  29764. expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('myLabel');
  29765. });
  29766. it('should not add label when value is incorrect (#bad-value)', function () {
  29767. handsontable({
  29768. data: [{ checked: 1, label: 'myLabel' }, { checked: 0, label: 'myLabel' }],
  29769. columns: [{ type: 'checkbox', data: 'checked', label: { position: 'after', property: 'label' } }]
  29770. });
  29771. expect(getCell(0, 0).querySelector('label')).toBe(null);
  29772. });
  29773. it('by default should add label on the end of a checkbox element', function () {
  29774. handsontable({
  29775. data: [{ checked: true, label: { test: 'Baz' } }, { checked: false, label: { test: 'Baz' } }],
  29776. columns: [{ type: 'checkbox', data: 'checked', label: { property: 'label.test' } }]
  29777. });
  29778. expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('Baz');
  29779. });
  29780. it('should add label with text filled from `value` label setting (passed as string)', function () {
  29781. handsontable({
  29782. data: [{ checked: true }, { checked: false }],
  29783. columns: [{ type: 'checkbox', data: 'checked', label: { value: 'myLabel' } }]
  29784. });
  29785. expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('myLabel');
  29786. });
  29787. it('should add label with text filled from `value` label setting (passed as function)', function () {
  29788. var labelFunction = jasmine.createSpy();
  29789. labelFunction.and.returnValue('myLabel');
  29790. handsontable({
  29791. autoRowSize: false,
  29792. autoColumnSize: false,
  29793. data: [{ checked: true }, { checked: false }],
  29794. columns: [{ type: 'checkbox', data: 'checked', label: { value: labelFunction } }]
  29795. });
  29796. expect(labelFunction.calls.count()).toBe(2);
  29797. expect(labelFunction.calls.argsFor(0)).toEqual([0, 0, 'checked', true]);
  29798. expect(labelFunction.calls.argsFor(1)).toEqual([1, 0, 'checked', false]);
  29799. expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('myLabel');
  29800. });
  29801. describe('CheckboxRenderer with ContextMenu', function () {
  29802. it('should add class name `htRight` after set align in contextMenu', function (done) {
  29803. handsontable({
  29804. startRows: 1,
  29805. startCols: 1,
  29806. contextMenu: ['alignment'],
  29807. cells: function cells() {
  29808. return {
  29809. type: 'checkbox'
  29810. };
  29811. },
  29812. height: 100
  29813. });
  29814. selectCell(0, 0);
  29815. contextMenu();
  29816. var menu = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator');
  29817. menu.simulate('mouseover');
  29818. setTimeout(function () {
  29819. var contextSubMenu = $('.htContextMenuSub_' + menu.text()).find('tbody td').eq(2);
  29820. contextSubMenu.simulate('mousedown');
  29821. contextSubMenu.simulate('mouseup');
  29822. expect($('.handsontable.ht_master .htRight').length).toBe(1);
  29823. done();
  29824. }, 500);
  29825. });
  29826. });
  29827. });
  29828. /***/ }),
  29829. /* 221 */
  29830. /***/ (function(module, exports, __webpack_require__) {
  29831. "use strict";
  29832. describe('HTMLRenderer', function () {
  29833. var id = 'testContainer';
  29834. beforeEach(function () {
  29835. this.$container = $('<div id="' + id + '" style="width: 300px; height: 200px;"></div>').appendTo('body');
  29836. });
  29837. afterEach(function () {
  29838. if (this.$container) {
  29839. destroy();
  29840. this.$container.remove();
  29841. }
  29842. });
  29843. it('should not fill empty rows with null values', function () {
  29844. handsontable({
  29845. data: [['a', 'b', 'c', 'd', 'e', 'f']],
  29846. colHeaders: true,
  29847. rowHeaders: true,
  29848. minSpareRows: 5,
  29849. renderer: 'html'
  29850. });
  29851. expect($('.handsontable table tr:last-child td:eq(0)').html()).toEqual('');
  29852. expect($('.handsontable table tr:last-child td:eq(1)').html()).toEqual('');
  29853. expect($('.handsontable table tr:last-child td:eq(2)').html()).toEqual('');
  29854. expect($('.handsontable table tr:last-child td:eq(3)').html()).toEqual('');
  29855. expect($('.handsontable table tr:last-child td:eq(4)').html()).toEqual('');
  29856. expect($('.handsontable table tr:last-child td:eq(5)').html()).toEqual('');
  29857. });
  29858. });
  29859. /***/ }),
  29860. /* 222 */
  29861. /***/ (function(module, exports, __webpack_require__) {
  29862. "use strict";
  29863. describe('renderers', function () {
  29864. var id = 'testContainer';
  29865. var _Handsontable$rendere = Handsontable.renderers,
  29866. registerRenderer = _Handsontable$rendere.registerRenderer,
  29867. getRenderer = _Handsontable$rendere.getRenderer;
  29868. beforeEach(function () {
  29869. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  29870. });
  29871. afterEach(function () {
  29872. if (this.$container) {
  29873. destroy();
  29874. this.$container.remove();
  29875. }
  29876. });
  29877. it('should register custom renderer', function () {
  29878. registerRenderer('myRenderer', function (hot, td, row, col, prop, value, cellProperties) {
  29879. td.innerHTML = '--' + value + '--';
  29880. });
  29881. var hot = handsontable({
  29882. data: [[1, 6, 10]],
  29883. columns: [{
  29884. renderer: 'myRenderer'
  29885. }]
  29886. });
  29887. expect(getCell(0, 0).innerHTML).toBe('--1--');
  29888. });
  29889. it('should retrieve predefined renderers by its names', function () {
  29890. expect(getRenderer('autocomplete')).toBeFunction();
  29891. expect(getRenderer('base')).toBeFunction();
  29892. expect(getRenderer('checkbox')).toBeFunction();
  29893. expect(getRenderer('html')).toBeFunction();
  29894. expect(getRenderer('numeric')).toBeFunction();
  29895. expect(getRenderer('password')).toBeFunction();
  29896. expect(getRenderer('text')).toBeFunction();
  29897. });
  29898. it('should retrieve custom renderer by its names', function () {
  29899. var spy = jasmine.createSpy();
  29900. registerRenderer('myRenderer', spy);
  29901. getRenderer('myRenderer')(1, 2, 3, 4, 5, 6);
  29902. expect(spy).toHaveBeenCalledWith(1, 2, 3, 4, 5, 6);
  29903. });
  29904. });
  29905. /***/ }),
  29906. /* 223 */
  29907. /***/ (function(module, exports, __webpack_require__) {
  29908. "use strict";
  29909. describe('NumericRenderer', function () {
  29910. var id = 'testContainer';
  29911. beforeEach(function () {
  29912. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  29913. });
  29914. afterEach(function () {
  29915. if (this.$container) {
  29916. destroy();
  29917. this.$container.remove();
  29918. }
  29919. });
  29920. it('should render formatted number', function (done) {
  29921. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  29922. handsontable({
  29923. cells: function cells() {
  29924. return {
  29925. type: 'numeric',
  29926. format: '$0,0.00'
  29927. };
  29928. },
  29929. afterValidate: onAfterValidate
  29930. });
  29931. setDataAtCell(2, 2, '1000.234');
  29932. setTimeout(function () {
  29933. expect(getCell(2, 2).innerHTML).toEqual('$1,000.23');
  29934. done();
  29935. }, 200);
  29936. });
  29937. it('should render signed number', function (done) {
  29938. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  29939. handsontable({
  29940. cells: function cells() {
  29941. return {
  29942. type: 'numeric',
  29943. format: '$0,0.00'
  29944. };
  29945. },
  29946. afterValidate: onAfterValidate
  29947. });
  29948. setDataAtCell(2, 2, '-1000.234');
  29949. setTimeout(function () {
  29950. expect(getCell(2, 2).innerHTML).toEqual('-$1,000.23');
  29951. done();
  29952. }, 200);
  29953. });
  29954. it('should try to render string as numeral', function (done) {
  29955. handsontable({
  29956. cells: function cells() {
  29957. return {
  29958. type: 'numeric',
  29959. format: '$0,0.00'
  29960. };
  29961. }
  29962. });
  29963. setDataAtCell(2, 2, '123 simple test');
  29964. setTimeout(function () {
  29965. expect(getCell(2, 2).innerHTML).toEqual('$123.00');
  29966. done();
  29967. }, 100);
  29968. });
  29969. it('should add class names `htNumeric` and `htRight` to the cell if it renders a number', function () {
  29970. var DIV = document.createElement('DIV');
  29971. var instance = new Handsontable(DIV, {});
  29972. var TD = document.createElement('TD');
  29973. TD.className = 'someClass';
  29974. Handsontable.renderers.NumericRenderer(instance, TD, 0, 0, 0, 123, {});
  29975. expect(TD.className).toEqual('someClass htRight htNumeric');
  29976. instance.destroy();
  29977. });
  29978. it('should add class names `htNumeric` and `htRight` to the cell if it renders a numeric string', function () {
  29979. var DIV = document.createElement('DIV');
  29980. var instance = new Handsontable(DIV, {});
  29981. var TD = document.createElement('TD');
  29982. TD.className = 'someClass';
  29983. Handsontable.renderers.NumericRenderer(instance, TD, 0, 0, 0, '123', {});
  29984. expect(TD.className).toEqual('someClass htRight htNumeric');
  29985. instance.destroy();
  29986. });
  29987. it('should not add class name `htNumeric` to the cell if it renders a text', function () {
  29988. var DIV = document.createElement('DIV');
  29989. var instance = new Handsontable(DIV, {});
  29990. var TD = document.createElement('TD');
  29991. TD.className = 'someClass';
  29992. Handsontable.renderers.NumericRenderer(instance, TD, 0, 0, 0, 'abc', {});
  29993. expect(TD.className).toEqual('someClass');
  29994. instance.destroy();
  29995. });
  29996. it('should add class name `htDimmed` to a read only cell', function () {
  29997. var DIV = document.createElement('DIV');
  29998. var instance = new Handsontable(DIV, {});
  29999. var TD = document.createElement('TD');
  30000. Handsontable.renderers.NumericRenderer(instance, TD, 0, 0, 0, 123, { readOnly: true, readOnlyCellClassName: 'htDimmed' });
  30001. expect(TD.className).toContain('htDimmed');
  30002. instance.destroy();
  30003. });
  30004. describe('NumericRenderer with ContextMenu', function () {
  30005. it('should change class name from default `htRight` to `htLeft` after set align in contextMenu', function (done) {
  30006. handsontable({
  30007. startRows: 1,
  30008. startCols: 1,
  30009. contextMenu: ['alignment'],
  30010. cells: function cells() {
  30011. return {
  30012. type: 'numeric',
  30013. format: '$0,0.00'
  30014. };
  30015. },
  30016. height: 100
  30017. });
  30018. setDataAtCell(0, 0, '1000');
  30019. selectCell(0, 0);
  30020. contextMenu();
  30021. var menu = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator');
  30022. menu.simulate('mouseover');
  30023. setTimeout(function () {
  30024. var contextSubMenu = $('.htContextMenuSub_' + menu.text()).find('tbody td').eq(0);
  30025. contextSubMenu.simulate('mousedown');
  30026. contextSubMenu.simulate('mouseup');
  30027. expect($('.handsontable.ht_master .htLeft:not(.htRight)').length).toBe(1);
  30028. done();
  30029. }, 500);
  30030. });
  30031. });
  30032. });
  30033. /***/ }),
  30034. /* 224 */
  30035. /***/ (function(module, exports, __webpack_require__) {
  30036. "use strict";
  30037. describe('passwordRenderer', function () {
  30038. var id = 'testContainer';
  30039. beforeEach(function () {
  30040. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30041. });
  30042. afterEach(function () {
  30043. if (this.$container) {
  30044. destroy();
  30045. this.$container.remove();
  30046. }
  30047. });
  30048. it('should render strings as a sequence of asterisks', function () {
  30049. handsontable({
  30050. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  30051. columns: [{
  30052. renderer: Handsontable.renderers.PasswordRenderer
  30053. }]
  30054. });
  30055. expect(getRenderedValue(0, 0)).toMatch(/^[*]+$/ig);
  30056. expect(getRenderedValue(1, 0)).toMatch(/^[*]+$/ig);
  30057. expect(getRenderedValue(2, 0)).toMatch(/^[*]+$/ig);
  30058. expect(getRenderedValue(3, 0)).toMatch(/^[*]+$/ig);
  30059. });
  30060. it('should render numbers as a sequence of asterisks ', function () {
  30061. handsontable({
  30062. data: [[1], [1234], [9090], [0]],
  30063. columns: [{
  30064. renderer: Handsontable.renderers.PasswordRenderer
  30065. }]
  30066. });
  30067. expect(getRenderedValue(0, 0)).toMatch(/^[*]+$/ig);
  30068. expect(getRenderedValue(1, 0)).toMatch(/^[*]+$/ig);
  30069. expect(getRenderedValue(2, 0)).toMatch(/^[*]+$/ig);
  30070. expect(getRenderedValue(3, 0)).toMatch(/^[*]+$/ig);
  30071. });
  30072. it('should be possible to set passwordRenderer with column \'type\' parameter', function () {
  30073. handsontable({
  30074. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  30075. columns: [{
  30076. type: 'password'
  30077. }]
  30078. });
  30079. expect(getRenderedValue(0, 0)).toMatch(/^[*]+$/ig);
  30080. expect(getRenderedValue(1, 0)).toMatch(/^[*]+$/ig);
  30081. expect(getRenderedValue(2, 0)).toMatch(/^[*]+$/ig);
  30082. expect(getRenderedValue(3, 0)).toMatch(/^[*]+$/ig);
  30083. });
  30084. it('should be possible to set passwordRenderer using alias \'password\'', function () {
  30085. handsontable({
  30086. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  30087. columns: [{
  30088. renderer: 'password'
  30089. }]
  30090. });
  30091. expect(getRenderedValue(0, 0)).toMatch(/^[*]+$/ig);
  30092. expect(getRenderedValue(1, 0)).toMatch(/^[*]+$/ig);
  30093. expect(getRenderedValue(2, 0)).toMatch(/^[*]+$/ig);
  30094. expect(getRenderedValue(3, 0)).toMatch(/^[*]+$/ig);
  30095. });
  30096. it('should render strings as a sequence of asterisks, of width matching the original value width', function () {
  30097. handsontable({
  30098. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  30099. columns: [{
  30100. renderer: Handsontable.renderers.PasswordRenderer
  30101. }]
  30102. });
  30103. expect(getRenderedValue(0, 0).length).toEqual(getDataAtCell(0, 0).length);
  30104. expect(getRenderedValue(1, 0).length).toEqual(getDataAtCell(1, 0).length);
  30105. expect(getRenderedValue(2, 0).length).toEqual(getDataAtCell(2, 0).length);
  30106. expect(getRenderedValue(3, 0).length).toEqual(getDataAtCell(3, 0).length);
  30107. });
  30108. it('should render strings as a sequence of asterisks, of fixed width', function () {
  30109. handsontable({
  30110. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  30111. columns: [{
  30112. renderer: Handsontable.renderers.PasswordRenderer,
  30113. hashLength: 10
  30114. }]
  30115. });
  30116. expect(getRenderedValue(0, 0).length).toEqual(10);
  30117. expect(getRenderedValue(1, 0).length).toEqual(10);
  30118. expect(getRenderedValue(2, 0).length).toEqual(10);
  30119. expect(getRenderedValue(3, 0).length).toEqual(10);
  30120. });
  30121. it('should render strings as a sequence of custom symbols', function () {
  30122. handsontable({
  30123. data: [[1, 'Joe'], [2, 'Timothy'], [3, 'Margaret'], [4, 'Jerry']],
  30124. columns: [{
  30125. renderer: Handsontable.renderers.PasswordRenderer,
  30126. hashSymbol: '#'
  30127. }, {
  30128. renderer: Handsontable.renderers.PasswordRenderer,
  30129. hashSymbol: 'x'
  30130. }]
  30131. });
  30132. expect(getRenderedValue(0, 0)).toMatch(/^[#]+$/ig);
  30133. expect(getRenderedValue(1, 0)).toMatch(/^[#]+$/ig);
  30134. expect(getRenderedValue(2, 0)).toMatch(/^[#]+$/ig);
  30135. expect(getRenderedValue(3, 0)).toMatch(/^[#]+$/ig);
  30136. expect(getRenderedValue(0, 1)).toMatch(/^[x]+$/ig);
  30137. expect(getRenderedValue(1, 1)).toMatch(/^[x]+$/ig);
  30138. expect(getRenderedValue(2, 1)).toMatch(/^[x]+$/ig);
  30139. expect(getRenderedValue(3, 1)).toMatch(/^[x]+$/ig);
  30140. });
  30141. });
  30142. /***/ }),
  30143. /* 225 */
  30144. /***/ (function(module, exports, __webpack_require__) {
  30145. "use strict";
  30146. describe('TextRenderer', function () {
  30147. var id = 'testContainer';
  30148. beforeEach(function () {
  30149. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30150. });
  30151. afterEach(function () {
  30152. if (this.$container) {
  30153. destroy();
  30154. this.$container.remove();
  30155. }
  30156. });
  30157. it('should render string', function () {
  30158. handsontable();
  30159. setDataAtCell(2, 2, 'string');
  30160. expect(getCell(2, 2).innerHTML).toEqual('string');
  30161. });
  30162. it('should render number', function () {
  30163. handsontable();
  30164. setDataAtCell(2, 2, 13);
  30165. expect(getCell(2, 2).innerHTML).toEqual('13');
  30166. });
  30167. it('should render boolean true', function () {
  30168. handsontable();
  30169. setDataAtCell(2, 2, true);
  30170. expect(getCell(2, 2).innerHTML).toEqual('true');
  30171. });
  30172. it('should render boolean false', function () {
  30173. handsontable();
  30174. setDataAtCell(2, 2, false);
  30175. expect(getCell(2, 2).innerHTML).toEqual('false');
  30176. });
  30177. it('should render null', function () {
  30178. handsontable();
  30179. setDataAtCell(2, 2, null);
  30180. expect(getCell(2, 2).innerHTML).toEqual('');
  30181. });
  30182. it('should render undefined', function () {
  30183. handsontable();
  30184. /* eslint-disable wrap-iife */
  30185. setDataAtCell(2, 2, function () {}());
  30186. expect(getCell(2, 2).innerHTML).toEqual('');
  30187. });
  30188. it('should add class name `htDimmed` to a read only cell', function () {
  30189. var DIV = document.createElement('DIV');
  30190. var instance = new Handsontable.Core(DIV, {});
  30191. var TD = document.createElement('TD');
  30192. TD.className = 'someClass';
  30193. Handsontable.renderers.TextRenderer(instance, TD, 0, 0, 0, '', { readOnly: true, readOnlyCellClassName: 'htDimmed' });
  30194. expect(TD.className).toEqual('someClass htDimmed');
  30195. instance.destroy();
  30196. });
  30197. it('should render a multiline string', function () {
  30198. handsontable();
  30199. setDataAtCell(1, 2, 'a b');
  30200. setDataAtCell(2, 2, 'a\nb');
  30201. expect($(getCell(2, 2)).height()).toBeGreaterThan($(getCell(1, 2)).height());
  30202. });
  30203. it('should wrap text when column width is limited', function () {
  30204. handsontable({
  30205. colWidths: [100]
  30206. });
  30207. setDataAtCell(0, 0, 'short text');
  30208. setDataAtCell(1, 0, 'long long long long long long long text');
  30209. expect($(getCell(1, 0)).height()).toBeGreaterThan($(getCell(0, 0)).height());
  30210. });
  30211. });
  30212. /***/ }),
  30213. /* 226 */
  30214. /***/ (function(module, exports, __webpack_require__) {
  30215. "use strict";
  30216. describe('settings', function () {
  30217. describe('colWidths', function () {
  30218. var id = 'testContainer';
  30219. beforeEach(function () {
  30220. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30221. });
  30222. afterEach(function () {
  30223. if (this.$container) {
  30224. destroy();
  30225. this.$container.remove();
  30226. }
  30227. });
  30228. describe('defined in constructor', function () {
  30229. it('should consider colWidths provided as number', function () {
  30230. handsontable({
  30231. colWidths: 123
  30232. });
  30233. expect(colWidth(this.$container, 0)).toBe(123);
  30234. });
  30235. it('should consider colWidths provided as string', function () {
  30236. handsontable({
  30237. colWidths: '123'
  30238. });
  30239. expect(colWidth(this.$container, 0)).toBe(123);
  30240. });
  30241. it('should consider colWidths provided as array of numbers', function () {
  30242. handsontable({
  30243. colWidths: [123]
  30244. });
  30245. expect(colWidth(this.$container, 0)).toBe(123);
  30246. });
  30247. it('should consider colWidths provided as array of strings', function () {
  30248. handsontable({
  30249. colWidths: ['123']
  30250. });
  30251. expect(colWidth(this.$container, 0)).toBe(123);
  30252. });
  30253. it('should consider colWidth provided as function that returns number', function () {
  30254. handsontable({
  30255. colWidths: function colWidths(index) {
  30256. if (index === 0) {
  30257. return 123;
  30258. }
  30259. return 50;
  30260. }
  30261. });
  30262. expect(colWidth(this.$container, 0)).toBe(123);
  30263. });
  30264. it('should consider colWidth provided as function that returns string', function () {
  30265. handsontable({
  30266. colWidths: function colWidths(index) {
  30267. if (index === 0) {
  30268. return '123';
  30269. }
  30270. return '50';
  30271. }
  30272. });
  30273. expect(colWidth(this.$container, 0)).toBe(123);
  30274. });
  30275. });
  30276. describe('defined in updateSettings', function () {
  30277. it('should consider colWidths provided as number', function () {
  30278. handsontable();
  30279. updateSettings({
  30280. colWidths: 123
  30281. });
  30282. expect(colWidth(this.$container, 0)).toBe(123);
  30283. });
  30284. it('should consider colWidths provided as string', function () {
  30285. handsontable();
  30286. updateSettings({
  30287. colWidths: '123'
  30288. });
  30289. expect(colWidth(this.$container, 0)).toBe(123);
  30290. });
  30291. it('should consider colWidths provided as array of numbers', function () {
  30292. handsontable();
  30293. updateSettings({
  30294. colWidths: [123]
  30295. });
  30296. expect(colWidth(this.$container, 0)).toBe(123);
  30297. });
  30298. it('should consider colWidths provided as array of strings', function () {
  30299. handsontable();
  30300. updateSettings({
  30301. colWidths: ['123']
  30302. });
  30303. expect(colWidth(this.$container, 0)).toBe(123);
  30304. });
  30305. it('should consider colWidth provided as function that returns number', function () {
  30306. handsontable();
  30307. updateSettings({
  30308. colWidths: function colWidths(index) {
  30309. if (index === 0) {
  30310. return 123;
  30311. }
  30312. return 50;
  30313. }
  30314. });
  30315. expect(colWidth(this.$container, 0)).toBe(123);
  30316. });
  30317. it('should consider colWidth provided as function that returns string', function () {
  30318. handsontable();
  30319. updateSettings({
  30320. colWidths: function colWidths(index) {
  30321. if (index === 0) {
  30322. return '123';
  30323. }
  30324. return '50';
  30325. }
  30326. });
  30327. expect(colWidth(this.$container, 0)).toBe(123);
  30328. });
  30329. });
  30330. describe('defined in columns', function () {
  30331. it('should consider width provided as number', function () {
  30332. handsontable({
  30333. columns: [{
  30334. width: 123
  30335. }]
  30336. });
  30337. expect(colWidth(this.$container, 0)).toBe(123);
  30338. });
  30339. it('should consider width provided as string', function () {
  30340. handsontable({
  30341. columns: [{
  30342. width: '123'
  30343. }]
  30344. });
  30345. expect(colWidth(this.$container, 0)).toBe(123);
  30346. });
  30347. it('should consider width provided as array of numbers', function () {
  30348. handsontable({
  30349. columns: [{
  30350. width: [123]
  30351. }]
  30352. });
  30353. expect(colWidth(this.$container, 0)).toBe(123);
  30354. });
  30355. it('should consider width provided as array of strings', function () {
  30356. handsontable({
  30357. columns: [{
  30358. width: ['123']
  30359. }]
  30360. });
  30361. expect(colWidth(this.$container, 0)).toBe(123);
  30362. });
  30363. it('should consider width provided as function that returns number', function () {
  30364. handsontable({
  30365. columns: [{
  30366. width: function width(index) {
  30367. if (index === 0) {
  30368. return 123;
  30369. }
  30370. return 50;
  30371. }
  30372. }]
  30373. });
  30374. expect(colWidth(this.$container, 0)).toBe(123);
  30375. });
  30376. it('should consider width provided as function that returns string', function () {
  30377. handsontable({
  30378. columns: [{
  30379. width: function width(index) {
  30380. if (index === 0) {
  30381. return '123';
  30382. }
  30383. return '50';
  30384. }
  30385. }]
  30386. });
  30387. expect(colWidth(this.$container, 0)).toBe(123);
  30388. });
  30389. });
  30390. describe('defined in cells', function () {
  30391. it('should consider width provided as number', function () {
  30392. handsontable({
  30393. cells: function cells(row, col) {
  30394. if (col === 0) {
  30395. this.width = 123;
  30396. }
  30397. }
  30398. });
  30399. expect(colWidth(this.$container, 0)).toBe(123);
  30400. });
  30401. it('should consider width provided as string', function () {
  30402. handsontable({
  30403. cells: function cells(row, col) {
  30404. if (col === 0) {
  30405. this.width = '123';
  30406. }
  30407. }
  30408. });
  30409. expect(colWidth(this.$container, 0)).toBe(123);
  30410. });
  30411. });
  30412. });
  30413. });
  30414. /***/ }),
  30415. /* 227 */
  30416. /***/ (function(module, exports, __webpack_require__) {
  30417. "use strict";
  30418. describe('settings', function () {
  30419. describe('columns', function () {
  30420. var id = 'testContainer';
  30421. var arrayOfArrays = function arrayOfArrays() {
  30422. return [['', 'Kia', 'Nissan', 'Toyota', 'Honda'], ['2008', 10, 11, 12, 13], ['2009', 20, 11, 14, 13], ['2010', 30, 15, 12, 13]];
  30423. };
  30424. var arrayOfObjects = function arrayOfObjects() {
  30425. return [{ id: 1, name: 'Ted', lastName: 'Right', date: '01/01/2015' }, { id: 2, name: 'Frank', lastName: 'Honest', date: '01/01/15' }, { id: 3, name: 'Joan', lastName: 'Well', date: '41/01/2015' }, { id: 4, name: 'Sid', lastName: 'Strong', date: '01/51/2015' }, { id: 5, name: 'Jane', lastName: 'Neat', date: '01/01/2015' }, { id: 6, name: 'Chuck', lastName: 'Jackson', date: '01/01/15' }, { id: 7, name: 'Meg', lastName: 'Jansen', date: '41/01/2015' }, { id: 8, name: 'Rob', lastName: 'Norris', date: '01/51/2015' }, { id: 9, name: 'Sean', lastName: 'O\'Hara', date: '01/01/2015' }, { id: 10, name: 'Eve', lastName: 'Branson', date: '01/01/15' }];
  30426. };
  30427. beforeEach(function () {
  30428. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30429. });
  30430. afterEach(function () {
  30431. if (this.$container) {
  30432. destroy();
  30433. this.$container.remove();
  30434. }
  30435. });
  30436. describe('as an array of objects', function () {
  30437. it('should not throw exception when passed columns array is empty (data source as array of arrays)', function () {
  30438. var hot = handsontable({
  30439. data: arrayOfArrays(),
  30440. columns: [{ data: 0 }, { data: 1 }, { data: 2 }]
  30441. });
  30442. expect(function () {
  30443. hot.updateSettings({ columns: [] });
  30444. }).not.toThrow();
  30445. });
  30446. it('should not throw exception when passed columns array is empty (data source as array of objects)', function () {
  30447. var hot = handsontable({
  30448. data: arrayOfObjects(),
  30449. columns: [{ data: 'id' }, { data: 'name' }, { data: 'lastName' }]
  30450. });
  30451. expect(function () {
  30452. hot.updateSettings({ columns: [] });
  30453. }).not.toThrow();
  30454. });
  30455. });
  30456. describe('as a function', function () {
  30457. describe('init', function () {
  30458. it('should render only these columns which are not `null`', function () {
  30459. var hot = handsontable({
  30460. data: arrayOfArrays(),
  30461. columns: function columns(column) {
  30462. return [1, 2].indexOf(column) > -1 ? {} : null;
  30463. }
  30464. });
  30465. expect(hot.getData()[0].length).toEqual(2);
  30466. });
  30467. it('should properly bind default data when is not defined (data source as array of arrays)', function () {
  30468. var hot = handsontable({
  30469. data: arrayOfArrays(),
  30470. columns: function columns(column) {
  30471. return [1, 2].indexOf(column) > -1 ? {} : null;
  30472. }
  30473. });
  30474. expect(hot.getDataAtCell(0, 0)).toEqual('');
  30475. expect(hot.getDataAtCell(0, 1)).toEqual('Kia');
  30476. });
  30477. it('should properly bind default data when is not defined (data source as array of objects)', function () {
  30478. var hot = handsontable({
  30479. data: arrayOfObjects(),
  30480. columns: function columns(column) {
  30481. return [1, 2].indexOf(column) > -1 ? {} : null;
  30482. }
  30483. });
  30484. expect(hot.getDataAtCell(0, 0)).toEqual(null);
  30485. expect(hot.getDataAtCell(0, 1)).toEqual(null);
  30486. });
  30487. it('should properly bind defined data (data source as array of arrays)', function () {
  30488. var hot = handsontable({
  30489. data: arrayOfArrays(),
  30490. columns: function columns(column) {
  30491. return [1, 2].indexOf(column) > -1 ? { data: column + 1 } : null;
  30492. }
  30493. });
  30494. expect(hot.getDataAtCell(0, 0)).toEqual('Nissan');
  30495. expect(hot.getDataAtCell(0, 1)).toEqual('Toyota');
  30496. });
  30497. it('should properly bind defined data (data source as array of objects)', function () {
  30498. var hot = handsontable({
  30499. data: arrayOfObjects(),
  30500. columns: function columns(column) {
  30501. var keys = ['id', 'name', 'lastName'];
  30502. return [1, 2].indexOf(column) > -1 ? { data: keys[column - 1] } : null;
  30503. }
  30504. });
  30505. expect(hot.getDataAtCell(0, 0)).toEqual(1);
  30506. expect(hot.getDataAtCell(0, 1)).toEqual('Ted');
  30507. });
  30508. });
  30509. describe('updateSettings', function () {
  30510. it('should not throw exception when passed columns function without return anything (data source as array of arrays) when columns is a function', function () {
  30511. var hot = handsontable({
  30512. data: arrayOfArrays(),
  30513. columns: function columns(column) {
  30514. return [0, 1, 2].indexOf(column) > -1 ? { data: column } : null;
  30515. }
  30516. });
  30517. expect(function () {
  30518. hot.updateSettings({
  30519. columns: function columns() {}
  30520. });
  30521. }).not.toThrow();
  30522. });
  30523. it('should not throw exception when passed columns function without return anything (data source as array of objects) when columns is a function', function () {
  30524. var hot = handsontable({
  30525. data: arrayOfObjects(),
  30526. columns: function columns(column) {
  30527. var keys = ['id', 'name', 'lasName'];
  30528. return [0, 1, 2].indexOf(column) > -1 ? { data: keys[column] } : null;
  30529. }
  30530. });
  30531. expect(function () {
  30532. hot.updateSettings({
  30533. columns: function columns() {}
  30534. });
  30535. }).not.toThrow();
  30536. });
  30537. });
  30538. describe('editors', function () {
  30539. it('should properly bind defined editors', function () {
  30540. handsontable({
  30541. data: [['Joe'], ['Timothy'], ['Margaret'], ['Jerry']],
  30542. columns: function columns(column) {
  30543. return column === 0 ? { editor: Handsontable.editors.PasswordEditor } : null;
  30544. }
  30545. });
  30546. selectCell(0, 0);
  30547. keyDown('enter');
  30548. var editor = $('.handsontableInput');
  30549. expect(editor.is(':visible')).toBe(true);
  30550. expect(editor.is(':password')).toBe(true);
  30551. });
  30552. });
  30553. describe('renderers', function () {
  30554. it('should properly bind defined renderer', function () {
  30555. handsontable({
  30556. data: [[true], [false], [true]],
  30557. columns: function columns(column) {
  30558. return column === 0 ? { type: 'checkbox' } : null;
  30559. }
  30560. });
  30561. expect($(getRenderedValue(0, 0)).is(':checkbox')).toBe(true);
  30562. expect($(getRenderedValue(1, 0)).is(':checkbox')).toBe(true);
  30563. expect($(getRenderedValue(2, 0)).is(':checkbox')).toBe(true);
  30564. });
  30565. });
  30566. describe('validators', function () {
  30567. it('should properly bind defined validator', function (done) {
  30568. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  30569. handsontable({
  30570. data: arrayOfObjects(),
  30571. columns: function columns(column) {
  30572. var settings = [{ data: 'date', type: 'date' }, { data: 'name' }, { data: 'lastName' }];
  30573. return [0, 1, 2].indexOf(column) > -1 ? settings[column] : null;
  30574. },
  30575. afterValidate: onAfterValidate
  30576. });
  30577. setDataAtCell(0, 0, '');
  30578. setTimeout(function () {
  30579. expect(onAfterValidate).toHaveBeenCalledWith(true, '', 0, 'date', undefined, undefined);
  30580. done();
  30581. }, 100);
  30582. });
  30583. });
  30584. });
  30585. });
  30586. });
  30587. /***/ }),
  30588. /* 228 */
  30589. /***/ (function(module, exports, __webpack_require__) {
  30590. "use strict";
  30591. describe('settings', function () {
  30592. describe('copyable', function () {
  30593. var id = 'testContainer';
  30594. beforeEach(function () {
  30595. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30596. });
  30597. afterEach(function () {
  30598. if (this.$container) {
  30599. destroy();
  30600. this.$container.remove();
  30601. }
  30602. });
  30603. it('by default, CTRL+C should NOT copy the password value', function () {
  30604. handsontable({
  30605. data: [['Joe', 'Secret', 'Jack']],
  30606. columns: [{}, {
  30607. type: 'password'
  30608. }, {}]
  30609. });
  30610. expect(getCopyableText(0, 0, 0, 2)).toMatch('Joe\t\tJack');
  30611. });
  30612. it('with copyable=true, CTRL+C should copy the password value', function () {
  30613. handsontable({
  30614. data: [['Joe', 'Secret', 'Jack']],
  30615. columns: [{}, {
  30616. type: 'password',
  30617. copyable: true
  30618. }, {}]
  30619. });
  30620. expect(getCopyableText(0, 0, 0, 2)).toMatch('Joe\tSecret\tJack');
  30621. });
  30622. it('with copyable=false, CTRL+C should NOT copy the password value', function () {
  30623. handsontable({
  30624. data: [['Joe', 'Secret', 'Jack']],
  30625. columns: [{}, {
  30626. type: 'password',
  30627. copyable: false
  30628. }, {}]
  30629. });
  30630. expect(getCopyableText(0, 0, 0, 2)).toMatch('Joe\t\tJack');
  30631. });
  30632. });
  30633. });
  30634. /***/ }),
  30635. /* 229 */
  30636. /***/ (function(module, exports, __webpack_require__) {
  30637. "use strict";
  30638. describe('settings', function () {
  30639. var id = 'testContainer';
  30640. beforeEach(function () {
  30641. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30642. });
  30643. afterEach(function () {
  30644. if (this.$container) {
  30645. destroy();
  30646. this.$container.remove();
  30647. }
  30648. });
  30649. describe('currentHeaderClassName', function () {
  30650. it('should apply default currentHeaderClassName to cells in row where there is a selection', function () {
  30651. handsontable({
  30652. rowHeaders: true,
  30653. colHeaders: true,
  30654. data: Handsontable.helper.createSpreadsheetData(5, 7)
  30655. });
  30656. selectCell(2, 2);
  30657. expect(this.$container.find('.ht_master th.ht__highlight').length).toEqual(2);
  30658. });
  30659. it('should apply default currentHeaderClassName from cells after deselection', function () {
  30660. handsontable({
  30661. rowHeaders: true,
  30662. colHeaders: true,
  30663. data: Handsontable.helper.createSpreadsheetData(5, 7)
  30664. });
  30665. selectCell(2, 2);
  30666. deselectCell();
  30667. expect(this.$container.find('.ht_master th.ht__highlight').length).toEqual(0);
  30668. });
  30669. it('should apply custom currentHeaderClassName to cells in row where there is a selection', function () {
  30670. handsontable({
  30671. rowHeaders: true,
  30672. colHeaders: true,
  30673. data: Handsontable.helper.createSpreadsheetData(5, 7),
  30674. currentHeaderClassName: 'currentHeaderClassName'
  30675. });
  30676. selectCell(2, 2);
  30677. expect(this.$container.find('.ht_master th.currentHeaderClassName').length).toEqual(2);
  30678. });
  30679. });
  30680. });
  30681. /***/ }),
  30682. /* 230 */
  30683. /***/ (function(module, exports, __webpack_require__) {
  30684. "use strict";
  30685. describe('settings', function () {
  30686. var id = 'testContainer';
  30687. beforeEach(function () {
  30688. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30689. });
  30690. afterEach(function () {
  30691. if (this.$container) {
  30692. destroy();
  30693. this.$container.remove();
  30694. }
  30695. });
  30696. describe('currentRowClassName', function () {
  30697. it('should apply currentRowClassName to cells in row where there is a selection', function () {
  30698. handsontable({
  30699. data: Handsontable.helper.createSpreadsheetData(5, 7),
  30700. currentRowClassName: 'currentRowClassName'
  30701. });
  30702. selectCell(2, 2);
  30703. expect(this.$container.find('td.currentRowClassName').length).toEqual(6);
  30704. });
  30705. it('should apply currentRowClassName from cells after deselection', function () {
  30706. handsontable({
  30707. data: Handsontable.helper.createSpreadsheetData(5, 7),
  30708. currentRowClassName: 'currentRowClassName'
  30709. });
  30710. selectCell(2, 2);
  30711. deselectCell();
  30712. expect(this.$container.find('td.currentRowClassName').length).toEqual(0);
  30713. });
  30714. });
  30715. describe('currentColClassName', function () {
  30716. it('should apply currentColClassName to cells in row where there is a selection', function () {
  30717. handsontable({
  30718. data: Handsontable.helper.createSpreadsheetData(5, 7),
  30719. currentColClassName: 'currentColClassName'
  30720. });
  30721. selectCell(2, 2);
  30722. expect(this.$container.find('td.currentColClassName').length).toEqual(4);
  30723. });
  30724. it('should remove currentColClassName from cells after deselection', function () {
  30725. handsontable({
  30726. data: Handsontable.helper.createSpreadsheetData(5, 7),
  30727. currentColClassName: 'currentColClassName'
  30728. });
  30729. selectCell(2, 2);
  30730. deselectCell();
  30731. expect(this.$container.find('td.currentColClassName').length).toEqual(0);
  30732. });
  30733. });
  30734. });
  30735. /***/ }),
  30736. /* 231 */
  30737. /***/ (function(module, exports, __webpack_require__) {
  30738. "use strict";
  30739. describe('settings', function () {
  30740. describe('editor', function () {
  30741. var id = 'testContainer';
  30742. beforeEach(function () {
  30743. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30744. });
  30745. afterEach(function () {
  30746. if (this.$container) {
  30747. destroy();
  30748. this.$container.remove();
  30749. }
  30750. });
  30751. describe('defined in constructor', function () {
  30752. it('should use text editor by default', function () {
  30753. var textEditorPrototype = Handsontable.editors.TextEditor.prototype;
  30754. spyOn(textEditorPrototype, 'init').and.callThrough();
  30755. handsontable();
  30756. selectCell(0, 0);
  30757. expect(textEditorPrototype.init).toHaveBeenCalled();
  30758. });
  30759. it('should use editor from predefined string', function () {
  30760. var textEditorPrototype = Handsontable.editors.TextEditor.prototype;
  30761. var checkboxEditorPrototype = Handsontable.editors.CheckboxEditor.prototype;
  30762. spyOn(textEditorPrototype, 'init');
  30763. spyOn(checkboxEditorPrototype, 'init');
  30764. handsontable({
  30765. columns: [{
  30766. editor: 'checkbox'
  30767. }]
  30768. });
  30769. selectCell(0, 0);
  30770. expect(textEditorPrototype.init).not.toHaveBeenCalled();
  30771. expect(checkboxEditorPrototype.init).toHaveBeenCalled();
  30772. });
  30773. it('should use editor from predefined string when columns is a function', function () {
  30774. var textEditorPrototype = Handsontable.editors.TextEditor.prototype;
  30775. var checkboxEditorPrototype = Handsontable.editors.CheckboxEditor.prototype;
  30776. spyOn(textEditorPrototype, 'init');
  30777. spyOn(checkboxEditorPrototype, 'init');
  30778. handsontable({
  30779. columns: function columns(column) {
  30780. return column === 0 ? { editor: 'checkbox' } : null;
  30781. }
  30782. });
  30783. selectCell(0, 0);
  30784. expect(textEditorPrototype.init).not.toHaveBeenCalled();
  30785. expect(checkboxEditorPrototype.init).toHaveBeenCalled();
  30786. });
  30787. it('should use editor class passed directly', function () {
  30788. var customEditor = jasmine.createSpy('customEditor');
  30789. customEditor.and.callFake(function () {
  30790. this.prepare = function () {};
  30791. });
  30792. handsontable({
  30793. columns: [{
  30794. editor: customEditor
  30795. }]
  30796. });
  30797. selectCell(0, 0);
  30798. expect(customEditor).toHaveBeenCalled();
  30799. });
  30800. it('should use editor class passed directly when columns is a function', function () {
  30801. var customEditor = jasmine.createSpy('customEditor');
  30802. customEditor.and.callFake(function () {
  30803. this.prepare = function () {};
  30804. });
  30805. handsontable({
  30806. columns: function columns(column) {
  30807. return column === 0 ? { editor: customEditor } : null;
  30808. }
  30809. });
  30810. selectCell(0, 0);
  30811. expect(customEditor).toHaveBeenCalled();
  30812. });
  30813. it('should use editor from custom string', function () {
  30814. var customEditor = jasmine.createSpy('customEditor');
  30815. customEditor.and.callFake(function () {
  30816. this.prepare = function () {};
  30817. });
  30818. Handsontable.editors.registerEditor('myEditor', customEditor);
  30819. handsontable({
  30820. columns: [{
  30821. editor: 'myEditor'
  30822. }]
  30823. });
  30824. selectCell(0, 0);
  30825. expect(customEditor).toHaveBeenCalled();
  30826. });
  30827. it('should use editor from custom string when columns is a function', function () {
  30828. var customEditor = jasmine.createSpy('customEditor');
  30829. customEditor.and.callFake(function () {
  30830. this.prepare = function () {};
  30831. });
  30832. Handsontable.editors.registerEditor('myEditor', customEditor);
  30833. handsontable({
  30834. columns: function columns(column) {
  30835. return column === 0 ? { editor: 'myEditor' } : null;
  30836. }
  30837. });
  30838. selectCell(0, 0);
  30839. expect(customEditor).toHaveBeenCalled();
  30840. });
  30841. });
  30842. });
  30843. });
  30844. /***/ }),
  30845. /* 232 */
  30846. /***/ (function(module, exports, __webpack_require__) {
  30847. "use strict";
  30848. describe('settings', function () {
  30849. describe('fixedColumnsLeft', function () {
  30850. var id = 'testContainer';
  30851. beforeEach(function () {
  30852. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30853. });
  30854. afterEach(function () {
  30855. if (this.$container) {
  30856. destroy();
  30857. this.$container.remove();
  30858. }
  30859. });
  30860. describe('defined in constructor', function () {
  30861. it('should show columns headers', function () {
  30862. handsontable({
  30863. fixedColumnsLeft: 3
  30864. });
  30865. expect(getLeftClone().find('tbody tr:eq(0) td').length).toEqual(3);
  30866. });
  30867. it('should show columns headers when headers are enabled', function () {
  30868. handsontable({
  30869. rowHeaders: true,
  30870. colHeaders: true,
  30871. fixedColumnsLeft: 2
  30872. });
  30873. expect(getLeftClone().find('thead tr th').length).toEqual(3);
  30874. expect(getLeftClone().find('tbody tr:eq(0) td').length).toEqual(2);
  30875. });
  30876. });
  30877. describe('defined in updateSettings', function () {
  30878. it('should increase fixed columns', function () {
  30879. handsontable({
  30880. fixedColumnsLeft: 2
  30881. });
  30882. updateSettings({
  30883. fixedColumnsLeft: 4
  30884. });
  30885. expect(getLeftClone().find('tbody tr:eq(0) td').length).toEqual(4);
  30886. });
  30887. it('should decrease fixed columns', function () {
  30888. handsontable({
  30889. fixedColumnsLeft: 4
  30890. });
  30891. updateSettings({
  30892. fixedColumnsLeft: 2
  30893. });
  30894. expect(getLeftClone().find('tbody tr:eq(0) td').length).toEqual(2);
  30895. });
  30896. it('should create fixed columns when they are disabled eariler', function () {
  30897. handsontable({
  30898. fixedColumnsLeft: 0
  30899. });
  30900. updateSettings({
  30901. fixedColumnsLeft: 2
  30902. });
  30903. expect(getLeftClone().find('tbody tr:eq(0) td').length).toEqual(2);
  30904. });
  30905. it('should disable fixed columns', function () {
  30906. handsontable({
  30907. fixedColumnsLeft: 2
  30908. });
  30909. updateSettings({
  30910. fixedColumnsLeft: 0
  30911. });
  30912. expect(getLeftClone().find('tbody tr:eq(0) td').length).toEqual(2);
  30913. expect(getLeftClone().width()).toBe(0);
  30914. });
  30915. it('should not throw errors while scrolling horizontally when fixed columns was set', function (done) {
  30916. var spy = jasmine.createSpyObj('error', ['test']);
  30917. var prevError = window.onerror;
  30918. window.onerror = function (messageOrEvent, source, lineno, colno, error) {
  30919. spy.test();
  30920. };
  30921. var hot = handsontable({
  30922. data: Handsontable.helper.createSpreadsheetData(50, 50),
  30923. width: 200,
  30924. height: 200,
  30925. colHeaders: true
  30926. });
  30927. updateSettings({
  30928. fixedColumnsLeft: 2
  30929. });
  30930. setTimeout(function () {
  30931. hot.scrollViewportTo(30, 30);
  30932. }, 100);
  30933. setTimeout(function () {
  30934. expect(spy.test.calls.count()).toBe(0);
  30935. done();
  30936. window.onerror = prevError;
  30937. }, 200);
  30938. });
  30939. });
  30940. });
  30941. });
  30942. /***/ }),
  30943. /* 233 */
  30944. /***/ (function(module, exports, __webpack_require__) {
  30945. "use strict";
  30946. describe('settings', function () {
  30947. describe('fixedRowsTop', function () {
  30948. var id = 'testContainer';
  30949. beforeEach(function () {
  30950. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  30951. });
  30952. afterEach(function () {
  30953. if (this.$container) {
  30954. destroy();
  30955. this.$container.remove();
  30956. }
  30957. });
  30958. describe('defined in constructor', function () {
  30959. it('should show rows headers', function () {
  30960. handsontable({
  30961. fixedRowsTop: 3
  30962. });
  30963. expect(getTopClone().find('tbody tr').length).toEqual(3);
  30964. });
  30965. it('should show rows headers when headers are enabled', function () {
  30966. handsontable({
  30967. rowHeaders: true,
  30968. colHeaders: true,
  30969. fixedRowsTop: 2
  30970. });
  30971. expect(getTopClone().find('thead tr').length).toEqual(1);
  30972. expect(getTopClone().find('tbody tr').length).toEqual(2);
  30973. });
  30974. });
  30975. describe('defined in updateSettings', function () {
  30976. it('should increase fixed rows', function () {
  30977. handsontable({
  30978. fixedRowsTop: 2
  30979. });
  30980. updateSettings({
  30981. fixedRowsTop: 4
  30982. });
  30983. expect(getTopClone().find('tbody tr').length).toEqual(4);
  30984. });
  30985. it('should decrease fixed rows', function () {
  30986. handsontable({
  30987. fixedRowsTop: 4
  30988. });
  30989. updateSettings({
  30990. fixedRowsTop: 2
  30991. });
  30992. expect(getTopClone().find('tbody tr').length).toEqual(2);
  30993. });
  30994. it('should create fixed rows when they are disabled eariler', function () {
  30995. handsontable({
  30996. fixedRowsTop: 0
  30997. });
  30998. updateSettings({
  30999. fixedRowsTop: 2
  31000. });
  31001. expect(getTopClone().find('tbody tr').length).toEqual(2);
  31002. });
  31003. it('should disable fixed rows', function () {
  31004. handsontable({
  31005. fixedRowsTop: 2
  31006. });
  31007. updateSettings({
  31008. fixedRowsTop: 0
  31009. });
  31010. expect(getTopClone().find('tbody tr').length).toEqual(2);
  31011. expect(getLeftClone().height()).toBe(0);
  31012. });
  31013. it('should not throw errors while scrolling vertically when fixed rows was set', function (done) {
  31014. var spy = jasmine.createSpyObj('error', ['test']);
  31015. var prevError = window.onerror;
  31016. window.onerror = function (messageOrEvent, source, lineno, colno, error) {
  31017. spy.test();
  31018. };
  31019. var hot = handsontable({
  31020. data: Handsontable.helper.createSpreadsheetData(50, 50),
  31021. width: 200,
  31022. height: 200,
  31023. rowHeaders: true
  31024. });
  31025. updateSettings({
  31026. fixedRowsTop: 2
  31027. });
  31028. setTimeout(function () {
  31029. hot.scrollViewportTo(30, 30);
  31030. }, 100);
  31031. setTimeout(function () {
  31032. expect(spy.test.calls.count()).toBe(0);
  31033. done();
  31034. window.onerror = prevError;
  31035. }, 200);
  31036. });
  31037. });
  31038. });
  31039. });
  31040. /***/ }),
  31041. /* 234 */
  31042. /***/ (function(module, exports, __webpack_require__) {
  31043. "use strict";
  31044. describe('settings', function () {
  31045. describe('fragmentSelection', function () {
  31046. var id = 'testContainer';
  31047. beforeEach(function () {
  31048. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  31049. });
  31050. afterEach(function () {
  31051. if (this.$container) {
  31052. destroy();
  31053. this.$container.remove();
  31054. }
  31055. });
  31056. /**
  31057. * Returns current text selection or false if there is no text selection
  31058. * @returns {*}
  31059. */
  31060. function getSelected() {
  31061. /* eslint-disable no-else-return */
  31062. var text = '';
  31063. // IE8
  31064. if (window.getSelection && window.getSelection().toString() && $(window.getSelection()).attr('type') != 'Caret') {
  31065. text = window.getSelection();
  31066. return text.toString();
  31067. } else {
  31068. // standards
  31069. var selection = document.selection && document.selection.createRange();
  31070. if (!(typeof selection === 'undefined') && selection.text && selection.text.toString()) {
  31071. text = selection.text;
  31072. return text.toString();
  31073. }
  31074. }
  31075. return false;
  31076. }
  31077. /**
  31078. * Selects a <fromEl> node at as many siblings as given in the <cells> value
  31079. * Note: IE8 fallback assumes that a node contains exactly one word
  31080. * @param fromEl
  31081. * @param siblings
  31082. */
  31083. function selectElementText(fromEl, siblings) {
  31084. var doc = window.document;
  31085. var sel;
  31086. var range;
  31087. if (window.getSelection && doc.createRange) {
  31088. // standards
  31089. sel = window.getSelection();
  31090. range = doc.createRange();
  31091. range.setStartBefore(fromEl, 0);
  31092. while (siblings > 1) {
  31093. fromEl = fromEl.nextSibling;
  31094. siblings--;
  31095. }
  31096. range.setEndAfter(fromEl, 0);
  31097. sel.removeAllRanges();
  31098. sel.addRange(range);
  31099. } else if (doc.body.createTextRange) {
  31100. // IE8
  31101. range = doc.body.createTextRange();
  31102. range.moveToElementText(fromEl);
  31103. range.moveEnd('word', siblings + 1);
  31104. range.select();
  31105. }
  31106. }
  31107. describe('constructor', function () {
  31108. it('should disallow fragmentSelection when set to false', function () {
  31109. handsontable({
  31110. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31111. fragmentSelection: false
  31112. });
  31113. selectElementText(this.$container.find('tr:eq(0) td:eq(1)')[0], 3);
  31114. mouseDown(this.$container.find('tr:eq(0) td:eq(3)'));
  31115. mouseUp(this.$container.find('tr:eq(0) td:eq(3)'));
  31116. var sel = getSelected();
  31117. expect(sel).toEqual(false);
  31118. });
  31119. it('should allow fragmentSelection when set to true', function () {
  31120. handsontable({
  31121. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31122. fragmentSelection: true
  31123. });
  31124. selectElementText(this.$container.find('td')[1], 3);
  31125. mouseDown(this.$container.find('tr:eq(0) td:eq(3)'));
  31126. mouseUp(this.$container.find('tr:eq(0) td:eq(3)'));
  31127. var sel = getSelected();
  31128. sel = sel.replace(/\s/g, ''); // tabs and spaces between <td>s are inconsistent in browsers, so let's ignore them
  31129. expect(sel).toEqual('B1C1D1');
  31130. });
  31131. it('should allow fragmentSelection from one cell when set to `cell`', function () {
  31132. var hot = handsontable({
  31133. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31134. fragmentSelection: 'cell'
  31135. });
  31136. selectElementText(this.$container.find('td')[1], 1);
  31137. mouseDown(this.$container.find('tr:eq(0) td:eq(1)'));
  31138. mouseOver(this.$container.find('tr:eq(0) td:eq(1)'));
  31139. mouseMove(this.$container.find('tr:eq(0) td:eq(1)'));
  31140. mouseUp(this.$container.find('tr:eq(0) td:eq(1)'));
  31141. expect(getSelected().replace(/\s/g, '')).toEqual('B1');
  31142. });
  31143. it('should disallow fragmentSelection from one cell when set to `cell` and when user selects adjacent cell', function () {
  31144. var hot = handsontable({
  31145. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31146. fragmentSelection: 'cell'
  31147. });
  31148. selectElementText(this.$container.find('td')[1], 1);
  31149. mouseDown(this.$container.find('tr:eq(0) td:eq(1)'));
  31150. mouseOver(this.$container.find('tr:eq(0) td:eq(2)'));
  31151. mouseMove(this.$container.find('tr:eq(0) td:eq(2)'));
  31152. mouseUp(this.$container.find('tr:eq(0) td:eq(2)'));
  31153. expect(getSelected()).toEqual(false);
  31154. });
  31155. it('should disallow fragmentSelection of Handsontable chrome (anything that is not table) when set to false', function () {
  31156. handsontable({
  31157. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31158. fragmentSelection: false
  31159. });
  31160. var $div = $('<div style="position: absolute; top: 0; left: 0">Text</div>');
  31161. this.$container.append($div);
  31162. selectElementText($div[0], 1);
  31163. mouseDown($div);
  31164. var sel = getSelected();
  31165. expect(sel).toEqual(false);
  31166. });
  31167. it('should disallow fragmentSelection of Handsontable chrome (anything that is not table) when set to true', function () {
  31168. handsontable({
  31169. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31170. fragmentSelection: true
  31171. });
  31172. var $div = $('<div style="position: absolute; top: 0; left: 0">Text</div>');
  31173. this.$container.append($div);
  31174. selectElementText($div[0], 1);
  31175. mouseDown($div);
  31176. var sel = getSelected();
  31177. expect(sel).toEqual(false);
  31178. });
  31179. });
  31180. describe('dynamic', function () {
  31181. it('should disallow fragmentSelection when set to false', function () {
  31182. handsontable({
  31183. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31184. fragmentSelection: true
  31185. });
  31186. updateSettings({ fragmentSelection: false });
  31187. selectElementText(this.$container.find('tr:eq(0) td:eq(1)')[0], 3);
  31188. mouseDown(this.$container.find('tr:eq(0) td:eq(3)'));
  31189. mouseUp(this.$container.find('tr:eq(0) td:eq(3)'));
  31190. var sel = getSelected();
  31191. expect(sel).toEqual(false);
  31192. });
  31193. it('should allow fragmentSelection when set to true', function () {
  31194. handsontable({
  31195. data: Handsontable.helper.createSpreadsheetData(4, 4),
  31196. fragmentSelection: false
  31197. });
  31198. updateSettings({ fragmentSelection: true });
  31199. selectElementText(this.$container.find('td')[1], 3);
  31200. mouseDown(this.$container.find('tr:eq(0) td:eq(3)'));
  31201. mouseUp(this.$container.find('tr:eq(0) td:eq(3)'));
  31202. var sel = getSelected();
  31203. sel = sel.replace(/\s/g, ''); // tabs and spaces between <td>s are inconsistent in browsers, so let's ignore them
  31204. expect(sel).toEqual('B1C1D1');
  31205. });
  31206. });
  31207. });
  31208. });
  31209. /***/ }),
  31210. /* 235 */
  31211. /***/ (function(module, exports, __webpack_require__) {
  31212. "use strict";
  31213. describe('settings', function () {
  31214. describe('maxCols', function () {
  31215. var id = 'testContainer';
  31216. beforeEach(function () {
  31217. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  31218. });
  31219. afterEach(function () {
  31220. if (this.$container) {
  31221. destroy();
  31222. this.$container.remove();
  31223. }
  31224. });
  31225. describe('works on init', function () {
  31226. it('should show data properly when `maxCols` is set to 0', function () {
  31227. handsontable({
  31228. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31229. maxCols: 0
  31230. });
  31231. expect(getSourceDataAtRow(0).length).toEqual(10);
  31232. expect(countSourceCols()).toEqual(10);
  31233. expect(getData().length).toEqual(0);
  31234. expect(getDataAtRow(0)).toEqual([]);
  31235. expect(countCols()).toEqual(0);
  31236. expect(countEmptyCols()).toEqual(0);
  31237. expect(getDataAtCol(0)).toEqual([]);
  31238. expect(getDataAtCol(1)).toEqual([]);
  31239. });
  31240. it('should show data properly when `maxCols` is set to value > 0', function () {
  31241. handsontable({
  31242. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31243. maxCols: 5
  31244. });
  31245. expect(getSourceDataAtRow(0).length).toEqual(10);
  31246. expect(countSourceCols()).toEqual(10);
  31247. expect(getData()[0].length).toEqual(5);
  31248. expect(getDataAtRow(0).length).toEqual(5);
  31249. expect(countCols()).toEqual(5);
  31250. expect(countEmptyCols()).toEqual(0);
  31251. expect(getDataAtCol(6)).toEqual([]);
  31252. });
  31253. it('should show data properly when `maxCols` is set to infinity value', function () {
  31254. handsontable({
  31255. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31256. maxCols: Infinity
  31257. });
  31258. expect(getSourceDataAtRow(0).length).toEqual(10);
  31259. expect(countSourceCols()).toEqual(10);
  31260. expect(getData()[0].length).toEqual(10);
  31261. expect(getDataAtRow(0).length).toEqual(10);
  31262. expect(countCols()).toEqual(10);
  31263. expect(countEmptyCols()).toEqual(0);
  31264. expect(getDataAtCol(0)).toEqual(['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10']);
  31265. });
  31266. describe('when `columns` property was set', function () {
  31267. it('should show data properly when `maxCols` is set to value > 0', function () {
  31268. handsontable({
  31269. columns: [{ type: 'text' }, { type: 'text' }, { type: 'text' }, { type: 'text' }, { type: 'text' }],
  31270. minRows: 10,
  31271. maxCols: 2
  31272. });
  31273. expect(getSourceDataAtRow(0).length).toEqual(5);
  31274. expect(countSourceCols()).toEqual(5);
  31275. expect(getData()[0].length).toEqual(2);
  31276. expect(getDataAtRow(0).length).toEqual(2);
  31277. expect(countCols()).toEqual(2);
  31278. expect(getDataAtCol(3)).toEqual([]);
  31279. });
  31280. });
  31281. });
  31282. describe('update settings works', function () {
  31283. it('should show data properly after maxCols is updated to 0', function () {
  31284. handsontable({
  31285. data: Handsontable.helper.createSpreadsheetData(10, 10)
  31286. });
  31287. updateSettings({
  31288. maxCols: 0
  31289. });
  31290. expect(getSourceDataAtRow(0).length).toEqual(10);
  31291. expect(countSourceCols()).toEqual(10);
  31292. expect(getData().length).toEqual(0);
  31293. expect(getDataAtRow(0)).toEqual([]);
  31294. expect(countCols()).toEqual(0);
  31295. expect(getDataAtCol(0)).toEqual([]);
  31296. expect(getDataAtCol(1)).toEqual([]);
  31297. });
  31298. it('should show data properly after maxCols is updated to value > 0 -> test no. 1', function () {
  31299. handsontable({
  31300. data: Handsontable.helper.createSpreadsheetData(10, 10)
  31301. });
  31302. updateSettings({
  31303. maxCols: 2
  31304. });
  31305. expect(getSourceDataAtRow(0).length).toEqual(10);
  31306. expect(countSourceCols()).toEqual(10);
  31307. expect(getData()[0].length).toEqual(2);
  31308. expect(getDataAtRow(0).length).toEqual(2);
  31309. expect(countCols()).toEqual(2);
  31310. expect(countEmptyCols()).toEqual(0);
  31311. expect(getDataAtCol(3)).toEqual([]);
  31312. });
  31313. it('should show data properly after maxCols is updated to value > 0 -> test no. 2', function () {
  31314. handsontable({
  31315. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31316. maxCols: 5
  31317. });
  31318. updateSettings({
  31319. maxCols: 2
  31320. });
  31321. expect(getSourceDataAtRow(0).length).toEqual(10);
  31322. expect(countSourceCols()).toEqual(10);
  31323. expect(getData()[0].length).toEqual(2);
  31324. expect(getDataAtRow(0).length).toEqual(2);
  31325. expect(countCols()).toEqual(2);
  31326. expect(countEmptyCols()).toEqual(0);
  31327. expect(getDataAtCol(3)).toEqual([]);
  31328. });
  31329. it('should show data properly after maxCols is updated to value > 0 -> test no. 3', function () {
  31330. handsontable({
  31331. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31332. maxCols: 2
  31333. });
  31334. updateSettings({
  31335. maxCols: 5
  31336. });
  31337. expect(getSourceDataAtRow(0).length).toEqual(10);
  31338. expect(countSourceCols()).toEqual(10);
  31339. expect(getData()[0].length).toEqual(5);
  31340. expect(getDataAtRow(0).length).toEqual(5);
  31341. expect(countCols()).toEqual(5);
  31342. expect(countEmptyCols()).toEqual(0);
  31343. expect(getDataAtCol(6)).toEqual([]);
  31344. });
  31345. it('should show data properly after maxCols is updated to infinity value -> test no. 1', function () {
  31346. handsontable({
  31347. data: Handsontable.helper.createSpreadsheetData(10, 10)
  31348. });
  31349. updateSettings({
  31350. maxCols: Infinity
  31351. });
  31352. expect(getSourceDataAtRow(0).length).toEqual(10);
  31353. expect(countSourceCols()).toEqual(10);
  31354. expect(getData()[0].length).toEqual(10);
  31355. expect(getDataAtRow(0).length).toEqual(10);
  31356. expect(countCols()).toEqual(10);
  31357. expect(countEmptyCols()).toEqual(0);
  31358. expect(getDataAtCol(0)).toEqual(['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10']);
  31359. });
  31360. it('should show data properly after maxCols is updated to infinity value -> test no. 2', function () {
  31361. handsontable({
  31362. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31363. maxCols: 2
  31364. });
  31365. updateSettings({
  31366. maxCols: Infinity
  31367. });
  31368. expect(getSourceDataAtRow(0).length).toEqual(10);
  31369. expect(countSourceCols()).toEqual(10);
  31370. expect(getData()[0].length).toEqual(10);
  31371. expect(getDataAtRow(0).length).toEqual(10);
  31372. expect(countCols()).toEqual(10);
  31373. expect(countEmptyCols()).toEqual(0);
  31374. expect(getDataAtCol(0)).toEqual(['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10']);
  31375. });
  31376. describe('works when `columns` property was set', function () {
  31377. it('should show data properly when `maxCols` is updated to value > 0', function () {
  31378. handsontable({
  31379. columns: [{ type: 'text' }, { type: 'text' }, { type: 'text' }, { type: 'text' }, { type: 'text' }],
  31380. minRows: 10
  31381. });
  31382. updateSettings({
  31383. maxCols: 2
  31384. });
  31385. expect(getSourceDataAtRow(0).length).toEqual(5);
  31386. expect(countSourceCols()).toEqual(5);
  31387. expect(getData()[0].length).toEqual(2);
  31388. expect(getDataAtRow(0).length).toEqual(2);
  31389. expect(countCols()).toEqual(2);
  31390. expect(getDataAtCol(0).length).toEqual(10);
  31391. });
  31392. });
  31393. });
  31394. });
  31395. });
  31396. /***/ }),
  31397. /* 236 */
  31398. /***/ (function(module, exports, __webpack_require__) {
  31399. "use strict";
  31400. describe('settings', function () {
  31401. describe('maxRows', function () {
  31402. var id = 'testContainer';
  31403. beforeEach(function () {
  31404. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  31405. });
  31406. afterEach(function () {
  31407. if (this.$container) {
  31408. destroy();
  31409. this.$container.remove();
  31410. }
  31411. });
  31412. describe('works on init', function () {
  31413. it('should show data properly when `maxRows` is set to 0', function () {
  31414. handsontable({
  31415. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31416. maxRows: 0
  31417. });
  31418. expect(getSourceDataAtCol(0).length).toEqual(10);
  31419. expect(countSourceRows()).toEqual(10);
  31420. expect(getData().length).toEqual(0);
  31421. expect(getDataAtCol(0)).toEqual([]);
  31422. expect(countRows()).toEqual(0);
  31423. expect(countEmptyRows()).toEqual(0);
  31424. expect(getDataAtRow(0)).toEqual([]);
  31425. expect(getDataAtRow(1)).toEqual([]);
  31426. });
  31427. it('should show data properly when `maxRows` is set to value > 0', function () {
  31428. handsontable({
  31429. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31430. maxRows: 5
  31431. });
  31432. expect(getSourceDataAtCol(0).length).toEqual(10);
  31433. expect(countSourceRows()).toEqual(10);
  31434. expect(getData().length).toEqual(5);
  31435. expect(getDataAtCol(0).length).toEqual(5);
  31436. expect(countRows()).toEqual(5);
  31437. expect(countEmptyRows()).toEqual(0);
  31438. expect(getDataAtRow(6)).toEqual([]);
  31439. });
  31440. it('should show data properly when `maxRows` is set to infinity value', function () {
  31441. handsontable({
  31442. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31443. maxRows: Infinity
  31444. });
  31445. expect(getSourceDataAtCol(0).length).toEqual(10);
  31446. expect(countSourceRows()).toEqual(10);
  31447. expect(getData().length).toEqual(10);
  31448. expect(getDataAtCol(0).length).toEqual(10);
  31449. expect(countRows()).toEqual(10);
  31450. expect(countEmptyRows()).toEqual(0);
  31451. expect(getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']);
  31452. });
  31453. });
  31454. describe('update settings works', function () {
  31455. it('should show data properly after maxRows is updated to 0', function () {
  31456. handsontable({
  31457. data: Handsontable.helper.createSpreadsheetData(10, 10)
  31458. });
  31459. updateSettings({
  31460. maxRows: 0
  31461. });
  31462. expect(getSourceDataAtCol(0).length).toEqual(10);
  31463. expect(countSourceRows()).toEqual(10);
  31464. expect(getData().length).toEqual(0);
  31465. expect(getDataAtCol(0)).toEqual([]);
  31466. expect(countRows()).toEqual(0);
  31467. expect(countEmptyRows()).toEqual(0);
  31468. expect(getDataAtRow(0)).toEqual([]);
  31469. expect(getDataAtRow(1)).toEqual([]);
  31470. });
  31471. it('should show data properly after maxRows is updated to value > 0 -> test no. 1', function () {
  31472. handsontable({
  31473. data: Handsontable.helper.createSpreadsheetData(10, 10)
  31474. });
  31475. updateSettings({
  31476. maxRows: 2
  31477. });
  31478. expect(getSourceDataAtCol(0).length).toEqual(10);
  31479. expect(countSourceRows()).toEqual(10);
  31480. expect(getData().length).toEqual(2);
  31481. expect(getDataAtCol(0).length).toEqual(2);
  31482. expect(countRows()).toEqual(2);
  31483. expect(countEmptyRows()).toEqual(0);
  31484. expect(getDataAtRow(3)).toEqual([]);
  31485. });
  31486. it('should show data properly after maxRows is updated to value > 0 -> test no. 2', function () {
  31487. handsontable({
  31488. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31489. maxRows: 5
  31490. });
  31491. updateSettings({
  31492. maxRows: 2
  31493. });
  31494. expect(getSourceDataAtCol(0).length).toEqual(10);
  31495. expect(countSourceRows()).toEqual(10);
  31496. expect(getData().length).toEqual(2);
  31497. expect(getDataAtCol(0).length).toEqual(2);
  31498. expect(countRows()).toEqual(2);
  31499. expect(countEmptyRows()).toEqual(0);
  31500. expect(getDataAtRow(3)).toEqual([]);
  31501. });
  31502. it('should show data properly after maxRows is updated to value > 0 -> test no. 3', function () {
  31503. handsontable({
  31504. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31505. maxRows: 2
  31506. });
  31507. updateSettings({
  31508. maxRows: 5
  31509. });
  31510. expect(getSourceDataAtCol(0).length).toEqual(10);
  31511. expect(countSourceRows()).toEqual(10);
  31512. expect(getData().length).toEqual(5);
  31513. expect(getDataAtCol(0).length).toEqual(5);
  31514. expect(countRows()).toEqual(5);
  31515. expect(countEmptyRows()).toEqual(0);
  31516. expect(getDataAtRow(6)).toEqual([]);
  31517. });
  31518. it('should show data properly after maxRows is updated to infinity value -> test no. 1', function () {
  31519. handsontable({
  31520. data: Handsontable.helper.createSpreadsheetData(10, 10)
  31521. });
  31522. updateSettings({
  31523. maxRows: Infinity
  31524. });
  31525. expect(getSourceDataAtCol(0).length).toEqual(10);
  31526. expect(countSourceRows()).toEqual(10);
  31527. expect(getData().length).toEqual(10);
  31528. expect(getDataAtCol(0).length).toEqual(10);
  31529. expect(countRows()).toEqual(10);
  31530. expect(countEmptyRows()).toEqual(0);
  31531. expect(getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']);
  31532. });
  31533. it('should show data properly after maxRows is updated to infinity value -> test no. 2', function () {
  31534. handsontable({
  31535. data: Handsontable.helper.createSpreadsheetData(10, 10),
  31536. maxRows: 2
  31537. });
  31538. updateSettings({
  31539. maxRows: Infinity
  31540. });
  31541. expect(getSourceDataAtCol(0).length).toEqual(10);
  31542. expect(countSourceRows()).toEqual(10);
  31543. expect(getData().length).toEqual(10);
  31544. expect(getDataAtCol(0).length).toEqual(10);
  31545. expect(countRows()).toEqual(10);
  31546. expect(countEmptyRows()).toEqual(0);
  31547. expect(getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']);
  31548. });
  31549. });
  31550. });
  31551. });
  31552. /***/ }),
  31553. /* 237 */
  31554. /***/ (function(module, exports, __webpack_require__) {
  31555. "use strict";
  31556. describe('settings', function () {
  31557. describe('renderer', function () {
  31558. var id = 'testContainer';
  31559. beforeEach(function () {
  31560. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  31561. });
  31562. afterEach(function () {
  31563. if (this.$container) {
  31564. destroy();
  31565. this.$container.remove();
  31566. }
  31567. });
  31568. describe('defined in constructor', function () {
  31569. it('should use text renderer by default', function () {
  31570. var originalTextRenderer = Handsontable.cellTypes.text.renderer;
  31571. spyOn(Handsontable.cellTypes.text, 'renderer');
  31572. Handsontable.renderers.registerRenderer('text', Handsontable.cellTypes.text.renderer);
  31573. handsontable();
  31574. expect(Handsontable.cellTypes.text.renderer).toHaveBeenCalled();
  31575. Handsontable.renderers.registerRenderer('text', originalTextRenderer);
  31576. });
  31577. it('should use renderer from predefined string', function () {
  31578. var originalTextRenderer = Handsontable.renderers.TextRenderer;
  31579. spyOn(Handsontable.renderers, 'TextRenderer');
  31580. Handsontable.renderers.registerRenderer('text', Handsontable.renderers.TextRenderer);
  31581. var originalCheckboxRenderer = Handsontable.renderers.CheckboxRenderer;
  31582. spyOn(Handsontable.renderers, 'CheckboxRenderer');
  31583. Handsontable.renderers.registerRenderer('checkbox', Handsontable.renderers.CheckboxRenderer);
  31584. handsontable({
  31585. columns: [{
  31586. renderer: 'checkbox'
  31587. }]
  31588. });
  31589. expect(Handsontable.renderers.TextRenderer).not.toHaveBeenCalled();
  31590. expect(Handsontable.renderers.CheckboxRenderer).toHaveBeenCalled();
  31591. Handsontable.renderers.registerRenderer('text', originalTextRenderer);
  31592. Handsontable.renderers.registerRenderer('checkbox', originalCheckboxRenderer);
  31593. });
  31594. it('should use renderer from predefined string when columns is a function', function () {
  31595. var originalTextRenderer = Handsontable.renderers.TextRenderer;
  31596. spyOn(Handsontable.renderers, 'TextRenderer');
  31597. Handsontable.renderers.registerRenderer('text', Handsontable.renderers.TextRenderer);
  31598. var originalCheckboxRenderer = Handsontable.renderers.CheckboxRenderer;
  31599. spyOn(Handsontable.renderers, 'CheckboxRenderer');
  31600. Handsontable.renderers.registerRenderer('checkbox', Handsontable.renderers.CheckboxRenderer);
  31601. handsontable({
  31602. columns: function columns(column) {
  31603. return column === 0 ? { renderer: 'checkbox' } : null;
  31604. }
  31605. });
  31606. expect(Handsontable.renderers.TextRenderer).not.toHaveBeenCalled();
  31607. expect(Handsontable.renderers.CheckboxRenderer).toHaveBeenCalled();
  31608. Handsontable.renderers.registerRenderer('text', originalTextRenderer);
  31609. Handsontable.renderers.registerRenderer('checkbox', originalCheckboxRenderer);
  31610. });
  31611. it('should use renderer from custom function', function () {
  31612. var called = false;
  31613. function myRenderer() {
  31614. called = true;
  31615. }
  31616. handsontable({
  31617. columns: [{
  31618. renderer: myRenderer
  31619. }]
  31620. });
  31621. expect(called).toBe(true);
  31622. });
  31623. it('should use renderer from custom function when columns is a function', function () {
  31624. var called = false;
  31625. function myRenderer() {
  31626. called = true;
  31627. }
  31628. handsontable({
  31629. columns: function columns(column) {
  31630. return column === 0 ? { renderer: myRenderer } : null;
  31631. }
  31632. });
  31633. expect(called).toBe(true);
  31634. });
  31635. it('should use renderer from custom string', function () {
  31636. var myRenderer = jasmine.createSpy('myRenderer');
  31637. Handsontable.renderers.registerRenderer('myRenderer', myRenderer);
  31638. handsontable({
  31639. columns: [{
  31640. renderer: 'myRenderer'
  31641. }]
  31642. });
  31643. expect(myRenderer).toHaveBeenCalled();
  31644. });
  31645. it('should use renderer from custom string when columns is a function', function () {
  31646. var myRenderer = jasmine.createSpy('myRenderer');
  31647. Handsontable.renderers.registerRenderer('myRenderer', myRenderer);
  31648. handsontable({
  31649. columns: function columns(column) {
  31650. return column === 0 ? { renderer: 'myRenderer' } : null;
  31651. }
  31652. });
  31653. expect(myRenderer).toHaveBeenCalled();
  31654. });
  31655. });
  31656. it('should call renderer with cellProperties.row, cellProperties.col matching row and col arguments', function () {
  31657. var rendererSpy = jasmine.createSpy('rendererSpy').and.callThrough();
  31658. var cellPropertiesCache = [];
  31659. rendererSpy.and.callFake(function (instance, TD, row, col, prop, value, cellProperties) {
  31660. cellPropertiesCache.push({
  31661. row: cellProperties.row,
  31662. col: cellProperties.col
  31663. });
  31664. });
  31665. handsontable({
  31666. renderer: rendererSpy
  31667. });
  31668. for (var i = 0, len = rendererSpy.calls.count(); i < len; i++) {
  31669. var args = rendererSpy.calls.argsFor(i);
  31670. var row = args[2];
  31671. var col = args[3];
  31672. var cellProperties = cellPropertiesCache[i];
  31673. expect(row).toEqual(cellProperties.row);
  31674. expect(col).toEqual(cellProperties.col);
  31675. }
  31676. });
  31677. it('should call cells function before passing cellProperties to renderer', function () {
  31678. var rendererSpy = jasmine.createSpy('rendererSpy').and.callThrough();
  31679. var cellPropertiesCache = [];
  31680. rendererSpy.and.callFake(function (instance, TD, row, col, prop, value, cellProperties) {
  31681. cellPropertiesCache.push({
  31682. cellsRow: cellProperties.cellsRow,
  31683. cellsCol: cellProperties.cellsCol
  31684. });
  31685. });
  31686. handsontable({
  31687. renderer: rendererSpy,
  31688. cells: function cells(row, col) {
  31689. return {
  31690. cellsRow: row,
  31691. cellsCol: col
  31692. };
  31693. }
  31694. });
  31695. for (var i = 0, len = rendererSpy.calls.count(); i < len; i++) {
  31696. var args = rendererSpy.calls.argsFor(i);
  31697. var row = args[2];
  31698. var col = args[3];
  31699. var cellProperties = cellPropertiesCache[i];
  31700. expect(row).toEqual(cellProperties.cellsRow);
  31701. expect(col).toEqual(cellProperties.cellsCol);
  31702. }
  31703. });
  31704. });
  31705. });
  31706. /***/ }),
  31707. /* 238 */
  31708. /***/ (function(module, exports, __webpack_require__) {
  31709. "use strict";
  31710. describe('settings', function () {
  31711. describe('tableClassName', function () {
  31712. var id = 'testContainer';
  31713. beforeEach(function () {
  31714. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  31715. });
  31716. afterEach(function () {
  31717. if (this.$container) {
  31718. destroy();
  31719. this.$container.remove();
  31720. }
  31721. });
  31722. it('should add class name every table element inside handsontable wrapper element (as string, without overlays)', function () {
  31723. var hot = handsontable({
  31724. colHeaders: false,
  31725. rowHeaders: false,
  31726. tableClassName: 'foo'
  31727. });
  31728. var possibleCounts = [3, 4]; // 3 for non-pro, 4 for pro (bottom overlay)
  31729. // all overlays is created anyway but without left-top corner
  31730. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.foo').length)).toBeGreaterThan(-1);
  31731. });
  31732. it('should add class name every table element inside handsontable wrapper element (as string, with overlays)', function () {
  31733. var hot = handsontable({
  31734. colHeaders: true,
  31735. rowHeaders: true,
  31736. tableClassName: 'foo'
  31737. });
  31738. var possibleCounts = [4, 5]; // 4 for non-pro, 5 for pro (bottom overlay)
  31739. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.foo').length)).toBeGreaterThan(-1);
  31740. });
  31741. it('should add class name every table element inside handsontable wrapper element (as string with spaces, without overlays)', function () {
  31742. var hot = handsontable({
  31743. colHeaders: false,
  31744. rowHeaders: false,
  31745. tableClassName: 'foo bar'
  31746. });
  31747. var possibleCounts = [3, 4]; // 3 for non-pro, 4 for pro (bottom overlay)
  31748. // all overlays is created anyway but without left-top corner
  31749. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.foo').length)).toBeGreaterThan(-1);
  31750. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.bar').length)).toBeGreaterThan(-1);
  31751. });
  31752. it('should add class name every table element inside handsontable wrapper element (as string with spaces, with overlays)', function () {
  31753. var hot = handsontable({
  31754. colHeaders: true,
  31755. rowHeaders: true,
  31756. tableClassName: 'foo bar'
  31757. });
  31758. var possibleCounts = [4, 5]; // 4 for non-pro, 5 for pro (bottom overlay)
  31759. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.foo').length)).toBeGreaterThan(-1);
  31760. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.bar').length)).toBeGreaterThan(-1);
  31761. });
  31762. it('should add class name every table element inside handsontable wrapper element (as array, without overlays)', function () {
  31763. var hot = handsontable({
  31764. colHeaders: false,
  31765. rowHeaders: false,
  31766. tableClassName: ['foo', 'bar', 'baz']
  31767. });
  31768. var possibleCounts = [3, 4]; // 3 for non-pro, 4 for pro (bottom overlay)
  31769. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.foo').length)).toBeGreaterThan(-1);
  31770. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.bar').length)).toBeGreaterThan(-1);
  31771. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.baz').length)).toBeGreaterThan(-1);
  31772. });
  31773. it('should add class name every table element inside handsontable wrapper element (as array, with overlays)', function () {
  31774. var hot = handsontable({
  31775. colHeaders: true,
  31776. rowHeaders: true,
  31777. tableClassName: ['foo', 'bar', 'baz']
  31778. });
  31779. var possibleCounts = [4, 5]; // 4 for non-pro, 5 for pro (bottom overlay)
  31780. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.foo').length)).toBeGreaterThan(-1);
  31781. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.bar').length)).toBeGreaterThan(-1);
  31782. expect(possibleCounts.indexOf(hot.rootElement.querySelectorAll('table.baz').length)).toBeGreaterThan(-1);
  31783. });
  31784. });
  31785. });
  31786. /***/ }),
  31787. /* 239 */
  31788. /***/ (function(module, exports, __webpack_require__) {
  31789. "use strict";
  31790. describe('GhostTable', function () {
  31791. var hotSettings = {
  31792. data: [['A', '1', 'A\nB\nC'], ['B', '2', 'A-----B-------C'], ['C', '3', 'A---\n--B-------C']]
  31793. };
  31794. var gt;
  31795. beforeEach(function () {
  31796. this.$container = $('<div id="testContainer"></div>').appendTo('body');
  31797. });
  31798. afterEach(function () {
  31799. if (this.$container) {
  31800. destroy();
  31801. this.$container.remove();
  31802. }
  31803. if (gt) {
  31804. gt.clean();
  31805. gt = null;
  31806. }
  31807. });
  31808. describe('row', function () {
  31809. it('should throw exception if we try to add column after added row', function () {
  31810. var hot = handsontable(hotSettings);
  31811. var exception = false;
  31812. var samples = new Map();
  31813. gt = new Handsontable.__GhostTable(hot);
  31814. gt.addRow(0, samples);
  31815. try {
  31816. gt.addColumn(0, samples);
  31817. } catch (ex) {
  31818. exception = true;
  31819. }
  31820. expect(exception).toBe(true);
  31821. });
  31822. it('should create container element only for first row', function () {
  31823. var hot = handsontable(hotSettings);
  31824. var samples = new Map();
  31825. gt = new Handsontable.__GhostTable(hot);
  31826. spyOn(gt, 'createContainer').and.callThrough();
  31827. gt.addRow(0, samples);
  31828. gt.addRow(0, samples);
  31829. gt.addRow(0, samples);
  31830. gt.addRow(1, samples);
  31831. gt.addRow(2, samples);
  31832. expect(gt.createContainer.calls.count()).toBe(1);
  31833. expect(gt.createContainer.calls.mostRecent().args).toEqual(['handsontable']);
  31834. });
  31835. it('should add row to rows collection after call `addRow` method', function () {
  31836. var hot = handsontable(hotSettings);
  31837. var samples = new Map();
  31838. gt = new Handsontable.__GhostTable(hot);
  31839. expect(gt.rows.length).toBe(0);
  31840. samples.clear();
  31841. samples.set(0, { strings: [{ value: 'Foo', row: 0 }, { value: 'Foo Bar', row: 0 }] });
  31842. gt.addRow(0, samples);
  31843. expect(gt.rows.length).toBe(1);
  31844. expect(gt.rows[0].row).toBe(0);
  31845. expect(gt.rows[0].table.className).toBe('htCore');
  31846. expect(gt.rows[0].table.nodeName).toBe('TABLE');
  31847. expect(gt.rows[0].table.querySelectorAll('colgroup > col').length).toBe(2);
  31848. expect(gt.rows[0].table.querySelector('tbody > tr > td').innerHTML).toBe('Foo');
  31849. samples.clear();
  31850. samples.set(0, { strings: [{ value: 'Bar', row: 1 }, { value: 'Baz1234', row: 1 }] });
  31851. gt.addRow(1, samples);
  31852. expect(gt.rows.length).toBe(2);
  31853. expect(gt.rows[1].row).toBe(1);
  31854. expect(gt.rows[1].table.className).toBe('htCore');
  31855. expect(gt.rows[1].table.nodeName).toBe('TABLE');
  31856. expect(gt.rows[1].table.querySelectorAll('colgroup > col').length).toBe(2);
  31857. expect(gt.rows[1].table.querySelector('tbody > tr > td').innerHTML).toBe('Bar');
  31858. });
  31859. it('should get valid heights', function () {
  31860. var hot = handsontable(hotSettings);
  31861. var heightSpy = jasmine.createSpy();
  31862. var samples = new Map();
  31863. gt = new Handsontable.__GhostTable(hot);
  31864. samples.clear();
  31865. samples.set(0, { strings: [{ value: 'Foo', row: 0 }, { value: 'Foo.....Bar', row: 0 }] });
  31866. gt.addRow(0, samples);
  31867. samples.clear();
  31868. samples.set(0, { strings: [{ value: 'Foo\nBar\nsqw', row: 1 }] });
  31869. gt.addRow(1, samples);
  31870. samples.clear();
  31871. samples.set(0, { strings: [{ value: 'Foo', row: 0 }, { value: 'Foo Bar', row: 0 }] });
  31872. gt.addRow(2, samples);
  31873. gt.getHeights(heightSpy);
  31874. expect(heightSpy.calls.count()).toBe(3);
  31875. expect(heightSpy.calls.argsFor(0)[0]).toBe(0);
  31876. expect(heightSpy.calls.argsFor(0)[1]).toBe(23);
  31877. expect(heightSpy.calls.argsFor(1)[0]).toBe(1);
  31878. expect(heightSpy.calls.argsFor(1)[1]).toBe(64);
  31879. expect(heightSpy.calls.argsFor(2)[0]).toBe(2);
  31880. expect(heightSpy.calls.argsFor(2)[1]).toBe(43);
  31881. });
  31882. });
  31883. describe('column', function () {
  31884. it('should throw exception if we try to add row after added column', function () {
  31885. var hot = handsontable(hotSettings);
  31886. var exception = false;
  31887. var samples = new Map();
  31888. gt = new Handsontable.__GhostTable(hot);
  31889. gt.addColumn(0, samples);
  31890. try {
  31891. gt.addRow(0, samples);
  31892. } catch (ex) {
  31893. exception = true;
  31894. }
  31895. expect(exception).toBe(true);
  31896. });
  31897. it('should create container element only for first column', function () {
  31898. var hot = handsontable(hotSettings);
  31899. var samples = new Map();
  31900. gt = new Handsontable.__GhostTable(hot);
  31901. spyOn(gt, 'createContainer').and.callThrough();
  31902. gt.addColumn(0, samples);
  31903. gt.addColumn(0, samples);
  31904. gt.addColumn(0, samples);
  31905. gt.addColumn(1, samples);
  31906. gt.addColumn(2, samples);
  31907. expect(gt.createContainer.calls.count()).toBe(1);
  31908. expect(gt.createContainer.calls.mostRecent().args).toEqual(['handsontable']);
  31909. });
  31910. it('should add column to columns collection after call `addColumn` method', function () {
  31911. var hot = handsontable(hotSettings);
  31912. var samples = new Map();
  31913. gt = new Handsontable.__GhostTable(hot);
  31914. expect(gt.columns.length).toBe(0);
  31915. samples.clear();
  31916. samples.set(0, { strings: [{ value: 'Foo', col: 0 }, { value: 'Foo Bar', col: 0 }] });
  31917. gt.addColumn(0, samples);
  31918. expect(gt.columns.length).toBe(1);
  31919. expect(gt.columns[0].col).toBe(0);
  31920. expect(gt.columns[0].table.className).toBe('htCore');
  31921. expect(gt.columns[0].table.style.width).toBe('auto');
  31922. expect(gt.columns[0].table.style.tableLayout).toBe('auto');
  31923. expect(gt.columns[0].table.nodeName).toBe('TABLE');
  31924. expect(gt.columns[0].table.querySelectorAll('thead > tr > th').length).toBe(1);
  31925. expect(gt.columns[0].table.querySelector('tbody > tr > td').innerHTML).toBe('Foo');
  31926. samples.clear();
  31927. samples.set(0, { strings: [{ value: 'Bar', row: 1 }, { value: 'Baz1234', row: 1 }] });
  31928. gt.addColumn(1, samples);
  31929. expect(gt.columns.length).toBe(2);
  31930. expect(gt.columns[1].col).toBe(1);
  31931. expect(gt.columns[1].table.className).toBe('htCore');
  31932. expect(gt.columns[1].table.nodeName).toBe('TABLE');
  31933. expect(gt.columns[1].table.querySelectorAll('thead > tr > th').length).toBe(1);
  31934. expect(gt.columns[1].table.querySelector('tbody > tr > td').innerHTML).toBe('Bar');
  31935. });
  31936. it('should get valid widths', function () {
  31937. var hot = handsontable(hotSettings);
  31938. var widthSpy = jasmine.createSpy();
  31939. var samples = new Map();
  31940. gt = new Handsontable.__GhostTable(hot);
  31941. samples.clear();
  31942. samples.set(0, { strings: [{ value: 'Foo', col: 0 }, { value: 'Foo.....Bar', col: 0 }] });
  31943. gt.addColumn(0, samples);
  31944. samples.clear();
  31945. samples.set(0, { strings: [{ value: 'Foo\nBar\nsqw', col: 1 }] });
  31946. gt.addColumn(1, samples);
  31947. samples.clear();
  31948. samples.set(0, { strings: [{ value: 'Foo', col: 0 }, { value: 'Foo Bar', col: 0 }] });
  31949. gt.addColumn(2, samples);
  31950. gt.getWidths(widthSpy);
  31951. expect(widthSpy.calls.count()).toBe(3);
  31952. expect(widthSpy.calls.argsFor(0)[0]).toBe(0);
  31953. expect(widthSpy.calls.argsFor(0)[1]).toBeAroundValue(87, 4);
  31954. expect(widthSpy.calls.argsFor(1)[0]).toBe(1);
  31955. expect(widthSpy.calls.argsFor(1)[1]).toBeAroundValue(41, 4);
  31956. expect(widthSpy.calls.argsFor(2)[0]).toBe(2);
  31957. expect(widthSpy.calls.argsFor(2)[1]).toBeAroundValue(68, 4);
  31958. });
  31959. });
  31960. it('should reset internal state after call `clean` method', function () {
  31961. var hot = handsontable(hotSettings);
  31962. var samples = new Map();
  31963. gt = new Handsontable.__GhostTable(hot);
  31964. gt.addColumn(0, samples);
  31965. gt.rows.push({});
  31966. gt.getWidths(function () {});
  31967. expect(gt.columns.length).toBe(1);
  31968. expect(gt.samples).toBeDefined();
  31969. expect(gt.injected).toBe(true);
  31970. expect(gt.container).toBeDefined();
  31971. expect(document.querySelector('.htGhostTable')).toBeDefined();
  31972. gt.clean();
  31973. expect(gt.columns.length).toBe(0);
  31974. expect(gt.samples).toBe(null);
  31975. expect(gt.injected).toBe(false);
  31976. expect(gt.container).toBe(null);
  31977. expect(document.querySelector('.htGhostTable')).toBe(null);
  31978. });
  31979. it('should be detected as vertical if at least one row is added', function () {
  31980. var hot = handsontable(hotSettings);
  31981. var samples = new Map();
  31982. var gt = new Handsontable.__GhostTable(hot);
  31983. gt.addRow(0, samples);
  31984. expect(gt.isVertical()).toBe(true);
  31985. expect(gt.isHorizontal()).toBe(false);
  31986. });
  31987. it('should be detected as horizontal if at least one column is added', function () {
  31988. var hot = handsontable(hotSettings);
  31989. var samples = new Map();
  31990. var gt = new Handsontable.__GhostTable(hot);
  31991. gt.addColumn(0, samples);
  31992. expect(gt.isVertical()).toBe(false);
  31993. expect(gt.isHorizontal()).toBe(true);
  31994. });
  31995. });
  31996. /***/ }),
  31997. /* 240 */
  31998. /***/ (function(module, exports, __webpack_require__) {
  31999. "use strict";
  32000. describe('autocompleteValidator', function () {
  32001. var id = 'testContainer';
  32002. beforeEach(function () {
  32003. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  32004. });
  32005. afterEach(function () {
  32006. if (this.$container) {
  32007. destroy();
  32008. this.$container.remove();
  32009. }
  32010. });
  32011. describe('allowEmpty', function () {
  32012. it('should validate empty cells positively (by default)', function (done) {
  32013. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32014. var hot = handsontable({
  32015. data: [['some', 'sample', 'data']],
  32016. columns: [{
  32017. type: 'autocomplete',
  32018. source: ['some', 'sample', 'data'],
  32019. strict: true
  32020. }, {
  32021. type: 'autocomplete',
  32022. source: ['some', 'sample', 'data'],
  32023. strict: true
  32024. }, {
  32025. type: 'autocomplete',
  32026. source: ['some', 'sample', 'data'],
  32027. strict: true
  32028. }],
  32029. afterValidate: onAfterValidate
  32030. });
  32031. setDataAtCell(0, 0, '');
  32032. setTimeout(function () {
  32033. expect(onAfterValidate).toHaveBeenCalledWith(true, '', 0, 0, undefined, undefined);
  32034. done();
  32035. }, 100);
  32036. });
  32037. it('should validate empty cells positively when allowEmpty is set to true', function (done) {
  32038. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32039. var hot = handsontable({
  32040. data: [['some', 'sample', 'data']],
  32041. columns: [{
  32042. type: 'autocomplete',
  32043. source: ['some', 'sample', 'data'],
  32044. strict: true
  32045. }, {
  32046. type: 'autocomplete',
  32047. source: ['some', 'sample', 'data'],
  32048. strict: true
  32049. }, {
  32050. type: 'autocomplete',
  32051. source: ['some', 'sample', 'data'],
  32052. strict: true
  32053. }],
  32054. allowEmpty: true,
  32055. afterValidate: onAfterValidate
  32056. });
  32057. setDataAtCell(0, 0, '');
  32058. setTimeout(function () {
  32059. expect(onAfterValidate).toHaveBeenCalledWith(true, '', 0, 0, undefined, undefined);
  32060. done();
  32061. }, 100);
  32062. });
  32063. it('should validate empty cells negatively when allowEmpty is set to false', function (done) {
  32064. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32065. var hot = handsontable({
  32066. data: [['some', 'sample', 'data']],
  32067. columns: [{
  32068. type: 'autocomplete',
  32069. source: ['some', 'sample', 'data'],
  32070. strict: true
  32071. }, {
  32072. type: 'autocomplete',
  32073. source: ['some', 'sample', 'data'],
  32074. strict: true
  32075. }, {
  32076. type: 'autocomplete',
  32077. source: ['some', 'sample', 'data'],
  32078. strict: true
  32079. }],
  32080. allowEmpty: false,
  32081. afterValidate: onAfterValidate
  32082. });
  32083. setDataAtCell(0, 0, '');
  32084. setTimeout(function () {
  32085. expect(onAfterValidate).toHaveBeenCalledWith(false, '', 0, 0, undefined, undefined);
  32086. done();
  32087. }, 100);
  32088. });
  32089. it('should respect the allowEmpty property for a single column', function (done) {
  32090. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32091. var hot = handsontable({
  32092. data: [['some', 'sample', 'data']],
  32093. columns: [{
  32094. type: 'autocomplete',
  32095. source: ['some', 'sample', 'data'],
  32096. strict: true
  32097. }, {
  32098. type: 'autocomplete',
  32099. source: ['some', 'sample', 'data'],
  32100. strict: true,
  32101. allowEmpty: false
  32102. }, {
  32103. type: 'autocomplete',
  32104. source: ['some', 'sample', 'data'],
  32105. strict: true
  32106. }],
  32107. afterValidate: onAfterValidate
  32108. });
  32109. setDataAtCell(0, 0, '');
  32110. setDataAtCell(0, 1, '');
  32111. setDataAtCell(0, 2, '');
  32112. setTimeout(function () {
  32113. expect(onAfterValidate.calls.argsFor(0)).toEqual([true, '', 0, 0, undefined, undefined]);
  32114. expect(onAfterValidate.calls.argsFor(1)).toEqual([false, '', 0, 1, undefined, undefined]);
  32115. expect(onAfterValidate.calls.argsFor(2)).toEqual([true, '', 0, 2, undefined, undefined]);
  32116. done();
  32117. }, 100);
  32118. });
  32119. it('should work for null and undefined values in cells', function (done) {
  32120. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32121. var hot = handsontable({
  32122. data: [['some', 'sample', 'data']],
  32123. columns: [{
  32124. type: 'autocomplete',
  32125. source: ['some', 'sample', 'data'],
  32126. strict: true
  32127. }, {
  32128. type: 'autocomplete',
  32129. source: ['some', 'sample', 'data'],
  32130. strict: true
  32131. }, {
  32132. type: 'autocomplete',
  32133. source: ['some', 'sample', 'data'],
  32134. strict: true
  32135. }],
  32136. allowEmpty: false,
  32137. afterValidate: onAfterValidate
  32138. });
  32139. setDataAtCell(0, 0, null);
  32140. setDataAtCell(0, 1, void 0);
  32141. setDataAtCell(0, 2, '');
  32142. setTimeout(function () {
  32143. expect(onAfterValidate.calls.argsFor(0)).toEqual([false, null, 0, 0, undefined, undefined]);
  32144. expect(onAfterValidate.calls.argsFor(1)).toEqual([false, void 0, 0, 1, undefined, undefined]);
  32145. expect(onAfterValidate.calls.argsFor(2)).toEqual([false, '', 0, 2, undefined, undefined]);
  32146. done();
  32147. }, 100);
  32148. });
  32149. });
  32150. describe('strict mode', function () {
  32151. it('sshould validate negatively when chars have different size', function (done) {
  32152. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32153. var hot = handsontable({
  32154. data: [['some', 'sample', 'data']],
  32155. columns: [{
  32156. type: 'autocomplete',
  32157. source: ['some', 'sample', 'data'],
  32158. strict: true
  32159. }],
  32160. afterValidate: onAfterValidate
  32161. });
  32162. setDataAtCell(0, 0, 'Some');
  32163. setTimeout(function () {
  32164. expect(onAfterValidate).toHaveBeenCalledWith(false, 'Some', 0, 0, undefined, undefined);
  32165. done();
  32166. }, 100);
  32167. });
  32168. });
  32169. });
  32170. /***/ }),
  32171. /* 241 */
  32172. /***/ (function(module, exports, __webpack_require__) {
  32173. "use strict";
  32174. describe('dateValidator', function () {
  32175. var id = 'testContainer';
  32176. beforeEach(function () {
  32177. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  32178. });
  32179. afterEach(function () {
  32180. if (this.$container) {
  32181. destroy();
  32182. this.$container.remove();
  32183. }
  32184. });
  32185. var arrayOfObjects = function arrayOfObjects() {
  32186. return [{ date: '01/01/2015', name: 'Ted', lastName: 'Right' }, { date: '01/01/15', name: 'Frank', lastName: 'Honest' }, { date: '41/01/2015', name: 'Joan', lastName: 'Well' }, { date: '01/51/2015', name: 'Sid', lastName: 'Strong' }];
  32187. };
  32188. it('should validate an empty string (default behavior)', function (done) {
  32189. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32190. handsontable({
  32191. data: arrayOfObjects(),
  32192. columns: [{ data: 'date', type: 'date' }, { data: 'name' }, { data: 'lastName' }],
  32193. afterValidate: onAfterValidate
  32194. });
  32195. setDataAtCell(0, 0, '');
  32196. setTimeout(function () {
  32197. expect(onAfterValidate).toHaveBeenCalledWith(true, '', 0, 'date', undefined, undefined);
  32198. done();
  32199. }, 100);
  32200. });
  32201. it('should rewrite an ISO 8601 string to the correct format if a date-string in different format is provided', function (done) {
  32202. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32203. handsontable({
  32204. data: arrayOfObjects(),
  32205. columns: [{ data: 'date', type: 'date', dateFormat: 'MM/DD/YYYY', correctFormat: true }, { data: 'lastName' }],
  32206. afterValidate: onAfterValidate
  32207. });
  32208. setDataAtCell(1, 0, '2016-03-18');
  32209. setTimeout(function () {
  32210. expect(onAfterValidate).toHaveBeenCalledWith(true, '2016-03-18', 1, 'date', undefined, undefined);
  32211. }, 100);
  32212. setTimeout(function () {
  32213. expect(getDataAtCell(1, 0)).toEqual('03/18/2016');
  32214. done();
  32215. }, 130);
  32216. });
  32217. it('should not positively validate a non-date string', function (done) {
  32218. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32219. handsontable({
  32220. data: arrayOfObjects(),
  32221. columns: [{ data: 'date', type: 'date' }, { data: 'name' }, { data: 'lastName' }],
  32222. afterValidate: onAfterValidate
  32223. });
  32224. setDataAtCell(0, 0, 'wat');
  32225. setTimeout(function () {
  32226. expect(onAfterValidate).toHaveBeenCalledWith(false, 'wat', 0, 'date', undefined, undefined);
  32227. done();
  32228. }, 100);
  32229. });
  32230. it('should not positively validate a incorrect date string', function (done) {
  32231. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32232. handsontable({
  32233. data: arrayOfObjects(),
  32234. columns: [{ data: 'date', type: 'date' }, { data: 'name' }, { data: 'lastName' }],
  32235. afterValidate: onAfterValidate
  32236. });
  32237. setDataAtCell(0, 0, '33/01/2014');
  32238. setTimeout(function () {
  32239. expect(onAfterValidate).toHaveBeenCalledWith(false, '33/01/2014', 0, 'date', undefined, undefined);
  32240. done();
  32241. }, 100);
  32242. });
  32243. it('should not positively validate a date string in wrong format', function (done) {
  32244. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32245. handsontable({
  32246. data: arrayOfObjects(),
  32247. columns: [{ data: 'date', type: 'date' }, { data: 'name' }, { data: 'lastName' }],
  32248. afterValidate: onAfterValidate
  32249. });
  32250. setDataAtCell(1, 0, '01/01/15');
  32251. setTimeout(function () {
  32252. expect(onAfterValidate).toHaveBeenCalledWith(false, '01/01/15', 1, 'date', undefined, undefined);
  32253. done();
  32254. }, 100);
  32255. });
  32256. it('should not positively validate a date string in wrong format (if custom format is provided)', function (done) {
  32257. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32258. handsontable({
  32259. data: arrayOfObjects(),
  32260. columns: [{ data: 'date', type: 'date', dateFormat: 'DD/MM/YY' }, { data: 'name' }, { data: 'lastName' }],
  32261. afterValidate: onAfterValidate
  32262. });
  32263. setDataAtCell(1, 0, '01/01/2015');
  32264. setTimeout(function () {
  32265. expect(onAfterValidate).toHaveBeenCalledWith(false, '01/01/2015', 1, 'date', undefined, undefined);
  32266. done();
  32267. }, 100);
  32268. });
  32269. it('should positively validate a date string in correct format', function (done) {
  32270. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32271. handsontable({
  32272. data: arrayOfObjects(),
  32273. columns: [{ data: 'date', type: 'date' }, { data: 'name' }, { data: 'lastName' }],
  32274. afterValidate: onAfterValidate
  32275. });
  32276. setDataAtCell(1, 0, '01/01/2015');
  32277. setTimeout(function () {
  32278. expect(onAfterValidate).toHaveBeenCalledWith(true, '01/01/2015', 1, 'date', undefined, undefined);
  32279. done();
  32280. }, 100);
  32281. });
  32282. it('should positively validate a date string in correct format (if custom format is provided)', function (done) {
  32283. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32284. handsontable({
  32285. data: arrayOfObjects(),
  32286. columns: [{ data: 'date', type: 'date', dateFormat: 'DD/MM/YY' }, { data: 'name' }, { data: 'lastName' }],
  32287. afterValidate: onAfterValidate
  32288. });
  32289. setDataAtCell(1, 0, '23/03/15');
  32290. setTimeout(function () {
  32291. expect(onAfterValidate).toHaveBeenCalledWith(true, '23/03/15', 1, 'date', undefined, undefined);
  32292. done();
  32293. }, 100);
  32294. });
  32295. describe('allowEmpty', function () {
  32296. it('should not validate an empty string when allowEmpty is set as `false`', function (done) {
  32297. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32298. handsontable({
  32299. data: arrayOfObjects(),
  32300. columns: [{ data: 'date', type: 'date', dateFormat: 'DD/MM/YY', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32301. afterValidate: onAfterValidate
  32302. });
  32303. setDataAtCell(1, 0, '');
  32304. setTimeout(function () {
  32305. expect(onAfterValidate).toHaveBeenCalledWith(false, '', 1, 'date', undefined, undefined);
  32306. done();
  32307. }, 100);
  32308. });
  32309. it('should not validate `null` when allowEmpty is set as `false`', function (done) {
  32310. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32311. handsontable({
  32312. data: arrayOfObjects(),
  32313. columns: [{ data: 'date', type: 'date', dateFormat: 'DD/MM/YY', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32314. afterValidate: onAfterValidate
  32315. });
  32316. setDataAtCell(1, 0, null);
  32317. setTimeout(function () {
  32318. expect(onAfterValidate).toHaveBeenCalledWith(false, null, 1, 'date', undefined, undefined);
  32319. done();
  32320. }, 100);
  32321. });
  32322. it('should not validate `undefined` when allowEmpty is set as `false`', function (done) {
  32323. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32324. handsontable({
  32325. data: arrayOfObjects(),
  32326. columns: [{ data: 'date', type: 'date', dateFormat: 'DD/MM/YY', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32327. afterValidate: onAfterValidate
  32328. });
  32329. setDataAtCell(1, 0, void 0);
  32330. setTimeout(function () {
  32331. expect(onAfterValidate).toHaveBeenCalledWith(false, void 0, 1, 'date', undefined, undefined);
  32332. done();
  32333. }, 100);
  32334. });
  32335. });
  32336. describe('correctFormat', function () {
  32337. it('should not make any changes to entered string if correctFormat is not set', function (done) {
  32338. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32339. handsontable({
  32340. data: arrayOfObjects(),
  32341. columns: [{ data: 'date', type: 'date', dateFormat: 'MM/DD/YY' }, { data: 'name' }, { data: 'lastName' }],
  32342. afterValidate: onAfterValidate
  32343. });
  32344. setDataAtCell(1, 0, '11/23/2013');
  32345. setTimeout(function () {
  32346. expect(onAfterValidate).toHaveBeenCalledWith(false, '11/23/2013', 1, 'date', undefined, undefined);
  32347. done();
  32348. }, 100);
  32349. });
  32350. it('should not make any changes to entered string if correctFormat is set to false', function (done) {
  32351. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32352. handsontable({
  32353. data: arrayOfObjects(),
  32354. columns: [{ data: 'date', type: 'date', dateFormat: 'MM/DD/YY', correctFormat: false }, { data: 'name' }, { data: 'lastName' }],
  32355. afterValidate: onAfterValidate
  32356. });
  32357. setDataAtCell(1, 0, '11/23/2013');
  32358. setTimeout(function () {
  32359. expect(onAfterValidate).toHaveBeenCalledWith(false, '11/23/2013', 1, 'date', undefined, undefined);
  32360. done();
  32361. }, 100);
  32362. });
  32363. it('should rewrite the string to the correct format if a date-string in different format is provided', function (done) {
  32364. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32365. handsontable({
  32366. data: arrayOfObjects(),
  32367. columns: [{ data: 'date', type: 'date', dateFormat: 'MM/DD/YYYY', correctFormat: true }, { data: 'lastName' }],
  32368. afterValidate: onAfterValidate
  32369. });
  32370. setDataAtCell(1, 0, '1/10/15');
  32371. setTimeout(function () {
  32372. expect(onAfterValidate).toHaveBeenCalledWith(true, '1/10/15', 1, 'date', undefined, undefined);
  32373. }, 100);
  32374. setTimeout(function () {
  32375. expect(getDataAtCell(1, 0)).toEqual('01/10/2015');
  32376. done();
  32377. }, 130);
  32378. });
  32379. it('should rewrite the string to the correct format if a date-string in different format is provided (for non-default format)', function (done) {
  32380. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32381. handsontable({
  32382. data: arrayOfObjects(),
  32383. columns: [{ data: 'date', type: 'date', dateFormat: 'DD.MM.YYYY', correctFormat: true }, { data: 'lastName' }],
  32384. afterValidate: onAfterValidate
  32385. });
  32386. setDataAtCell(1, 0, '5.3.2016');
  32387. setTimeout(function () {
  32388. expect(onAfterValidate).toHaveBeenCalledWith(true, '5.3.2016', 1, 'date', undefined, undefined);
  32389. }, 100);
  32390. setTimeout(function () {
  32391. expect(getDataAtCell(1, 0)).toEqual('05.03.2016');
  32392. done();
  32393. }, 130);
  32394. });
  32395. it('should not try to correct format of non-date strings', function (done) {
  32396. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32397. handsontable({
  32398. data: arrayOfObjects(),
  32399. columns: [{ data: 'date', type: 'date', dateFormat: 'DD/MM/YY', correctFormat: true }, { data: 'name' }, { data: 'lastName' }],
  32400. afterValidate: onAfterValidate
  32401. });
  32402. setDataAtCell(1, 0, 'test non-date string');
  32403. setTimeout(function () {
  32404. expect(onAfterValidate).toHaveBeenCalledWith(false, 'test non-date string', 1, 'date', undefined, undefined);
  32405. done();
  32406. }, 100);
  32407. });
  32408. });
  32409. });
  32410. /***/ }),
  32411. /* 242 */
  32412. /***/ (function(module, exports, __webpack_require__) {
  32413. "use strict";
  32414. function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
  32415. describe('validators', function () {
  32416. var id = 'testContainer';
  32417. var _Handsontable$validat = Handsontable.validators,
  32418. registerValidator = _Handsontable$validat.registerValidator,
  32419. getValidator = _Handsontable$validat.getValidator;
  32420. beforeEach(function () {
  32421. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  32422. });
  32423. afterEach(function () {
  32424. if (this.$container) {
  32425. destroy();
  32426. this.$container.remove();
  32427. }
  32428. });
  32429. it('should register custom validator', _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
  32430. var onAfterValidate, hot;
  32431. return regeneratorRuntime.wrap(function _callee$(_context) {
  32432. while (1) {
  32433. switch (_context.prev = _context.next) {
  32434. case 0:
  32435. registerValidator('myValidator', function (value, cb) {
  32436. cb(value === 10);
  32437. });
  32438. onAfterValidate = jasmine.createSpy('onAfterValidate');
  32439. hot = handsontable({
  32440. data: [[1, 6, 10]],
  32441. columns: [{
  32442. validator: 'myValidator'
  32443. }],
  32444. afterValidate: onAfterValidate
  32445. });
  32446. hot.setDataAtCell(1, 0, 10);
  32447. _context.next = 6;
  32448. return sleep(100);
  32449. case 6:
  32450. expect(onAfterValidate).toHaveBeenCalledWith(true, 10, 1, 0, undefined, undefined);
  32451. hot.setDataAtCell(2, 0, 2);
  32452. _context.next = 10;
  32453. return sleep(100);
  32454. case 10:
  32455. expect(onAfterValidate).toHaveBeenCalledWith(false, 2, 2, 0, undefined, undefined);
  32456. case 11:
  32457. case 'end':
  32458. return _context.stop();
  32459. }
  32460. }
  32461. }, _callee, undefined);
  32462. })));
  32463. it('should retrieve predefined validators by its names', function () {
  32464. expect(getValidator('autocomplete')).toBeFunction();
  32465. expect(getValidator('date')).toBeFunction();
  32466. expect(getValidator('numeric')).toBeFunction();
  32467. expect(getValidator('time')).toBeFunction();
  32468. });
  32469. it('should retrieve custom validator by its names', function () {
  32470. registerValidator('myValidator', function (value, cb) {
  32471. cb(value === 10);
  32472. });
  32473. getValidator('myValidator')(2, function (isValid) {
  32474. expect(isValid).toBe(false);
  32475. });
  32476. getValidator('myValidator')('10', function (isValid) {
  32477. expect(isValid).toBe(false);
  32478. });
  32479. getValidator('myValidator')(10, function (isValid) {
  32480. expect(isValid).toBe(true);
  32481. });
  32482. });
  32483. });
  32484. /***/ }),
  32485. /* 243 */
  32486. /***/ (function(module, exports, __webpack_require__) {
  32487. "use strict";
  32488. describe('numericValidator', function () {
  32489. var id = 'testContainer';
  32490. beforeEach(function () {
  32491. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  32492. });
  32493. afterEach(function () {
  32494. if (this.$container) {
  32495. destroy();
  32496. this.$container.remove();
  32497. }
  32498. });
  32499. var arrayOfObjects = function arrayOfObjects() {
  32500. return [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }, { id: 6, name: 'Chuck', lastName: 'Jackson' }, { id: 7, name: 'Meg', lastName: 'Jansen' }, { id: 8, name: 'Rob', lastName: 'Norris' }, { id: 9, name: 'Sean', lastName: 'O\'Hara' }, { id: 10, name: 'Eve', lastName: 'Branson' }];
  32501. };
  32502. it('should validate an empty string (default behavior)', function (done) {
  32503. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32504. handsontable({
  32505. data: arrayOfObjects(),
  32506. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  32507. afterValidate: onAfterValidate
  32508. });
  32509. setDataAtCell(2, 0, '');
  32510. setTimeout(function () {
  32511. expect(onAfterValidate).toHaveBeenCalledWith(true, '', 2, 'id', undefined, undefined);
  32512. done();
  32513. }, 100);
  32514. });
  32515. it('should not validate non numeric string', function (done) {
  32516. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32517. handsontable({
  32518. data: arrayOfObjects(),
  32519. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  32520. afterValidate: onAfterValidate
  32521. });
  32522. setDataAtCell(2, 0, 'test');
  32523. setTimeout(function () {
  32524. expect(onAfterValidate).toHaveBeenCalledWith(false, 'test', 2, 'id', undefined, undefined);
  32525. done();
  32526. }, 100);
  32527. });
  32528. it('should validate numeric string', function (done) {
  32529. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32530. handsontable({
  32531. data: arrayOfObjects(),
  32532. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  32533. afterValidate: onAfterValidate
  32534. });
  32535. setDataAtCell(2, 0, '123');
  32536. setTimeout(function () {
  32537. expect(onAfterValidate).toHaveBeenCalledWith(true, 123, 2, 'id', undefined, undefined);
  32538. done();
  32539. }, 100);
  32540. });
  32541. it('should validate signed numeric string', function (done) {
  32542. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32543. handsontable({
  32544. data: arrayOfObjects(),
  32545. columns: [{ data: 'id', type: 'numeric' }, { data: 'name' }, { data: 'lastName' }],
  32546. afterValidate: onAfterValidate
  32547. });
  32548. setDataAtCell(2, 0, '-123');
  32549. setTimeout(function () {
  32550. expect(onAfterValidate).toHaveBeenCalledWith(true, -123, 2, 'id', undefined, undefined);
  32551. done();
  32552. }, 100);
  32553. });
  32554. describe('allowEmpty', function () {
  32555. it('should not validate an empty string when allowEmpty is set as `false`', function (done) {
  32556. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32557. handsontable({
  32558. data: arrayOfObjects(),
  32559. columns: [{ data: 'id', type: 'numeric', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32560. afterValidate: onAfterValidate
  32561. });
  32562. setDataAtCell(2, 0, '');
  32563. setTimeout(function () {
  32564. expect(onAfterValidate).toHaveBeenCalledWith(false, '', 2, 'id', undefined, undefined);
  32565. done();
  32566. }, 100);
  32567. });
  32568. it('should not validate `null` when allowEmpty is set as `false`', function (done) {
  32569. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32570. handsontable({
  32571. data: arrayOfObjects(),
  32572. columns: [{ data: 'id', type: 'numeric', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32573. afterValidate: onAfterValidate
  32574. });
  32575. setDataAtCell(2, 0, null);
  32576. setTimeout(function () {
  32577. expect(onAfterValidate).toHaveBeenCalledWith(false, null, 2, 'id', undefined, undefined);
  32578. done();
  32579. }, 100);
  32580. });
  32581. it('should not validate `undefined` when allowEmpty is set as `false`', function (done) {
  32582. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32583. handsontable({
  32584. data: arrayOfObjects(),
  32585. columns: [{ data: 'id', type: 'numeric', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32586. afterValidate: onAfterValidate
  32587. });
  32588. setDataAtCell(2, 0, void 0);
  32589. setTimeout(function () {
  32590. expect(onAfterValidate).toHaveBeenCalledWith(false, void 0, 2, 'id', undefined, undefined);
  32591. done();
  32592. }, 100);
  32593. });
  32594. it('should validate 0 when allowEmpty is set as `false`', function (done) {
  32595. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32596. handsontable({
  32597. data: arrayOfObjects(),
  32598. columns: [{ data: 'id', type: 'numeric', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32599. afterValidate: onAfterValidate
  32600. });
  32601. setDataAtCell(2, 0, 0);
  32602. setTimeout(function () {
  32603. expect(onAfterValidate).toHaveBeenCalledWith(true, 0, 2, 'id', undefined, undefined);
  32604. done();
  32605. }, 100);
  32606. });
  32607. it('should add / remove `htInvalid` class properly when validating non-numeric data', function (done) {
  32608. var hot = handsontable({
  32609. data: [{ id: 1, name: 'Ted', salary: 10000 }, { id: 2, name: 'Frank', salary: '5300' }, { id: 3, name: 'Joan', salary: 'non-numeric value' }],
  32610. columns: [{ data: 'id' }, { data: 'name' }, { data: 'salary', type: 'numeric', allowInvalid: false }]
  32611. });
  32612. hot.validateCells();
  32613. setTimeout(function () {
  32614. expect($(getCell(1, 2)).hasClass(hot.getSettings().invalidCellClassName)).toBe(false);
  32615. expect($(getCell(2, 2)).hasClass(hot.getSettings().invalidCellClassName)).toBe(true);
  32616. setDataAtCell(2, 2, 8000);
  32617. }, 200);
  32618. setTimeout(function () {
  32619. expect($(getCell(2, 2)).hasClass(hot.getSettings().invalidCellClassName)).toBe(false);
  32620. done();
  32621. }, 400);
  32622. });
  32623. });
  32624. });
  32625. /***/ }),
  32626. /* 244 */
  32627. /***/ (function(module, exports, __webpack_require__) {
  32628. "use strict";
  32629. describe('timeValidator', function () {
  32630. var id = 'testContainer';
  32631. beforeEach(function () {
  32632. this.$container = $('<div id="' + id + '"></div>').appendTo('body');
  32633. });
  32634. afterEach(function () {
  32635. if (this.$container) {
  32636. destroy();
  32637. this.$container.remove();
  32638. }
  32639. });
  32640. var arrayOfObjects = function arrayOfObjects() {
  32641. return [{ time: '4:10:05 am', name: 'Ted', lastName: 'Right' }, { time: '17:15:25', name: 'Frank', lastName: 'Honest' }, { time: '14:65:45 am', name: 'Joan', lastName: 'Well' }, { time: '33:25:05', name: 'Sid', lastName: 'Strong' }];
  32642. };
  32643. it('should validate an empty string (default behavior)', function (done) {
  32644. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32645. handsontable({
  32646. data: arrayOfObjects(),
  32647. columns: [{ data: 'time', type: 'time' }, { data: 'name' }, { data: 'lastName' }],
  32648. afterValidate: onAfterValidate
  32649. });
  32650. setDataAtCell(0, 0, '');
  32651. setTimeout(function () {
  32652. expect(onAfterValidate).toHaveBeenCalledWith(true, '', 0, 'time', undefined, undefined);
  32653. done();
  32654. }, 100);
  32655. });
  32656. it('should not positively validate a non-date format', function (done) {
  32657. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32658. handsontable({
  32659. data: arrayOfObjects(),
  32660. columns: [{ data: 'time', type: 'time' }, { data: 'name' }, { data: 'lastName' }],
  32661. afterValidate: onAfterValidate
  32662. });
  32663. setDataAtCell(0, 0, 'nd');
  32664. setTimeout(function () {
  32665. expect(onAfterValidate).toHaveBeenCalledWith(false, 'nd', 0, 'time', undefined, undefined);
  32666. done();
  32667. }, 100);
  32668. });
  32669. it('should not positively validate a incorrect time string', function (done) {
  32670. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32671. handsontable({
  32672. data: arrayOfObjects(),
  32673. columns: [{ data: 'time', type: 'time' }, { data: 'name' }, { data: 'lastName' }],
  32674. afterValidate: onAfterValidate
  32675. });
  32676. setDataAtCell(0, 0, '30:10:25');
  32677. setTimeout(function () {
  32678. expect(onAfterValidate).toHaveBeenCalledWith(false, '30:10:25', 0, 'time', undefined, undefined);
  32679. done();
  32680. }, 100);
  32681. });
  32682. it('should not positively validate a time string in not default format', function (done) {
  32683. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32684. handsontable({
  32685. data: arrayOfObjects(),
  32686. columns: [{ data: 'time', type: 'time' }, { data: 'name' }, { data: 'lastName' }],
  32687. afterValidate: onAfterValidate
  32688. });
  32689. setDataAtCell(1, 0, '20:20:01');
  32690. setTimeout(function () {
  32691. expect(onAfterValidate).toHaveBeenCalledWith(false, '20:20:01', 1, 'time', undefined, undefined);
  32692. done();
  32693. }, 100);
  32694. });
  32695. it('should not positively validate a time string in wrong format (if custom format is provided)', function (done) {
  32696. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32697. handsontable({
  32698. data: arrayOfObjects(),
  32699. columns: [{ data: 'time', type: 'time', timeFormat: 'HH:mm:ss' }, { data: 'name' }, { data: 'lastName' }],
  32700. afterValidate: onAfterValidate
  32701. });
  32702. setDataAtCell(1, 0, '5:10:15 am');
  32703. setTimeout(function () {
  32704. expect(onAfterValidate).toHaveBeenCalledWith(false, '5:10:15 am', 1, 'time', undefined, undefined);
  32705. done();
  32706. }, 100);
  32707. });
  32708. it('should positively validate a date string in correct format (if custom format is provided)', function (done) {
  32709. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32710. handsontable({
  32711. data: arrayOfObjects(),
  32712. columns: [{ data: 'time', type: 'time', timeFormat: 'HH:mm:ss' }, { data: 'name' }, { data: 'lastName' }],
  32713. afterValidate: onAfterValidate
  32714. });
  32715. setDataAtCell(1, 0, '16:32:03');
  32716. setTimeout(function () {
  32717. expect(onAfterValidate).toHaveBeenCalledWith(true, '16:32:03', 1, 'time', undefined, undefined);
  32718. done();
  32719. }, 100);
  32720. });
  32721. describe('allowEmpty', function () {
  32722. it('should not validate an empty string when allowEmpty is set as `false`', function (done) {
  32723. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32724. handsontable({
  32725. data: arrayOfObjects(),
  32726. columns: [{ data: 'time', type: 'time', dateFormat: 'HH:mm', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32727. afterValidate: onAfterValidate
  32728. });
  32729. setDataAtCell(1, 0, '');
  32730. setTimeout(function () {
  32731. expect(onAfterValidate).toHaveBeenCalledWith(false, '', 1, 'time', undefined, undefined);
  32732. done();
  32733. }, 100);
  32734. });
  32735. it('should not validate `null` when allowEmpty is set as `false`', function (done) {
  32736. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32737. handsontable({
  32738. data: arrayOfObjects(),
  32739. columns: [{ data: 'time', type: 'time', dateFormat: 'HH:mm', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32740. afterValidate: onAfterValidate
  32741. });
  32742. setDataAtCell(1, 0, null);
  32743. setTimeout(function () {
  32744. expect(onAfterValidate).toHaveBeenCalledWith(false, null, 1, 'time', undefined, undefined);
  32745. done();
  32746. }, 100);
  32747. });
  32748. it('should not validate `undefined` when allowEmpty is set as `false`', function (done) {
  32749. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32750. handsontable({
  32751. data: arrayOfObjects(),
  32752. columns: [{ data: 'time', type: 'time', dateFormat: 'HH:mm', allowEmpty: false }, { data: 'name' }, { data: 'lastName' }],
  32753. afterValidate: onAfterValidate
  32754. });
  32755. setDataAtCell(1, 0, void 0);
  32756. setTimeout(function () {
  32757. expect(onAfterValidate).toHaveBeenCalledWith(false, void 0, 1, 'time', undefined, undefined);
  32758. done();
  32759. }, 100);
  32760. });
  32761. });
  32762. describe('correctFormat', function () {
  32763. it('should not make any changes to entered string if correctFormat is not set', function (done) {
  32764. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32765. handsontable({
  32766. data: arrayOfObjects(),
  32767. columns: [{ data: 'time', type: 'time', timeFormat: 'h:mm:ss a' }, { data: 'name' }, { data: 'lastName' }],
  32768. afterValidate: onAfterValidate
  32769. });
  32770. setDataAtCell(1, 0, '13:00:00');
  32771. setTimeout(function () {
  32772. expect(onAfterValidate).toHaveBeenCalledWith(false, '13:00:00', 1, 'time', undefined, undefined);
  32773. done();
  32774. }, 100);
  32775. });
  32776. it('should not make any changes to entered string if correctFormat is set to false', function (done) {
  32777. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32778. handsontable({
  32779. data: arrayOfObjects(),
  32780. columns: [{ data: 'time', type: 'time', timeFormat: 'h:mm:ss a', correctFormat: false }, { data: 'name' }, { data: 'lastName' }],
  32781. afterValidate: onAfterValidate
  32782. });
  32783. setDataAtCell(1, 0, '13:00:00');
  32784. setTimeout(function () {
  32785. expect(onAfterValidate).toHaveBeenCalledWith(false, '13:00:00', 1, 'time', undefined, undefined);
  32786. done();
  32787. }, 100);
  32788. });
  32789. it('should rewrite the string to the correct format if a time-string in different format is provided', function (done) {
  32790. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32791. handsontable({
  32792. data: arrayOfObjects(),
  32793. columns: [{ data: 'time', type: 'time', timeFormat: 'h:mm:ss a', correctFormat: true }, { data: 'lastName' }],
  32794. afterValidate: onAfterValidate
  32795. });
  32796. setDataAtCell(1, 0, '16:35:01');
  32797. setTimeout(function () {
  32798. expect(onAfterValidate).toHaveBeenCalledWith(true, '16:35:01', 1, 'time', undefined, undefined);
  32799. }, 100);
  32800. setTimeout(function () {
  32801. expect(getDataAtCell(1, 0)).toEqual('4:35:01 pm');
  32802. done();
  32803. }, 130);
  32804. });
  32805. it('should rewrite the string to the correct format if a time in micro-timestamp format is provided', function (done) {
  32806. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32807. handsontable({
  32808. data: arrayOfObjects(),
  32809. columns: [{ data: 'time', type: 'time', timeFormat: 'HH:mm:ss', correctFormat: true }, { data: 'lastName' }],
  32810. afterValidate: onAfterValidate
  32811. });
  32812. var currentDateTime = new Date();
  32813. setDataAtCell(1, 0, currentDateTime.getTime()); // timestamp in milliseconds
  32814. setTimeout(function () {
  32815. expect(onAfterValidate).toHaveBeenCalledWith(true, currentDateTime.getTime(), 1, 'time', undefined, undefined);
  32816. }, 100);
  32817. setTimeout(function () {
  32818. var addLeadingZero = function addLeadingZero(number) {
  32819. return number < 10 ? '0' + number : number;
  32820. };
  32821. expect(getDataAtCell(1, 0)).toEqual(addLeadingZero(currentDateTime.getHours()) + ':' + addLeadingZero(currentDateTime.getMinutes()) + ':' + addLeadingZero(currentDateTime.getSeconds()));
  32822. done();
  32823. }, 130);
  32824. });
  32825. it('should rewrite the string to the correct format if a time in ISO8601 format is provided', function (done) {
  32826. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32827. handsontable({
  32828. data: arrayOfObjects(),
  32829. columns: [{ data: 'time', type: 'time', timeFormat: 'HH:mm:ss', correctFormat: true }, { data: 'lastName' }],
  32830. afterValidate: onAfterValidate
  32831. });
  32832. var currentDateTime = new Date();
  32833. setDataAtCell(1, 0, currentDateTime.toISOString()); // ISO-formatted datetime, sth like '2016-02-19T12:40:04.983Z'
  32834. setTimeout(function () {
  32835. expect(onAfterValidate).toHaveBeenCalledWith(true, currentDateTime.toISOString(), 1, 'time', undefined, undefined);
  32836. }, 100);
  32837. setTimeout(function () {
  32838. var addLeadingZero = function addLeadingZero(number) {
  32839. return number < 10 ? '0' + number : number;
  32840. };
  32841. expect(getDataAtCell(1, 0)).toEqual(addLeadingZero(currentDateTime.getHours()) + ':' + addLeadingZero(currentDateTime.getMinutes()) + ':' + addLeadingZero(currentDateTime.getSeconds()));
  32842. done();
  32843. }, 130);
  32844. });
  32845. it('should rewrite one and two-digit number to the correct format at hours', function (done) {
  32846. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32847. handsontable({
  32848. data: arrayOfObjects(),
  32849. columns: [{ data: 'time', type: 'time', timeFormat: 'hh:mm:ss a', correctFormat: true }, { data: 'lastName' }],
  32850. afterValidate: onAfterValidate
  32851. });
  32852. setDataAtCell(1, 0, '19');
  32853. setTimeout(function () {
  32854. expect(onAfterValidate).toHaveBeenCalledWith(true, '19', 1, 'time', undefined, undefined);
  32855. }, 100);
  32856. setTimeout(function () {
  32857. expect(getDataAtCell(1, 0)).toEqual('07:00:00 pm');
  32858. done();
  32859. }, 130);
  32860. });
  32861. it('should rewrite one and two-digit number to the correct format at minutes', function (done) {
  32862. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32863. handsontable({
  32864. data: arrayOfObjects(),
  32865. columns: [{ data: 'time', type: 'time', timeFormat: 'mm:ss', correctFormat: true }, { data: 'lastName' }],
  32866. afterValidate: onAfterValidate
  32867. });
  32868. setDataAtCell(1, 0, '57');
  32869. setTimeout(function () {
  32870. expect(onAfterValidate).toHaveBeenCalledWith(true, '57', 1, 'time', undefined, undefined);
  32871. }, 100);
  32872. setTimeout(function () {
  32873. expect(getDataAtCell(1, 0)).toEqual('57:00');
  32874. done();
  32875. }, 130);
  32876. });
  32877. it('should not try to correct format of non-date strings', function (done) {
  32878. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  32879. handsontable({
  32880. data: arrayOfObjects(),
  32881. columns: [{ data: 'time', type: 'time', timeFormat: 'HH:mm:ss', correctFormat: true }, { data: 'name' }, { data: 'lastName' }],
  32882. afterValidate: onAfterValidate
  32883. });
  32884. setDataAtCell(1, 0, 'test non-time string');
  32885. setTimeout(function () {
  32886. expect(onAfterValidate).toHaveBeenCalledWith(false, 'test non-time string', 1, 'time', undefined, undefined);
  32887. done();
  32888. }, 100);
  32889. });
  32890. });
  32891. });
  32892. /***/ }),
  32893. /* 245 */,
  32894. /* 246 */
  32895. /***/ (function(module, exports) {
  32896. /**
  32897. * slice() reference.
  32898. */
  32899. var slice = Array.prototype.slice;
  32900. /**
  32901. * Expose `co`.
  32902. */
  32903. module.exports = co['default'] = co.co = co;
  32904. /**
  32905. * Wrap the given generator `fn` into a
  32906. * function that returns a promise.
  32907. * This is a separate function so that
  32908. * every `co()` call doesn't create a new,
  32909. * unnecessary closure.
  32910. *
  32911. * @param {GeneratorFunction} fn
  32912. * @return {Function}
  32913. * @api public
  32914. */
  32915. co.wrap = function (fn) {
  32916. createPromise.__generatorFunction__ = fn;
  32917. return createPromise;
  32918. function createPromise() {
  32919. return co.call(this, fn.apply(this, arguments));
  32920. }
  32921. };
  32922. /**
  32923. * Execute the generator function or a generator
  32924. * and return a promise.
  32925. *
  32926. * @param {Function} fn
  32927. * @return {Promise}
  32928. * @api public
  32929. */
  32930. function co(gen) {
  32931. var ctx = this;
  32932. var args = slice.call(arguments, 1)
  32933. // we wrap everything in a promise to avoid promise chaining,
  32934. // which leads to memory leak errors.
  32935. // see https://github.com/tj/co/issues/180
  32936. return new Promise(function(resolve, reject) {
  32937. if (typeof gen === 'function') gen = gen.apply(ctx, args);
  32938. if (!gen || typeof gen.next !== 'function') return resolve(gen);
  32939. onFulfilled();
  32940. /**
  32941. * @param {Mixed} res
  32942. * @return {Promise}
  32943. * @api private
  32944. */
  32945. function onFulfilled(res) {
  32946. var ret;
  32947. try {
  32948. ret = gen.next(res);
  32949. } catch (e) {
  32950. return reject(e);
  32951. }
  32952. next(ret);
  32953. }
  32954. /**
  32955. * @param {Error} err
  32956. * @return {Promise}
  32957. * @api private
  32958. */
  32959. function onRejected(err) {
  32960. var ret;
  32961. try {
  32962. ret = gen.throw(err);
  32963. } catch (e) {
  32964. return reject(e);
  32965. }
  32966. next(ret);
  32967. }
  32968. /**
  32969. * Get the next value in the generator,
  32970. * return a promise.
  32971. *
  32972. * @param {Object} ret
  32973. * @return {Promise}
  32974. * @api private
  32975. */
  32976. function next(ret) {
  32977. if (ret.done) return resolve(ret.value);
  32978. var value = toPromise.call(ctx, ret.value);
  32979. if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
  32980. return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
  32981. + 'but the following object was passed: "' + String(ret.value) + '"'));
  32982. }
  32983. });
  32984. }
  32985. /**
  32986. * Convert a `yield`ed value into a promise.
  32987. *
  32988. * @param {Mixed} obj
  32989. * @return {Promise}
  32990. * @api private
  32991. */
  32992. function toPromise(obj) {
  32993. if (!obj) return obj;
  32994. if (isPromise(obj)) return obj;
  32995. if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
  32996. if ('function' == typeof obj) return thunkToPromise.call(this, obj);
  32997. if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
  32998. if (isObject(obj)) return objectToPromise.call(this, obj);
  32999. return obj;
  33000. }
  33001. /**
  33002. * Convert a thunk to a promise.
  33003. *
  33004. * @param {Function}
  33005. * @return {Promise}
  33006. * @api private
  33007. */
  33008. function thunkToPromise(fn) {
  33009. var ctx = this;
  33010. return new Promise(function (resolve, reject) {
  33011. fn.call(ctx, function (err, res) {
  33012. if (err) return reject(err);
  33013. if (arguments.length > 2) res = slice.call(arguments, 1);
  33014. resolve(res);
  33015. });
  33016. });
  33017. }
  33018. /**
  33019. * Convert an array of "yieldables" to a promise.
  33020. * Uses `Promise.all()` internally.
  33021. *
  33022. * @param {Array} obj
  33023. * @return {Promise}
  33024. * @api private
  33025. */
  33026. function arrayToPromise(obj) {
  33027. return Promise.all(obj.map(toPromise, this));
  33028. }
  33029. /**
  33030. * Convert an object of "yieldables" to a promise.
  33031. * Uses `Promise.all()` internally.
  33032. *
  33033. * @param {Object} obj
  33034. * @return {Promise}
  33035. * @api private
  33036. */
  33037. function objectToPromise(obj){
  33038. var results = new obj.constructor();
  33039. var keys = Object.keys(obj);
  33040. var promises = [];
  33041. for (var i = 0; i < keys.length; i++) {
  33042. var key = keys[i];
  33043. var promise = toPromise.call(this, obj[key]);
  33044. if (promise && isPromise(promise)) defer(promise, key);
  33045. else results[key] = obj[key];
  33046. }
  33047. return Promise.all(promises).then(function () {
  33048. return results;
  33049. });
  33050. function defer(promise, key) {
  33051. // predefine the key in the result
  33052. results[key] = undefined;
  33053. promises.push(promise.then(function (res) {
  33054. results[key] = res;
  33055. }));
  33056. }
  33057. }
  33058. /**
  33059. * Check if `obj` is a promise.
  33060. *
  33061. * @param {Object} obj
  33062. * @return {Boolean}
  33063. * @api private
  33064. */
  33065. function isPromise(obj) {
  33066. return 'function' == typeof obj.then;
  33067. }
  33068. /**
  33069. * Check if `obj` is a generator.
  33070. *
  33071. * @param {Mixed} obj
  33072. * @return {Boolean}
  33073. * @api private
  33074. */
  33075. function isGenerator(obj) {
  33076. return 'function' == typeof obj.next && 'function' == typeof obj.throw;
  33077. }
  33078. /**
  33079. * Check if `obj` is a generator function.
  33080. *
  33081. * @param {Mixed} obj
  33082. * @return {Boolean}
  33083. * @api private
  33084. */
  33085. function isGeneratorFunction(obj) {
  33086. var constructor = obj.constructor;
  33087. if (!constructor) return false;
  33088. if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true;
  33089. return isGenerator(constructor.prototype);
  33090. }
  33091. /**
  33092. * Check for plain object.
  33093. *
  33094. * @param {Mixed} val
  33095. * @return {Boolean}
  33096. * @api private
  33097. */
  33098. function isObject(val) {
  33099. return Object == val.constructor;
  33100. }
  33101. /***/ }),
  33102. /* 247 */
  33103. /***/ (function(module, exports, __webpack_require__) {
  33104. "use strict";
  33105. // 22.1.3.3 Array.prototype.copyWithin(target, start, end = this.length)
  33106. var toObject = __webpack_require__(19)
  33107. , toIndex = __webpack_require__(34)
  33108. , toLength = __webpack_require__(9);
  33109. module.exports = [].copyWithin || function copyWithin(target/*= 0*/, start/*= 0, end = @length*/){
  33110. var O = toObject(this)
  33111. , len = toLength(O.length)
  33112. , to = toIndex(target, len)
  33113. , from = toIndex(start, len)
  33114. , end = arguments.length > 2 ? arguments[2] : undefined
  33115. , count = Math.min((end === undefined ? len : toIndex(end, len)) - from, len - to)
  33116. , inc = 1;
  33117. if(from < to && to < from + count){
  33118. inc = -1;
  33119. from += count - 1;
  33120. to += count - 1;
  33121. }
  33122. while(count-- > 0){
  33123. if(from in O)O[to] = O[from];
  33124. else delete O[to];
  33125. to += inc;
  33126. from += inc;
  33127. } return O;
  33128. };
  33129. /***/ }),
  33130. /* 248 */
  33131. /***/ (function(module, exports, __webpack_require__) {
  33132. "use strict";
  33133. // 22.1.3.6 Array.prototype.fill(value, start = 0, end = this.length)
  33134. var toObject = __webpack_require__(19)
  33135. , toIndex = __webpack_require__(34)
  33136. , toLength = __webpack_require__(9);
  33137. module.exports = function fill(value /*, start = 0, end = @length */){
  33138. var O = toObject(this)
  33139. , length = toLength(O.length)
  33140. , aLen = arguments.length
  33141. , index = toIndex(aLen > 1 ? arguments[1] : undefined, length)
  33142. , end = aLen > 2 ? arguments[2] : undefined
  33143. , endPos = end === undefined ? length : toIndex(end, length);
  33144. while(endPos > index)O[index++] = value;
  33145. return O;
  33146. };
  33147. /***/ }),
  33148. /* 249 */
  33149. /***/ (function(module, exports, __webpack_require__) {
  33150. var isObject = __webpack_require__(3)
  33151. , isArray = __webpack_require__(59)
  33152. , SPECIES = __webpack_require__(1)('species');
  33153. module.exports = function(original){
  33154. var C;
  33155. if(isArray(original)){
  33156. C = original.constructor;
  33157. // cross-realm fallback
  33158. if(typeof C == 'function' && (C === Array || isArray(C.prototype)))C = undefined;
  33159. if(isObject(C)){
  33160. C = C[SPECIES];
  33161. if(C === null)C = undefined;
  33162. }
  33163. } return C === undefined ? Array : C;
  33164. };
  33165. /***/ }),
  33166. /* 250 */
  33167. /***/ (function(module, exports, __webpack_require__) {
  33168. // 9.4.2.3 ArraySpeciesCreate(originalArray, length)
  33169. var speciesConstructor = __webpack_require__(249);
  33170. module.exports = function(original, length){
  33171. return new (speciesConstructor(original))(length);
  33172. };
  33173. /***/ }),
  33174. /* 251 */
  33175. /***/ (function(module, exports, __webpack_require__) {
  33176. // all enumerable object keys, includes symbols
  33177. var getKeys = __webpack_require__(17)
  33178. , gOPS = __webpack_require__(32)
  33179. , pIE = __webpack_require__(23);
  33180. module.exports = function(it){
  33181. var result = getKeys(it)
  33182. , getSymbols = gOPS.f;
  33183. if(getSymbols){
  33184. var symbols = getSymbols(it)
  33185. , isEnum = pIE.f
  33186. , i = 0
  33187. , key;
  33188. while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))result.push(key);
  33189. } return result;
  33190. };
  33191. /***/ }),
  33192. /* 252 */
  33193. /***/ (function(module, exports, __webpack_require__) {
  33194. "use strict";
  33195. // 21.2.5.3 get RegExp.prototype.flags
  33196. var anObject = __webpack_require__(4);
  33197. module.exports = function(){
  33198. var that = anObject(this)
  33199. , result = '';
  33200. if(that.global) result += 'g';
  33201. if(that.ignoreCase) result += 'i';
  33202. if(that.multiline) result += 'm';
  33203. if(that.unicode) result += 'u';
  33204. if(that.sticky) result += 'y';
  33205. return result;
  33206. };
  33207. /***/ }),
  33208. /* 253 */
  33209. /***/ (function(module, exports, __webpack_require__) {
  33210. var isObject = __webpack_require__(3)
  33211. , setPrototypeOf = __webpack_require__(68).set;
  33212. module.exports = function(that, target, C){
  33213. var P, S = target.constructor;
  33214. if(S !== C && typeof S == 'function' && (P = S.prototype) !== C.prototype && isObject(P) && setPrototypeOf){
  33215. setPrototypeOf(that, P);
  33216. } return that;
  33217. };
  33218. /***/ }),
  33219. /* 254 */
  33220. /***/ (function(module, exports) {
  33221. // fast apply, http://jsperf.lnkit.com/fast-apply/5
  33222. module.exports = function(fn, args, that){
  33223. var un = that === undefined;
  33224. switch(args.length){
  33225. case 0: return un ? fn()
  33226. : fn.call(that);
  33227. case 1: return un ? fn(args[0])
  33228. : fn.call(that, args[0]);
  33229. case 2: return un ? fn(args[0], args[1])
  33230. : fn.call(that, args[0], args[1]);
  33231. case 3: return un ? fn(args[0], args[1], args[2])
  33232. : fn.call(that, args[0], args[1], args[2]);
  33233. case 4: return un ? fn(args[0], args[1], args[2], args[3])
  33234. : fn.call(that, args[0], args[1], args[2], args[3]);
  33235. } return fn.apply(that, args);
  33236. };
  33237. /***/ }),
  33238. /* 255 */
  33239. /***/ (function(module, exports, __webpack_require__) {
  33240. "use strict";
  33241. var create = __webpack_require__(43)
  33242. , descriptor = __webpack_require__(18)
  33243. , setToStringTag = __webpack_require__(24)
  33244. , IteratorPrototype = {};
  33245. // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
  33246. __webpack_require__(13)(IteratorPrototype, __webpack_require__(1)('iterator'), function(){ return this; });
  33247. module.exports = function(Constructor, NAME, next){
  33248. Constructor.prototype = create(IteratorPrototype, {next: descriptor(1, next)});
  33249. setToStringTag(Constructor, NAME + ' Iterator');
  33250. };
  33251. /***/ }),
  33252. /* 256 */
  33253. /***/ (function(module, exports, __webpack_require__) {
  33254. var getKeys = __webpack_require__(17)
  33255. , toIObject = __webpack_require__(8);
  33256. module.exports = function(object, el){
  33257. var O = toIObject(object)
  33258. , keys = getKeys(O)
  33259. , length = keys.length
  33260. , index = 0
  33261. , key;
  33262. while(length > index)if(O[key = keys[index++]] === el)return key;
  33263. };
  33264. /***/ }),
  33265. /* 257 */
  33266. /***/ (function(module, exports, __webpack_require__) {
  33267. var global = __webpack_require__(2)
  33268. , macrotask = __webpack_require__(49).set
  33269. , Observer = global.MutationObserver || global.WebKitMutationObserver
  33270. , process = global.process
  33271. , Promise = global.Promise
  33272. , isNode = __webpack_require__(16)(process) == 'process';
  33273. module.exports = function(){
  33274. var head, last, notify;
  33275. var flush = function(){
  33276. var parent, fn;
  33277. if(isNode && (parent = process.domain))parent.exit();
  33278. while(head){
  33279. fn = head.fn;
  33280. head = head.next;
  33281. try {
  33282. fn();
  33283. } catch(e){
  33284. if(head)notify();
  33285. else last = undefined;
  33286. throw e;
  33287. }
  33288. } last = undefined;
  33289. if(parent)parent.enter();
  33290. };
  33291. // Node.js
  33292. if(isNode){
  33293. notify = function(){
  33294. process.nextTick(flush);
  33295. };
  33296. // browsers with MutationObserver
  33297. } else if(Observer){
  33298. var toggle = true
  33299. , node = document.createTextNode('');
  33300. new Observer(flush).observe(node, {characterData: true}); // eslint-disable-line no-new
  33301. notify = function(){
  33302. node.data = toggle = !toggle;
  33303. };
  33304. // environments with maybe non-completely correct, but existent Promise
  33305. } else if(Promise && Promise.resolve){
  33306. var promise = Promise.resolve();
  33307. notify = function(){
  33308. promise.then(flush);
  33309. };
  33310. // for other environments - macrotask based on:
  33311. // - setImmediate
  33312. // - MessageChannel
  33313. // - window.postMessag
  33314. // - onreadystatechange
  33315. // - setTimeout
  33316. } else {
  33317. notify = function(){
  33318. // strange IE + webpack dev server bug - use .call(global)
  33319. macrotask.call(global, flush);
  33320. };
  33321. }
  33322. return function(fn){
  33323. var task = {fn: fn, next: undefined};
  33324. if(last)last.next = task;
  33325. if(!head){
  33326. head = task;
  33327. notify();
  33328. } last = task;
  33329. };
  33330. };
  33331. /***/ }),
  33332. /* 258 */
  33333. /***/ (function(module, exports, __webpack_require__) {
  33334. var dP = __webpack_require__(5)
  33335. , anObject = __webpack_require__(4)
  33336. , getKeys = __webpack_require__(17);
  33337. module.exports = __webpack_require__(6) ? Object.defineProperties : function defineProperties(O, Properties){
  33338. anObject(O);
  33339. var keys = getKeys(Properties)
  33340. , length = keys.length
  33341. , i = 0
  33342. , P;
  33343. while(length > i)dP.f(O, P = keys[i++], Properties[P]);
  33344. return O;
  33345. };
  33346. /***/ }),
  33347. /* 259 */
  33348. /***/ (function(module, exports, __webpack_require__) {
  33349. // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
  33350. var toIObject = __webpack_require__(8)
  33351. , gOPN = __webpack_require__(45).f
  33352. , toString = {}.toString;
  33353. var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames
  33354. ? Object.getOwnPropertyNames(window) : [];
  33355. var getWindowNames = function(it){
  33356. try {
  33357. return gOPN(it);
  33358. } catch(e){
  33359. return windowNames.slice();
  33360. }
  33361. };
  33362. module.exports.f = function getOwnPropertyNames(it){
  33363. return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(toIObject(it));
  33364. };
  33365. /***/ }),
  33366. /* 260 */
  33367. /***/ (function(module, exports, __webpack_require__) {
  33368. // 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)
  33369. var has = __webpack_require__(7)
  33370. , toObject = __webpack_require__(19)
  33371. , IE_PROTO = __webpack_require__(46)('IE_PROTO')
  33372. , ObjectProto = Object.prototype;
  33373. module.exports = Object.getPrototypeOf || function(O){
  33374. O = toObject(O);
  33375. if(has(O, IE_PROTO))return O[IE_PROTO];
  33376. if(typeof O.constructor == 'function' && O instanceof O.constructor){
  33377. return O.constructor.prototype;
  33378. } return O instanceof Object ? ObjectProto : null;
  33379. };
  33380. /***/ }),
  33381. /* 261 */
  33382. /***/ (function(module, exports, __webpack_require__) {
  33383. // all object keys, includes non-enumerable and symbols
  33384. var gOPN = __webpack_require__(45)
  33385. , gOPS = __webpack_require__(32)
  33386. , anObject = __webpack_require__(4)
  33387. , Reflect = __webpack_require__(2).Reflect;
  33388. module.exports = Reflect && Reflect.ownKeys || function ownKeys(it){
  33389. var keys = gOPN.f(anObject(it))
  33390. , getSymbols = gOPS.f;
  33391. return getSymbols ? keys.concat(getSymbols(it)) : keys;
  33392. };
  33393. /***/ }),
  33394. /* 262 */
  33395. /***/ (function(module, exports) {
  33396. // 7.2.9 SameValue(x, y)
  33397. module.exports = Object.is || function is(x, y){
  33398. return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
  33399. };
  33400. /***/ }),
  33401. /* 263 */
  33402. /***/ (function(module, exports, __webpack_require__) {
  33403. // 7.3.20 SpeciesConstructor(O, defaultConstructor)
  33404. var anObject = __webpack_require__(4)
  33405. , aFunction = __webpack_require__(36)
  33406. , SPECIES = __webpack_require__(1)('species');
  33407. module.exports = function(O, D){
  33408. var C = anObject(O).constructor, S;
  33409. return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? D : aFunction(S);
  33410. };
  33411. /***/ }),
  33412. /* 264 */
  33413. /***/ (function(module, exports, __webpack_require__) {
  33414. var toInteger = __webpack_require__(35)
  33415. , defined = __webpack_require__(11);
  33416. // true -> String#at
  33417. // false -> String#codePointAt
  33418. module.exports = function(TO_STRING){
  33419. return function(that, pos){
  33420. var s = String(defined(that))
  33421. , i = toInteger(pos)
  33422. , l = s.length
  33423. , a, b;
  33424. if(i < 0 || i >= l)return TO_STRING ? '' : undefined;
  33425. a = s.charCodeAt(i);
  33426. return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff
  33427. ? TO_STRING ? s.charAt(i) : a
  33428. : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;
  33429. };
  33430. };
  33431. /***/ }),
  33432. /* 265 */
  33433. /***/ (function(module, exports, __webpack_require__) {
  33434. var global = __webpack_require__(2)
  33435. , core = __webpack_require__(20)
  33436. , LIBRARY = __webpack_require__(31)
  33437. , wksExt = __webpack_require__(72)
  33438. , defineProperty = __webpack_require__(5).f;
  33439. module.exports = function(name){
  33440. var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {});
  33441. if(name.charAt(0) != '_' && !(name in $Symbol))defineProperty($Symbol, name, {value: wksExt.f(name)});
  33442. };
  33443. /***/ }),
  33444. /* 266 */
  33445. /***/ (function(module, exports) {
  33446. /**
  33447. * Export generator function checks.
  33448. */
  33449. module.exports = isGenerator
  33450. module.exports.fn = isGeneratorFunction
  33451. /**
  33452. * Check whether an object is a generator.
  33453. *
  33454. * @param {Object} obj
  33455. * @return {Boolean}
  33456. */
  33457. function isGenerator (obj) {
  33458. return obj &&
  33459. typeof obj.next === 'function' &&
  33460. typeof obj.throw === 'function'
  33461. }
  33462. /**
  33463. * Check whether a function is generator.
  33464. *
  33465. * @param {Function} fn
  33466. * @return {Boolean}
  33467. */
  33468. function isGeneratorFunction (fn) {
  33469. return typeof fn === 'function' &&
  33470. fn.constructor &&
  33471. fn.constructor.name === 'GeneratorFunction'
  33472. }
  33473. /***/ })
  33474. /******/ ]);
  33475. //# sourceMappingURL=e2e.entry.js.map