You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xhiveframework-datatable.cjs.js 168 KiB

2 年之前
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983
  1. 'use strict';
  2. function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  3. var Sortable = _interopDefault(require('sortablejs'));
  4. function $(expr, con) {
  5. return typeof expr === 'string' ?
  6. (con || document).querySelector(expr) :
  7. expr || null;
  8. }
  9. $.each = (expr, con) => {
  10. return typeof expr === 'string' ?
  11. Array.from((con || document).querySelectorAll(expr)) :
  12. expr || null;
  13. };
  14. $.create = (tag, o) => {
  15. let element = document.createElement(tag);
  16. for (let i in o) {
  17. let val = o[i];
  18. if (i === 'inside') {
  19. $(val).appendChild(element);
  20. } else
  21. if (i === 'around') {
  22. let ref = $(val);
  23. ref.parentNode.insertBefore(element, ref);
  24. element.appendChild(ref);
  25. } else
  26. if (i === 'styles') {
  27. if (typeof val === 'object') {
  28. Object.keys(val).map(prop => {
  29. element.style[prop] = val[prop];
  30. });
  31. }
  32. } else
  33. if (i in element) {
  34. element[i] = val;
  35. } else {
  36. element.setAttribute(i, val);
  37. }
  38. }
  39. return element;
  40. };
  41. $.on = (element, event, selector, callback) => {
  42. if (!callback) {
  43. callback = selector;
  44. $.bind(element, event, callback);
  45. } else {
  46. $.delegate(element, event, selector, callback);
  47. }
  48. };
  49. $.off = (element, event, handler) => {
  50. element.removeEventListener(event, handler);
  51. };
  52. $.bind = (element, event, callback) => {
  53. event.split(/\s+/).forEach(function (event) {
  54. element.addEventListener(event, callback);
  55. });
  56. };
  57. $.delegate = (element, event, selector, callback) => {
  58. element.addEventListener(event, function (e) {
  59. const delegatedTarget = e.target.closest(selector);
  60. if (delegatedTarget) {
  61. e.delegatedTarget = delegatedTarget;
  62. callback.call(this, e, delegatedTarget);
  63. }
  64. });
  65. };
  66. $.unbind = (element, o) => {
  67. if (element) {
  68. for (let event in o) {
  69. let callback = o[event];
  70. event.split(/\s+/).forEach(function (event) {
  71. element.removeEventListener(event, callback);
  72. });
  73. }
  74. }
  75. };
  76. $.fire = (target, type, properties) => {
  77. let evt = document.createEvent('HTMLEvents');
  78. evt.initEvent(type, true, true);
  79. for (let j in properties) {
  80. evt[j] = properties[j];
  81. }
  82. return target.dispatchEvent(evt);
  83. };
  84. $.data = (element, attrs) => { // eslint-disable-line
  85. if (!attrs) {
  86. return element.dataset;
  87. }
  88. for (const attr in attrs) {
  89. element.dataset[attr] = attrs[attr];
  90. }
  91. };
  92. $.style = (elements, styleMap) => { // eslint-disable-line
  93. if (typeof styleMap === 'string') {
  94. return $.getStyle(elements, styleMap);
  95. }
  96. if (!Array.isArray(elements)) {
  97. elements = [elements];
  98. }
  99. elements.map(element => {
  100. for (const prop in styleMap) {
  101. element.style[prop] = styleMap[prop];
  102. }
  103. });
  104. };
  105. $.removeStyle = (elements, styleProps) => {
  106. if (!Array.isArray(elements)) {
  107. elements = [elements];
  108. }
  109. if (!Array.isArray(styleProps)) {
  110. styleProps = [styleProps];
  111. }
  112. elements.map(element => {
  113. for (const prop of styleProps) {
  114. element.style[prop] = '';
  115. }
  116. });
  117. };
  118. $.getStyle = (element, prop) => {
  119. if (!prop) {
  120. return getComputedStyle(element);
  121. }
  122. let val = getComputedStyle(element)[prop];
  123. if (['width', 'height'].includes(prop)) {
  124. val = parseFloat(val);
  125. }
  126. return val;
  127. };
  128. $.closest = (selector, element) => {
  129. if (!element) return null;
  130. if (element.matches(selector)) {
  131. return element;
  132. }
  133. return $.closest(selector, element.parentNode);
  134. };
  135. $.inViewport = (el, parentEl) => {
  136. const {
  137. top,
  138. left,
  139. bottom,
  140. right
  141. } = el.getBoundingClientRect();
  142. const {
  143. top: pTop,
  144. left: pLeft,
  145. bottom: pBottom,
  146. right: pRight
  147. } = parentEl.getBoundingClientRect();
  148. return top >= pTop && left >= pLeft && bottom <= pBottom && right <= pRight;
  149. };
  150. $.scrollTop = function scrollTop(element, pixels) {
  151. requestAnimationFrame(() => {
  152. element.scrollTop = pixels;
  153. });
  154. };
  155. $.scrollbarSize = function scrollbarSize() {
  156. if (!$.scrollBarSizeValue) {
  157. $.scrollBarSizeValue = getScrollBarSize();
  158. }
  159. return $.scrollBarSizeValue;
  160. };
  161. function getScrollBarSize() {
  162. // assume scrollbar width and height would be the same
  163. // Create the measurement node
  164. const scrollDiv = document.createElement('div');
  165. $.style(scrollDiv, {
  166. width: '100px',
  167. height: '100px',
  168. overflow: 'scroll',
  169. position: 'absolute',
  170. top: '-9999px'
  171. });
  172. document.body.appendChild(scrollDiv);
  173. // Get the scrollbar width
  174. const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  175. // Delete the DIV
  176. document.body.removeChild(scrollDiv);
  177. return scrollbarWidth;
  178. }
  179. $.hasVerticalOverflow = function (element) {
  180. return element.scrollHeight > element.offsetHeight + 10;
  181. };
  182. $.hasHorizontalOverflow = function (element) {
  183. return element.scrollWidth > element.offsetWidth + 10;
  184. };
  185. $.measureTextWidth = function (text) {
  186. const div = document.createElement('div');
  187. div.style.position = 'absolute';
  188. div.style.visibility = 'hidden';
  189. div.style.height = 'auto';
  190. div.style.width = 'auto';
  191. div.style.whiteSpace = 'nowrap';
  192. div.innerText = text;
  193. document.body.appendChild(div);
  194. return div.clientWidth + 1;
  195. };
  196. /**
  197. * Checks if `value` is the
  198. * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
  199. * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
  200. *
  201. * @static
  202. * @memberOf _
  203. * @since 0.1.0
  204. * @category Lang
  205. * @param {*} value The value to check.
  206. * @returns {boolean} Returns `true` if `value` is an object, else `false`.
  207. * @example
  208. *
  209. * _.isObject({});
  210. * // => true
  211. *
  212. * _.isObject([1, 2, 3]);
  213. * // => true
  214. *
  215. * _.isObject(_.noop);
  216. * // => true
  217. *
  218. * _.isObject(null);
  219. * // => false
  220. */
  221. function isObject(value) {
  222. var type = typeof value;
  223. return value != null && (type == 'object' || type == 'function');
  224. }
  225. var isObject_1 = isObject;
  226. var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
  227. function commonjsRequire () {
  228. throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
  229. }
  230. function unwrapExports (x) {
  231. return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
  232. }
  233. function createCommonjsModule(fn, module) {
  234. return module = { exports: {} }, fn(module, module.exports), module.exports;
  235. }
  236. /** Detect free variable `global` from Node.js. */
  237. var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
  238. var _freeGlobal = freeGlobal;
  239. /** Detect free variable `self`. */
  240. var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
  241. /** Used as a reference to the global object. */
  242. var root = _freeGlobal || freeSelf || Function('return this')();
  243. var _root = root;
  244. /**
  245. * Gets the timestamp of the number of milliseconds that have elapsed since
  246. * the Unix epoch (1 January 1970 00:00:00 UTC).
  247. *
  248. * @static
  249. * @memberOf _
  250. * @since 2.4.0
  251. * @category Date
  252. * @returns {number} Returns the timestamp.
  253. * @example
  254. *
  255. * _.defer(function(stamp) {
  256. * console.log(_.now() - stamp);
  257. * }, _.now());
  258. * // => Logs the number of milliseconds it took for the deferred invocation.
  259. */
  260. var now = function() {
  261. return _root.Date.now();
  262. };
  263. var now_1 = now;
  264. /** Used to match a single whitespace character. */
  265. var reWhitespace = /\s/;
  266. /**
  267. * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
  268. * character of `string`.
  269. *
  270. * @private
  271. * @param {string} string The string to inspect.
  272. * @returns {number} Returns the index of the last non-whitespace character.
  273. */
  274. function trimmedEndIndex(string) {
  275. var index = string.length;
  276. while (index-- && reWhitespace.test(string.charAt(index))) {}
  277. return index;
  278. }
  279. var _trimmedEndIndex = trimmedEndIndex;
  280. /** Used to match leading whitespace. */
  281. var reTrimStart = /^\s+/;
  282. /**
  283. * The base implementation of `_.trim`.
  284. *
  285. * @private
  286. * @param {string} string The string to trim.
  287. * @returns {string} Returns the trimmed string.
  288. */
  289. function baseTrim(string) {
  290. return string
  291. ? string.slice(0, _trimmedEndIndex(string) + 1).replace(reTrimStart, '')
  292. : string;
  293. }
  294. var _baseTrim = baseTrim;
  295. /** Built-in value references. */
  296. var Symbol = _root.Symbol;
  297. var _Symbol = Symbol;
  298. /** Used for built-in method references. */
  299. var objectProto = Object.prototype;
  300. /** Used to check objects for own properties. */
  301. var hasOwnProperty = objectProto.hasOwnProperty;
  302. /**
  303. * Used to resolve the
  304. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  305. * of values.
  306. */
  307. var nativeObjectToString = objectProto.toString;
  308. /** Built-in value references. */
  309. var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
  310. /**
  311. * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
  312. *
  313. * @private
  314. * @param {*} value The value to query.
  315. * @returns {string} Returns the raw `toStringTag`.
  316. */
  317. function getRawTag(value) {
  318. var isOwn = hasOwnProperty.call(value, symToStringTag),
  319. tag = value[symToStringTag];
  320. try {
  321. value[symToStringTag] = undefined;
  322. } catch (e) {}
  323. var result = nativeObjectToString.call(value);
  324. {
  325. if (isOwn) {
  326. value[symToStringTag] = tag;
  327. } else {
  328. delete value[symToStringTag];
  329. }
  330. }
  331. return result;
  332. }
  333. var _getRawTag = getRawTag;
  334. /** Used for built-in method references. */
  335. var objectProto$1 = Object.prototype;
  336. /**
  337. * Used to resolve the
  338. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  339. * of values.
  340. */
  341. var nativeObjectToString$1 = objectProto$1.toString;
  342. /**
  343. * Converts `value` to a string using `Object.prototype.toString`.
  344. *
  345. * @private
  346. * @param {*} value The value to convert.
  347. * @returns {string} Returns the converted string.
  348. */
  349. function objectToString(value) {
  350. return nativeObjectToString$1.call(value);
  351. }
  352. var _objectToString = objectToString;
  353. /** `Object#toString` result references. */
  354. var nullTag = '[object Null]',
  355. undefinedTag = '[object Undefined]';
  356. /** Built-in value references. */
  357. var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
  358. /**
  359. * The base implementation of `getTag` without fallbacks for buggy environments.
  360. *
  361. * @private
  362. * @param {*} value The value to query.
  363. * @returns {string} Returns the `toStringTag`.
  364. */
  365. function baseGetTag(value) {
  366. if (value == null) {
  367. return value === undefined ? undefinedTag : nullTag;
  368. }
  369. return (symToStringTag$1 && symToStringTag$1 in Object(value))
  370. ? _getRawTag(value)
  371. : _objectToString(value);
  372. }
  373. var _baseGetTag = baseGetTag;
  374. /**
  375. * Checks if `value` is object-like. A value is object-like if it's not `null`
  376. * and has a `typeof` result of "object".
  377. *
  378. * @static
  379. * @memberOf _
  380. * @since 4.0.0
  381. * @category Lang
  382. * @param {*} value The value to check.
  383. * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
  384. * @example
  385. *
  386. * _.isObjectLike({});
  387. * // => true
  388. *
  389. * _.isObjectLike([1, 2, 3]);
  390. * // => true
  391. *
  392. * _.isObjectLike(_.noop);
  393. * // => false
  394. *
  395. * _.isObjectLike(null);
  396. * // => false
  397. */
  398. function isObjectLike(value) {
  399. return value != null && typeof value == 'object';
  400. }
  401. var isObjectLike_1 = isObjectLike;
  402. /** `Object#toString` result references. */
  403. var symbolTag = '[object Symbol]';
  404. /**
  405. * Checks if `value` is classified as a `Symbol` primitive or object.
  406. *
  407. * @static
  408. * @memberOf _
  409. * @since 4.0.0
  410. * @category Lang
  411. * @param {*} value The value to check.
  412. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
  413. * @example
  414. *
  415. * _.isSymbol(Symbol.iterator);
  416. * // => true
  417. *
  418. * _.isSymbol('abc');
  419. * // => false
  420. */
  421. function isSymbol(value) {
  422. return typeof value == 'symbol' ||
  423. (isObjectLike_1(value) && _baseGetTag(value) == symbolTag);
  424. }
  425. var isSymbol_1 = isSymbol;
  426. /** Used as references for various `Number` constants. */
  427. var NAN = 0 / 0;
  428. /** Used to detect bad signed hexadecimal string values. */
  429. var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
  430. /** Used to detect binary string values. */
  431. var reIsBinary = /^0b[01]+$/i;
  432. /** Used to detect octal string values. */
  433. var reIsOctal = /^0o[0-7]+$/i;
  434. /** Built-in method references without a dependency on `root`. */
  435. var freeParseInt = parseInt;
  436. /**
  437. * Converts `value` to a number.
  438. *
  439. * @static
  440. * @memberOf _
  441. * @since 4.0.0
  442. * @category Lang
  443. * @param {*} value The value to process.
  444. * @returns {number} Returns the number.
  445. * @example
  446. *
  447. * _.toNumber(3.2);
  448. * // => 3.2
  449. *
  450. * _.toNumber(Number.MIN_VALUE);
  451. * // => 5e-324
  452. *
  453. * _.toNumber(Infinity);
  454. * // => Infinity
  455. *
  456. * _.toNumber('3.2');
  457. * // => 3.2
  458. */
  459. function toNumber(value) {
  460. if (typeof value == 'number') {
  461. return value;
  462. }
  463. if (isSymbol_1(value)) {
  464. return NAN;
  465. }
  466. if (isObject_1(value)) {
  467. var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
  468. value = isObject_1(other) ? (other + '') : other;
  469. }
  470. if (typeof value != 'string') {
  471. return value === 0 ? value : +value;
  472. }
  473. value = _baseTrim(value);
  474. var isBinary = reIsBinary.test(value);
  475. return (isBinary || reIsOctal.test(value))
  476. ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
  477. : (reIsBadHex.test(value) ? NAN : +value);
  478. }
  479. var toNumber_1 = toNumber;
  480. /** Error message constants. */
  481. var FUNC_ERROR_TEXT = 'Expected a function';
  482. /* Built-in method references for those with the same name as other `lodash` methods. */
  483. var nativeMax = Math.max,
  484. nativeMin = Math.min;
  485. /**
  486. * Creates a debounced function that delays invoking `func` until after `wait`
  487. * milliseconds have elapsed since the last time the debounced function was
  488. * invoked. The debounced function comes with a `cancel` method to cancel
  489. * delayed `func` invocations and a `flush` method to immediately invoke them.
  490. * Provide `options` to indicate whether `func` should be invoked on the
  491. * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
  492. * with the last arguments provided to the debounced function. Subsequent
  493. * calls to the debounced function return the result of the last `func`
  494. * invocation.
  495. *
  496. * **Note:** If `leading` and `trailing` options are `true`, `func` is
  497. * invoked on the trailing edge of the timeout only if the debounced function
  498. * is invoked more than once during the `wait` timeout.
  499. *
  500. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
  501. * until to the next tick, similar to `setTimeout` with a timeout of `0`.
  502. *
  503. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
  504. * for details over the differences between `_.debounce` and `_.throttle`.
  505. *
  506. * @static
  507. * @memberOf _
  508. * @since 0.1.0
  509. * @category Function
  510. * @param {Function} func The function to debounce.
  511. * @param {number} [wait=0] The number of milliseconds to delay.
  512. * @param {Object} [options={}] The options object.
  513. * @param {boolean} [options.leading=false]
  514. * Specify invoking on the leading edge of the timeout.
  515. * @param {number} [options.maxWait]
  516. * The maximum time `func` is allowed to be delayed before it's invoked.
  517. * @param {boolean} [options.trailing=true]
  518. * Specify invoking on the trailing edge of the timeout.
  519. * @returns {Function} Returns the new debounced function.
  520. * @example
  521. *
  522. * // Avoid costly calculations while the window size is in flux.
  523. * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
  524. *
  525. * // Invoke `sendMail` when clicked, debouncing subsequent calls.
  526. * jQuery(element).on('click', _.debounce(sendMail, 300, {
  527. * 'leading': true,
  528. * 'trailing': false
  529. * }));
  530. *
  531. * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
  532. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
  533. * var source = new EventSource('/stream');
  534. * jQuery(source).on('message', debounced);
  535. *
  536. * // Cancel the trailing debounced invocation.
  537. * jQuery(window).on('popstate', debounced.cancel);
  538. */
  539. function debounce(func, wait, options) {
  540. var lastArgs,
  541. lastThis,
  542. maxWait,
  543. result,
  544. timerId,
  545. lastCallTime,
  546. lastInvokeTime = 0,
  547. leading = false,
  548. maxing = false,
  549. trailing = true;
  550. if (typeof func != 'function') {
  551. throw new TypeError(FUNC_ERROR_TEXT);
  552. }
  553. wait = toNumber_1(wait) || 0;
  554. if (isObject_1(options)) {
  555. leading = !!options.leading;
  556. maxing = 'maxWait' in options;
  557. maxWait = maxing ? nativeMax(toNumber_1(options.maxWait) || 0, wait) : maxWait;
  558. trailing = 'trailing' in options ? !!options.trailing : trailing;
  559. }
  560. function invokeFunc(time) {
  561. var args = lastArgs,
  562. thisArg = lastThis;
  563. lastArgs = lastThis = undefined;
  564. lastInvokeTime = time;
  565. result = func.apply(thisArg, args);
  566. return result;
  567. }
  568. function leadingEdge(time) {
  569. // Reset any `maxWait` timer.
  570. lastInvokeTime = time;
  571. // Start the timer for the trailing edge.
  572. timerId = setTimeout(timerExpired, wait);
  573. // Invoke the leading edge.
  574. return leading ? invokeFunc(time) : result;
  575. }
  576. function remainingWait(time) {
  577. var timeSinceLastCall = time - lastCallTime,
  578. timeSinceLastInvoke = time - lastInvokeTime,
  579. timeWaiting = wait - timeSinceLastCall;
  580. return maxing
  581. ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
  582. : timeWaiting;
  583. }
  584. function shouldInvoke(time) {
  585. var timeSinceLastCall = time - lastCallTime,
  586. timeSinceLastInvoke = time - lastInvokeTime;
  587. // Either this is the first call, activity has stopped and we're at the
  588. // trailing edge, the system time has gone backwards and we're treating
  589. // it as the trailing edge, or we've hit the `maxWait` limit.
  590. return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
  591. (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
  592. }
  593. function timerExpired() {
  594. var time = now_1();
  595. if (shouldInvoke(time)) {
  596. return trailingEdge(time);
  597. }
  598. // Restart the timer.
  599. timerId = setTimeout(timerExpired, remainingWait(time));
  600. }
  601. function trailingEdge(time) {
  602. timerId = undefined;
  603. // Only invoke if we have `lastArgs` which means `func` has been
  604. // debounced at least once.
  605. if (trailing && lastArgs) {
  606. return invokeFunc(time);
  607. }
  608. lastArgs = lastThis = undefined;
  609. return result;
  610. }
  611. function cancel() {
  612. if (timerId !== undefined) {
  613. clearTimeout(timerId);
  614. }
  615. lastInvokeTime = 0;
  616. lastArgs = lastCallTime = lastThis = timerId = undefined;
  617. }
  618. function flush() {
  619. return timerId === undefined ? result : trailingEdge(now_1());
  620. }
  621. function debounced() {
  622. var time = now_1(),
  623. isInvoking = shouldInvoke(time);
  624. lastArgs = arguments;
  625. lastThis = this;
  626. lastCallTime = time;
  627. if (isInvoking) {
  628. if (timerId === undefined) {
  629. return leadingEdge(lastCallTime);
  630. }
  631. if (maxing) {
  632. // Handle invocations in a tight loop.
  633. clearTimeout(timerId);
  634. timerId = setTimeout(timerExpired, wait);
  635. return invokeFunc(lastCallTime);
  636. }
  637. }
  638. if (timerId === undefined) {
  639. timerId = setTimeout(timerExpired, wait);
  640. }
  641. return result;
  642. }
  643. debounced.cancel = cancel;
  644. debounced.flush = flush;
  645. return debounced;
  646. }
  647. var debounce_1 = debounce;
  648. /** Error message constants. */
  649. var FUNC_ERROR_TEXT$1 = 'Expected a function';
  650. /**
  651. * Creates a throttled function that only invokes `func` at most once per
  652. * every `wait` milliseconds. The throttled function comes with a `cancel`
  653. * method to cancel delayed `func` invocations and a `flush` method to
  654. * immediately invoke them. Provide `options` to indicate whether `func`
  655. * should be invoked on the leading and/or trailing edge of the `wait`
  656. * timeout. The `func` is invoked with the last arguments provided to the
  657. * throttled function. Subsequent calls to the throttled function return the
  658. * result of the last `func` invocation.
  659. *
  660. * **Note:** If `leading` and `trailing` options are `true`, `func` is
  661. * invoked on the trailing edge of the timeout only if the throttled function
  662. * is invoked more than once during the `wait` timeout.
  663. *
  664. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
  665. * until to the next tick, similar to `setTimeout` with a timeout of `0`.
  666. *
  667. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
  668. * for details over the differences between `_.throttle` and `_.debounce`.
  669. *
  670. * @static
  671. * @memberOf _
  672. * @since 0.1.0
  673. * @category Function
  674. * @param {Function} func The function to throttle.
  675. * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
  676. * @param {Object} [options={}] The options object.
  677. * @param {boolean} [options.leading=true]
  678. * Specify invoking on the leading edge of the timeout.
  679. * @param {boolean} [options.trailing=true]
  680. * Specify invoking on the trailing edge of the timeout.
  681. * @returns {Function} Returns the new throttled function.
  682. * @example
  683. *
  684. * // Avoid excessively updating the position while scrolling.
  685. * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
  686. *
  687. * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
  688. * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
  689. * jQuery(element).on('click', throttled);
  690. *
  691. * // Cancel the trailing throttled invocation.
  692. * jQuery(window).on('popstate', throttled.cancel);
  693. */
  694. function throttle(func, wait, options) {
  695. var leading = true,
  696. trailing = true;
  697. if (typeof func != 'function') {
  698. throw new TypeError(FUNC_ERROR_TEXT$1);
  699. }
  700. if (isObject_1(options)) {
  701. leading = 'leading' in options ? !!options.leading : leading;
  702. trailing = 'trailing' in options ? !!options.trailing : trailing;
  703. }
  704. return debounce_1(func, wait, {
  705. 'leading': leading,
  706. 'maxWait': wait,
  707. 'trailing': trailing
  708. });
  709. }
  710. var throttle_1 = throttle;
  711. /** `Object#toString` result references. */
  712. var asyncTag = '[object AsyncFunction]',
  713. funcTag = '[object Function]',
  714. genTag = '[object GeneratorFunction]',
  715. proxyTag = '[object Proxy]';
  716. /**
  717. * Checks if `value` is classified as a `Function` object.
  718. *
  719. * @static
  720. * @memberOf _
  721. * @since 0.1.0
  722. * @category Lang
  723. * @param {*} value The value to check.
  724. * @returns {boolean} Returns `true` if `value` is a function, else `false`.
  725. * @example
  726. *
  727. * _.isFunction(_);
  728. * // => true
  729. *
  730. * _.isFunction(/abc/);
  731. * // => false
  732. */
  733. function isFunction(value) {
  734. if (!isObject_1(value)) {
  735. return false;
  736. }
  737. // The use of `Object#toString` avoids issues with the `typeof` operator
  738. // in Safari 9 which returns 'object' for typed arrays and other constructors.
  739. var tag = _baseGetTag(value);
  740. return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
  741. }
  742. var isFunction_1 = isFunction;
  743. /** Used to detect overreaching core-js shims. */
  744. var coreJsData = _root['__core-js_shared__'];
  745. var _coreJsData = coreJsData;
  746. /** Used to detect methods masquerading as native. */
  747. var maskSrcKey = (function() {
  748. var uid = /[^.]+$/.exec(_coreJsData && _coreJsData.keys && _coreJsData.keys.IE_PROTO || '');
  749. return uid ? ('Symbol(src)_1.' + uid) : '';
  750. }());
  751. /**
  752. * Checks if `func` has its source masked.
  753. *
  754. * @private
  755. * @param {Function} func The function to check.
  756. * @returns {boolean} Returns `true` if `func` is masked, else `false`.
  757. */
  758. function isMasked(func) {
  759. return !!maskSrcKey && (maskSrcKey in func);
  760. }
  761. var _isMasked = isMasked;
  762. /** Used for built-in method references. */
  763. var funcProto = Function.prototype;
  764. /** Used to resolve the decompiled source of functions. */
  765. var funcToString = funcProto.toString;
  766. /**
  767. * Converts `func` to its source code.
  768. *
  769. * @private
  770. * @param {Function} func The function to convert.
  771. * @returns {string} Returns the source code.
  772. */
  773. function toSource(func) {
  774. if (func != null) {
  775. try {
  776. return funcToString.call(func);
  777. } catch (e) {}
  778. try {
  779. return (func + '');
  780. } catch (e) {}
  781. }
  782. return '';
  783. }
  784. var _toSource = toSource;
  785. /**
  786. * Used to match `RegExp`
  787. * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
  788. */
  789. var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
  790. /** Used to detect host constructors (Safari). */
  791. var reIsHostCtor = /^\[object .+?Constructor\]$/;
  792. /** Used for built-in method references. */
  793. var funcProto$1 = Function.prototype,
  794. objectProto$2 = Object.prototype;
  795. /** Used to resolve the decompiled source of functions. */
  796. var funcToString$1 = funcProto$1.toString;
  797. /** Used to check objects for own properties. */
  798. var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
  799. /** Used to detect if a method is native. */
  800. var reIsNative = RegExp('^' +
  801. funcToString$1.call(hasOwnProperty$1).replace(reRegExpChar, '\\$&')
  802. .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
  803. );
  804. /**
  805. * The base implementation of `_.isNative` without bad shim checks.
  806. *
  807. * @private
  808. * @param {*} value The value to check.
  809. * @returns {boolean} Returns `true` if `value` is a native function,
  810. * else `false`.
  811. */
  812. function baseIsNative(value) {
  813. if (!isObject_1(value) || _isMasked(value)) {
  814. return false;
  815. }
  816. var pattern = isFunction_1(value) ? reIsNative : reIsHostCtor;
  817. return pattern.test(_toSource(value));
  818. }
  819. var _baseIsNative = baseIsNative;
  820. /**
  821. * Gets the value at `key` of `object`.
  822. *
  823. * @private
  824. * @param {Object} [object] The object to query.
  825. * @param {string} key The key of the property to get.
  826. * @returns {*} Returns the property value.
  827. */
  828. function getValue(object, key) {
  829. return object == null ? undefined : object[key];
  830. }
  831. var _getValue = getValue;
  832. /**
  833. * Gets the native function at `key` of `object`.
  834. *
  835. * @private
  836. * @param {Object} object The object to query.
  837. * @param {string} key The key of the method to get.
  838. * @returns {*} Returns the function if it's native, else `undefined`.
  839. */
  840. function getNative(object, key) {
  841. var value = _getValue(object, key);
  842. return _baseIsNative(value) ? value : undefined;
  843. }
  844. var _getNative = getNative;
  845. /* Built-in method references that are verified to be native. */
  846. var nativeCreate = _getNative(Object, 'create');
  847. var _nativeCreate = nativeCreate;
  848. /**
  849. * Removes all key-value entries from the hash.
  850. *
  851. * @private
  852. * @name clear
  853. * @memberOf Hash
  854. */
  855. function hashClear() {
  856. this.__data__ = _nativeCreate ? _nativeCreate(null) : {};
  857. this.size = 0;
  858. }
  859. var _hashClear = hashClear;
  860. /**
  861. * Removes `key` and its value from the hash.
  862. *
  863. * @private
  864. * @name delete
  865. * @memberOf Hash
  866. * @param {Object} hash The hash to modify.
  867. * @param {string} key The key of the value to remove.
  868. * @returns {boolean} Returns `true` if the entry was removed, else `false`.
  869. */
  870. function hashDelete(key) {
  871. var result = this.has(key) && delete this.__data__[key];
  872. this.size -= result ? 1 : 0;
  873. return result;
  874. }
  875. var _hashDelete = hashDelete;
  876. /** Used to stand-in for `undefined` hash values. */
  877. var HASH_UNDEFINED = '__lodash_hash_undefined__';
  878. /** Used for built-in method references. */
  879. var objectProto$3 = Object.prototype;
  880. /** Used to check objects for own properties. */
  881. var hasOwnProperty$2 = objectProto$3.hasOwnProperty;
  882. /**
  883. * Gets the hash value for `key`.
  884. *
  885. * @private
  886. * @name get
  887. * @memberOf Hash
  888. * @param {string} key The key of the value to get.
  889. * @returns {*} Returns the entry value.
  890. */
  891. function hashGet(key) {
  892. var data = this.__data__;
  893. if (_nativeCreate) {
  894. var result = data[key];
  895. return result === HASH_UNDEFINED ? undefined : result;
  896. }
  897. return hasOwnProperty$2.call(data, key) ? data[key] : undefined;
  898. }
  899. var _hashGet = hashGet;
  900. /** Used for built-in method references. */
  901. var objectProto$4 = Object.prototype;
  902. /** Used to check objects for own properties. */
  903. var hasOwnProperty$3 = objectProto$4.hasOwnProperty;
  904. /**
  905. * Checks if a hash value for `key` exists.
  906. *
  907. * @private
  908. * @name has
  909. * @memberOf Hash
  910. * @param {string} key The key of the entry to check.
  911. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  912. */
  913. function hashHas(key) {
  914. var data = this.__data__;
  915. return _nativeCreate ? (data[key] !== undefined) : hasOwnProperty$3.call(data, key);
  916. }
  917. var _hashHas = hashHas;
  918. /** Used to stand-in for `undefined` hash values. */
  919. var HASH_UNDEFINED$1 = '__lodash_hash_undefined__';
  920. /**
  921. * Sets the hash `key` to `value`.
  922. *
  923. * @private
  924. * @name set
  925. * @memberOf Hash
  926. * @param {string} key The key of the value to set.
  927. * @param {*} value The value to set.
  928. * @returns {Object} Returns the hash instance.
  929. */
  930. function hashSet(key, value) {
  931. var data = this.__data__;
  932. this.size += this.has(key) ? 0 : 1;
  933. data[key] = (_nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value;
  934. return this;
  935. }
  936. var _hashSet = hashSet;
  937. /**
  938. * Creates a hash object.
  939. *
  940. * @private
  941. * @constructor
  942. * @param {Array} [entries] The key-value pairs to cache.
  943. */
  944. function Hash(entries) {
  945. var index = -1,
  946. length = entries == null ? 0 : entries.length;
  947. this.clear();
  948. while (++index < length) {
  949. var entry = entries[index];
  950. this.set(entry[0], entry[1]);
  951. }
  952. }
  953. // Add methods to `Hash`.
  954. Hash.prototype.clear = _hashClear;
  955. Hash.prototype['delete'] = _hashDelete;
  956. Hash.prototype.get = _hashGet;
  957. Hash.prototype.has = _hashHas;
  958. Hash.prototype.set = _hashSet;
  959. var _Hash = Hash;
  960. /**
  961. * Removes all key-value entries from the list cache.
  962. *
  963. * @private
  964. * @name clear
  965. * @memberOf ListCache
  966. */
  967. function listCacheClear() {
  968. this.__data__ = [];
  969. this.size = 0;
  970. }
  971. var _listCacheClear = listCacheClear;
  972. /**
  973. * Performs a
  974. * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
  975. * comparison between two values to determine if they are equivalent.
  976. *
  977. * @static
  978. * @memberOf _
  979. * @since 4.0.0
  980. * @category Lang
  981. * @param {*} value The value to compare.
  982. * @param {*} other The other value to compare.
  983. * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
  984. * @example
  985. *
  986. * var object = { 'a': 1 };
  987. * var other = { 'a': 1 };
  988. *
  989. * _.eq(object, object);
  990. * // => true
  991. *
  992. * _.eq(object, other);
  993. * // => false
  994. *
  995. * _.eq('a', 'a');
  996. * // => true
  997. *
  998. * _.eq('a', Object('a'));
  999. * // => false
  1000. *
  1001. * _.eq(NaN, NaN);
  1002. * // => true
  1003. */
  1004. function eq(value, other) {
  1005. return value === other || (value !== value && other !== other);
  1006. }
  1007. var eq_1 = eq;
  1008. /**
  1009. * Gets the index at which the `key` is found in `array` of key-value pairs.
  1010. *
  1011. * @private
  1012. * @param {Array} array The array to inspect.
  1013. * @param {*} key The key to search for.
  1014. * @returns {number} Returns the index of the matched value, else `-1`.
  1015. */
  1016. function assocIndexOf(array, key) {
  1017. var length = array.length;
  1018. while (length--) {
  1019. if (eq_1(array[length][0], key)) {
  1020. return length;
  1021. }
  1022. }
  1023. return -1;
  1024. }
  1025. var _assocIndexOf = assocIndexOf;
  1026. /** Used for built-in method references. */
  1027. var arrayProto = Array.prototype;
  1028. /** Built-in value references. */
  1029. var splice = arrayProto.splice;
  1030. /**
  1031. * Removes `key` and its value from the list cache.
  1032. *
  1033. * @private
  1034. * @name delete
  1035. * @memberOf ListCache
  1036. * @param {string} key The key of the value to remove.
  1037. * @returns {boolean} Returns `true` if the entry was removed, else `false`.
  1038. */
  1039. function listCacheDelete(key) {
  1040. var data = this.__data__,
  1041. index = _assocIndexOf(data, key);
  1042. if (index < 0) {
  1043. return false;
  1044. }
  1045. var lastIndex = data.length - 1;
  1046. if (index == lastIndex) {
  1047. data.pop();
  1048. } else {
  1049. splice.call(data, index, 1);
  1050. }
  1051. --this.size;
  1052. return true;
  1053. }
  1054. var _listCacheDelete = listCacheDelete;
  1055. /**
  1056. * Gets the list cache value for `key`.
  1057. *
  1058. * @private
  1059. * @name get
  1060. * @memberOf ListCache
  1061. * @param {string} key The key of the value to get.
  1062. * @returns {*} Returns the entry value.
  1063. */
  1064. function listCacheGet(key) {
  1065. var data = this.__data__,
  1066. index = _assocIndexOf(data, key);
  1067. return index < 0 ? undefined : data[index][1];
  1068. }
  1069. var _listCacheGet = listCacheGet;
  1070. /**
  1071. * Checks if a list cache value for `key` exists.
  1072. *
  1073. * @private
  1074. * @name has
  1075. * @memberOf ListCache
  1076. * @param {string} key The key of the entry to check.
  1077. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  1078. */
  1079. function listCacheHas(key) {
  1080. return _assocIndexOf(this.__data__, key) > -1;
  1081. }
  1082. var _listCacheHas = listCacheHas;
  1083. /**
  1084. * Sets the list cache `key` to `value`.
  1085. *
  1086. * @private
  1087. * @name set
  1088. * @memberOf ListCache
  1089. * @param {string} key The key of the value to set.
  1090. * @param {*} value The value to set.
  1091. * @returns {Object} Returns the list cache instance.
  1092. */
  1093. function listCacheSet(key, value) {
  1094. var data = this.__data__,
  1095. index = _assocIndexOf(data, key);
  1096. if (index < 0) {
  1097. ++this.size;
  1098. data.push([key, value]);
  1099. } else {
  1100. data[index][1] = value;
  1101. }
  1102. return this;
  1103. }
  1104. var _listCacheSet = listCacheSet;
  1105. /**
  1106. * Creates an list cache object.
  1107. *
  1108. * @private
  1109. * @constructor
  1110. * @param {Array} [entries] The key-value pairs to cache.
  1111. */
  1112. function ListCache(entries) {
  1113. var index = -1,
  1114. length = entries == null ? 0 : entries.length;
  1115. this.clear();
  1116. while (++index < length) {
  1117. var entry = entries[index];
  1118. this.set(entry[0], entry[1]);
  1119. }
  1120. }
  1121. // Add methods to `ListCache`.
  1122. ListCache.prototype.clear = _listCacheClear;
  1123. ListCache.prototype['delete'] = _listCacheDelete;
  1124. ListCache.prototype.get = _listCacheGet;
  1125. ListCache.prototype.has = _listCacheHas;
  1126. ListCache.prototype.set = _listCacheSet;
  1127. var _ListCache = ListCache;
  1128. /* Built-in method references that are verified to be native. */
  1129. var Map = _getNative(_root, 'Map');
  1130. var _Map = Map;
  1131. /**
  1132. * Removes all key-value entries from the map.
  1133. *
  1134. * @private
  1135. * @name clear
  1136. * @memberOf MapCache
  1137. */
  1138. function mapCacheClear() {
  1139. this.size = 0;
  1140. this.__data__ = {
  1141. 'hash': new _Hash,
  1142. 'map': new (_Map || _ListCache),
  1143. 'string': new _Hash
  1144. };
  1145. }
  1146. var _mapCacheClear = mapCacheClear;
  1147. /**
  1148. * Checks if `value` is suitable for use as unique object key.
  1149. *
  1150. * @private
  1151. * @param {*} value The value to check.
  1152. * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
  1153. */
  1154. function isKeyable(value) {
  1155. var type = typeof value;
  1156. return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
  1157. ? (value !== '__proto__')
  1158. : (value === null);
  1159. }
  1160. var _isKeyable = isKeyable;
  1161. /**
  1162. * Gets the data for `map`.
  1163. *
  1164. * @private
  1165. * @param {Object} map The map to query.
  1166. * @param {string} key The reference key.
  1167. * @returns {*} Returns the map data.
  1168. */
  1169. function getMapData(map, key) {
  1170. var data = map.__data__;
  1171. return _isKeyable(key)
  1172. ? data[typeof key == 'string' ? 'string' : 'hash']
  1173. : data.map;
  1174. }
  1175. var _getMapData = getMapData;
  1176. /**
  1177. * Removes `key` and its value from the map.
  1178. *
  1179. * @private
  1180. * @name delete
  1181. * @memberOf MapCache
  1182. * @param {string} key The key of the value to remove.
  1183. * @returns {boolean} Returns `true` if the entry was removed, else `false`.
  1184. */
  1185. function mapCacheDelete(key) {
  1186. var result = _getMapData(this, key)['delete'](key);
  1187. this.size -= result ? 1 : 0;
  1188. return result;
  1189. }
  1190. var _mapCacheDelete = mapCacheDelete;
  1191. /**
  1192. * Gets the map value for `key`.
  1193. *
  1194. * @private
  1195. * @name get
  1196. * @memberOf MapCache
  1197. * @param {string} key The key of the value to get.
  1198. * @returns {*} Returns the entry value.
  1199. */
  1200. function mapCacheGet(key) {
  1201. return _getMapData(this, key).get(key);
  1202. }
  1203. var _mapCacheGet = mapCacheGet;
  1204. /**
  1205. * Checks if a map value for `key` exists.
  1206. *
  1207. * @private
  1208. * @name has
  1209. * @memberOf MapCache
  1210. * @param {string} key The key of the entry to check.
  1211. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  1212. */
  1213. function mapCacheHas(key) {
  1214. return _getMapData(this, key).has(key);
  1215. }
  1216. var _mapCacheHas = mapCacheHas;
  1217. /**
  1218. * Sets the map `key` to `value`.
  1219. *
  1220. * @private
  1221. * @name set
  1222. * @memberOf MapCache
  1223. * @param {string} key The key of the value to set.
  1224. * @param {*} value The value to set.
  1225. * @returns {Object} Returns the map cache instance.
  1226. */
  1227. function mapCacheSet(key, value) {
  1228. var data = _getMapData(this, key),
  1229. size = data.size;
  1230. data.set(key, value);
  1231. this.size += data.size == size ? 0 : 1;
  1232. return this;
  1233. }
  1234. var _mapCacheSet = mapCacheSet;
  1235. /**
  1236. * Creates a map cache object to store key-value pairs.
  1237. *
  1238. * @private
  1239. * @constructor
  1240. * @param {Array} [entries] The key-value pairs to cache.
  1241. */
  1242. function MapCache(entries) {
  1243. var index = -1,
  1244. length = entries == null ? 0 : entries.length;
  1245. this.clear();
  1246. while (++index < length) {
  1247. var entry = entries[index];
  1248. this.set(entry[0], entry[1]);
  1249. }
  1250. }
  1251. // Add methods to `MapCache`.
  1252. MapCache.prototype.clear = _mapCacheClear;
  1253. MapCache.prototype['delete'] = _mapCacheDelete;
  1254. MapCache.prototype.get = _mapCacheGet;
  1255. MapCache.prototype.has = _mapCacheHas;
  1256. MapCache.prototype.set = _mapCacheSet;
  1257. var _MapCache = MapCache;
  1258. /** Used to stand-in for `undefined` hash values. */
  1259. var HASH_UNDEFINED$2 = '__lodash_hash_undefined__';
  1260. /**
  1261. * Adds `value` to the array cache.
  1262. *
  1263. * @private
  1264. * @name add
  1265. * @memberOf SetCache
  1266. * @alias push
  1267. * @param {*} value The value to cache.
  1268. * @returns {Object} Returns the cache instance.
  1269. */
  1270. function setCacheAdd(value) {
  1271. this.__data__.set(value, HASH_UNDEFINED$2);
  1272. return this;
  1273. }
  1274. var _setCacheAdd = setCacheAdd;
  1275. /**
  1276. * Checks if `value` is in the array cache.
  1277. *
  1278. * @private
  1279. * @name has
  1280. * @memberOf SetCache
  1281. * @param {*} value The value to search for.
  1282. * @returns {number} Returns `true` if `value` is found, else `false`.
  1283. */
  1284. function setCacheHas(value) {
  1285. return this.__data__.has(value);
  1286. }
  1287. var _setCacheHas = setCacheHas;
  1288. /**
  1289. *
  1290. * Creates an array cache object to store unique values.
  1291. *
  1292. * @private
  1293. * @constructor
  1294. * @param {Array} [values] The values to cache.
  1295. */
  1296. function SetCache(values) {
  1297. var index = -1,
  1298. length = values == null ? 0 : values.length;
  1299. this.__data__ = new _MapCache;
  1300. while (++index < length) {
  1301. this.add(values[index]);
  1302. }
  1303. }
  1304. // Add methods to `SetCache`.
  1305. SetCache.prototype.add = SetCache.prototype.push = _setCacheAdd;
  1306. SetCache.prototype.has = _setCacheHas;
  1307. var _SetCache = SetCache;
  1308. /**
  1309. * The base implementation of `_.findIndex` and `_.findLastIndex` without
  1310. * support for iteratee shorthands.
  1311. *
  1312. * @private
  1313. * @param {Array} array The array to inspect.
  1314. * @param {Function} predicate The function invoked per iteration.
  1315. * @param {number} fromIndex The index to search from.
  1316. * @param {boolean} [fromRight] Specify iterating from right to left.
  1317. * @returns {number} Returns the index of the matched value, else `-1`.
  1318. */
  1319. function baseFindIndex(array, predicate, fromIndex, fromRight) {
  1320. var length = array.length,
  1321. index = fromIndex + (fromRight ? 1 : -1);
  1322. while ((fromRight ? index-- : ++index < length)) {
  1323. if (predicate(array[index], index, array)) {
  1324. return index;
  1325. }
  1326. }
  1327. return -1;
  1328. }
  1329. var _baseFindIndex = baseFindIndex;
  1330. /**
  1331. * The base implementation of `_.isNaN` without support for number objects.
  1332. *
  1333. * @private
  1334. * @param {*} value The value to check.
  1335. * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
  1336. */
  1337. function baseIsNaN(value) {
  1338. return value !== value;
  1339. }
  1340. var _baseIsNaN = baseIsNaN;
  1341. /**
  1342. * A specialized version of `_.indexOf` which performs strict equality
  1343. * comparisons of values, i.e. `===`.
  1344. *
  1345. * @private
  1346. * @param {Array} array The array to inspect.
  1347. * @param {*} value The value to search for.
  1348. * @param {number} fromIndex The index to search from.
  1349. * @returns {number} Returns the index of the matched value, else `-1`.
  1350. */
  1351. function strictIndexOf(array, value, fromIndex) {
  1352. var index = fromIndex - 1,
  1353. length = array.length;
  1354. while (++index < length) {
  1355. if (array[index] === value) {
  1356. return index;
  1357. }
  1358. }
  1359. return -1;
  1360. }
  1361. var _strictIndexOf = strictIndexOf;
  1362. /**
  1363. * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
  1364. *
  1365. * @private
  1366. * @param {Array} array The array to inspect.
  1367. * @param {*} value The value to search for.
  1368. * @param {number} fromIndex The index to search from.
  1369. * @returns {number} Returns the index of the matched value, else `-1`.
  1370. */
  1371. function baseIndexOf(array, value, fromIndex) {
  1372. return value === value
  1373. ? _strictIndexOf(array, value, fromIndex)
  1374. : _baseFindIndex(array, _baseIsNaN, fromIndex);
  1375. }
  1376. var _baseIndexOf = baseIndexOf;
  1377. /**
  1378. * A specialized version of `_.includes` for arrays without support for
  1379. * specifying an index to search from.
  1380. *
  1381. * @private
  1382. * @param {Array} [array] The array to inspect.
  1383. * @param {*} target The value to search for.
  1384. * @returns {boolean} Returns `true` if `target` is found, else `false`.
  1385. */
  1386. function arrayIncludes(array, value) {
  1387. var length = array == null ? 0 : array.length;
  1388. return !!length && _baseIndexOf(array, value, 0) > -1;
  1389. }
  1390. var _arrayIncludes = arrayIncludes;
  1391. /**
  1392. * This function is like `arrayIncludes` except that it accepts a comparator.
  1393. *
  1394. * @private
  1395. * @param {Array} [array] The array to inspect.
  1396. * @param {*} target The value to search for.
  1397. * @param {Function} comparator The comparator invoked per element.
  1398. * @returns {boolean} Returns `true` if `target` is found, else `false`.
  1399. */
  1400. function arrayIncludesWith(array, value, comparator) {
  1401. var index = -1,
  1402. length = array == null ? 0 : array.length;
  1403. while (++index < length) {
  1404. if (comparator(value, array[index])) {
  1405. return true;
  1406. }
  1407. }
  1408. return false;
  1409. }
  1410. var _arrayIncludesWith = arrayIncludesWith;
  1411. /**
  1412. * Checks if a `cache` value for `key` exists.
  1413. *
  1414. * @private
  1415. * @param {Object} cache The cache to query.
  1416. * @param {string} key The key of the entry to check.
  1417. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  1418. */
  1419. function cacheHas(cache, key) {
  1420. return cache.has(key);
  1421. }
  1422. var _cacheHas = cacheHas;
  1423. /* Built-in method references that are verified to be native. */
  1424. var Set = _getNative(_root, 'Set');
  1425. var _Set = Set;
  1426. /**
  1427. * This method returns `undefined`.
  1428. *
  1429. * @static
  1430. * @memberOf _
  1431. * @since 2.3.0
  1432. * @category Util
  1433. * @example
  1434. *
  1435. * _.times(2, _.noop);
  1436. * // => [undefined, undefined]
  1437. */
  1438. function noop() {
  1439. // No operation performed.
  1440. }
  1441. var noop_1 = noop;
  1442. /**
  1443. * Converts `set` to an array of its values.
  1444. *
  1445. * @private
  1446. * @param {Object} set The set to convert.
  1447. * @returns {Array} Returns the values.
  1448. */
  1449. function setToArray(set) {
  1450. var index = -1,
  1451. result = Array(set.size);
  1452. set.forEach(function(value) {
  1453. result[++index] = value;
  1454. });
  1455. return result;
  1456. }
  1457. var _setToArray = setToArray;
  1458. /** Used as references for various `Number` constants. */
  1459. var INFINITY = 1 / 0;
  1460. /**
  1461. * Creates a set object of `values`.
  1462. *
  1463. * @private
  1464. * @param {Array} values The values to add to the set.
  1465. * @returns {Object} Returns the new set.
  1466. */
  1467. var createSet = !(_Set && (1 / _setToArray(new _Set([,-0]))[1]) == INFINITY) ? noop_1 : function(values) {
  1468. return new _Set(values);
  1469. };
  1470. var _createSet = createSet;
  1471. /** Used as the size to enable large array optimizations. */
  1472. var LARGE_ARRAY_SIZE = 200;
  1473. /**
  1474. * The base implementation of `_.uniqBy` without support for iteratee shorthands.
  1475. *
  1476. * @private
  1477. * @param {Array} array The array to inspect.
  1478. * @param {Function} [iteratee] The iteratee invoked per element.
  1479. * @param {Function} [comparator] The comparator invoked per element.
  1480. * @returns {Array} Returns the new duplicate free array.
  1481. */
  1482. function baseUniq(array, iteratee, comparator) {
  1483. var index = -1,
  1484. includes = _arrayIncludes,
  1485. length = array.length,
  1486. isCommon = true,
  1487. result = [],
  1488. seen = result;
  1489. if (comparator) {
  1490. isCommon = false;
  1491. includes = _arrayIncludesWith;
  1492. }
  1493. else if (length >= LARGE_ARRAY_SIZE) {
  1494. var set = iteratee ? null : _createSet(array);
  1495. if (set) {
  1496. return _setToArray(set);
  1497. }
  1498. isCommon = false;
  1499. includes = _cacheHas;
  1500. seen = new _SetCache;
  1501. }
  1502. else {
  1503. seen = iteratee ? [] : result;
  1504. }
  1505. outer:
  1506. while (++index < length) {
  1507. var value = array[index],
  1508. computed = iteratee ? iteratee(value) : value;
  1509. value = (comparator || value !== 0) ? value : 0;
  1510. if (isCommon && computed === computed) {
  1511. var seenIndex = seen.length;
  1512. while (seenIndex--) {
  1513. if (seen[seenIndex] === computed) {
  1514. continue outer;
  1515. }
  1516. }
  1517. if (iteratee) {
  1518. seen.push(computed);
  1519. }
  1520. result.push(value);
  1521. }
  1522. else if (!includes(seen, computed, comparator)) {
  1523. if (seen !== result) {
  1524. seen.push(computed);
  1525. }
  1526. result.push(value);
  1527. }
  1528. }
  1529. return result;
  1530. }
  1531. var _baseUniq = baseUniq;
  1532. /**
  1533. * Creates a duplicate-free version of an array, using
  1534. * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
  1535. * for equality comparisons, in which only the first occurrence of each element
  1536. * is kept. The order of result values is determined by the order they occur
  1537. * in the array.
  1538. *
  1539. * @static
  1540. * @memberOf _
  1541. * @since 0.1.0
  1542. * @category Array
  1543. * @param {Array} array The array to inspect.
  1544. * @returns {Array} Returns the new duplicate free array.
  1545. * @example
  1546. *
  1547. * _.uniq([2, 1, 2]);
  1548. * // => [2, 1]
  1549. */
  1550. function uniq(array) {
  1551. return (array && array.length) ? _baseUniq(array) : [];
  1552. }
  1553. var uniq_1 = uniq;
  1554. function camelCaseToDash(str) {
  1555. return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
  1556. }
  1557. function makeDataAttributeString(props) {
  1558. const keys = Object.keys(props);
  1559. return keys
  1560. .map((key) => {
  1561. const _key = camelCaseToDash(key);
  1562. const val = props[key];
  1563. if (val === undefined) return '';
  1564. return `data-${_key}="${val}" `;
  1565. })
  1566. .join('')
  1567. .trim();
  1568. }
  1569. function copyTextToClipboard(text) {
  1570. // https://stackoverflow.com/a/30810322/5353542
  1571. var textArea = document.createElement('textarea');
  1572. //
  1573. // *** This styling is an extra step which is likely not required. ***
  1574. //
  1575. // Why is it here? To ensure:
  1576. // 1. the element is able to have focus and selection.
  1577. // 2. if element was to flash render it has minimal visual impact.
  1578. // 3. less flakyness with selection and copying which **might** occur if
  1579. // the textarea element is not visible.
  1580. //
  1581. // The likelihood is the element won't even render, not even a flash,
  1582. // so some of these are just precautions. However in IE the element
  1583. // is visible whilst the popup box asking the user for permission for
  1584. // the web page to copy to the clipboard.
  1585. //
  1586. // Place in top-left corner of screen regardless of scroll position.
  1587. textArea.style.position = 'fixed';
  1588. textArea.style.top = 0;
  1589. textArea.style.left = 0;
  1590. // Ensure it has a small width and height. Setting to 1px / 1em
  1591. // doesn't work as this gives a negative w/h on some browsers.
  1592. textArea.style.width = '2em';
  1593. textArea.style.height = '2em';
  1594. // We don't need padding, reducing the size if it does flash render.
  1595. textArea.style.padding = 0;
  1596. // Clean up any borders.
  1597. textArea.style.border = 'none';
  1598. textArea.style.outline = 'none';
  1599. textArea.style.boxShadow = 'none';
  1600. // Avoid flash of white box if rendered for any reason.
  1601. textArea.style.background = 'transparent';
  1602. textArea.value = text;
  1603. document.body.appendChild(textArea);
  1604. textArea.select();
  1605. try {
  1606. document.execCommand('copy');
  1607. } catch (err) {
  1608. console.log('Oops, unable to copy');
  1609. }
  1610. document.body.removeChild(textArea);
  1611. }
  1612. function isNumeric(val) {
  1613. return !isNaN(val);
  1614. }
  1615. let throttle$1 = throttle_1;
  1616. let debounce$1 = debounce_1;
  1617. function nextTick(fn, context = null) {
  1618. return (...args) => {
  1619. return new Promise(resolve => {
  1620. const execute = () => {
  1621. const out = fn.apply(context, args);
  1622. resolve(out);
  1623. };
  1624. setTimeout(execute);
  1625. });
  1626. };
  1627. }
  1628. function linkProperties(target, source, properties) {
  1629. const props = properties.reduce((acc, prop) => {
  1630. acc[prop] = {
  1631. get() {
  1632. return source[prop];
  1633. }
  1634. };
  1635. return acc;
  1636. }, {});
  1637. Object.defineProperties(target, props);
  1638. }
  1639. function isSet(val) {
  1640. return val !== undefined || val !== null;
  1641. }
  1642. function notSet(val) {
  1643. return !isSet(val);
  1644. }
  1645. function isNumber(val) {
  1646. return !isNaN(val);
  1647. }
  1648. function ensureArray(val) {
  1649. if (!Array.isArray(val)) {
  1650. return [val];
  1651. }
  1652. return val;
  1653. }
  1654. function uniq$1(arr) {
  1655. return uniq_1(arr);
  1656. }
  1657. function numberSortAsc(a, b) {
  1658. return a - b;
  1659. }
  1660. function stripHTML(html) {
  1661. return html.replace(/<[^>]*>/g, '');
  1662. }
  1663. function format(str, args) {
  1664. if (!str) return str;
  1665. Object.keys(args).forEach(arg => {
  1666. let regex = new RegExp(`{(${arg})}`, 'g');
  1667. str = str.replace(regex, args[arg]);
  1668. });
  1669. return str;
  1670. }
  1671. class DataManager {
  1672. constructor(options) {
  1673. this.options = options;
  1674. this.sortRows = nextTick(this.sortRows, this);
  1675. this.switchColumn = nextTick(this.switchColumn, this);
  1676. this.removeColumn = nextTick(this.removeColumn, this);
  1677. this.options.filterRows = nextTick(this.options.filterRows, this);
  1678. }
  1679. init(data, columns) {
  1680. if (!data) {
  1681. data = this.options.data;
  1682. }
  1683. if (columns) {
  1684. this.options.columns = columns;
  1685. }
  1686. this.data = data;
  1687. this.rowCount = 0;
  1688. this.columns = [];
  1689. this.rows = [];
  1690. this.prepareColumns();
  1691. this.prepareRows();
  1692. this.prepareTreeRows();
  1693. this.prepareRowView();
  1694. this.prepareNumericColumns();
  1695. }
  1696. // computed property
  1697. get currentSort() {
  1698. const col = this.columns.find(col => col.sortOrder !== 'none');
  1699. return col || {
  1700. colIndex: -1,
  1701. sortOrder: 'none'
  1702. };
  1703. }
  1704. prepareColumns() {
  1705. this.columns = [];
  1706. this.validateColumns();
  1707. this.prepareDefaultColumns();
  1708. this.prepareHeader();
  1709. }
  1710. prepareDefaultColumns() {
  1711. if (this.options.checkboxColumn && !this.hasColumnById('_checkbox')) {
  1712. const cell = {
  1713. id: '_checkbox',
  1714. content: this.getCheckboxHTML(),
  1715. editable: false,
  1716. resizable: false,
  1717. sortable: false,
  1718. focusable: false,
  1719. dropdown: false,
  1720. width: 32
  1721. };
  1722. this.columns.push(cell);
  1723. }
  1724. if (this.options.serialNoColumn && !this.hasColumnById('_rowIndex')) {
  1725. let cell = {
  1726. id: '_rowIndex',
  1727. content: '',
  1728. align: 'center',
  1729. editable: false,
  1730. resizable: false,
  1731. focusable: false,
  1732. dropdown: false
  1733. };
  1734. this.columns.push(cell);
  1735. }
  1736. }
  1737. prepareHeader() {
  1738. let columns = this.columns.concat(this.options.columns);
  1739. const baseCell = {
  1740. isHeader: 1,
  1741. editable: true,
  1742. sortable: true,
  1743. resizable: true,
  1744. focusable: true,
  1745. dropdown: true,
  1746. width: null,
  1747. format: (value) => {
  1748. if (value === null || value === undefined) {
  1749. return '';
  1750. }
  1751. return value + '';
  1752. }
  1753. };
  1754. this.columns = columns
  1755. .map((cell, i) => this.prepareCell(cell, i))
  1756. .map(col => Object.assign({}, baseCell, col))
  1757. .map(col => {
  1758. col.content = col.content || col.name || '';
  1759. col.id = col.id || col.content;
  1760. return col;
  1761. });
  1762. }
  1763. prepareCell(content, i) {
  1764. const cell = {
  1765. content: '',
  1766. sortOrder: 'none',
  1767. colIndex: i,
  1768. column: this.columns[i]
  1769. };
  1770. if (content !== null && typeof content === 'object') {
  1771. // passed as column/header
  1772. Object.assign(cell, content);
  1773. } else {
  1774. cell.content = content;
  1775. }
  1776. return cell;
  1777. }
  1778. prepareNumericColumns() {
  1779. const row0 = this.getRow(0);
  1780. if (!row0) return;
  1781. this.columns = this.columns.map((column, i) => {
  1782. const cellValue = row0[i].content;
  1783. if (!column.align && isNumeric(cellValue)) {
  1784. column.align = 'right';
  1785. }
  1786. return column;
  1787. });
  1788. }
  1789. prepareRows() {
  1790. this.validateData(this.data);
  1791. this.rows = this.data.map((d, i) => {
  1792. const index = this._getNextRowCount();
  1793. let row = [];
  1794. let meta = {
  1795. rowIndex: index
  1796. };
  1797. if (Array.isArray(d)) {
  1798. // row is an array
  1799. if (this.options.checkboxColumn) {
  1800. row.push(this.getCheckboxHTML());
  1801. }
  1802. if (this.options.serialNoColumn) {
  1803. row.push((index + 1) + '');
  1804. }
  1805. row = row.concat(d);
  1806. while (row.length < this.columns.length) {
  1807. row.push('');
  1808. }
  1809. } else {
  1810. // row is an object
  1811. for (let col of this.columns) {
  1812. if (col.id === '_checkbox') {
  1813. row.push(this.getCheckboxHTML());
  1814. } else if (col.id === '_rowIndex') {
  1815. row.push((index + 1) + '');
  1816. } else {
  1817. row.push(d[col.id]);
  1818. }
  1819. }
  1820. meta.indent = d.indent || 0;
  1821. }
  1822. return this.prepareRow(row, meta);
  1823. });
  1824. }
  1825. prepareTreeRows() {
  1826. this.rows.forEach((row, i) => {
  1827. if (isNumber(row.meta.indent)) {
  1828. // if (i === 36) debugger;
  1829. const nextRow = this.getRow(i + 1);
  1830. row.meta.isLeaf = !nextRow ||
  1831. notSet(nextRow.meta.indent) ||
  1832. nextRow.meta.indent <= row.meta.indent;
  1833. row.meta.isTreeNodeClose = false;
  1834. }
  1835. });
  1836. }
  1837. prepareRowView() {
  1838. // This is order in which rows will be rendered in the table.
  1839. // When sorting happens, only this.rowViewOrder will change
  1840. // and not the original this.rows
  1841. this.rowViewOrder = this.rows.map(row => row.meta.rowIndex);
  1842. }
  1843. prepareRow(row, meta) {
  1844. const baseRowCell = {
  1845. rowIndex: meta.rowIndex,
  1846. indent: meta.indent
  1847. };
  1848. row = row
  1849. .map((cell, i) => this.prepareCell(cell, i))
  1850. .map(cell => Object.assign({}, baseRowCell, cell));
  1851. // monkey patched in array object
  1852. row.meta = meta;
  1853. return row;
  1854. }
  1855. validateColumns() {
  1856. const columns = this.options.columns;
  1857. if (!Array.isArray(columns)) {
  1858. throw new DataError('`columns` must be an array');
  1859. }
  1860. columns.forEach((column, i) => {
  1861. if (typeof column !== 'string' && typeof column !== 'object') {
  1862. throw new DataError(`column "${i}" must be a string or an object`);
  1863. }
  1864. });
  1865. }
  1866. validateData(data) {
  1867. if (Array.isArray(data) &&
  1868. (data.length === 0 || Array.isArray(data[0]) || typeof data[0] === 'object')) {
  1869. return true;
  1870. }
  1871. throw new DataError('`data` must be an array of arrays or objects');
  1872. }
  1873. appendRows(rows) {
  1874. this.validateData(rows);
  1875. this.rows.push(...this.prepareRows(rows));
  1876. }
  1877. sortRows(colIndex, sortOrder = 'none') {
  1878. colIndex = +colIndex;
  1879. // reset sortOrder and update for colIndex
  1880. this.getColumns()
  1881. .map(col => {
  1882. if (col.colIndex === colIndex) {
  1883. col.sortOrder = sortOrder;
  1884. } else {
  1885. col.sortOrder = 'none';
  1886. }
  1887. });
  1888. this._sortRows(colIndex, sortOrder);
  1889. }
  1890. _sortRows(colIndex, sortOrder) {
  1891. if (this.currentSort.colIndex === colIndex) {
  1892. // reverse the array if only sortOrder changed
  1893. if (
  1894. (this.currentSort.sortOrder === 'asc' && sortOrder === 'desc') ||
  1895. (this.currentSort.sortOrder === 'desc' && sortOrder === 'asc')
  1896. ) {
  1897. this.reverseArray(this.rowViewOrder);
  1898. this.currentSort.sortOrder = sortOrder;
  1899. return;
  1900. }
  1901. }
  1902. this.rowViewOrder.sort((a, b) => {
  1903. const aIndex = a;
  1904. const bIndex = b;
  1905. let aContent = this.getCell(colIndex, a).content;
  1906. let bContent = this.getCell(colIndex, b).content;
  1907. aContent = aContent == null ? '' : aContent;
  1908. bContent = bContent == null ? '' : bContent;
  1909. if (sortOrder === 'none') {
  1910. return aIndex - bIndex;
  1911. } else if (sortOrder === 'asc') {
  1912. if (aContent < bContent) return -1;
  1913. if (aContent > bContent) return 1;
  1914. if (aContent === bContent) return 0;
  1915. } else if (sortOrder === 'desc') {
  1916. if (aContent < bContent) return 1;
  1917. if (aContent > bContent) return -1;
  1918. if (aContent === bContent) return 0;
  1919. }
  1920. return 0;
  1921. });
  1922. if (this.hasColumnById('_rowIndex')) {
  1923. // update row index
  1924. const srNoColIndex = this.getColumnIndexById('_rowIndex');
  1925. this.rows.forEach((row, index) => {
  1926. const viewIndex = this.rowViewOrder.indexOf(index);
  1927. const cell = row[srNoColIndex];
  1928. cell.content = (viewIndex + 1) + '';
  1929. });
  1930. }
  1931. }
  1932. reverseArray(array) {
  1933. let left = null;
  1934. let right = null;
  1935. let length = array.length;
  1936. for (left = 0, right = length - 1; left < right; left += 1, right -= 1) {
  1937. const temporary = array[left];
  1938. array[left] = array[right];
  1939. array[right] = temporary;
  1940. }
  1941. }
  1942. switchColumn(index1, index2) {
  1943. // update columns
  1944. const temp = this.columns[index1];
  1945. this.columns[index1] = this.columns[index2];
  1946. this.columns[index2] = temp;
  1947. this.columns[index1].colIndex = index1;
  1948. this.columns[index2].colIndex = index2;
  1949. // update rows
  1950. this.rows.forEach(row => {
  1951. const newCell1 = Object.assign({}, row[index1], {
  1952. colIndex: index2
  1953. });
  1954. const newCell2 = Object.assign({}, row[index2], {
  1955. colIndex: index1
  1956. });
  1957. row[index2] = newCell1;
  1958. row[index1] = newCell2;
  1959. });
  1960. }
  1961. removeColumn(index) {
  1962. index = +index;
  1963. const filter = cell => cell.colIndex !== index;
  1964. const map = (cell, i) => Object.assign({}, cell, {
  1965. colIndex: i
  1966. });
  1967. // update columns
  1968. this.columns = this.columns
  1969. .filter(filter)
  1970. .map(map);
  1971. // update rows
  1972. this.rows.forEach(row => {
  1973. // remove cell
  1974. row.splice(index, 1);
  1975. // update colIndex
  1976. row.forEach((cell, i) => {
  1977. cell.colIndex = i;
  1978. });
  1979. });
  1980. }
  1981. updateRow(row, rowIndex) {
  1982. if (row.length < this.columns.length) {
  1983. if (this.hasColumnById('_rowIndex')) {
  1984. const val = (rowIndex + 1) + '';
  1985. row = [val].concat(row);
  1986. }
  1987. if (this.hasColumnById('_checkbox')) {
  1988. const val = '<input type="checkbox" />';
  1989. row = [val].concat(row);
  1990. }
  1991. }
  1992. const _row = this.prepareRow(row, {rowIndex});
  1993. const index = this.rows.findIndex(row => row[0].rowIndex === rowIndex);
  1994. this.rows[index] = _row;
  1995. return _row;
  1996. }
  1997. updateCell(colIndex, rowIndex, options) {
  1998. let cell;
  1999. if (typeof colIndex === 'object') {
  2000. // cell object was passed,
  2001. // must have colIndex, rowIndex
  2002. cell = colIndex;
  2003. colIndex = cell.colIndex;
  2004. rowIndex = cell.rowIndex;
  2005. // the object passed must be merged with original cell
  2006. options = cell;
  2007. }
  2008. cell = this.getCell(colIndex, rowIndex);
  2009. // mutate object directly
  2010. for (let key in options) {
  2011. const newVal = options[key];
  2012. if (newVal !== undefined) {
  2013. cell[key] = newVal;
  2014. }
  2015. }
  2016. return cell;
  2017. }
  2018. updateColumn(colIndex, keyValPairs) {
  2019. const column = this.getColumn(colIndex);
  2020. for (let key in keyValPairs) {
  2021. const newVal = keyValPairs[key];
  2022. if (newVal !== undefined) {
  2023. column[key] = newVal;
  2024. }
  2025. }
  2026. return column;
  2027. }
  2028. filterRows(filters) {
  2029. return this.options.filterRows(this.rows, filters)
  2030. .then(result => {
  2031. if (!result) {
  2032. result = this.getAllRowIndices();
  2033. }
  2034. if (!result.then) {
  2035. result = Promise.resolve(result);
  2036. }
  2037. return result.then(rowsToShow => {
  2038. this._filteredRows = rowsToShow;
  2039. const rowsToHide = this.getAllRowIndices()
  2040. .filter(index => !rowsToShow.includes(index));
  2041. return {
  2042. rowsToHide,
  2043. rowsToShow
  2044. };
  2045. });
  2046. });
  2047. }
  2048. getFilteredRowIndices() {
  2049. return this._filteredRows || this.getAllRowIndices();
  2050. }
  2051. getAllRowIndices() {
  2052. return this.rows.map(row => row.meta.rowIndex);
  2053. }
  2054. getRowCount() {
  2055. return this.rowCount;
  2056. }
  2057. _getNextRowCount() {
  2058. const val = this.rowCount;
  2059. this.rowCount++;
  2060. return val;
  2061. }
  2062. getRows(start, end) {
  2063. return this.rows.slice(start, end);
  2064. }
  2065. getRowsForView(start, end) {
  2066. const rows = this.rowViewOrder.map(i => this.rows[i]);
  2067. return rows.slice(start, end);
  2068. }
  2069. getColumns(skipStandardColumns) {
  2070. let columns = this.columns;
  2071. if (skipStandardColumns) {
  2072. columns = columns.slice(this.getStandardColumnCount());
  2073. }
  2074. return columns;
  2075. }
  2076. getStandardColumnCount() {
  2077. if (this.options.checkboxColumn && this.options.serialNoColumn) {
  2078. return 2;
  2079. }
  2080. if (this.options.checkboxColumn || this.options.serialNoColumn) {
  2081. return 1;
  2082. }
  2083. return 0;
  2084. }
  2085. getColumnCount(skipStandardColumns) {
  2086. let val = this.columns.length;
  2087. if (skipStandardColumns) {
  2088. val = val - this.getStandardColumnCount();
  2089. }
  2090. return val;
  2091. }
  2092. getColumn(colIndex) {
  2093. colIndex = +colIndex;
  2094. if (colIndex < 0) {
  2095. // negative indexes
  2096. colIndex = this.columns.length + colIndex;
  2097. }
  2098. return this.columns.find(col => col.colIndex === colIndex);
  2099. }
  2100. getColumnById(id) {
  2101. return this.columns.find(col => col.id === id);
  2102. }
  2103. getRow(rowIndex) {
  2104. rowIndex = +rowIndex;
  2105. return this.rows[rowIndex];
  2106. }
  2107. getCell(colIndex, rowIndex) {
  2108. rowIndex = +rowIndex;
  2109. colIndex = +colIndex;
  2110. return this.getRow(rowIndex)[colIndex];
  2111. }
  2112. getChildren(parentRowIndex) {
  2113. parentRowIndex = +parentRowIndex;
  2114. const parentIndent = this.getRow(parentRowIndex).meta.indent;
  2115. const out = [];
  2116. for (let i = parentRowIndex + 1; i < this.rowCount; i++) {
  2117. const row = this.getRow(i);
  2118. if (isNaN(row.meta.indent)) continue;
  2119. if (row.meta.indent > parentIndent) {
  2120. out.push(i);
  2121. }
  2122. if (row.meta.indent === parentIndent) {
  2123. break;
  2124. }
  2125. }
  2126. return out;
  2127. }
  2128. getImmediateChildren(parentRowIndex) {
  2129. parentRowIndex = +parentRowIndex;
  2130. const parentIndent = this.getRow(parentRowIndex).meta.indent;
  2131. const out = [];
  2132. const childIndent = parentIndent + 1;
  2133. for (let i = parentRowIndex + 1; i < this.rowCount; i++) {
  2134. const row = this.getRow(i);
  2135. if (isNaN(row.meta.indent) || row.meta.indent > childIndent) continue;
  2136. if (row.meta.indent === childIndent) {
  2137. out.push(i);
  2138. }
  2139. if (row.meta.indent === parentIndent) {
  2140. break;
  2141. }
  2142. }
  2143. return out;
  2144. }
  2145. get() {
  2146. return {
  2147. columns: this.columns,
  2148. rows: this.rows
  2149. };
  2150. }
  2151. /**
  2152. * Returns the original data which was passed
  2153. * based on rowIndex
  2154. * @param {Number} rowIndex
  2155. * @returns Array|Object
  2156. * @memberof DataManager
  2157. */
  2158. getData(rowIndex) {
  2159. return this.data[rowIndex];
  2160. }
  2161. hasColumn(name) {
  2162. return Boolean(this.columns.find(col => col.content === name));
  2163. }
  2164. hasColumnById(id) {
  2165. return Boolean(this.columns.find(col => col.id === id));
  2166. }
  2167. getColumnIndex(name) {
  2168. return this.columns.findIndex(col => col.content === name);
  2169. }
  2170. getColumnIndexById(id) {
  2171. return this.columns.findIndex(col => col.id === id);
  2172. }
  2173. getCheckboxHTML() {
  2174. return '<input type="checkbox" />';
  2175. }
  2176. }
  2177. // Custom Errors
  2178. class DataError extends TypeError {}
  2179. /* eslint-disable max-len */
  2180. // Icons from https://feathericons.com/
  2181. let icons = {
  2182. chevronDown: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>',
  2183. chevronRight: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>'
  2184. };
  2185. class CellManager {
  2186. constructor(instance) {
  2187. this.instance = instance;
  2188. linkProperties(this, this.instance, [
  2189. 'wrapper',
  2190. 'options',
  2191. 'style',
  2192. 'header',
  2193. 'bodyScrollable',
  2194. 'columnmanager',
  2195. 'rowmanager',
  2196. 'datamanager',
  2197. 'keyboard'
  2198. ]);
  2199. this.bindEvents();
  2200. }
  2201. bindEvents() {
  2202. this.bindFocusCell();
  2203. this.bindEditCell();
  2204. this.bindKeyboardSelection();
  2205. this.bindCopyCellContents();
  2206. this.bindMouseEvents();
  2207. this.bindTreeEvents();
  2208. }
  2209. bindFocusCell() {
  2210. this.bindKeyboardNav();
  2211. }
  2212. bindEditCell() {
  2213. this.$editingCell = null;
  2214. $.on(this.bodyScrollable, 'dblclick', '.dt-cell', (e, cell) => {
  2215. this.activateEditing(cell);
  2216. });
  2217. this.keyboard.on('enter', () => {
  2218. if (this.$focusedCell && !this.$editingCell) {
  2219. // enter keypress on focused cell
  2220. this.activateEditing(this.$focusedCell);
  2221. } else if (this.$editingCell) {
  2222. // enter keypress on editing cell
  2223. this.deactivateEditing();
  2224. }
  2225. });
  2226. }
  2227. bindKeyboardNav() {
  2228. const focusLastCell = (direction) => {
  2229. if (!this.$focusedCell || this.$editingCell) {
  2230. return false;
  2231. }
  2232. let $cell = this.$focusedCell;
  2233. const {
  2234. rowIndex,
  2235. colIndex
  2236. } = $.data($cell);
  2237. if (direction === 'left') {
  2238. $cell = this.getLeftMostCell$(rowIndex);
  2239. } else if (direction === 'right') {
  2240. $cell = this.getRightMostCell$(rowIndex);
  2241. } else if (direction === 'up') {
  2242. $cell = this.getTopMostCell$(colIndex);
  2243. } else if (direction === 'down') {
  2244. $cell = this.getBottomMostCell$(colIndex);
  2245. }
  2246. this.focusCell($cell);
  2247. return true;
  2248. };
  2249. ['left', 'right', 'up', 'down', 'tab', 'shift+tab']
  2250. .map(direction => this.keyboard.on(direction, () => this.focusCellInDirection(direction)));
  2251. ['left', 'right', 'up', 'down']
  2252. .map(direction => this.keyboard.on(`ctrl+${direction}`, () => focusLastCell(direction)));
  2253. this.keyboard.on('esc', () => {
  2254. this.deactivateEditing(false);
  2255. this.columnmanager.toggleFilter(false);
  2256. });
  2257. if (this.options.inlineFilters) {
  2258. this.keyboard.on('ctrl+f', (e) => {
  2259. const $cell = $.closest('.dt-cell', e.target);
  2260. const { colIndex } = $.data($cell);
  2261. this.activateFilter(colIndex);
  2262. return true;
  2263. });
  2264. $.on(this.header, 'focusin', '.dt-filter', () => {
  2265. this.unfocusCell(this.$focusedCell);
  2266. });
  2267. }
  2268. }
  2269. bindKeyboardSelection() {
  2270. const getNextSelectionCursor = (direction) => {
  2271. let $selectionCursor = this.getSelectionCursor();
  2272. if (direction === 'left') {
  2273. $selectionCursor = this.getLeftCell$($selectionCursor);
  2274. } else if (direction === 'right') {
  2275. $selectionCursor = this.getRightCell$($selectionCursor);
  2276. } else if (direction === 'up') {
  2277. $selectionCursor = this.getAboveCell$($selectionCursor);
  2278. } else if (direction === 'down') {
  2279. $selectionCursor = this.getBelowCell$($selectionCursor);
  2280. }
  2281. return $selectionCursor;
  2282. };
  2283. ['left', 'right', 'up', 'down']
  2284. .map(direction =>
  2285. this.keyboard.on(`shift+${direction}`, () => this.selectArea(getNextSelectionCursor(direction))));
  2286. }
  2287. bindCopyCellContents() {
  2288. this.keyboard.on('ctrl+c', () => {
  2289. const noOfCellsCopied = this.copyCellContents(this.$focusedCell, this.$selectionCursor);
  2290. const message = this.instance.translate('{count} cells copied', {
  2291. count: noOfCellsCopied
  2292. });
  2293. if (noOfCellsCopied) {
  2294. this.instance.showToastMessage(message, 2);
  2295. }
  2296. });
  2297. if (this.options.pasteFromClipboard) {
  2298. this.keyboard.on('ctrl+v', (e) => {
  2299. // hack
  2300. // https://stackoverflow.com/a/2177059/5353542
  2301. this.instance.pasteTarget.focus();
  2302. setTimeout(() => {
  2303. const data = this.instance.pasteTarget.value;
  2304. this.instance.pasteTarget.value = '';
  2305. this.pasteContentInCell(data);
  2306. }, 10);
  2307. return false;
  2308. });
  2309. }
  2310. }
  2311. bindMouseEvents() {
  2312. let mouseDown = null;
  2313. $.on(this.bodyScrollable, 'mousedown', '.dt-cell', (e) => {
  2314. mouseDown = true;
  2315. this.focusCell($(e.delegatedTarget));
  2316. });
  2317. $.on(this.bodyScrollable, 'mouseup', () => {
  2318. mouseDown = false;
  2319. });
  2320. const selectArea = (e) => {
  2321. if (!mouseDown) return;
  2322. this.selectArea($(e.delegatedTarget));
  2323. };
  2324. $.on(this.bodyScrollable, 'mousemove', '.dt-cell', throttle$1(selectArea, 50));
  2325. }
  2326. bindTreeEvents() {
  2327. $.on(this.bodyScrollable, 'click', '.dt-tree-node__toggle', (e, $toggle) => {
  2328. const $cell = $.closest('.dt-cell', $toggle);
  2329. const { rowIndex } = $.data($cell);
  2330. if ($cell.classList.contains('dt-cell--tree-close')) {
  2331. this.rowmanager.openSingleNode(rowIndex);
  2332. } else {
  2333. this.rowmanager.closeSingleNode(rowIndex);
  2334. }
  2335. });
  2336. }
  2337. focusCell($cell, {
  2338. skipClearSelection = 0,
  2339. skipDOMFocus = 0,
  2340. skipScrollToCell = 0
  2341. } = {}) {
  2342. if (!$cell) return;
  2343. // don't focus if already editing cell
  2344. if ($cell === this.$editingCell) return;
  2345. const {
  2346. colIndex,
  2347. isHeader
  2348. } = $.data($cell);
  2349. if (isHeader) {
  2350. return;
  2351. }
  2352. const column = this.columnmanager.getColumn(colIndex);
  2353. if (column.focusable === false) {
  2354. return;
  2355. }
  2356. if (!skipScrollToCell) {
  2357. this.scrollToCell($cell);
  2358. }
  2359. this.deactivateEditing();
  2360. if (!skipClearSelection) {
  2361. this.clearSelection();
  2362. }
  2363. if (this.$focusedCell) {
  2364. this.$focusedCell.classList.remove('dt-cell--focus');
  2365. }
  2366. this.$focusedCell = $cell;
  2367. $cell.classList.add('dt-cell--focus');
  2368. if (!skipDOMFocus) {
  2369. // so that keyboard nav works
  2370. $cell.focus();
  2371. }
  2372. this.highlightRowColumnHeader($cell);
  2373. }
  2374. unfocusCell($cell) {
  2375. if (!$cell) return;
  2376. // remove cell border
  2377. $cell.classList.remove('dt-cell--focus');
  2378. this.$focusedCell = null;
  2379. // reset header background
  2380. if (this.lastHeaders) {
  2381. this.lastHeaders.forEach(header => header && header.classList.remove('dt-cell--highlight'));
  2382. }
  2383. }
  2384. highlightRowColumnHeader($cell) {
  2385. const {
  2386. colIndex,
  2387. rowIndex
  2388. } = $.data($cell);
  2389. const srNoColIndex = this.datamanager.getColumnIndexById('_rowIndex');
  2390. const colHeaderSelector = `.dt-cell--header-${colIndex}`;
  2391. const rowHeaderSelector = `.dt-cell--${srNoColIndex}-${rowIndex}`;
  2392. if (this.lastHeaders) {
  2393. this.lastHeaders.forEach(header => header && header.classList.remove('dt-cell--highlight'));
  2394. }
  2395. const colHeader = $(colHeaderSelector, this.wrapper);
  2396. const rowHeader = $(rowHeaderSelector, this.wrapper);
  2397. this.lastHeaders = [colHeader, rowHeader];
  2398. this.lastHeaders.forEach(header => header && header.classList.add('dt-cell--highlight'));
  2399. }
  2400. selectAreaOnClusterChanged() {
  2401. if (!(this.$focusedCell && this.$selectionCursor)) return;
  2402. const {
  2403. colIndex,
  2404. rowIndex
  2405. } = $.data(this.$selectionCursor);
  2406. const $cell = this.getCell$(colIndex, rowIndex);
  2407. if (!$cell || $cell === this.$selectionCursor) return;
  2408. // selectArea needs $focusedCell
  2409. const fCell = $.data(this.$focusedCell);
  2410. this.$focusedCell = this.getCell$(fCell.colIndex, fCell.rowIndex);
  2411. this.selectArea($cell);
  2412. }
  2413. focusCellOnClusterChanged() {
  2414. if (!this.$focusedCell) return;
  2415. const {
  2416. colIndex,
  2417. rowIndex
  2418. } = $.data(this.$focusedCell);
  2419. const $cell = this.getCell$(colIndex, rowIndex);
  2420. if (!$cell) return;
  2421. // this function is called after hyperlist renders the rows after scroll,
  2422. // focusCell calls clearSelection which resets the area selection
  2423. // so a flag to skip it
  2424. // we also skip DOM focus and scroll to cell
  2425. // because it fights with the user scroll
  2426. this.focusCell($cell, {
  2427. skipClearSelection: 1,
  2428. skipDOMFocus: 1,
  2429. skipScrollToCell: 1
  2430. });
  2431. }
  2432. selectArea($selectionCursor) {
  2433. if (!this.$focusedCell) return;
  2434. if (this._selectArea(this.$focusedCell, $selectionCursor)) {
  2435. // valid selection
  2436. this.$selectionCursor = $selectionCursor;
  2437. }
  2438. }
  2439. _selectArea($cell1, $cell2) {
  2440. if ($cell1 === $cell2) return false;
  2441. const cells = this.getCellsInRange($cell1, $cell2);
  2442. if (!cells) return false;
  2443. this.clearSelection();
  2444. this._selectedCells = cells.map(index => this.getCell$(...index));
  2445. requestAnimationFrame(() => {
  2446. this._selectedCells.map($cell => $cell.classList.add('dt-cell--highlight'));
  2447. });
  2448. return true;
  2449. }
  2450. getCellsInRange($cell1, $cell2) {
  2451. let colIndex1, rowIndex1, colIndex2, rowIndex2;
  2452. if (typeof $cell1 === 'number') {
  2453. [colIndex1, rowIndex1, colIndex2, rowIndex2] = arguments;
  2454. } else
  2455. if (typeof $cell1 === 'object') {
  2456. if (!($cell1 && $cell2)) {
  2457. return false;
  2458. }
  2459. const cell1 = $.data($cell1);
  2460. const cell2 = $.data($cell2);
  2461. colIndex1 = +cell1.colIndex;
  2462. rowIndex1 = +cell1.rowIndex;
  2463. colIndex2 = +cell2.colIndex;
  2464. rowIndex2 = +cell2.rowIndex;
  2465. }
  2466. if (rowIndex1 > rowIndex2) {
  2467. [rowIndex1, rowIndex2] = [rowIndex2, rowIndex1];
  2468. }
  2469. if (colIndex1 > colIndex2) {
  2470. [colIndex1, colIndex2] = [colIndex2, colIndex1];
  2471. }
  2472. if (this.isStandardCell(colIndex1) || this.isStandardCell(colIndex2)) {
  2473. return false;
  2474. }
  2475. const cells = [];
  2476. let colIndex = colIndex1;
  2477. let rowIndex = rowIndex1;
  2478. const rowIndices = [];
  2479. while (rowIndex <= rowIndex2) {
  2480. rowIndices.push(rowIndex);
  2481. rowIndex += 1;
  2482. }
  2483. rowIndices.map((rowIndex) => {
  2484. while (colIndex <= colIndex2) {
  2485. cells.push([colIndex, rowIndex]);
  2486. colIndex++;
  2487. }
  2488. colIndex = colIndex1;
  2489. });
  2490. return cells;
  2491. }
  2492. clearSelection() {
  2493. (this._selectedCells || [])
  2494. .forEach($cell => $cell.classList.remove('dt-cell--highlight'));
  2495. this._selectedCells = [];
  2496. this.$selectionCursor = null;
  2497. }
  2498. getSelectionCursor() {
  2499. return this.$selectionCursor || this.$focusedCell;
  2500. }
  2501. activateEditing($cell) {
  2502. this.focusCell($cell);
  2503. const {
  2504. rowIndex,
  2505. colIndex
  2506. } = $.data($cell);
  2507. const col = this.columnmanager.getColumn(colIndex);
  2508. if (col && (col.editable === false || col.focusable === false)) {
  2509. return;
  2510. }
  2511. const cell = this.getCell(colIndex, rowIndex);
  2512. if (cell && cell.editable === false) {
  2513. return;
  2514. }
  2515. if (this.$editingCell) {
  2516. const {
  2517. _rowIndex,
  2518. _colIndex
  2519. } = $.data(this.$editingCell);
  2520. if (rowIndex === _rowIndex && colIndex === _colIndex) {
  2521. // editing the same cell
  2522. return;
  2523. }
  2524. }
  2525. this.$editingCell = $cell;
  2526. $cell.classList.add('dt-cell--editing');
  2527. const $editCell = $('.dt-cell__edit', $cell);
  2528. $editCell.innerHTML = '';
  2529. const editor = this.getEditor(colIndex, rowIndex, cell.content, $editCell);
  2530. if (editor) {
  2531. this.currentCellEditor = editor;
  2532. // initialize editing input with cell value
  2533. editor.initValue(cell.content, rowIndex, col);
  2534. }
  2535. }
  2536. deactivateEditing(submitValue = true) {
  2537. if (submitValue) {
  2538. this.submitEditing();
  2539. }
  2540. // keep focus on the cell so that keyboard navigation works
  2541. if (this.$focusedCell) this.$focusedCell.focus();
  2542. if (!this.$editingCell) return;
  2543. this.$editingCell.classList.remove('dt-cell--editing');
  2544. this.$editingCell = null;
  2545. }
  2546. getEditor(colIndex, rowIndex, value, parent) {
  2547. const column = this.datamanager.getColumn(colIndex);
  2548. const row = this.datamanager.getRow(rowIndex);
  2549. const data = this.datamanager.getData(rowIndex);
  2550. let editor = this.options.getEditor ?
  2551. this.options.getEditor(colIndex, rowIndex, value, parent, column, row, data) :
  2552. this.getDefaultEditor(parent);
  2553. if (editor === false) {
  2554. // explicitly returned false
  2555. return false;
  2556. }
  2557. if (editor === undefined) {
  2558. // didn't return editor, fallback to default
  2559. editor = this.getDefaultEditor(parent);
  2560. }
  2561. return editor;
  2562. }
  2563. getDefaultEditor(parent) {
  2564. const $input = $.create('input', {
  2565. class: 'dt-input',
  2566. type: 'text',
  2567. inside: parent
  2568. });
  2569. return {
  2570. initValue(value) {
  2571. $input.focus();
  2572. $input.value = value;
  2573. },
  2574. getValue() {
  2575. return $input.value;
  2576. },
  2577. setValue(value) {
  2578. $input.value = value;
  2579. }
  2580. };
  2581. }
  2582. submitEditing() {
  2583. let promise = Promise.resolve();
  2584. if (!this.$editingCell) return promise;
  2585. const $cell = this.$editingCell;
  2586. const {
  2587. rowIndex,
  2588. colIndex
  2589. } = $.data($cell);
  2590. const col = this.datamanager.getColumn(colIndex);
  2591. if ($cell) {
  2592. const editor = this.currentCellEditor;
  2593. if (editor) {
  2594. let valuePromise = editor.getValue();
  2595. // convert to stubbed Promise
  2596. if (!valuePromise.then) {
  2597. valuePromise = Promise.resolve(valuePromise);
  2598. }
  2599. promise = valuePromise.then((value) => {
  2600. const oldValue = this.getCell(colIndex, rowIndex).content;
  2601. if (oldValue === value) return false;
  2602. const done = editor.setValue(value, rowIndex, col);
  2603. // update cell immediately
  2604. this.updateCell(colIndex, rowIndex, value, true);
  2605. $cell.focus();
  2606. if (done && done.then) {
  2607. // revert to oldValue if promise fails
  2608. done.catch((e) => {
  2609. console.log(e);
  2610. this.updateCell(colIndex, rowIndex, oldValue);
  2611. });
  2612. }
  2613. return done;
  2614. });
  2615. }
  2616. }
  2617. this.currentCellEditor = null;
  2618. return promise;
  2619. }
  2620. copyCellContents($cell1, $cell2) {
  2621. if (!$cell2 && $cell1) {
  2622. // copy only focusedCell
  2623. const {
  2624. colIndex,
  2625. rowIndex
  2626. } = $.data($cell1);
  2627. const cell = this.getCell(colIndex, rowIndex);
  2628. copyTextToClipboard(cell.content);
  2629. return 1;
  2630. }
  2631. const cells = this.getCellsInRange($cell1, $cell2);
  2632. if (!cells) return 0;
  2633. const rows = cells
  2634. // get cell objects
  2635. .map(index => this.getCell(...index))
  2636. // convert to array of rows
  2637. .reduce((acc, curr) => {
  2638. const rowIndex = curr.rowIndex;
  2639. acc[rowIndex] = acc[rowIndex] || [];
  2640. acc[rowIndex].push(curr.content);
  2641. return acc;
  2642. }, []);
  2643. const values = rows
  2644. // join values by tab
  2645. .map(row => row.join('\t'))
  2646. // join rows by newline
  2647. .join('\n');
  2648. copyTextToClipboard(values);
  2649. // return no of cells copied
  2650. return rows.reduce((total, row) => total + row.length, 0);
  2651. }
  2652. pasteContentInCell(data) {
  2653. if (!this.$focusedCell) return;
  2654. const matrix = data
  2655. .split('\n')
  2656. .map(row => row.split('\t'))
  2657. .filter(row => row.length && row.every(it => it));
  2658. let { colIndex, rowIndex } = $.data(this.$focusedCell);
  2659. let focusedCell = {
  2660. colIndex: +colIndex,
  2661. rowIndex: +rowIndex
  2662. };
  2663. matrix.forEach((row, i) => {
  2664. let rowIndex = i + focusedCell.rowIndex;
  2665. row.forEach((cell, j) => {
  2666. let colIndex = j + focusedCell.colIndex;
  2667. this.updateCell(colIndex, rowIndex, cell, true);
  2668. });
  2669. });
  2670. }
  2671. activateFilter(colIndex) {
  2672. this.columnmanager.toggleFilter();
  2673. this.columnmanager.focusFilter(colIndex);
  2674. if (!this.columnmanager.isFilterShown) {
  2675. // put focus back on cell
  2676. this.$focusedCell && this.$focusedCell.focus();
  2677. }
  2678. }
  2679. updateCell(colIndex, rowIndex, value, refreshHtml = false) {
  2680. const cell = this.datamanager.updateCell(colIndex, rowIndex, {
  2681. content: value
  2682. });
  2683. this.refreshCell(cell, refreshHtml);
  2684. }
  2685. refreshCell(cell, refreshHtml = false) {
  2686. const $cell = $(this.selector(cell.colIndex, cell.rowIndex), this.bodyScrollable);
  2687. $cell.innerHTML = this.getCellContent(cell, refreshHtml);
  2688. }
  2689. toggleTreeButton(rowIndex, flag) {
  2690. const colIndex = this.columnmanager.getFirstColumnIndex();
  2691. const $cell = this.getCell$(colIndex, rowIndex);
  2692. if ($cell) {
  2693. $cell.classList[flag ? 'remove' : 'add']('dt-cell--tree-close');
  2694. }
  2695. }
  2696. isStandardCell(colIndex) {
  2697. // Standard cells are in Sr. No and Checkbox column
  2698. return colIndex < this.columnmanager.getFirstColumnIndex();
  2699. }
  2700. focusCellInDirection(direction) {
  2701. if (!this.$focusedCell || (this.$editingCell && ['left', 'right', 'up', 'down'].includes(direction))) {
  2702. return false;
  2703. } else if (this.$editingCell && ['tab', 'shift+tab'].includes(direction)) {
  2704. this.deactivateEditing();
  2705. }
  2706. let $cell = this.$focusedCell;
  2707. if (direction === 'left' || direction === 'shift+tab') {
  2708. $cell = this.getLeftCell$($cell);
  2709. } else if (direction === 'right' || direction === 'tab') {
  2710. $cell = this.getRightCell$($cell);
  2711. } else if (direction === 'up') {
  2712. $cell = this.getAboveCell$($cell);
  2713. } else if (direction === 'down') {
  2714. $cell = this.getBelowCell$($cell);
  2715. }
  2716. if (!$cell) {
  2717. return false;
  2718. }
  2719. const {
  2720. colIndex
  2721. } = $.data($cell);
  2722. const column = this.columnmanager.getColumn(colIndex);
  2723. if (!column.focusable) {
  2724. let $prevFocusedCell = this.$focusedCell;
  2725. this.unfocusCell($prevFocusedCell);
  2726. this.$focusedCell = $cell;
  2727. let ret = this.focusCellInDirection(direction);
  2728. if (!ret) {
  2729. this.focusCell($prevFocusedCell);
  2730. }
  2731. return ret;
  2732. }
  2733. this.focusCell($cell);
  2734. return true;
  2735. }
  2736. getCell$(colIndex, rowIndex) {
  2737. return $(this.selector(colIndex, rowIndex), this.bodyScrollable);
  2738. }
  2739. getAboveCell$($cell) {
  2740. const {
  2741. colIndex
  2742. } = $.data($cell);
  2743. let $aboveRow = $cell.parentElement.previousElementSibling;
  2744. while ($aboveRow && $aboveRow.classList.contains('dt-row--hide')) {
  2745. $aboveRow = $aboveRow.previousElementSibling;
  2746. }
  2747. if (!$aboveRow) return $cell;
  2748. return $(`.dt-cell--col-${colIndex}`, $aboveRow);
  2749. }
  2750. getBelowCell$($cell) {
  2751. const {
  2752. colIndex
  2753. } = $.data($cell);
  2754. let $belowRow = $cell.parentElement.nextElementSibling;
  2755. while ($belowRow && $belowRow.classList.contains('dt-row--hide')) {
  2756. $belowRow = $belowRow.nextElementSibling;
  2757. }
  2758. if (!$belowRow) return $cell;
  2759. return $(`.dt-cell--col-${colIndex}`, $belowRow);
  2760. }
  2761. getLeftCell$($cell) {
  2762. return $cell.previousElementSibling;
  2763. }
  2764. getRightCell$($cell) {
  2765. return $cell.nextElementSibling;
  2766. }
  2767. getLeftMostCell$(rowIndex) {
  2768. return this.getCell$(this.columnmanager.getFirstColumnIndex(), rowIndex);
  2769. }
  2770. getRightMostCell$(rowIndex) {
  2771. return this.getCell$(this.columnmanager.getLastColumnIndex(), rowIndex);
  2772. }
  2773. getTopMostCell$(colIndex) {
  2774. return this.getCell$(colIndex, this.rowmanager.getFirstRowIndex());
  2775. }
  2776. getBottomMostCell$(colIndex) {
  2777. return this.getCell$(colIndex, this.rowmanager.getLastRowIndex());
  2778. }
  2779. getCell(colIndex, rowIndex) {
  2780. return this.instance.datamanager.getCell(colIndex, rowIndex);
  2781. }
  2782. getRowHeight() {
  2783. return $.style($('.dt-row', this.bodyScrollable), 'height');
  2784. }
  2785. scrollToCell($cell) {
  2786. if ($.inViewport($cell, this.bodyScrollable)) return false;
  2787. const {
  2788. rowIndex
  2789. } = $.data($cell);
  2790. this.rowmanager.scrollToRow(rowIndex);
  2791. return false;
  2792. }
  2793. getRowCountPerPage() {
  2794. return Math.ceil(this.instance.getViewportHeight() / this.getRowHeight());
  2795. }
  2796. getCellHTML(cell) {
  2797. const {
  2798. rowIndex,
  2799. colIndex,
  2800. isHeader,
  2801. isFilter,
  2802. isTotalRow
  2803. } = cell;
  2804. const dataAttr = makeDataAttributeString({
  2805. rowIndex,
  2806. colIndex,
  2807. isHeader,
  2808. isFilter,
  2809. isTotalRow
  2810. });
  2811. const row = this.datamanager.getRow(rowIndex);
  2812. const isBodyCell = !(isHeader || isFilter || isTotalRow);
  2813. const className = [
  2814. 'dt-cell',
  2815. 'dt-cell--col-' + colIndex,
  2816. isBodyCell ? `dt-cell--${colIndex}-${rowIndex}` : '',
  2817. isBodyCell ? 'dt-cell--row-' + rowIndex : '',
  2818. isHeader ? 'dt-cell--header' : '',
  2819. isHeader ? `dt-cell--header-${colIndex}` : '',
  2820. isFilter ? 'dt-cell--filter' : '',
  2821. isBodyCell && (row && row.meta.isTreeNodeClose) ? 'dt-cell--tree-close' : ''
  2822. ].join(' ');
  2823. return `
  2824. <div class="${className}" ${dataAttr} tabindex="0">
  2825. ${this.getCellContent(cell)}
  2826. </div>
  2827. `;
  2828. }
  2829. getCellContent(cell, refreshHtml = false) {
  2830. const {
  2831. isHeader,
  2832. isFilter,
  2833. colIndex
  2834. } = cell;
  2835. const editable = !isHeader && cell.editable !== false;
  2836. const editCellHTML = editable ? this.getEditCellHTML(colIndex) : '';
  2837. const sortable = isHeader && cell.sortable !== false;
  2838. const sortIndicator = sortable ?
  2839. `<span class="sort-indicator">
  2840. ${this.options.sortIndicator[cell.sortOrder]}
  2841. </span>` :
  2842. '';
  2843. const resizable = isHeader && cell.resizable !== false;
  2844. const resizeColumn = resizable ? '<span class="dt-cell__resize-handle"></span>' : '';
  2845. const hasDropdown = isHeader && cell.dropdown !== false;
  2846. const dropdown = hasDropdown ? this.columnmanager.getDropdownHTML() : '';
  2847. let customFormatter = CellManager.getCustomCellFormatter(cell);
  2848. let contentHTML;
  2849. if (isHeader || isFilter || !customFormatter) {
  2850. contentHTML = cell.content;
  2851. } else {
  2852. if (!cell.html || refreshHtml) {
  2853. const row = this.datamanager.getRow(cell.rowIndex);
  2854. const data = this.datamanager.getData(cell.rowIndex);
  2855. contentHTML = customFormatter(cell.content, row, cell.column, data);
  2856. } else {
  2857. contentHTML = cell.html;
  2858. }
  2859. }
  2860. cell.html = contentHTML;
  2861. if (this.options.treeView && !(isHeader || isFilter) && cell.indent !== undefined) {
  2862. const nextRow = this.datamanager.getRow(cell.rowIndex + 1);
  2863. const addToggle = nextRow && nextRow.meta.indent > cell.indent;
  2864. const leftPadding = 20;
  2865. const unit = 'px';
  2866. // Add toggle and indent in the first column
  2867. const firstColumnIndex = this.datamanager.getColumnIndexById('_rowIndex') + 1;
  2868. if (firstColumnIndex === cell.colIndex) {
  2869. const padding = ((cell.indent || 0)) * leftPadding;
  2870. const toggleHTML = addToggle ?
  2871. `<span class="dt-tree-node__toggle" style="left: ${padding - leftPadding}${unit}">
  2872. <span class="icon-open">${icons.chevronDown}</span>
  2873. <span class="icon-close">${icons.chevronRight}</span>
  2874. </span>` : '';
  2875. contentHTML = `<span class="dt-tree-node" style="padding-left: ${padding}${unit}">
  2876. ${toggleHTML}
  2877. <span>${contentHTML}</span>
  2878. </span>`;
  2879. }
  2880. }
  2881. const className = [
  2882. 'dt-cell__content',
  2883. isHeader ? `dt-cell__content--header-${colIndex}` : `dt-cell__content--col-${colIndex}`
  2884. ].join(' ');
  2885. return `
  2886. <div class="${className}">
  2887. ${contentHTML}
  2888. ${sortIndicator}
  2889. ${resizeColumn}
  2890. ${dropdown}
  2891. </div>
  2892. ${editCellHTML}
  2893. `;
  2894. }
  2895. getEditCellHTML(colIndex) {
  2896. return `<div class="dt-cell__edit dt-cell__edit--col-${colIndex}"></div>`;
  2897. }
  2898. selector(colIndex, rowIndex) {
  2899. return `.dt-cell--${colIndex}-${rowIndex}`;
  2900. }
  2901. static getCustomCellFormatter(cell) {
  2902. return cell.format || (cell.column && cell.column.format) || null;
  2903. }
  2904. }
  2905. class ColumnManager {
  2906. constructor(instance) {
  2907. this.instance = instance;
  2908. linkProperties(this, this.instance, [
  2909. 'options',
  2910. 'fireEvent',
  2911. 'header',
  2912. 'datamanager',
  2913. 'cellmanager',
  2914. 'style',
  2915. 'wrapper',
  2916. 'rowmanager',
  2917. 'bodyScrollable',
  2918. 'bodyRenderer'
  2919. ]);
  2920. this.bindEvents();
  2921. }
  2922. renderHeader() {
  2923. this.header.innerHTML = '<div></div>';
  2924. this.refreshHeader();
  2925. }
  2926. refreshHeader() {
  2927. const columns = this.datamanager.getColumns();
  2928. // refresh html
  2929. $('div', this.header).innerHTML = this.getHeaderHTML(columns);
  2930. this.$filterRow = $('.dt-row-filter', this.header);
  2931. if (this.$filterRow) {
  2932. $.style(this.$filterRow, { display: 'none' });
  2933. }
  2934. // reset columnMap
  2935. this.$columnMap = [];
  2936. this.bindMoveColumn();
  2937. }
  2938. getHeaderHTML(columns) {
  2939. let html = this.rowmanager.getRowHTML(columns, {
  2940. isHeader: 1
  2941. });
  2942. if (this.options.inlineFilters) {
  2943. html += this.rowmanager.getRowHTML(columns, {
  2944. isFilter: 1
  2945. });
  2946. }
  2947. return html;
  2948. }
  2949. bindEvents() {
  2950. this.bindDropdown();
  2951. this.bindResizeColumn();
  2952. this.bindPerfectColumnWidth();
  2953. this.bindFilter();
  2954. }
  2955. bindDropdown() {
  2956. let toggleClass = '.dt-dropdown__toggle';
  2957. let dropdownClass = '.dt-dropdown__list';
  2958. // attach the dropdown list to container
  2959. this.instance.dropdownContainer.innerHTML = this.getDropdownListHTML();
  2960. this.$dropdownList = this.instance.dropdownContainer.firstElementChild;
  2961. $.on(this.header, 'click', toggleClass, e => {
  2962. this.openDropdown(e);
  2963. });
  2964. const deactivateDropdownOnBodyClick = (e) => {
  2965. const selector = [
  2966. toggleClass, toggleClass + ' *',
  2967. dropdownClass, dropdownClass + ' *'
  2968. ].join(',');
  2969. if (e.target.matches(selector)) return;
  2970. deactivateDropdown();
  2971. };
  2972. $.on(document.body, 'click', deactivateDropdownOnBodyClick);
  2973. document.addEventListener('scroll', deactivateDropdown, true);
  2974. this.instance.on('onDestroy', () => {
  2975. $.off(document.body, 'click', deactivateDropdownOnBodyClick);
  2976. $.off(document, 'scroll', deactivateDropdown);
  2977. });
  2978. $.on(this.$dropdownList, 'click', '.dt-dropdown__list-item', (e, $item) => {
  2979. if (!this._dropdownActiveColIndex) return;
  2980. const dropdownItems = this.options.headerDropdown;
  2981. const { index } = $.data($item);
  2982. const colIndex = this._dropdownActiveColIndex;
  2983. let callback = dropdownItems[index].action;
  2984. callback && callback.call(this.instance, this.getColumn(colIndex));
  2985. this.hideDropdown();
  2986. });
  2987. const _this = this;
  2988. function deactivateDropdown(e) {
  2989. _this.hideDropdown();
  2990. }
  2991. this.hideDropdown();
  2992. }
  2993. openDropdown(e) {
  2994. if (!this._dropdownWidth) {
  2995. $.style(this.$dropdownList, { display: '' });
  2996. this._dropdownWidth = $.style(this.$dropdownList, 'width');
  2997. }
  2998. $.style(this.$dropdownList, {
  2999. display: '',
  3000. left: (e.clientX - this._dropdownWidth + 4) + 'px',
  3001. top: (e.clientY + 4) + 'px'
  3002. });
  3003. const $cell = $.closest('.dt-cell', e.target);
  3004. const { colIndex } = $.data($cell);
  3005. this._dropdownActiveColIndex = colIndex;
  3006. }
  3007. hideDropdown() {
  3008. $.style(this.$dropdownList, {
  3009. display: 'none'
  3010. });
  3011. this._dropdownActiveColIndex = null;
  3012. }
  3013. bindResizeColumn() {
  3014. let isDragging = false;
  3015. let $resizingCell, startWidth, startX;
  3016. $.on(this.header, 'mousedown', '.dt-cell .dt-cell__resize-handle', (e, $handle) => {
  3017. document.body.classList.add('dt-resize');
  3018. const $cell = $handle.parentNode.parentNode;
  3019. $resizingCell = $cell;
  3020. const {
  3021. colIndex
  3022. } = $.data($resizingCell);
  3023. const col = this.getColumn(colIndex);
  3024. if (col && col.resizable === false) {
  3025. return;
  3026. }
  3027. isDragging = true;
  3028. startWidth = $.style($('.dt-cell__content', $resizingCell), 'width');
  3029. startX = e.pageX;
  3030. });
  3031. const onMouseup = (e) => {
  3032. document.body.classList.remove('dt-resize');
  3033. if (!$resizingCell) return;
  3034. isDragging = false;
  3035. const {
  3036. colIndex
  3037. } = $.data($resizingCell);
  3038. this.setColumnWidth(colIndex);
  3039. this.style.setBodyStyle();
  3040. $resizingCell = null;
  3041. };
  3042. $.on(document.body, 'mouseup', onMouseup);
  3043. this.instance.on('onDestroy', () => {
  3044. $.off(document.body, 'mouseup', onMouseup);
  3045. });
  3046. const onMouseMove = (e) => {
  3047. if (!isDragging) return;
  3048. let delta = e.pageX - startX;
  3049. if (this.options.direction === 'rtl') {
  3050. delta = -1 * delta;
  3051. }
  3052. const finalWidth = startWidth + delta;
  3053. const {
  3054. colIndex
  3055. } = $.data($resizingCell);
  3056. let columnMinWidth = this.options.minimumColumnWidth;
  3057. if (columnMinWidth > finalWidth) {
  3058. // don't resize past 30 pixels
  3059. return;
  3060. }
  3061. this.datamanager.updateColumn(colIndex, {
  3062. width: finalWidth
  3063. });
  3064. this.setColumnHeaderWidth(colIndex);
  3065. };
  3066. $.on(document.body, 'mousemove', onMouseMove);
  3067. this.instance.on('onDestroy', () => {
  3068. $.off(document.body, 'mousemove', onMouseMove);
  3069. });
  3070. }
  3071. bindPerfectColumnWidth() {
  3072. $.on(this.header, 'dblclick', '.dt-cell .dt-cell__resize-handle', (e, $handle) => {
  3073. const $cell = $handle.parentNode.parentNode;
  3074. const { colIndex } = $.data($cell);
  3075. let longestCell = this.bodyRenderer.visibleRows
  3076. .map(d => d[colIndex])
  3077. .reduce((acc, curr) => acc.content.length > curr.content.length ? acc : curr);
  3078. let $longestCellHTML = this.cellmanager.getCellHTML(longestCell);
  3079. let $div = document.createElement('div');
  3080. $div.innerHTML = $longestCellHTML;
  3081. let cellText = $div.querySelector('.dt-cell__content').textContent;
  3082. let {
  3083. borderLeftWidth,
  3084. borderRightWidth,
  3085. paddingLeft,
  3086. paddingRight
  3087. } = $.getStyle(this.bodyScrollable.querySelector('.dt-cell__content'));
  3088. let padding = [borderLeftWidth, borderRightWidth, paddingLeft, paddingRight]
  3089. .map(parseFloat)
  3090. .reduce((sum, val) => sum + val);
  3091. let width = $.measureTextWidth(cellText) + padding;
  3092. this.datamanager.updateColumn(colIndex, { width });
  3093. this.setColumnHeaderWidth(colIndex);
  3094. this.setColumnWidth(colIndex);
  3095. });
  3096. }
  3097. bindMoveColumn() {
  3098. if (this.options.disableReorderColumn) return;
  3099. const $parent = $('.dt-row', this.header);
  3100. this.sortable = Sortable.create($parent, {
  3101. onEnd: (e) => {
  3102. const {
  3103. oldIndex,
  3104. newIndex
  3105. } = e;
  3106. const $draggedCell = e.item;
  3107. const {
  3108. colIndex
  3109. } = $.data($draggedCell);
  3110. if (+colIndex === newIndex) return;
  3111. this.switchColumn(oldIndex, newIndex);
  3112. },
  3113. preventOnFilter: false,
  3114. filter: '.dt-cell__resize-handle, .dt-dropdown',
  3115. chosenClass: 'dt-cell--dragging',
  3116. animation: 150
  3117. });
  3118. }
  3119. sortColumn(colIndex, nextSortOrder) {
  3120. this.instance.freeze();
  3121. this.sortRows(colIndex, nextSortOrder)
  3122. .then(() => {
  3123. this.refreshHeader();
  3124. return this.rowmanager.refreshRows();
  3125. })
  3126. .then(() => this.instance.unfreeze())
  3127. .then(() => {
  3128. this.fireEvent('onSortColumn', this.getColumn(colIndex));
  3129. });
  3130. }
  3131. removeColumn(colIndex) {
  3132. const removedCol = this.getColumn(colIndex);
  3133. this.instance.freeze();
  3134. this.datamanager.removeColumn(colIndex)
  3135. .then(() => {
  3136. this.refreshHeader();
  3137. return this.rowmanager.refreshRows();
  3138. })
  3139. .then(() => this.instance.unfreeze())
  3140. .then(() => {
  3141. this.fireEvent('onRemoveColumn', removedCol);
  3142. });
  3143. }
  3144. switchColumn(oldIndex, newIndex) {
  3145. this.instance.freeze();
  3146. this.datamanager.switchColumn(oldIndex, newIndex)
  3147. .then(() => {
  3148. this.refreshHeader();
  3149. return this.rowmanager.refreshRows();
  3150. })
  3151. .then(() => {
  3152. this.setColumnWidth(oldIndex);
  3153. this.setColumnWidth(newIndex);
  3154. this.instance.unfreeze();
  3155. })
  3156. .then(() => {
  3157. this.fireEvent('onSwitchColumn',
  3158. this.getColumn(oldIndex), this.getColumn(newIndex)
  3159. );
  3160. });
  3161. }
  3162. toggleFilter(flag) {
  3163. if (!this.options.inlineFilters) return;
  3164. let showFilter;
  3165. if (flag === undefined) {
  3166. showFilter = !this.isFilterShown;
  3167. } else {
  3168. showFilter = flag;
  3169. }
  3170. if (showFilter) {
  3171. $.style(this.$filterRow, { display: '' });
  3172. } else {
  3173. $.style(this.$filterRow, { display: 'none' });
  3174. }
  3175. this.isFilterShown = showFilter;
  3176. this.style.setBodyStyle();
  3177. }
  3178. focusFilter(colIndex) {
  3179. if (!this.isFilterShown) return;
  3180. const $filterInput = $(`.dt-cell--col-${colIndex} .dt-filter`, this.$filterRow);
  3181. $filterInput.focus();
  3182. }
  3183. bindFilter() {
  3184. if (!this.options.inlineFilters) return;
  3185. const handler = e => {
  3186. this.applyFilter(this.getAppliedFilters());
  3187. };
  3188. $.on(this.header, 'keydown', '.dt-filter', debounce$1(handler, 300));
  3189. }
  3190. applyFilter(filters) {
  3191. this.datamanager.filterRows(filters)
  3192. .then(({
  3193. rowsToShow
  3194. }) => {
  3195. this.rowmanager.showRows(rowsToShow);
  3196. });
  3197. }
  3198. getAppliedFilters() {
  3199. const filters = {};
  3200. $.each('.dt-filter', this.header).map((input) => {
  3201. const value = input.value;
  3202. if (value) {
  3203. filters[input.dataset.colIndex] = value;
  3204. }
  3205. });
  3206. return filters;
  3207. }
  3208. applyDefaultSortOrder() {
  3209. // sort rows if any 1 column has a default sortOrder set
  3210. const columnsToSort = this.getColumns().filter(col => col.sortOrder !== 'none');
  3211. if (columnsToSort.length === 1) {
  3212. const column = columnsToSort[0];
  3213. this.sortColumn(column.colIndex, column.sortOrder);
  3214. }
  3215. }
  3216. sortRows(colIndex, sortOrder) {
  3217. return this.datamanager.sortRows(colIndex, sortOrder);
  3218. }
  3219. getColumn(colIndex) {
  3220. return this.datamanager.getColumn(colIndex);
  3221. }
  3222. getColumns() {
  3223. return this.datamanager.getColumns();
  3224. }
  3225. setColumnWidth(colIndex, width) {
  3226. colIndex = +colIndex;
  3227. let columnWidth = width || this.getColumn(colIndex).width;
  3228. const selector = [
  3229. `.dt-cell__content--col-${colIndex}`,
  3230. `.dt-cell__edit--col-${colIndex}`
  3231. ].join(', ');
  3232. const styles = {
  3233. width: columnWidth + 'px'
  3234. };
  3235. this.style.setStyle(selector, styles);
  3236. }
  3237. setColumnHeaderWidth(colIndex) {
  3238. colIndex = +colIndex;
  3239. this.$columnMap = this.$columnMap || [];
  3240. const selector = `.dt-cell__content--header-${colIndex}`;
  3241. const {
  3242. width
  3243. } = this.getColumn(colIndex);
  3244. let $column = this.$columnMap[colIndex];
  3245. if (!$column) {
  3246. $column = this.header.querySelector(selector);
  3247. this.$columnMap[colIndex] = $column;
  3248. }
  3249. $column.style.width = width + 'px';
  3250. }
  3251. getColumnMinWidth(colIndex) {
  3252. colIndex = +colIndex;
  3253. return this.getColumn(colIndex).minWidth || 24;
  3254. }
  3255. getFirstColumnIndex() {
  3256. return this.datamanager.getColumnIndexById('_rowIndex') + 1;
  3257. }
  3258. getHeaderCell$(colIndex) {
  3259. return $(`.dt-cell--header-${colIndex}`, this.header);
  3260. }
  3261. getLastColumnIndex() {
  3262. return this.datamanager.getColumnCount() - 1;
  3263. }
  3264. getDropdownHTML() {
  3265. const { dropdownButton } = this.options;
  3266. return `
  3267. <div class="dt-dropdown">
  3268. <div class="dt-dropdown__toggle">${dropdownButton}</div>
  3269. </div>
  3270. `;
  3271. }
  3272. getDropdownListHTML() {
  3273. const { headerDropdown: dropdownItems } = this.options;
  3274. return `
  3275. <div class="dt-dropdown__list">
  3276. ${dropdownItems.map((d, i) => `
  3277. <div class="dt-dropdown__list-item" data-index="${i}">${d.label}</div>
  3278. `).join('')}
  3279. </div>
  3280. `;
  3281. }
  3282. }
  3283. class RowManager {
  3284. constructor(instance) {
  3285. this.instance = instance;
  3286. linkProperties(this, this.instance, [
  3287. 'options',
  3288. 'fireEvent',
  3289. 'wrapper',
  3290. 'bodyScrollable',
  3291. 'bodyRenderer',
  3292. 'style'
  3293. ]);
  3294. this.bindEvents();
  3295. this.refreshRows = nextTick(this.refreshRows, this);
  3296. }
  3297. get datamanager() {
  3298. return this.instance.datamanager;
  3299. }
  3300. get cellmanager() {
  3301. return this.instance.cellmanager;
  3302. }
  3303. bindEvents() {
  3304. this.bindCheckbox();
  3305. }
  3306. bindCheckbox() {
  3307. if (!this.options.checkboxColumn) return;
  3308. // map of checked rows
  3309. this.checkMap = [];
  3310. $.on(this.wrapper, 'click', '.dt-cell--col-0 [type="checkbox"]', (e, $checkbox) => {
  3311. const $cell = $checkbox.closest('.dt-cell');
  3312. const {
  3313. rowIndex,
  3314. isHeader
  3315. } = $.data($cell);
  3316. const checked = $checkbox.checked;
  3317. if (isHeader) {
  3318. this.checkAll(checked);
  3319. } else {
  3320. this.checkRow(rowIndex, checked);
  3321. }
  3322. });
  3323. }
  3324. refreshRows() {
  3325. this.instance.renderBody();
  3326. this.instance.setDimensions();
  3327. }
  3328. refreshRow(row, rowIndex) {
  3329. const _row = this.datamanager.updateRow(row, rowIndex);
  3330. _row.forEach(cell => {
  3331. this.cellmanager.refreshCell(cell, true);
  3332. });
  3333. }
  3334. getCheckedRows() {
  3335. if (!this.checkMap) {
  3336. return [];
  3337. }
  3338. let out = [];
  3339. for (let rowIndex in this.checkMap) {
  3340. const checked = this.checkMap[rowIndex];
  3341. if (checked === 1) {
  3342. out.push(rowIndex);
  3343. }
  3344. }
  3345. return out;
  3346. }
  3347. highlightCheckedRows() {
  3348. this.getCheckedRows()
  3349. .map(rowIndex => this.checkRow(rowIndex, true));
  3350. }
  3351. checkRow(rowIndex, toggle) {
  3352. const value = toggle ? 1 : 0;
  3353. const selector = rowIndex => `.dt-cell--0-${rowIndex} [type="checkbox"]`;
  3354. // update internal map
  3355. this.checkMap[rowIndex] = value;
  3356. // set checkbox value explicitly
  3357. $.each(selector(rowIndex), this.bodyScrollable)
  3358. .map(input => {
  3359. input.checked = toggle;
  3360. });
  3361. // highlight row
  3362. this.highlightRow(rowIndex, toggle);
  3363. this.showCheckStatus();
  3364. this.fireEvent('onCheckRow', this.datamanager.getRow(rowIndex));
  3365. }
  3366. checkAll(toggle) {
  3367. const value = toggle ? 1 : 0;
  3368. // update internal map
  3369. if (toggle) {
  3370. this.checkMap = Array.from(Array(this.getTotalRows())).map(c => value);
  3371. } else {
  3372. this.checkMap = [];
  3373. }
  3374. // set checkbox value
  3375. $.each('.dt-cell--col-0 [type="checkbox"]', this.bodyScrollable)
  3376. .map(input => {
  3377. input.checked = toggle;
  3378. });
  3379. // highlight all
  3380. this.highlightAll(toggle);
  3381. this.showCheckStatus();
  3382. this.fireEvent('onCheckRow');
  3383. }
  3384. showCheckStatus() {
  3385. if (!this.options.checkedRowStatus) return;
  3386. const checkedRows = this.getCheckedRows();
  3387. const count = checkedRows.length;
  3388. if (count > 0) {
  3389. let message = this.instance.translate('{count} rows selected', {
  3390. count: count
  3391. });
  3392. this.bodyRenderer.showToastMessage(message);
  3393. } else {
  3394. this.bodyRenderer.clearToastMessage();
  3395. }
  3396. }
  3397. highlightRow(rowIndex, toggle = true) {
  3398. const $row = this.getRow$(rowIndex);
  3399. if (!$row) return;
  3400. if (!toggle && this.bodyScrollable.classList.contains('dt-scrollable--highlight-all')) {
  3401. $row.classList.add('dt-row--unhighlight');
  3402. return;
  3403. }
  3404. if (toggle && $row.classList.contains('dt-row--unhighlight')) {
  3405. $row.classList.remove('dt-row--unhighlight');
  3406. }
  3407. this._highlightedRows = this._highlightedRows || {};
  3408. if (toggle) {
  3409. $row.classList.add('dt-row--highlight');
  3410. this._highlightedRows[rowIndex] = $row;
  3411. } else {
  3412. $row.classList.remove('dt-row--highlight');
  3413. delete this._highlightedRows[rowIndex];
  3414. }
  3415. }
  3416. highlightAll(toggle = true) {
  3417. if (toggle) {
  3418. this.bodyScrollable.classList.add('dt-scrollable--highlight-all');
  3419. } else {
  3420. this.bodyScrollable.classList.remove('dt-scrollable--highlight-all');
  3421. for (const rowIndex in this._highlightedRows) {
  3422. const $row = this._highlightedRows[rowIndex];
  3423. $row.classList.remove('dt-row--highlight');
  3424. }
  3425. this._highlightedRows = {};
  3426. }
  3427. }
  3428. showRows(rowIndices) {
  3429. rowIndices = ensureArray(rowIndices);
  3430. const rows = rowIndices.map(rowIndex => this.datamanager.getRow(rowIndex));
  3431. this.bodyRenderer.renderRows(rows);
  3432. }
  3433. showAllRows() {
  3434. const rowIndices = this.datamanager.getAllRowIndices();
  3435. this.showRows(rowIndices);
  3436. }
  3437. getChildrenToShowForNode(rowIndex) {
  3438. const row = this.datamanager.getRow(rowIndex);
  3439. row.meta.isTreeNodeClose = false;
  3440. return this.datamanager.getImmediateChildren(rowIndex);
  3441. }
  3442. openSingleNode(rowIndex) {
  3443. const childrenToShow = this.getChildrenToShowForNode(rowIndex);
  3444. const visibleRowIndices = this.bodyRenderer.visibleRowIndices;
  3445. const rowsToShow = uniq$1([...childrenToShow, ...visibleRowIndices]).sort(numberSortAsc);
  3446. this.showRows(rowsToShow);
  3447. }
  3448. getChildrenToHideForNode(rowIndex) {
  3449. const row = this.datamanager.getRow(rowIndex);
  3450. row.meta.isTreeNodeClose = true;
  3451. const rowsToHide = this.datamanager.getChildren(rowIndex);
  3452. rowsToHide.forEach(rowIndex => {
  3453. const row = this.datamanager.getRow(rowIndex);
  3454. if (!row.meta.isLeaf) {
  3455. row.meta.isTreeNodeClose = true;
  3456. }
  3457. });
  3458. return rowsToHide;
  3459. }
  3460. closeSingleNode(rowIndex) {
  3461. const rowsToHide = this.getChildrenToHideForNode(rowIndex);
  3462. const visibleRows = this.bodyRenderer.visibleRowIndices;
  3463. const rowsToShow = visibleRows
  3464. .filter(rowIndex => !rowsToHide.includes(rowIndex))
  3465. .sort(numberSortAsc);
  3466. this.showRows(rowsToShow);
  3467. }
  3468. expandAllNodes() {
  3469. let rows = this.datamanager.getRows();
  3470. let rootNodes = rows.filter(row => !row.meta.isLeaf);
  3471. const childrenToShow = rootNodes.map(row => this.getChildrenToShowForNode(row.meta.rowIndex)).flat();
  3472. const visibleRowIndices = this.bodyRenderer.visibleRowIndices;
  3473. const rowsToShow = uniq$1([...childrenToShow, ...visibleRowIndices]).sort(numberSortAsc);
  3474. this.showRows(rowsToShow);
  3475. }
  3476. collapseAllNodes() {
  3477. let rows = this.datamanager.getRows();
  3478. let rootNodes = rows.filter(row => row.meta.indent === 0);
  3479. const rowsToHide = rootNodes.map(row => this.getChildrenToHideForNode(row.meta.rowIndex)).flat();
  3480. const visibleRows = this.bodyRenderer.visibleRowIndices;
  3481. const rowsToShow = visibleRows
  3482. .filter(rowIndex => !rowsToHide.includes(rowIndex))
  3483. .sort(numberSortAsc);
  3484. this.showRows(rowsToShow);
  3485. }
  3486. setTreeDepth(depth) {
  3487. let rows = this.datamanager.getRows();
  3488. const rowsToOpen = rows.filter(row => row.meta.indent < depth);
  3489. const rowsToClose = rows.filter(row => row.meta.indent >= depth);
  3490. const rowsToHide = rowsToClose.filter(row => row.meta.indent > depth);
  3491. rowsToClose.forEach(row => {
  3492. if (!row.meta.isLeaf) {
  3493. row.meta.isTreeNodeClose = true;
  3494. }
  3495. });
  3496. rowsToOpen.forEach(row => {
  3497. if (!row.meta.isLeaf) {
  3498. row.meta.isTreeNodeClose = false;
  3499. }
  3500. });
  3501. const rowsToShow = rows
  3502. .filter(row => !rowsToHide.includes(row))
  3503. .map(row => row.meta.rowIndex)
  3504. .sort(numberSortAsc);
  3505. this.showRows(rowsToShow);
  3506. }
  3507. getRow$(rowIndex) {
  3508. return $(this.selector(rowIndex), this.bodyScrollable);
  3509. }
  3510. getTotalRows() {
  3511. return this.datamanager.getRowCount();
  3512. }
  3513. getFirstRowIndex() {
  3514. return 0;
  3515. }
  3516. getLastRowIndex() {
  3517. return this.datamanager.getRowCount() - 1;
  3518. }
  3519. scrollToRow(rowIndex) {
  3520. rowIndex = +rowIndex;
  3521. this._lastScrollTo = this._lastScrollTo || 0;
  3522. const $row = this.getRow$(rowIndex);
  3523. if ($.inViewport($row, this.bodyScrollable)) return;
  3524. const {
  3525. height
  3526. } = $row.getBoundingClientRect();
  3527. const {
  3528. top,
  3529. bottom
  3530. } = this.bodyScrollable.getBoundingClientRect();
  3531. const rowsInView = Math.floor((bottom - top) / height);
  3532. let offset = 0;
  3533. if (rowIndex > this._lastScrollTo) {
  3534. offset = height * ((rowIndex + 1) - rowsInView);
  3535. } else {
  3536. offset = height * ((rowIndex + 1) - 1);
  3537. }
  3538. this._lastScrollTo = rowIndex;
  3539. $.scrollTop(this.bodyScrollable, offset);
  3540. }
  3541. getRowHTML(row, props) {
  3542. const dataAttr = makeDataAttributeString(props);
  3543. let rowIdentifier = props.rowIndex;
  3544. if (props.isFilter) {
  3545. row = row.map(cell => (Object.assign({}, cell, {
  3546. content: this.getFilterInput({
  3547. colIndex: cell.colIndex,
  3548. name: cell.name
  3549. }),
  3550. isFilter: 1,
  3551. isHeader: undefined,
  3552. editable: false
  3553. })));
  3554. rowIdentifier = 'filter';
  3555. }
  3556. if (props.isHeader) {
  3557. rowIdentifier = 'header';
  3558. }
  3559. return `
  3560. <div class="dt-row dt-row-${rowIdentifier}" ${dataAttr}>
  3561. ${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
  3562. </div>
  3563. `;
  3564. }
  3565. getFilterInput(props) {
  3566. let title = `title="Filter based on ${props.name || 'Index'}"`;
  3567. const dataAttr = makeDataAttributeString(props);
  3568. return `<input class="dt-filter dt-input" type="text" ${dataAttr} tabindex="1"
  3569. ${props.colIndex === 0 ? 'disabled' : title} />`;
  3570. }
  3571. selector(rowIndex) {
  3572. return `.dt-row-${rowIndex}`;
  3573. }
  3574. }
  3575. var hyperlist = createCommonjsModule(function (module, exports) {
  3576. (function(f){{module.exports=f();}})(function(){return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof commonjsRequire&&commonjsRequire;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t);}return n[i].exports}for(var u="function"==typeof commonjsRequire&&commonjsRequire,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(_dereq_,module,exports){
  3577. // Default configuration.
  3578. Object.defineProperty(exports, "__esModule", {
  3579. value: true
  3580. });
  3581. 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; }; }();
  3582. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  3583. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3584. var defaultConfig = {
  3585. width: '100%',
  3586. height: '100%'
  3587. // Check for valid number.
  3588. };var isNumber = function isNumber(input) {
  3589. return Number(input) === Number(input);
  3590. };
  3591. // Add a class to an element.
  3592. var addClass = 'classList' in document.documentElement ? function (element, className) {
  3593. element.classList.add(className);
  3594. } : function (element, className) {
  3595. var oldClass = element.getAttribute('class') || '';
  3596. element.setAttribute('class', oldClass + ' ' + className);
  3597. };
  3598. /**
  3599. * Creates a HyperList instance that virtually scrolls very large amounts of
  3600. * data effortlessly.
  3601. */
  3602. var HyperList = function () {
  3603. _createClass(HyperList, null, [{
  3604. key: 'create',
  3605. value: function create(element, userProvidedConfig) {
  3606. return new HyperList(element, userProvidedConfig);
  3607. }
  3608. /**
  3609. * Merge given css style on an element
  3610. * @param {DOMElement} element
  3611. * @param {Object} style
  3612. */
  3613. }, {
  3614. key: 'mergeStyle',
  3615. value: function mergeStyle(element, style) {
  3616. for (var i in style) {
  3617. if (element.style[i] !== style[i]) {
  3618. element.style[i] = style[i];
  3619. }
  3620. }
  3621. }
  3622. }, {
  3623. key: 'getMaxBrowserHeight',
  3624. value: function getMaxBrowserHeight() {
  3625. // Create two elements, the wrapper is `1px` tall and is transparent and
  3626. // positioned at the top of the page. Inside that is an element that gets
  3627. // set to 1 billion pixels. Then reads the max height the browser can
  3628. // calculate.
  3629. var wrapper = document.createElement('div');
  3630. var fixture = document.createElement('div');
  3631. // As said above, these values get set to put the fixture elements into the
  3632. // right visual state.
  3633. HyperList.mergeStyle(wrapper, { position: 'absolute', height: '1px', opacity: 0 });
  3634. HyperList.mergeStyle(fixture, { height: '1e7px' });
  3635. // Add the fixture into the wrapper element.
  3636. wrapper.appendChild(fixture);
  3637. // Apply to the page, the values won't kick in unless this is attached.
  3638. document.body.appendChild(wrapper);
  3639. // Get the maximum element height in pixels.
  3640. var maxElementHeight = fixture.offsetHeight;
  3641. // Remove the element immediately after reading the value.
  3642. document.body.removeChild(wrapper);
  3643. return maxElementHeight;
  3644. }
  3645. }]);
  3646. function HyperList(element, userProvidedConfig) {
  3647. var _this = this;
  3648. _classCallCheck(this, HyperList);
  3649. this._config = {};
  3650. this._lastRepaint = null;
  3651. this._maxElementHeight = HyperList.getMaxBrowserHeight();
  3652. this.refresh(element, userProvidedConfig);
  3653. var config = this._config;
  3654. // Create internal render loop.
  3655. var render = function render() {
  3656. var scrollTop = _this._getScrollPosition();
  3657. var lastRepaint = _this._lastRepaint;
  3658. _this._renderAnimationFrame = window.requestAnimationFrame(render);
  3659. if (scrollTop === lastRepaint) {
  3660. return;
  3661. }
  3662. var diff = lastRepaint ? scrollTop - lastRepaint : 0;
  3663. if (!lastRepaint || diff < 0 || diff > _this._averageHeight) {
  3664. var rendered = _this._renderChunk();
  3665. _this._lastRepaint = scrollTop;
  3666. if (rendered !== false && typeof config.afterRender === 'function') {
  3667. config.afterRender();
  3668. }
  3669. }
  3670. };
  3671. render();
  3672. }
  3673. _createClass(HyperList, [{
  3674. key: 'destroy',
  3675. value: function destroy() {
  3676. window.cancelAnimationFrame(this._renderAnimationFrame);
  3677. }
  3678. }, {
  3679. key: 'refresh',
  3680. value: function refresh(element, userProvidedConfig) {
  3681. var _scrollerStyle;
  3682. Object.assign(this._config, defaultConfig, userProvidedConfig);
  3683. if (!element || element.nodeType !== 1) {
  3684. throw new Error('HyperList requires a valid DOM Node container');
  3685. }
  3686. this._element = element;
  3687. var config = this._config;
  3688. var scroller = this._scroller || config.scroller || document.createElement(config.scrollerTagName || 'tr');
  3689. // Default configuration option `useFragment` to `true`.
  3690. if (typeof config.useFragment !== 'boolean') {
  3691. this._config.useFragment = true;
  3692. }
  3693. if (!config.generate) {
  3694. throw new Error('Missing required `generate` function');
  3695. }
  3696. if (!isNumber(config.total)) {
  3697. throw new Error('Invalid required `total` value, expected number');
  3698. }
  3699. if (!Array.isArray(config.itemHeight) && !isNumber(config.itemHeight)) {
  3700. throw new Error('\n Invalid required `itemHeight` value, expected number or array\n '.trim());
  3701. } else if (isNumber(config.itemHeight)) {
  3702. this._itemHeights = Array(config.total).fill(config.itemHeight);
  3703. } else {
  3704. this._itemHeights = config.itemHeight;
  3705. }
  3706. // Width and height should be coerced to string representations. Either in
  3707. // `%` or `px`.
  3708. Object.keys(defaultConfig).filter(function (prop) {
  3709. return prop in config;
  3710. }).forEach(function (prop) {
  3711. var value = config[prop];
  3712. var isValueNumber = isNumber(value);
  3713. if (value && typeof value !== 'string' && typeof value !== 'number') {
  3714. var msg = 'Invalid optional `' + prop + '`, expected string or number';
  3715. throw new Error(msg);
  3716. } else if (isValueNumber) {
  3717. config[prop] = value + 'px';
  3718. }
  3719. });
  3720. var isHoriz = Boolean(config.horizontal);
  3721. var value = config[isHoriz ? 'width' : 'height'];
  3722. if (value) {
  3723. var isValueNumber = isNumber(value);
  3724. var isValuePercent = isValueNumber ? false : value.slice(-1) === '%';
  3725. // Compute the containerHeight as number
  3726. var numberValue = isValueNumber ? value : parseInt(value.replace(/px|%/, ''), 10);
  3727. var innerSize = window[isHoriz ? 'innerWidth' : 'innerHeight'];
  3728. if (isValuePercent) {
  3729. this._containerSize = innerSize * numberValue / 100;
  3730. } else {
  3731. this._containerSize = isNumber(value) ? value : numberValue;
  3732. }
  3733. }
  3734. var scrollContainer = config.scrollContainer;
  3735. var scrollerHeight = config.itemHeight * config.total;
  3736. var maxElementHeight = this._maxElementHeight;
  3737. if (scrollerHeight > maxElementHeight) {
  3738. console.warn(['HyperList: The maximum element height', maxElementHeight + 'px has', 'been exceeded; please reduce your item height.'].join(' '));
  3739. }
  3740. // Decorate the container element with styles that will match
  3741. // the user supplied configuration.
  3742. var elementStyle = {
  3743. width: '' + config.width,
  3744. height: scrollContainer ? scrollerHeight + 'px' : '' + config.height,
  3745. overflow: scrollContainer ? 'none' : 'auto',
  3746. position: 'relative'
  3747. };
  3748. HyperList.mergeStyle(element, elementStyle);
  3749. if (scrollContainer) {
  3750. HyperList.mergeStyle(config.scrollContainer, { overflow: 'auto' });
  3751. }
  3752. var scrollerStyle = (_scrollerStyle = {
  3753. opacity: '0',
  3754. position: 'absolute'
  3755. }, _defineProperty(_scrollerStyle, isHoriz ? 'height' : 'width', '1px'), _defineProperty(_scrollerStyle, isHoriz ? 'width' : 'height', scrollerHeight + 'px'), _scrollerStyle);
  3756. HyperList.mergeStyle(scroller, scrollerStyle);
  3757. // Only append the scroller element once.
  3758. if (!this._scroller) {
  3759. element.appendChild(scroller);
  3760. }
  3761. var padding = this._computeScrollPadding();
  3762. this._scrollPaddingBottom = padding.bottom;
  3763. this._scrollPaddingTop = padding.top;
  3764. // Set the scroller instance.
  3765. this._scroller = scroller;
  3766. this._scrollHeight = this._computeScrollHeight();
  3767. // Reuse the item positions if refreshed, otherwise set to empty array.
  3768. this._itemPositions = this._itemPositions || Array(config.total).fill(0);
  3769. // Each index in the array should represent the position in the DOM.
  3770. this._computePositions(0);
  3771. // Render after refreshing. Force render if we're calling refresh manually.
  3772. this._renderChunk(this._lastRepaint !== null);
  3773. if (typeof config.afterRender === 'function') {
  3774. config.afterRender();
  3775. }
  3776. }
  3777. }, {
  3778. key: '_getRow',
  3779. value: function _getRow(i) {
  3780. var config = this._config;
  3781. var item = config.generate(i);
  3782. var height = item.height;
  3783. if (height !== undefined && isNumber(height)) {
  3784. item = item.element;
  3785. // The height isn't the same as predicted, compute positions again
  3786. if (height !== this._itemHeights[i]) {
  3787. this._itemHeights[i] = height;
  3788. this._computePositions(i);
  3789. this._scrollHeight = this._computeScrollHeight(i);
  3790. }
  3791. } else {
  3792. height = this._itemHeights[i];
  3793. }
  3794. if (!item || item.nodeType !== 1) {
  3795. throw new Error('Generator did not return a DOM Node for index: ' + i);
  3796. }
  3797. addClass(item, config.rowClassName || 'vrow');
  3798. var top = this._itemPositions[i] + this._scrollPaddingTop;
  3799. HyperList.mergeStyle(item, _defineProperty({
  3800. position: 'absolute'
  3801. }, config.horizontal ? 'left' : 'top', top + 'px'));
  3802. return item;
  3803. }
  3804. }, {
  3805. key: '_getScrollPosition',
  3806. value: function _getScrollPosition() {
  3807. var config = this._config;
  3808. if (typeof config.overrideScrollPosition === 'function') {
  3809. return config.overrideScrollPosition();
  3810. }
  3811. return this._element[config.horizontal ? 'scrollLeft' : 'scrollTop'];
  3812. }
  3813. }, {
  3814. key: '_renderChunk',
  3815. value: function _renderChunk(force) {
  3816. var config = this._config;
  3817. var element = this._element;
  3818. var scrollTop = this._getScrollPosition();
  3819. var total = config.total;
  3820. var from = config.reverse ? this._getReverseFrom(scrollTop) : this._getFrom(scrollTop) - 1;
  3821. if (from < 0 || from - this._screenItemsLen < 0) {
  3822. from = 0;
  3823. }
  3824. if (!force && this._lastFrom === from) {
  3825. return false;
  3826. }
  3827. this._lastFrom = from;
  3828. var to = from + this._cachedItemsLen;
  3829. if (to > total || to + this._cachedItemsLen > total) {
  3830. to = total;
  3831. }
  3832. // Append all the new rows in a document fragment that we will later append
  3833. // to the parent node
  3834. var fragment = config.useFragment ? document.createDocumentFragment() : []
  3835. // Sometimes you'll pass fake elements to this tool and Fragments require
  3836. // real elements.
  3837. // The element that forces the container to scroll.
  3838. ;var scroller = this._scroller;
  3839. // Keep the scroller in the list of children.
  3840. fragment[config.useFragment ? 'appendChild' : 'push'](scroller);
  3841. for (var i = from; i < to; i++) {
  3842. var row = this._getRow(i);
  3843. fragment[config.useFragment ? 'appendChild' : 'push'](row);
  3844. }
  3845. if (config.applyPatch) {
  3846. return config.applyPatch(element, fragment);
  3847. }
  3848. element.innerHTML = '';
  3849. element.appendChild(fragment);
  3850. }
  3851. }, {
  3852. key: '_computePositions',
  3853. value: function _computePositions() {
  3854. var from = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
  3855. var config = this._config;
  3856. var total = config.total;
  3857. var reverse = config.reverse;
  3858. if (from < 1 && !reverse) {
  3859. from = 1;
  3860. }
  3861. for (var i = from; i < total; i++) {
  3862. if (reverse) {
  3863. if (i === 0) {
  3864. this._itemPositions[0] = this._scrollHeight - this._itemHeights[0];
  3865. } else {
  3866. this._itemPositions[i] = this._itemPositions[i - 1] - this._itemHeights[i];
  3867. }
  3868. } else {
  3869. this._itemPositions[i] = this._itemHeights[i - 1] + this._itemPositions[i - 1];
  3870. }
  3871. }
  3872. }
  3873. }, {
  3874. key: '_computeScrollHeight',
  3875. value: function _computeScrollHeight() {
  3876. var _HyperList$mergeStyle2,
  3877. _this2 = this;
  3878. var config = this._config;
  3879. var isHoriz = Boolean(config.horizontal);
  3880. var total = config.total;
  3881. var scrollHeight = this._itemHeights.reduce(function (a, b) {
  3882. return a + b;
  3883. }, 0) + this._scrollPaddingBottom + this._scrollPaddingTop;
  3884. HyperList.mergeStyle(this._scroller, (_HyperList$mergeStyle2 = {
  3885. opacity: 0,
  3886. position: 'absolute',
  3887. top: '0px'
  3888. }, _defineProperty(_HyperList$mergeStyle2, isHoriz ? 'height' : 'width', '1px'), _defineProperty(_HyperList$mergeStyle2, isHoriz ? 'width' : 'height', scrollHeight + 'px'), _HyperList$mergeStyle2));
  3889. // Calculate the height median
  3890. var sortedItemHeights = this._itemHeights.slice(0).sort(function (a, b) {
  3891. return a - b;
  3892. });
  3893. var middle = Math.floor(total / 2);
  3894. var averageHeight = total % 2 === 0 ? (sortedItemHeights[middle] + sortedItemHeights[middle - 1]) / 2 : sortedItemHeights[middle];
  3895. var clientProp = isHoriz ? 'clientWidth' : 'clientHeight';
  3896. var element = config.scrollContainer ? config.scrollContainer : this._element;
  3897. var containerHeight = element[clientProp] ? element[clientProp] : this._containerSize;
  3898. this._screenItemsLen = Math.ceil(containerHeight / averageHeight);
  3899. this._containerSize = containerHeight;
  3900. // Cache 3 times the number of items that fit in the container viewport.
  3901. this._cachedItemsLen = Math.max(this._cachedItemsLen || 0, this._screenItemsLen * 3);
  3902. this._averageHeight = averageHeight;
  3903. if (config.reverse) {
  3904. window.requestAnimationFrame(function () {
  3905. if (isHoriz) {
  3906. _this2._element.scrollLeft = scrollHeight;
  3907. } else {
  3908. _this2._element.scrollTop = scrollHeight;
  3909. }
  3910. });
  3911. }
  3912. return scrollHeight;
  3913. }
  3914. }, {
  3915. key: '_computeScrollPadding',
  3916. value: function _computeScrollPadding() {
  3917. var config = this._config;
  3918. var isHoriz = Boolean(config.horizontal);
  3919. var isReverse = config.reverse;
  3920. var styles = window.getComputedStyle(this._element);
  3921. var padding = function padding(location) {
  3922. var cssValue = styles.getPropertyValue('padding-' + location);
  3923. return parseInt(cssValue, 10) || 0;
  3924. };
  3925. if (isHoriz && isReverse) {
  3926. return {
  3927. bottom: padding('left'),
  3928. top: padding('right')
  3929. };
  3930. } else if (isHoriz) {
  3931. return {
  3932. bottom: padding('right'),
  3933. top: padding('left')
  3934. };
  3935. } else if (isReverse) {
  3936. return {
  3937. bottom: padding('top'),
  3938. top: padding('bottom')
  3939. };
  3940. } else {
  3941. return {
  3942. bottom: padding('bottom'),
  3943. top: padding('top')
  3944. };
  3945. }
  3946. }
  3947. }, {
  3948. key: '_getFrom',
  3949. value: function _getFrom(scrollTop) {
  3950. var i = 0;
  3951. while (this._itemPositions[i] < scrollTop) {
  3952. i++;
  3953. }
  3954. return i;
  3955. }
  3956. }, {
  3957. key: '_getReverseFrom',
  3958. value: function _getReverseFrom(scrollTop) {
  3959. var i = this._config.total - 1;
  3960. while (i > 0 && this._itemPositions[i] < scrollTop + this._containerSize) {
  3961. i--;
  3962. }
  3963. return i;
  3964. }
  3965. }]);
  3966. return HyperList;
  3967. }();
  3968. exports.default = HyperList;
  3969. module.exports = exports['default'];
  3970. },{}]},{},[1])(1)
  3971. });
  3972. });
  3973. var HyperList = unwrapExports(hyperlist);
  3974. class BodyRenderer {
  3975. constructor(instance) {
  3976. this.instance = instance;
  3977. this.options = instance.options;
  3978. this.datamanager = instance.datamanager;
  3979. this.rowmanager = instance.rowmanager;
  3980. this.cellmanager = instance.cellmanager;
  3981. this.bodyScrollable = instance.bodyScrollable;
  3982. this.footer = this.instance.footer;
  3983. this.log = instance.log;
  3984. }
  3985. renderRows(rows) {
  3986. this.visibleRows = rows;
  3987. this.visibleRowIndices = rows.map(row => row.meta.rowIndex);
  3988. if (rows.length === 0) {
  3989. this.bodyScrollable.innerHTML = this.getNoDataHTML();
  3990. return;
  3991. }
  3992. const rowViewOrder = this.datamanager.rowViewOrder.map(index => {
  3993. if (this.visibleRowIndices.includes(index)) {
  3994. return index;
  3995. }
  3996. return null;
  3997. }).filter(index => index !== null);
  3998. const computedStyle = getComputedStyle(this.bodyScrollable);
  3999. let config = {
  4000. width: computedStyle.width,
  4001. height: computedStyle.height,
  4002. itemHeight: this.options.cellHeight,
  4003. total: rows.length,
  4004. generate: (index) => {
  4005. const el = document.createElement('div');
  4006. const rowIndex = rowViewOrder[index];
  4007. const row = this.datamanager.getRow(rowIndex);
  4008. const rowHTML = this.rowmanager.getRowHTML(row, row.meta);
  4009. el.innerHTML = rowHTML;
  4010. return el.children[0];
  4011. },
  4012. afterRender: () => {
  4013. this.restoreState();
  4014. }
  4015. };
  4016. if (!this.hyperlist) {
  4017. this.hyperlist = new HyperList(this.bodyScrollable, config);
  4018. } else {
  4019. this.hyperlist.refresh(this.bodyScrollable, config);
  4020. }
  4021. this.renderFooter();
  4022. }
  4023. render() {
  4024. const rows = this.datamanager.getRowsForView();
  4025. this.renderRows(rows);
  4026. // setDimensions requires atleast 1 row to exist in dom
  4027. this.instance.setDimensions();
  4028. }
  4029. renderFooter() {
  4030. if (!this.options.showTotalRow) return;
  4031. const totalRow = this.getTotalRow();
  4032. let html = this.rowmanager.getRowHTML(totalRow, { isTotalRow: 1, rowIndex: 'totalRow' });
  4033. this.footer.innerHTML = html;
  4034. }
  4035. getTotalRow() {
  4036. const columns = this.datamanager.getColumns();
  4037. const totalRowTemplate = columns.map(col => {
  4038. let content = null;
  4039. if (['_rowIndex', '_checkbox'].includes(col.id)) {
  4040. content = '';
  4041. }
  4042. return {
  4043. content,
  4044. isTotalRow: 1,
  4045. colIndex: col.colIndex,
  4046. column: col
  4047. };
  4048. });
  4049. const totalRow = totalRowTemplate.map((cell, i) => {
  4050. if (cell.content === '') return cell;
  4051. if (this.options.hooks.columnTotal) {
  4052. const columnValues = this.visibleRows.map(row => row[i].content);
  4053. const result = this.options.hooks.columnTotal.call(this.instance, columnValues, cell);
  4054. if (result != null) {
  4055. cell.content = result;
  4056. return cell;
  4057. }
  4058. }
  4059. cell.content = this.visibleRows.reduce((acc, prevRow) => {
  4060. const prevCell = prevRow[i];
  4061. if (typeof prevCell.content === 'number') {
  4062. if (acc == null) acc = 0;
  4063. return acc + prevCell.content;
  4064. }
  4065. return acc;
  4066. }, cell.content);
  4067. return cell;
  4068. });
  4069. return totalRow;
  4070. }
  4071. restoreState() {
  4072. this.rowmanager.highlightCheckedRows();
  4073. this.cellmanager.selectAreaOnClusterChanged();
  4074. this.cellmanager.focusCellOnClusterChanged();
  4075. }
  4076. showToastMessage(message, hideAfter) {
  4077. this.instance.toastMessage.innerHTML = this.getToastMessageHTML(message);
  4078. if (hideAfter) {
  4079. setTimeout(() => {
  4080. this.clearToastMessage();
  4081. }, hideAfter * 1000);
  4082. }
  4083. }
  4084. clearToastMessage() {
  4085. this.instance.toastMessage.innerHTML = '';
  4086. }
  4087. getNoDataHTML() {
  4088. return `<div class="dt-scrollable__no-data">${this.options.noDataMessage}</div>`;
  4089. }
  4090. getToastMessageHTML(message) {
  4091. return `<span class="dt-toast__message">${message}</span>`;
  4092. }
  4093. }
  4094. class Style {
  4095. constructor(instance) {
  4096. this.instance = instance;
  4097. linkProperties(this, this.instance, [
  4098. 'options', 'datamanager', 'columnmanager',
  4099. 'header', 'footer', 'bodyScrollable', 'datatableWrapper',
  4100. 'getColumn', 'bodyRenderer'
  4101. ]);
  4102. this.scopeClass = 'dt-instance-' + instance.constructor.instances;
  4103. instance.datatableWrapper.classList.add(this.scopeClass);
  4104. const styleEl = document.createElement('style');
  4105. instance.wrapper.insertBefore(styleEl, instance.datatableWrapper);
  4106. this.styleEl = styleEl;
  4107. this.bindResizeWindow();
  4108. this.bindScrollHeader();
  4109. }
  4110. get stylesheet() {
  4111. return this.styleEl.sheet;
  4112. }
  4113. bindResizeWindow() {
  4114. this.onWindowResize = this.onWindowResize.bind(this);
  4115. this.onWindowResize = throttle$1(this.onWindowResize, 300);
  4116. if (this.options.layout === 'fluid') {
  4117. $.on(window, 'resize', this.onWindowResize);
  4118. }
  4119. }
  4120. bindScrollHeader() {
  4121. this._settingHeaderPosition = false;
  4122. $.on(this.bodyScrollable, 'scroll', (e) => {
  4123. if (this._settingHeaderPosition) return;
  4124. this._settingHeaderPosition = true;
  4125. requestAnimationFrame(() => {
  4126. const left = -e.target.scrollLeft;
  4127. $.style(this.header, {
  4128. transform: `translateX(${left}px)`
  4129. });
  4130. $.style(this.footer, {
  4131. transform: `translateX(${left}px)`
  4132. });
  4133. this._settingHeaderPosition = false;
  4134. });
  4135. });
  4136. }
  4137. onWindowResize() {
  4138. this.distributeRemainingWidth();
  4139. this.refreshColumnWidth();
  4140. this.setBodyStyle();
  4141. }
  4142. destroy() {
  4143. this.styleEl.remove();
  4144. $.off(window, 'resize', this.onWindowResize);
  4145. }
  4146. setStyle(selector, styleObject) {
  4147. if (selector.includes(',')) {
  4148. selector.split(',')
  4149. .map(s => s.trim())
  4150. .forEach(selector => {
  4151. this.setStyle(selector, styleObject);
  4152. });
  4153. return;
  4154. }
  4155. selector = selector.trim();
  4156. if (!selector) return;
  4157. this._styleRulesMap = this._styleRulesMap || {};
  4158. const prefixedSelector = this._getPrefixedSelector(selector);
  4159. if (this._styleRulesMap[prefixedSelector]) {
  4160. this.removeStyle(selector);
  4161. // merge with old styleobject
  4162. styleObject = Object.assign({}, this._styleRulesMap[prefixedSelector], styleObject);
  4163. }
  4164. const styleString = this._getRuleString(styleObject);
  4165. const ruleString = `${prefixedSelector} { ${styleString} }`;
  4166. this._styleRulesMap[prefixedSelector] = styleObject;
  4167. this.stylesheet.insertRule(ruleString);
  4168. }
  4169. removeStyle(selector) {
  4170. if (selector.includes(',')) {
  4171. selector.split(',')
  4172. .map(s => s.trim())
  4173. .forEach(selector => {
  4174. this.removeStyle(selector);
  4175. });
  4176. return;
  4177. }
  4178. selector = selector.trim();
  4179. if (!selector) return;
  4180. // find and remove
  4181. const prefixedSelector = this._getPrefixedSelector(selector);
  4182. const index = Array.from(this.stylesheet.cssRules)
  4183. .findIndex(rule => rule.selectorText === prefixedSelector);
  4184. if (index === -1) return;
  4185. this.stylesheet.deleteRule(index);
  4186. }
  4187. _getPrefixedSelector(selector) {
  4188. return `.${this.scopeClass} ${selector}`;
  4189. }
  4190. _getRuleString(styleObject) {
  4191. return Object.keys(styleObject)
  4192. .map(prop => {
  4193. let dashed = prop;
  4194. if (!prop.includes('-')) {
  4195. dashed = camelCaseToDash(prop);
  4196. }
  4197. return `${dashed}:${styleObject[prop]};`;
  4198. })
  4199. .join('');
  4200. }
  4201. setDimensions() {
  4202. this.setCellHeight();
  4203. this.setupMinWidth();
  4204. this.setupNaturalColumnWidth();
  4205. this.setupColumnWidth();
  4206. this.distributeRemainingWidth();
  4207. this.setColumnStyle();
  4208. this.setBodyStyle();
  4209. }
  4210. setCellHeight() {
  4211. this.setStyle('.dt-cell', {
  4212. height: this.options.cellHeight + 'px'
  4213. });
  4214. }
  4215. setupMinWidth() {
  4216. $.each('.dt-cell--header', this.header).map(col => {
  4217. const { colIndex } = $.data(col);
  4218. const column = this.getColumn(colIndex);
  4219. if (!column.minWidth) {
  4220. const width = $.style($('.dt-cell__content', col), 'width');
  4221. // only set this once
  4222. column.minWidth = width;
  4223. }
  4224. });
  4225. }
  4226. setupNaturalColumnWidth() {
  4227. if (!$('.dt-row')) return;
  4228. $.each('.dt-row-header .dt-cell', this.header).map($headerCell => {
  4229. const { colIndex } = $.data($headerCell);
  4230. const column = this.datamanager.getColumn(colIndex);
  4231. let width = $.style($('.dt-cell__content', $headerCell), 'width');
  4232. if (typeof width === 'number' && width >= this.options.minimumColumnWidth) {
  4233. column.naturalWidth = width;
  4234. } else {
  4235. column.naturalWidth = this.options.minimumColumnWidth;
  4236. }
  4237. });
  4238. // set initial width as naturally calculated by table's first row
  4239. $.each('.dt-row-0 .dt-cell', this.bodyScrollable).map($cell => {
  4240. const {
  4241. colIndex
  4242. } = $.data($cell);
  4243. const column = this.datamanager.getColumn(colIndex);
  4244. let naturalWidth = $.style($('.dt-cell__content', $cell), 'width');
  4245. if (typeof naturalWidth === 'number' && naturalWidth >= column.naturalWidth) {
  4246. column.naturalWidth = naturalWidth;
  4247. } else {
  4248. column.naturalWidth = column.naturalWidth;
  4249. }
  4250. });
  4251. }
  4252. setupColumnWidth() {
  4253. if (this.options.layout === 'ratio') {
  4254. let totalWidth = $.style(this.datatableWrapper, 'width');
  4255. if (this.options.serialNoColumn) {
  4256. const rowIndexColumn = this.datamanager.getColumnById('_rowIndex');
  4257. totalWidth = totalWidth - rowIndexColumn.width - 1;
  4258. }
  4259. if (this.options.checkboxColumn) {
  4260. const rowIndexColumn = this.datamanager.getColumnById('_checkbox');
  4261. totalWidth = totalWidth - rowIndexColumn.width - 1;
  4262. }
  4263. const totalParts = this.datamanager.getColumns()
  4264. .map(column => {
  4265. if (column.id === '_rowIndex' || column.id === '_checkbox') {
  4266. return 0;
  4267. }
  4268. if (!column.width) {
  4269. column.width = 1;
  4270. }
  4271. column.ratioWidth = parseInt(column.width, 10);
  4272. return column.ratioWidth;
  4273. })
  4274. .reduce((a, c) => a + c);
  4275. const onePart = totalWidth / totalParts;
  4276. this.datamanager.getColumns()
  4277. .map(column => {
  4278. if (column.id === '_rowIndex' || column.id === '_checkbox') return;
  4279. column.width = Math.floor(onePart * column.ratioWidth) - 1;
  4280. });
  4281. } else {
  4282. this.datamanager.getColumns()
  4283. .map(column => {
  4284. if (!column.width) {
  4285. column.width = column.naturalWidth;
  4286. }
  4287. if (column.id === '_rowIndex') {
  4288. column.width = this.getRowIndexColumnWidth();
  4289. }
  4290. if (column.width < this.options.minimumColumnWidth) {
  4291. column.width = this.options.minimumColumnWidth;
  4292. }
  4293. });
  4294. }
  4295. }
  4296. distributeRemainingWidth() {
  4297. if (this.options.layout !== 'fluid') return;
  4298. const wrapperWidth = $.style(this.instance.datatableWrapper, 'width');
  4299. let firstRow = $('.dt-row', this.bodyScrollable);
  4300. let firstRowWidth = wrapperWidth;
  4301. if (!firstRow) {
  4302. let headerRow = $('.dt-row', this.instance.header);
  4303. let cellWidths = Array.from(headerRow.children)
  4304. .map(cell => cell.offsetWidth);
  4305. firstRowWidth = cellWidths.reduce((sum, a) => sum + a, 0);
  4306. } else {
  4307. firstRowWidth = $.style(firstRow, 'width');
  4308. }
  4309. const resizableColumns = this.datamanager.getColumns().filter(col => col.resizable);
  4310. const deltaWidth = (wrapperWidth - firstRowWidth) / resizableColumns.length;
  4311. resizableColumns.map(col => {
  4312. const width = $.style(this.getColumnHeaderElement(col.colIndex), 'width');
  4313. let finalWidth = Math.floor(width + deltaWidth) - 2;
  4314. this.datamanager.updateColumn(col.colIndex, {
  4315. width: finalWidth
  4316. });
  4317. });
  4318. }
  4319. setColumnStyle() {
  4320. // align columns
  4321. this.datamanager.getColumns()
  4322. .map(column => {
  4323. // alignment
  4324. if (!column.align) {
  4325. column.align = 'left';
  4326. }
  4327. if (!['left', 'center', 'right'].includes(column.align)) {
  4328. column.align = 'left';
  4329. }
  4330. this.setStyle(`.dt-cell--col-${column.colIndex}`, {
  4331. 'text-align': column.align
  4332. });
  4333. // width
  4334. this.columnmanager.setColumnHeaderWidth(column.colIndex);
  4335. this.columnmanager.setColumnWidth(column.colIndex);
  4336. });
  4337. }
  4338. refreshColumnWidth() {
  4339. this.datamanager.getColumns()
  4340. .map(column => {
  4341. this.columnmanager.setColumnHeaderWidth(column.colIndex);
  4342. this.columnmanager.setColumnWidth(column.colIndex);
  4343. });
  4344. }
  4345. setBodyStyle() {
  4346. const bodyWidth = $.style(this.datatableWrapper, 'width');
  4347. const firstRow = $('.dt-row', this.bodyScrollable);
  4348. if (!firstRow) return;
  4349. const rowWidth = $.style(firstRow, 'width');
  4350. let width = bodyWidth > rowWidth ? rowWidth : bodyWidth;
  4351. $.style(this.bodyScrollable, {
  4352. width: width + 'px'
  4353. });
  4354. // remove the body height, so that it resets to it's original
  4355. $.removeStyle(this.bodyScrollable, 'height');
  4356. // when there are less rows than the container
  4357. // adapt the container height
  4358. let bodyHeight = $.getStyle(this.bodyScrollable, 'height');
  4359. const scrollHeight = (this.bodyRenderer.hyperlist || {})._scrollHeight || Infinity;
  4360. const hasHorizontalOverflow = $.hasHorizontalOverflow(this.bodyScrollable);
  4361. let height;
  4362. if (scrollHeight < bodyHeight) {
  4363. height = scrollHeight;
  4364. // account for scrollbar size when
  4365. // there is horizontal overflow
  4366. if (hasHorizontalOverflow) {
  4367. height += $.scrollbarSize();
  4368. }
  4369. $.style(this.bodyScrollable, {
  4370. height: height + 'px'
  4371. });
  4372. }
  4373. const verticalOverflow = this.bodyScrollable.scrollHeight - this.bodyScrollable.offsetHeight;
  4374. if (verticalOverflow < $.scrollbarSize()) {
  4375. // if verticalOverflow is less than scrollbar size
  4376. // then most likely scrollbar is causing the scroll
  4377. // which is not needed
  4378. $.style(this.bodyScrollable, {
  4379. overflowY: 'hidden'
  4380. });
  4381. }
  4382. if (this.options.layout === 'fluid') {
  4383. $.style(this.bodyScrollable, {
  4384. overflowX: 'hidden'
  4385. });
  4386. }
  4387. }
  4388. getColumnHeaderElement(colIndex) {
  4389. colIndex = +colIndex;
  4390. if (colIndex < 0) return null;
  4391. return $(`.dt-cell--col-${colIndex}`, this.header);
  4392. }
  4393. getRowIndexColumnWidth() {
  4394. const rowCount = this.datamanager.getRowCount();
  4395. const padding = 22;
  4396. return $.measureTextWidth(rowCount + '') + padding;
  4397. }
  4398. }
  4399. const KEYCODES = {
  4400. 13: 'enter',
  4401. 91: 'meta',
  4402. 16: 'shift',
  4403. 17: 'ctrl',
  4404. 18: 'alt',
  4405. 37: 'left',
  4406. 38: 'up',
  4407. 39: 'right',
  4408. 40: 'down',
  4409. 9: 'tab',
  4410. 27: 'esc',
  4411. 67: 'c',
  4412. 70: 'f',
  4413. 86: 'v'
  4414. };
  4415. class Keyboard {
  4416. constructor(element) {
  4417. this.listeners = {};
  4418. $.on(element, 'keydown', this.handler.bind(this));
  4419. }
  4420. handler(e) {
  4421. let key = KEYCODES[e.keyCode];
  4422. if (e.shiftKey && key !== 'shift') {
  4423. key = 'shift+' + key;
  4424. }
  4425. if ((e.ctrlKey && key !== 'ctrl') || (e.metaKey && key !== 'meta')) {
  4426. key = 'ctrl+' + key;
  4427. }
  4428. const listeners = this.listeners[key];
  4429. if (listeners && listeners.length > 0) {
  4430. for (let listener of listeners) {
  4431. const preventBubbling = listener(e);
  4432. if (preventBubbling === undefined || preventBubbling === true) {
  4433. e.preventDefault();
  4434. }
  4435. }
  4436. }
  4437. }
  4438. on(key, listener) {
  4439. const keys = key.split(',').map(k => k.trim());
  4440. keys.map(key => {
  4441. this.listeners[key] = this.listeners[key] || [];
  4442. this.listeners[key].push(listener);
  4443. });
  4444. }
  4445. }
  4446. var en = {
  4447. "Sort Ascending": "Sort Ascending",
  4448. "Sort Descending": "Sort Descending",
  4449. "Reset sorting": "Reset sorting",
  4450. "Remove column": "Remove column",
  4451. "No Data": "No Data",
  4452. "{count} cells copied": {"1":"{count} cell copied","default":"{count} cells copied"},
  4453. "{count} rows selected": {"1":"{count} row selected","default":"{count} rows selected"}
  4454. };
  4455. var de = {
  4456. "Sort Ascending": "Aufsteigend sortieren",
  4457. "Sort Descending": "Absteigend sortieren",
  4458. "Reset sorting": "Sortierung zurücksetzen",
  4459. "Remove column": "Spalte entfernen",
  4460. "No Data": "Keine Daten",
  4461. "{count} cells copied": {"1":"{count} Zelle kopiert","default":"{count} Zellen kopiert"},
  4462. "{count} rows selected": {"1":"{count} Zeile ausgewählt","default":"{count} Zeilen ausgewählt"}
  4463. };
  4464. var fr = {
  4465. "Sort Ascending": "Trier par ordre croissant",
  4466. "Sort Descending": "Trier par ordre décroissant",
  4467. "Reset sorting": "Réinitialiser le tri",
  4468. "Remove column": "Supprimer colonne",
  4469. "No Data": "Pas de données",
  4470. "{count} cells copied": {"1":"{count} cellule copiée","default":"{count} cellules copiées"},
  4471. "{count} rows selected": {"1":"{count} ligne sélectionnée","default":"{count} lignes sélectionnées"}
  4472. };
  4473. var it = {
  4474. "Sort Ascending": "Ordinamento ascendente",
  4475. "Sort Descending": "Ordinamento decrescente",
  4476. "Reset sorting": "Azzeramento ordinamento",
  4477. "Remove column": "Rimuovi colonna",
  4478. "No Data": "Nessun dato",
  4479. "{count} cells copied": {"1":"Copiato {count} cella","default":"{count} celle copiate"},
  4480. "{count} rows selected": {"1":"{count} linea selezionata","default":"{count} linee selezionate"}
  4481. };
  4482. function getTranslations() {
  4483. return {
  4484. en,
  4485. de,
  4486. fr,
  4487. it,
  4488. };
  4489. }
  4490. class TranslationManager {
  4491. constructor(language) {
  4492. this.language = language;
  4493. this.translations = getTranslations();
  4494. }
  4495. addTranslations(translations) {
  4496. this.translations = Object.assign(this.translations, translations);
  4497. }
  4498. translate(sourceText, args) {
  4499. let translation = (this.translations[this.language] &&
  4500. this.translations[this.language][sourceText]) || sourceText;
  4501. if (typeof translation === 'object') {
  4502. translation = args && args.count ?
  4503. this.getPluralizedTranslation(translation, args.count) :
  4504. sourceText;
  4505. }
  4506. return format(translation, args || {});
  4507. }
  4508. getPluralizedTranslation(translations, count) {
  4509. return translations[count] || translations['default'];
  4510. }
  4511. }
  4512. function filterRows(rows, filters) {
  4513. let filteredRowIndices = [];
  4514. if (Object.keys(filters).length === 0) {
  4515. return rows.map(row => row.meta.rowIndex);
  4516. }
  4517. for (let colIndex in filters) {
  4518. const keyword = filters[colIndex];
  4519. const filteredRows = filteredRowIndices.length ?
  4520. filteredRowIndices.map(i => rows[i]) :
  4521. rows;
  4522. const cells = filteredRows.map(row => row[colIndex]);
  4523. let filter = guessFilter(keyword);
  4524. let filterMethod = getFilterMethod(rows, filter);
  4525. if (filterMethod) {
  4526. filteredRowIndices = filterMethod(filter.text, cells);
  4527. } else {
  4528. filteredRowIndices = cells.map(cell => cell.rowIndex);
  4529. }
  4530. }
  4531. return filteredRowIndices;
  4532. }
  4533. function getFilterMethod(rows, filter) {
  4534. const getFormattedValue = cell => {
  4535. let formatter = CellManager.getCustomCellFormatter(cell);
  4536. if (formatter && cell.content) {
  4537. cell.html = formatter(cell.content, rows[cell.rowIndex], cell.column, rows[cell.rowIndex]);
  4538. return stripHTML(cell.html);
  4539. }
  4540. return cell.content || '';
  4541. };
  4542. const stringCompareValue = cell =>
  4543. String(stripHTML(cell.html || '') || getFormattedValue(cell)).toLowerCase();
  4544. const numberCompareValue = cell => parseFloat(cell.content);
  4545. const getCompareValues = (cell, keyword) => {
  4546. if (cell.column.compareValue) {
  4547. const compareValues = cell.column.compareValue(cell, keyword);
  4548. if (compareValues && Array.isArray(compareValues)) return compareValues;
  4549. }
  4550. // check if it can be converted to number
  4551. const float = numberCompareValue(cell);
  4552. if (!isNaN(float)) {
  4553. return [float, keyword];
  4554. }
  4555. return [stringCompareValue(cell), keyword];
  4556. };
  4557. let filterMethodMap = {
  4558. contains(keyword, cells) {
  4559. return cells
  4560. .filter(cell => {
  4561. const hay = stringCompareValue(cell);
  4562. const needle = (keyword || '').toLowerCase();
  4563. return !needle || hay.includes(needle);
  4564. })
  4565. .map(cell => cell.rowIndex);
  4566. },
  4567. greaterThan(keyword, cells) {
  4568. return cells
  4569. .filter(cell => {
  4570. const [compareValue, keywordValue] = getCompareValues(cell, keyword);
  4571. return compareValue > keywordValue;
  4572. })
  4573. .map(cell => cell.rowIndex);
  4574. },
  4575. lessThan(keyword, cells) {
  4576. return cells
  4577. .filter(cell => {
  4578. const [compareValue, keywordValue] = getCompareValues(cell, keyword);
  4579. return compareValue < keywordValue;
  4580. })
  4581. .map(cell => cell.rowIndex);
  4582. },
  4583. equals(keyword, cells) {
  4584. return cells
  4585. .filter(cell => {
  4586. const value = parseFloat(cell.content);
  4587. return value === keyword;
  4588. })
  4589. .map(cell => cell.rowIndex);
  4590. },
  4591. notEquals(keyword, cells) {
  4592. return cells
  4593. .filter(cell => {
  4594. const value = parseFloat(cell.content);
  4595. return value !== keyword;
  4596. })
  4597. .map(cell => cell.rowIndex);
  4598. },
  4599. range(rangeValues, cells) {
  4600. return cells
  4601. .filter(cell => {
  4602. const values1 = getCompareValues(cell, rangeValues[0]);
  4603. const values2 = getCompareValues(cell, rangeValues[1]);
  4604. const value = values1[0];
  4605. return value >= values1[1] && value <= values2[1];
  4606. })
  4607. .map(cell => cell.rowIndex);
  4608. },
  4609. containsNumber(keyword, cells) {
  4610. return cells
  4611. .filter(cell => {
  4612. let number = parseFloat(keyword, 10);
  4613. let string = keyword;
  4614. let hayNumber = numberCompareValue(cell);
  4615. let hayString = stringCompareValue(cell);
  4616. return number === hayNumber || hayString.includes(string);
  4617. })
  4618. .map(cell => cell.rowIndex);
  4619. }
  4620. };
  4621. return filterMethodMap[filter.type];
  4622. }
  4623. function guessFilter(keyword = '') {
  4624. if (keyword.length === 0) return {};
  4625. let compareString = keyword;
  4626. if (['>', '<', '='].includes(compareString[0])) {
  4627. compareString = keyword.slice(1);
  4628. } else if (compareString.startsWith('!=')) {
  4629. compareString = keyword.slice(2);
  4630. }
  4631. if (keyword.startsWith('>')) {
  4632. if (compareString) {
  4633. return {
  4634. type: 'greaterThan',
  4635. text: compareString.trim()
  4636. };
  4637. }
  4638. }
  4639. if (keyword.startsWith('<')) {
  4640. if (compareString) {
  4641. return {
  4642. type: 'lessThan',
  4643. text: compareString.trim()
  4644. };
  4645. }
  4646. }
  4647. if (keyword.startsWith('=')) {
  4648. if (isNumber(compareString)) {
  4649. return {
  4650. type: 'equals',
  4651. text: Number(keyword.slice(1).trim())
  4652. };
  4653. }
  4654. }
  4655. if (isNumber(compareString)) {
  4656. return {
  4657. type: 'containsNumber',
  4658. text: compareString
  4659. };
  4660. }
  4661. if (keyword.startsWith('!=')) {
  4662. if (isNumber(compareString)) {
  4663. return {
  4664. type: 'notEquals',
  4665. text: Number(keyword.slice(2).trim())
  4666. };
  4667. }
  4668. }
  4669. if (keyword.split(':').length === 2) {
  4670. compareString = keyword.split(':');
  4671. return {
  4672. type: 'range',
  4673. text: compareString.map(v => v.trim())
  4674. };
  4675. }
  4676. return {
  4677. type: 'contains',
  4678. text: compareString.toLowerCase()
  4679. };
  4680. }
  4681. function getDefaultOptions(instance) {
  4682. return {
  4683. columns: [],
  4684. data: [],
  4685. dropdownButton: icons.chevronDown,
  4686. headerDropdown: [
  4687. {
  4688. label: instance.translate('Sort Ascending'),
  4689. action: function (column) {
  4690. this.sortColumn(column.colIndex, 'asc');
  4691. }
  4692. },
  4693. {
  4694. label: instance.translate('Sort Descending'),
  4695. action: function (column) {
  4696. this.sortColumn(column.colIndex, 'desc');
  4697. }
  4698. },
  4699. {
  4700. label: instance.translate('Reset sorting'),
  4701. action: function (column) {
  4702. this.sortColumn(column.colIndex, 'none');
  4703. }
  4704. },
  4705. {
  4706. label: instance.translate('Remove column'),
  4707. action: function (column) {
  4708. this.removeColumn(column.colIndex);
  4709. }
  4710. }
  4711. ],
  4712. events: {
  4713. onRemoveColumn(column) {},
  4714. onSwitchColumn(column1, column2) {},
  4715. onSortColumn(column) {},
  4716. onCheckRow(row) {},
  4717. onDestroy() {}
  4718. },
  4719. hooks: {
  4720. columnTotal: null
  4721. },
  4722. sortIndicator: {
  4723. asc: '↑',
  4724. desc: '↓',
  4725. none: ''
  4726. },
  4727. overrideComponents: {
  4728. // ColumnManager: CustomColumnManager
  4729. },
  4730. filterRows: filterRows,
  4731. freezeMessage: '',
  4732. getEditor: null,
  4733. serialNoColumn: true,
  4734. checkboxColumn: false,
  4735. clusterize: true,
  4736. logs: false,
  4737. layout: 'fixed', // fixed, fluid, ratio
  4738. noDataMessage: instance.translate('No Data'),
  4739. cellHeight: 40,
  4740. minimumColumnWidth: 30,
  4741. inlineFilters: false,
  4742. treeView: false,
  4743. checkedRowStatus: true,
  4744. dynamicRowHeight: false,
  4745. pasteFromClipboard: false,
  4746. showTotalRow: false,
  4747. direction: 'ltr',
  4748. disableReorderColumn: false
  4749. };
  4750. }
  4751. let defaultComponents = {
  4752. DataManager,
  4753. CellManager,
  4754. ColumnManager,
  4755. RowManager,
  4756. BodyRenderer,
  4757. Style,
  4758. Keyboard
  4759. };
  4760. class DataTable {
  4761. constructor(wrapper, options) {
  4762. DataTable.instances++;
  4763. if (typeof wrapper === 'string') {
  4764. // css selector
  4765. wrapper = document.querySelector(wrapper);
  4766. }
  4767. this.wrapper = wrapper;
  4768. if (!(this.wrapper instanceof HTMLElement)) {
  4769. throw new Error('Invalid argument given for `wrapper`');
  4770. }
  4771. this.initializeTranslations(options);
  4772. this.setDefaultOptions();
  4773. this.buildOptions(options);
  4774. this.prepare();
  4775. this.initializeComponents();
  4776. if (this.options.data) {
  4777. this.refresh();
  4778. this.columnmanager.applyDefaultSortOrder();
  4779. }
  4780. }
  4781. initializeTranslations(options) {
  4782. this.language = options.language || 'en';
  4783. this.translationManager = new TranslationManager(this.language);
  4784. if (options.translations) {
  4785. this.translationManager.addTranslations(options.translations);
  4786. }
  4787. }
  4788. setDefaultOptions() {
  4789. this.DEFAULT_OPTIONS = getDefaultOptions(this);
  4790. }
  4791. buildOptions(options) {
  4792. this.options = this.options || {};
  4793. this.options = Object.assign(
  4794. {}, this.DEFAULT_OPTIONS,
  4795. this.options || {}, options
  4796. );
  4797. options.headerDropdown = options.headerDropdown || [];
  4798. this.options.headerDropdown = [
  4799. ...this.DEFAULT_OPTIONS.headerDropdown,
  4800. ...options.headerDropdown
  4801. ];
  4802. // custom user events
  4803. this.events = Object.assign(
  4804. {}, this.DEFAULT_OPTIONS.events,
  4805. this.options.events || {},
  4806. options.events || {}
  4807. );
  4808. this.fireEvent = this.fireEvent.bind(this);
  4809. }
  4810. prepare() {
  4811. this.prepareDom();
  4812. this.unfreeze();
  4813. }
  4814. initializeComponents() {
  4815. let components = Object.assign({}, defaultComponents, this.options.overrideComponents);
  4816. let {
  4817. Style: Style$$1,
  4818. Keyboard: Keyboard$$1,
  4819. DataManager: DataManager$$1,
  4820. RowManager: RowManager$$1,
  4821. ColumnManager: ColumnManager$$1,
  4822. CellManager: CellManager$$1,
  4823. BodyRenderer: BodyRenderer$$1
  4824. } = components;
  4825. this.style = new Style$$1(this);
  4826. this.keyboard = new Keyboard$$1(this.wrapper);
  4827. this.datamanager = new DataManager$$1(this.options);
  4828. this.rowmanager = new RowManager$$1(this);
  4829. this.columnmanager = new ColumnManager$$1(this);
  4830. this.cellmanager = new CellManager$$1(this);
  4831. this.bodyRenderer = new BodyRenderer$$1(this);
  4832. }
  4833. prepareDom() {
  4834. this.wrapper.innerHTML = `
  4835. <div class="datatable" dir="${this.options.direction}">
  4836. <div class="dt-header"></div>
  4837. <div class="dt-scrollable"></div>
  4838. <div class="dt-footer"></div>
  4839. <div class="dt-freeze">
  4840. <span class="dt-freeze__message">
  4841. ${this.options.freezeMessage}
  4842. </span>
  4843. </div>
  4844. <div class="dt-toast"></div>
  4845. <div class="dt-dropdown-container"></div>
  4846. <textarea class="dt-paste-target"></textarea>
  4847. </div>
  4848. `;
  4849. this.datatableWrapper = $('.datatable', this.wrapper);
  4850. this.header = $('.dt-header', this.wrapper);
  4851. this.footer = $('.dt-footer', this.wrapper);
  4852. this.bodyScrollable = $('.dt-scrollable', this.wrapper);
  4853. this.freezeContainer = $('.dt-freeze', this.wrapper);
  4854. this.toastMessage = $('.dt-toast', this.wrapper);
  4855. this.pasteTarget = $('.dt-paste-target', this.wrapper);
  4856. this.dropdownContainer = $('.dt-dropdown-container', this.wrapper);
  4857. }
  4858. refresh(data, columns) {
  4859. this.datamanager.init(data, columns);
  4860. this.render();
  4861. this.setDimensions();
  4862. }
  4863. destroy() {
  4864. this.wrapper.innerHTML = '';
  4865. this.style.destroy();
  4866. this.fireEvent('onDestroy');
  4867. }
  4868. appendRows(rows) {
  4869. this.datamanager.appendRows(rows);
  4870. this.rowmanager.refreshRows();
  4871. }
  4872. refreshRow(row, rowIndex) {
  4873. this.rowmanager.refreshRow(row, rowIndex);
  4874. }
  4875. render() {
  4876. this.renderHeader();
  4877. this.renderBody();
  4878. }
  4879. renderHeader() {
  4880. this.columnmanager.renderHeader();
  4881. }
  4882. renderBody() {
  4883. this.bodyRenderer.render();
  4884. }
  4885. setDimensions() {
  4886. this.style.setDimensions();
  4887. }
  4888. showToastMessage(message, hideAfter) {
  4889. this.bodyRenderer.showToastMessage(message, hideAfter);
  4890. }
  4891. clearToastMessage() {
  4892. this.bodyRenderer.clearToastMessage();
  4893. }
  4894. getColumn(colIndex) {
  4895. return this.datamanager.getColumn(colIndex);
  4896. }
  4897. getColumns() {
  4898. return this.datamanager.getColumns();
  4899. }
  4900. getRows() {
  4901. return this.datamanager.getRows();
  4902. }
  4903. getCell(colIndex, rowIndex) {
  4904. return this.datamanager.getCell(colIndex, rowIndex);
  4905. }
  4906. getColumnHeaderElement(colIndex) {
  4907. return this.columnmanager.getColumnHeaderElement(colIndex);
  4908. }
  4909. getViewportHeight() {
  4910. if (!this.viewportHeight) {
  4911. this.viewportHeight = $.style(this.bodyScrollable, 'height');
  4912. }
  4913. return this.viewportHeight;
  4914. }
  4915. sortColumn(colIndex, sortOrder) {
  4916. this.columnmanager.sortColumn(colIndex, sortOrder);
  4917. }
  4918. removeColumn(colIndex) {
  4919. this.columnmanager.removeColumn(colIndex);
  4920. }
  4921. scrollToLastColumn() {
  4922. this.datatableWrapper.scrollLeft = 9999;
  4923. }
  4924. freeze() {
  4925. $.style(this.freezeContainer, {
  4926. display: ''
  4927. });
  4928. }
  4929. unfreeze() {
  4930. $.style(this.freezeContainer, {
  4931. display: 'none'
  4932. });
  4933. }
  4934. updateOptions(options) {
  4935. this.buildOptions(options);
  4936. }
  4937. fireEvent(eventName, ...args) {
  4938. // fire internalEventHandlers if any
  4939. // and then user events
  4940. const handlers = [
  4941. ...(this._internalEventHandlers[eventName] || []),
  4942. this.events[eventName]
  4943. ].filter(Boolean);
  4944. for (let handler of handlers) {
  4945. handler.apply(this, args);
  4946. }
  4947. }
  4948. on(event, handler) {
  4949. this._internalEventHandlers = this._internalEventHandlers || {};
  4950. this._internalEventHandlers[event] = this._internalEventHandlers[event] || [];
  4951. this._internalEventHandlers[event].push(handler);
  4952. }
  4953. log() {
  4954. if (this.options.logs) {
  4955. console.log.apply(console, arguments);
  4956. }
  4957. }
  4958. translate(str, args) {
  4959. return this.translationManager.translate(str, args);
  4960. }
  4961. }
  4962. DataTable.instances = 0;
  4963. var name = "xhiveframework-datatable";
  4964. var version = "0.0.0-development";
  4965. var description = "A modern datatable library for the web";
  4966. var main = "dist/xhiveframework-datatable.cjs.js";
  4967. var unpkg = "dist/xhiveframework-datatable.min.js";
  4968. var jsdelivr = "dist/xhiveframework-datatable.min.js";
  4969. var scripts = {"start":"yarn run dev","build":"rollup -c && NODE_ENV=production rollup -c","dev":"rollup -c -w","cy:server":"http-server -p 8989","cy:open":"cypress open","cy:run":"cypress run","test":"start-server-and-test cy:server http://localhost:8989 cy:run","test-local":"start-server-and-test cy:server http://localhost:8989 cy:open","travis-deploy-once":"travis-deploy-once","semantic-release":"semantic-release","lint":"eslint src","lint-and-build":"yarn lint && yarn build","commit":"npx git-cz"};
  4970. var files = ["dist","src"];
  4971. var devDependencies = {"autoprefixer":"^9.0.0","chai":"3.5.0","cypress":"^9.2.0","cz-conventional-changelog":"^2.1.0","deepmerge":"^2.0.1","eslint":"^5.0.1","eslint-config-airbnb":"^16.1.0","eslint-config-airbnb-base":"^12.1.0","eslint-plugin-import":"^2.11.0","http-server":"^0.11.1","mocha":"3.3.0","postcss-custom-properties":"^7.0.0","postcss-nested":"^3.0.0","rollup":"^0.59.4","rollup-plugin-commonjs":"^8.3.0","rollup-plugin-eslint":"^4.0.0","rollup-plugin-json":"^2.3.0","rollup-plugin-node-resolve":"^3.0.3","rollup-plugin-postcss":"^1.2.8","rollup-plugin-uglify-es":"^0.0.1","semantic-release":"^17.1.1","start-server-and-test":"^1.4.1","travis-deploy-once":"^5.0.1"};
  4972. var repository = {"type":"git","url":"https://github.com/xhiveframework/datatable.git"};
  4973. var keywords = ["datatable","data","grid","table"];
  4974. var author = "Faris Ansari";
  4975. var license = "MIT";
  4976. var bugs = {"url":"https://github.com/xhiveframework/datatable/issues"};
  4977. var homepage = "https://xhiveframework.com/datatable";
  4978. var dependencies = {"hyperlist":"^1.0.0-beta","lodash":"^4.17.5","sortablejs":"^1.7.0"};
  4979. var config = {"commitizen":{"path":"cz-conventional-changelog"}};
  4980. var packageJson = {
  4981. name: name,
  4982. version: version,
  4983. description: description,
  4984. main: main,
  4985. unpkg: unpkg,
  4986. jsdelivr: jsdelivr,
  4987. scripts: scripts,
  4988. files: files,
  4989. devDependencies: devDependencies,
  4990. repository: repository,
  4991. keywords: keywords,
  4992. author: author,
  4993. license: license,
  4994. bugs: bugs,
  4995. homepage: homepage,
  4996. dependencies: dependencies,
  4997. config: config
  4998. };
  4999. DataTable.__version__ = packageJson.version;
  5000. module.exports = DataTable;