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.

dataTables.searchBuilder.js 182KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402
  1. (function () {
  2. 'use strict';
  3. /*! DateTime picker for DataTables.net v1.0.1
  4. *
  5. * ©2020 SpryMedia Ltd, all rights reserved.
  6. * License: MIT datatables.net/license/mit
  7. */
  8. /**
  9. * @summary DateTime picker for DataTables.net
  10. * @version 1.0.1
  11. * @file dataTables.dateTime.js
  12. * @author SpryMedia Ltd
  13. * @contact www.datatables.net/contact
  14. */
  15. (function (factory) {
  16. if (typeof define === 'function' && define.amd) {
  17. // AMD
  18. define(['jquery'], function ($) {
  19. return factory($, window, document);
  20. });
  21. } else if (typeof exports === 'object') {
  22. // CommonJS
  23. module.exports = function (root, $) {
  24. if (!root) {
  25. root = window;
  26. }
  27. return factory($, root, root.document);
  28. };
  29. } else {
  30. // Browser
  31. factory(jQuery, window, document);
  32. }
  33. }(function ($, window, document, undefined$1) {
  34. // Support libraries which support a Moment like API
  35. var dateLib = window.moment
  36. ? window.moment
  37. : window.dayjs
  38. ? window.dayjs
  39. : null;
  40. /*
  41. * This file provides a DateTime GUI picker (calendar and time input). Only the
  42. * format YYYY-MM-DD is supported without additional software, but the end user
  43. * experience can be greatly enhanced by including the momentjs or dayjs library
  44. * which provide date / time parsing and formatting options.
  45. *
  46. * This functionality is required because the HTML5 date and datetime input
  47. * types are not widely supported in desktop browsers.
  48. *
  49. * Constructed by using:
  50. *
  51. * new DateTime( input, opts )
  52. *
  53. * where `input` is the HTML input element to use and `opts` is an object of
  54. * options based on the `DateTime.defaults` object.
  55. */
  56. var DateTime = function (input, opts) {
  57. this.c = $.extend(true, {}, DateTime.defaults, opts);
  58. var classPrefix = this.c.classPrefix;
  59. var i18n = this.c.i18n;
  60. // Only IS8601 dates are supported without moment pr dayjs
  61. if (!dateLib && this.c.format !== 'YYYY-MM-DD') {
  62. throw "DateTime: Without momentjs or dayjs only the format 'YYYY-MM-DD' can be used";
  63. }
  64. // Min and max need to be `Date` objects in the config
  65. if (typeof this.c.minDate === 'string') {
  66. this.c.minDate = new Date(this.c.minDate);
  67. }
  68. if (typeof this.c.maxDate === 'string') {
  69. this.c.maxDate = new Date(this.c.maxDate);
  70. }
  71. // DOM structure
  72. var structure = $(
  73. '<div class="' + classPrefix + '">' +
  74. '<div class="' + classPrefix + '-date">' +
  75. '<div class="' + classPrefix + '-title">' +
  76. '<div class="' + classPrefix + '-iconLeft">' +
  77. '<button>' + i18n.previous + '</button>' +
  78. '</div>' +
  79. '<div class="' + classPrefix + '-iconRight">' +
  80. '<button>' + i18n.next + '</button>' +
  81. '</div>' +
  82. '<div class="' + classPrefix + '-label">' +
  83. '<span></span>' +
  84. '<select class="' + classPrefix + '-month"></select>' +
  85. '</div>' +
  86. '<div class="' + classPrefix + '-label">' +
  87. '<span></span>' +
  88. '<select class="' + classPrefix + '-year"></select>' +
  89. '</div>' +
  90. '</div>' +
  91. '<div class="' + classPrefix + '-calendar"></div>' +
  92. '</div>' +
  93. '<div class="' + classPrefix + '-time">' +
  94. '<div class="' + classPrefix + '-hours"></div>' +
  95. '<div class="' + classPrefix + '-minutes"></div>' +
  96. '<div class="' + classPrefix + '-seconds"></div>' +
  97. '</div>' +
  98. '<div class="' + classPrefix + '-error"></div>' +
  99. '</div>'
  100. );
  101. this.dom = {
  102. container: structure,
  103. date: structure.find('.' + classPrefix + '-date'),
  104. title: structure.find('.' + classPrefix + '-title'),
  105. calendar: structure.find('.' + classPrefix + '-calendar'),
  106. time: structure.find('.' + classPrefix + '-time'),
  107. error: structure.find('.' + classPrefix + '-error'),
  108. input: $(input)
  109. };
  110. this.s = {
  111. /** @type {Date} Date value that the picker has currently selected */
  112. d: null,
  113. /** @type {Date} Date of the calendar - might not match the value */
  114. display: null,
  115. /** @type {number} Used to select minutes in a range where the range base is itself unavailable */
  116. minutesRange: null,
  117. /** @type {number} Used to select minutes in a range where the range base is itself unavailable */
  118. secondsRange: null,
  119. /** @type {String} Unique namespace string for this instance */
  120. namespace: 'dateime-' + (DateTime._instance++),
  121. /** @type {Object} Parts of the picker that should be shown */
  122. parts: {
  123. date: this.c.format.match(/[YMD]|L(?!T)|l/) !== null,
  124. time: this.c.format.match(/[Hhm]|LT|LTS/) !== null,
  125. seconds: this.c.format.indexOf('s') !== -1,
  126. hours12: this.c.format.match(/[haA]/) !== null
  127. }
  128. };
  129. this.dom.container
  130. .append(this.dom.date)
  131. .append(this.dom.time)
  132. .append(this.dom.error);
  133. this.dom.date
  134. .append(this.dom.title)
  135. .append(this.dom.calendar);
  136. this._constructor();
  137. };
  138. $.extend(DateTime.prototype, {
  139. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  140. * Public
  141. */
  142. /**
  143. * Destroy the control
  144. */
  145. destroy: function () {
  146. this._hide(true);
  147. this.dom.container.off().empty();
  148. this.dom.input.off('.datetime');
  149. },
  150. errorMsg: function (msg) {
  151. var error = this.dom.error;
  152. if (msg) {
  153. error.html(msg);
  154. } else {
  155. error.empty();
  156. }
  157. return this;
  158. },
  159. hide: function () {
  160. this._hide();
  161. return this;
  162. },
  163. max: function (date) {
  164. this.c.maxDate = typeof date === 'string'
  165. ? new Date(date)
  166. : date;
  167. this._optionsTitle();
  168. this._setCalander();
  169. return this;
  170. },
  171. min: function (date) {
  172. this.c.minDate = typeof date === 'string'
  173. ? new Date(date)
  174. : date;
  175. this._optionsTitle();
  176. this._setCalander();
  177. return this;
  178. },
  179. /**
  180. * Check if an element belongs to this control
  181. *
  182. * @param {node} node Element to check
  183. * @return {boolean} true if owned by this control, false otherwise
  184. */
  185. owns: function (node) {
  186. return $(node).parents().filter(this.dom.container).length > 0;
  187. },
  188. /**
  189. * Get / set the value
  190. *
  191. * @param {string|Date} set Value to set
  192. * @param {boolean} [write=true] Flag to indicate if the formatted value
  193. * should be written into the input element
  194. */
  195. val: function (set, write) {
  196. if (set === undefined$1) {
  197. return this.s.d;
  198. }
  199. if (set instanceof Date) {
  200. this.s.d = this._dateToUtc(set);
  201. } else if (set === null || set === '') {
  202. this.s.d = null;
  203. } else if (set === '--now') {
  204. this.s.d = new Date();
  205. } else if (typeof set === 'string') {
  206. if (dateLib) {
  207. // Use moment or dayjs if possible (even for ISO8601 strings, since it
  208. // will correctly handle 0000-00-00 and the like)
  209. var m = dateLib.utc(set, this.c.format, this.c.locale, this.c.strict);
  210. this.s.d = m.isValid() ? m.toDate() : null;
  211. } else {
  212. // Else must be using ISO8601 without a date library (constructor would
  213. // have thrown an error otherwise)
  214. var match = set.match(/(\d{4})\-(\d{2})\-(\d{2})/);
  215. this.s.d = match ?
  216. new Date(Date.UTC(match[1], match[2] - 1, match[3])) :
  217. null;
  218. }
  219. }
  220. if (write || write === undefined$1) {
  221. if (this.s.d) {
  222. this._writeOutput();
  223. } else {
  224. // The input value was not valid...
  225. this.dom.input.val(set);
  226. }
  227. }
  228. // We need a date to be able to display the calendar at all
  229. if (!this.s.d) {
  230. this.s.d = this._dateToUtc(new Date());
  231. }
  232. this.s.display = new Date(this.s.d.toString());
  233. // Set the day of the month to be 1 so changing between months doesn't
  234. // run into issues when going from day 31 to 28 (for example)
  235. this.s.display.setUTCDate(1);
  236. // Update the display elements for the new value
  237. this._setTitle();
  238. this._setCalander();
  239. this._setTime();
  240. return this;
  241. },
  242. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  243. * Constructor
  244. */
  245. /**
  246. * Build the control and assign initial event handlers
  247. *
  248. * @private
  249. */
  250. _constructor: function () {
  251. var that = this;
  252. var classPrefix = this.c.classPrefix;
  253. var onChange = function () {
  254. that.c.onChange.call(that, that.dom.input.val(), that.s.d, that.dom.input);
  255. };
  256. if (!this.s.parts.date) {
  257. this.dom.date.css('display', 'none');
  258. }
  259. if (!this.s.parts.time) {
  260. this.dom.time.css('display', 'none');
  261. }
  262. if (!this.s.parts.seconds) {
  263. this.dom.time.children('div.' + classPrefix + '-seconds').remove();
  264. this.dom.time.children('span').eq(1).remove();
  265. }
  266. // Render the options
  267. this._optionsTitle();
  268. window.allan = this;
  269. // When attached to a hidden input, we always show the input picker, and
  270. // do so inline
  271. if (this.dom.input.attr('type') === 'hidden') {
  272. this.dom.container.addClass('inline');
  273. this.c.attachTo = 'input';
  274. this.val(this.dom.input.val(), false);
  275. this._show();
  276. }
  277. // Trigger the display of the widget when clicking or focusing on the
  278. // input element
  279. this.dom.input
  280. .attr('autocomplete', 'off')
  281. .on('focus.datetime click.datetime', function () {
  282. // If already visible - don't do anything
  283. if (that.dom.container.is(':visible') || that.dom.input.is(':disabled')) {
  284. return;
  285. }
  286. // In case the value has changed by text
  287. that.val(that.dom.input.val(), false);
  288. that._show();
  289. })
  290. .on('keyup.datetime', function () {
  291. // Update the calendar's displayed value as the user types
  292. if (that.dom.container.is(':visible')) {
  293. that.val(that.dom.input.val(), false);
  294. }
  295. });
  296. // Main event handlers for input in the widget
  297. this.dom.container
  298. .on('change', 'select', function () {
  299. var select = $(this);
  300. var val = select.val();
  301. if (select.hasClass(classPrefix + '-month')) {
  302. // Month select
  303. that._correctMonth(that.s.display, val);
  304. that._setTitle();
  305. that._setCalander();
  306. } else if (select.hasClass(classPrefix + '-year')) {
  307. // Year select
  308. that.s.display.setUTCFullYear(val);
  309. that._setTitle();
  310. that._setCalander();
  311. } else if (select.hasClass(classPrefix + '-hours') || select.hasClass(classPrefix + '-ampm')) {
  312. // Hours - need to take account of AM/PM input if present
  313. if (that.s.parts.hours12) {
  314. var hours = $(that.dom.container).find('.' + classPrefix + '-hours').val() * 1;
  315. var pm = $(that.dom.container).find('.' + classPrefix + '-ampm').val() === 'pm';
  316. that.s.d.setUTCHours(hours === 12 && !pm ?
  317. 0 :
  318. pm && hours !== 12 ?
  319. hours + 12 :
  320. hours
  321. );
  322. } else {
  323. that.s.d.setUTCHours(val);
  324. }
  325. that._setTime();
  326. that._writeOutput(true);
  327. onChange();
  328. } else if (select.hasClass(classPrefix + '-minutes')) {
  329. // Minutes select
  330. that.s.d.setUTCMinutes(val);
  331. that._setTime();
  332. that._writeOutput(true);
  333. onChange();
  334. } else if (select.hasClass(classPrefix + '-seconds')) {
  335. // Seconds select
  336. that.s.d.setSeconds(val);
  337. that._setTime();
  338. that._writeOutput(true);
  339. onChange();
  340. }
  341. that.dom.input.focus();
  342. that._position();
  343. })
  344. .on('click', function (e) {
  345. var d = that.s.d;
  346. var nodeName = e.target.nodeName.toLowerCase();
  347. var target = nodeName === 'span' ?
  348. e.target.parentNode :
  349. e.target;
  350. nodeName = target.nodeName.toLowerCase();
  351. if (nodeName === 'select') {
  352. return;
  353. }
  354. e.stopPropagation();
  355. if (nodeName === 'button') {
  356. var button = $(target);
  357. var parent = button.parent();
  358. if (parent.hasClass('disabled') && !parent.hasClass('range')) {
  359. button.blur();
  360. return;
  361. }
  362. if (parent.hasClass(classPrefix + '-iconLeft')) {
  363. // Previous month
  364. that.s.display.setUTCMonth(that.s.display.getUTCMonth() - 1);
  365. that._setTitle();
  366. that._setCalander();
  367. that.dom.input.focus();
  368. } else if (parent.hasClass(classPrefix + '-iconRight')) {
  369. // Next month
  370. that._correctMonth(that.s.display, that.s.display.getUTCMonth() + 1);
  371. that._setTitle();
  372. that._setCalander();
  373. that.dom.input.focus();
  374. } else if (button.parents('.' + classPrefix + '-time').length) {
  375. var val = button.data('value');
  376. var unit = button.data('unit');
  377. if (unit === 'minutes') {
  378. if (parent.hasClass('disabled') && parent.hasClass('range')) {
  379. that.s.minutesRange = val;
  380. that._setTime();
  381. return;
  382. } else {
  383. that.s.minutesRange = null;
  384. }
  385. }
  386. if (unit === 'seconds') {
  387. if (parent.hasClass('disabled') && parent.hasClass('range')) {
  388. that.s.secondsRange = val;
  389. that._setTime();
  390. return;
  391. } else {
  392. that.s.secondsRange = null;
  393. }
  394. }
  395. // Specific to hours for 12h clock
  396. if (val === 'am') {
  397. if (d.getUTCHours() >= 12) {
  398. val = d.getUTCHours() - 12;
  399. } else {
  400. return;
  401. }
  402. } else if (val === 'pm') {
  403. if (d.getUTCHours() < 12) {
  404. val = d.getUTCHours() + 12;
  405. } else {
  406. return;
  407. }
  408. }
  409. var set = unit === 'hours' ?
  410. 'setUTCHours' :
  411. unit === 'minutes' ?
  412. 'setUTCMinutes' :
  413. 'setSeconds';
  414. d[set](val);
  415. that._setTime();
  416. that._writeOutput(true);
  417. onChange();
  418. } else {
  419. // Calendar click
  420. if (!d) {
  421. d = that._dateToUtc(new Date());
  422. }
  423. // Can't be certain that the current day will exist in
  424. // the new month, and likewise don't know that the
  425. // new day will exist in the old month, But 1 always
  426. // does, so we can change the month without worry of a
  427. // recalculation being done automatically by `Date`
  428. d.setUTCDate(1);
  429. d.setUTCFullYear(button.data('year'));
  430. d.setUTCMonth(button.data('month'));
  431. d.setUTCDate(button.data('day'));
  432. that._writeOutput(true);
  433. // Don't hide if there is a time picker, since we want to
  434. // be able to select a time as well.
  435. if (!that.s.parts.time) {
  436. // This is annoying but IE has some kind of async
  437. // behaviour with focus and the focus from the above
  438. // write would occur after this hide - resulting in the
  439. // calendar opening immediately
  440. setTimeout(function () {
  441. that._hide();
  442. }, 10);
  443. } else {
  444. that._setCalander();
  445. }
  446. onChange();
  447. }
  448. } else {
  449. // Click anywhere else in the widget - return focus to the
  450. // input element
  451. that.dom.input.focus();
  452. }
  453. });
  454. },
  455. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  456. * Private
  457. */
  458. /**
  459. * Compare the date part only of two dates - this is made super easy by the
  460. * toDateString method!
  461. *
  462. * @param {Date} a Date 1
  463. * @param {Date} b Date 2
  464. * @private
  465. */
  466. _compareDates: function (a, b) {
  467. // Can't use toDateString as that converts to local time
  468. return this._dateToUtcString(a) === this._dateToUtcString(b);
  469. },
  470. /**
  471. * When changing month, take account of the fact that some months don't have
  472. * the same number of days. For example going from January to February you
  473. * can have the 31st of Jan selected and just add a month since the date
  474. * would still be 31, and thus drop you into March.
  475. *
  476. * @param {Date} date Date - will be modified
  477. * @param {integer} month Month to set
  478. * @private
  479. */
  480. _correctMonth: function (date, month) {
  481. var days = this._daysInMonth(date.getUTCFullYear(), month);
  482. var correctDays = date.getUTCDate() > days;
  483. date.setUTCMonth(month);
  484. if (correctDays) {
  485. date.setUTCDate(days);
  486. date.setUTCMonth(month);
  487. }
  488. },
  489. /**
  490. * Get the number of days in a method. Based on
  491. * http://stackoverflow.com/a/4881951 by Matti Virkkunen
  492. *
  493. * @param {integer} year Year
  494. * @param {integer} month Month (starting at 0)
  495. * @private
  496. */
  497. _daysInMonth: function (year, month) {
  498. //
  499. var isLeap = ((year % 4) === 0 && ((year % 100) !== 0 || (year % 400) === 0));
  500. var months = [31, (isLeap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  501. return months[month];
  502. },
  503. /**
  504. * Create a new date object which has the UTC values set to the local time.
  505. * This allows the local time to be used directly for the library which
  506. * always bases its calculations and display on UTC.
  507. *
  508. * @param {Date} s Date to "convert"
  509. * @return {Date} Shifted date
  510. */
  511. _dateToUtc: function (s) {
  512. return new Date(Date.UTC(
  513. s.getFullYear(), s.getMonth(), s.getDate(),
  514. s.getHours(), s.getMinutes(), s.getSeconds()
  515. ));
  516. },
  517. /**
  518. * Create a UTC ISO8601 date part from a date object
  519. *
  520. * @param {Date} d Date to "convert"
  521. * @return {string} ISO formatted date
  522. */
  523. _dateToUtcString: function (d) {
  524. return d.getUTCFullYear() + '-' +
  525. this._pad(d.getUTCMonth() + 1) + '-' +
  526. this._pad(d.getUTCDate());
  527. },
  528. /**
  529. * Hide the control and remove events related to its display
  530. *
  531. * @private
  532. */
  533. _hide: function (destroy) {
  534. if (!destroy && this.dom.input.attr('type') === 'hidden') {
  535. return;
  536. }
  537. var namespace = this.s.namespace;
  538. this.dom.container.detach();
  539. $(window).off('.' + namespace);
  540. $(document).off('keydown.' + namespace);
  541. $('div.dataTables_scrollBody').off('scroll.' + namespace);
  542. $('div.DTE_Body_Content').off('scroll.' + namespace);
  543. $('body').off('click.' + namespace);
  544. },
  545. /**
  546. * Convert a 24 hour value to a 12 hour value
  547. *
  548. * @param {integer} val 24 hour value
  549. * @return {integer} 12 hour value
  550. * @private
  551. */
  552. _hours24To12: function (val) {
  553. return val === 0 ?
  554. 12 :
  555. val > 12 ?
  556. val - 12 :
  557. val;
  558. },
  559. /**
  560. * Generate the HTML for a single day in the calendar - this is basically
  561. * and HTML cell with a button that has data attributes so we know what was
  562. * clicked on (if it is clicked on) and a bunch of classes for styling.
  563. *
  564. * @param {object} day Day object from the `_htmlMonth` method
  565. * @return {string} HTML cell
  566. */
  567. _htmlDay: function (day) {
  568. if (day.empty) {
  569. return '<td class="empty"></td>';
  570. }
  571. var classes = ['selectable'];
  572. var classPrefix = this.c.classPrefix;
  573. if (day.disabled) {
  574. classes.push('disabled');
  575. }
  576. if (day.today) {
  577. classes.push('now');
  578. }
  579. if (day.selected) {
  580. classes.push('selected');
  581. }
  582. return '<td data-day="' + day.day + '" class="' + classes.join(' ') + '">' +
  583. '<button class="' + classPrefix + '-button ' + classPrefix + '-day" type="button" ' + 'data-year="' + day.year + '" data-month="' + day.month + '" data-day="' + day.day + '">' +
  584. '<span>' + day.day + '</span>' +
  585. '</button>' +
  586. '</td>';
  587. },
  588. /**
  589. * Create the HTML for a month to be displayed in the calendar table.
  590. *
  591. * Based upon the logic used in Pikaday - MIT licensed
  592. * Copyright (c) 2014 David Bushell
  593. * https://github.com/dbushell/Pikaday
  594. *
  595. * @param {integer} year Year
  596. * @param {integer} month Month (starting at 0)
  597. * @return {string} Calendar month HTML
  598. * @private
  599. */
  600. _htmlMonth: function (year, month) {
  601. var now = this._dateToUtc(new Date()),
  602. days = this._daysInMonth(year, month),
  603. before = new Date(Date.UTC(year, month, 1)).getUTCDay(),
  604. data = [],
  605. row = [];
  606. if (this.c.firstDay > 0) {
  607. before -= this.c.firstDay;
  608. if (before < 0) {
  609. before += 7;
  610. }
  611. }
  612. var cells = days + before,
  613. after = cells;
  614. while (after > 7) {
  615. after -= 7;
  616. }
  617. cells += 7 - after;
  618. var minDate = this.c.minDate;
  619. var maxDate = this.c.maxDate;
  620. if (minDate) {
  621. minDate.setUTCHours(0);
  622. minDate.setUTCMinutes(0);
  623. minDate.setSeconds(0);
  624. }
  625. if (maxDate) {
  626. maxDate.setUTCHours(23);
  627. maxDate.setUTCMinutes(59);
  628. maxDate.setSeconds(59);
  629. }
  630. for (var i = 0, r = 0; i < cells; i++) {
  631. var day = new Date(Date.UTC(year, month, 1 + (i - before))),
  632. selected = this.s.d ? this._compareDates(day, this.s.d) : false,
  633. today = this._compareDates(day, now),
  634. empty = i < before || i >= (days + before),
  635. disabled = (minDate && day < minDate) ||
  636. (maxDate && day > maxDate);
  637. var disableDays = this.c.disableDays;
  638. if (Array.isArray(disableDays) && $.inArray(day.getUTCDay(), disableDays) !== -1) {
  639. disabled = true;
  640. } else if (typeof disableDays === 'function' && disableDays(day) === true) {
  641. disabled = true;
  642. }
  643. var dayConfig = {
  644. day: 1 + (i - before),
  645. month: month,
  646. year: year,
  647. selected: selected,
  648. today: today,
  649. disabled: disabled,
  650. empty: empty
  651. };
  652. row.push(this._htmlDay(dayConfig));
  653. if (++r === 7) {
  654. if (this.c.showWeekNumber) {
  655. row.unshift(this._htmlWeekOfYear(i - before, month, year));
  656. }
  657. data.push('<tr>' + row.join('') + '</tr>');
  658. row = [];
  659. r = 0;
  660. }
  661. }
  662. var classPrefix = this.c.classPrefix;
  663. var className = classPrefix + '-table';
  664. if (this.c.showWeekNumber) {
  665. className += ' weekNumber';
  666. }
  667. // Show / hide month icons based on min/max
  668. if (minDate) {
  669. var underMin = minDate >= new Date(Date.UTC(year, month, 1, 0, 0, 0));
  670. this.dom.title.find('div.' + classPrefix + '-iconLeft')
  671. .css('display', underMin ? 'none' : 'block');
  672. }
  673. if (maxDate) {
  674. var overMax = maxDate < new Date(Date.UTC(year, month + 1, 1, 0, 0, 0));
  675. this.dom.title.find('div.' + classPrefix + '-iconRight')
  676. .css('display', overMax ? 'none' : 'block');
  677. }
  678. return '<table class="' + className + '">' +
  679. '<thead>' +
  680. this._htmlMonthHead() +
  681. '</thead>' +
  682. '<tbody>' +
  683. data.join('') +
  684. '</tbody>' +
  685. '</table>';
  686. },
  687. /**
  688. * Create the calendar table's header (week days)
  689. *
  690. * @return {string} HTML cells for the row
  691. * @private
  692. */
  693. _htmlMonthHead: function () {
  694. var a = [];
  695. var firstDay = this.c.firstDay;
  696. var i18n = this.c.i18n;
  697. // Take account of the first day shift
  698. var dayName = function (day) {
  699. day += firstDay;
  700. while (day >= 7) {
  701. day -= 7;
  702. }
  703. return i18n.weekdays[day];
  704. };
  705. // Empty cell in the header
  706. if (this.c.showWeekNumber) {
  707. a.push('<th></th>');
  708. }
  709. for (var i = 0; i < 7; i++) {
  710. a.push('<th>' + dayName(i) + '</th>');
  711. }
  712. return a.join('');
  713. },
  714. /**
  715. * Create a cell that contains week of the year - ISO8601
  716. *
  717. * Based on https://stackoverflow.com/questions/6117814/ and
  718. * http://techblog.procurios.nl/k/n618/news/view/33796/14863/
  719. *
  720. * @param {integer} d Day of month
  721. * @param {integer} m Month of year (zero index)
  722. * @param {integer} y Year
  723. * @return {string}
  724. * @private
  725. */
  726. _htmlWeekOfYear: function (d, m, y) {
  727. var date = new Date(y, m, d, 0, 0, 0, 0);
  728. // First week of the year always has 4th January in it
  729. date.setDate(date.getDate() + 4 - (date.getDay() || 7));
  730. var oneJan = new Date(y, 0, 1);
  731. var weekNum = Math.ceil((((date - oneJan) / 86400000) + 1) / 7);
  732. return '<td class="' + this.c.classPrefix + '-week">' + weekNum + '</td>';
  733. },
  734. /**
  735. * Create option elements from a range in an array
  736. *
  737. * @param {string} selector Class name unique to the select element to use
  738. * @param {array} values Array of values
  739. * @param {array} [labels] Array of labels. If given must be the same
  740. * length as the values parameter.
  741. * @private
  742. */
  743. _options: function (selector, values, labels) {
  744. if (!labels) {
  745. labels = values;
  746. }
  747. var select = this.dom.container.find('select.' + this.c.classPrefix + '-' + selector);
  748. select.empty();
  749. for (var i = 0, ien = values.length; i < ien; i++) {
  750. select.append('<option value="' + values[i] + '">' + labels[i] + '</option>');
  751. }
  752. },
  753. /**
  754. * Set an option and update the option's span pair (since the select element
  755. * has opacity 0 for styling)
  756. *
  757. * @param {string} selector Class name unique to the select element to use
  758. * @param {*} val Value to set
  759. * @private
  760. */
  761. _optionSet: function (selector, val) {
  762. var select = this.dom.container.find('select.' + this.c.classPrefix + '-' + selector);
  763. var span = select.parent().children('span');
  764. select.val(val);
  765. var selected = select.find('option:selected');
  766. span.html(selected.length !== 0 ?
  767. selected.text() :
  768. this.c.i18n.unknown
  769. );
  770. },
  771. /**
  772. * Create time options list.
  773. *
  774. * @param {string} unit Time unit - hours, minutes or seconds
  775. * @param {integer} count Count range - 12, 24 or 60
  776. * @param {integer} val Existing value for this unit
  777. * @param {integer[]} allowed Values allow for selection
  778. * @param {integer} range Override range
  779. * @private
  780. */
  781. _optionsTime: function (unit, count, val, allowed, range) {
  782. var classPrefix = this.c.classPrefix;
  783. var container = this.dom.container.find('div.' + classPrefix + '-' + unit);
  784. var i, j;
  785. var render = count === 12 ?
  786. function (i) {
  787. return i;
  788. } :
  789. this._pad;
  790. var classPrefix = this.c.classPrefix;
  791. var className = classPrefix + '-table';
  792. var i18n = this.c.i18n;
  793. if (!container.length) {
  794. return;
  795. }
  796. var a = '';
  797. var span = 10;
  798. var button = function (value, label, className) {
  799. // Shift the value for PM
  800. if (count === 12 && typeof value === 'number') {
  801. if (val >= 12) {
  802. value += 12;
  803. }
  804. if (value == 12) {
  805. value = 0;
  806. } else if (value == 24) {
  807. value = 12;
  808. }
  809. }
  810. var selected = val === value || (value === 'am' && val < 12) || (value === 'pm' && val >= 12) ?
  811. 'selected' :
  812. '';
  813. if (allowed && $.inArray(value, allowed) === -1) {
  814. selected += ' disabled';
  815. }
  816. if (className) {
  817. selected += ' ' + className;
  818. }
  819. return '<td class="selectable ' + selected + '">' +
  820. '<button class="' + classPrefix + '-button ' + classPrefix + '-day" type="button" data-unit="' + unit + '" data-value="' + value + '">' +
  821. '<span>' + label + '</span>' +
  822. '</button>' +
  823. '</td>';
  824. };
  825. if (count === 12) {
  826. // Hours with AM/PM
  827. a += '<tr>';
  828. for (i = 1; i <= 6; i++) {
  829. a += button(i, render(i));
  830. }
  831. a += button('am', i18n.amPm[0]);
  832. a += '</tr>';
  833. a += '<tr>';
  834. for (i = 7; i <= 12; i++) {
  835. a += button(i, render(i));
  836. }
  837. a += button('pm', i18n.amPm[1]);
  838. a += '</tr>';
  839. span = 7;
  840. } else if (count === 24) {
  841. // Hours - 24
  842. var c = 0;
  843. for (j = 0; j < 4; j++) {
  844. a += '<tr>';
  845. for (i = 0; i < 6; i++) {
  846. a += button(c, render(c));
  847. c++;
  848. }
  849. a += '</tr>';
  850. }
  851. span = 6;
  852. } else {
  853. // Minutes and seconds
  854. a += '<tr>';
  855. for (j = 0; j < 60; j += 10) {
  856. a += button(j, render(j), 'range');
  857. }
  858. a += '</tr>';
  859. // Slight hack to allow for the different number of columns
  860. a += '</tbody></thead><table class="' + className + ' ' + className + '-nospace"><tbody>';
  861. var start = range !== null ?
  862. range :
  863. Math.floor(val / 10) * 10;
  864. a += '<tr>';
  865. for (j = start + 1; j < start + 10; j++) {
  866. a += button(j, render(j));
  867. }
  868. a += '</tr>';
  869. span = 6;
  870. }
  871. container
  872. .empty()
  873. .append(
  874. '<table class="' + className + '">' +
  875. '<thead><tr><th colspan="' + span + '">' +
  876. i18n[unit] +
  877. '</th></tr></thead>' +
  878. '<tbody>' +
  879. a +
  880. '</tbody>' +
  881. '</table>'
  882. );
  883. },
  884. /**
  885. * Create the options for the month and year
  886. *
  887. * @param {integer} year Year
  888. * @param {integer} month Month (starting at 0)
  889. * @private
  890. */
  891. _optionsTitle: function () {
  892. var i18n = this.c.i18n;
  893. var min = this.c.minDate;
  894. var max = this.c.maxDate;
  895. var minYear = min ? min.getFullYear() : null;
  896. var maxYear = max ? max.getFullYear() : null;
  897. var i = minYear !== null ? minYear : new Date().getFullYear() - this.c.yearRange;
  898. var j = maxYear !== null ? maxYear : new Date().getFullYear() + this.c.yearRange;
  899. this._options('month', this._range(0, 11), i18n.months);
  900. this._options('year', this._range(i, j));
  901. },
  902. /**
  903. * Simple two digit pad
  904. *
  905. * @param {integer} i Value that might need padding
  906. * @return {string|integer} Padded value
  907. * @private
  908. */
  909. _pad: function (i) {
  910. return i < 10 ? '0' + i : i;
  911. },
  912. /**
  913. * Position the calendar to look attached to the input element
  914. * @private
  915. */
  916. _position: function () {
  917. var offset = this.c.attachTo === 'input' ? this.dom.input.position() : this.dom.input.offset();
  918. var container = this.dom.container;
  919. var inputHeight = this.dom.input.outerHeight();
  920. if (container.hasClass('inline')) {
  921. container.insertAfter(this.dom.input);
  922. return;
  923. }
  924. if (this.s.parts.date && this.s.parts.time && $(window).width() > 550) {
  925. container.addClass('horizontal');
  926. } else {
  927. container.removeClass('horizontal');
  928. }
  929. if (this.c.attachTo === 'input') {
  930. container
  931. .css({
  932. top: offset.top + inputHeight,
  933. left: offset.left
  934. })
  935. .insertAfter(this.dom.input);
  936. } else {
  937. container
  938. .css({
  939. top: offset.top + inputHeight,
  940. left: offset.left
  941. })
  942. .appendTo('body');
  943. }
  944. var calHeight = container.outerHeight();
  945. var calWidth = container.outerWidth();
  946. var scrollTop = $(window).scrollTop();
  947. // Correct to the bottom
  948. if (offset.top + inputHeight + calHeight - scrollTop > $(window).height()) {
  949. var newTop = offset.top - calHeight;
  950. container.css('top', newTop < 0 ? 0 : newTop);
  951. }
  952. // Correct to the right
  953. if (calWidth + offset.left > $(window).width()) {
  954. var newLeft = $(window).width() - calWidth;
  955. // Account for elements which are inside a position absolute element
  956. if (this.c.attachTo === 'input') {
  957. newLeft -= $(container).offsetParent().offset().left;
  958. }
  959. container.css('left', newLeft < 0 ? 0 : newLeft);
  960. }
  961. },
  962. /**
  963. * Create a simple array with a range of values
  964. *
  965. * @param {integer} start Start value (inclusive)
  966. * @param {integer} end End value (inclusive)
  967. * @param {integer} [inc=1] Increment value
  968. * @return {array} Created array
  969. * @private
  970. */
  971. _range: function (start, end, inc) {
  972. var a = [];
  973. if (!inc) {
  974. inc = 1;
  975. }
  976. for (var i = start; i <= end; i += inc) {
  977. a.push(i);
  978. }
  979. return a;
  980. },
  981. /**
  982. * Redraw the calendar based on the display date - this is a destructive
  983. * operation
  984. *
  985. * @private
  986. */
  987. _setCalander: function () {
  988. if (this.s.display) {
  989. this.dom.calendar
  990. .empty()
  991. .append(this._htmlMonth(
  992. this.s.display.getUTCFullYear(),
  993. this.s.display.getUTCMonth()
  994. ));
  995. }
  996. },
  997. /**
  998. * Set the month and year for the calendar based on the current display date
  999. *
  1000. * @private
  1001. */
  1002. _setTitle: function () {
  1003. this._optionSet('month', this.s.display.getUTCMonth());
  1004. this._optionSet('year', this.s.display.getUTCFullYear());
  1005. },
  1006. /**
  1007. * Set the time based on the current value of the widget
  1008. *
  1009. * @private
  1010. */
  1011. _setTime: function () {
  1012. var that = this;
  1013. var d = this.s.d;
  1014. var hours = d ? d.getUTCHours() : 0;
  1015. var allowed = function (prop) { // Backwards compt with `Increment` option
  1016. return that.c[prop + 'Available'] ?
  1017. that.c[prop + 'Available'] :
  1018. that._range(0, 59, that.c[prop + 'Increment']);
  1019. };
  1020. this._optionsTime('hours', this.s.parts.hours12 ? 12 : 24, hours, this.c.hoursAvailable);
  1021. this._optionsTime('minutes', 60, d ? d.getUTCMinutes() : 0, allowed('minutes'), this.s.minutesRange);
  1022. this._optionsTime('seconds', 60, d ? d.getSeconds() : 0, allowed('seconds'), this.s.secondsRange);
  1023. },
  1024. /**
  1025. * Show the widget and add events to the document required only while it
  1026. * is displayed
  1027. *
  1028. * @private
  1029. */
  1030. _show: function () {
  1031. var that = this;
  1032. var namespace = this.s.namespace;
  1033. this._position();
  1034. // Need to reposition on scroll
  1035. $(window).on('scroll.' + namespace + ' resize.' + namespace, function () {
  1036. that._hide();
  1037. });
  1038. $('div.DTE_Body_Content').on('scroll.' + namespace, function () {
  1039. that._hide();
  1040. });
  1041. $('div.dataTables_scrollBody').on('scroll.' + namespace, function () {
  1042. that._hide();
  1043. });
  1044. var offsetParent = this.dom.input[0].offsetParent;
  1045. if (offsetParent !== document.body) {
  1046. $(offsetParent).on('scroll.' + namespace, function () {
  1047. that._hide();
  1048. });
  1049. }
  1050. // On tab focus will move to a different field (no keyboard navigation
  1051. // in the date picker - this might need to be changed).
  1052. $(document).on('keydown.' + namespace, function (e) {
  1053. if (
  1054. e.keyCode === 9 || // tab
  1055. e.keyCode === 27 || // esc
  1056. e.keyCode === 13 // return
  1057. ) {
  1058. that._hide();
  1059. }
  1060. });
  1061. // Hide if clicking outside of the widget - but in a different click
  1062. // event from the one that was used to trigger the show (bubble and
  1063. // inline)
  1064. setTimeout(function () {
  1065. $('body').on('click.' + namespace, function (e) {
  1066. var parents = $(e.target).parents();
  1067. if (!parents.filter(that.dom.container).length && e.target !== that.dom.input[0]) {
  1068. that._hide();
  1069. }
  1070. });
  1071. }, 10);
  1072. },
  1073. /**
  1074. * Write the formatted string to the input element this control is attached
  1075. * to
  1076. *
  1077. * @private
  1078. */
  1079. _writeOutput: function (focus) {
  1080. var date = this.s.d;
  1081. // Use moment or dayjs if possible - otherwise it must be ISO8601 (or the
  1082. // constructor would have thrown an error)
  1083. var out = dateLib ?
  1084. dateLib.utc(date, undefined$1, this.c.locale, this.c.strict).format(this.c.format) :
  1085. date.getUTCFullYear() + '-' +
  1086. this._pad(date.getUTCMonth() + 1) + '-' +
  1087. this._pad(date.getUTCDate());
  1088. this.dom.input
  1089. .val(out)
  1090. .trigger('change', {write: date});
  1091. if (this.dom.input.attr('type') === 'hidden') {
  1092. this.val(out, false);
  1093. }
  1094. if (focus) {
  1095. this.dom.input.focus();
  1096. }
  1097. }
  1098. });
  1099. /**
  1100. * Use a specificmoment compatible date library
  1101. */
  1102. DateTime.use = function (lib) {
  1103. dateLib = lib;
  1104. };
  1105. /**
  1106. * For generating unique namespaces
  1107. *
  1108. * @type {Number}
  1109. * @private
  1110. */
  1111. DateTime._instance = 0;
  1112. /**
  1113. * Defaults for the date time picker
  1114. *
  1115. * @type {Object}
  1116. */
  1117. DateTime.defaults = {
  1118. attachTo: 'body',
  1119. // Not documented - could be an internal property
  1120. classPrefix: 'dt-datetime',
  1121. // function or array of ints
  1122. disableDays: null,
  1123. // first day of the week (0: Sunday, 1: Monday, etc)
  1124. firstDay: 1,
  1125. format: 'YYYY-MM-DD',
  1126. hoursAvailable: null,
  1127. i18n: {
  1128. previous: 'Previous',
  1129. next: 'Next',
  1130. months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
  1131. weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  1132. amPm: ['am', 'pm'],
  1133. hours: 'Hour',
  1134. minutes: 'Minute',
  1135. seconds: 'Second',
  1136. unknown: '-'
  1137. },
  1138. maxDate: null,
  1139. minDate: null,
  1140. minutesAvailable: null,
  1141. minutesIncrement: 1, // deprecated
  1142. strict: true,
  1143. locale: 'en',
  1144. onChange: function () {
  1145. },
  1146. secondsAvailable: null,
  1147. secondsIncrement: 1, // deprecated
  1148. // show the ISO week number at the head of the row
  1149. showWeekNumber: false,
  1150. // overruled by max / min date
  1151. yearRange: 25
  1152. };
  1153. DateTime.version = '1.0.1';
  1154. // Global export - if no conflicts
  1155. if (!window.DateTime) {
  1156. window.DateTime = DateTime;
  1157. }
  1158. // Make available via jQuery
  1159. $.fn.dtDateTime = function (options) {
  1160. return this.each(function () {
  1161. new DateTime(this, options);
  1162. });
  1163. };
  1164. // Attach to DataTables if present
  1165. if ($.fn.dataTable) {
  1166. $.fn.dataTable.DateTime = DateTime;
  1167. $.fn.DataTable.DateTime = DateTime;
  1168. }
  1169. return DateTime;
  1170. }));
  1171. var $;
  1172. var DataTable;
  1173. var moment = window.moment;
  1174. /**
  1175. * Sets the value of jQuery for use in the file
  1176. * @param jq the instance of jQuery to be set
  1177. */
  1178. function setJQuery(jq) {
  1179. $ = jq;
  1180. DataTable = jq.fn.dataTable;
  1181. }
  1182. /**
  1183. * The Criteria class is used within SearchBuilder to represent a search criteria
  1184. */
  1185. var Criteria = /** @class */ (function () {
  1186. function Criteria(table, opts, topGroup, index, depth) {
  1187. var _this = this;
  1188. if (index === void 0) {
  1189. index = 0;
  1190. }
  1191. if (depth === void 0) {
  1192. depth = 1;
  1193. }
  1194. // Check that the required version of DataTables is included
  1195. if (!DataTable || !DataTable.versionCheck || !DataTable.versionCheck('1.10.0')) {
  1196. throw new Error('SearchPane requires DataTables 1.10 or newer');
  1197. }
  1198. this.classes = $.extend(true, {}, Criteria.classes);
  1199. // Get options from user and any extra conditions/column types defined by plug-ins
  1200. this.c = $.extend(true, {}, Criteria.defaults, $.fn.dataTable.ext.searchBuilder, opts);
  1201. var i18n = this.c.i18n;
  1202. this.s = {
  1203. condition: undefined,
  1204. conditions: {},
  1205. data: undefined,
  1206. dataIdx: -1,
  1207. dataPoints: [],
  1208. depth: depth,
  1209. dt: table,
  1210. filled: false,
  1211. index: index,
  1212. momentFormat: false,
  1213. topGroup: topGroup,
  1214. type: '',
  1215. value: []
  1216. };
  1217. this.dom = {
  1218. buttons: $('<div/>')
  1219. .addClass(this.classes.buttonContainer),
  1220. condition: $('<select disabled/>')
  1221. .addClass(this.classes.condition)
  1222. .addClass(this.classes.dropDown)
  1223. .addClass(this.classes.italic)
  1224. .attr('autocomplete', 'hacking'),
  1225. conditionTitle: $('<option value="" disabled selected hidden/>')
  1226. .text(this.s.dt.i18n('searchBuilder.condition', i18n.condition)),
  1227. container: $('<div/>')
  1228. .addClass(this.classes.container),
  1229. data: $('<select/>')
  1230. .addClass(this.classes.data)
  1231. .addClass(this.classes.dropDown)
  1232. .addClass(this.classes.italic),
  1233. dataTitle: $('<option value="" disabled selected hidden/>')
  1234. .text(this.s.dt.i18n('searchBuilder.data', i18n.data)),
  1235. defaultValue: $('<select disabled/>')
  1236. .addClass(this.classes.value)
  1237. .addClass(this.classes.dropDown),
  1238. "delete": $('<button>&times</button>')
  1239. .addClass(this.classes["delete"])
  1240. .addClass(this.classes.button)
  1241. .attr('title', this.s.dt.i18n('searchBuilder.deleteTitle', i18n.deleteTitle))
  1242. .attr('type', 'button'),
  1243. left: $('<button>\<</button>')
  1244. .addClass(this.classes.left)
  1245. .addClass(this.classes.button)
  1246. .attr('title', this.s.dt.i18n('searchBuilder.leftTitle', i18n.leftTitle))
  1247. .attr('type', 'button'),
  1248. right: $('<button>\></button>')
  1249. .addClass(this.classes.right)
  1250. .addClass(this.classes.button)
  1251. .attr('title', this.s.dt.i18n('searchBuilder.rightTitle', i18n.rightTitle))
  1252. .attr('type', 'button'),
  1253. value: [
  1254. $('<select disabled/>').addClass(this.classes.value).addClass(this.classes.dropDown).addClass(this.classes.italic)
  1255. ],
  1256. valueTitle: $('<option value="--valueTitle--" selected/>').text(this.s.dt.i18n('searchBuilder.value', i18n.value))
  1257. };
  1258. // If the greyscale option is selected then add the class to add the grey colour to SearchBuilder
  1259. if (this.c.greyscale) {
  1260. $(this.dom.data).addClass(this.classes.greyscale);
  1261. $(this.dom.condition).addClass(this.classes.greyscale);
  1262. $(this.dom.defaultValue).addClass(this.classes.greyscale);
  1263. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  1264. var val = _a[_i];
  1265. $(val).addClass(this.classes.greyscale);
  1266. }
  1267. }
  1268. // For responsive design, adjust the criterias properties on the following events
  1269. this.s.dt.on('draw.dtsp', function () {
  1270. _this._adjustCriteria();
  1271. });
  1272. this.s.dt.on('buttons-action', function () {
  1273. _this._adjustCriteria();
  1274. });
  1275. $(window).on('resize.dtsp', DataTable.util.throttle(function () {
  1276. _this._adjustCriteria();
  1277. }));
  1278. this._buildCriteria();
  1279. return this;
  1280. }
  1281. /**
  1282. * Adds the left button to the criteria
  1283. */
  1284. Criteria.prototype.updateArrows = function (hasSiblings, redraw) {
  1285. if (hasSiblings === void 0) {
  1286. hasSiblings = false;
  1287. }
  1288. if (redraw === void 0) {
  1289. redraw = true;
  1290. }
  1291. // Empty the container and append all of the elements in the correct order
  1292. $(this.dom.container)
  1293. .empty()
  1294. .append(this.dom.data)
  1295. .append(this.dom.condition)
  1296. .append(this.dom.value[0]);
  1297. // Trigger the inserted events for the value elements as they are inserted
  1298. $(this.dom.value[0]).trigger('dtsb-inserted');
  1299. for (var i = 1; i < this.dom.value.length; i++) {
  1300. $(this.dom.container).append(this.dom.value[i]);
  1301. $(this.dom.value[i]).trigger('dtsb-inserted');
  1302. }
  1303. // If this is a top level criteria then don't let it move left
  1304. if (this.s.depth > 1) {
  1305. $(this.dom.buttons).append(this.dom.left);
  1306. }
  1307. // If the depthLimit of the query has been hit then don't add the right button
  1308. if ((this.c.depthLimit === false || this.s.depth < this.c.depthLimit) && hasSiblings) {
  1309. $(this.dom.buttons).append(this.dom.right);
  1310. } else {
  1311. $(this.dom.right).remove();
  1312. }
  1313. $(this.dom.buttons).append(this.dom["delete"]);
  1314. $(this.dom.container).append(this.dom.buttons);
  1315. if (redraw) {
  1316. // A different combination of arrows and selectors may lead to a need for responsive to be triggered
  1317. this._adjustCriteria();
  1318. }
  1319. };
  1320. /**
  1321. * Destroys the criteria, removing listeners and container from the dom
  1322. */
  1323. Criteria.prototype.destroy = function () {
  1324. // Turn off listeners
  1325. $(this.dom.data).off('.dtsb');
  1326. $(this.dom.condition).off('.dtsb');
  1327. $(this.dom["delete"]).off('.dtsb');
  1328. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  1329. var val = _a[_i];
  1330. $(val).off('.dtsb');
  1331. }
  1332. // Remove container from the dom
  1333. $(this.dom.container).remove();
  1334. };
  1335. /**
  1336. * Passes in the data for the row and compares it against this single criteria
  1337. * @param rowData The data for the row to be compared
  1338. * @returns boolean Whether the criteria has passed
  1339. */
  1340. Criteria.prototype.search = function (rowData, rowIdx) {
  1341. var condition = this.s.conditions[this.s.condition];
  1342. if (this.s.condition !== undefined && condition !== undefined) {
  1343. // This check is in place for if a custom decimal character is in place
  1344. if (this.s.type.indexOf('num') !== -1 && this.s.dt.settings()[0].oLanguage.sDecimal !== '') {
  1345. rowData[this.s.dataIdx] = rowData[this.s.dataIdx].replace(this.s.dt.settings()[0].oLanguage.sDecimal, '.');
  1346. }
  1347. var filter = rowData[this.s.dataIdx];
  1348. // If orthogonal data is in place we need to get it's values for searching
  1349. if (this.c.orthogonal.search !== 'search') {
  1350. var settings = this.s.dt.settings()[0];
  1351. filter = settings.oApi._fnGetCellData(settings, rowIdx, this.s.dataIdx, typeof this.c.orthogonal === 'string' ?
  1352. this.c.orthogonal :
  1353. this.c.orthogonal.search);
  1354. }
  1355. if (this.s.type === 'array') {
  1356. // Make sure we are working with an array
  1357. if (!Array.isArray(filter)) {
  1358. filter = [filter];
  1359. }
  1360. filter.sort();
  1361. }
  1362. return condition.search(filter, this.s.value, this);
  1363. }
  1364. };
  1365. /**
  1366. * Gets the details required to rebuild the criteria
  1367. */
  1368. Criteria.prototype.getDetails = function () {
  1369. var value = this.s.value;
  1370. // This check is in place for if a custom decimal character is in place
  1371. if (this.s.type.indexOf('num') !== -1 && this.s.dt.settings()[0].oLanguage.sDecimal !== '') {
  1372. for (var i = 0; i < this.s.value.length; i++) {
  1373. if (this.s.value[i].indexOf('.') !== -1) {
  1374. value[i] = this.s.value[i].replace('.', this.s.dt.settings()[0].oLanguage.sDecimal);
  1375. }
  1376. }
  1377. }
  1378. return {
  1379. condition: this.s.condition,
  1380. data: this.s.data,
  1381. value: value
  1382. };
  1383. };
  1384. /**
  1385. * Getter for the node for the container of the criteria
  1386. * @returns JQuery<HTMLElement> the node for the container
  1387. */
  1388. Criteria.prototype.getNode = function () {
  1389. return this.dom.container;
  1390. };
  1391. /**
  1392. * Populates the criteria data, condition and value(s) as far as has been selected
  1393. */
  1394. Criteria.prototype.populate = function () {
  1395. this._populateData();
  1396. // If the column index has been found attempt to select a condition
  1397. if (this.s.dataIdx !== -1) {
  1398. this._populateCondition();
  1399. // If the condittion has been found attempt to select the values
  1400. if (this.s.condition !== undefined) {
  1401. this._populateValue();
  1402. }
  1403. }
  1404. };
  1405. /**
  1406. * Rebuilds the criteria based upon the details passed in
  1407. * @param loadedCriteria the details required to rebuild the criteria
  1408. */
  1409. Criteria.prototype.rebuild = function (loadedCriteria) {
  1410. // Check to see if the previously selected data exists, if so select it
  1411. var foundData = false;
  1412. var dataIdx;
  1413. this._populateData();
  1414. // If a data selection has previously been made attempt to find and select it
  1415. if (loadedCriteria.data !== undefined) {
  1416. var italic_1 = this.classes.italic;
  1417. var data_1 = this.dom.data;
  1418. $(this.dom.data).children('option').each(function () {
  1419. if ($(this).text() === loadedCriteria.data) {
  1420. $(this).attr('selected', true);
  1421. $(data_1).removeClass(italic_1);
  1422. foundData = true;
  1423. dataIdx = $(this).val();
  1424. }
  1425. });
  1426. }
  1427. // If the data has been found and selected then the condition can be populated and searched
  1428. if (foundData) {
  1429. this.s.data = loadedCriteria.data;
  1430. this.s.dataIdx = dataIdx;
  1431. $(this.dom.dataTitle).remove();
  1432. this._populateCondition();
  1433. $(this.dom.conditionTitle).remove();
  1434. var condition_1;
  1435. // Check to see if the previously selected condition exists, if so select it
  1436. $(this.dom.condition).children('option').each(function () {
  1437. if ((loadedCriteria.condition !== undefined &&
  1438. $(this).val() === loadedCriteria.condition &&
  1439. typeof loadedCriteria.condition === 'string')) {
  1440. $(this).attr('selected', true);
  1441. condition_1 = $(this).val();
  1442. }
  1443. });
  1444. this.s.condition = condition_1;
  1445. // If the condition has been found and selected then the value can be populated and searched
  1446. if (this.s.condition !== undefined) {
  1447. $(this.dom.conditionTitle).remove();
  1448. $(this.dom.condition).removeClass(this.classes.italic);
  1449. this._populateValue(loadedCriteria);
  1450. } else {
  1451. $(this.dom.conditionTitle).prependTo(this.dom.condition).attr('selected', true);
  1452. }
  1453. }
  1454. };
  1455. /**
  1456. * Sets the listeners for the criteria
  1457. */
  1458. Criteria.prototype.setListeners = function () {
  1459. var _this = this;
  1460. $(this.dom.data)
  1461. .unbind('input change')
  1462. .on('input change', function () {
  1463. $(_this.dom.dataTitle).attr('selected', false);
  1464. $(_this.dom.data).removeClass(_this.classes.italic);
  1465. _this.s.dataIdx = $(_this.dom.data).children('option:selected').val();
  1466. _this.s.data = $(_this.dom.data).children('option:selected').text();
  1467. _this.c.orthogonal = _this._getOptions().orthogonal;
  1468. // When the data is changed, the values in condition and value may also change so need to renew them
  1469. _this._clearCondition();
  1470. _this._clearValue();
  1471. _this._populateCondition();
  1472. // If this criteria was previously active in the search then remove it from the search and trigger a new search
  1473. if (_this.s.filled) {
  1474. _this.s.filled = false;
  1475. _this.s.dt.draw();
  1476. _this.setListeners();
  1477. }
  1478. _this.s.dt.state.save();
  1479. });
  1480. $(this.dom.condition)
  1481. .unbind('input change')
  1482. .on('input change', function () {
  1483. $(_this.dom.conditionTitle).attr('selected', false);
  1484. $(_this.dom.condition).removeClass(_this.classes.italic);
  1485. var condDisp = $(_this.dom.condition).children('option:selected').val();
  1486. // Find the condition that has been selected and store it internally
  1487. for (var _i = 0, _a = Object.keys(_this.s.conditions); _i < _a.length; _i++) {
  1488. var cond = _a[_i];
  1489. if (cond === condDisp) {
  1490. _this.s.condition = condDisp;
  1491. break;
  1492. }
  1493. }
  1494. // When the condition is changed, the value selector may switch between a select element and an input element
  1495. _this._clearValue();
  1496. _this._populateValue();
  1497. for (var _b = 0, _c = _this.dom.value; _b < _c.length; _b++) {
  1498. var val = _c[_b];
  1499. // If this criteria was previously active in the search then remove it from the search and trigger a new search
  1500. if (_this.s.filled && $(_this.dom.container).has(val).length !== 0) {
  1501. _this.s.filled = false;
  1502. _this.s.dt.draw();
  1503. _this.setListeners();
  1504. }
  1505. }
  1506. _this.s.dt.draw();
  1507. });
  1508. };
  1509. /**
  1510. * Adjusts the criteria to make SearchBuilder responsive
  1511. */
  1512. Criteria.prototype._adjustCriteria = function () {
  1513. // If this criteria is not present then don't bother adjusting it
  1514. if ($(document).has(this.dom.container).length === 0) {
  1515. return;
  1516. }
  1517. var valRight;
  1518. var valWidth;
  1519. var outmostval = this.dom.value[this.dom.value.length - 1];
  1520. // Calculate the width and right value of the outmost value element
  1521. if ($(this.dom.container).has(outmostval).length !== 0) {
  1522. valWidth = $(outmostval).outerWidth(true);
  1523. valRight = $(outmostval).offset().left + valWidth;
  1524. } else {
  1525. return;
  1526. }
  1527. var leftOffset = $(this.dom.left).offset();
  1528. var rightOffset = $(this.dom.right).offset();
  1529. var clearOffset = $(this.dom["delete"]).offset();
  1530. var hasLeft = $(this.dom.container).has(this.dom.left).length !== 0;
  1531. var hasRight = $(this.dom.container).has(this.dom.right).length !== 0;
  1532. var buttonsLeft = hasLeft ?
  1533. leftOffset.left :
  1534. hasRight ?
  1535. rightOffset.left :
  1536. clearOffset.left;
  1537. // Perform the responsive calculations and redraw where necessary
  1538. if (buttonsLeft - valRight < 15 ||
  1539. (hasLeft && leftOffset.top !== clearOffset.top) ||
  1540. (hasRight && rightOffset.top !== clearOffset.top)) {
  1541. $(this.dom.container).parent().addClass(this.classes.vertical);
  1542. $(this.s.topGroup).trigger('dtsb-redrawContents');
  1543. } else if (buttonsLeft -
  1544. ($(this.dom.data).offset().left +
  1545. $(this.dom.data).outerWidth(true) +
  1546. $(this.dom.condition).outerWidth(true) +
  1547. valWidth) > 15) {
  1548. $(this.dom.container).parent().removeClass(this.classes.vertical);
  1549. $(this.s.topGroup).trigger('dtsb-redrawContents');
  1550. }
  1551. };
  1552. /**
  1553. * Builds the elements of the dom together
  1554. */
  1555. Criteria.prototype._buildCriteria = function () {
  1556. // Append Titles for select elements
  1557. $(this.dom.data).append(this.dom.dataTitle);
  1558. $(this.dom.condition).append(this.dom.conditionTitle);
  1559. // Add elements to container
  1560. $(this.dom.container)
  1561. .append(this.dom.data)
  1562. .append(this.dom.condition);
  1563. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  1564. var val = _a[_i];
  1565. $(val).append(this.dom.valueTitle);
  1566. $(this.dom.container).append(val);
  1567. }
  1568. // Add buttons to container
  1569. $(this.dom.container)
  1570. .append(this.dom["delete"])
  1571. .append(this.dom.right);
  1572. this.setListeners();
  1573. };
  1574. /**
  1575. * Clears the condition select element
  1576. */
  1577. Criteria.prototype._clearCondition = function () {
  1578. $(this.dom.condition).empty();
  1579. $(this.dom.conditionTitle).attr('selected', true).attr('disabled', true);
  1580. $(this.dom.condition).prepend(this.dom.conditionTitle).prop('selectedIndex', 0);
  1581. this.s.conditions = {};
  1582. this.s.condition = undefined;
  1583. };
  1584. /**
  1585. * Clears the value elements
  1586. */
  1587. Criteria.prototype._clearValue = function () {
  1588. if (this.s.condition !== undefined) {
  1589. // Remove all of the value elements
  1590. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  1591. var val = _a[_i];
  1592. $(val).remove();
  1593. }
  1594. // Call the init function to get the value elements for this condition
  1595. this.dom.value = [].concat(this.s.conditions[this.s.condition].init(this, Criteria.updateListener));
  1596. $(this.dom.value[0]).insertAfter(this.dom.condition).trigger('dtsb-inserted');
  1597. // Insert all of the value elements
  1598. for (var i = 1; i < this.dom.value.length; i++) {
  1599. $(this.dom.value[i]).insertAfter(this.dom.value[i - 1]).trigger('dtsb-inserted');
  1600. }
  1601. } else {
  1602. // Remove all of the value elements
  1603. for (var _b = 0, _c = this.dom.value; _b < _c.length; _b++) {
  1604. var val = _c[_b];
  1605. $(val).remove();
  1606. }
  1607. // Append the default valueTitle to the default select element
  1608. $(this.dom.valueTitle)
  1609. .attr('selected', true);
  1610. $(this.dom.defaultValue)
  1611. .append(this.dom.valueTitle)
  1612. .insertAfter(this.dom.condition);
  1613. }
  1614. this.s.value = [];
  1615. };
  1616. /**
  1617. * Gets the options for the column
  1618. * @returns {object} The options for the column
  1619. */
  1620. Criteria.prototype._getOptions = function () {
  1621. var table = this.s.dt;
  1622. return $.extend(true, {}, Criteria.defaults, table.settings()[0].aoColumns[this.s.dataIdx].searchBuilder);
  1623. };
  1624. /**
  1625. * Populates the condition dropdown
  1626. */
  1627. Criteria.prototype._populateCondition = function () {
  1628. var conditionOpts = [];
  1629. var conditionsLength = Object.keys(this.s.conditions).length;
  1630. // If there are no conditions stored then we need to get them from the appropriate type
  1631. if (conditionsLength === 0) {
  1632. var column = $(this.dom.data).children('option:selected').val();
  1633. this.s.type = this.s.dt.columns().type().toArray()[column];
  1634. // If the column type is unknown, call a draw to try reading it again
  1635. if (this.s.type === null) {
  1636. this.s.dt.draw();
  1637. this.setListeners();
  1638. this.s.type = this.s.dt.columns().type().toArray()[column];
  1639. }
  1640. // Enable the condition element
  1641. $(this.dom.condition)
  1642. .attr('disabled', false)
  1643. .empty()
  1644. .append(this.dom.conditionTitle)
  1645. .addClass(this.classes.italic);
  1646. $(this.dom.conditionTitle)
  1647. .attr('selected', true);
  1648. var decimal = this.s.dt.settings()[0].oLanguage.sDecimal;
  1649. // This check is in place for if a custom decimal character is in place
  1650. if (decimal !== '' && this.s.type.indexOf(decimal) === this.s.type.length - decimal.length) {
  1651. if (this.s.type.indexOf('num-fmt') !== -1) {
  1652. this.s.type = this.s.type.replace(decimal, '');
  1653. } else if (this.s.type.indexOf('num') !== -1) {
  1654. this.s.type = this.s.type.replace(decimal, '');
  1655. }
  1656. }
  1657. // Select which conditions are going to be used based on the column type
  1658. var conditionObj = this.c.conditions[this.s.type] !== undefined ?
  1659. this.c.conditions[this.s.type] :
  1660. this.s.type.indexOf('moment') !== -1 ?
  1661. this.c.conditions.moment :
  1662. this.c.conditions.string;
  1663. // If it is a moment format then extract the date format
  1664. if (this.s.type.indexOf('moment') !== -1) {
  1665. this.s.momentFormat = this.s.type.replace(/moment\-/g, '');
  1666. }
  1667. // Add all of the conditions to the select element
  1668. for (var _i = 0, _a = Object.keys(conditionObj); _i < _a.length; _i++) {
  1669. var condition = _a[_i];
  1670. if (conditionObj[condition] !== null) {
  1671. this.s.conditions[condition] = conditionObj[condition];
  1672. var condName = conditionObj[condition].conditionName;
  1673. if (typeof condName === 'function') {
  1674. condName = condName(this.s.dt, this.c.i18n);
  1675. }
  1676. conditionOpts.push($('<option>', {
  1677. text: condName,
  1678. value: condition
  1679. })
  1680. .addClass(this.classes.option)
  1681. .addClass(this.classes.notItalic));
  1682. }
  1683. }
  1684. }
  1685. // Otherwise we can just load them in
  1686. else if (conditionsLength > 0) {
  1687. $(this.dom.condition).empty().attr('disabled', false).addClass(this.classes.italic);
  1688. for (var _b = 0, _c = Object.keys(this.s.conditions); _b < _c.length; _b++) {
  1689. var condition = _c[_b];
  1690. var condName = this.s.conditions[condition].conditionName;
  1691. if (typeof condName === 'function') {
  1692. condName = condName(this.s.dt, this.c.i18n);
  1693. }
  1694. var newOpt = $('<option>', {
  1695. text: condName,
  1696. value: condition
  1697. })
  1698. .addClass(this.classes.option)
  1699. .addClass(this.classes.notItalic);
  1700. if (this.s.condition !== undefined && this.s.condition === condName) {
  1701. $(newOpt).attr('selected', true);
  1702. $(this.dom.condition).removeClass(this.classes.italic);
  1703. }
  1704. conditionOpts.push(newOpt);
  1705. }
  1706. } else {
  1707. $(this.dom.condition)
  1708. .attr('disabled', true)
  1709. .addClass(this.classes.italic);
  1710. return;
  1711. }
  1712. for (var _d = 0, conditionOpts_1 = conditionOpts; _d < conditionOpts_1.length; _d++) {
  1713. var opt = conditionOpts_1[_d];
  1714. $(this.dom.condition).append(opt);
  1715. }
  1716. $(this.dom.condition).prop('selectedIndex', 0);
  1717. };
  1718. /**
  1719. * Populates the data select element
  1720. */
  1721. Criteria.prototype._populateData = function () {
  1722. var _this = this;
  1723. $(this.dom.data).empty().append(this.dom.dataTitle);
  1724. // If there are no datas stored then we need to get them from the table
  1725. if (this.s.dataPoints.length === 0) {
  1726. this.s.dt.columns().every(function (index) {
  1727. // Need to check that the column can be filtered on before adding it
  1728. if (_this.c.columns === true ||
  1729. (_this.s.dt.columns(_this.c.columns).indexes().toArray().indexOf(index) !== -1)) {
  1730. var found = false;
  1731. for (var _i = 0, _a = _this.s.dataPoints; _i < _a.length; _i++) {
  1732. var val = _a[_i];
  1733. if (val.index === index) {
  1734. found = true;
  1735. break;
  1736. }
  1737. }
  1738. if (!found) {
  1739. var opt = {text: _this.s.dt.settings()[0].aoColumns[index].sTitle, index: index};
  1740. _this.s.dataPoints.push(opt);
  1741. $(_this.dom.data).append($('<option>', {
  1742. text: opt.text,
  1743. value: opt.index
  1744. })
  1745. .addClass(_this.classes.option)
  1746. .addClass(_this.classes.notItalic));
  1747. }
  1748. }
  1749. });
  1750. }
  1751. // Otherwise we can just load them in
  1752. else {
  1753. var _loop_1 = function (data) {
  1754. this_1.s.dt.columns().every(function (index) {
  1755. if (_this.s.dt.settings()[0].aoColumns[index].sTitle === data.text) {
  1756. data.index = index;
  1757. }
  1758. });
  1759. var newOpt = $('<option>', {
  1760. text: data.text,
  1761. value: data.index
  1762. })
  1763. .addClass(this_1.classes.option)
  1764. .addClass(this_1.classes.notItalic);
  1765. if (this_1.s.data === data.text) {
  1766. this_1.s.dataIdx = data.index;
  1767. $(newOpt).attr('selected', true);
  1768. $(this_1.dom.data).removeClass(this_1.classes.italic);
  1769. }
  1770. $(this_1.dom.data).append(newOpt);
  1771. };
  1772. var this_1 = this;
  1773. for (var _i = 0, _a = this.s.dataPoints; _i < _a.length; _i++) {
  1774. var data = _a[_i];
  1775. _loop_1(data);
  1776. }
  1777. }
  1778. };
  1779. /**
  1780. * Populates the Value select element
  1781. * @param loadedCriteria optional, used to reload criteria from predefined filters
  1782. */
  1783. Criteria.prototype._populateValue = function (loadedCriteria) {
  1784. var _this = this;
  1785. var prevFilled = this.s.filled;
  1786. this.s.filled = false;
  1787. // Remove any previous value elements
  1788. $(this.dom.defaultValue).remove();
  1789. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  1790. var val = _a[_i];
  1791. $(val).remove();
  1792. }
  1793. var children = $(this.dom.container).children();
  1794. if (children.length > 3) {
  1795. for (var i = 2; i < children.length - 1; i++) {
  1796. $(children[i]).remove();
  1797. }
  1798. }
  1799. // Find the column with the title matching the data for the criteria and take note of the index
  1800. if (loadedCriteria !== undefined) {
  1801. this.s.dt.columns().every(function (index) {
  1802. if (_this.s.dt.settings()[0].aoColumns[index].sTitle === loadedCriteria.data) {
  1803. _this.s.dataIdx = index;
  1804. }
  1805. });
  1806. }
  1807. // Initialise the value elements based on the condition
  1808. this.dom.value = [].concat(this.s.conditions[this.s.condition].init(this, Criteria.updateListener, loadedCriteria !== undefined ? loadedCriteria.value : undefined));
  1809. if (loadedCriteria !== undefined && loadedCriteria.value !== undefined) {
  1810. this.s.value = loadedCriteria.value;
  1811. }
  1812. // Insert value elements and trigger the inserted event
  1813. $(this.dom.value[0])
  1814. .insertAfter(this.dom.condition)
  1815. .trigger('dtsb-inserted');
  1816. for (var i = 1; i < this.dom.value.length; i++) {
  1817. $(this.dom.value[i])
  1818. .insertAfter(this.dom.value[i - 1])
  1819. .trigger('dtsb-inserted');
  1820. }
  1821. // Check if the criteria can be used in a search
  1822. this.s.filled = this.s.conditions[this.s.condition].isInputValid(this.dom.value, this);
  1823. this.setListeners();
  1824. // If it can and this is different to before then trigger a draw
  1825. if (prevFilled !== this.s.filled) {
  1826. this.s.dt.draw();
  1827. this.setListeners();
  1828. }
  1829. };
  1830. Criteria.version = '1.0.0';
  1831. Criteria.classes = {
  1832. button: 'dtsb-button',
  1833. buttonContainer: 'dtsb-buttonContainer',
  1834. condition: 'dtsb-condition',
  1835. container: 'dtsb-criteria',
  1836. data: 'dtsb-data',
  1837. "delete": 'dtsb-delete',
  1838. dropDown: 'dtsb-dropDown',
  1839. greyscale: 'dtsb-greyscale',
  1840. input: 'dtsb-input',
  1841. italic: 'dtsb-italic',
  1842. joiner: 'dtsp-joiner',
  1843. left: 'dtsb-left',
  1844. notItalic: 'dtsb-notItalic',
  1845. option: 'dtsb-option',
  1846. right: 'dtsb-right',
  1847. value: 'dtsb-value',
  1848. vertical: 'dtsb-vertical'
  1849. };
  1850. /**
  1851. * Default initialisation function for select conditions
  1852. */
  1853. Criteria.initSelect = function (that, fn, preDefined, array) {
  1854. if (preDefined === void 0) {
  1855. preDefined = null;
  1856. }
  1857. if (array === void 0) {
  1858. array = false;
  1859. }
  1860. var column = $(that.dom.data).children('option:selected').val();
  1861. var indexArray = that.s.dt.rows().indexes().toArray();
  1862. var settings = that.s.dt.settings()[0];
  1863. // Declare select element to be used with all of the default classes and listeners.
  1864. var el = $('<select/>')
  1865. .addClass(Criteria.classes.value)
  1866. .addClass(Criteria.classes.dropDown)
  1867. .addClass(Criteria.classes.italic)
  1868. .append(that.dom.valueTitle)
  1869. .on('input change', function () {
  1870. $(this).removeClass(Criteria.classes.italic);
  1871. fn(that, this);
  1872. });
  1873. if (that.c.greyscale) {
  1874. $(el).addClass(Criteria.classes.greyscale);
  1875. }
  1876. var added = [];
  1877. var options = [];
  1878. // Add all of the options from the table to the select element.
  1879. // Only add one option for each possible value
  1880. for (var _i = 0, indexArray_1 = indexArray; _i < indexArray_1.length; _i++) {
  1881. var index = indexArray_1[_i];
  1882. var filter = settings.oApi._fnGetCellData(settings, index, column, typeof that.c.orthogonal === 'string' ?
  1883. that.c.orthogonal :
  1884. that.c.orthogonal.search);
  1885. var value = {
  1886. filter: typeof filter === 'string' ?
  1887. filter.replace(/[\r\n\u2028]/g, ' ') : // Need to replace certain characters to match the search values
  1888. filter,
  1889. index: index,
  1890. text: settings.oApi._fnGetCellData(settings, index, column, typeof that.c.orthogonal === 'string' ?
  1891. that.c.orthogonal :
  1892. that.c.orthogonal.display)
  1893. };
  1894. // If we are dealing with an array type, either make sure we are working with arrays, or sort them
  1895. if (that.s.type === 'array') {
  1896. value.filter = !Array.isArray(value.filter) ?
  1897. [value.filter] :
  1898. value.filter = value.filter.sort();
  1899. value.text = !Array.isArray(value.text) ?
  1900. [value.text] :
  1901. value.text = value.text.sort();
  1902. }
  1903. // Function to add an option to the select element
  1904. var addOption = function (filt, text) {
  1905. // Add text and value, stripping out any html if that is the column type
  1906. var opt = $('<option>', {
  1907. text: typeof text === 'string' ?
  1908. text.replace(/(<([^>]+)>)/ig, '') :
  1909. text,
  1910. type: Array.isArray(filt) ? 'Array' : 'String',
  1911. value: that.s.type.indexOf('html') !== -1 && filt !== null && typeof filt === 'string' ?
  1912. filt.replace(/(<([^>]+)>)/ig, '') :
  1913. filt
  1914. })
  1915. .addClass(that.classes.option)
  1916. .addClass(that.classes.notItalic);
  1917. var val = $(opt).val();
  1918. // Check that this value has not already been added
  1919. if (added.indexOf(val) === -1) {
  1920. added.push(val);
  1921. options.push(opt);
  1922. if (preDefined !== null && Array.isArray(preDefined[0])) {
  1923. preDefined[0] = preDefined[0].sort().join(',');
  1924. }
  1925. // If this value was previously selected as indicated by preDefined, then select it again
  1926. if (preDefined !== null && opt.val() === preDefined[0]) {
  1927. opt.attr('selected', true);
  1928. $(el).removeClass(Criteria.classes.italic);
  1929. }
  1930. }
  1931. };
  1932. // If this is to add the individual values within the array we need to loop over the array
  1933. if (array) {
  1934. for (var i = 0; i < value.filter.length; i++) {
  1935. addOption(value.filter[i], value.text[i]);
  1936. }
  1937. }
  1938. // Otherwise the value that is in the cell is to be added
  1939. else {
  1940. addOption(value.filter, value.text);
  1941. }
  1942. }
  1943. options.sort(function (a, b) {
  1944. if (that.s.type === 'string' || that.s.type === 'num' || that.s.type === 'html' || that.s.type === 'html-num') {
  1945. if ($(a).val() < $(b).val()) {
  1946. return -1;
  1947. } else if ($(a).val() < $(b).val()) {
  1948. return 1;
  1949. } else {
  1950. return 0;
  1951. }
  1952. } else if (that.s.type === 'num-fmt' || that.s.type === 'html-num-fmt') {
  1953. if (+$(a).val().replace(/[^0-9.]/g, '') < +$(b).val().replace(/[^0-9.]/g, '')) {
  1954. return -1;
  1955. } else if (+$(a).val().replace(/[^0-9.]/g, '') < +$(b).val().replace(/[^0-9.]/g, '')) {
  1956. return 1;
  1957. } else {
  1958. return 0;
  1959. }
  1960. }
  1961. });
  1962. for (var _a = 0, options_1 = options; _a < options_1.length; _a++) {
  1963. var opt = options_1[_a];
  1964. $(el).append(opt);
  1965. }
  1966. return el;
  1967. };
  1968. /**
  1969. * Default initialisation function for select array conditions
  1970. *
  1971. * This exists because there needs to be different select functionality for contains/without and equals/not
  1972. */
  1973. Criteria.initSelectArray = function (that, fn, preDefined) {
  1974. if (preDefined === void 0) {
  1975. preDefined = null;
  1976. }
  1977. return Criteria.initSelect(that, fn, preDefined, true);
  1978. };
  1979. /**
  1980. * Default initialisation function for input conditions
  1981. */
  1982. Criteria.initInput = function (that, fn, preDefined) {
  1983. if (preDefined === void 0) {
  1984. preDefined = null;
  1985. }
  1986. // Declare the input element
  1987. var el = $('<input/>')
  1988. .addClass(Criteria.classes.value)
  1989. .addClass(Criteria.classes.input)
  1990. .on('input', function () {
  1991. fn(that, this);
  1992. });
  1993. if (that.c.greyscale) {
  1994. $(el).addClass(Criteria.classes.greyscale);
  1995. }
  1996. // If there is a preDefined value then add it
  1997. if (preDefined !== null) {
  1998. $(el).val(preDefined[0]);
  1999. }
  2000. return el;
  2001. };
  2002. /**
  2003. * Default initialisation function for conditions requiring 2 inputs
  2004. */
  2005. Criteria.init2Input = function (that, fn, preDefined) {
  2006. if (preDefined === void 0) {
  2007. preDefined = null;
  2008. }
  2009. // Declare all of the necessary jQuery elements
  2010. var els = [
  2011. $('<input/>')
  2012. .addClass(Criteria.classes.value)
  2013. .addClass(Criteria.classes.input)
  2014. .on('input', function () {
  2015. fn(that, this);
  2016. }),
  2017. $('<span>')
  2018. .addClass(that.classes.joiner).text(that.s.dt.i18n('searchBuilder.valueJoiner', that.c.i18n.valueJoiner)),
  2019. $('<input/>')
  2020. .addClass(Criteria.classes.value)
  2021. .addClass(Criteria.classes.input)
  2022. .on('input', function () {
  2023. fn(that, this);
  2024. })
  2025. ];
  2026. if (that.c.greyscale) {
  2027. $(els[0]).addClass(Criteria.classes.greyscale);
  2028. $(els[2]).addClass(Criteria.classes.greyscale);
  2029. }
  2030. // If there is a preDefined value then add it
  2031. if (preDefined !== null) {
  2032. $(els[0]).val(preDefined[0]);
  2033. $(els[2]).val(preDefined[1]);
  2034. }
  2035. that.s.dt.off('draw');
  2036. that.s.dt.one('draw', function () {
  2037. $(that.s.topGroup).trigger('dtsb-redrawContents');
  2038. });
  2039. return els;
  2040. };
  2041. /**
  2042. * Default initialisation function for date conditions
  2043. */
  2044. Criteria.initDate = function (that, fn, preDefined) {
  2045. if (preDefined === void 0) {
  2046. preDefined = null;
  2047. }
  2048. // Declare date element using DataTables dateTime plugin
  2049. var el = $('<input/>')
  2050. .addClass(Criteria.classes.value)
  2051. .addClass(Criteria.classes.input)
  2052. .dtDateTime({
  2053. attachTo: 'input',
  2054. format: that.s.momentFormat ? that.s.momentFormat : undefined
  2055. })
  2056. .on('input change', function () {
  2057. fn(that, this);
  2058. });
  2059. if (that.c.greyscale) {
  2060. $(el).addClass(Criteria.classes.greyscale);
  2061. }
  2062. // If there is a preDefined value then add it
  2063. if (preDefined !== null) {
  2064. $(el).val(preDefined[0]);
  2065. }
  2066. return el;
  2067. };
  2068. Criteria.initNoValue = function (that) {
  2069. that.s.dt.off('draw');
  2070. that.s.dt.one('draw', function () {
  2071. $(that.s.topGroup).trigger('dtsb-redrawContents');
  2072. });
  2073. };
  2074. Criteria.init2Date = function (that, fn, preDefined) {
  2075. if (preDefined === void 0) {
  2076. preDefined = null;
  2077. }
  2078. // Declare all of the date elements that are required using DataTables dateTime plugin
  2079. var els = [
  2080. $('<input/>')
  2081. .addClass(Criteria.classes.value)
  2082. .addClass(Criteria.classes.input)
  2083. .dtDateTime({
  2084. attachTo: 'input',
  2085. format: that.s.momentFormat ? that.s.momentFormat : undefined
  2086. })
  2087. .on('input change', function () {
  2088. fn(that, this);
  2089. }),
  2090. $('<span>')
  2091. .addClass(that.classes.joiner)
  2092. .text(that.s.dt.i18n('searchBuilder.valueJoiner', that.c.i18n.valueJoiner)),
  2093. $('<input/>')
  2094. .addClass(Criteria.classes.value)
  2095. .addClass(Criteria.classes.input)
  2096. .dtDateTime({
  2097. attachTo: 'input',
  2098. format: that.s.momentFormat ? that.s.momentFormat : undefined
  2099. })
  2100. .on('input change', function () {
  2101. fn(that, this);
  2102. })
  2103. ];
  2104. if (that.c.greyscale) {
  2105. $(els[0]).addClass(Criteria.classes.greyscale);
  2106. $(els[2]).addClass(Criteria.classes.greyscale);
  2107. }
  2108. // If there are and preDefined values then add them
  2109. if (preDefined !== null && preDefined.length > 0) {
  2110. $(els[0]).val(preDefined[0]);
  2111. $(els[2]).val(preDefined[1]);
  2112. }
  2113. that.s.dt.off('draw');
  2114. that.s.dt.one('draw', function () {
  2115. $(that.s.topGroup).trigger('dtsb-redrawContents');
  2116. });
  2117. return els;
  2118. };
  2119. /**
  2120. * Default function for select elements to validate condition
  2121. */
  2122. Criteria.isInputValidSelect = function (el) {
  2123. var allFilled = true;
  2124. // Check each element to make sure that the selections are valid
  2125. for (var _i = 0, el_1 = el; _i < el_1.length; _i++) {
  2126. var element = el_1[_i];
  2127. if ($(element).children('option:selected').length === $(element).children('option').length - $(element).children('option.' + Criteria.classes.notItalic).length &&
  2128. $(element).children('option:selected').length === 1 &&
  2129. $(element).children('option:selected')[0] === $(element).children('option:hidden')[0]) {
  2130. allFilled = false;
  2131. }
  2132. }
  2133. return allFilled;
  2134. };
  2135. /**
  2136. * Default function for input and date elements to validate condition
  2137. */
  2138. Criteria.isInputValidInput = function (el) {
  2139. var allFilled = true;
  2140. // Check each element to make sure that the inputs are valid
  2141. for (var _i = 0, el_2 = el; _i < el_2.length; _i++) {
  2142. var element = el_2[_i];
  2143. if ($(element).is('input') && $(element).val().length === 0) {
  2144. allFilled = false;
  2145. }
  2146. }
  2147. return allFilled;
  2148. };
  2149. /**
  2150. * Default function for getting select conditions
  2151. */
  2152. Criteria.inputValueSelect = function (el) {
  2153. var values = [];
  2154. // Go through the select elements and push each selected option to the return array
  2155. for (var _i = 0, el_3 = el; _i < el_3.length; _i++) {
  2156. var element = el_3[_i];
  2157. if ($(element).is('select')) {
  2158. var val = $(element).children('option:selected').val();
  2159. // If the type of the option is an array we need to split it up and sort it
  2160. values.push($(element).children('option:selected').attr('type') === 'Array' ?
  2161. val.split(',').sort() :
  2162. val);
  2163. }
  2164. }
  2165. return values;
  2166. };
  2167. /**
  2168. * Default function for getting input conditions
  2169. */
  2170. Criteria.inputValueInput = function (el) {
  2171. var values = [];
  2172. // Go through the input elements and push each value to the return array
  2173. for (var _i = 0, el_4 = el; _i < el_4.length; _i++) {
  2174. var element = el_4[_i];
  2175. if ($(element).is('input')) {
  2176. values.push($(element).val());
  2177. }
  2178. }
  2179. return values;
  2180. };
  2181. /**
  2182. * Function that is run on each element as a call back when a search should be triggered
  2183. */
  2184. Criteria.updateListener = function (that, el) {
  2185. // When the value is changed the criteria is now complete so can be included in searches
  2186. // Get the condition from the map based on the key that has been selected for the condition
  2187. var condition = that.s.conditions[that.s.condition];
  2188. that.s.filled = condition.isInputValid(that.dom.value, that);
  2189. that.s.value = condition.inputValue(that.dom.value, that);
  2190. if (!Array.isArray(that.s.value)) {
  2191. that.s.value = [that.s.value];
  2192. }
  2193. for (var i = 0; i < that.s.value.length; i++) {
  2194. // If the value is an array we need to sort it
  2195. if (Array.isArray(that.s.value[i])) {
  2196. that.s.value[i].sort();
  2197. }
  2198. // Otherwise replace the decimal place character for i18n
  2199. else if (that.s.dt.settings()[0].oLanguage.sDecimal !== '') {
  2200. that.s.value[i] = that.s.value[i].replace(that.s.dt.settings()[0].oLanguage.sDecimal, '.');
  2201. }
  2202. }
  2203. // Take note of the cursor position so that we can refocus there later
  2204. var idx = null;
  2205. var cursorPos = null;
  2206. for (var i = 0; i < that.dom.value.length; i++) {
  2207. if (el === that.dom.value[i][0]) {
  2208. idx = i;
  2209. if (el.selectionStart !== undefined) {
  2210. cursorPos = el.selectionStart;
  2211. }
  2212. }
  2213. }
  2214. // Trigger a search
  2215. that.s.dt.draw();
  2216. // Refocus the element and set the correct cursor position
  2217. if (idx !== null) {
  2218. $(that.dom.value[idx]).removeClass(that.classes.italic);
  2219. $(that.dom.value[idx]).focus();
  2220. if (cursorPos !== null) {
  2221. $(that.dom.value[idx])[0].setSelectionRange(cursorPos, cursorPos);
  2222. }
  2223. }
  2224. };
  2225. // The order of the conditions will make tslint sad :(
  2226. Criteria.dateConditions = {
  2227. '=': {
  2228. conditionName: function (dt, i18n) {
  2229. return dt.i18n('searchBuilder.conditions.date.equals', i18n.conditions.date.equals);
  2230. },
  2231. init: Criteria.initDate,
  2232. inputValue: Criteria.inputValueInput,
  2233. isInputValid: Criteria.isInputValidInput,
  2234. search: function (value, comparison) {
  2235. value = value.replace(/(\/|\-|\,)/g, '-');
  2236. return value === comparison[0];
  2237. }
  2238. },
  2239. '!=': {
  2240. conditionName: function (dt, i18n) {
  2241. return dt.i18n('searchBuilder.conditions.date.not', i18n.conditions.date.not);
  2242. },
  2243. init: Criteria.initDate,
  2244. inputValue: Criteria.inputValueInput,
  2245. isInputValid: Criteria.isInputValidInput,
  2246. search: function (value, comparison) {
  2247. value = value.replace(/(\/|\-|\,)/g, '-');
  2248. return value !== comparison[0];
  2249. }
  2250. },
  2251. '<': {
  2252. conditionName: function (dt, i18n) {
  2253. return dt.i18n('searchBuilder.conditions.date.before', i18n.conditions.date.before);
  2254. },
  2255. init: Criteria.initDate,
  2256. inputValue: Criteria.inputValueInput,
  2257. isInputValid: Criteria.isInputValidInput,
  2258. search: function (value, comparison) {
  2259. value = value.replace(/(\/|\-|\,)/g, '-');
  2260. return value < comparison[0];
  2261. }
  2262. },
  2263. '>': {
  2264. conditionName: function (dt, i18n) {
  2265. return dt.i18n('searchBuilder.conditions.date.after', i18n.conditions.date.after);
  2266. },
  2267. init: Criteria.initDate,
  2268. inputValue: Criteria.inputValueInput,
  2269. isInputValid: Criteria.isInputValidInput,
  2270. search: function (value, comparison) {
  2271. value = value.replace(/(\/|\-|\,)/g, '-');
  2272. return value > comparison[0];
  2273. }
  2274. },
  2275. 'between': {
  2276. conditionName: function (dt, i18n) {
  2277. return dt.i18n('searchBuilder.conditions.date.between', i18n.conditions.date.between);
  2278. },
  2279. init: Criteria.init2Date,
  2280. inputValue: Criteria.inputValueInput,
  2281. isInputValid: Criteria.isInputValidInput,
  2282. search: function (value, comparison) {
  2283. value = value.replace(/(\/|\-|\,)/g, '-');
  2284. if (comparison[0] < comparison[1]) {
  2285. return comparison[0] <= value && value <= comparison[1];
  2286. } else {
  2287. return comparison[1] <= value && value <= comparison[0];
  2288. }
  2289. }
  2290. },
  2291. '!between': {
  2292. conditionName: function (dt, i18n) {
  2293. return dt.i18n('searchBuilder.conditions.date.notBetween', i18n.conditions.date.notBetween);
  2294. },
  2295. init: Criteria.init2Date,
  2296. inputValue: Criteria.inputValueInput,
  2297. isInputValid: Criteria.isInputValidInput,
  2298. search: function (value, comparison) {
  2299. value = value.replace(/(\/|\-|\,)/g, '-');
  2300. if (comparison[0] < comparison[1]) {
  2301. return !(comparison[0] <= value && value <= comparison[1]);
  2302. } else {
  2303. return !(comparison[1] <= value && value <= comparison[0]);
  2304. }
  2305. }
  2306. },
  2307. 'null': {
  2308. conditionName: function (dt, i18n) {
  2309. return dt.i18n('searchBuilder.conditions.date.empty', i18n.conditions.date.empty);
  2310. },
  2311. isInputValid: function () {
  2312. return true;
  2313. },
  2314. init: Criteria.initNoValue,
  2315. inputValue: function () {
  2316. },
  2317. search: function (value) {
  2318. return (value === null || value === undefined || value.length === 0);
  2319. }
  2320. },
  2321. '!null': {
  2322. conditionName: function (dt, i18n) {
  2323. return dt.i18n('searchBuilder.conditions.date.notEmpty', i18n.conditions.date.notEmpty);
  2324. },
  2325. isInputValid: function () {
  2326. return true;
  2327. },
  2328. init: Criteria.initNoValue,
  2329. inputValue: function () {
  2330. },
  2331. search: function (value) {
  2332. return !(value === null || value === undefined || value.length === 0);
  2333. }
  2334. }
  2335. };
  2336. // The order of the conditions will make tslint sad :(
  2337. Criteria.momentDateConditions = {
  2338. '=': {
  2339. conditionName: function (dt, i18n) {
  2340. return dt.i18n('searchBuilder.conditions.moment.equals', i18n.conditions.moment.equals);
  2341. },
  2342. init: Criteria.initDate,
  2343. inputValue: Criteria.inputValueInput,
  2344. isInputValid: Criteria.isInputValidInput,
  2345. search: function (value, comparison, that) {
  2346. return moment(value, that.s.momentFormat).valueOf() === moment(comparison[0], that.s.momentFormat).valueOf();
  2347. }
  2348. },
  2349. '!=': {
  2350. conditionName: function (dt, i18n) {
  2351. return dt.i18n('searchBuilder.conditions.moment.not', i18n.conditions.moment.not);
  2352. },
  2353. init: Criteria.initDate,
  2354. inputValue: Criteria.inputValueInput,
  2355. isInputValid: Criteria.isInputValidInput,
  2356. search: function (value, comparison, that) {
  2357. return moment(value, that.s.momentFormat).valueOf() !== moment(comparison[0], that.s.momentFormat).valueOf();
  2358. }
  2359. },
  2360. '<': {
  2361. conditionName: function (dt, i18n) {
  2362. return dt.i18n('searchBuilder.conditions.moment.before', i18n.conditions.moment.before);
  2363. },
  2364. init: Criteria.initDate,
  2365. inputValue: Criteria.inputValueInput,
  2366. isInputValid: Criteria.isInputValidInput,
  2367. search: function (value, comparison, that) {
  2368. return moment(value, that.s.momentFormat).valueOf() < moment(comparison[0], that.s.momentFormat).valueOf();
  2369. }
  2370. },
  2371. '>': {
  2372. conditionName: function (dt, i18n) {
  2373. return dt.i18n('searchBuilder.conditions.moment.after', i18n.conditions.moment.after);
  2374. },
  2375. init: Criteria.initDate,
  2376. inputValue: Criteria.inputValueInput,
  2377. isInputValid: Criteria.isInputValidInput,
  2378. search: function (value, comparison, that) {
  2379. return moment(value, that.s.momentFormat).valueOf() > moment(comparison[0], that.s.momentFormat).valueOf();
  2380. }
  2381. },
  2382. 'between': {
  2383. conditionName: function (dt, i18n) {
  2384. return dt.i18n('searchBuilder.conditions.moment.between', i18n.conditions.moment.between);
  2385. },
  2386. init: Criteria.init2Date,
  2387. inputValue: Criteria.inputValueInput,
  2388. isInputValid: Criteria.isInputValidInput,
  2389. search: function (value, comparison, that) {
  2390. var val = moment(value, that.s.momentFormat).valueOf();
  2391. var comp0 = moment(comparison[0], that.s.momentFormat).valueOf();
  2392. var comp1 = moment(comparison[1], that.s.momentFormat).valueOf();
  2393. if (comp0 < comp1) {
  2394. return comp0 <= val && val <= comp1;
  2395. } else {
  2396. return comp1 <= val && val <= comp0;
  2397. }
  2398. }
  2399. },
  2400. '!between': {
  2401. conditionName: function (dt, i18n) {
  2402. return dt.i18n('searchBuilder.conditions.moment.notBetween', i18n.conditions.moment.notBetween);
  2403. },
  2404. init: Criteria.init2Date,
  2405. inputValue: Criteria.inputValueInput,
  2406. isInputValid: Criteria.isInputValidInput,
  2407. search: function (value, comparison, that) {
  2408. var val = moment(value, that.s.momentFormat).valueOf();
  2409. var comp0 = moment(comparison[0], that.s.momentFormat).valueOf();
  2410. var comp1 = moment(comparison[1], that.s.momentFormat).valueOf();
  2411. if (comp0 < comp1) {
  2412. return !(+comp0 <= +val && +val <= +comp1);
  2413. } else {
  2414. return !(+comp1 <= +val && +val <= +comp0);
  2415. }
  2416. }
  2417. },
  2418. 'null': {
  2419. conditionName: function (dt, i18n) {
  2420. return dt.i18n('searchBuilder.conditions.moment.empty', i18n.conditions.moment.empty);
  2421. },
  2422. isInputValid: function () {
  2423. return true;
  2424. },
  2425. init: Criteria.initNoValue,
  2426. inputValue: function () {
  2427. },
  2428. search: function (value) {
  2429. return (value === null || value === undefined || value.length === 0);
  2430. }
  2431. },
  2432. '!null': {
  2433. conditionName: function (dt, i18n) {
  2434. return dt.i18n('searchBuilder.conditions.moment.notEmpty', i18n.conditions.moment.notEmpty);
  2435. },
  2436. isInputValid: function () {
  2437. return true;
  2438. },
  2439. init: Criteria.initNoValue,
  2440. inputValue: function () {
  2441. },
  2442. search: function (value) {
  2443. return !(value === null || value === undefined || value.length === 0);
  2444. }
  2445. }
  2446. };
  2447. // The order of the conditions will make tslint sad :(
  2448. Criteria.numConditions = {
  2449. '=': {
  2450. conditionName: function (dt, i18n) {
  2451. return dt.i18n('searchBuilder.conditions.number.equals', i18n.conditions.number.equals);
  2452. },
  2453. init: Criteria.initSelect,
  2454. inputValue: Criteria.inputValueSelect,
  2455. isInputValid: Criteria.isInputValidSelect,
  2456. search: function (value, comparison) {
  2457. return +value === +comparison[0];
  2458. }
  2459. },
  2460. '!=': {
  2461. conditionName: function (dt, i18n) {
  2462. return dt.i18n('searchBuilder.conditions.number.not', i18n.conditions.number.not);
  2463. },
  2464. init: Criteria.initSelect,
  2465. inputValue: Criteria.inputValueSelect,
  2466. isInputValid: Criteria.isInputValidSelect,
  2467. search: function (value, comparison) {
  2468. return +value !== +comparison[0];
  2469. }
  2470. },
  2471. '<': {
  2472. conditionName: function (dt, i18n) {
  2473. return dt.i18n('searchBuilder.conditions.number.lt', i18n.conditions.number.lt);
  2474. },
  2475. init: Criteria.initInput,
  2476. inputValue: Criteria.inputValueInput,
  2477. isInputValid: Criteria.isInputValidInput,
  2478. search: function (value, comparison) {
  2479. return +value < +comparison[0];
  2480. }
  2481. },
  2482. '<=': {
  2483. conditionName: function (dt, i18n) {
  2484. return dt.i18n('searchBuilder.conditions.number.lte', i18n.conditions.number.lte);
  2485. },
  2486. init: Criteria.initInput,
  2487. inputValue: Criteria.inputValueInput,
  2488. isInputValid: Criteria.isInputValidInput,
  2489. search: function (value, comparison) {
  2490. return +value <= +comparison[0];
  2491. }
  2492. },
  2493. '>=': {
  2494. conditionName: function (dt, i18n) {
  2495. return dt.i18n('searchBuilder.conditions.number.gte', i18n.conditions.number.gte);
  2496. },
  2497. init: Criteria.initInput,
  2498. inputValue: Criteria.inputValueInput,
  2499. isInputValid: Criteria.isInputValidInput,
  2500. search: function (value, comparison) {
  2501. return +value >= +comparison[0];
  2502. }
  2503. },
  2504. '>': {
  2505. conditionName: function (dt, i18n) {
  2506. return dt.i18n('searchBuilder.conditions.number.gt', i18n.conditions.number.gt);
  2507. },
  2508. init: Criteria.initInput,
  2509. inputValue: Criteria.inputValueInput,
  2510. isInputValid: Criteria.isInputValidInput,
  2511. search: function (value, comparison) {
  2512. return +value > +comparison[0];
  2513. }
  2514. },
  2515. 'between': {
  2516. conditionName: function (dt, i18n) {
  2517. return dt.i18n('searchBuilder.conditions.number.between', i18n.conditions.number.between);
  2518. },
  2519. init: Criteria.init2Input,
  2520. inputValue: Criteria.inputValueInput,
  2521. isInputValid: Criteria.isInputValidInput,
  2522. search: function (value, comparison) {
  2523. if (+comparison[0] < +comparison[1]) {
  2524. return +comparison[0] <= +value && +value <= +comparison[1];
  2525. } else {
  2526. return +comparison[1] <= +value && +value <= +comparison[0];
  2527. }
  2528. }
  2529. },
  2530. '!between': {
  2531. conditionName: function (dt, i18n) {
  2532. return dt.i18n('searchBuilder.conditions.number.notBetween', i18n.conditions.number.notBetween);
  2533. },
  2534. init: Criteria.init2Input,
  2535. inputValue: Criteria.inputValueInput,
  2536. isInputValid: Criteria.isInputValidInput,
  2537. search: function (value, comparison) {
  2538. if (+comparison[0] < +comparison[1]) {
  2539. return !(+comparison[0] <= +value && +value <= +comparison[1]);
  2540. } else {
  2541. return !(+comparison[1] <= +value && +value <= +comparison[0]);
  2542. }
  2543. }
  2544. },
  2545. 'null': {
  2546. conditionName: function (dt, i18n) {
  2547. return dt.i18n('searchBuilder.conditions.number.empty', i18n.conditions.number.empty);
  2548. },
  2549. init: Criteria.initNoValue,
  2550. inputValue: function () {
  2551. },
  2552. isInputValid: function () {
  2553. return true;
  2554. },
  2555. search: function (value) {
  2556. return (value === null || value === undefined || value.length === 0);
  2557. }
  2558. },
  2559. '!null': {
  2560. conditionName: function (dt, i18n) {
  2561. return dt.i18n('searchBuilder.conditions.number.notEmpty', i18n.conditions.number.notEmpty);
  2562. },
  2563. isInputValid: function () {
  2564. return true;
  2565. },
  2566. init: Criteria.initNoValue,
  2567. inputValue: function () {
  2568. },
  2569. search: function (value) {
  2570. return !(value === null || value === undefined || value.length === 0);
  2571. }
  2572. }
  2573. };
  2574. // The order of the conditions will make tslint sad :(
  2575. Criteria.numFmtConditions = {
  2576. '=': {
  2577. conditionName: function (dt, i18n) {
  2578. return dt.i18n('searchBuilder.conditions.number.equals', i18n.conditions.number.equals);
  2579. },
  2580. init: Criteria.initSelect,
  2581. inputValue: Criteria.inputValueSelect,
  2582. isInputValid: Criteria.isInputValidSelect,
  2583. search: function (value, comparison) {
  2584. var val = value.indexOf('-') === 0 ?
  2585. '-' + value.replace(/[^0-9.]/g, '') :
  2586. value.replace(/[^0-9.]/g, '');
  2587. var comp = comparison[0].indexOf('-') === 0 ?
  2588. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2589. comparison[0].replace(/[^0-9.]/g, '');
  2590. return +val === +comp;
  2591. }
  2592. },
  2593. '!=': {
  2594. conditionName: function (dt, i18n) {
  2595. return dt.i18n('searchBuilder.conditions.number.not', i18n.conditions.number.not);
  2596. },
  2597. init: Criteria.initSelect,
  2598. inputValue: Criteria.inputValueSelect,
  2599. isInputValid: Criteria.isInputValidSelect,
  2600. search: function (value, comparison) {
  2601. var val = value.indexOf('-') === 0 ?
  2602. '-' + value.replace(/[^0-9.]/g, '') :
  2603. value.replace(/[^0-9.]/g, '');
  2604. var comp = comparison[0].indexOf('-') === 0 ?
  2605. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2606. comparison[0].replace(/[^0-9.]/g, '');
  2607. return +val !== +comp;
  2608. }
  2609. },
  2610. '<': {
  2611. conditionName: function (dt, i18n) {
  2612. return dt.i18n('searchBuilder.conditions.number.lt', i18n.conditions.number.lt);
  2613. },
  2614. init: Criteria.initInput,
  2615. inputValue: Criteria.inputValueInput,
  2616. isInputValid: Criteria.isInputValidInput,
  2617. search: function (value, comparison) {
  2618. var val = value.indexOf('-') === 0 ?
  2619. '-' + value.replace(/[^0-9.]/g, '') :
  2620. value.replace(/[^0-9.]/g, '');
  2621. var comp = comparison[0].indexOf('-') === 0 ?
  2622. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2623. comparison[0].replace(/[^0-9.]/g, '');
  2624. return +val < +comp;
  2625. }
  2626. },
  2627. '<=': {
  2628. conditionName: function (dt, i18n) {
  2629. return dt.i18n('searchBuilder.conditions.number.lte', i18n.conditions.number.lte);
  2630. },
  2631. init: Criteria.initInput,
  2632. inputValue: Criteria.inputValueInput,
  2633. isInputValid: Criteria.isInputValidInput,
  2634. search: function (value, comparison) {
  2635. var val = value.indexOf('-') === 0 ?
  2636. '-' + value.replace(/[^0-9.]/g, '') :
  2637. value.replace(/[^0-9.]/g, '');
  2638. var comp = comparison[0].indexOf('-') === 0 ?
  2639. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2640. comparison[0].replace(/[^0-9.]/g, '');
  2641. return +val <= +comp;
  2642. }
  2643. },
  2644. '>=': {
  2645. conditionName: function (dt, i18n) {
  2646. return dt.i18n('searchBuilder.conditions.number.gte', i18n.conditions.number.gte);
  2647. },
  2648. init: Criteria.initInput,
  2649. inputValue: Criteria.inputValueInput,
  2650. isInputValid: Criteria.isInputValidInput,
  2651. search: function (value, comparison) {
  2652. var val = value.indexOf('-') === 0 ?
  2653. '-' + value.replace(/[^0-9.]/g, '') :
  2654. value.replace(/[^0-9.]/g, '');
  2655. var comp = comparison[0].indexOf('-') === 0 ?
  2656. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2657. comparison[0].replace(/[^0-9.]/g, '');
  2658. return +val >= +comp;
  2659. }
  2660. },
  2661. '>': {
  2662. conditionName: function (dt, i18n) {
  2663. return dt.i18n('searchBuilder.conditions.number.gt', i18n.conditions.number.gt);
  2664. },
  2665. init: Criteria.initInput,
  2666. inputValue: Criteria.inputValueInput,
  2667. isInputValid: Criteria.isInputValidInput,
  2668. search: function (value, comparison) {
  2669. var val = value.indexOf('-') === 0 ?
  2670. '-' + value.replace(/[^0-9.]/g, '') :
  2671. value.replace(/[^0-9.]/g, '');
  2672. var comp = comparison[0].indexOf('-') === 0 ?
  2673. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2674. comparison[0].replace(/[^0-9.]/g, '');
  2675. return +val > +comp;
  2676. }
  2677. },
  2678. 'between': {
  2679. conditionName: function (dt, i18n) {
  2680. return dt.i18n('searchBuilder.conditions.number.between', i18n.conditions.number.between);
  2681. },
  2682. init: Criteria.init2Input,
  2683. inputValue: Criteria.inputValueInput,
  2684. isInputValid: Criteria.isInputValidInput,
  2685. search: function (value, comparison) {
  2686. var val = value.indexOf('-') === 0 ?
  2687. '-' + value.replace(/[^0-9.]/g, '') :
  2688. value.replace(/[^0-9.]/g, '');
  2689. var comp0 = comparison[0].indexOf('-') === 0 ?
  2690. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2691. comparison[0].replace(/[^0-9.]/g, '');
  2692. var comp1 = comparison[1].indexOf('-') === 0 ?
  2693. '-' + comparison[1].replace(/[^0-9.]/g, '') :
  2694. comparison[1].replace(/[^0-9.]/g, '');
  2695. if (+comp0 < +comp1) {
  2696. return +comp0 <= +val && +val <= +comp1;
  2697. } else {
  2698. return +comp1 <= +val && +val <= +comp0;
  2699. }
  2700. }
  2701. },
  2702. '!between': {
  2703. conditionName: function (dt, i18n) {
  2704. return dt.i18n('searchBuilder.conditions.number.notBetween', i18n.conditions.number.notBetween);
  2705. },
  2706. init: Criteria.init2Input,
  2707. inputValue: Criteria.inputValueInput,
  2708. isInputValid: Criteria.isInputValidInput,
  2709. search: function (value, comparison) {
  2710. var val = value.indexOf('-') === 0 ?
  2711. '-' + value.replace(/[^0-9.]/g, '') :
  2712. value.replace(/[^0-9.]/g, '');
  2713. var comp0 = comparison[0].indexOf('-') === 0 ?
  2714. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  2715. comparison[0].replace(/[^0-9.]/g, '');
  2716. var comp1 = comparison[1].indexOf('-') === 0 ?
  2717. '-' + comparison[1].replace(/[^0-9.]/g, '') :
  2718. comparison[1].replace(/[^0-9.]/g, '');
  2719. if (+comp0 < +comp1) {
  2720. return !(+comp0 <= +val && +val <= +comp1);
  2721. } else {
  2722. return !(+comp1 <= +val && +val <= +comp0);
  2723. }
  2724. }
  2725. },
  2726. 'null': {
  2727. conditionName: function (dt, i18n) {
  2728. return dt.i18n('searchBuilder.conditions.number.empty', i18n.conditions.number.empty);
  2729. },
  2730. init: Criteria.initNoValue,
  2731. inputValue: function () {
  2732. },
  2733. isInputValid: function () {
  2734. return true;
  2735. },
  2736. search: function (value) {
  2737. return (value === null || value === undefined || value.length === 0);
  2738. }
  2739. },
  2740. '!null': {
  2741. conditionName: function (dt, i18n) {
  2742. return dt.i18n('searchBuilder.conditions.number.notEmpty', i18n.conditions.number.notEmpty);
  2743. },
  2744. isInputValid: function () {
  2745. return true;
  2746. },
  2747. init: Criteria.initNoValue,
  2748. inputValue: function () {
  2749. },
  2750. search: function (value) {
  2751. return !(value === null || value === undefined || value.length === 0);
  2752. }
  2753. }
  2754. };
  2755. // The order of the conditions will make tslint sad :(
  2756. Criteria.stringConditions = {
  2757. '=': {
  2758. conditionName: function (dt, i18n) {
  2759. return dt.i18n('searchBuilder.conditions.string.equals', i18n.conditions.string.equals);
  2760. },
  2761. init: Criteria.initSelect,
  2762. inputValue: Criteria.inputValueSelect,
  2763. isInputValid: Criteria.isInputValidSelect,
  2764. search: function (value, comparison) {
  2765. return value === comparison[0];
  2766. }
  2767. },
  2768. '!=': {
  2769. conditionName: function (dt, i18n) {
  2770. return dt.i18n('searchBuilder.conditions.string.not', i18n.conditions.string.not);
  2771. },
  2772. init: Criteria.initSelect,
  2773. inputValue: Criteria.inputValueSelect,
  2774. isInputValid: Criteria.isInputValidInput,
  2775. search: function (value, comparison) {
  2776. return value !== comparison[0];
  2777. }
  2778. },
  2779. 'starts': {
  2780. conditionName: function (dt, i18n) {
  2781. return dt.i18n('searchBuilder.conditions.string.startsWith', i18n.conditions.string.startsWith);
  2782. },
  2783. init: Criteria.initInput,
  2784. inputValue: Criteria.inputValueInput,
  2785. isInputValid: Criteria.isInputValidInput,
  2786. search: function (value, comparison) {
  2787. return value.toLowerCase().indexOf(comparison[0].toLowerCase()) === 0;
  2788. }
  2789. },
  2790. 'contains': {
  2791. conditionName: function (dt, i18n) {
  2792. return dt.i18n('searchBuilder.conditions.string.contains', i18n.conditions.string.contains);
  2793. },
  2794. init: Criteria.initInput,
  2795. inputValue: Criteria.inputValueInput,
  2796. isInputValid: Criteria.isInputValidInput,
  2797. search: function (value, comparison) {
  2798. return value.toLowerCase().indexOf(comparison[0].toLowerCase()) !== -1;
  2799. }
  2800. },
  2801. 'ends': {
  2802. conditionName: function (dt, i18n) {
  2803. return dt.i18n('searchBuilder.conditions.string.endsWith', i18n.conditions.string.endsWith);
  2804. },
  2805. init: Criteria.initInput,
  2806. inputValue: Criteria.inputValueInput,
  2807. isInputValid: Criteria.isInputValidInput,
  2808. search: function (value, comparison) {
  2809. return value.toLowerCase().endsWith(comparison[0].toLowerCase());
  2810. }
  2811. },
  2812. 'null': {
  2813. conditionName: function (dt, i18n) {
  2814. return dt.i18n('searchBuilder.conditions.string.empty', i18n.conditions.string.empty);
  2815. },
  2816. init: Criteria.initNoValue,
  2817. inputValue: function () {
  2818. },
  2819. isInputValid: function () {
  2820. return true;
  2821. },
  2822. search: function (value) {
  2823. return (value === null || value === undefined || value.length === 0);
  2824. }
  2825. },
  2826. '!null': {
  2827. conditionName: function (dt, i18n) {
  2828. return dt.i18n('searchBuilder.conditions.string.notEmpty', i18n.conditions.string.notEmpty);
  2829. },
  2830. isInputValid: function () {
  2831. return true;
  2832. },
  2833. init: Criteria.initNoValue,
  2834. inputValue: function () {
  2835. },
  2836. search: function (value) {
  2837. return !(value === null || value === undefined || value.length === 0);
  2838. }
  2839. }
  2840. };
  2841. // The order of the conditions will make tslint sad :(
  2842. Criteria.arrayConditions = {
  2843. 'contains': {
  2844. conditionName: function (dt, i18n) {
  2845. return dt.i18n('searchBuilder.conditions.array.contains', i18n.conditions.array.contains);
  2846. },
  2847. init: Criteria.initSelectArray,
  2848. inputValue: Criteria.inputValueSelect,
  2849. isInputValid: Criteria.isInputValidSelect,
  2850. search: function (value, comparison) {
  2851. return value.indexOf(comparison[0]) !== -1;
  2852. }
  2853. },
  2854. 'without': {
  2855. conditionName: function (dt, i18n) {
  2856. return dt.i18n('searchBuilder.conditions.array.without', i18n.conditions.array.without);
  2857. },
  2858. init: Criteria.initSelectArray,
  2859. inputValue: Criteria.inputValueSelect,
  2860. isInputValid: Criteria.isInputValidSelect,
  2861. search: function (value, comparison) {
  2862. return value.indexOf(comparison[0]) === -1;
  2863. }
  2864. },
  2865. '=': {
  2866. conditionName: function (dt, i18n) {
  2867. return dt.i18n('searchBuilder.conditions.array.equals', i18n.conditions.array.equals);
  2868. },
  2869. init: Criteria.initSelect,
  2870. inputValue: Criteria.inputValueSelect,
  2871. isInputValid: Criteria.isInputValidSelect,
  2872. search: function (value, comparison) {
  2873. if (value.length === comparison[0].length) {
  2874. for (var i = 0; i < value.length; i++) {
  2875. if (value[i] !== comparison[0][i]) {
  2876. return false;
  2877. }
  2878. }
  2879. return true;
  2880. }
  2881. return false;
  2882. }
  2883. },
  2884. '!=': {
  2885. conditionName: function (dt, i18n) {
  2886. return dt.i18n('searchBuilder.conditions.array.not', i18n.conditions.array.not);
  2887. },
  2888. init: Criteria.initSelect,
  2889. inputValue: Criteria.inputValueSelect,
  2890. isInputValid: Criteria.isInputValidSelect,
  2891. search: function (value, comparison) {
  2892. if (value.length === comparison[0].length) {
  2893. for (var i = 0; i < value.length; i++) {
  2894. if (value[i] !== comparison[0][i]) {
  2895. return true;
  2896. }
  2897. }
  2898. return false;
  2899. }
  2900. return true;
  2901. }
  2902. },
  2903. 'null': {
  2904. conditionName: function (dt, i18n) {
  2905. return dt.i18n('searchBuilder.conditions.array.empty', i18n.conditions.array.empty);
  2906. },
  2907. init: Criteria.initNoValue,
  2908. isInputValid: function () {
  2909. return true;
  2910. },
  2911. inputValue: function () {
  2912. },
  2913. search: function (value) {
  2914. return (value === null || value === undefined || value.length === 0);
  2915. }
  2916. },
  2917. '!null': {
  2918. conditionName: function (dt, i18n) {
  2919. return dt.i18n('searchBuilder.conditions.array.notEmpty', i18n.conditions.array.notEmpty);
  2920. },
  2921. isInputValid: function () {
  2922. return true;
  2923. },
  2924. init: Criteria.initNoValue,
  2925. inputValue: function () {
  2926. },
  2927. search: function (value) {
  2928. return (value !== null && value !== undefined && value.length !== 0);
  2929. }
  2930. }
  2931. };
  2932. Criteria.defaults = {
  2933. columns: true,
  2934. conditions: {
  2935. 'array': Criteria.arrayConditions,
  2936. 'date': Criteria.dateConditions,
  2937. 'html': Criteria.stringConditions,
  2938. 'html-num': Criteria.numConditions,
  2939. 'html-num-fmt': Criteria.numFmtConditions,
  2940. 'moment': Criteria.momentDateConditions,
  2941. 'num': Criteria.numConditions,
  2942. 'num-fmt': Criteria.numFmtConditions,
  2943. 'string': Criteria.stringConditions
  2944. },
  2945. depthLimit: false,
  2946. filterChanged: undefined,
  2947. greyscale: false,
  2948. i18n: {
  2949. add: 'Add Condition',
  2950. button: {
  2951. 0: 'Search Builder',
  2952. _: 'Search Builder (%d)'
  2953. },
  2954. clearAll: 'Clear All',
  2955. condition: 'Condition',
  2956. data: 'Data',
  2957. deleteTitle: 'Delete filtering rule',
  2958. leftTitle: 'Outdent criteria',
  2959. logicAnd: 'And',
  2960. logicOr: 'Or',
  2961. rightTitle: 'Indent criteria',
  2962. title: {
  2963. 0: 'Custom Search Builder',
  2964. _: 'Custom Search Builder (%d)'
  2965. },
  2966. value: 'Value',
  2967. valueJoiner: 'and'
  2968. },
  2969. logic: 'AND',
  2970. orthogonal: {
  2971. display: 'display',
  2972. search: 'filter'
  2973. },
  2974. preDefined: false
  2975. };
  2976. return Criteria;
  2977. }());
  2978. var $$1;
  2979. var DataTable$1;
  2980. /**
  2981. * Sets the value of jQuery for use in the file
  2982. * @param jq the instance of jQuery to be set
  2983. */
  2984. function setJQuery$1(jq) {
  2985. $$1 = jq;
  2986. DataTable$1 = jq.fn.dataTable;
  2987. }
  2988. /**
  2989. * The Group class is used within SearchBuilder to represent a group of criteria
  2990. */
  2991. var Group = /** @class */ (function () {
  2992. function Group(table, opts, topGroup, index, isChild, depth) {
  2993. if (index === void 0) {
  2994. index = 0;
  2995. }
  2996. if (isChild === void 0) {
  2997. isChild = false;
  2998. }
  2999. if (depth === void 0) {
  3000. depth = 1;
  3001. }
  3002. // Check that the required version of DataTables is included
  3003. if (!DataTable$1 || !DataTable$1.versionCheck || !DataTable$1.versionCheck('1.10.0')) {
  3004. throw new Error('SearchBuilder requires DataTables 1.10 or newer');
  3005. }
  3006. this.classes = $$1.extend(true, {}, Group.classes);
  3007. // Get options from user
  3008. this.c = $$1.extend(true, {}, Group.defaults, opts);
  3009. this.s = {
  3010. criteria: [],
  3011. depth: depth,
  3012. dt: table,
  3013. index: index,
  3014. isChild: isChild,
  3015. logic: undefined,
  3016. opts: opts,
  3017. toDrop: undefined,
  3018. topGroup: topGroup
  3019. };
  3020. this.dom = {
  3021. add: $$1('<button/>')
  3022. .addClass(this.classes.add)
  3023. .addClass(this.classes.button)
  3024. .attr('type', 'button'),
  3025. clear: $$1('<button>&times</button>')
  3026. .addClass(this.classes.button)
  3027. .addClass(this.classes.clearGroup)
  3028. .attr('type', 'button'),
  3029. container: $$1('<div/>')
  3030. .addClass(this.classes.group),
  3031. logic: $$1('<button/>')
  3032. .addClass(this.classes.logic)
  3033. .addClass(this.classes.button)
  3034. .attr('type', 'button'),
  3035. logicContainer: $$1('<div/>')
  3036. .addClass(this.classes.logicContainer)
  3037. };
  3038. // A reference to the top level group is maintained throughout any subgroups and criteria that may be created
  3039. if (this.s.topGroup === undefined) {
  3040. this.s.topGroup = this.dom.container;
  3041. }
  3042. this._setup();
  3043. return this;
  3044. }
  3045. /**
  3046. * Destroys the groups buttons, clears the internal criteria and removes it from the dom
  3047. */
  3048. Group.prototype.destroy = function () {
  3049. // Turn off listeners
  3050. $$1(this.dom.add).off('.dtsb');
  3051. $$1(this.dom.logic).off('.dtsb');
  3052. // Trigger event for groups at a higher level to pick up on
  3053. $$1(this.dom.container)
  3054. .trigger('dtsb-destroy')
  3055. .remove();
  3056. this.s.criteria = [];
  3057. };
  3058. /**
  3059. * Gets the details required to rebuild the group
  3060. */
  3061. Group.prototype.getDetails = function () {
  3062. if (this.s.criteria.length === 0) {
  3063. return {};
  3064. }
  3065. var details = {
  3066. criteria: [],
  3067. logic: this.s.logic
  3068. };
  3069. // NOTE here crit could be either a subgroup or a criteria
  3070. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  3071. var crit = _a[_i];
  3072. details.criteria.push(crit.criteria.getDetails());
  3073. }
  3074. return details;
  3075. };
  3076. /**
  3077. * Getter for the node for the container of the group
  3078. * @returns Node for the container of the group
  3079. */
  3080. Group.prototype.getNode = function () {
  3081. return this.dom.container;
  3082. };
  3083. /**
  3084. * Rebuilds the group based upon the details passed in
  3085. * @param loadedDetails the details required to rebuild the group
  3086. */
  3087. Group.prototype.rebuild = function (loadedDetails) {
  3088. // If no criteria are stored then just return
  3089. if (loadedDetails.criteria === undefined || loadedDetails.criteria === null || loadedDetails.criteria.length === 0) {
  3090. return;
  3091. }
  3092. this.s.logic = loadedDetails.logic;
  3093. $$1(this.dom.logic).text(this.s.logic === 'OR'
  3094. ? this.s.dt.i18n('searchBuilder.logicOr', this.c.i18n.logicOr)
  3095. : this.s.dt.i18n('searchBuilder.logicAnd', this.c.i18n.logicAnd));
  3096. // Add all of the criteria, be it a sub group or a criteria
  3097. for (var _i = 0, _a = loadedDetails.criteria; _i < _a.length; _i++) {
  3098. var crit = _a[_i];
  3099. if (crit.logic !== undefined) {
  3100. this._addPrevGroup(crit);
  3101. } else if (crit.logic === undefined) {
  3102. this._addPrevCriteria(crit);
  3103. }
  3104. }
  3105. // For all of the criteria children, update the arrows incase they require changing and set the listeners
  3106. for (var _b = 0, _c = this.s.criteria; _b < _c.length; _b++) {
  3107. var crit = _c[_b];
  3108. if (crit.criteria instanceof Criteria) {
  3109. crit.criteria.updateArrows(this.s.criteria.length > 1, false);
  3110. this._setCriteriaListeners(crit.criteria);
  3111. }
  3112. }
  3113. };
  3114. /**
  3115. * Redraws the Contents of the searchBuilder Groups and Criteria
  3116. */
  3117. Group.prototype.redrawContents = function () {
  3118. // Clear the container out and add the basic elements
  3119. $$1(this.dom.container)
  3120. .empty()
  3121. .append(this.dom.logicContainer)
  3122. .append(this.dom.add);
  3123. // Sort the criteria by index so that they appear in the correct order
  3124. this.s.criteria.sort(function (a, b) {
  3125. if (a.criteria.s.index < b.criteria.s.index) {
  3126. return -1;
  3127. } else if (a.criteria.s.index > b.criteria.s.index) {
  3128. return 1;
  3129. }
  3130. return 0;
  3131. });
  3132. this.setListeners();
  3133. for (var i = 0; i < this.s.criteria.length; i++) {
  3134. var crit = this.s.criteria[i].criteria;
  3135. if (crit instanceof Criteria) {
  3136. // Reset the index to the new value
  3137. this.s.criteria[i].index = i;
  3138. this.s.criteria[i].criteria.s.index = i;
  3139. // Add to the group
  3140. $$1(this.s.criteria[i].criteria.dom.container).insertBefore(this.dom.add);
  3141. // Set listeners for various points
  3142. this._setCriteriaListeners(crit);
  3143. this.s.criteria[i].criteria.rebuild(this.s.criteria[i].criteria.getDetails());
  3144. } else if (crit instanceof Group && crit.s.criteria.length > 0) {
  3145. // Reset the index to the new value
  3146. this.s.criteria[i].index = i;
  3147. this.s.criteria[i].criteria.s.index = i;
  3148. // Add the sub group to the group
  3149. $$1(this.s.criteria[i].criteria.dom.container).insertBefore(this.dom.add);
  3150. // Redraw the contents of the group
  3151. crit.redrawContents();
  3152. this._setGroupListeners(crit);
  3153. } else {
  3154. // The group is empty so remove it
  3155. this.s.criteria.splice(i, 1);
  3156. i--;
  3157. }
  3158. }
  3159. this.setupLogic();
  3160. };
  3161. /**
  3162. * Search method, checking the row data against the criteria in the group
  3163. * @param rowData The row data to be compared
  3164. * @returns boolean The result of the search
  3165. */
  3166. Group.prototype.search = function (rowData, rowIdx) {
  3167. if (this.s.logic === 'AND') {
  3168. return this._andSearch(rowData, rowIdx);
  3169. } else if (this.s.logic === 'OR') {
  3170. return this._orSearch(rowData, rowIdx);
  3171. }
  3172. return true;
  3173. };
  3174. /**
  3175. * Locates the groups logic button to the correct location on the page
  3176. */
  3177. Group.prototype.setupLogic = function () {
  3178. // Remove logic button
  3179. $$1(this.dom.logicContainer).remove();
  3180. $$1(this.dom.clear).remove();
  3181. // If there are no criteria in the group then keep the logic removed and return
  3182. if (this.s.criteria.length < 1) {
  3183. if (!this.s.isChild) {
  3184. $$1(this.dom.container).trigger('dtsb-destroy');
  3185. // Set criteria left margin
  3186. $$1(this.dom.container).css('margin-left', 0);
  3187. }
  3188. return;
  3189. }
  3190. // Set width, take 2 for the border
  3191. var height = $$1(this.dom.container).height() - 2;
  3192. $$1(this.dom.clear).height('0px');
  3193. $$1(this.dom.logicContainer).append(this.dom.clear).width(height);
  3194. // Prepend logic button
  3195. $$1(this.dom.container).prepend(this.dom.logicContainer);
  3196. this._setLogicListener();
  3197. // Set criteria left margin
  3198. $$1(this.dom.container).css('margin-left', $$1(this.dom.logicContainer).outerHeight(true));
  3199. var logicOffset = $$1(this.dom.logicContainer).offset();
  3200. // Set horizontal alignment
  3201. var currentLeft = logicOffset.left;
  3202. var groupLeft = $$1(this.dom.container).offset().left;
  3203. var shuffleLeft = currentLeft - groupLeft;
  3204. var newPos = currentLeft - shuffleLeft - $$1(this.dom.logicContainer).outerHeight(true);
  3205. $$1(this.dom.logicContainer).offset({left: newPos});
  3206. // Set vertical alignment
  3207. var firstCrit = $$1(this.dom.logicContainer).next();
  3208. var currentTop = logicOffset.top;
  3209. var firstTop = $$1(firstCrit).offset().top;
  3210. var shuffleTop = currentTop - firstTop;
  3211. var newTop = currentTop - shuffleTop;
  3212. $$1(this.dom.logicContainer).offset({top: newTop});
  3213. $$1(this.dom.clear).outerHeight($$1(this.dom.logicContainer).height());
  3214. this._setClearListener();
  3215. };
  3216. /**
  3217. * Sets listeners on the groups elements
  3218. */
  3219. Group.prototype.setListeners = function () {
  3220. var _this = this;
  3221. $$1(this.dom.add).unbind('click');
  3222. $$1(this.dom.add).on('click', function () {
  3223. // If this is the parent group then the logic button has not been added yet
  3224. if (!_this.s.isChild) {
  3225. $$1(_this.dom.container).prepend(_this.dom.logicContainer);
  3226. }
  3227. _this.addCriteria();
  3228. $$1(_this.dom.container).trigger('dtsb-add');
  3229. _this.s.dt.state.save();
  3230. return false;
  3231. });
  3232. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  3233. var crit = _a[_i];
  3234. crit.criteria.setListeners();
  3235. }
  3236. this._setClearListener();
  3237. this._setLogicListener();
  3238. };
  3239. /**
  3240. * Adds a criteria to the group
  3241. * @param crit Instance of Criteria to be added to the group
  3242. */
  3243. Group.prototype.addCriteria = function (crit, redraw) {
  3244. if (crit === void 0) {
  3245. crit = null;
  3246. }
  3247. if (redraw === void 0) {
  3248. redraw = true;
  3249. }
  3250. var index = crit === null ? this.s.criteria.length : crit.s.index;
  3251. var criteria = new Criteria(this.s.dt, this.s.opts, this.s.topGroup, index, this.s.depth);
  3252. // If a Criteria has been passed in then set the values to continue that
  3253. if (crit !== null) {
  3254. criteria.c = crit.c;
  3255. criteria.s = crit.s;
  3256. criteria.s.depth = this.s.depth;
  3257. criteria.classes = crit.classes;
  3258. }
  3259. criteria.populate();
  3260. var inserted = false;
  3261. for (var i = 0; i < this.s.criteria.length; i++) {
  3262. if (i === 0 && this.s.criteria[i].criteria.s.index > criteria.s.index) {
  3263. // Add the node for the criteria at the start of the group
  3264. $$1(criteria.getNode()).insertBefore(this.s.criteria[i].criteria.dom.container);
  3265. inserted = true;
  3266. } else if (i < this.s.criteria.length - 1 &&
  3267. this.s.criteria[i].criteria.s.index < criteria.s.index &&
  3268. this.s.criteria[i + 1].criteria.s.index > criteria.s.index) {
  3269. // Add the node for the criteria in the correct location
  3270. $$1(criteria.getNode()).insertAfter(this.s.criteria[i].criteria.dom.container);
  3271. inserted = true;
  3272. }
  3273. }
  3274. if (!inserted) {
  3275. $$1(criteria.getNode()).insertBefore(this.dom.add);
  3276. }
  3277. // Add the details for this criteria to the array
  3278. this.s.criteria.push({
  3279. criteria: criteria,
  3280. index: index
  3281. });
  3282. this.s.criteria = this.s.criteria.sort(function (a, b) {
  3283. return a.criteria.s.index - b.criteria.s.index;
  3284. });
  3285. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  3286. var opt = _a[_i];
  3287. if (opt.criteria instanceof Criteria) {
  3288. opt.criteria.updateArrows(this.s.criteria.length > 1, redraw);
  3289. }
  3290. }
  3291. this._setCriteriaListeners(criteria);
  3292. criteria.setListeners();
  3293. this.setupLogic();
  3294. };
  3295. /**
  3296. * Checks the group to see if it has any filled criteria
  3297. */
  3298. Group.prototype.checkFilled = function () {
  3299. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  3300. var crit = _a[_i];
  3301. if ((crit.criteria instanceof Criteria && crit.criteria.s.filled) ||
  3302. (crit.criteria instanceof Group && crit.criteria.checkFilled())) {
  3303. return true;
  3304. }
  3305. }
  3306. return false;
  3307. };
  3308. /**
  3309. * Gets the count for the number of criteria in this group and any sub groups
  3310. */
  3311. Group.prototype.count = function () {
  3312. var count = 0;
  3313. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  3314. var crit = _a[_i];
  3315. if (crit.criteria instanceof Group) {
  3316. count += crit.criteria.count();
  3317. } else {
  3318. count++;
  3319. }
  3320. }
  3321. return count;
  3322. };
  3323. /**
  3324. * Rebuilds a sub group that previously existed
  3325. * @param loadedGroup The details of a group within this group
  3326. */
  3327. Group.prototype._addPrevGroup = function (loadedGroup) {
  3328. var idx = this.s.criteria.length;
  3329. var group = new Group(this.s.dt, this.c, this.s.topGroup, idx, true, this.s.depth + 1);
  3330. // Add the new group to the criteria array
  3331. this.s.criteria.push({
  3332. criteria: group,
  3333. index: idx,
  3334. logic: group.s.logic
  3335. });
  3336. // Rebuild it with the previous conditions for that group
  3337. group.rebuild(loadedGroup);
  3338. this.s.criteria[idx].criteria = group;
  3339. $$1(this.s.topGroup).trigger('dtsb-redrawContents');
  3340. this._setGroupListeners(group);
  3341. };
  3342. /**
  3343. * Rebuilds a criteria of this group that previously existed
  3344. * @param loadedCriteria The details of a criteria within the group
  3345. */
  3346. Group.prototype._addPrevCriteria = function (loadedCriteria) {
  3347. var idx = this.s.criteria.length;
  3348. var criteria = new Criteria(this.s.dt, this.s.opts, this.s.topGroup, idx, this.s.depth);
  3349. criteria.populate();
  3350. // Add the new criteria to the criteria array
  3351. this.s.criteria.push({
  3352. criteria: criteria,
  3353. index: idx
  3354. });
  3355. // Rebuild it with the previous conditions for that criteria
  3356. criteria.rebuild(loadedCriteria);
  3357. this.s.criteria[idx].criteria = criteria;
  3358. $$1(this.s.topGroup).trigger('dtsb-redrawContents');
  3359. };
  3360. /**
  3361. * Checks And the criteria using AND logic
  3362. * @param rowData The row data to be checked against the search criteria
  3363. * @returns boolean The result of the AND search
  3364. */
  3365. Group.prototype._andSearch = function (rowData, rowIdx) {
  3366. // If there are no criteria then return true for this group
  3367. if (this.s.criteria.length === 0) {
  3368. return true;
  3369. }
  3370. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  3371. var crit = _a[_i];
  3372. // If the criteria is not complete then skip it
  3373. if (crit.criteria instanceof Criteria && !crit.criteria.s.filled) {
  3374. }
  3375. // Otherwise if a single one fails return false
  3376. else if (!crit.criteria.search(rowData, rowIdx)) {
  3377. return false;
  3378. }
  3379. }
  3380. // If we get to here then everything has passed, so return true for the group
  3381. return true;
  3382. };
  3383. /**
  3384. * Checks And the criteria using OR logic
  3385. * @param rowData The row data to be checked against the search criteria
  3386. * @returns boolean The result of the OR search
  3387. */
  3388. Group.prototype._orSearch = function (rowData, rowIdx) {
  3389. // If there are no criteria in the group then return true
  3390. if (this.s.criteria.length === 0) {
  3391. return true;
  3392. }
  3393. // This will check to make sure that at least one criteria in the group is complete
  3394. var filledfound = false;
  3395. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  3396. var crit = _a[_i];
  3397. if (crit.criteria instanceof Criteria && crit.criteria.s.filled) {
  3398. // A completed criteria has been found so set the flag
  3399. filledfound = true;
  3400. // If the search passes then return true
  3401. if (crit.criteria.search(rowData, rowIdx)) {
  3402. return true;
  3403. }
  3404. } else if (crit.criteria instanceof Group && crit.criteria.checkFilled()) {
  3405. filledfound = true;
  3406. if (crit.criteria.search(rowData, rowIdx)) {
  3407. return true;
  3408. }
  3409. }
  3410. }
  3411. // If we get here we need to return the inverse of filledfound,
  3412. // as if any have been found and we are here then none have passed
  3413. return !filledfound;
  3414. };
  3415. /**
  3416. * Removes a criteria from the group
  3417. * @param criteria The criteria instance to be removed
  3418. */
  3419. Group.prototype._removeCriteria = function (criteria, group) {
  3420. if (group === void 0) {
  3421. group = false;
  3422. }
  3423. // If removing a criteria and there is only then then just destroy the group
  3424. if (this.s.criteria.length <= 1 && this.s.isChild) {
  3425. this.destroy();
  3426. } else {
  3427. // Otherwise splice the given criteria out and redo the indexes
  3428. var last = void 0;
  3429. for (var i = 0; i < this.s.criteria.length; i++) {
  3430. if (this.s.criteria[i].index === criteria.s.index && (!group || this.s.criteria[i].criteria instanceof Group)) {
  3431. last = i;
  3432. }
  3433. }
  3434. // We want to remove the last element with the desired index, as its replacement will be inserted before it
  3435. if (last !== undefined) {
  3436. this.s.criteria.splice(last, 1);
  3437. }
  3438. for (var i = 0; i < this.s.criteria.length; i++) {
  3439. this.s.criteria[i].index = i;
  3440. this.s.criteria[i].criteria.s.index = i;
  3441. }
  3442. }
  3443. };
  3444. /**
  3445. * Sets the listeners in group for a criteria
  3446. * @param criteria The criteria for the listeners to be set on
  3447. */
  3448. Group.prototype._setCriteriaListeners = function (criteria) {
  3449. var _this = this;
  3450. $$1(criteria.dom["delete"])
  3451. .unbind('click')
  3452. .on('click', function () {
  3453. _this._removeCriteria(criteria);
  3454. $$1(criteria.dom.container).remove();
  3455. for (var _i = 0, _a = _this.s.criteria; _i < _a.length; _i++) {
  3456. var crit = _a[_i];
  3457. if (crit.criteria instanceof Criteria) {
  3458. crit.criteria.updateArrows(_this.s.criteria.length > 1);
  3459. }
  3460. }
  3461. criteria.destroy();
  3462. _this.s.dt.draw();
  3463. $$1(_this.s.topGroup).trigger('dtsb-redrawContents');
  3464. $$1(_this.s.topGroup).trigger('dtsb-updateTitle');
  3465. return false;
  3466. });
  3467. $$1(criteria.dom.right)
  3468. .unbind('click')
  3469. .on('click', function () {
  3470. var idx = criteria.s.index;
  3471. var group = new Group(_this.s.dt, _this.s.opts, _this.s.topGroup, criteria.s.index, true, _this.s.depth + 1);
  3472. // Add the criteria that is to be moved to the new group
  3473. group.addCriteria(criteria);
  3474. // Update the details in the current groups criteria array
  3475. _this.s.criteria[idx].criteria = group;
  3476. _this.s.criteria[idx].logic = 'AND';
  3477. $$1(_this.s.topGroup).trigger('dtsb-redrawContents');
  3478. _this._setGroupListeners(group);
  3479. return false;
  3480. });
  3481. $$1(criteria.dom.left)
  3482. .unbind('click')
  3483. .on('click', function () {
  3484. _this.s.toDrop = new Criteria(_this.s.dt, _this.s.opts, _this.s.topGroup, criteria.s.index);
  3485. _this.s.toDrop.s = criteria.s;
  3486. _this.s.toDrop.c = criteria.c;
  3487. _this.s.toDrop.classes = criteria.classes;
  3488. _this.s.toDrop.populate();
  3489. // The dropCriteria event mutates the reference to the index so need to store it
  3490. var index = _this.s.toDrop.s.index;
  3491. $$1(_this.dom.container).trigger('dtsb-dropCriteria');
  3492. criteria.s.index = index;
  3493. _this._removeCriteria(criteria);
  3494. // By tracking the top level group we can directly trigger a redraw on it,
  3495. // bubbling is also possible, but that is slow with deep levelled groups
  3496. $$1(_this.s.topGroup).trigger('dtsb-redrawContents');
  3497. _this.s.dt.draw();
  3498. return false;
  3499. });
  3500. };
  3501. /**
  3502. * Set's the listeners for the group clear button
  3503. */
  3504. Group.prototype._setClearListener = function () {
  3505. var _this = this;
  3506. $$1(this.dom.clear)
  3507. .unbind('click')
  3508. .on('click', function () {
  3509. if (!_this.s.isChild) {
  3510. $$1(_this.dom.container).trigger('dtsb-clearContents');
  3511. return false;
  3512. }
  3513. _this.destroy();
  3514. $$1(_this.s.topGroup).trigger('dtsb-updateTitle');
  3515. $$1(_this.s.topGroup).trigger('dtsb-redrawContents');
  3516. return false;
  3517. });
  3518. };
  3519. /**
  3520. * Sets listeners for sub groups of this group
  3521. * @param group The sub group that the listeners are to be set on
  3522. */
  3523. Group.prototype._setGroupListeners = function (group) {
  3524. var _this = this;
  3525. // Set listeners for the new group
  3526. $$1(group.dom.add)
  3527. .unbind('click')
  3528. .on('click', function () {
  3529. _this.setupLogic();
  3530. $$1(_this.dom.container).trigger('dtsb-add');
  3531. return false;
  3532. });
  3533. $$1(group.dom.container)
  3534. .unbind('dtsb-add')
  3535. .on('dtsb-add', function () {
  3536. _this.setupLogic();
  3537. $$1(_this.dom.container).trigger('dtsb-add');
  3538. return false;
  3539. });
  3540. $$1(group.dom.container)
  3541. .unbind('dtsb-destroy')
  3542. .on('dtsb-destroy', function () {
  3543. _this._removeCriteria(group, true);
  3544. $$1(group.dom.container).remove();
  3545. _this.setupLogic();
  3546. return false;
  3547. });
  3548. $$1(group.dom.container)
  3549. .unbind('dtsb-dropCriteria')
  3550. .on('dtsb-dropCriteria', function () {
  3551. var toDrop = group.s.toDrop;
  3552. toDrop.s.index = group.s.index;
  3553. toDrop.updateArrows(_this.s.criteria.length > 1, false);
  3554. _this.addCriteria(toDrop, false);
  3555. return false;
  3556. });
  3557. group.setListeners();
  3558. };
  3559. /**
  3560. * Sets up the Group instance, setting listeners and appending elements
  3561. */
  3562. Group.prototype._setup = function () {
  3563. this.setListeners();
  3564. $$1(this.dom.add).text(this.s.dt.i18n('searchBuilder.add', this.c.i18n.add));
  3565. $$1(this.dom.logic).text(this.c.logic === 'OR'
  3566. ? this.s.dt.i18n('searchBuilder.logicOr', this.c.i18n.logicOr)
  3567. : this.s.dt.i18n('searchBuilder.logicAnd', this.c.i18n.logicAnd));
  3568. this.s.logic = this.c.logic === 'OR' ? 'OR' : 'AND';
  3569. if (this.c.greyscale) {
  3570. $$1(this.dom.logic).addClass(this.classes.greyscale);
  3571. }
  3572. $$1(this.dom.logicContainer).append(this.dom.logic).append(this.dom.clear);
  3573. // Only append the logic button immediately if this is a sub group,
  3574. // otherwise it will be prepended later when adding a criteria
  3575. if (this.s.isChild) {
  3576. $$1(this.dom.container).append(this.dom.logicContainer);
  3577. }
  3578. $$1(this.dom.container).append(this.dom.add);
  3579. };
  3580. /**
  3581. * Sets the listener for the logic button
  3582. */
  3583. Group.prototype._setLogicListener = function () {
  3584. var _this = this;
  3585. $$1(this.dom.logic)
  3586. .unbind('click')
  3587. .on('click', function () {
  3588. _this._toggleLogic();
  3589. _this.s.dt.draw();
  3590. for (var _i = 0, _a = _this.s.criteria; _i < _a.length; _i++) {
  3591. var crit = _a[_i];
  3592. crit.criteria.setListeners();
  3593. }
  3594. });
  3595. };
  3596. /**
  3597. * Toggles the logic for the group
  3598. */
  3599. Group.prototype._toggleLogic = function () {
  3600. if (this.s.logic === 'OR') {
  3601. this.s.logic = 'AND';
  3602. $$1(this.dom.logic).text(this.s.dt.i18n('searchBuilder.logicAnd', this.c.i18n.logicAnd));
  3603. } else if (this.s.logic === 'AND') {
  3604. this.s.logic = 'OR';
  3605. $$1(this.dom.logic).text(this.s.dt.i18n('searchBuilder.logicOr', this.c.i18n.logicOr));
  3606. }
  3607. };
  3608. Group.version = '1.0.0';
  3609. Group.classes = {
  3610. add: 'dtsb-add',
  3611. button: 'dtsb-button',
  3612. clearGroup: 'dtsb-clearGroup',
  3613. greyscale: 'dtsb-greyscale',
  3614. group: 'dtsb-group',
  3615. inputButton: 'dtsb-iptbtn',
  3616. logic: 'dtsb-logic',
  3617. logicContainer: 'dtsb-logicContainer'
  3618. };
  3619. Group.defaults = {
  3620. columns: true,
  3621. conditions: {
  3622. 'date': Criteria.dateConditions,
  3623. 'html': Criteria.stringConditions,
  3624. 'html-num': Criteria.numConditions,
  3625. 'html-num-fmt': Criteria.numFmtConditions,
  3626. 'moment': Criteria.momentDateConditions,
  3627. 'num': Criteria.numConditions,
  3628. 'num-fmt': Criteria.numFmtConditions,
  3629. 'string': Criteria.stringConditions
  3630. },
  3631. depthLimit: false,
  3632. filterChanged: undefined,
  3633. greyscale: false,
  3634. i18n: {
  3635. add: 'Add Condition',
  3636. button: {
  3637. 0: 'Search Builder',
  3638. _: 'Search Builder (%d)'
  3639. },
  3640. clearAll: 'Clear All',
  3641. condition: 'Condition',
  3642. data: 'Data',
  3643. deleteTitle: 'Delete filtering rule',
  3644. leftTitle: 'Outdent criteria',
  3645. logicAnd: 'And',
  3646. logicOr: 'Or',
  3647. rightTitle: 'Indent criteria',
  3648. title: {
  3649. 0: 'Custom Search Builder',
  3650. _: 'Custom Search Builder (%d)'
  3651. },
  3652. value: 'Value',
  3653. valueJoiner: 'and'
  3654. },
  3655. logic: 'AND',
  3656. orthogonal: {
  3657. display: 'display',
  3658. search: 'filter'
  3659. },
  3660. preDefined: false
  3661. };
  3662. return Group;
  3663. }());
  3664. var $$2;
  3665. var DataTable$2;
  3666. /**
  3667. * Sets the value of jQuery for use in the file
  3668. * @param jq the instance of jQuery to be set
  3669. */
  3670. function setJQuery$2(jq) {
  3671. $$2 = jq;
  3672. DataTable$2 = jq.fn.DataTable;
  3673. }
  3674. /**
  3675. * SearchBuilder class for DataTables.
  3676. * Allows for complex search queries to be constructed and implemented on a DataTable
  3677. */
  3678. var SearchBuilder = /** @class */ (function () {
  3679. function SearchBuilder(builderSettings, opts) {
  3680. var _this = this;
  3681. // Check that the required version of DataTables is included
  3682. if (!DataTable$2 || !DataTable$2.versionCheck || !DataTable$2.versionCheck('1.10.0')) {
  3683. throw new Error('SearchBuilder requires DataTables 1.10 or newer');
  3684. }
  3685. var table = new DataTable$2.Api(builderSettings);
  3686. this.classes = $$2.extend(true, {}, SearchBuilder.classes);
  3687. // Get options from user
  3688. this.c = $$2.extend(true, {}, SearchBuilder.defaults, opts);
  3689. this.dom = {
  3690. clearAll: $$2('<button type="button">' + table.i18n('searchBuilder.clearAll', this.c.i18n.clearAll) + '</button>')
  3691. .addClass(this.classes.clearAll)
  3692. .addClass(this.classes.button)
  3693. .attr('type', 'button'),
  3694. container: $$2('<div/>')
  3695. .addClass(this.classes.container),
  3696. title: $$2('<div/>')
  3697. .addClass(this.classes.title),
  3698. titleRow: $$2('<div/>')
  3699. .addClass(this.classes.titleRow),
  3700. topGroup: undefined
  3701. };
  3702. this.s = {
  3703. dt: table,
  3704. opts: opts,
  3705. search: undefined,
  3706. topGroup: undefined
  3707. };
  3708. // If searchbuilder is already defined for this table then return
  3709. if (table.settings()[0]._searchBuilder !== undefined) {
  3710. return;
  3711. }
  3712. table.settings()[0]._searchBuilder = this;
  3713. // Run the remaining setup when the table is initialised
  3714. if (this.s.dt.settings()[0]._bInitComplete) {
  3715. this._setUp();
  3716. } else {
  3717. table.one('init.dt', function () {
  3718. _this._setUp();
  3719. });
  3720. }
  3721. return this;
  3722. }
  3723. /**
  3724. * Gets the details required to rebuild the SearchBuilder as it currently is
  3725. */
  3726. SearchBuilder.prototype.getDetails = function () {
  3727. return this.s.topGroup.getDetails();
  3728. };
  3729. /**
  3730. * Getter for the node of the container for the searchBuilder
  3731. * @returns JQuery<HTMLElement> the node of the container
  3732. */
  3733. SearchBuilder.prototype.getNode = function () {
  3734. return this.dom.container;
  3735. };
  3736. /**
  3737. * Rebuilds the SearchBuilder to a state that is provided
  3738. * @param details The details required to perform a rebuild
  3739. */
  3740. SearchBuilder.prototype.rebuild = function (details) {
  3741. $$2(this.dom.clearAll).click();
  3742. // If there are no details to rebuild then return
  3743. if (details === undefined || details === null) {
  3744. return this;
  3745. }
  3746. this.s.topGroup.rebuild(details);
  3747. this.s.dt.draw();
  3748. this.s.topGroup.setListeners();
  3749. return this;
  3750. };
  3751. /**
  3752. * Applies the defaults to preDefined criteria
  3753. * @param preDef the array of criteria to be processed.
  3754. */
  3755. SearchBuilder.prototype._applyPreDefDefaults = function (preDef) {
  3756. var _this = this;
  3757. if (preDef.criteria !== undefined && preDef.logic === undefined) {
  3758. preDef.logic = 'AND';
  3759. }
  3760. var _loop_1 = function (crit) {
  3761. // Apply the defaults to any further criteria
  3762. if (crit.criteria !== undefined) {
  3763. crit = this_1._applyPreDefDefaults(crit);
  3764. } else {
  3765. this_1.s.dt.columns().every(function (index) {
  3766. if (_this.s.dt.settings()[0].aoColumns[index].sTitle === crit.data) {
  3767. crit.dataIdx = index;
  3768. }
  3769. });
  3770. }
  3771. };
  3772. var this_1 = this;
  3773. for (var _i = 0, _a = preDef.criteria; _i < _a.length; _i++) {
  3774. var crit = _a[_i];
  3775. _loop_1(crit);
  3776. }
  3777. return preDef;
  3778. };
  3779. /**
  3780. * Set's up the SearchBuilder
  3781. */
  3782. SearchBuilder.prototype._setUp = function (loadState) {
  3783. var _this = this;
  3784. if (loadState === void 0) {
  3785. loadState = true;
  3786. }
  3787. this.s.topGroup = new Group(this.s.dt, this.c, undefined);
  3788. this._setClearListener();
  3789. this.s.dt.on('stateSaveParams', function (e, settings, data) {
  3790. data.searchBuilder = _this.getDetails();
  3791. data.page = _this.s.dt.page();
  3792. });
  3793. this._build();
  3794. if (loadState) {
  3795. var loadedState = this.s.dt.state.loaded();
  3796. // If the loaded State is not null rebuild based on it for statesave
  3797. if (loadedState !== null && loadedState.searchBuilder !== undefined) {
  3798. this.s.topGroup.rebuild(loadedState.searchBuilder);
  3799. $$2(this.s.topGroup.dom.container).trigger('dtsb-redrawContents');
  3800. this.s.dt.page(loadedState.page).draw('page');
  3801. this.s.topGroup.setListeners();
  3802. }
  3803. // Otherwise load any predefined options
  3804. else if (this.c.preDefined !== false) {
  3805. this.c.preDefined = this._applyPreDefDefaults(this.c.preDefined);
  3806. this.rebuild(this.c.preDefined);
  3807. }
  3808. }
  3809. this._setEmptyListener();
  3810. this.s.dt.state.save();
  3811. };
  3812. /**
  3813. * Updates the title of the SearchBuilder
  3814. * @param count the number of filters in the SearchBuilder
  3815. */
  3816. SearchBuilder.prototype._updateTitle = function (count) {
  3817. $$2(this.dom.title).text(this.s.dt.i18n('searchBuilder.title', this.c.i18n.title, count));
  3818. };
  3819. /**
  3820. * Builds all of the dom elements together
  3821. */
  3822. SearchBuilder.prototype._build = function () {
  3823. var _this = this;
  3824. // Empty and setup the container
  3825. $$2(this.dom.clearAll).remove();
  3826. $$2(this.dom.container).empty();
  3827. var count = this.s.topGroup.count();
  3828. this._updateTitle(count);
  3829. $$2(this.dom.titleRow).append(this.dom.title);
  3830. $$2(this.dom.container).append(this.dom.titleRow);
  3831. this.dom.topGroup = this.s.topGroup.getNode();
  3832. $$2(this.dom.container).append(this.dom.topGroup);
  3833. this._setRedrawListener();
  3834. var tableNode = this.s.dt.table(0).node();
  3835. if ($$2.fn.dataTable.ext.search.indexOf(this.s.search) === -1) {
  3836. // Custom search function for SearchBuilder
  3837. this.s.search = function (settings, searchData, dataIndex, origData) {
  3838. if (settings.nTable !== tableNode) {
  3839. return true;
  3840. }
  3841. return _this.s.topGroup.search(searchData, dataIndex);
  3842. };
  3843. // Add SearchBuilder search function to the dataTables search array
  3844. $$2.fn.dataTable.ext.search.push(this.s.search);
  3845. }
  3846. // Register an Api method for getting the column type
  3847. $$2.fn.DataTable.Api.registerPlural('columns().type()', 'column().type()', function (selector, opts) {
  3848. return this.iterator('column', function (settings, column) {
  3849. return settings.aoColumns[column].sType;
  3850. }, 1);
  3851. });
  3852. this.s.dt.on('destroy.dt', function () {
  3853. $$2(_this.dom.container).remove();
  3854. $$2(_this.dom.clearAll).remove();
  3855. var searchIdx = $$2.fn.dataTable.ext.search.indexOf(_this.s.search);
  3856. while (searchIdx !== -1) {
  3857. $$2.fn.dataTable.ext.search.splice(searchIdx, 1);
  3858. searchIdx = $$2.fn.dataTable.ext.search.indexOf(_this.s.search);
  3859. }
  3860. });
  3861. };
  3862. /**
  3863. * Checks if the clearAll button should be added or not
  3864. */
  3865. SearchBuilder.prototype._checkClear = function () {
  3866. if (this.s.topGroup.s.criteria.length > 0) {
  3867. $$2(this.dom.clearAll).insertAfter(this.dom.title);
  3868. this._setClearListener();
  3869. } else {
  3870. $$2(this.dom.clearAll).remove();
  3871. }
  3872. };
  3873. /**
  3874. * Update the count in the title/button
  3875. * @param count Number of filters applied
  3876. */
  3877. SearchBuilder.prototype._filterChanged = function (count) {
  3878. var fn = this.c.filterChanged;
  3879. if (typeof fn === 'function') {
  3880. fn(count, this.s.dt.i18n('searchBuilder.button', this.c.i18n.button, count));
  3881. }
  3882. };
  3883. /**
  3884. * Set the listener for the clear button
  3885. */
  3886. SearchBuilder.prototype._setClearListener = function () {
  3887. var _this = this;
  3888. $$2(this.dom.clearAll).unbind('click');
  3889. $$2(this.dom.clearAll).on('click', function () {
  3890. _this.s.topGroup = new Group(_this.s.dt, _this.c, undefined);
  3891. _this._build();
  3892. _this.s.dt.draw();
  3893. _this.s.topGroup.setListeners();
  3894. $$2(_this.dom.clearAll).remove();
  3895. _this._setEmptyListener();
  3896. _this._filterChanged(0);
  3897. return false;
  3898. });
  3899. };
  3900. /**
  3901. * Set the listener for the Redraw event
  3902. */
  3903. SearchBuilder.prototype._setRedrawListener = function () {
  3904. var _this = this;
  3905. $$2(this.s.topGroup.dom.container).unbind('dtsb-redrawContents');
  3906. $$2(this.s.topGroup.dom.container).on('dtsb-redrawContents', function () {
  3907. _this._checkClear();
  3908. _this.s.topGroup.redrawContents();
  3909. _this.s.topGroup.setupLogic();
  3910. _this._setEmptyListener();
  3911. var count = _this.s.topGroup.count();
  3912. _this._updateTitle(count);
  3913. _this._filterChanged(count);
  3914. _this.s.dt.state.save();
  3915. });
  3916. $$2(this.s.topGroup.dom.container).unbind('dtsb-clearContents');
  3917. $$2(this.s.topGroup.dom.container).on('dtsb-clearContents', function () {
  3918. _this._setUp(false);
  3919. _this._filterChanged(0);
  3920. _this.s.dt.draw();
  3921. });
  3922. $$2(this.s.topGroup.dom.container).on('dtsb-updateTitle', function () {
  3923. var count = _this.s.topGroup.count();
  3924. _this._updateTitle(count);
  3925. _this._filterChanged(count);
  3926. });
  3927. };
  3928. /**
  3929. * Sets listeners to check whether clearAll should be added or removed
  3930. */
  3931. SearchBuilder.prototype._setEmptyListener = function () {
  3932. var _this = this;
  3933. $$2(this.s.topGroup.dom.add).on('click', function () {
  3934. _this._checkClear();
  3935. });
  3936. $$2(this.s.topGroup.dom.container).on('dtsb-destroy', function () {
  3937. $$2(_this.dom.clearAll).remove();
  3938. });
  3939. };
  3940. SearchBuilder.version = '1.0.1';
  3941. SearchBuilder.classes = {
  3942. button: 'dtsb-button',
  3943. clearAll: 'dtsb-clearAll',
  3944. container: 'dtsb-searchBuilder',
  3945. inputButton: 'dtsb-iptbtn',
  3946. title: 'dtsb-title',
  3947. titleRow: 'dtsb-titleRow'
  3948. };
  3949. SearchBuilder.defaults = {
  3950. columns: true,
  3951. conditions: {
  3952. 'date': Criteria.dateConditions,
  3953. 'html': Criteria.stringConditions,
  3954. 'html-num': Criteria.numConditions,
  3955. 'html-num-fmt': Criteria.numFmtConditions,
  3956. 'moment': Criteria.momentDateConditions,
  3957. 'num': Criteria.numConditions,
  3958. 'num-fmt': Criteria.numFmtConditions,
  3959. 'string': Criteria.stringConditions
  3960. },
  3961. depthLimit: false,
  3962. filterChanged: undefined,
  3963. greyscale: false,
  3964. i18n: {
  3965. add: 'Add Condition',
  3966. button: {
  3967. 0: 'Search Builder',
  3968. _: 'Search Builder (%d)'
  3969. },
  3970. clearAll: 'Clear All',
  3971. condition: 'Condition',
  3972. conditions: {
  3973. array: {
  3974. contains: 'Contains',
  3975. empty: 'Empty',
  3976. equals: 'Equals',
  3977. not: 'Not',
  3978. notEmpty: 'Not Empty',
  3979. without: 'Without'
  3980. },
  3981. date: {
  3982. after: 'After',
  3983. before: 'Before',
  3984. between: 'Between',
  3985. empty: 'Empty',
  3986. equals: 'Equals',
  3987. not: 'Not',
  3988. notBetween: 'Not Between',
  3989. notEmpty: 'Not Empty'
  3990. },
  3991. moment: {
  3992. after: 'After',
  3993. before: 'Before',
  3994. between: 'Between',
  3995. empty: 'Empty',
  3996. equals: 'Equals',
  3997. not: 'Not',
  3998. notBetween: 'Not Between',
  3999. notEmpty: 'Not Empty'
  4000. },
  4001. number: {
  4002. between: 'Between',
  4003. empty: 'Empty',
  4004. equals: 'Equals',
  4005. gt: 'Greater Than',
  4006. gte: 'Greater Than Equal To',
  4007. lt: 'Less Than',
  4008. lte: 'Less Than Equal To',
  4009. not: 'Not',
  4010. notBetween: 'Not Between',
  4011. notEmpty: 'Not Empty'
  4012. },
  4013. string: {
  4014. contains: 'Contains',
  4015. empty: 'Empty',
  4016. endsWith: 'Ends With',
  4017. equals: 'Equals',
  4018. not: 'Not',
  4019. notEmpty: 'Not Empty',
  4020. startsWith: 'Starts With'
  4021. }
  4022. },
  4023. data: 'Data',
  4024. deleteTitle: 'Delete filtering rule',
  4025. leftTitle: 'Outdent criteria',
  4026. logicAnd: 'And',
  4027. logicOr: 'Or',
  4028. rightTitle: 'Indent criteria',
  4029. title: {
  4030. 0: 'Custom Search Builder',
  4031. _: 'Custom Search Builder (%d)'
  4032. },
  4033. value: 'Value',
  4034. valueJoiner: 'and'
  4035. },
  4036. logic: 'AND',
  4037. orthogonal: {
  4038. display: 'display',
  4039. search: 'filter'
  4040. },
  4041. preDefined: false
  4042. };
  4043. return SearchBuilder;
  4044. }());
  4045. /*! SearchBuilder 1.0.1
  4046. * ©2020 SpryMedia Ltd - datatables.net/license/mit
  4047. */
  4048. // DataTables extensions common UMD. Note that this allows for AMD, CommonJS
  4049. // (with window and jQuery being allowed as parameters to the returned
  4050. // function) or just default browser loading.
  4051. (function (factory) {
  4052. if (typeof define === 'function' && define.amd) {
  4053. // AMD
  4054. define(['jquery', 'datatables.net'], function ($) {
  4055. return factory($, window, document);
  4056. });
  4057. } else if (typeof exports === 'object') {
  4058. // CommonJS
  4059. module.exports = function (root, $) {
  4060. if (!root) {
  4061. root = window;
  4062. }
  4063. if (!$ || !$.fn.dataTable) {
  4064. $ = require('datatables.net')(root, $).$;
  4065. }
  4066. return factory($, root, root.document);
  4067. };
  4068. } else {
  4069. // Browser - assume jQuery has already been loaded
  4070. factory(window.jQuery, window, document);
  4071. }
  4072. }(function ($, window, document) {
  4073. setJQuery$2($);
  4074. setJQuery$1($);
  4075. setJQuery($);
  4076. var DataTable = $.fn.dataTable;
  4077. $.fn.dataTable.SearchBuilder = SearchBuilder;
  4078. $.fn.DataTable.SearchBuilder = SearchBuilder;
  4079. $.fn.dataTable.Group = Group;
  4080. $.fn.DataTable.Group = Group;
  4081. $.fn.dataTable.Criteria = Criteria;
  4082. $.fn.DataTable.Criteria = Criteria;
  4083. var apiRegister = $.fn.dataTable.Api.register;
  4084. // Set up object for plugins
  4085. $.fn.dataTable.ext.searchBuilder = {
  4086. conditions: {}
  4087. };
  4088. $.fn.dataTable.ext.buttons.searchBuilder = {
  4089. action: function (e, dt, node, config) {
  4090. e.stopPropagation();
  4091. this.popover(config._searchBuilder.getNode(), {
  4092. align: 'dt-container'
  4093. });
  4094. },
  4095. config: {},
  4096. init: function (dt, node, config) {
  4097. var sb = new $.fn.dataTable.SearchBuilder(dt, $.extend({
  4098. filterChanged: function (count, text) {
  4099. dt.button(node).text(text);
  4100. }
  4101. }, config.config));
  4102. dt.button(node).text(config.text || dt.i18n('searchBuilder.button', sb.c.i18n.button, 0));
  4103. config._searchBuilder = sb;
  4104. },
  4105. text: null
  4106. };
  4107. apiRegister('searchBuilder.getDetails()', function () {
  4108. var ctx = this.context[0];
  4109. return ctx._searchBuilder.getDetails();
  4110. });
  4111. apiRegister('searchBuilder.rebuild()', function (details) {
  4112. var ctx = this.context[0];
  4113. ctx._searchBuilder.rebuild(details);
  4114. return this;
  4115. });
  4116. apiRegister('searchBuilder.container()', function () {
  4117. var ctx = this.context[0];
  4118. return ctx._searchBuilder.getNode();
  4119. });
  4120. /**
  4121. * Init function for SearchBuilder
  4122. * @param settings the settings to be applied
  4123. * @param options the options for SearchBuilder
  4124. * @returns JQUERY<HTMLElement> Returns the node of the SearchBuilder
  4125. */
  4126. function _init(settings, options) {
  4127. var api = new DataTable.Api(settings);
  4128. var opts = options
  4129. ? options
  4130. : api.init().searchBuilder || DataTable.defaults.searchBuilder;
  4131. var searchBuilder = new SearchBuilder(api, opts);
  4132. var node = searchBuilder.getNode();
  4133. return node;
  4134. }
  4135. // Attach a listener to the document which listens for DataTables initialisation
  4136. // events so we can automatically initialise
  4137. $(document).on('preInit.dt.dtsp', function (e, settings, json) {
  4138. if (e.namespace !== 'dt') {
  4139. return;
  4140. }
  4141. if (settings.oInit.searchBuilder ||
  4142. DataTable.defaults.searchBuilder) {
  4143. if (!settings._searchBuilder) {
  4144. _init(settings);
  4145. }
  4146. }
  4147. });
  4148. // DataTables `dom` feature option
  4149. DataTable.ext.feature.push({
  4150. cFeature: 'Q',
  4151. fnInit: _init
  4152. });
  4153. // DataTables 2 layout feature
  4154. if (DataTable.ext.features) {
  4155. DataTable.ext.features.register('searchBuilder', _init);
  4156. }
  4157. }));
  4158. }());